The NEAR Protocol provides a JavaScript API, known as near-api-js, that allows developers to interact with the Smart Contract and perform various operations related to Non-Fungible Tokens (NFTs).
near-api-js
is a complete library to interact with the NEAR blockchain. You can use it in the browser, or in Node.js runtime.
Using near-api-js
, developers can deploy smart contracts , mint new NFTs and transfer ownership of NFTs.
In the NFT kit we are using near-api-js to do interactions with the Near Protocol Blockchain
Create sub-account :
When developing it's a best practice to create a subaccount and deploy the contract to it.
This function allows the subaccount creation and transfering Near token from the main account to use them for gas fees and storage.
Copy async createAccount (createSubAccount: CreateSubAccount) {
try {
let rpcUrl;
let networkId;
if ( createSubAccount .chain === "testnet" ) {
rpcUrl = "https://rpc.testnet.near.org" ;
networkId = "testnet" ;
} else if ( createSubAccount .chain === "mainnet" ) {
rpcUrl = "https://rpc.mainnet.near.org" ;
networkId = "mainnet" ;
} else {
throw new Error ( "Chain parameter is not defined" );
}
this .addKeyPairToKeyStore (
createSubAccount .account_id ,
createSubAccount .chain
);
this .connectionConfig = {
networkId : networkId ,
keyStore : this .myKeyStore ,
nodeUrl : "https://rpc.testnet.near.org" ,
walletUrl : "" ,
helperUrl : "" ,
explorerUrl : "" ,
};
const near = await nearAPI .connect ( this .connectionConfig);
const account = await near .account ( createSubAccount .account_id);
const publickey = this . keyPair .getPublicKey () .toString ();
const PK = publickey .replace ( "ed25519:" , "" );
const amount = new BN ( createSubAccount .amount);
const response = account .createAccount (
createSubAccount .newAccountId ,
PK ,
amount .mul ( new BN ( "1000000000000000000000000" ))
);
return JSON .stringify ( ( await response). transaction .hash );
} catch (err) {
console .log (err);
}
}
Deploy smart contract with default Metadata :
Every NFT smart contract should be initialized , here we can deploy it with walt.id default metadata.
Copy async deployContract (contractDeployment: ContractDeployment) {
this .addKeyPairToKeyStore (
contractDeployment .account_id ,
contractDeployment .chain
);
const near = await nearAPI .connect ( this .connectionConfig);
const account = await near .account ( contractDeployment .account_id);
const response = await account .deployContract (
fs .readFileSync ( "near/smart contract/waltid_nftkit.wasm" )
);
const contract = new Contract (account , contractDeployment .account_id , {
viewMethods : [] ,
changeMethods : [ "new_default_meta" ] ,
});
const GAS = new BN ( "100000000000000" );
contract .new_default_meta ({
args : {
owner_id : contractDeployment .account_id ,
} ,
gas : GAS ,
});
return JSON .stringify (( await response). transaction .hash);
}
Deploy smart contract with custom Metadata :
For more flexibility we offer a custom metadata initialization to the deployed smart contract.
Copy async deployContractWithCustomMetadata (
ContractDeploymentWithCustomMetadata: DeployContractWithCustomInit
) {
let rpcUrl;
let networkId;
if ( ContractDeploymentWithCustomMetadata .chain === "testnet" ) {
rpcUrl = "https://rpc.testnet.near.org" ;
networkId = "testnet" ;
} else if ( ContractDeploymentWithCustomMetadata .chain === "mainnet" ) {
rpcUrl = "https://rpc.mainnet.near.org" ;
networkId = "mainnet" ;
} else {
throw new Error ( "Chain parameter is not defined" );
}
this .addKeyPairToKeyStore (
ContractDeploymentWithCustomMetadata .account_id ,
ContractDeploymentWithCustomMetadata .chain
);
this .connectionConfig = {
networkId : networkId ,
keyStore : this .myKeyStore ,
nodeUrl : rpcUrl ,
walletUrl : "" ,
helperUrl : "" ,
};
const near = await nearAPI .connect ( this .connectionConfig);
const account = await near .account (
ContractDeploymentWithCustomMetadata .account_id
);
const response = await account .deployContract (
fs .readFileSync ( "near/smart contract/waltid_nftkit.wasm" )
);
const contract = new Contract (
account ,
ContractDeploymentWithCustomMetadata .account_id ,
{
viewMethods : [] ,
changeMethods : [ "new" ] ,
}
);
const GAS = new BN ( "100000000000000" );
contract .new ({
args : {
owner_id : ContractDeploymentWithCustomMetadata .account_id ,
metadata : {
spec : ContractDeploymentWithCustomMetadata .spec ,
name : ContractDeploymentWithCustomMetadata .name ,
symbol : ContractDeploymentWithCustomMetadata .symbol ,
icon : ContractDeploymentWithCustomMetadata .icon ,
base_uri : ContractDeploymentWithCustomMetadata .base_uri ,
reference : ContractDeploymentWithCustomMetadata .reference ,
reference_hash : ContractDeploymentWithCustomMetadata .reference_hash ,
} ,
} ,
gas : GAS ,
});
return JSON .stringify (( await response). transaction .hash);
}
Mint NFT :
Finally we mint the non-fungible token with the custom metadata .
Copy async mintToken (nftmint: NftMint) {
let rpcUrl;
let networkId;
if ( nftmint .chain === "testnet" ) {
rpcUrl = "https://rpc.testnet.near.org" ;
networkId = "testnet" ;
} else if ( nftmint .chain === "mainnet" ) {
rpcUrl = "https://rpc.mainnet.near.org" ;
networkId = "mainnet" ;
} else {
throw new Error ( "Chain parameter is not defined" );
}
this .addKeyPairToKeyStore (
nftmint .account_id ,
nftmint .chain
);
this .connectionConfig = {
networkId : networkId ,
keyStore : this .myKeyStore ,
nodeUrl : rpcUrl ,
walletUrl : "" ,
helperUrl : "" ,
};
const near = await nearAPI .connect ( this .connectionConfig);
const account = await near .account ( nftmint .account_id);
const GAS = new BN ( "100000000000000" );
const Amount_deposited = new BN ( "100000000000000000000000" );
const functionCallResponse = await account .functionCall ({
contractId : nftmint .contract_id ,
methodName : "nft_mint" ,
args : {
token_id : nftmint .token_id ,
metadata : {
title : nftmint .title ,
description : nftmint .description ,
media : nftmint .media ,
media_hash : null ,
} ,
receiver_id : nftmint .receiver_id ,
} ,
gas : GAS ,
attachedDeposit : Amount_deposited ,
});
return JSON .stringify ( functionCallResponse . transaction .hash);
}