diff --git a/docs/3.tutorials/nfts/0-intro.md b/docs/3.tutorials/nfts/0-intro.md index ff61c441687..e18b92bedda 100644 --- a/docs/3.tutorials/nfts/0-intro.md +++ b/docs/3.tutorials/nfts/0-intro.md @@ -15,7 +15,7 @@ To complete these tutorials successfully, you'll need: - [Rust](https://www.rust-lang.org/tools/install) - [A Testnet wallet](https://testnet.mynearwallet.com/create) -- [NEAR-CLI](/tools/near-cli#setup) +- [NEAR-CLI-RS](../../4.tools/cli-rs.md#setup) - [cargo-near](https://github.com/near/cargo-near) :::info New to Rust? @@ -36,14 +36,10 @@ These are the steps that will bring you from **_Zero_** to **_Hero_** in no time | 4 | [Upgrade a contract](/tutorials/nfts/upgrade-contract) | Discover the process to upgrade an existing smart contract. | | 5 | [Enumeration](/tutorials/nfts/enumeration) | Explore enumeration methods that can be used to return the smart contract's states. | | 6 | [Core](/tutorials/nfts/core) | Extend the NFT contract using the core standard which allows token transfer. | -| 7 | [Approvals](/tutorials/nfts/approvals) | Expand the contract allowing other accounts to transfer NFTs on your behalf. | -| 8 | [Royalty](/tutorials/nfts/royalty) | Add NFT royalties allowing for a set percentage to be paid out to the token creator. | -| 9 | [Marketplace](/tutorials/nfts/marketplace) | Learn about how common marketplaces operate on NEAR and dive into some of the code that allows buying and selling NFTs. | - - +| 7 | [Events](/tutorials/nfts/events) | The events extension, allowing the contract to react on certain events. | +| 8 | [Approvals](/tutorials/nfts/approvals) | Expand the contract allowing other accounts to transfer NFTs on your behalf. | +| 9 | [Royalty](/tutorials/nfts/royalty) | Add NFT royalties allowing for a set percentage to be paid out to the token creator. | +| 10 | [Marketplace](/tutorials/nfts/marketplace) | Learn about how common marketplaces operate on NEAR and dive into some of the code that allows buying and selling NFTs. | --- diff --git a/docs/3.tutorials/nfts/0-predeployed.md b/docs/3.tutorials/nfts/0-predeployed.md index 4bbda97ccc1..141091cae7e 100644 --- a/docs/3.tutorials/nfts/0-predeployed.md +++ b/docs/3.tutorials/nfts/0-predeployed.md @@ -10,15 +10,7 @@ Create your first non-fungible token by using a pre-deployed NFT smart contract ## Prerequisites -To complete this tutorial successfully, you'll need [a NEAR Wallet](https://testnet.mynearwallet.com/create) and [NEAR CLI](/tools/near-cli#setup) - -:::tip -You can install near-cli through the following command: - -```bash -npm install -g near-cli -``` -::: +To complete this tutorial successfully, you'll need [a NEAR Wallet](https://testnet.mynearwallet.com/create) and [NEAR CLI RS](../../4.tools/cli-rs.md#setup) --- @@ -35,7 +27,7 @@ To interact with the contract you will need to first login to your NEAR account Log in to your newly created account with `near-cli` by running the following command in your terminal: ```bash -near login +near account import-account using-web-wallet network-config testnet ``` Set an environment variable for your account ID to make it easy to copy and paste commands from this tutorial: @@ -50,10 +42,10 @@ export NEARID=YOUR_ACCOUNT_NAME We have already deployed an NFT contract to `nft.examples.testnet` which allows users to freely mint tokens. Let's use it to mint our first token. -Run this command in your terminal, remember to replace the `token_id` with a string of your choice. This string will uniquely identify the token you mint. +Run this command in your terminal, remember to replace the `token_id` with a string of your choice. This string will uniquely identify the token you mint. ```bash -near call nft.examples.testnet nft_mint '{"token_id": "TYPE_A_UNIQUE_VALUE_HERE", "receiver_id": "'$NEARID'", "metadata": { "title": "GO TEAM", "description": "The Team Goes", "media": "https://bafybeidl4hjbpdr6u6xvlrizwxbrfcyqurzvcnn5xoilmcqbxfbdwrmp5m.ipfs.dweb.link/", "copies": 1}}' --accountId $NEARID --deposit 0.1 +near contract call-function as-transaction nft.examples.testnet nft_mint json-args '{"token_id": "TYPE_A_UNIQUE_VALUE_HERE", "receiver_id": "'$NEARID'", "metadata": { "title": "GO TEAM", "description": "The Team Goes", "media": "https://bafybeidl4hjbpdr6u6xvlrizwxbrfcyqurzvcnn5xoilmcqbxfbdwrmp5m.ipfs.dweb.link/", "copies": 1}}' prepaid-gas '100.0 Tgas' attached-deposit '0.1 NEAR' sign-as $NEARID network-config testnet sign-with-legacy-keychain send ```
@@ -82,7 +74,7 @@ You can also replace the `media` URL with a link to any image file hosted on you To view tokens owned by an account you can call the NFT contract with the following `near-cli` command: ```bash -near view nft.examples.testnet nft_tokens_for_owner '{"account_id": "'$NEARID'"}' +near contract call-function as-read-only nft.examples.testnet nft_tokens_for_owner json-args '{"account_id": "'$NEARID'"}' network-config testnet now ```
@@ -134,7 +126,7 @@ Now that you're familiar with the process, you can jump to [Contract Architectur At the time of this writing, this example works with the following versions: -- near-cli: `4.0.13` -- NFT standard: [NEP171](https://nomicon.io/Standards/Tokens/NonFungibleToken/Core), version `1.1.0` +- near-cli-rs: `0.11.0` +- NFT standard: [NEP171](https://nomicon.io/Standards/Tokens/NonFungibleToken/Core), version `1.0.0` ::: diff --git a/docs/3.tutorials/nfts/1-skeleton.md b/docs/3.tutorials/nfts/1-skeleton.md index 85122bbe1d2..b7fa67f9e79 100644 --- a/docs/3.tutorials/nfts/1-skeleton.md +++ b/docs/3.tutorials/nfts/1-skeleton.md @@ -236,12 +236,12 @@ Since this source is just a skeleton you'll get many warnings about unused code, │ | ^^^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^ │ | │ = note: `#[warn(unused_imports)]` on by default - │ + │ │ warning: unused import: `Base64VecU8` │ --> src/lib.rs:4:28 │ | │ 4 | use near_sdk::json_types::{Base64VecU8, U128}; - │ | + │ | │ warning: `nft_contract_skeleton` (lib) generated 48 warnings (run `cargo fix --lib -p nft_contract_skeleton` to apply 45 suggestions) │ Finished release [optimized] target(s) in 11.01s @@ -256,13 +256,14 @@ Building the skeleton is useful to validate that your Rust toolchain works prope ## Conclusion You've seen the layout of this NFT smart contract, and how all the functions are laid out across the different source files. -Using `yarn`, you've been able to compile the contract, and you'll start fleshing out this skeleton in the next [Minting tutorial](/tutorials/nfts/minting). +Using `yarn`, you've been able to compile the contract, and you'll start fleshing out this skeleton in the next [Minting tutorial](2-minting.md). :::note Versioning for this article At the time of this writing, this example works with the following versions: - rustc: `1.76.0` - near-sdk-rs: `5.1.0` -- NFT standard: [NEP171](https://nomicon.io/Standards/Tokens/NonFungibleToken/Core), version `1.1.0` +- cargo-near: `0.6.1` +- NFT standard: [NEP171](https://nomicon.io/Standards/Tokens/NonFungibleToken/Core), version `1.0.0` ::: diff --git a/docs/3.tutorials/nfts/2-minting.md b/docs/3.tutorials/nfts/2-minting.md index 0df45b10588..13153b019a4 100644 --- a/docs/3.tutorials/nfts/2-minting.md +++ b/docs/3.tutorials/nfts/2-minting.md @@ -7,7 +7,7 @@ import {Github} from "@site/src/components/codetabs" This is the first of many tutorials in a series where you'll be creating a complete NFT smart contract from scratch that conforms with all the NEAR [NFT standards](https://nomicon.io/Standards/NonFungibleToken/). -Today you'll learn how to create the logic needed to mint NFTs and have them show up in your NEAR wallet. You will be filling a bare-bones [skeleton smart contract](/tutorials/nfts/skeleton) to add minting functionalities. +Today you'll learn how to create the logic needed to mint NFTs and have them show up in your NEAR wallet. You will be filling a bare-bones [skeleton smart contract](1-skeleton.md) to add minting functionalities. :::info Contracts You can find the skeleton contract in our [Skeleton folder](https://github.com/near-examples/nft-tutorial/tree/main/nft-contract-skeleton) @@ -19,7 +19,7 @@ A completed version of this tutorial can be found in the [Basic NFT folder](http ## Introduction -To get started, go to the `nft-contract-skeleton` folder in our repo. If you haven't cloned the repository, refer to the [Contract Architecture](/tutorials/nfts/skeleton) to get started. +To get started, go to the `nft-contract-skeleton` folder in our repo. If you haven't cloned the repository, refer to the [Contract Architecture](1-skeleton.md) to get started. ``` cd nft-contract-skeleton/ @@ -221,16 +221,16 @@ Now that the logic for minting is complete and you've added a way to query for i ### Deploying the contract {#deploy-the-contract} -For deployment, you will need a NEAR account with the keys stored on your local machine. Navigate to the [NEAR wallet](https://testnet.mynearwallet.com//) site and create an account. +For deployment, you will need a NEAR account with the keys stored on your local machine. Navigate to the [NEAR wallet](https://testnet.mynearwallet.com/) site and create an account. :::info Please ensure that you deploy the contract to an account with no pre-existing contracts. It's easiest to simply create a new account or create a sub-account for this tutorial. ::: -Log in to your newly created account with `near-cli` by running the following command in your terminal. +Log in to your newly created account with [`near-cli-rs`](../../4.tools/cli-rs.md) by running the following command in your terminal. ```bash -near login +near account import-account using-web-wallet network-config testnet ``` To make this tutorial easier to copy/paste, we're going to set an environment variable for your account ID. In the command below, replace `YOUR_ACCOUNT_NAME` with the account name you just logged in with including the `.testnet` portion: @@ -277,7 +277,7 @@ You've just deployed and initialized the contract with some default metadata and Now that the contract has been initialized, you can call some of the functions you wrote earlier. More specifically, let's test out the function that returns the contract's metadata: ```bash -near view $NFT_CONTRACT_ID nft_metadata +near contract call-function as-read-only $NFT_CONTRACT_ID nft_metadata json-args {} network-config testnet now ``` This should return an output similar to the following: @@ -314,7 +314,7 @@ Let's mint an NFT with a title, description, and media to start. The media field - **receiver_id**: "'$NFT_CONTRACT_ID'" ```bash -near call $NFT_CONTRACT_ID nft_mint '{"token_id": "token-1", "metadata": {"title": "My Non Fungible Team Token", "description": "The Team Most Certainly Goes :)", "media": "https://bafybeiftczwrtyr3k7a2k4vutd3amkwsmaqyhrdzlhvpt33dyjivufqusq.ipfs.dweb.link/goteam-gif.gif"}, "receiver_id": "'$NFT_CONTRACT_ID'"}' --accountId $NFT_CONTRACT_ID --amount 0.1 +near contract call-function as-transaction $NFT_CONTRACT_ID nft_mint json-args '{"token_id": "token-1", "metadata": {"title": "My Non Fungible Team Token", "description": "The Team Most Certainly Goes :)", "media": "https://bafybeiftczwrtyr3k7a2k4vutd3amkwsmaqyhrdzlhvpt33dyjivufqusq.ipfs.dweb.link/goteam-gif.gif"}, "receiver_id": "'$NFT_CONTRACT_ID'"}' prepaid-gas '100.0 Tgas' attached-deposit '0.1 NEAR' sign-as $NFT_CONTRACT_ID network-config testnet sign-with-legacy-keychain send ``` :::info @@ -329,7 +329,7 @@ Now that the NFT has been minted, you can check and see if everything went corre This should return a `JsonToken` which should contain the `token_id`, `owner_id`, and `metadata`. ```bash -near view $NFT_CONTRACT_ID nft_token '{"token_id": "token-1"}' +near contract call-function as-read-only $NFT_CONTRACT_ID nft_token json-args '{"token_id": "token-1"}' network-config testnet now ```
@@ -366,7 +366,7 @@ near view $NFT_CONTRACT_ID nft_token '{"token_id": "token-1"}' ## Viewing your NFTs in the wallet -If you navigate to the [collectibles tab](https://testnet.mynearwallet.com//?tab=collectibles) in the NEAR wallet, this should list all the NFTs that you own. It should look something like the what's below. +If you navigate to the [collectibles tab](https://testnet.mynearwallet.com/?tab=collectibles) in the NEAR wallet, this should list all the NFTs that you own. It should look something like the what's below. ![empty-nft-in-wallet](/docs/assets/nfts/empty-nft-in-wallet.png) @@ -388,15 +388,16 @@ After the contract was written, it was time to deploy to the blockchain. You [de ## Next Steps -In the [next tutorial](/tutorials/nfts/upgrade-contract), you'll find out how to deploy a patch fix and what that means so that you can view your NFTs in the wallet. +In the [next tutorial](2-upgrade.md), you'll find out how to deploy a patch fix and what that means so that you can view your NFTs in the wallet. :::note Versioning for this article At the time of this writing, this example works with the following versions: -- near-cli: `4.0.13` +- rustc: `1.77.1` +- near-cli-rs: `0.11.0` - cargo-near `0.6.1` -- NFT standard: [NEP171](https://nomicon.io/Standards/Tokens/NonFungibleToken/Core), version `1.1.0` +- NFT standard: [NEP171](https://nomicon.io/Standards/Tokens/NonFungibleToken/Core), version `1.0.0` - Metadata standard: [NEP177](https://nomicon.io/Standards/Tokens/NonFungibleToken/Metadata), version `2.1.0` ::: diff --git a/docs/3.tutorials/nfts/2-upgrade.md b/docs/3.tutorials/nfts/2-upgrade.md index dfffcb11a99..d5851aa386c 100644 --- a/docs/3.tutorials/nfts/2-upgrade.md +++ b/docs/3.tutorials/nfts/2-upgrade.md @@ -5,7 +5,7 @@ sidebar_label: Upgrade a Contract --- import {Github} from "@site/src/components/codetabs" -In this tutorial, you'll build off the work you previously did to implement the [minting functionality](/tutorials/nfts/minting) on a skeleton smart contract. You got to the point where NFTs could be minted and the wallet correctly picked up on the fact that you owned an NFT. However, it had no way of displaying the tokens since your contract didn't implement the method that the wallet was trying to call. +In this tutorial, you'll build off the work you previously did to implement the [minting functionality](2-minting.md) on a skeleton smart contract. You got to the point where NFTs could be minted and the wallet correctly picked up on the fact that you owned an NFT. However, it had no way of displaying the tokens since your contract didn't implement the method that the wallet was trying to call. --- @@ -52,7 +52,7 @@ cargo near deploy $NFT_CONTRACT_ID without-init-call network-config testnet sign Once the contract has been redeployed, let's test and see if the state migrated correctly by running a simple view function: ```bash -near view $NFT_CONTRACT_ID nft_metadata +near contract call-function as-read-only $NFT_CONTRACT_ID nft_metadata json-args {} network-config testnet now ``` This should return an output similar to the following: @@ -72,7 +72,7 @@ This should return an output similar to the following: **Go team!** At this point, you can now test and see if the new function you wrote works correctly. Let's query for the list of tokens that you own: ```bash -near view $NFT_CONTRACT_ID nft_tokens_for_owner '{"account_id": "'$NFT_CONTRACT_ID'", "limit": 5}' +near contract call-function as-read-only $NFT_CONTRACT_ID nft_tokens_for_owner json-args '{"account_id": "'$NFT_CONTRACT_ID'", "limit": 5}' network-config testnet now ```
@@ -109,7 +109,7 @@ near view $NFT_CONTRACT_ID nft_tokens_for_owner '{"account_id": "'$NFT_CONTRACT_ ## Viewing NFTs in the wallet {#viewing-nfts-in-wallet} -Now that your contract implements the necessary functions that the wallet uses to display NFTs, you should be able to see your tokens on display in the [collectibles tab](https://testnet.mynearwallet.com//?tab=collectibles). +Now that your contract implements the necessary functions that the wallet uses to display NFTs, you should be able to see your tokens on display in the [collectibles tab](https://testnet.mynearwallet.com/?tab=collectibles). ![filled-nft-in-wallet](/docs/assets/nfts/filled-nft-in-wallet.png) @@ -119,14 +119,15 @@ Now that your contract implements the necessary functions that the wallet uses t In this tutorial, you learned about the basics of [upgrading contracts](#upgrading-contracts). Then, you implemented the necessary [modifications to your smart contract](#modifications-to-contract) and [redeployed it](#redeploying-contract). Finally you navigated to the wallet collectibles tab and [viewed your NFTs](#viewing-nfts-in-wallet). -In the [next tutorial](/tutorials/nfts/enumeration), you'll implement the remaining functions needed to complete the [enumeration](https://nomicon.io/Standards/Tokens/NonFungibleToken/Enumeration) standard. +In the [next tutorial](3-enumeration.md), you'll implement the remaining functions needed to complete the [enumeration](https://nomicon.io/Standards/Tokens/NonFungibleToken/Enumeration) standard. :::note Versioning for this article At the time of this writing, this example works with the following versions: -- near-cli: `4.0.13` +- rustc: `1.77.1` +- near-cli-rs: `0.11.0` - cargo-near `0.6.1` -- NFT standard: [NEP171](https://nomicon.io/Standards/Tokens/NonFungibleToken/Core), version `1.1.0` +- NFT standard: [NEP171](https://nomicon.io/Standards/Tokens/NonFungibleToken/Core), version `1.0.0` ::: diff --git a/docs/3.tutorials/nfts/3-enumeration.md b/docs/3.tutorials/nfts/3-enumeration.md index 0bf26b7b2f9..52e89cadea7 100644 --- a/docs/3.tutorials/nfts/3-enumeration.md +++ b/docs/3.tutorials/nfts/3-enumeration.md @@ -5,7 +5,7 @@ sidebar_label: Enumeration --- import {Github} from "@site/src/components/codetabs" -In the previous tutorials, you looked at ways to integrate the minting functionality into a skeleton smart contract. In order to get your NFTs to show in the wallet, you also had to deploy a patch fix that implemented one of the enumeration methods. In this tutorial, you'll expand on and finish the rest of the enumeration methods as per the [standard](https://nomicon.io/Standards/Tokens/NonFungibleToken/Enumeration) +In the previous tutorials, you looked at ways to integrate the minting functionality into a skeleton smart contract. In order to get your NFTs to show in the wallet, you also had to deploy a patch fix that implemented one of the enumeration methods. In this tutorial, you'll expand on and finish the rest of the enumeration methods as per the [standard](https://nomicon.io/Standards/Tokens/NonFungibleToken/Enumeration). Now you'll extend the NFT smart contract and add a couple of enumeration methods that can be used to return the contract's state. @@ -13,13 +13,13 @@ Now you'll extend the NFT smart contract and add a couple of enumeration methods ## Introduction -As mentioned in the [Upgrade a Contract](/tutorials/nfts/upgrade-contract/) tutorial, you can deploy patches and fixes to smart contracts. This time, you'll use that knowledge to implement the `nft_total_supply`, `nft_tokens` and `nft_supply_for_owner` enumeration functions. +As mentioned in the [Upgrade a Contract](2-upgrade.md) tutorial, you can deploy patches and fixes to smart contracts. This time, you'll use that knowledge to implement the `nft_total_supply`, `nft_tokens` and `nft_supply_for_owner` enumeration functions. --- ## Modifications to the contract -Let's start by opening the `src/enumeration.rs` file and locating the empty `nft_total_supply` function. +Let's start by opening the `src/enumeration.rs` file and locating the empty `nft_total_supply` function. **nft_total_supply** @@ -68,7 +68,7 @@ Once the updated contract has been redeployed, you can test and see if these new Let's query for a list of non-fungible tokens on the contract. Use the following command to query for the information of up to 50 NFTs starting from the 10th item: ```bash -near view $NFT_CONTRACT_ID nft_tokens '{"from_index": "10", "limit": 50}' +near contract call-function as-read-only $NFT_CONTRACT_ID nft_tokens json-args '{"from_index": "10", "limit": 50}' network-config testnet now ``` This command should return an output similar to the following: @@ -91,7 +91,7 @@ This command should return an output similar to the following: To get the total supply of NFTs owned by the `goteam.testnet` account, call the `nft_supply_for_owner` function and set the `account_id` parameter: ```bash -near view $NFT_CONTRACT_ID nft_supply_for_owner '{"account_id": "goteam.testnet"}' +near contract call-function as-read-only $NFT_CONTRACT_ID nft_supply_for_owner json-args '{"account_id": "goteam.testnet"}' network-config testnet now ``` This should return an output similar to the following: @@ -113,15 +113,16 @@ This should return an output similar to the following: In this tutorial, you have added two [new enumeration functions](/tutorials/nfts/enumeration#modifications-to-the-contract), and now you have a basic NFT smart contract with minting and enumeration methods in place. After implementing these modifications, you redeployed the smart contract and tested the functions using the CLI. -In the [next tutorial](/tutorials/nfts/core), you'll implement the core functions needed to allow users to transfer the minted tokens. +In the [next tutorial](4-core.md), you'll implement the core functions needed to allow users to transfer the minted tokens. :::note Versioning for this article At the time of this writing, this example works with the following versions: -- near-cli: `4.0.13` +- rustc: `1.77.1` +- near-cli-rs: `0.11.0` - cargo-near `0.6.1` -- NFT standard: [NEP171](https://nomicon.io/Standards/Tokens/NonFungibleToken/Core), version `1.1.0` +- NFT standard: [NEP171](https://nomicon.io/Standards/Tokens/NonFungibleToken/Core), version `1.0.0` - Enumeration standard: [NEP181](https://nomicon.io/Standards/Tokens/NonFungibleToken/Enumeration), version `1.0.0` ::: diff --git a/docs/3.tutorials/nfts/4-core.md b/docs/3.tutorials/nfts/4-core.md index a9122e6946a..3d7d79c3a4f 100644 --- a/docs/3.tutorials/nfts/4-core.md +++ b/docs/3.tutorials/nfts/4-core.md @@ -22,7 +22,7 @@ We will define two methods for transferring NFTs: Up until this point, you've created a simple NFT smart contract that allows users to mint tokens and view information using the [enumeration standards](https://nomicon.io/Standards/Tokens/NonFungibleToken/Enumeration). Today, you'll expand your smart contract to allow for users to not only mint tokens, but transfer them as well. -As we did in the [minting tutorial](/tutorials/nfts/minting), let's break down the problem into multiple subtasks to make our lives easier. When a token is minted, information is stored in 3 places: +As we did in the [minting tutorial](2-minting.md), let's break down the problem into multiple subtasks to make our lives easier. When a token is minted, information is stored in 3 places: - **tokens_per_owner**: set of tokens for each account. - **tokens_by_id**: maps a token ID to a `Token` object. @@ -93,7 +93,7 @@ We want to create this function within the contract implementation (below the `i -Now let's look at the function called `internal_remove_token_from_owner`. That function implements the functionality for removing a token ID from an owner's set. +Now let's look at the function called `internal_remove_token_from_owner`. That function implements the functionality for removing a token ID from an owner's set. In the remove function, we get the set of tokens for a given account ID and then remove the passed in token ID. If the account's set is empty after the removal, we simply remove the account from the `tokens_per_owner` data structure. @@ -166,14 +166,14 @@ Let's test this out by transferring an NFT to the account `benjiman.testnet` and This means that the NFT won't be recoverable unless the account `benjiman.testnet` transfers it back to you. If you don't want your NFT lost, make a new account and transfer the token to that account instead. ::: -If you run the following command, it will transfer the token `"token-1"` to the account `benjiman.testnet` with the memo `"Go Team :)"`. Take note that you're also attaching exactly 1 yoctoNEAR by using the `--depositYocto` flag. +If you run the following command, it will transfer the token `"token-1"` to the account `benjiman.testnet` with the memo `"Go Team :)"`. Take note that you're also attaching exactly 1 yoctoNEAR by using the `--depositYocto` flag. :::tip If you used a different token ID in the previous tutorials, replace `token-1` with your token ID. ::: ```bash -near call $NFT_CONTRACT_ID nft_transfer '{"receiver_id": "benjiman.testnet", "token_id": "token-1", "memo": "Go Team :)"}' --accountId $NFT_CONTRACT_ID --depositYocto 1 +near contract call-function as-transaction $NFT_CONTRACT_ID nft_transfer json-args '{"receiver_id": "benjiman.testnet", "token_id": "token-1", "memo": "Go Team :)"}' prepaid-gas '100.0 Tgas' attached-deposit '1 yoctoNEAR' sign-as $NFT_CONTRACT_ID network-config testnet sign-with-legacy-keychain send ``` If you now query for all the tokens owned by your account, that token should be missing. Similarly, if you query for the list of tokens owned by `benjiman.testnet`, that account should now own your NFT. @@ -187,13 +187,13 @@ Now that you've tested the `nft_transfer` function, it's time to test the `nft_t First mint a new NFT that will be used to test the transfer call functionality. ```bash -near call $NFT_CONTRACT_ID nft_mint '{"token_id": "token-2", "metadata": {"title": "NFT Tutorial Token", "description": "Testing the transfer call function", "media": "https://bafybeiftczwrtyr3k7a2k4vutd3amkwsmaqyhrdzlhvpt33dyjivufqusq.ipfs.dweb.link/goteam-gif.gif"}, "receiver_id": "'$NFT_CONTRACT_ID'"}' --accountId $NFT_CONTRACT_ID --amount 0.1 +near contract call-function as-transaction $NFT_CONTRACT_ID nft_mint json-args '{"token_id": "token-2", "metadata": {"title": "NFT Tutorial Token", "description": "Testing the transfer call function", "media": "https://bafybeiftczwrtyr3k7a2k4vutd3amkwsmaqyhrdzlhvpt33dyjivufqusq.ipfs.dweb.link/goteam-gif.gif"}, "receiver_id": "'$NFT_CONTRACT_ID'"}' prepaid-gas '100.0 Tgas' attached-deposit '0.1 NEAR' sign-as $NFT_CONTRACT_ID network-config testnet sign-with-legacy-keychain send ``` Now that you've minted the token, you can try to transfer the NFT to the account `no-contract.testnet` which as the name suggests, doesn't have a contract. This means that the receiver doesn't implement the `nft_on_transfer` function and the NFT should remain yours after the transaction is complete. ```bash -near call $NFT_CONTRACT_ID nft_transfer_call '{"receiver_id": "no-contract.testnet", "token_id": "token-2", "msg": "foo"}' --accountId $NFT_CONTRACT_ID --depositYocto 1 --gas 200000000000000 +near contract call-function as-transaction $NFT_CONTRACT_ID nft_transfer_call json-args '{"receiver_id": "no-contract.testnet", "token_id": "token-2", "msg": "foo"}' prepaid-gas '100.0 Tgas' attached-deposit '1 yoctoNEAR' sign-as $NFT_CONTRACT_ID network-config testnet sign-with-legacy-keychain send ``` If you query for your tokens, you should still have `token-2` and at this point, you're finished! @@ -204,15 +204,16 @@ If you query for your tokens, you should still have `token-2` and at this point, In this tutorial, you learned how to expand an NFT contract past the minting functionality and you added ways for users to transfer NFTs. You [broke down](#introduction) the problem into smaller, more digestible subtasks and took that information and implemented both the [NFT transfer](#transfer-function) and [NFT transfer call](#transfer-call-function) functions. In addition, you deployed another [patch fix](#redeploying-contract) to your smart contract and [tested](#testing-changes) the transfer functionality. -In the [next tutorial](/tutorials/nfts/approvals), you'll learn about the approval management system and how you can approve others to transfer tokens on your behalf. +In the [next tutorial](5-approval.md), you'll learn about the approval management system and how you can approve others to transfer tokens on your behalf. :::note Versioning for this article At the time of this writing, this example works with the following versions: -- near-cli: `4.0.13` +- rustc: `1.77.1` +- near-cli-rs: `0.11.0` - cargo-near `0.6.1` -- NFT standard: [NEP171](https://nomicon.io/Standards/Tokens/NonFungibleToken/Core), version `1.1.0` +- NFT standard: [NEP171](https://nomicon.io/Standards/Tokens/NonFungibleToken/Core), version `1.0.0` - Enumeration standard: [NEP181](https://nomicon.io/Standards/Tokens/NonFungibleToken/Enumeration), version `1.0.0` ::: diff --git a/docs/3.tutorials/nfts/5-approval.md b/docs/3.tutorials/nfts/5-approval.md index 285febc0c0d..76e5f8ab787 100644 --- a/docs/3.tutorials/nfts/5-approval.md +++ b/docs/3.tutorials/nfts/5-approval.md @@ -267,7 +267,7 @@ Next, you'll deploy this contract to the network. ```bash export APPROVAL_NFT_CONTRACT_ID= -near create-account $APPROVAL_NFT_CONTRACT_ID --useFaucet +near account create-account sponsor-by-faucet-service $APPROVAL_NFT_CONTRACT_ID autogenerate-new-keypair save-to-legacy-keychain network-config testnet create ``` Using the cargo-near, deploy and initialize the contract as you did in the previous tutorials: @@ -283,13 +283,13 @@ cargo near deploy $APPROVAL_NFT_CONTRACT_ID with-init-call new_default_meta json Next, you'll need to mint a token. By running this command, you'll mint a token with a token ID `"approval-token"` and the receiver will be your new account. ```bash -near call $APPROVAL_NFT_CONTRACT_ID nft_mint '{"token_id": "approval-token", "metadata": {"title": "Approval Token", "description": "testing out the new approval extension of the standard", "media": "https://bafybeiftczwrtyr3k7a2k4vutd3amkwsmaqyhrdzlhvpt33dyjivufqusq.ipfs.dweb.link/goteam-gif.gif"}, "receiver_id": "'$APPROVAL_NFT_CONTRACT_ID'"}' --accountId $APPROVAL_NFT_CONTRACT_ID --amount 0.1 +near contract call-function as-transaction $APPROVAL_NFT_CONTRACT_ID nft_mint json-args '{"token_id": "approval-token", "metadata": {"title": "Approval Token", "description": "testing out the new approval extension of the standard", "media": "https://bafybeiftczwrtyr3k7a2k4vutd3amkwsmaqyhrdzlhvpt33dyjivufqusq.ipfs.dweb.link/goteam-gif.gif"}, "receiver_id": "'$APPROVAL_NFT_CONTRACT_ID'"}' prepaid-gas '100.0 Tgas' attached-deposit '0.1 NEAR' sign-as $APPROVAL_NFT_CONTRACT_ID network-config testnet sign-with-legacy-keychain send ``` You can check to see if everything went through properly by calling one of the enumeration functions: ```bash -near view $APPROVAL_NFT_CONTRACT_ID nft_tokens_for_owner '{"account_id": "'$APPROVAL_NFT_CONTRACT_ID'", "limit": 10}' +near contract call-function as-read-only $APPROVAL_NFT_CONTRACT_ID nft_tokens_for_owner json-args '{"account_id": "'$APPROVAL_NFT_CONTRACT_ID'", "limit": 10}' network-config testnet now ``` This should return an output similar to the following: @@ -329,13 +329,13 @@ At this point, you should have two accounts. One stored under `$NFT_CONTRACT_ID` Execute the following command to approve the account stored under `$NFT_CONTRACT_ID` to have access to transfer your NFT with an ID `"approval-token"`. You don't need to pass a message since the old account didn't implement the `nft_on_approve` function. In addition, you'll need to attach enough NEAR to cover the cost of storing the account on the contract. 0.1 NEAR should be more than enough and you'll be refunded any excess that is unused. ```bash -near call $APPROVAL_NFT_CONTRACT_ID nft_approve '{"token_id": "approval-token", "account_id": "'$NFT_CONTRACT_ID'"}' --accountId $APPROVAL_NFT_CONTRACT_ID --deposit 0.1 +near contract call-function as-transaction $APPROVAL_NFT_CONTRACT_ID nft_approve json-args '{"token_id": "approval-token", "account_id": "'$NFT_CONTRACT_ID'"}' prepaid-gas '100.0 Tgas' attached-deposit '0.1 NEAR' sign-as $NFT_CONTRACT_ID network-config testnet sign-with-legacy-keychain send ``` If you call the same enumeration method as before, you should see the new approved account ID being returned. ```bash -near view $APPROVAL_NFT_CONTRACT_ID nft_tokens_for_owner '{"account_id": "'$APPROVAL_NFT_CONTRACT_ID'", "limit": 10}' +near contract call-function as-read-only $APPROVAL_NFT_CONTRACT_ID nft_tokens_for_owner json-args '{"account_id": "'$APPROVAL_NFT_CONTRACT_ID'", "limit": 10}' network-config testnet now ``` This should return an output similar to the following: @@ -371,7 +371,7 @@ This should return an output similar to the following: Now that you've approved another account to transfer the token, you can test that behavior. You should be able to use the other account to transfer the NFT to itself by which the approved account IDs should be reset. Let's test transferring the NFT with the wrong approval ID: ```bash -near call $APPROVAL_NFT_CONTRACT_ID nft_transfer '{"receiver_id": "'$NFT_CONTRACT_ID'", "token_id": "approval-token", "approval_id": 1}' --accountId $NFT_CONTRACT_ID --depositYocto 1 +near contract call-function as-transaction $APPROVAL_NFT_CONTRACT_ID nft_transfer json-args '{"receiver_id": "'$NFT_CONTRACT_ID'", "token_id": "approval-token", "approval_id": 1}' prepaid-gas '100.0 Tgas' attached-deposit '1 yoctoNEAR' sign-as $NFT_CONTRACT_ID network-config testnet sign-with-legacy-keychain send ```
@@ -392,7 +392,7 @@ kind: { If you pass the correct approval ID which is `0`, everything should work fine. ```bash -near call $APPROVAL_NFT_CONTRACT_ID nft_transfer '{"receiver_id": "'$NFT_CONTRACT_ID'", "token_id": "approval-token", "approval_id": 0}' --accountId $NFT_CONTRACT_ID --depositYocto 1 +near contract call-function as-transaction $APPROVAL_NFT_CONTRACT_ID nft_transfer json-args '{"receiver_id": "'$NFT_CONTRACT_ID'", "token_id": "approval-token", "approval_id": 0}' prepaid-gas '100.0 Tgas' attached-deposit '1 yoctoNEAR' sign-as $NFT_CONTRACT_ID network-config testnet sign-with-legacy-keychain send ``` If you again call the enumeration method, you should see the owner updated and the approved account IDs reset. @@ -424,13 +424,13 @@ If you again call the enumeration method, you should see the owner updated and t Let's now test the approval ID incrementing across different owners. If you approve the account that originally minted the token, the approval ID should be 1 now. ```bash -near call $APPROVAL_NFT_CONTRACT_ID nft_approve '{"token_id": "approval-token", "account_id": "'$APPROVAL_NFT_CONTRACT_ID'"}' --accountId $NFT_CONTRACT_ID --deposit 0.1 +near contract call-function as-transaction $APPROVAL_NFT_CONTRACT_ID nft_approve json-args '{"token_id": "approval-token", "account_id": "'$APPROVAL_NFT_CONTRACT_ID'"}' prepaid-gas '100.0 Tgas' attached-deposit '0.1 NEAR' sign-as $NFT_CONTRACT_ID network-config testnet sign-with-legacy-keychain send ``` Calling the view function again show now return an approval ID of 1 for the account that was approved. ```bash -near view $APPROVAL_NFT_CONTRACT_ID nft_tokens_for_owner '{"account_id": "'$NFT_CONTRACT_ID'", "limit": 10}' +near contract call-function as-read-only $APPROVAL_NFT_CONTRACT_ID nft_tokens_for_owner json-args '{"account_id": "'$NFT_CONTRACT_ID'", "limit": 10}' network-config testnet now ```
@@ -484,15 +484,16 @@ You implemented a view method to [check](#check-if-account-approved) if an accou After this, the contract code was finished and it was time to move onto testing where you created an [account](#deployment) and tested the [approving](#approving-an-account) and [transferring](#transferring-the-nft) for your NFTs. -In the next tutorial, you'll learn about the royalty standards and how you can interact with NFT marketplaces. +In the [next tutorial](6-royalty.md), you'll learn about the royalty standards and how you can interact with NFT marketplaces. :::note Versioning for this article At the time of this writing, this example works with the following versions: -- near-cli: `4.0.13` +- rustc: `1.77.1` +- near-cli-rs: `0.11.0` - cargo-near `0.6.1` -- NFT standard: [NEP171](https://nomicon.io/Standards/Tokens/NonFungibleToken/Core), version `1.1.0` +- NFT standard: [NEP171](https://nomicon.io/Standards/Tokens/NonFungibleToken/Core), version `1.0.0` - Enumeration standard: [NEP181](https://nomicon.io/Standards/Tokens/NonFungibleToken/Enumeration), version `1.0.0` - Approval standard: [NEP178](https://nomicon.io/Standards/Tokens/NonFungibleToken/ApprovalManagement), version `1.1.0` diff --git a/docs/3.tutorials/nfts/6-royalty.md b/docs/3.tutorials/nfts/6-royalty.md index 378f5ac7e4d..dd3de208a80 100644 --- a/docs/3.tutorials/nfts/6-royalty.md +++ b/docs/3.tutorials/nfts/6-royalty.md @@ -111,7 +111,7 @@ At the very end, it will insert `damian` into the payout object and give him `1 Now that you know how payouts are calculated, it's time to create the function that will transfer the NFT and return the payout to the marketplace. - +
@@ -145,7 +145,7 @@ Next, you'll deploy this contract to the network. ```bash export ROYALTY_NFT_CONTRACT_ID= -near create-account $ROYALTY_NFT_CONTRACT_ID --useFaucet +near account create-account sponsor-by-faucet-service $ROYALTY_NFT_CONTRACT_ID autogenerate-new-keypair save-to-legacy-keychain network-config testnet create ``` Using the cargo-near, deploy and initialize the contract as you did in the previous tutorials: @@ -159,13 +159,13 @@ cargo near deploy $ROYALTY_NFT_CONTRACT_ID with-init-call new_default_meta json- Next, you'll need to mint a token. By running this command, you'll mint a token with a token ID `"royalty-token"` and the receiver will be your new account. In addition, you're passing in a map with two accounts that will get perpetual royalties whenever your token is sold. ```bash -near call $ROYALTY_NFT_CONTRACT_ID nft_mint '{"token_id": "royalty-token", "metadata": {"title": "Royalty Token", "description": "testing out the new royalty extension of the standard", "media": "https://bafybeiftczwrtyr3k7a2k4vutd3amkwsmaqyhrdzlhvpt33dyjivufqusq.ipfs.dweb.link/goteam-gif.gif"}, "receiver_id": "'$ROYALTY_NFT_CONTRACT_ID'", "perpetual_royalties": {"benjiman.testnet": 2000, "mike.testnet": 1000, "josh.testnet": 500}}' --accountId $ROYALTY_NFT_CONTRACT_ID --amount 0.1 +near contract call-function as-transaction $ROYALTY_NFT_CONTRACT_ID nft_mint json-args '{"token_id": "royalty-token", "metadata": {"title": "Royalty Token", "description": "testing out the new royalty extension of the standard", "media": "https://bafybeiftczwrtyr3k7a2k4vutd3amkwsmaqyhrdzlhvpt33dyjivufqusq.ipfs.dweb.link/goteam-gif.gif"}, "receiver_id": "'$ROYALTY_NFT_CONTRACT_ID'", "perpetual_royalties": {"benjiman.testnet": 2000, "mike.testnet": 1000, "josh.testnet": 500}}' prepaid-gas '100.0 Tgas' attached-deposit '0.1 NEAR' sign-as $ROYALTY_NFT_CONTRACT_ID network-config testnet sign-with-legacy-keychain send ``` You can check to see if everything went through properly by calling one of the enumeration functions: ```bash -near view $ROYALTY_NFT_CONTRACT_ID nft_tokens_for_owner '{"account_id": "'$ROYALTY_NFT_CONTRACT_ID'", "limit": 10}' +near contract call-function as-read-only $ROYALTY_NFT_CONTRACT_ID nft_tokens_for_owner json-args '{"account_id": "'$ROYALTY_NFT_CONTRACT_ID'", "limit": 10}' network-config testnet now ``` This should return an output similar to the following: @@ -206,12 +206,12 @@ Notice how there's now a royalty field that contains the 3 accounts that will ge Let's calculate the payout for the `"royalty-token"` NFT, given a balance of 100 yoctoNEAR. It's important to note that the balance being passed into the `nft_payout` function is expected to be in yoctoNEAR. ```bash -near view $ROYALTY_NFT_CONTRACT_ID nft_payout '{"token_id": "royalty-token", "balance": "100", "max_len_payout": 100}' +near contract call-function as-read-only $ROYALTY_NFT_CONTRACT_ID nft_payout json-args '{"token_id": "royalty-token", "balance": "100", "max_len_payout": 100}' network-config testnet now ``` This command should return an output similar to the following: -```bash +```js { payout: { 'josh.testnet': '5', @@ -222,7 +222,7 @@ This command should return an output similar to the following: } ``` -If the NFT was sold for 100 yoctoNEAR, josh would get 5, benji would get 20, mike would get 10, and the owner, in this case `royalty.goteam.examples.testnet` would get the rest: 65. +If the NFT was sold for 100 yoctoNEAR, josh would get 5, Benji would get 20, mike would get 10, and the owner, in this case `royalty.goteam.examples.testnet` would get the rest: 65. ## Conclusion @@ -237,9 +237,10 @@ If you want to see the finished code from this tutorial, you can go to the `nft- At the time of this writing, this example works with the following versions: -- near-cli: `4.0.13` +- rustc: `1.77.1` +- near-cli-rs: `0.11.0` - cargo-near `0.6.1` -- NFT standard: [NEP171](https://nomicon.io/Standards/Tokens/NonFungibleToken/Core), version `1.1.0` +- NFT standard: [NEP171](https://nomicon.io/Standards/Tokens/NonFungibleToken/Core), version `1.0.0` - Enumeration standard: [NEP181](https://nomicon.io/Standards/Tokens/NonFungibleToken/Enumeration), version `1.0.0` - Royalties standard: [NEP199](https://nomicon.io/Standards/Tokens/NonFungibleToken/Payout), version `2.0.0` diff --git a/docs/3.tutorials/nfts/7-events.md b/docs/3.tutorials/nfts/7-events.md index 8063636611b..093826515fd 100644 --- a/docs/3.tutorials/nfts/7-events.md +++ b/docs/3.tutorials/nfts/7-events.md @@ -10,15 +10,15 @@ In this tutorial, you'll learn about the [events standard](https://nomicon.io/St ## Understanding the use case {#understanding-the-use-case} -Have you ever wondered how the wallet knows which NFTs you own and how it can display them in the [collectibles tab](https://testnet.mynearwallet.com//?tab=collectibles)? Originally, an indexer used to listen for any functions calls starting with `nft_` on your account. These contracts were then flagged on your account as likely NFT contracts. +Have you ever wondered how the wallet knows which NFTs you own and how it can display them in the [collectibles tab](https://testnet.mynearwallet.com/?tab=collectibles)? Originally, an indexer used to listen for any functions calls starting with `nft_` on your account. These contracts were then flagged on your account as likely NFT contracts. -When you navigated to your collectibles tab, the wallet would then query all those contracts for the list of NFTs you owned using the `nft_tokens_for_owner` function you saw in the [enumeration tutorial](/tutorials/nfts/enumeration). +When you navigated to your collectibles tab, the wallet would then query all those contracts for the list of NFTs you owned using the `nft_tokens_for_owner` function you saw in the [enumeration tutorial](3-enumeration.md).
### The problem {#the-problem} -This method of flagging contracts was not reliable as each NFT-driven application might have its own way of minting or transferring NFTs. In addition, it's common for apps to transfer or mint many tokens at a time using batch functions. +This method of flagging contracts was not reliable as each NFT-driven application might have its own way of minting or transferring NFTs. In addition, it's common for apps to transfer or mint many tokens at a time using batch functions.
@@ -28,7 +28,7 @@ A standard was introduced so that smart contracts could emit an event anytime NF As per the standard, you need to implement a logging functionality that gets fired when NFTs are transferred or minted. In this case, the contract doesn't support burning so you don't need to worry about that for now. -It's important to note the standard dictates that the log should begin with `"EVENT_JSON:"`. The structure of your log should, however, always contain the 3 following things: +It's important to note the standard dictates that the log should begin with `"EVENT_JSON:"`. The structure of your log should, however, always contain the 3 following things: - **standard**: the current name of the standard (e.g. nep171) - **version**: the version of the standard you're using (e.g. 1.0.0) @@ -113,11 +113,11 @@ If you wish to see the finished code of the events implementation, that can be f ### Creating the events file {#events-rs} -Copy the following into your file. This will outline the structs for your `EventLog`, `NftMintLog`, and `NftTransferLog`. In addition, we've added a way for `EVENT_JSON:` to be prefixed whenever you log the `EventLog`. +Copy the following into your file. This will outline the structs for your `EventLog`, `NftMintLog`, and `NftTransferLog`. In addition, we've added a way for `EVENT_JSON:` to be prefixed whenever you log the `EventLog`. -This requires the `serde_json` package which you can easily add to your `nft-contract-skeleton/Cargo.toml` file: +This requires the `serde_json` package which you can easily add to your `nft-contract-skeleton/Cargo.toml` file: @@ -147,7 +147,7 @@ Let's open the `nft-contract-basic/src/internal.rs` file and navigate to the `in This solution, unfortunately, has an edge case which will break things. If an NFT is transferred via the `nft_transfer_call` function, there's a chance that the transfer will be reverted if the `nft_on_transfer` function returns `true`. Taking a look at the logic for `nft_transfer_call`, you can see why this is a problem. -When `nft_transfer_call` is invoked, it will: +When `nft_transfer_call` is invoked, it will: - Call `internal_transfer` to perform the actual transfer logic. - Initiate a cross-contract call and invoke the `nft_on_transfer` function. - Resolve the promise and perform logic in `nft_resolve_transfer`. @@ -186,7 +186,7 @@ Next, you'll deploy this contract to the network. ```bash export EVENTS_NFT_CONTRACT_ID= -near create-account $EVENTS_NFT_CONTRACT_ID --useFaucet +near account create-account sponsor-by-faucet-service $EVENTS_NFT_CONTRACT_ID autogenerate-new-keypair save-to-legacy-keychain network-config testnet create ``` Using the cargo-near, deploy and initialize the contract as you did in the previous tutorials: @@ -202,7 +202,7 @@ cargo near deploy $EVENTS_NFT_CONTRACT_ID with-init-call new_default_meta json-a Next, you'll need to mint a token. By running this command, you'll mint a token with a token ID `"events-token"` and the receiver will be your new account. In addition, you're passing in a map with two accounts that will get perpetual royalties whenever your token is sold. ```bash -near call $EVENTS_NFT_CONTRACT_ID nft_mint '{"token_id": "events-token", "metadata": {"title": "Events Token", "description": "testing out the new events extension of the standard", "media": "https://bafybeiftczwrtyr3k7a2k4vutd3amkwsmaqyhrdzlhvpt33dyjivufqusq.ipfs.dweb.link/goteam-gif.gif"}, "receiver_id": "'$EVENTS_NFT_CONTRACT_ID'"}' --accountId $EVENTS_NFT_CONTRACT_ID --amount 0.1 +near contract call-function as-transaction $EVENTS_NFT_CONTRACT_ID nft_mint json-args '{"token_id": "events-token", "metadata": {"title": "Events Token", "description": "testing out the new events extension of the standard", "media": "https://bafybeiftczwrtyr3k7a2k4vutd3amkwsmaqyhrdzlhvpt33dyjivufqusq.ipfs.dweb.link/goteam-gif.gif"}, "receiver_id": "'$EVENTS_NFT_CONTRACT_ID'"}' prepaid-gas '100.0 Tgas' attached-deposit '0.1 NEAR' sign-as $EVENTS_NFT_CONTRACT_ID network-config testnet sign-with-legacy-keychain send ``` You can check to see if everything went through properly by looking at the output in your CLI: @@ -226,7 +226,7 @@ You can see that the event was properly logged! You can now test if your transfer log works as expected by sending `benjiman.testnet` your NFT. ```bash -near call $EVENTS_NFT_CONTRACT_ID nft_transfer '{"receiver_id": "benjiman.testnet", "token_id": "events-token", "memo": "Go Team :)", "approval_id": 0}' --accountId $EVENTS_NFT_CONTRACT_ID --depositYocto 1 +near contract call-function as-transaction $EVENTS_NFT_CONTRACT_ID nft_transfer json-args '{"receiver_id": "benjiman.testnet", "token_id": "events-token", "memo": "Go Team :)", "approval_id": 0}' prepaid-gas '100.0 Tgas' attached-deposit '1 yoctoNEAR' sign-as $EVENTS_NFT_CONTRACT_ID network-config testnet sign-with-legacy-keychain send ``` This should return an output similar to the following: @@ -250,15 +250,16 @@ Hurray! At this point, your NFT contract is fully complete and the events standa Today you went through the [events standard](https://nomicon.io/Standards/Tokens/NonFungibleToken/Event) and implemented the necessary logic in your smart contract. You created events for [minting](#logging-minted-tokens) and [transferring](#logging-transfers) NFTs. You then deployed and [tested](#initialization-and-minting) your changes by minting and transferring NFTs. -In the next tutorial, you'll look at the basics of a marketplace contract and how it was built. +In the [next tutorial](8-marketplace.md), you'll look at the basics of a marketplace contract and how it was built. :::note Versioning for this article At the time of this writing, this example works with the following versions: -- near-cli: `4.0.13` +- rustc: `1.77.1` +- near-cli-rs: `0.11.0` - cargo-near `0.6.1` -- NFT standard: [NEP171](https://nomicon.io/Standards/Tokens/NonFungibleToken/Core), version `1.1.0` +- NFT standard: [NEP171](https://nomicon.io/Standards/Tokens/NonFungibleToken/Core), version `1.0.0` - Events standard: [NEP297 extension](https://nomicon.io/Standards/Tokens/NonFungibleToken/Event), version `1.1.0` ::: diff --git a/docs/3.tutorials/nfts/8-marketplace.md b/docs/3.tutorials/nfts/8-marketplace.md index fa6b39bb221..a7124347bae 100644 --- a/docs/3.tutorials/nfts/8-marketplace.md +++ b/docs/3.tutorials/nfts/8-marketplace.md @@ -5,7 +5,7 @@ sidebar_label: Marketplace --- import {Github} from "@site/src/components/codetabs" -In this tutorial, you'll learn the basics of an NFT marketplace contract where you can buy and sell non-fungible tokens for $NEAR. In the previous tutorials, you went through and created a fully fledged NFT contract that incorporates all the standards found in the [NFT standard](https://nomicon.io/Standards/NonFungibleToken). +In this tutorial, you'll learn the basics of an NFT marketplace contract where you can buy and sell non-fungible tokens for $NEAR. In the previous tutorials, you went through and created a fully fledged NFT contract that incorporates all the standards found in the [NFT standard](https://nomicon.io/Standards/NonFungibleToken). --- @@ -57,15 +57,15 @@ The first function you'll look at is the initialization function. This takes an ### Storage management model {#storage-management-model} -Next, let's talk about the storage management model chosen for this contract. On the NFT contract, users attached $NEAR to the calls that needed storage paid for. For example, if someone was minting an NFT, they would need to attach `x` amount of NEAR to cover the cost of storing the data on the contract. +Next, let's talk about the storage management model chosen for this contract. On the NFT contract, users attached $NEAR to the calls that needed storage paid for. For example, if someone was minting an NFT, they would need to attach `x` amount of NEAR to cover the cost of storing the data on the contract. -On this marketplace contract, however, the storage model is a bit different. Users will need to deposit $NEAR onto the marketplace to cover the storage costs. Whenever someone puts an NFT for sale, the marketplace needs to store that information which costs $NEAR. Users can either deposit as much NEAR as they want so that they never have to worry about storage again or they can deposit the minimum amount to cover 1 sale on an as-needed basis. +On this marketplace contract, however, the storage model is a bit different. Users will need to deposit $NEAR onto the marketplace to cover the storage costs. Whenever someone puts an NFT for sale, the marketplace needs to store that information which costs $NEAR. Users can either deposit as much NEAR as they want so that they never have to worry about storage again or they can deposit the minimum amount to cover 1 sale on an as-needed basis. You might be thinking about the scenario when a sale is purchased. What happens to the storage that is now being released on the contract? This is why we've introduced a storage withdrawal function. This allows users to withdraw any excess storage that is not being used. Let's go through some scenarios to understand the logic. The required storage for 1 sale is 0.01 NEAR on the marketplace contract. **Scenario A** -- Benji wants to list his NFT on the marketplace but has never paid for storage. +- Benji wants to list his NFT on the marketplace but has never paid for storage. - He deposits exactly 0.01 NEAR using the `storage_deposit` method. This will cover 1 sale. - He lists his NFT on the marketplace and is now using up 1 out of his prepaid 1 sales and has no more storage left. If he were to call `storage_withdraw`, nothing would happen. - Dorian loves his NFT and quickly purchases it before anybody else can. This means that Benji's sale has now been taken down (since it was purchased) and Benji is using up 0 out of his prepaid 1 sales. In other words, he has an excess of 1 sale or 0.01 NEAR. @@ -170,13 +170,12 @@ Next, you'll deploy this contract to the network. ```bash export MARKETPLACE_CONTRACT_ID= -near create-account $MARKETPLACE_CONTRACT_ID --useFaucet +near account create-account sponsor-by-faucet-service $MARKETPLACE_CONTRACT_ID autogenerate-new-keypair save-to-legacy-keychain network-config testnet create ``` Using the build script, deploy the contract as you did in the previous tutorials: ```bash -near deploy $MARKETPLACE_CONTRACT_ID out/market.wasm cargo near deploy $MARKETPLACE_CONTRACT_ID with-init-call new json-args '{"owner_id": "'$MARKETPLACE_CONTRACT_ID'"}' prepaid-gas '100.0 Tgas' attached-deposit '0 NEAR' network-config testnet sign-with-keychain send ``` @@ -187,9 +186,11 @@ cargo near deploy $MARKETPLACE_CONTRACT_ID with-init-call new json-args '{"owner Let's mint a new NFT token and approve a marketplace contract: ```bash -near call $NFT_CONTRACT_ID nft_mint '{"token_id": "token-1", "metadata": {"title": "My Non Fungible Team Token", "description": "The Team Most Certainly Goes :)", "media": "https://bafybeiftczwrtyr3k7a2k4vutd3amkwsmaqyhrdzlhvpt33dyjivufqusq.ipfs.dweb.link/goteam-gif.gif"}, "receiver_id": "'$NFT_CONTRACT_ID'"}' --accountId $NFT_CONTRACT_ID --amount 0.1 +near contract call-function as-transaction $NFT_CONTRACT_ID nft_mint json-args '{"token_id": "token-1", "metadata": {"title": "My Non Fungible Team Token", "description": "The Team Most Certainly Goes :)", "media": "https://bafybeiftczwrtyr3k7a2k4vutd3amkwsmaqyhrdzlhvpt33dyjivufqusq.ipfs.dweb.link/goteam-gif.gif"}, "receiver_id": "'$NFT_CONTRACT_ID'"}' prepaid-gas '100.0 Tgas' attached-deposit '0.1 NEAR' sign-as $NFT_CONTRACT_ID network-config testnet sign-with-legacy-keychain send +``` -near call $NFT_CONTRACT_ID nft_approve '{"token_id": "token-1", "account_id": "'$MARKETPLACE_CONTRACT_ID'"}' --accountId $NFT_CONTRACT_ID --deposit 0.1 +```bash +near contract call-function as-transaction $NFT_CONTRACT_ID nft_approve json-args '{"token_id": "token-1", "account_id": "'$MARKETPLACE_CONTRACT_ID'"}' prepaid-gas '100.0 Tgas' attached-deposit '0.1 NEAR' sign-as $NFT_CONTRACT_ID network-config testnet sign-with-legacy-keychain send ```
@@ -197,7 +198,7 @@ near call $NFT_CONTRACT_ID nft_approve '{"token_id": "token-1", "account_id": "' ### Listing NFT on sale ```bash -near call $MARKETPLACE_CONTRACT_ID list_nft_for_sale '{"nft_contract_id": "'$NFT_CONTRACT_ID'", "token_id": "token-1", "approval_id": 0, "msg": "{\"sale_conditions\": \"1\"}"}' --accountId $NFT_CONTRACT_ID --gas 30000000000000 +near contract call-function as-transaction $MARKETPLACE_CONTRACT_ID list_nft_for_sale json-args '{"nft_contract_id": "'$NFT_CONTRACT_ID'", "token_id": "token-1", "approval_id": 0, "msg": "{\"sale_conditions\": \"1\"}"}' prepaid-gas '300.0 Tgas' attached-deposit '0 NEAR' sign-as $NFT_CONTRACT_ID network-config testnet sign-with-legacy-keychain send ```
@@ -207,7 +208,7 @@ near call $MARKETPLACE_CONTRACT_ID list_nft_for_sale '{"nft_contract_id": "'$NFT To query for the total supply of NFTs listed on the marketplace, you can call the `get_supply_sales` function. An example can be seen below. ```bash -near view $MARKETPLACE_CONTRACT_ID get_supply_sales +near contract call-function as-read-only $MARKETPLACE_CONTRACT_ID get_supply_sales json-args {} network-config testnet now ```
@@ -217,7 +218,7 @@ near view $MARKETPLACE_CONTRACT_ID get_supply_sales To query for the total supply of NFTs listed by a specific owner on the marketplace, you can call the `get_supply_by_owner_id` function. An example can be seen below. ```bash -near view $MARKETPLACE_CONTRACT_ID get_supply_by_owner_id '{"account_id": "'$NFT_CONTRACT_ID'"}' +near contract call-function as-read-only $MARKETPLACE_CONTRACT_ID get_supply_by_owner_id json-args '{"account_id": "'$NFT_CONTRACT_ID'"}' network-config testnet now ```
@@ -227,7 +228,7 @@ near view $MARKETPLACE_CONTRACT_ID get_supply_by_owner_id '{"account_id": "'$NFT To query for the total supply of NFTs that belong to a specific contract, you can call the `get_supply_by_nft_contract_id` function. An example can be seen below. ```bash -near view $MARKETPLACE_CONTRACT_ID get_supply_by_nft_contract_id '{"nft_contract_id": "'$NFT_CONTRACT_ID'"}' +near contract call-function as-read-only $MARKETPLACE_CONTRACT_ID get_supply_by_nft_contract_id json-args '{"nft_contract_id": "'$NFT_CONTRACT_ID'"}' network-config testnet now ```
@@ -237,30 +238,30 @@ near view $MARKETPLACE_CONTRACT_ID get_supply_by_nft_contract_id '{"nft_contract To query for important information for a specific listing, you can call the `get_sale` function. This requires that you pass in the `nft_contract_token`. This is essentially the unique identifier for sales on the market contract as explained earlier. It consists of the NFT contract followed by a `DELIMITER` followed by the token ID. In this contract, the `DELIMITER` is simply a period: `.`. An example of this query can be seen below. ```bash -near view $MARKETPLACE_CONTRACT_ID get_sale '{"nft_contract_token": "'$NFT_CONTRACT_ID'.token-1"}' +near contract call-function as-read-only $MARKETPLACE_CONTRACT_ID get_sale json-args '{"nft_contract_token": "'$NFT_CONTRACT_ID'.token-1"}' network-config testnet now ``` In addition, you can query for paginated information about the listings for a given owner by calling the `get_sales_by_owner_id` function. ```bash -near view $MARKETPLACE_CONTRACT_ID get_sales_by_owner_id '{"account_id": "'$NFT_CONTRACT_ID'", "from_index": "0", "limit": 5}' +near contract call-function as-read-only $MARKETPLACE_CONTRACT_ID get_sales_by_owner_id json-args '{"account_id": "'$NFT_CONTRACT_ID'", "from_index": "0", "limit": 5}' network-config testnet now ``` Finally, you can query for paginated information about the listings that originate from a given NFT contract by calling the `get_sales_by_nft_contract_id` function. ```bash -near view $MARKETPLACE_CONTRACT_ID get_sales_by_nft_contract_id '{"nft_contract_id": "'$NFT_CONTRACT_ID'", "from_index": "0", "limit": 5}' +near contract call-function as-read-only $MARKETPLACE_CONTRACT_ID get_sales_by_nft_contract_id json-args '{"nft_contract_id": "'$NFT_CONTRACT_ID'", "from_index": "0", "limit": 5}' network-config testnet now ``` --- ## Conclusion -In this tutorial, you learned about the basics of a marketplace contract and how it works. You went through the [lib.rs](#lib-rs) file and learned about the [initialization function](#initialization-function) in addition to the [storage management](#storage-management-model) model. +In this tutorial, you learned about the basics of a marketplace contract and how it works. You went through the [lib.rs](#lib-rs) file and learned about the [initialization function](#initialization-function) in addition to the [storage management](#storage-management-model) model. You went through the [NFTs listing process](#listing-logic). In addition, you went through some important functions needed after you've listed an NFT. This includes [removing sales](#removing-sales), [updating the price](#updating-price), and [purchasing NFTs](#purchasing-nfts). -Finally, you went through the enumeration methods found in the [`sale_view`](#sale_view-rs) file. These allow you to query for important information found on the marketplace contract. +Finally, you went through the enumeration methods found in the [`sale_view`](#sale_view-rs) file. These allow you to query for important information found on the marketplace contract. You should now have a solid understanding of NFTs and marketplaces on NEAR. Feel free to branch off and expand on these contracts to create whatever cool applications you'd like. In the [next tutorial](9-series.md), you'll learn how to take the existing NFT contract and optimize it to allow for: - Lazy Minting @@ -272,8 +273,9 @@ You should now have a solid understanding of NFTs and marketplaces on NEAR. Feel At the time of this writing, this example works with the following versions: -- near-cli: `4.0.13` +- rustc: `1.77.1` +- near-cli-rs: `0.11.0` - cargo-near `0.6.1` -- NFT standard: [NEP171](https://nomicon.io/Standards/Tokens/NonFungibleToken/Core), version `1.1.0` +- NFT standard: [NEP171](https://nomicon.io/Standards/Tokens/NonFungibleToken/Core), version `1.0.0` ::: diff --git a/docs/3.tutorials/nfts/9-series.md b/docs/3.tutorials/nfts/9-series.md index 93cd10aca17..0b86a06266c 100644 --- a/docs/3.tutorials/nfts/9-series.md +++ b/docs/3.tutorials/nfts/9-series.md @@ -6,10 +6,10 @@ sidebar_label: Lazy Minting, Collections, and More! import {Github} from "@site/src/components/codetabs" In this tutorial, you'll learn how to take the [existing NFT contract](https://github.com/near-examples/nft-tutorial) you've been working with and modify it to meet some of the most common needs in the ecosystem. This includes: -- Lazy Minting NFTs -- Creating Collections -- Restricting Minting Access -- Highly Optimizing Storage +- [Lazy Minting NFTs](#lazy-minting) +- [Creating Collections](#nft-collections-and-series) +- [Restricting Minting Access](#restricted-access) +- [Highly Optimizing Storage](#modifying-view-calls-for-optimizations) - Hacking Enumeration Methods --- @@ -18,7 +18,7 @@ In this tutorial, you'll learn how to take the [existing NFT contract](https://g Now that you have a deeper understanding of basic NFT smart contracts, we can start to get creative and implement more unique features. The basic contract works really well for simple use-cases but as you begin to explore the potential of NFTs, you can use it as a foundation to build upon. -A fun analogy would be that you now have a standard muffin recipe and it's now up to you to decide how to alter it to create your own delicious varieties, may I suggest blueberry perhaps. +A fun analogy would be that you now have a standard muffin recipe and it's now up to you to decide how to alter it to create your own delicious varieties, may I suggest blueberry perhaps. Below we've created a few of these new varieties by showing potential solutions to the problems outlined above. As we demonstrate how to customize the basic NFT contract, we hope it activates your ingenuity thus introducing you to what's possible and helping you discover the true potential of NFTs. 💪 @@ -32,7 +32,7 @@ NFT Collections help solve two common problems when dealing with the basic NFT c The concept of a collection in the NFT space has a very loose meaning and can be interpreted in many different ways. In our case, we'll define a collection as a set of tokens that share **similar metadata**. For example, you could create a painting and want 100 identical copies to be put for sale. In this case, all one hundred pieces would be part of the same *collection*. Each piece would have the same artist, title, description, media etc. -One of the biggest problems with the basic NFT contract is that you store similar data many times. If you mint NFTs, the contract will store the metadata individually for **every single token ID**. We can fix this by introducing the idea of NFT series, or NFT collection. +One of the biggest problems with the basic NFT contract is that you store similar data many times. If you mint NFTs, the contract will store the metadata individually for **every single token ID**. We can fix this by introducing the idea of NFT series, or NFT collection. A series can be thought of as a bucket of token IDs that *all* share similar information. This information is specified when the series is **created** and can be the metadata, royalties, price etc. Rather than storing this information for **every token ID**, you can simply store it once in the series and then associate token IDs with their respective buckets. @@ -54,9 +54,9 @@ On the other hand, you can also be an approved creator. This allows you to defin Lazy minting allows users to mint *on demand*. Rather than minting all the NFTs and spending $NEAR on storage, you can instead mint the tokens **when they are purchased**. This helps to avoid burning unnecessary Gas and saves on storage for when not all the NFTs are purchased. Let's look at a common scenario to help solidify your understanding: -Benji has created an amazing digital painting of the famous Go Team gif. He wants to sell 1000 copies of it for 1 $NEAR each. Using the traditional approach, he would have to mint each copy individually and pay for the storage himself. He would then need to either find or deploy a marketplace contract and pay for the storage to put 1000 copies up for sale. He would need to burn Gas putting each token ID up for sale 1 by 1. +Benji has created an amazing digital painting of the famous Go Team gif. He wants to sell 1000 copies of it for 1 $NEAR each. Using the traditional approach, he would have to mint each copy individually and pay for the storage himself. He would then need to either find or deploy a marketplace contract and pay for the storage to put 1000 copies up for sale. He would need to burn Gas putting each token ID up for sale 1 by 1. -After that, people would purchase the NFTs, and there would be no guarantee that all or even any would be sold. There's a real possibility that nobody buys a single piece of his artwork, and Benji spent all that time, effort and money on nothing. +After that, people would purchase the NFTs, and there would be no guarantee that all or even any would be sold. There's a real possibility that nobody buys a single piece of his artwork, and Benji spent all that time, effort and money on nothing. Lazy minting would allow the NFTs to be *automatically minted on-demand*. Rather than having to purchase NFTs from a marketplace, Benji could specify a price on the NFT contract and a user could directly call the `nft_mint` function whereby the funds would be distributed to Benji's account directly. @@ -68,7 +68,7 @@ With this example laid out, a high level overview of lazy minting is that it giv ## New Contract File Structure -Let's now take a look at how we've implemented solutions to the issues we've discussed so far. +Let's now take a look at how we've implemented solutions to the issues we've discussed so far. In your locally cloned example of the [`nft-tutorial`](https://github.com/near-examples/nft-tutorial) check out the `main` branch and be sure to pull the most recent version. @@ -96,7 +96,7 @@ src ## Differences -You'll notice that most of this code is the same, however, there are a few differences between this contract and the basic NFT contract. +You'll notice that most of this code is the same, however, there are a few differences between this contract and the basic NFT contract. ### Main Library File @@ -169,13 +169,13 @@ Next, we'll look at the minting function. If you remember from before, this used - Token ID - Metadata - Receiver ID -- Perpetual Royalties +- Perpetual Royalties With the new and improved minting function, these parameters have been changed to just two: - The series ID - The receiver ID. -The mint function might look complicated at first but let's break it down to understand what's happening. The first thing it does is get the [series object](#series-object) from the specified series ID. From there, it will check that the number of copies won't be exceeded if one is specified in the metadata. +The mint function might look complicated at first but let's break it down to understand what's happening. The first thing it does is get the [series object](#series-object) from the specified series ID. From there, it will check that the number of copies won't be exceeded if one is specified in the metadata. It will then store the token information on the contract as explained in the [minting section](2-minting.md#storage-implications) of the tutorial and map the token ID to the series. Once this is finished, a mint log will be emitted and it will ensure that enough deposit has been attached to the call. This amount differs based on whether or not the series has a price. @@ -211,15 +211,29 @@ The common practice is to return everything **except** the `UnorderedSet` in a s The view functions are listed below. - **[get_series_total_supply](https://github.com/near-examples/nft-tutorial/blob/main/nft-series/src/enumeration.rs#L92)**: Get the total number of series currently on the contract. - Arguments: None. + + + - **[get_series](https://github.com/near-examples/nft-tutorial/blob/main/nft-series/src/enumeration.rs#L97)**: Paginate through all the series in the contract and return a vector of `JsonSeries` objects. - Arguments: `from_index: String | null`, `limit: number | null`. + + + - **[get_series_details](https://github.com/near-examples/nft-tutorial/blob/main/nft-series/src/enumeration.rs#L115)**: Get the `JsonSeries` details for a specific series. - Arguments: `id: number`. + + + - **[nft_supply_for_series](https://github.com/near-examples/nft-tutorial/blob/main/nft-series/src/enumeration.rs#L133)**: View the total number of NFTs minted for a specific series. - Arguments: `id: number`. + + + - **[nft_tokens_for_series](https://github.com/near-examples/nft-tutorial/blob/main/nft-series/src/enumeration.rs#L146)**: Paginate through all NFTs for a specific series and return a vector of `JsonToken` objects. - Arguments: `id: number`, `from_index: String | null`, `limit: number | null`. + + :::info Notice how with every pagination function, we've also included a getter to view the total supply. This is so that you can use the `from_index` and `limit` parameters of the pagination functions in conjunction with the total supply so you know where to end your pagination. ::: @@ -239,10 +253,10 @@ To do this, here's a way of modifying the `nft_token` function as it's central t For example if a token had a title `"My Amazing Go Team Gif"` and the NFT was edition 42, the new title returned would be `"My Amazing Go Team Gif - 42"`. If the NFT didn't have a title in the metadata, the series and edition number would be returned in the form of `Series {} : Edition {}`. While this is a small optimization, this idea is extremely powerful as you can potentially save on a ton of storage. As an example: most of the time NFTs don't utilize the following fields in their metadata. -- issued_at -- expires_at -- starts_at -- updated_at +- `issued_at` +- `expires_at` +- `starts_at` +- `updated_at` As an optimization, you could change the token metadata that's **stored** on the contract to not include these fields but then when returning the information in `nft_token`, you could simply add them in as `null` values. @@ -277,7 +291,7 @@ Next, you'll deploy this contract to the network. ```bash export NFT_CONTRACT_ID= -near create-account $NFT_CONTRACT_ID --useFaucet +near account create-account sponsor-by-faucet-service $NFT_CONTRACT_ID autogenerate-new-keypair save-to-legacy-keychain network-config testnet create ``` Check if this worked correctly by echoing the environment variable. @@ -292,17 +306,19 @@ cargo near deploy $NFT_CONTRACT_ID with-init-call new_default_meta json-args '{" If you now query for the metadata of the contract, it should return our default metadata. ```bash -near view $NFT_CONTRACT_ID nft_metadata +near contract call-function as-read-only $NFT_CONTRACT_ID nft_metadata json-args {} network-config testnet now ``` --- ## Creating The Series -The next step is to create two different series. One will have a price for lazy minting and the other will simply be a basic series with no price. The first step is to create an owner [sub-account](../../4.tools/cli.md#create-a-sub-account) that you can use to create both series +The next step is to create two different series. One will have a price for lazy minting and the other will simply be a basic series with no price. The first step is to create an owner [sub-account](../../4.tools/cli-rs.md#accounts) that you can use to create both series ```bash -near create-account owner.$NFT_CONTRACT_ID --masterAccount $NFT_CONTRACT_ID --initialBalance 3 && export SERIES_OWNER=owner.$NFT_CONTRACT_ID +export SERIES_OWNER=owner.$NFT_CONTRACT_ID + +near account create-account fund-myself $SERIES_OWNER '3 NEAR' autogenerate-new-keypair save-to-legacy-keychain sign-as $NFT_CONTRACT_ID network-config testnet sign-with-legacy-keychain send ``` ### Basic Series @@ -310,25 +326,28 @@ near create-account owner.$NFT_CONTRACT_ID --masterAccount $NFT_CONTRACT_ID --in You'll now need to create the simple series with no price and no royalties. If you try to run the following command before adding the owner account as an approved creator, the contract should throw an error. ```bash -near call $NFT_CONTRACT_ID create_series '{"id": 1, "metadata": {"title": "SERIES!", "description": "testing out the new series contract", "media": "https://bafybeiftczwrtyr3k7a2k4vutd3amkwsmaqyhrdzlhvpt33dyjivufqusq.ipfs.dweb.link/goteam-gif.gif"}}' --accountId $SERIES_OWNER --amount 1 +near contract call-function as-transaction $NFT_CONTRACT_ID create_series json-args '{"id": 1, "metadata": {"title": "SERIES!", "description": "testing out the new series contract", "media": "https://bafybeiftczwrtyr3k7a2k4vutd3amkwsmaqyhrdzlhvpt33dyjivufqusq.ipfs.dweb.link/goteam-gif.gif"}}' prepaid-gas '100.0 Tgas' attached-deposit '1 NEAR' sign-as $SERIES_OWNER network-config testnet sign-with-legacy-keychain send ``` The expected output is an error thrown: `ExecutionError: 'Smart contract panicked: only approved creators can add a type`. If you now add the series owner as a creator, it should work. ```bash -near call $NFT_CONTRACT_ID add_approved_creator '{"account_id": "'$SERIES_OWNER'"}' --accountId $NFT_CONTRACT_ID +near contract call-function as-transaction $NFT_CONTRACT_ID add_approved_creator json-args '{"account_id": "'$SERIES_OWNER'"}' prepaid-gas '100.0 Tgas' attached-deposit '0 NEAR' sign-as $NFT_CONTRACT_ID network-config testnet sign-with-legacy-keychain send ``` + ```bash -near call $NFT_CONTRACT_ID create_series '{"id": 1, "metadata": {"title": "SERIES!", "description": "testing out the new series contract", "media": "https://bafybeiftczwrtyr3k7a2k4vutd3amkwsmaqyhrdzlhvpt33dyjivufqusq.ipfs.dweb.link/goteam-gif.gif"}}' --accountId $SERIES_OWNER --amount 1 +near contract call-function as-transaction $NFT_CONTRACT_ID create_series json-args '{"id": 1, "metadata": {"title": "SERIES!", "description": "testing out the new series contract", "media": "https://bafybeiftczwrtyr3k7a2k4vutd3amkwsmaqyhrdzlhvpt33dyjivufqusq.ipfs.dweb.link/goteam-gif.gif"}}' prepaid-gas '100.0 Tgas' attached-deposit '1 NEAR' sign-as $SERIES_OWNER network-config testnet sign-with-legacy-keychain send ``` If you now query for the series information, it should work! ```bash -near view $NFT_CONTRACT_ID get_series +near contract call-function as-read-only $NFT_CONTRACT_ID get_series json-args {} network-config testnet now ``` + Which should return something similar to: -```bash + +```js [ { series_id: 1, @@ -356,20 +375,21 @@ Which should return something similar to: ### Series With a Price -Now that you've created the first, simple series, let's create the second one that has a price of 1 $NEAR associated with it. +Now that you've created the first, simple series, let's create the second one that has a price of 1 $NEAR associated with it. ```bash -near call $NFT_CONTRACT_ID create_series '{"id": 2, "metadata": {"title": "COMPLEX SERIES!", "description": "testing out the new contract with a complex series", "media": "https://bafybeiftczwrtyr3k7a2k4vutd3amkwsmaqyhrdzlhvpt33dyjivufqusq.ipfs.dweb.link/goteam-gif.gif"}, "price": "500000000000000000000000"}' --accountId $SERIES_OWNER --amount 1 +near contract call-function as-transaction $NFT_CONTRACT_ID create_series json-args '{"id": 2, "metadata": {"title": "COMPLEX SERIES!", "description": "testing out the new contract with a complex series", "media": "https://bafybeiftczwrtyr3k7a2k4vutd3amkwsmaqyhrdzlhvpt33dyjivufqusq.ipfs.dweb.link/goteam-gif.gif"}, "price": "500000000000000000000000"}' prepaid-gas '100.0 Tgas' attached-deposit '1 NEAR' sign-as $SERIES_OWNER network-config testnet sign-with-legacy-keychain send ``` If you now paginate through the series again, you should see both appear. + ```bash -near view $NFT_CONTRACT_ID get_series +near contract call-function as-read-only $NFT_CONTRACT_ID get_series json-args {} network-config testnet now ``` Which has -```bash +```js [ { series_id: 1, @@ -419,7 +439,9 @@ Which has Now that you have both series created, it's time to now mint some NFTs. You can either login with an existing NEAR wallet using [`near login`](../../4.tools/cli.md#near-login) or you can create a sub-account of the NFT contract. In our case, we'll use a sub-account. ```bash -near create-account buyer.$NFT_CONTRACT_ID --masterAccount $NFT_CONTRACT_ID --initialBalance 1 && export BUYER_ID=buyer.$NFT_CONTRACT_ID +export BUYER_ID=buyer.$NFT_CONTRACT_ID + +near account create-account fund-myself $BUYER_ID '1 NEAR' autogenerate-new-keypair save-to-legacy-keychain sign-as $NFT_CONTRACT_ID network-config testnet sign-with-legacy-keychain send ``` ### Lazy Minting @@ -434,13 +456,13 @@ export NFT_RECEIVER_ID=YOUR_ACCOUNT_ID_HERE Now if you try and run the mint command but don't attach enough $NEAR, it should throw an error. ```bash -near call $NFT_CONTRACT_ID nft_mint '{"id": "2", "receiver_id": "'$NFT_RECEIVER_ID'"}' --accountId $BUYER_ID +near contract call-function as-transaction $NFT_CONTRACT_ID nft_mint json-args '{"id": "2", "receiver_id": "'$NFT_RECEIVER_ID'"}' prepaid-gas '100.0 Tgas' attached-deposit '0 NEAR' sign-as $BUYER_ID network-config testnet sign-with-legacy-keychain send ``` Run the command again but this time, attach 1.5 $NEAR. ```bash -near call $NFT_CONTRACT_ID nft_mint '{"id": "2", "receiver_id": "'$NFT_RECEIVER_ID'"}' --accountId $BUYER_ID --amount 0.6 +near contract call-function as-transaction $NFT_CONTRACT_ID nft_mint json-args '{"id": "2", "receiver_id": "'$NFT_RECEIVER_ID'"}' prepaid-gas '100.0 Tgas' attached-deposit '1.5 NEAR' sign-as $BUYER_ID network-config testnet sign-with-legacy-keychain send ``` This should output the following logs. @@ -454,7 +476,7 @@ https://testnet.nearblocks.io/txns/FxWLFGuap7SFrUPLskVr7Uxxq8hpDtAG76AvshWppBVC '' ``` -If you check the explorer link, it should show that the owner received on the order of `0.59305 $NEAR`. +If you check the explorer link, it should show that the owner received on the order of `0.59305 $NEAR`. @@ -465,19 +487,19 @@ If you check the explorer link, it should show that the owner received on the or If you try to mint the NFT for the simple series with no price, it should throw an error saying you're not an approved minter. ```bash -near call $NFT_CONTRACT_ID nft_mint '{"id": "1", "receiver_id": "'$NFT_RECEIVER_ID'"}' --accountId $BUYER_ID --amount 0.1 +near contract call-function as-transaction $NFT_CONTRACT_ID nft_mint json-args '{"id": "1", "receiver_id": "'$NFT_RECEIVER_ID'"}' prepaid-gas '100.0 Tgas' attached-deposit '0.1 NEAR' sign-as $BUYER_ID network-config testnet sign-with-legacy-keychain send ``` Go ahead and run the following command to add the buyer account as an approved minter. ```bash -near call $NFT_CONTRACT_ID add_approved_minter '{"account_id": "'$BUYER_ID'"}' --accountId $NFT_CONTRACT_ID +near contract call-function as-transaction $NFT_CONTRACT_ID add_approved_minter json-args '{"account_id": "'$BUYER_ID'"}' prepaid-gas '100.0 Tgas' attached-deposit '0 NEAR' sign-as $NFT_CONTRACT_ID network-config testnet sign-with-legacy-keychain send ``` If you now run the mint command again, it should work. ```bash -near call $NFT_CONTRACT_ID nft_mint '{"id": "1", "receiver_id": "'$NFT_RECEIVER_ID'"}' --accountId $BUYER_ID --amount 0.1 +near contract call-function as-transaction $NFT_CONTRACT_ID nft_mint json-args '{"id": "1", "receiver_id": "'$NFT_RECEIVER_ID'"}' prepaid-gas '100.0 Tgas' attached-deposit '0.1 NEAR' sign-as $BUYER_ID network-config testnet sign-with-legacy-keychain send ```
@@ -504,8 +526,9 @@ Thank you so much for going through this journey with us! I wish you all the bes At the time of this writing, this example works with the following versions: -- near-cli: `4.0.13` +- rustc: `1.77.1` +- near-cli-rs: `0.11.0` - cargo-near `0.6.1` -- NFT standard: [NEP171](https://nomicon.io/Standards/Tokens/NonFungibleToken/Core), version `1.1.0` +- NFT standard: [NEP171](https://nomicon.io/Standards/Tokens/NonFungibleToken/Core), version `1.0.0` :::