diff --git a/docs/build/guides/fungible-token.md b/docs/build/guides/fungible-token.md index 33f72818a4..aa9f345486 100644 --- a/docs/build/guides/fungible-token.md +++ b/docs/build/guides/fungible-token.md @@ -24,26 +24,46 @@ This process ensures secure and accurate token transfers on the Flow blockchain. ## Fungible Token Standard -The [Fungible Token Standard](https://github.com/onflow/flow-ft) defines what a fungible token should look like on Flow. Wallets and other platforms need to recognize these tokens, so they adhere to a specific interface, which defines fields like balance, totalSupply, withdraw functionality, and more. This interface ensures that all fungible tokens on Flow have a consistent structure and behavior. [Learn more about interfaces here](https://cadence-lang.org/docs/language/interfaces). +The [Fungible Token Standard](https://github.com/onflow/flow-ft) defines what a fungible token should look like on Flow. Wallets and other platforms need to recognize these tokens, so they adhere to a specific interface, which defines fields like balance, totalSupply, withdraw functionality, and more. This interface ensures that all fungible tokens on Flow have a consistent structure and behavior. [Learn more about interfaces here](https://developers.flow.com/cadence/language/interfaces). -## Creating Our Project +## Setting Up a Project -To get started making our fungible token, let's first create a project directory in our terminal and go to it. We'll call it FooToken. +To start creating an NFT on the Flow blockchain, you'll first need some tools and configurations in place. + +### Installing Flow CLI + +The **Flow CLI** (Command Line Interface) provides a suite of tools that allow developers to interact seamlessly with the Flow blockchain. + +If you haven't installed the Flow CLI yet and have [Homebrew](https://brew.sh/) installed, you can run `brew install flow-cli`. If you don’t have Homebrew, please follow [the installation guide here](https://developers.flow.com/tools/flow-cli/install). + +### Initializing a New Project + +> 💡 Note: Here is [a link to the completed code](https://github.com/chasefleming/foobar-nft) if you want to skip ahead or reference as you follow along. + +Once you have the Flow CLI installed, you can set up a new project using the `flow setup` command. This command initializes the necessary directory structure and a `flow.json` configuration file (a way to configure your project for contract sources, deployments, accounts, and more): ```bash -mkdir FooToken -cd FooToken +flow setup FooToken ``` -Next, we'll initialize a project using the Flow CLI, which will create a configuration file named **`flow.json`**. This file configures the Flow CLI for the Flow blockchain, handling settings such as network details, accounts, and contracts. +Upon execution, the command will generate the following directory structure: + +``` +/cadence + /contracts + /scripts + /transactions + /tests +flow.json +``` -If you haven't installed the Flow CLI yet and have [homebrew](https://brew.sh/) installed you can run `brew install flow-cli`. If you don’t have homebrew, please follow [the installation guide here](../../tools/flow-cli/install.md). +Now, navigate into the project directory: ```bash -flow init +cd FooToken ``` -In our `flow.json` for the network we want to use, we are going to state the address the Fungible Token is deployed to via `aliases` in a new `contracts` section. Since it is a standard contract, it has already been deployed to the emulator, a tool that runs and emulates a local development version of the Flow Blockchain, for us. You can find addresses for other networks, like Testnet and Mainnet, on the [Fungible Token Standard repo](https://github.com/onflow/flow-ft). +In our configuration file, called `flow.json`, for the network we want to use, we are going to state the address the `FungibleToken` contract is deployed to via `aliases` in a new `contracts` section. Since it is a standard contract, it has already been deployed to the emulator, a tool that runs and emulates a local development version of the Flow Blockchain, for us. You can find addresses for other networks, like Testnet and Mainnet, on the [Fungible Token Standard repo](https://github.com/onflow/flow-ft). ```json "contracts": { @@ -57,14 +77,14 @@ In our `flow.json` for the network we want to use, we are going to state the add ## Writing Our Token Contract -Next let's create a directory and a file for our new FooToken contract. +Next let's create a `FooToken` contract at `cadence/contract/FooToken.cdc` using the boilerplate `generate` command from the Flow CLI: ```bash -mkdir cadence -mkdir cadence/contracts -touch cadence/contracts/FooToken.cdc +flow generate contract FooToken ``` +This will create a new file called `FooToken.cdc` in the `contracts` directory. Let's open it up and add some code. + In this contract file, we want to import our `FungibleToken` contract that we've defined in `flow.json`. ```cadence @@ -76,7 +96,7 @@ In this same file, let's create our contract which implements the `FungibleToken ```cadence // ...previous code -pub contract FooToken: FungibleToken { +access(all) contract FooToken: FungibleToken { pub var totalSupply: UFix64 init() { @@ -92,7 +112,7 @@ Inside of this contract, we'll need to create a resource for a Vault. A resource ```cadence import "FungibleToken" -pub contract FooToken: FungibleToken { +access(all) contract FooToken: FungibleToken { // ...totalSupply code pub resource Vault: FungibleToken.Provider, FungibleToken.Receiver, FungibleToken.Balance { @@ -112,7 +132,7 @@ In order to give an account a vault, we need to create a function that creates a ```cadence import "FungibleToken" -pub contract FooToken: FungibleToken { +access(all) contract FooToken: FungibleToken { // ...other code pub fun createEmptyVault(): @FooToken.Vault { @@ -128,7 +148,7 @@ The standard also wants us to implement the events required for creating a token ```cadence import "FungibleToken" -pub contract FooToken: FungibleToken { +access(all) contract FooToken: FungibleToken { pub event TokensInitialized(initialSupply: UFix64) pub event TokensWithdrawn(amount: UFix64, from: Address?) @@ -143,7 +163,7 @@ Inside our `Vault` resource, we also need a way to withdraw balances. To do that ```cadence import "FungibleToken" -pub contract FooToken: FungibleToken { +access(all) contract FooToken: FungibleToken { // ...previous code @@ -165,12 +185,12 @@ pub contract FooToken: FungibleToken { } ``` -In addition to withdrawing, the vault also needs a way to deposit. We'll again emit the appropriate event, as well as [typecast](https://cadence-lang.org/docs/language/operators#casting-operators) to make sure we are dealing with the correct token, update the vault balance, and destroy the vault. We also need to set the balance to 0 in the current vault so that the destroy method is not triggered. Add this code to your resource: +In addition to withdrawing, the vault also needs a way to deposit. We'll again emit the appropriate event, as well as [typecast](https://developers.flow.com/cadence/language/operators#casting-operators) to make sure we are dealing with the correct token, update the vault balance, and destroy the vault. We also need to set the balance to 0 in the current vault so that the destroy method is not triggered. Add this code to your resource: ```cadence import "FungibleToken" -pub contract FooToken: FungibleToken { +access(all) contract FooToken: FungibleToken { // ...previous code @@ -201,7 +221,7 @@ The destroy call is an important thing to handle though since if anyone ever doe ```cadence import "FungibleToken" -pub contract FooToken: FungibleToken { +access(all) contract FooToken: FungibleToken { // ...previous code @@ -228,7 +248,7 @@ If we want the ability to create new tokens, we'll need a way to mint them. To d ```cadence import "FungibleToken" -pub contract FooToken: FungibleToken { +access(all) contract FooToken: FungibleToken { // ...additional contract code @@ -250,7 +270,7 @@ We also want to decide which account/s we want to give this ability to. In our e ```cadence import "FungibleToken" -pub contract FooToken: FungibleToken { +access(all) contract FooToken: FungibleToken { // ...additional contract code @@ -266,7 +286,7 @@ After each of these steps, your `FooToken.cdc` contract file should now look lik ```cadence import "FungibleToken" -pub contract FooToken: FungibleToken { +access(all) contract FooToken: FungibleToken { pub event TokensInitialized(initialSupply: UFix64) pub event TokensWithdrawn(amount: UFix64, from: Address?) @@ -351,23 +371,22 @@ Open a new terminal and run the following to deploy your project: flow project deploy ``` -Congrats, you've deployed your contract to the Flow Blockchain emulator. To read more about deploying your project to other environments, see the [CLI docs](../../tools/flow-cli/deployment/deploy-project-contracts.md). +Congrats, you've deployed your contract to the Flow Blockchain emulator. To read more about deploying your project to other environments, see the [CLI docs](https://developers.flow.com/tools/flow-cli/deployment/deploy-project-contracts). ## Reading the Token’s Total Supply -Let's now check that our total supply was initialized with 1,000 FooTokens. Go ahead and create a new directory and script file called `TotalSupply.cdc`. +Let's now check that our total supply was initialized with 1,000 FooTokens. Go ahead and create a script called `TotalSupply.cdc` using the `generate` command. ```bash -mkdir cadence/scripts -touch cadence/scripts/TotalSupply.cdc +flow generate script TotalSupply ``` -In `TotalSupply.cdc`, let's add this code which will log the `totalSupply` value from the `FooToken` contract: +In `cadence/scripts/TotalSupply.cdc` (which was just created), let's add this code which will log the `totalSupply` value from the `FooToken` contract: ```cadence import "FooToken" -pub fun main() { +access(all) fun main() { log(FooToken.totalSupply) } ``` @@ -380,20 +399,19 @@ flow scripts execute cadence/scripts/TotalSupply.cdc In the terminal where you started the emulator, you should see `1000.0` -To learn more about running scripts using Flow CLI, [see the docs](../../tools/flow-cli/scripts/execute-scripts.md). +To learn more about running scripts using Flow CLI, [see the docs](https://developers.flow.com/tools/flow-cli/scripts/execute-scripts). ## Giving Accounts the Ability to Receive Tokens On Flow, newly created accounts cannot receive arbitrary assets. They need to be initialized to receive resources. In our case, we want to give accounts tokens and we’ll need to create a `Vault` (which acts as a receiver) on each account that we want to have the ability to receive tokens. To do this, we'll need to run a transaction which will create the vault and set it in their storage using the `createEmptyVault` function we created earlier on the contract. -Let's first create the file for this transaction called `CreateVault.cdc`: +Let's first create the file at `cadence/transactions/CreateVault.cdc` using the `generate` command: ```bash -mkdir cadence/transactions -touch cadence/transactions/CreateVault.cdc +flow generate transaction CreateVault ``` -Then add this code to it. This will call the `createEmptyVault` function, save it in storage, and create a capability for the vault which will later allow us to read from it (To learn more about capabilities, see [the Cadence docs here](https://cadence-lang.org/docs/language/capabilities)). +Then add this code to it. This will call the `createEmptyVault` function, save it in storage, and create a capability for the vault which will later allow us to read from it (To learn more about capabilities, see [the Cadence docs here](https://developers.flow.com/cadence/language/capabilities)). ```cadence import "FooToken" @@ -431,16 +449,16 @@ To call our create vault transaction from the CLI, we'll run the following: flow transactions send ./cadence/transactions/CreateVault.cdc --signer test-acct --network emulator ``` -To learn more about running transactions using CLI, [see the docs](../../tools/flow-cli/transactions/send-transactions.md). +To learn more about running transactions using CLI, [see the docs](https://developers.flow.com/tools/flow-cli/transactions/send-transactions). ## Reading a Vault’s Balance Let's now read the balance of the newly created account (`test-acct`) to check it's zero. -Create this new script file `ReadVaultBalance.cdc`: +Create this new script file `cadence/scripts/ReadVaultBalance.cdc`: ```bash -touch cadence/scripts/ReadVaultBalance.cdc +flow generate script ReadVaultBalance ``` Add this code which attempts to borrow the capability from the account requested and logs the vault balance if permitted: @@ -449,7 +467,7 @@ Add this code which attempts to borrow the capability from the account requested import "FooToken" import "FungibleToken" -pub fun main(account: Address) { +access(all) fun main(account: Address) { let vault = getAccount(account).getCapability(/public/Vault) .borrow<&FooToken.Vault{FungibleToken.Balance}>() ?? panic("Can't borrow public Vault") @@ -470,10 +488,10 @@ You should see a balance of zero logged. Now that we have an account with a vault, let's mint some tokens into it using the Minter we created on the contract account. -To do this, let's create a new transaction file called `Minter.cdc`: +To do this, let's create a new transaction file `cadence/transactions/Minter.cdc`: ```bash -touch cadence/transactions/Minter.cdc +flow generate transaction Minter ``` Next, let's add the following code to the `Minter.cdc` file. This code will attempt to borrow the minting capability and mint 20 new tokens into the receivers account. @@ -518,10 +536,10 @@ It should now say 20 tokens are in the vault. The final functionality we'll add is the ability to transfer tokens from one account to another. -To do that, create a new `Transfer.cdc` transaction file: +To do that, create a new `cadence/transactions/Transfer.cdc` transaction file: ```bash -touch cadence/transactions/Transfer.cdc +flow generate transaction Transfer ``` Let's add the code which states that the signer of the transaction will withdraw from their vault and put it into the receiver's vault which will be passed as a transaction argument. @@ -587,4 +605,4 @@ You should now see 1 token in `test-acct-2` account! - [View a repo of this example code](https://github.com/chasefleming/FooToken) - [Watch a video on how to create a fungible token on Playground](https://www.youtube.com/watch?v=Yq_sUARMQ4E) - [Review an `ExampleToken` contract implementing all of the remaining FungibleToken interface](https://github.com/onflow/flow-ft/blob/master/contracts/ExampleToken.cdc) -- [View the Flow Token Standard](https://github.com/onflow/flow-ft/blob/master/contracts/FungibleToken.cdc) +- [View the Flow Token Standard](https://github.com/onflow/flow-ft/blob/master/contracts/FungibleToken.cdc) \ No newline at end of file diff --git a/docs/build/guides/nft.md b/docs/build/guides/nft.md index 976afe3be8..a1aeede25a 100644 --- a/docs/build/guides/nft.md +++ b/docs/build/guides/nft.md @@ -23,7 +23,6 @@ If you haven't installed the Flow CLI yet and have [Homebrew](https://brew.sh/) ### Initializing a New Project - > 💡 Note: Here is [a link to the completed code](https://github.com/chasefleming/foobar-nft) if you want to skip ahead or reference as you follow along. Once you have the Flow CLI installed, you can set up a new project using the `flow setup` command. This command initializes the necessary directory structure and a `flow.json` configuration file (a way to configure your project for contract sources, deployments, accounts, and more): @@ -49,16 +48,16 @@ Now, navigate into the project directory: cd foobar-nft ``` -To begin, let's create a contract file named `FooBar` for the `FooBar` token, which will be the focus of this tutorial: +To begin, let's create a contract file named `FooBar` for the `FooBar` token, which will be the focus of this tutorial. To do this, we can use the boilerplate `generate` command from the Flow CLI: ```bash -touch cadence/contracts/FooBar.cdc +flow generate contract FooBar ``` -With the contract file in place, you can now set up the basic contract structure: +This will create a new file at `cadence/contracts/FooBar.cdc` with the following contents: ```cadence -pub contract FooBar { +access(all) contract FooBar { init() {} } ``` @@ -72,7 +71,7 @@ On the Flow blockchain, "[Resources](https://cadence-lang.org/docs/tutorial/reso To begin, let's define a basic `NFT` resource. This resource requires an `init` method, which is invoked when the resource is instantiated: ```cadence -pub contract FooBar { +access(all) contract FooBar { pub resource NFT { init() {} @@ -85,7 +84,7 @@ pub contract FooBar { Every resource in Cadence has a unique identifier assigned to it. We can use it to set an ID for our NFT. Here's how you can do that: ```cadence -pub contract FooBar { +access(all) contract FooBar { pub resource NFT { pub let id: UInt64 @@ -102,7 +101,7 @@ pub contract FooBar { We also need to keep track of the total supply of NFTs in existance. To do this let’s create a `totalSupply` variable on our contract and increase it by one whenever a new NFT is created. We can set this on the initialization of the NFT using the resource `init` function: ```cadence -pub contract FooBar { +access(all) contract FooBar { pub var totalSupply: UInt64 pub resource NFT { @@ -123,7 +122,7 @@ pub contract FooBar { To control the creation of NFTs, it's essential to have a mechanism that restricts their minting. This ensures that not just anyone can create an NFT and inflate its supply. To achieve this, you can introduce an `NFTMinter` resource that contains a `createNFT` function: ```cadence -pub contract FooBar { +access(all) contract FooBar { // ...[previous code]... @@ -144,7 +143,7 @@ pub contract FooBar { In this example, the `NFTMinter` resource will be stored on the contract account's storage. This means that only the contract account will have the ability to mint new NFTs. To set this up, add the following line to the contract's `init` function: ```cadence -pub contract FooBar { +access(all) contract FooBar { // ...[previous code]... @@ -162,7 +161,7 @@ Storing individual NFTs directly in an account's storage can cause issues, espec Start by creating a new resource named `Collection`. This resource will act as a container for your NFTs, storing them in a dictionary indexed by their IDs. Additionally, to ensure that all NFTs within a collection are destroyed when the collection itself is destroyed, you can add a `destroy` function: ```cadence -pub contract FooBar { +access(all) contract FooBar { // ...[NFT resource code]... @@ -245,7 +244,7 @@ pub resource Collection { For security reasons, you might not want to expose all the functions of the Collection to everyone. Instead, you can create an [interface](https://cadence-lang.org/docs/language/interfaces) that exposes only the methods you want to make public. In Cadence, interfaces act as a blueprint for resources and structures, ensuring that certain methods or properties exist. By leveraging these interfaces, you establish clear boundaries and standardized interactions. In this case, you might want to expose only the `deposit` and `getIDs` methods. This interface can then be used to create capabilities, ensuring that only the allowed methods are accessible. ```cadence -pub contract FooBar { +access(all) contract FooBar { // ...[previous code]... @@ -275,7 +274,7 @@ Begin by importing the token standard into your contract: ```cadence import "NonFungibleToken" -pub contract FooBar: NonFungibleToken { +access(all) contract FooBar: NonFungibleToken { // ...[rest of code]... @@ -293,7 +292,7 @@ For instance, when the contract is initialized, a `ContractInitialized` event sh ```cadence import "NonFungibleToken" -pub contract FooBar: NonFungibleToken { +access(all) contract FooBar: NonFungibleToken { pub event ContractInitialized() @@ -314,9 +313,9 @@ Additionally, when NFTs are withdrawn or deposited, corresponding events should ```cadence import "NonFungibleToken" -pub contract FooBar: NonFungibleToken { +access(all) contract FooBar: NonFungibleToken { - pub event ContractInitialized() + pub event ContractInitialized() pub event Withdraw(id: UInt64, from: Address?) pub event Deposit(id: UInt64, to: Address?) @@ -435,12 +434,14 @@ You’ll then see a message that says `All contracts deployed successfully`. ## Creating an NFTCollection -To manage multiple NFTs, you'll need an NFT collection. Start by creating a transaction file for this purpose: +To manage multiple NFTs, you'll need an NFT collection. Start by creating a transaction file for this purpose (we can use the `generate` command again): ```bash -touch cadence/transactions/CreateCollection.cdc +flow generate transaction CreateCollection ``` +This creates a transaction file at `cadence/transactions/CreateCollection.cdc`. + Transactions, on the other hand, are pieces of Cadence code that can mutate the state of the blockchain. Transactions need to be signed by one or more accounts, and they can have multiple phases, represented by different blocks of code. In this file, import the necessary contracts and define a transaction to create a new collection, storing it in the account's storage. Additionally, for the **`CollectionPublic`** interface, create a capability that allows others to read from its methods. This capability ensures secure, restricted access to specific functionalities or information within a resource. @@ -479,10 +480,10 @@ Congratulations! You've successfully created an NFT collection for the `test-acc To retrieve the NFTs associated with an account, you'll need a script. Scripts are read-only operations that allow you to query the blockchain. They don't modify the blockchain's state, and therefore, they don't require gas fees or signatures (read more about scripts here). -Start by creating a script file: +Start by creating a script file using the `generate` command again: ```bash -touch cadence/scripts/GetNFTs.cdc +flow generate script GetNFTs ``` In this script, import the necessary contracts and define a function that retrieves the NFT IDs associated with a given account: @@ -491,7 +492,7 @@ In this script, import the necessary contracts and define a function that retrie import "FooBar" import "NonFungibleToken" -pub fun main(account: Address): [UInt64] { +access(all) fun main(account: Address): [UInt64] { let publicReference = getAccount(account).getCapability(/public/FooBarCollection) .borrow<&FooBar.Collection{NonFungibleToken.CollectionPublic}>() ?? panic("Could not borrow public reference to FooBar") @@ -513,7 +514,7 @@ Since you haven't added any NFTs to the collection yet, the result will be an em To mint and deposit an NFT into a collection, create a new transaction file: ```bash -touch cadence/transactions/DepositNFT.cdc +flow generate transaction DepositNFT ``` In this file, define a transaction that takes a recipient's address as an argument. This transaction will borrow the minting capability from the contract account, borrow the recipient's collection capability, create a new NFT using the minter, and deposit it into the recipient's collection: @@ -552,10 +553,10 @@ You should now see a value in the `test-acct`'s collection array! ## Transferring an NFT to Another Account -To transfer an NFT to another account, create a new transaction file: +To transfer an NFT to another account, create a new transaction file using `generate`: ```bash -touch cadence/transactions/TransferNFT.cdc +flow generate transaction TransferNFT ``` In this file, define a transaction that takes a recipient's address and the ID of the NFT you want to transfer as arguments. This transaction will borrow the sender's collection, get the recipient's capability, withdraw the NFT from the sender's collection, and deposit it into the recipient's collection: @@ -679,7 +680,7 @@ import "NonFungibleToken" import "MetadataViews" import "ViewResolver" -pub contract FooBar: NonFungibleToken, ViewResolver { +access(all) contract FooBar: NonFungibleToken, ViewResolver { //...[contract code]... } ``` @@ -687,7 +688,7 @@ pub contract FooBar: NonFungibleToken, ViewResolver { Just like the NFT (except at a contract level), we’ll add functions for `getView` which returns the `Display` and `resolveViews` which tells it how to get the `Display` values: ```cadence -pub contract FooBar: NonFungibleToken, ViewResolver { +access(all) contract FooBar: NonFungibleToken, ViewResolver { //...[all code above contract init]...