Muhammad Adeel Hussain
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    ## Rust And NEAR: An Introduction Here is a todo list for you to follow. ## ToDo List: - [ ] ToDos - [ ] Download and Install Rustup and Cargo - [ ] Explore Rusts and Test - [ ] Explore NEAR - [ ] Explore NEAR-SDK - [ ] Explore NFTs using NEAR ### Rust Setup: For the purpose of this introduction to Rust and NEAR I am assuming that you have the basic setup of Rust complete on your machine, and you can build and run, a hello world program through Cargo.If not, you can install `rustup` from [here](https://www.Rust-lang.org/tools/install "Rust Installation"). Let's get started. ### Outline: 1. Cargo Introduction. 2. Rust Syntax. (Functions, Variable, Data_Types). 3. Rust Tests. 4. NEAR Setup. 5. Introduction to NEAR SDK. 6. Basic Contract. 7. NFT. 8. NFT Using NEAR. #### Cargo Introduction Cargo is Rust's package manager. It provides an interface to build, run and test Rust programs. It makes the life of Rust developer a lot easier when it comes to package management and adding dependencies to your project. You will see that in a while when adding the NEAR SDK to your project. It is always better you take a look at Rust [crates registry](https://crates.io/) before trying to implement things from scratch. To start a new project, for an executable, all you have to do is run ```console Cargo new [project_name] ``` In our case the project name will be `intro_to_rust_near`. Some other useful Cargo commands are as follows. ```console Cargo run Cargo build Cargo test ``` These are used to run, build and test our project, we will go through some of the extra flags we can add when we need them. Cargo uses a file called `Cargo.toml`(Tom's Obvious Minimal Language.). To manage dependencies, versioning and if the crate is library or an executable. A basic toml file when you run `Cargo new` looks like this. ```toml [package] name = "intro_to_rust_near" version = "0.1.0" edition = "2018" # See more keys and their definitions at https://doc.Rust-lang.org/Cargo/reference/manifest.html [dependencies] ``` Let's suppose we want to add a [dependency](https://docs.rs/NEAR-SDK/3.1.0/NEAR_SDK/ "NEAR-SDK") we will just add: ```toml [dependencies] NEAR-SDK = "3.1.0" ``` And we can use the interface provided by the NEAR SDK in our program and Cargo will manage the rest. Other than package and dependencies, you might also see other headers in the TOML file like, `lib`, that specifies the crate we are going to write is a library. **Let's Summarise:** * Cargo is a package manager. * `Cargo.toml` is used to manage dependencies. * `Cargo new`, `Cargo init`, `Cargo build`, `Cargo run` are useful to know. ### Rust Syntax Let's start getting familiar with basic Rust syntax. #### Functions We define functions in Rust using the keyword `fn` followed by function name, parameters in brackets which are followed by the arrow operator `->` return type. ```Rust= fn function_name(function_parameters) ->return_type{definition;} ``` When you run ``` Cargo new``` it generates the main function of your program. Which looks like this and takes no parameters and does not return. ```Rust= fn main() { println!("Hello World!"); } ``` #### Variables And Data Types Now let's move on to how Rust works with variable. To define a variable in Rust you can use keyword `let`. There are still multiple things to look at when you define a variable you can just use let and give it a value and compiler can infer the data type that it needs to use. The list of data types that Rust supports can be seen [here](https://doc.rust-lang.org/book/ch03-02-data-types.html). For this example we will only be using some basic data types like `Integer`, `String`, `Float` and `Boolean`. Now "let's" declare some variables. We will declare a variable and let the compiler infer its type and then we will explicitly define the type. ```Rust= // Letting the compiler infer the data type let variable_inferred = 32; // Explicitly defining data type. let variable_statically_typed: u64 = 32; ``` So what can happen when the compiler infers the type? The compiler can deduce the data type to be `i32` which is a signed integer. What about our intention was to define a variable that is an unsigned integer of 64 bits, for that we will have to tell the compiler to use `u64` . So depending on what we want to use we have to take care when to let compiler infer the data type and when to explicitly define it. ###### Mutability By default the variables that we define are immutable but we can make it mutable using the keyword `mut` . You might be thinking about immutable state of variable and why it's the default. It's because Rust prefers safety by making sure variables are immutable by making the defualt variable binding immutable Rust makes sure that at compile time we know we are changing an immutable variable. ```Rust= let mut mutable_variable = 32; ``` ###### Constants But we also have a keyword const that defines constants. ```Rust= const PI: f32 = 3.14; ``` So what's the difference between const and immutable variable? first of all const doesn't allow mut keywords it's always immutable. Constants can be a part of global scope. They are also useful in defining constant expressions like we defined PI above. And we can keep it global so life of `PI` is useful for entire program. More on const [here](https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html#differences-between-variables-and-constants) ###### Scope and Shadowing. If you have programmed in other languages you must be familiar with the concept of scope. A variable's scope is where it can be accessed by the user and other parts of the program. ```Rust= // Scope of a Variable { // This variable can only be accessed within the scope of these brackets. let scoped_variable = "scope"; } //If you try accessing scoped_variable here you will get an error. So be careful ``` Shadowing is a concept of using the let keyword to redefine the variable, it is important to note that we are redefining the variable and not using mut keyword to perform operations on it. These are two separate things. For Example: ```Rust= // First definition let shadow_variable = "xyz"; // Redefining the variable let shadow_variable = "abc"; ``` ###### Example Now let's write our own example using the concepts we have learned so far. Let's write a piece of code that adds a transaction to a hashmap everytime a new transaction is successful. It makes sure that two transaction IDs are not the same and we can also query if the transaction exists. We can use database to manage transactions, but to keep it simple and for learning about Rust, we will be using `hashmap` provided by Rust's standard library `std::collections`. ```Rust= use std::collections::HashMap; pub fn insert_transaction(transaction_map: &mut HashMap<String, u64>, id_value: (String, u64)) -> bool { if transaction_map.contains_key(&id_value.0) { return false; } else{ transaction_map.insert(id_value.0, id_value.1); return true; } } // TO check if transaction exists pub fn transaction_exists(transaction_map: &mut HashMap<String, u64>, transactionid: String) -> bool { if transaction_map.contains_key(&transactionid) { return true; } return false; } ``` We can build up on this by adding other functions like `transaction_validite` that validates the transcation but for now it's okay. #### Rust Tests Now let's move towards writing tests. In Rust for writing tests we use the attribute `#[cfg(test)]` and they are mostly part of the module called tests which is defined by `mod tests`. The individual functions are marked with `#[test]` so compiler knows these are tests. You can check for panic and tests and provide some other attributes but for simpilicity we won't be using them right now. ```Rust= #[cfg(test)] mod tests { use super::*; #[test] fn test_transaction() { // Defining a transaction map let mut transaction_map: HashMap<String, u64> = HashMap::new(); // Inserting key for the first time let transaction:(String, u64) = (String::from("ABC"), 30000); assert_eq!(insert_transaction(&mut transaction_map, transaction), true); // Inserting Same key and asserting we get a false let transaction2:(String, u64) = (String::from("ABC"), 30000); assert_eq!(insert_transaction(&mut transaction_map, transaction2), false); } } ``` ### NEAR Setup So before getting started it's important that we have `near-cli` setup on our machines. Make sure you have npm and node installed, and Node version is 12 or above. You can install by using. ```console npm install -g NEAR-cli ``` We will be using the `near-cli` and will go through the commands as we need them for our project. ###### Introduction To NEAR SDK Now let's take a look at [NEAR-SDK](https://docs.rs/NEAR-SDK/3.1.0/NEAR_SDK/) for Rust. NEAR SDK provides an interface on top of Rust to interact with the NEAR blockchain and develop smart contracts for NEAR platform. We will be looking at some of the important parts of the SDK that will be needed for developing basic smart contract and NFTs. Lets start with a list of [attributes](https://docs.rs/NEAR-SDK/3.1.0/NEAR_SDK/#attributes "NEAR Attributes"). ```Rust= #[NEAR_bindgen] Here is a helpful video. {%youtube eVmVMrwZW0g %} ``` ##### A Basic Contract Using NEAR Let's discuss a basic smart contract that has been written in Rust. For this purpose we will be using the [basic counter](https://github.com/NEAR-examples/Rust-counter "Rust Counter") example. ###### Cargo So we build our contracts on NEAR platform as a [library](https://hackmd.io/@NEARly-learning/contract-basics-Rust) . Remember the `Cargo new` command we used to build it as a library we will have to use `--lib`, this specifies that the new package should be built as a library. ```console Cargo new Rust_counter --lib ``` Lets talk about dependencies for NEAR-SDK. If you are coming from C++ adding dependencies can be a tedious process but Rust provides an easy interface using Cargo. Just open your Cargo.toml file and add this under dependencies. ```toml [dependencies] NEAR-SDK = "3.1.0" [dev-dependencies] NEAR-SDK-sim = "3.1.0" ``` ###### **Code** Wrap a Rust struct in `#[NEAR_bindgen]` and it generates a smart contract compatible with the NEAR blockchain. That’s it. Every Rust contract struct must be tagged with this macro since it exposes the execution environment to the contract allowing it to receive method calls, send results and generally behave like a contract within the runtime environment. More on this [here](https://hackmd.io/@NEARly-learning/contract-basics-Rust#Lines-13---15). For our example we will be using a struct called `Counter` with one `i8` variable. Borsh macros are used for serailizing and deserializing on the NEAR blockchain platform. ```Rust= #[NEAR_bindgen] #[derive(Default, BorshDeserialize, BorshSerialize)] pub struct Counter { // See more data types at https://doc.Rust-lang.org/book/ch03-02-data-types.html val: i8, // i8 is signed. unsigned integers are also available: u8, u16, u32, u64, u128 } ``` Now let's discuss functions that will be implemented for our counter. These will be part of `impl Counter` as we want to implement them for our type `Counter`. `get_num` Return the current counter number. This must match the data type of the 8 bit signed integer we provided above ```Rust= pub fn get_num(&self) -> i8 { return self.val; } ``` `increment` Increment the `counter` by one. Look how we provide `&mut self` as a parameter that's because we want to change the value of our variable. `after_counter_change` is called which we will discuss later. ```Rust= pub fn increment(&mut self) { // note: adding one like this is an easy way to accidentally overflow // real smart contracts will want to have safety checks // e.g. self.val = i8::wrapping_add(self.val, 1); // https://doc.Rust-lang.org/std/primitive.i8.html#method.wrapping_add self.val += 1; let log_message = format!("Increased number to {}", self.val); env::log(log_message.as_bytes()); after_counter_change(); } ``` `decrement` Again like increment this changes the value so we need `&mut` and it decreases the value by one. Also `after_counter_change` is called which we will discuss later. ```Rust= pub fn decrement(&mut self) { // note: subtracting one like this is an easy way to accidentally overflow // real smart contracts will want to have safety checks // e.g. self.val = i8::wrapping_sub(self.val, 1); // https://doc.Rust-lang.org/std/primitive.i8.html#method.wrapping_sub self.val -= 1; let log_message = format!("Decreased number to {}", self.val); env::log(log_message.as_bytes()); after_counter_change(); } ``` `reset` Reset the counter value to zero. Depends on our need. ```Rust= pub fn reset(&mut self) { self.val = 0; // Another way to log is to cast a string into bytes, hence "b" below: env::log(b"Reset counter to zero"); } ``` Now the rest of the code involves a function that checks if the value has gone above 127 or below 128 as we don't want the value to overflow our 8bit signed integer. ```Rust= fn after_counter_change() { // show helpful warning that i8 (8-bit signed integer) will overflow above 127 or below -128 env::log("Make sure you don't overflow, my friend.".as_bytes()); } ``` You can take a look at full example and unit tests for this implementation [here](https://github.com/NEAR-examples/Rust-counter/blob/master/contract/src/lib.rs#L128) If you want to learn more about NEAR and it's basics. Here is a good [playlist](https://www.youtube.com/playlist?list=PL9tzQn_TEuFWJwvBg5V6EVa2DtYL_-2lJ) to get you started. ###### NFTs Before moving on to talking about implementing NFTs on NEAR, lets briefly talk about what NFTs are. NFT stands for **Non-Fungible Token**. To fully understand what Non-Fungible Tokens are we will have to understand the concept of **Fungible things** and **Fungible Tokens**. Fungible tokens or things can be exchanged (or for ease of understanding traded with each other directly) because they are not associated to the uniqueness of the items. Their worth is not dependent on anyone who owns them, there is a set of rules that is followed for their trading, For example the market decides how many NEAR protocol coins can be traded for a Bitcoin and not some one entity. On the other hand non-fungible things can be thought of as valuable possession like a painting or a piece of art, and each non-fungible thing or token has unique property assigned to it that only that NFT holds and no body else can have that. Lets just say for ease of understanding NFTs are another way that we can leverage blockchain technology apart from cryptocurrencies and mostly to have digital assets. ##### NFTs on NEAR: Let's explore writing an NFT on NEAR using Rust-NEAR-SDK. [Protocol specifications](https://nomicon.io/) and [documentation](https://docs.rs/NEAR-SDK/3.1.0/NEAR_SDK/) will be handy. Bookmark them and keep them as your friend for further development. First of all lets talk about what you have to build. And how you have to structure the project let's use this [example](https://github.com/NEAR-examples/NFT) to discuss. We will start off with `Cargo.toml` file. We will specify that we will build it as a library which has been discussed above, and then we will add the dependencies for our examples that are [**NEAR-SDK**](https://docs.rs/NEAR-SDK/3.1.0/NEAR_SDK/) and [**NEAR-contract-standards**](https://docs.rs/NEAR-contract-standards/3.2.0/NEAR_contract_standards/) ```toml [package] name = "non-fungible-token" version = "1.1.0" authors = ["NEAR Inc <hello@NEAR.org>"] edition = "2018" [lib] crate-type = ["cdylib", "rlib"] [dependencies] NEAR-SDK = "3.1.0" NEAR-contract-standards = "3.1.1" ``` Next we will talk about the code and what we will need to write code for an NFT on NEAR. In our example we will be implementing an NFT with JSON serialization and taking into account some of the important details discussed in the GitHub [Example](https://github.com/near-examples/NFT/blob/master/nft/src/lib.rs#L3). ```Rust= /*! NOTES: - The maximum balance value is limited by U128 (2**128 - 1). - JSON calls should pass U128 as a base-10 string. E.g. "100". - The contract optimizes the inner trie structure by hashing account IDs. It will prevent some abuse of deep tries. Shouldn't be an issue, once NEAR clients implement full hashing of keys. - The contract tracks the change in storage before and after the call. If the storage increases, the contract requires the caller of the contract to attach enough deposit to the function call to cover the storage cost. This is done to prevent a denial of service attack on the contract by taking all available storage. If the storage decreases, the contract will issue a refund for the cost of the released storage. The unused tokens from the attached deposit are also refunded, so it's safe to attach more deposit than required. - To prevent the deployed contract from being modified or deleted, it should not have any access keys on its account. */ ``` Now lets talk about what part of NEAR SDK and `NEAR-contract SDK` we will be using in this NFT. First up are the [contract metadata](https://docs.rs/NEAR-contract-standards/3.2.0/NEAR_contract_standards/non_fungible_token/metadata/index.html) as per the specifications for NFT protocol imported from NEAR-contract-SDK. and then there are NFT [token and token struct](https://docs.rs/NEAR-contract-standards/3.2.0/NEAR_contract_standards/non_fungible_token/struct.Token.html) as per specs. After that we will use the [non_fungible_token](https://docs.rs/NEAR-contract-standards/3.2.0/NEAR_contract_standards/non_fungible_token/index.html) type trait for our NFT. Using SDK for `near-contract-standards` makes our programming job a lot easier as we don't have to worry about implementing specifications on our own and can build on top of it. ```Rust= use NEAR_contract_standards::non_fungible_token::metadata::{ NFTContractMetadata, NonFungibleTokenMetadataProvider, TokenMetadata, NFT_METADATA_SPEC, }; use NEAR_contract_standards::non_fungible_token::{Token, TokenId}; use NEAR_contract_standards::non_fungible_token::NonFungibleToken; ``` Then we will import things we need from NEAR SDK for serialization and [container](https://docs.rs/NEAR-SDK/3.1.0/NEAR_SDK/collections/index.html) for storing our contract details apart from how to add helper for json [json types](https://docs.rs/NEAR-SDK/3.1.0/NEAR_SDK/json_types/index.html), type traits for [Borsh Storage Key](https://docs.rs/NEAR-SDK/3.1.0/NEAR_SDK/derive.BorshStorageKey.html), [Panic On Default](https://docs.rs/NEAR-SDK/3.1.0/NEAR_SDK/derive.PanicOnDefault.html), [Promise](https://docs.rs/NEAR-SDK/3.1.0/NEAR_SDK/struct.Promise.html) A structure representing a result of the scheduled execution on another contract. or [PromiseOrValue](https://docs.rs/NEAR-SDK/3.1.0/NEAR_SDK/enum.PromiseOrValue.html). ```Rust= use NEAR_SDK::borsh::{self, BorshDeserialize, BorshSerialize}; ``` ```Rust= use NEAR_SDK::collections::LazyOption; ``` ```Rust= use NEAR_SDK::json_types::ValidAccountId; ``` ```Rust= use NEAR_SDK::{ env, NEAR_bindgen, AccountId, BorshStorageKey, PanicOnDefault, Promise, PromiseOrValue, }; ``` To start if off we will use `setup_alloc!()` macro boilerplate for setting up allocator used in WASM binary. And a contract struct, for storing our contract's token and metadata. ```Rust= NEAR_SDK::setup_alloc!(); #[NEAR_bindgen] #[derive(BorshDeserialize, BorshSerialize, PanicOnDefault)] pub struct Contract { tokens: NonFungibleToken, metadata: LazyOption<NFTContractMetadata>, } ``` Here we are defining an example to be used as our NFT and an enum that we will serialize to be used on NEAR Platform. ```Rust= const DATA_IMAGE_SVG_NEAR_ICON: &str = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 288 288'%3E%3Cg id='l' data-name='l'%3E%3Cpath d='M187.58,79.81l-30.1,44.69a3.2,3.2,0,0,0,4.75,4.2L191.86,103a1.2,1.2,0,0,1,2,.91v80.46a1.2,1.2,0,0,1-2.12.77L102.18,77.93A15.35,15.35,0,0,0,90.47,72.5H87.34A15.34,15.34,0,0,0,72,87.84V201.16A15.34,15.34,0,0,0,87.34,216.5h0a15.35,15.35,0,0,0,13.08-7.31l30.1-44.69a3.2,3.2,0,0,0-4.75-4.2L96.14,186a1.2,1.2,0,0,1-2-.91V104.61a1.2,1.2,0,0,1,2.12-.77l89.55,107.23a15.35,15.35,0,0,0,11.71,5.43h3.13A15.34,15.34,0,0,0,216,201.16V87.84A15.34,15.34,0,0,0,200.66,72.5h0A15.35,15.35,0,0,0,187.58,79.81Z'/%3E%3C/g%3E%3C/svg%3E"; #[derive(BorshSerialize, BorshStorageKey)] enum StorageKey { NonFungibleToken, Metadata, TokenMetadata, Enumeration, Approval, } ``` Next we will implement details for our contract type trait that includes defining the newmetadata for our NFT details for its owner and the method to mint in on NEAR platform. ```Rust= #[NEAR_bindgen] impl Contract { /// Initializes the contract owned by `owner_id` with /// default metadata (for example purposes only). #[init] pub fn new_default_meta(owner_id: ValidAccountId) -> Self { Self::new( owner_id, NFTContractMetadata { spec: NFT_METADATA_SPEC.to_string(), name: "Example NEAR non-fungible token".to_string(), symbol: "EXAMPLE".to_string(), icon: Some(DATA_IMAGE_SVG_NEAR_ICON.to_string()), base_uri: None, reference: None, reference_hash: None, }, ) } #[init] pub fn new(owner_id: ValidAccountId, metadata: NFTContractMetadata) -> Self { assert!(!env::state_exists(), "Already initialized"); metadata.assert_valid(); Self { tokens: NonFungibleToken::new( StorageKey::NonFungibleToken, owner_id, Some(StorageKey::TokenMetadata), Some(StorageKey::Enumeration), Some(StorageKey::Approval), ), metadata: LazyOption::new(StorageKey::Metadata, Some(&metadata)), } } /// Mint a new token with ID=`token_id` belonging to `receiver_id`. /// /// Since this example implements metadata, it also requires per-token metadata to be provided /// in this call. `self.tokens.mint` will also require it to be Some, since /// `StorageKey::TokenMetadata` was provided at initialization. /// /// `self.tokens.mint` will enforce `predecessor_account_id` to equal the `owner_id` given in /// initialization call to `new`. #[payable] pub fn NFT_mint( &mut self, token_id: TokenId, receiver_id: ValidAccountId, token_metadata: TokenMetadata, ) -> Token { self.tokens.mint(token_id, receiver_id, Some(token_metadata)) } } ``` Here we are using the [macros](https://docs.rs/NEAR-contract-standards/3.2.0/NEAR_contract_standards/index.html#macros) provided by `near_contract_standards` depending on our requirement. `impl_non_fungible_token_approval` Non-fungible token approval management allows for an escrow system where multiple approvals for each token exist. `impl_non_fungible_token_core` The core methods for a basic non-fungible token. Extension standards may be added in addition to this macro. `impl_non_fungible_token_enumeration` Non-fungible enumeration adds the extension standard offering several view-only methods to get token supply, tokens for each owner, etc. ```Rust= NEAR_contract_standards::impl_non_fungible_token_core!(Contract, tokens); NEAR_contract_standards::impl_non_fungible_token_approval!(Contract, tokens); NEAR_contract_standards::impl_non_fungible_token_enumeration!(Contract, tokens); ``` This function has been implemented to get the NFT metadata from our contract. ```Rust= #[NEAR_bindgen] impl NonFungibleTokenMetadataProvider for Contract { fn NFT_metadata(&self) -> NFTContractMetadata { self.metadata.get().unwrap() } } ``` You can look for [tests](https://github.com/NEAR-examples/NFT/blob/master/NFT/src/lib.rs#L116) and implementations and usage of the contract on GitHub [NFT example](https://github.com/NEAR-examples/NFT). The example also has test implementations. #### Conclusion Rust provides a way to write fast and safe code, and it can be leveraged for use cases where that's a need. Rust community also provides great introductory documents and is quite welcoming for beginners. NEAR SDK provides a great way to write contracts for NEAR protocol using Rust. In this post we have discussed some basics of Rust and how to use NEAR SDK for writing NFT. There are a lot of things that are to be learned when it comes to Rust and it might seem difficult but if we can break it down for our understanding it can get easier.

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully