# Your First NFT

This tutorial describes how to create and transfer NFTs on the Aptos blockchain. The Aptos implementation for core NFTs can be found in the [token.move](https://github.com/aptos-labs/aptos-core/blob/main/aptos-move/framework/aptos-token/sources/token.move) Move module.

### Step 1: Pick an SDK[​](https://aptos.dev/tutorials/your-first-nft#step-1-pick-an-sdk) <a href="#step-1-pick-an-sdk" id="step-1-pick-an-sdk"></a>

Install your preferred SDK from the below list:

* [Typescript SDK](https://aptos.dev/sdks/ts-sdk/index)
* [Python SDK](https://aptos.dev/sdks/python-sdk)
* [Rust SDK](https://aptos.dev/sdks/rust-sdk)

***

### Step 2: Run the example[​](https://aptos.dev/tutorials/your-first-nft#step-2-run-the-example) <a href="#step-2-run-the-example" id="step-2-run-the-example"></a>

Each SDK provides an `examples` directory. This tutorial covers the `simple-nft` example.

Clone the `aptos-core` repo:

```
git clone git@github.com:aptos-labs/aptos-core.git ~/aptos-core
```

* Typescript
* Python
* Rust

Navigate to the Typescript SDK examples directory:

```
cd ~/aptos-core/ecosystem/typescript/sdk/examples/typescript
```

Install the necessary dependencies:

```
yarn install
```

Run the Typescript [`simple_nft`](https://github.com/aptos-labs/aptos-core/blob/main/ecosystem/typescript/sdk/examples/typescript/simple_nft.ts) example:

```
yarn run simple_nft
```

***

### Step 3: Understand the output[​](https://aptos.dev/tutorials/your-first-nft#step-3-understand-the-output) <a href="#step-3-understand-the-output" id="step-3-understand-the-output"></a>

The following output should appear after executing the `simple-nft` example, though some values will be different:

```
=== Addresses ===Alice: 0x9df0f527f3a0b445e4d5c320cfa269cdefafc7cd1ed17ffce4b3fd485b17aafbBob: 0xfcc74af84dde26b0050dce35d6b3d11c60f5c8c58728ca3a0b11035942a0b1de=== Initial Coin Balances ===Alice: 20000Bob: 20000=== Creating Collection and Token ===Alice's collection: {    "description": "Alice's simple collection",    "maximum": "18446744073709551615",    "mutability_config": {        "description": false,        "maximum": false,        "uri": false    },    "name": "Alice's",    "supply": "1",    "uri": "https://aptos.dev"}Alice's token balance: 1Alice's token data: {    "default_properties": {        "map": {            "data": []        }    },    "description": "Alice's simple token",    "largest_property_version": "0",    "maximum": "1",    "mutability_config": {        "description": false,        "maximum": false,        "properties": false,        "royalty": false,        "uri": false    },    "name": "Alice's first token",    "royalty": {        "payee_address": "0x9df0f527f3a0b445e4d5c320cfa269cdefafc7cd1ed17ffce4b3fd485b17aafb",        "royalty_points_denominator": "1000000",        "royalty_points_numerator": "0"    },    "supply": "1",    "uri": "https://aptos.dev/img/nyan.jpeg"}=== Transferring the token to Bob ===Alice's token balance: 0Bob's token balance: 1=== Transferring the token back to Alice using MultiAgent ===Alice's token balance: 1Bob's token balance: 0
```

This example demonstrates:

* Initializing the REST and faucet clients.
* The creation of two accounts: Alice and Bob.
* The funding and creation of Alice and Bob's accounts.
* The creation of a collection and a token using Alice's account.
* Alice offering a token and Bob claiming it.
* Bob unilaterally sending the token to Alice via a multiagent transaction.

***

### Step 4: The SDK in depth[​](https://aptos.dev/tutorials/your-first-nft#step-4-the-sdk-in-depth) <a href="#step-4-the-sdk-in-depth" id="step-4-the-sdk-in-depth"></a>

* Typescript
* Python
* Rust

SEE THE FULL CODE

See [`simple_nft`](https://github.com/aptos-labs/aptos-core/blob/main/ecosystem/typescript/sdk/examples/typescript/simple_nft.ts) for the complete code as you follow the below steps.

***

#### Step 4.1: Initializing the clients[​](https://aptos.dev/tutorials/your-first-nft#step-41-initializing-the-clients) <a href="#step-41-initializing-the-clients" id="step-41-initializing-the-clients"></a>

In the first step the example initializes both the API and faucet clients.

* The API client interacts with the REST API, and
* The faucet client interacts with the devnet Faucet service for creating and funding accounts.
* Typescript
* Python
* Rust

```
const client = new AptosClient(NODE_URL);const faucetClient = new FaucetClient(NODE_URL, FAUCET_URL); 
```

Using the API client we can create a `TokenClient`, which we use for common token operations such as creating collections and tokens, transferring them, claiming them, and so on.

```
const tokenClient = new TokenClient(client); 
```

`common.ts` initializes the URL values as such:

```
export const NODE_URL = process.env.APTOS_NODE_URL || "https://fullnode.devnet.aptoslabs.com";export const FAUCET_URL = process.env.APTOS_FAUCET_URL || "https://faucet.devnet.aptoslabs.com";
```

TIP

By default the URLs for both the services point to Aptos devnet services. However, they can be configured with the following environment variables:

* `APTOS_NODE_URL`
* `APTOS_FAUCET_URL`

***

#### Step 4.2: Creating local accounts[​](https://aptos.dev/tutorials/your-first-nft#step-42-creating-local-accounts) <a href="#step-42-creating-local-accounts" id="step-42-creating-local-accounts"></a>

The next step is to create two accounts locally. [Accounts](https://aptos.dev/concepts/basics-accounts) represent both on and off-chain state. Off-chain state consists of an address and the public, private key pair used to authenticate ownership. This step demonstrates how to generate that off-chain state.

* Typescript
* Python
* Rust

```
const alice = new AptosAccount();const bob = new AptosAccount(); 
```

***

#### Step 4.3: Creating blockchain accounts[​](https://aptos.dev/tutorials/your-first-nft#step-43-creating-blockchain-accounts) <a href="#step-43-creating-blockchain-accounts" id="step-43-creating-blockchain-accounts"></a>

In Aptos, each account must have an on-chain representation in order to support receive tokens and coins as well as interacting in other dApps. An account represents a medium for storing assets, hence it must be explicitly created. This example leverages the Faucet to create Alice and Bob's accounts:

* Typescript
* Python
* Rust

```
await faucetClient.fundAccount(alice.address(), 100_000_000);await faucetClient.fundAccount(bob.address(), 100_000_000); 
```

***

#### Step 4.4: Creating a collection[​](https://aptos.dev/tutorials/your-first-nft#step-44-creating-a-collection) <a href="#step-44-creating-a-collection" id="step-44-creating-a-collection"></a>

Now begins the process of creating tokens. First, the creator must create a collection to store tokens. A collection can contain zero, one, or many distinct tokens within it. The collection does not restrict the attributes of the tokens, as it is only a container.

* Typescript
* Python
* Rust

Your application will call `createCollection`:

```
const txnHash1 = await tokenClient.createCollection(  alice,  collectionName,  "Alice's simple collection",  "https://alice.com",); 
```

The function signature of `createCollection`. It returns a transaction hash:

```
async createCollection(  account: AptosAccount,  name: string,  description: string,  uri: string,  maxAmount: AnyNumber = MAX_U64_BIG_INT,  extraArgs?: OptionalTransactionArgs,): Promise<string> {  
```

***

#### Step 4.5: Creating a token[​](https://aptos.dev/tutorials/your-first-nft#step-45-creating-a-token) <a href="#step-45-creating-a-token" id="step-45-creating-a-token"></a>

To create a token, the creator must specify an associated collection. A token must be associated with a collection and that collection must have remaining tokens that can be minted. There are many attributes associated with a token, but the helper API only exposes the minimal amount required to create static content.

* Typescript
* Python
* Rust

Your application will call `createToken`:

```
const txnHash2 = await tokenClient.createToken(  alice,  collectionName,  tokenName,  "Alice's simple token",  1,  "https://aptos.dev/img/nyan.jpeg",); 
```

The function signature of `createToken`. It returns a transaction hash:

```
async createToken(  account: AptosAccount,  collectionName: string,  name: string,  description: string,  supply: number,  uri: string,  max: AnyNumber = MAX_U64_BIG_INT,  royalty_payee_address: MaybeHexString = account.address(),  royalty_points_denominator: number = 0,  royalty_points_numerator: number = 0,  property_keys: Array<string> = [],  property_values: Array<string> = [],  property_types: Array<string> = [],  extraArgs?: OptionalTransactionArgs,): Promise<string> {  
```

***

#### Step 4.6: Reading token and collection metadata[​](https://aptos.dev/tutorials/your-first-nft#step-46-reading-token-and-collection-metadata) <a href="#step-46-reading-token-and-collection-metadata" id="step-46-reading-token-and-collection-metadata"></a>

Both the collection and token metadata are stored on the creator's account within their `Collections` in a table. The SDKs provide convenience wrappers around querying these specific tables:

* Typescript
* Python
* Rust

To read a collection's metadata:

```
const collectionData = await tokenClient.getCollectionData(alice.address(), collectionName);console.log(`Alice's collection: ${JSON.stringify(collectionData, null, 4)}`); 
```

To read a token's metadata:

```
const tokenData = await tokenClient.getTokenData(alice.address(), collectionName, tokenName);console.log(`Alice's token data: ${JSON.stringify(tokenData, null, 4)}`); 
```

Here's how `getTokenData` queries the token metadata:

```
async getTokenData(  creator: MaybeHexString,  collectionName: string,  tokenName: string,): Promise<TokenTypes.TokenData> {  const creatorHex = creator instanceof HexString ? creator.hex() : creator;  const collection: { type: Gen.MoveStructTag; data: any } = await this.aptosClient.getAccountResource(    creatorHex,    "0x3::token::Collections",  );  const { handle } = collection.data.token_data;  const tokenDataId = {    creator: creatorHex,    collection: collectionName,    name: tokenName,  };  const getTokenTableItemRequest: Gen.TableItemRequest = {    key_type: "0x3::token::TokenDataId",    value_type: "0x3::token::TokenData",    key: tokenDataId,  };  // We know the response will be a struct containing TokenData, hence the  // implicit cast.  return this.aptosClient.getTableItem(handle, getTokenTableItemRequest);} 
```

***

#### Step 4.7: Reading a token balance[​](https://aptos.dev/tutorials/your-first-nft#step-47-reading-a-token-balance) <a href="#step-47-reading-a-token-balance" id="step-47-reading-a-token-balance"></a>

Each token within Aptos is a distinct asset, the assets owned by the user are stored within their `TokenStore`. To get the balance:

* Typescript
* Python
* Rust

```
const aliceBalance1 = await tokenClient.getToken(  alice.address(),  collectionName,  tokenName,  `${tokenPropertyVersion}`,);console.log(`Alice's token balance: ${aliceBalance1["amount"]}`); 
```

***

#### Step 4.8: Offering and claiming a token[​](https://aptos.dev/tutorials/your-first-nft#step-48-offering-and-claiming-a-token) <a href="#step-48-offering-and-claiming-a-token" id="step-48-offering-and-claiming-a-token"></a>

Many users have received unwanted tokens that may cause minimally embarrassment to serious ramifications. Aptos gives the rights to each owner of an account to dictate whether or not to receive unilateral transfers. By default, unilateral transfers are unsupported. So Aptos provides a framework for *offering* and *claiming* tokens.

To offer a token:

* Typescript
* Python
* Rust

```
const txnHash3 = await tokenClient.offerToken(  alice,  bob.address(),  alice.address(),  collectionName,  tokenName,  1,  tokenPropertyVersion,); 
```

To claim a token:

* Typescript
* Python
* Rust

```
const txnHash4 = await tokenClient.claimToken(  bob,  alice.address(),  alice.address(),  collectionName,  tokenName,  tokenPropertyVersion,); 
```

***

#### Step 4.9: Safe unilateral transferring of a token[​](https://aptos.dev/tutorials/your-first-nft#step-49-safe-unilateral-transferring-of-a-token) <a href="#step-49-safe-unilateral-transferring-of-a-token" id="step-49-safe-unilateral-transferring-of-a-token"></a>

To support safe unilateral transfers of a token, the sender may first ask the recipient to acknowledge off-chain about a pending transfer. This comes in the form of a multiagent transaction request. Multiagent transactions contain multiple signatures, one for each on-chain account. Move then can leverage this to give `signer` level permissions to all that signed. For token transfers, this ensures that the receiving party does indeed desire to receive this token without requiring the use of the token transfer framework described above.

* Typescript
* Python
* Rust

```
let txnHash5 = await tokenClient.directTransferToken(  bob,  alice,  alice.address(),  collectionName,  tokenName,  1,  tokenPropertyVersion,); 
```

***

#### Step 4.10: Enabling unilateral token transfers[​](https://aptos.dev/tutorials/your-first-nft#step-410-enabling-unilateral-token-transfers) <a href="#step-410-enabling-unilateral-token-transfers" id="step-410-enabling-unilateral-token-transfers"></a>

Coming soon.

* Python
* Rust
* Typescript

Coming soon.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://jin-network.gitbook.io/jin-network/developer-tutorials/your-first-nft.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
