From 5aa916475c3f648cc2dd193e9d27de179d23fe69 Mon Sep 17 00:00:00 2001 From: garikbesson Date: Fri, 27 Oct 2023 13:53:22 +0200 Subject: [PATCH] ft primitives structure --- docs/7.primitives/ft/additional-resources.md | 10 + docs/7.primitives/ft/interacting/bos.md | 75 ++ docs/7.primitives/ft/interacting/near-cli.md | 14 + .../ft/{ => interacting}/smart-contract.md | 2 +- docs/7.primitives/ft/interacting/web-app.md | 800 ++++++++++++++++++ docs/7.primitives/ft/introduction.md | 8 +- website/sidebars.json | 16 +- 7 files changed, 915 insertions(+), 10 deletions(-) create mode 100644 docs/7.primitives/ft/additional-resources.md create mode 100644 docs/7.primitives/ft/interacting/bos.md create mode 100644 docs/7.primitives/ft/interacting/near-cli.md rename docs/7.primitives/ft/{ => interacting}/smart-contract.md (58%) create mode 100644 docs/7.primitives/ft/interacting/web-app.md diff --git a/docs/7.primitives/ft/additional-resources.md b/docs/7.primitives/ft/additional-resources.md new file mode 100644 index 00000000000..1f7113e20b4 --- /dev/null +++ b/docs/7.primitives/ft/additional-resources.md @@ -0,0 +1,10 @@ +--- +id: additional-resources +title: Additional Resources +hide_table_of_contents: false +--- + +import {FeatureList, Column, Feature} from "@site/components/featurelist" +import ContactUs from '@site/components/ContactUs.mdx'; + +1. \ No newline at end of file diff --git a/docs/7.primitives/ft/interacting/bos.md b/docs/7.primitives/ft/interacting/bos.md new file mode 100644 index 00000000000..0b02be8eafc --- /dev/null +++ b/docs/7.primitives/ft/interacting/bos.md @@ -0,0 +1,75 @@ +--- +id: bos +title: NEAR Component +hide_table_of_contents: false +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +This section shows how to interact with FTs directly from a [NEAR Component](../../../bos/components.md) + +--- + +## Check token balance + + + + + +```js +``` + + + + + +```js +const tokenContract = "token.v2.ref-finance.near"; +const tokenPrice = fetch( + "https://indexer.ref.finance/get-token-price?token_id=token.v2.ref-finance.near" +).body; + +console.log("refPrice: ", JSON.parse(tokenPrice)); +``` + +
+Example response +

+ +```json +{ + "token_contract_id": "token.v2.ref-finance.near", + "price": "0.05732698" +} +``` + +

+
+ +
+ + + +```js + +``` + + + +
+ +## Send tokens +## Get prices (?) + +Ref Finance API + +List of prices +https://indexer.ref.finance/list-token-price + +Get token price +https://indexer.ref.finance/get-token-price?token_id=token.v2.ref-finance.near + +## Swap tokens (?) +## Attaching FTs to a Call (? already exist [here](https://docs.near.org/develop/relevant-contracts/ft)) +## Minting FTs (? already exist [here](https://docs.near.org/tutorials/fts/simple-fts)) \ No newline at end of file diff --git a/docs/7.primitives/ft/interacting/near-cli.md b/docs/7.primitives/ft/interacting/near-cli.md new file mode 100644 index 00000000000..1dfe53051cb --- /dev/null +++ b/docs/7.primitives/ft/interacting/near-cli.md @@ -0,0 +1,14 @@ +--- +id: near-cli +title: NEAR CLI +hide_table_of_contents: false +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +This section shows how to interact with FTs from your shell using [`near-cli`](../../../4.tools/cli.md). + +--- + +## \ No newline at end of file diff --git a/docs/7.primitives/ft/smart-contract.md b/docs/7.primitives/ft/interacting/smart-contract.md similarity index 58% rename from docs/7.primitives/ft/smart-contract.md rename to docs/7.primitives/ft/interacting/smart-contract.md index f9838834ba4..15814a26897 100644 --- a/docs/7.primitives/ft/smart-contract.md +++ b/docs/7.primitives/ft/interacting/smart-contract.md @@ -4,4 +4,4 @@ title: Smart Contract hide_table_of_contents: false --- -How to check account balance on smart-contract (example). \ No newline at end of file +This section will explain how a smart contract can ... \ No newline at end of file diff --git a/docs/7.primitives/ft/interacting/web-app.md b/docs/7.primitives/ft/interacting/web-app.md new file mode 100644 index 00000000000..60498e94e20 --- /dev/null +++ b/docs/7.primitives/ft/interacting/web-app.md @@ -0,0 +1,800 @@ +--- +id: web-app +title: Web Application +hide_table_of_contents: false +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +This section describes how to interact with NFT contracts from a web app. + +:::info +All the examples are using a `Wallet` object, which comes from our [basic template](https://github.com/near-examples/hello-near-js/blob/master/frontend/near-wallet.js) +::: + +:::tip +In order to interact with NFT from your Web App you can request data from various APIs from your app (for example, [Marketplaces API](/primitives/nft/querying/marketplaces)). +::: + +--- + +## Mint a NFT + + + + +```js +import { Wallet } from './near-wallet'; + +const CONTRACT_ADDRESS = "nft.primitives.near"; +const wallet = new Wallet({ createAccessKeyFor: CONTRACT_ADDRESS }); + +await wallet.callMethod({ + method: 'nft_mint', + args: { + token_id: "1", + receiver_id: "bob.near", + token_metadata: { + title: "NFT Primitive Token", + description: "Awesome NFT Primitive Token", + media: "string", // URL to associated media, preferably to decentralized, content-addressed storage + } + }, + contractId: CONTRACT_ADDRESS +}); +``` + + + + + +```js +import { Wallet } from './near-wallet'; + +const CONTRACT_ADDRESS = "x.paras.near"; +const wallet = new Wallet({ createAccessKeyFor: CONTRACT_ADDRESS }); + +await wallet.callMethod({ + method: 'nft_mint', + args: { + token_series_id: "490641", + receiver_id: "bob.near", + }, + contractId: CONTRACT_ADDRESS +}); +``` + +:::note +In order to use `nft_mint` method of the `x.paras.near` contract you have to be a creator of a particular token series. +::: + + + + + +By using [`near-api-js`](https://docs.near.org/tools/near-api-js/quick-reference) + +```js +import { Wallet } from './near-wallet'; + +const CONTRACT_ADDRESS = "thomasettorreiv.mintbase1.near"; +const wallet = new Wallet({ createAccessKeyFor: CONTRACT_ADDRESS }); + +await wallet.callMethod({ + method: 'nft_batch_mint', + args: { + num_to_mint: 1, + owner_id: "bob.near", + metadata: {}, + }, + contractId: CONTRACT_ADDRESS, + deposit: 1 +}); +``` + +:::note +In order to use `nft_batch_mint` method of Mintbase store contract your account have to be a in the contract minters list. +::: + +By using [`Mintbase JS`](https://docs.mintbase.xyz/dev/mintbase-sdk-ref/sdk/mint) + +```js +import { useState } from 'react'; +import { useWallet } from '@mintbase-js/react'; +import { execute, mint, MintArgs } from '@mintbase-js/sdk'; + + +export const MintComponent = ({ media, reference, contractAddress, owner }: MintArgs): JSX.Element => { + + const { selector } = useWallet(); + + const handleMint = async (): Promise => { + + const wallet = await selector.wallet(); + + await execute( + mint({ contractAddress: contractAddress, metadata: { media, reference }, ownerId: owner }) + ); + + } + + return ( +
+ +
+ ); +}; +``` + +
+
+ +--- + +## Buy a NFT + + + + +```js +import { Wallet } from './near-wallet'; + +const CONTRACT_ADDRESS = "x.paras.near"; +const wallet = new Wallet({ createAccessKeyFor: CONTRACT_ADDRESS }); + +await wallet.callMethod({ + method: 'nft_buy', + args: { + token_series_id: "299102", + receiver_id: "bob.near", + }, + contractId: CONTRACT_ADDRESS, + deposit: 205740000000000000000000 // attached deposit in yoctoNEAR, covers NFT price + storage cost +}); +``` + +
+Example response +

+ +```json +"299102:1" +``` + +

+
+ +
+ + + +By using [`near-api-js`](https://docs.near.org/tools/near-api-js/quick-reference) + +```js +import { Wallet } from './near-wallet'; + +const CONTRACT_ADDRESS = "simple.market.mintbase1.near"; +const wallet = new Wallet({ createAccessKeyFor: CONTRACT_ADDRESS }); + +await wallet.callMethod({ + method: 'buy', + args: { + nft_contract_id: "rubennnnnnnn.mintbase1.near", + token_id: "38" + }, + contractId: CONTRACT_ADDRESS, + deposit: 1000000000000000000000 // attached deposit in yoctoNEAR, covers NFT price + storage cost (optional) +}); +``` + +
+Example response +

+ +```json +{ + "payout": { + "rub3n.near": "889200000000000000000", + "rubenm4rcus.near": "85800000000000000000" + } +} +``` + +

+
+ +By using [`Mintbase JS`](https://docs.mintbase.xyz/dev/mintbase-sdk-ref/sdk/buy) + +```js +import { useState } from 'react'; +import { useWallet } from '@mintbase-js/react'; +import { execute, burn, BuyArgs } from '@mintbase-js/sdk'; + + +export const BuyComponent = ({ contractAddress, price, tokenId, affiliateAccount, marketId }:BuyArgs): JSX.Element => { + + const { selector } = useWallet(); + + const handleBuy = async (): Promise => { + + const wallet = await selector.wallet(); + + const buyArgs = {contractAddress: contractAddress, tokenId: tokenId, affiliateAccount: affiliateAccount , marketId:marketId, price:price } + + await execute( + {wallet}, + buy(buyArgs) + ); + + } + + return ( +
+ +
+ ); +}; +``` + +
+
+ +--- + +## Query NFT data + + + + +```js +import { Wallet } from './near-wallet'; + +const CONTRACT_ADDRESS = "nft.primitives.near"; +const wallet = new Wallet({ createAccessKeyFor: CONTRACT_ADDRESS }); + +const response = await wallet.viewMethod({ + method: 'nft_token', + args: { + token_id: "1" + } +}); +``` + +
+Example response +

+ +```json +{ + "token_id": "1", + "owner_id": "bob.near", + "metadata": { + "title": "string", // ex. "Arch Nemesis: Mail Carrier" or "Parcel #5055" + "description": "string", // free-form description + "media": "string", // URL to associated media, preferably to decentralized, content-addressed storage + "media_hash": "string", // Base64-encoded sha256 hash of content referenced by the `media` field. Required if `media` is included. + "copies": 1, // number of copies of this set of metadata in existence when token was minted. + "issued_at": 1642053411068358156, // When token was issued or minted, Unix epoch in milliseconds + "expires_at": 1642053411168358156, // When token expires, Unix epoch in milliseconds + "starts_at": 1642053411068358156, // When token starts being valid, Unix epoch in milliseconds + "updated_at": 1642053411068358156, // When token was last updated, Unix epoch in milliseconds + "extra": "string", // anything extra the NFT wants to store on-chain. Can be stringified JSON. + "reference": "string", // URL to an off-chain JSON file with more info. + "reference_hash": "string" // Base64-encoded sha256 hash of JSON from reference field. Required if `reference` is included. + } +} +``` + +

+
+ +
+ + + +By using [`near-api-js`](https://docs.near.org/tools/near-api-js/quick-reference) + +```js +import { Wallet } from './near-wallet'; + +const CONTRACT_ADDRESS = "x.paras.near"; +const wallet = new Wallet({ createAccessKeyFor: CONTRACT_ADDRESS }); + +const response = await wallet.viewMethod({ + method: 'nft_token', + args: { + token_id: "84686:1154" + } +}); +``` + +
+Example response +

+ +```json +{ + "token_id": "84686:1154", + "owner_id": "bob.near", + "metadata": { + "title": "Tokenfox Silver Coin #1154", + "description": null, + "media": "bafkreihpapfu7rzsmejjgl2twllge6pbrfmqaahj2wkz6nq55c6trhhtrq", + "media_hash": null, + "copies": 4063, + "issued_at": "1642053411068358156", + "expires_at": null, + "starts_at": null, + "updated_at": null, + "extra": null, + "reference": "bafkreib6uj5kxbadfvf6qes5flema7jx6u5dj5zyqcneaoyqqzlm6kpu5a", + "reference_hash": null + }, + "approved_account_ids": {} +} +``` + +

+
+ +By calling a Paras API method + +```js +const tokenData = fetch("https://api-v2-mainnet.paras.id/token?token_id=84686:1154"); +``` + +
+Example response +

+ +```json +{ + "status": 1, + "data": { + "results": [ + { + "_id": "61dfbf27284abc1cc0b87c9d", + "contract_id": "x.paras.near", + "token_id": "84686:1154", + "owner_id": "bob.near", + "token_series_id": "84686", + "edition_id": "1154", + "metadata": { + "title": "Tokenfox Silver Coin #1154", + "description": "Holding this silver coin in your wallet will bring you health and happiness \uD83D\uDE0A", + "media": "bafkreihpapfu7rzsmejjgl2twllge6pbrfmqaahj2wkz6nq55c6trhhtrq", + "media_hash": null, + "copies": 4063, + "issued_at": null, + "expires_at": null, + "starts_at": null, + "updated_at": null, + "extra": null, + "reference": "bafkreib6uj5kxbadfvf6qes5flema7jx6u5dj5zyqcneaoyqqzlm6kpu5a", + "reference_hash": null, + "collection": "Tokenfox Collection Cards", + "collection_id": "tokenfox-collection-cards-by-tokenfoxnear", + "creator_id": "tokenfox.near", + "blurhash": "U7F~gc00_3D%00~q4n%M_39F-;RjM{xuWBRj", + "score": 0, + "mime_type": "image/png" + }, + "royalty": { + "tokenfox.near": 1000 + }, + "price": null, + "approval_id": null, + "ft_token_id": null, + "has_price": null, + "is_creator": true, + "total_likes": 8, + "likes": null, + "categories": [], + "view": 4 + } + ], + "count": 1, + "skip": 0, + "limit": 10 + } +} +``` + +

+
+ +:::info +See the [Paras API documentation](https://parashq.github.io/) for the full list of methods. +::: + +:::note +When you call Paras smart contract method it returns data that are stored in the Paras NFT smart contract. It means a response contains only data about NFTs which were minted via Paras NFT contract. + +When you call Paras API methods it returns data from other NFT contracts as well, due to the work of the indexer. It means you might want to pass more parameters like `contract_id` or `owner_id` to make the response more accurate. +::: + +
+ + + +By using [`near-api-js`](https://docs.near.org/tools/near-api-js/quick-reference) + +```js +import { Wallet } from './near-wallet'; + +const CONTRACT_ADDRESS = "anthropocene.mintbase1.near"; +const wallet = new Wallet({ createAccessKeyFor: CONTRACT_ADDRESS }); + +const response = await wallet.viewMethod({ + method: 'nft_token', + args: { + token_id: "17960" + } +}); +``` + +
+Example response +

+ +```json +{ + "token_id": "17960", + "owner_id": "876f40299dd919f39252863e2136c4e1922cd5f78759215474cbc8f1fc361e14", + "approved_account_ids": {}, + "metadata": { + "title": null, + "description": null, + "media": null, + "media_hash": null, + "copies": 1, + "issued_at": null, + "expires_at": null, + "starts_at": null, + "updated_at": null, + "extra": null, + "reference": "F-30s_uQ3ZdAHZClY4DYatDPapaIRNLju41RxfMXC24", + "reference_hash": null + }, + "royalty": { + "split_between": { + "seventhage.near": { + "numerator": 10000 + } + }, + "percentage": { + "numerator": 100 + } + }, + "split_owners": null, + "minter": "anthropocene.seventhage.near", + "loan": null, + "composeable_stats": { "local_depth": 0, "cross_contract_children": 0 }, + "origin_key": null +} +``` + +

+
+ +:::note +When someone creates a NFT on Mintbase they need to deploy their own NFT contract using Mintbase factory. Those smart contract are subaccounts of mintbase1.near, e.g. `anthropocene.mintbase1.near`. +::: + +By calling a Mintbase GraphQL API method + +```js +const tokenData = fetch("https://graph.mintbase.xyz", { + method: "POST", + headers: { + "mb-api-key": "anon", + "Content-Type": "application/json", + "x-hasura-role": "anonymous", + }, + body: JSON.stringify({ + query: ` + query getToken{ + tokens: nft_tokens( + where: { + token_id: { _eq: "84686:1154" } + } + ) { + tokenId: token_id + ownerId: owner + contractId: nft_contract_id + reference + issuedAt: issued_at + copies + metadataId: metadata_id + } + } + `, + }), +}); +``` + +
+Example response +

+ +```json +{ + "ok": true, + "status": 200, + "contentType": "application/json", + "body": { + "data": { + "tokens": [ + { + "tokenId": "84686:1154", + "ownerId": "bob.near", + "contractId": "x.paras.near", + "reference": "bafkreib6uj5kxbadfvf6qes5flema7jx6u5dj5zyqcneaoyqqzlm6kpu5a", + "issuedAt": "2022-01-13T05:56:51.068358", + "copies": 4063, + "metadataId": "x.paras.near:5210047642790498956c9669d6a37b98" + } + ] + } + } +} +``` + +

+
+ +:::note +In the future, users may be required to register using an api key. For now, simply passing the valueanon for `mb-api-key` will work. +::: + +By using [`Mintbase JS`](https://docs.mintbase.xyz/dev/mintbase-sdk-ref/data/api/tokenbyid) + +```js +import { tokenById } from '@mintbase-js/data' + +const { data, error } = await tokenById( '1','rub3n.testnet'); + +if (error) {console.log('error', error)} + + +console.log(data.tokenData[0]) // => token metadata +``` + +
+
+ +--- + +## Transfer a NFT + + + + +```js +import { Wallet } from './near-wallet'; + +const CONTRACT_ADDRESS = "nft.primitives.near"; +const wallet = new Wallet({ createAccessKeyFor: CONTRACT_ADDRESS }); + +await wallet.callMethod({ + method: 'nft_transfer', + args: { + token_id: "1", + receiver_id: "bob.near" + }, + contractId: CONTRACT_ADDRESS +}); +``` + + + + + +```js +import { Wallet } from './near-wallet'; + +const CONTRACT_ADDRESS = "x.paras.near"; +const wallet = new Wallet({ createAccessKeyFor: CONTRACT_ADDRESS }); + +await wallet.callMethod({ + method: 'nft_transfer', + args: { + token_id: "490641", + receiver_id: "bob.near" + }, + contractId: CONTRACT_ADDRESS +}); +``` + + + + + +By using [`near-api-js`](https://docs.near.org/tools/near-api-js/quick-reference) + +```js +import { Wallet } from './near-wallet'; + +const CONTRACT_ADDRESS = "thomasettorreiv.mintbase1.near"; +const wallet = new Wallet({ createAccessKeyFor: CONTRACT_ADDRESS }); + +await wallet.callMethod({ + method: 'nft_transfer', + args: { + token_id: "490641", + receiver_id: "bob.near" + }, + contractId: CONTRACT_ADDRESS +}); +``` + +By using [`Mintbase JS`](https://docs.mintbase.xyz/dev/mintbase-sdk-ref/sdk/transfer) + +```js +import { useState } from 'react'; +import { useWallet } from '@mintbase-js/react'; +import { execute, transfer, TransferArgs } from '@mintbase-js/sdk'; + +const TransferComponent = ({ tokenId, contractAddress }: TransferArgs): JSX.Element => { + const { selector, activeAccountId } = useWallet(); + + const handleTransfer = async (): Promise => { + const wallet = await selector.wallet(); + + const transferArgs: TransferArgs = { + contractAddress: contractAddress, + transfers: [{ + receiverId: 'mb_carol.testnet', + tokenId: token.tokenId, + }], + } + + await execute( + { wallet }, + transfer(transferArgs), + ); + }; + + return ( +
+ +
+ ); +} +``` + +
+
+ +--- + +## List a NFT up for a sale + +Basic NFT contracts following [the NEP-171 and NEP-177 standards](https://nomicon.io/Standards/Tokens/NonFungibleToken) do not implement marketplace functionality. + +For this purpose, there are ecosystem apps such as [Paras](https://paras.id/) or [Mintbase](https://www.mintbase.xyz/), that use dedicated marketplace contracts. + +In order to put a NFT for a sale on a marketplace you need to do two actions: + +1. Cover data storage costs in the marketplace contract. +2. Approve the marketplace to sell the NFT in your NFT contract. + + + + + +```js +import { Wallet } from './near-wallet'; + +const CONTRACT_ADDRESS = "marketplace.paras.near"; +const wallet = new Wallet({ createAccessKeyFor: CONTRACT_ADDRESS }); + +await wallet.callMethod({ + method: 'storage_deposit', + args: { + receiver_id: "bob.near" + }, + contractId: CONTRACT_ADDRESS, + gas: 300000000000000, // attached GAS (optional) + deposit: 9390000000000000000 // attached deposit in yoctoNEAR (optional) +}); + +await wallet.callMethod({ + method: 'nft_approve', + args: { + token_id: "1e95238d266e5497d735eb30", + account_id: "marketplace.paras.near", + msg: { + price: "200000000000000000000000", + market_type: "sale", + ft_token_id: "near" + } + }, + contractId: "nft.primitives.near" +}); +``` + +Method `nft_approve` of a NFT contract also calls the `nft_on_approve` method in `marketplace.paras.near` as a callback. + + + + + +```js +import { Wallet } from './near-wallet'; + +const CONTRACT_ADDRESS = "simple.market.mintbase1.near"; +const wallet = new Wallet({ createAccessKeyFor: CONTRACT_ADDRESS }); + +await wallet.callMethod({ + method: 'deposit_storage', + args: { + autotransfer: true + }, + contractId: CONTRACT_ADDRESS, + gas: 300000000000000, // attached GAS (optional) + deposit: 9390000000000000000 // attached deposit in yoctoNEAR (optional) +}); + +await wallet.callMethod({ + method: 'nft_approve', + args: { + args: { + token_id: "3c46b76cbd48e65f2fc88473", + account_id: "simple.market.mintbase1.near", + msg: { + price: "200000000000000000000000" + } + }, + }, + contractId: "nft.primitives.near" +}); +``` + +Method `nft_approve` of a NFT contract also calls the `nft_on_approve` method in `simple.market.mintbase1.near` as a callback. + +By using [`Mintbase JS`](https://docs.mintbase.xyz/dev/mintbase-sdk-ref/sdk/list) + +```js +import { useState } from 'react'; +import { useWallet } from '@mintbase-js/react'; +import { execute, list, ListArgs } from '@mintbase-js/sdk'; + + +export const ListComponent = ({ contractAddress, marketAddress , tokenId, price }:ListArgs):JSX.Element => { + + const { selector } = useWallet(); + + const handleList = async (): Promise => { + const wallet = await selector.wallet(); + + await execute( + {wallet}, + list({ + contractAddress: nftContractId, + marketAddress: marketId, + tokenId: tokenId, + price: price + }) + ) + } + + return ( +
+ +
+ ); +}; +``` + +
+
\ No newline at end of file diff --git a/docs/7.primitives/ft/introduction.md b/docs/7.primitives/ft/introduction.md index d7a2080031f..a9ad07efb76 100644 --- a/docs/7.primitives/ft/introduction.md +++ b/docs/7.primitives/ft/introduction.md @@ -11,7 +11,6 @@ import ContactUs from '@site/components/ContactUs.mdx'; - [What is an FT?](#what-is-an-ft) - [How to create FT token](#how-to-create-ft-token) -- [Additional sources](#additional-sources) --- @@ -37,9 +36,4 @@ Usually tokens are created by deploying own FT contract on blockchain. But there 1. [Token Farm](https://tkn.farm/) is a tool that can be use to create a new fungible token. It is deployed as subaccount of the factory contract, for example, `new_token.tkn.near`. To create a new FT you need to fill in few fields - token name, symbol, supply, decimals, owner account id and choose an icon. -2. [Token Laboratory](https://app.jumpdefi.xyz/token-launcher) by Jump Defi. Provides the same functionality to create tokens as Token Farm. ---- - -## Additional sources - ---- \ No newline at end of file +2. [Token Laboratory](https://app.jumpdefi.xyz/token-launcher) by Jump Defi. Provides the same functionality to create tokens as Token Farm. \ No newline at end of file diff --git a/website/sidebars.json b/website/sidebars.json index 6cbb82be7e4..7255943bc74 100644 --- a/website/sidebars.json +++ b/website/sidebars.json @@ -387,9 +387,21 @@ "type": "html", "value": " Fungible Tokens (FT) " }, + "primitives/ft/introduction", { - "type": "html", - "value": "Coming Soon" + "Using FTs": [ + "primitives/ft/interacting/bos", + "primitives/ft/interacting/web-app", + "primitives/ft/interacting/smart-contract", + "primitives/ft/interacting/near-cli" + ] + }, + "primitives/ft/additional-resources", + { + "Drafts": [ + "primitives/ft/bos", + "primitives/ft/dex" + ] }, { "type": "html",