Follow its steps to set up the account and on how to upload assets.
Upload the assets
Upload token-images folder, and then we can fill the image field for token meta data. Do it for all your token meta data. (change to your own ipfs urls)
After filling all the info for token meta data, upload metadata folder.
Finally, upload the logo picture.
Set the metadata, royalty, token config
Make a nft-config.json in the project root folder, we'll use these info for later use. Content below:
{
"collectionMeta": {
"name": "Aptos Birds",
"description": "They're a collection of 10,000 utility-enabled PFPs that feature a richly diverse and unique pool of rarity-powered traits. What's more, each Aptosbird unlocks private club membership and additional benefits the longer you hold them.",
"external_url": "https://aptosbirds.xyz"
},
"royalty": {
"takeRate": 5,
"feeRecipient": "0xc8c5f00f234b26a7e206d616a9a2063e6b7894651abc94d4b0ace979f53295fa"
},
"tokenInfo": {
"maxSupply": 10000
},
"assets": {
"logo": "./assets/logo.png",
"collectionImagesPath": "./assets/collection-images/"
}
}
You can adjust the config according to your need. A few things to be clear:
takeRate: the percent of the royalty, 5 stands for 5%.
feeRecipient: the address that will collect the royalty fees
maxSupply: the maximum supply for this collection
Set up Aptos account
We need an Aptos account to interact with the blockchain. If you don't have an account, you can generate an account using the Petra wallet.
Fund your account with some $APT tokens, 1 $APT tokens should be enough. You can buy on Binance, FTX.
Mint NFT using typescript
Make a src folder in the project root to contain all the source code, also you need a .env file to store PRIV_KEY to prevent you from submitting it to a git repo.
account.ts
Create account.ts under the src folder. Content below:
// account.ts
import dotenv from 'dotenv';
dotenv.config();
import { AptosAccount } from "aptos";
// Need to set PRIV_KEY in the .env file
const PRIV_KEY = process.env.PRIV_KEY;
// AptosAccount accepts unit8array as private key, so we need this helper function
const fromHexStringToUnit8Array = (hexString: string) =>
Uint8Array.from(hexString.match(/.{1,2}/g).map((byte) => parseInt(byte, 16)));
const PRIV_KEY_ARR = fromHexStringToUnit8Array(PRIV_KEY);
export const aptosAccount = new AptosAccount(PRIV_KEY_ARR);
Get the private key from .env file
Convert to Unit8Array
Initialize the account, and export for later use.
chain.ts
Create chain.ts under the src folder. Content below:
// chain.ts
export const APTOS_NODE_URL_MAIN = 'https://fullnode.mainnet.aptoslabs.com'
import { AptosClient, FaucetClient, MaybeHexString, TokenClient } from "aptos";
const APTOS_NODE_URL_MAIN = 'https://fullnode.mainnet.aptoslabs.com'
const APTOS_NODE_URL_DEV = 'https://fullnode.devnet.aptoslabs.com'
const APTOS_FAUCET_URL_DEV = 'https://faucet.devnet.aptoslabs.com'
// For mainnet usage, set CHAIN_NET in .env file
const CHAIN_NET = process.env.CHAIN_NET;
export const isMainnet = CHAIN_NET === "Main";
// Initialize aptos client
// This client is used to interact with aptos blockchain
const aptosNodeUrl = isMainnet ? APTOS_NODE_URL_MAIN : APTOS_NODE_URL_DEV;
const aptosClient = new AptosClient(aptosNodeUrl);
export const tokenClient = new TokenClient(aptosClient);
// For dev purpose, we need to fund our account with faucet.
export const fundAccountForDev = (address: MaybeHexString) => {
const faucetClient = new FaucetClient(APTOS_NODE_URL_DEV, APTOS_FAUCET_URL_DEV);
faucetClient.fundAccount(address, 100_000_000);
}
Here we get the tokenClient to interact with Aptos blockchain, and a helper function fundAccountForDev to get $APT for dev purpose. isMainnet flag is used turn on/off mainnet interaction.
issue_NFT.ts
Create issue_NFT.ts under the src folder. Content below:
// issue_NFT.ts
import collectionConfig from "../collection-config.json";
import { aptosAccount } from "./account";
import { aptosClient, tokenClient, fundAccountForDev, isMainnet } from "./chain";
(async () => {
console.log("=== Addresses ===");
console.log(`Account address: ${aptosAccount.address()}`);
console.log("");
// Fund the account if in dev
if (isMainnet) {
await fundAccountForDev(aptosAccount.address());
}
console.log("=== Creating Collection ===");
// Get params from config
const collectionName = collectionConfig.collectionMeta.name;
const collectionDesc = collectionConfig.collectionMeta.description;
const collectionUri = collectionConfig.assets.logoUri;
const collectionMaxAmount = collectionConfig.tokenInfo.maxSupply;
const tokenUri = collectionConfig.assets.tokenMetadataUri;
const feeRecipient = collectionConfig.royalty.feeRecipient;
const royaltyPointsDenominator = 100;
const royaltyPointsNumerator = collectionConfig.royalty.takeRate;
// Create the collection.
const createCollectionTxn = await tokenClient.createCollection(
aptosAccount,
collectionName,
collectionDesc,
collectionUri,
collectionMaxAmount,
);
await aptosClient.waitForTransaction(createCollectionTxn, { checkSuccess: true });
// Log the collection info after creation
const logCollection = async () => {
console.log("Collection info:");
const collectionData = await tokenClient.getCollectionData(aptosAccount.address(), collectionName);
console.log(`${collectionName}: ${JSON.stringify(collectionData, null, 4)}`);
}
await logCollection();
console.log("=== Mint Token ===");
const mintToken = async (tokenId: number) => {
const txnHash = await tokenClient.createToken(
aptosAccount,
collectionName,
`${collectionName} #${tokenId}`, // name of token, exp. Monkey #1
`${collectionName} #${tokenId}`, // description of token
1, // amount to mint, in most cases 1 for ERC721
`${tokenUri}/${tokenId}.json`,
1, // max supply for this token, set 1 for ERC721
feeRecipient,
royaltyPointsDenominator,
royaltyPointsNumerator,
);
await aptosClient.waitForTransaction(txnHash, { checkSuccess: true });
}
// mint token 1
await mintToken(1);
// await mintToken(2); // you can do the same with token 2
// Log the collection info after token mint
logCollection();
})();
The above code created a collection, and mint 1 token under the collection. A few things to konw:
You can only create 1 collection with the same name.
If you set CHAIN_NET=main, you'll need to fund your account with $APT to mint tokens