Hedera
Search…
Create and Transfer an NFT using a Solidity Contract

Summary

Besides creating NFTs using Hedera SDK, you can use a Solidity Contract to create, mint, and transfer NFTs by calling contract functions directly. These are the contracts you will need to import into your working directory provided by Hedera:
We recommend you complete the following introduction to get a basic understanding of Hedera transactions. This example does not build upon the previous examples.
If you are interested in creating, minting, and transferring NFTs using Hedera SDK you can find the example here.
In this example, you will set gas for smart contract transactions multiple times. If you don't have enough gas you will receive anINSUFFICIENT_GAS response. If you set the value too high you will be refunded a maximum of 20% of the amount that was set for the transaction.

1. Create an β€œNFT Creator” Smart Contract

You can find an NFTCreator Solidity contract sample below together with the contract bytecode obtained by compiling the solidity contract using Remix IDE. If you are not familiar with Solidity you can take a look at the docs here.
The following contract is composed of three functions:
  • createNft
  • mintNft
  • transferNft
The important thing to know is that the NFT created in this example will have the contract itself as Treasury Account, Supply Key, and Auto-renew account. There’s NO admin key for the NFT or the contract.
NFTCreator.sol
NFTCreator_sol_NFTCreator.bin
1
// SPDX-License-Identifier: GPL-3.0
2
pragma solidity >=0.5.0 <0.9.0;
3
4
import './HederaResponseCodes.sol';
5
import './IHederaTokenService.sol';
6
import './HederaTokenService.sol';
7
import './ExpiryHelper.sol';
8
9
10
contract NFTCreator is ExpiryHelper {
11
12
function createNft(
13
string memory name,
14
string memory symbol,
15
string memory memo,
16
uint32 maxSupply,
17
uint32 autoRenewPeriod
18
) external payable returns (address){
19
20
IHederaTokenService.TokenKey[] memory keys = new IHederaTokenService.TokenKey[](1);
21
// Set this contract as supply
22
keys[0] = getSingleKey(HederaTokenService.SUPPLY_KEY_TYPE, KeyHelper.CONTRACT_ID_KEY, address(this));
23
24
IHederaTokenService.HederaToken memory token;
25
token.name = name;
26
token.symbol = symbol;
27
token.memo = memo;
28
token.treasury = address(this);
29
token.tokenSupplyType = true; // set supply to FINITE
30
token.maxSupply = maxSupply;
31
token.tokenKeys = keys;
32
token.freezeDefault = false;
33
token.expiry = getAutoRenewExpiry(address(this), autoRenewPeriod); // Contract automatically renew by himself
34
35
(int responseCode, address createdToken) = HederaTokenService.createNonFungibleToken(token);
36
37
if(responseCode != HederaResponseCodes.SUCCESS){
38
revert("Failed to create non-fungible token");
39
}
40
return createdToken;
41
}
42
43
function mintNft(
44
address token,
45
bytes[] memory metadata
46
) external returns(int64){
47
48
(int response, , int64[] memory serial) = HederaTokenService.mintToken(token, 0, metadata);
49
50
if(response != HederaResponseCodes.SUCCESS){
51
revert("Failed to mint non-fungible token");
52
}
53
54
return serial[0];
55
}
56
57
function transferNft(
58
address token,
59
address receiver,
60
int64 serial
61
) external returns(int){
62
63
HederaTokenService.associateToken(receiver, token);
64
int response = HederaTokenService.transferNFT(token, address(this), receiver, serial);
65
66
if(response != HederaResponseCodes.SUCCESS){
67
revert("Failed to transfer non-fungible token");
68
}
69
70
return response;
71
}
72
73
}
Copied!
1
608060405234801561001057600080fd5b50611afc806100206000396000f3fe6080604052600436106100345760003560e01c80630a284cb61461003957806382b562aa14610076578063a1a79cde146100b3575b600080fd5b34801561004557600080fd5b50610060600480360381019061005b9190610d90565b6100e3565b60405161006d9190610e08565b60405180910390f35b34801561008257600080fd5b5061009d60048036038101906100989190610e4f565b610165565b6040516100aa9190610ebb565b60405180910390f35b6100cd60048036038101906100c89190610fb3565b6101d3565b6040516100da9190611091565b60405180910390f35b60008060006100f485600086610370565b9250509150601660030b821461013f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101369061112f565b60405180910390fd5b806000815181106101535761015261114f565b5b60200260200101519250505092915050565b600061017183856104e8565b50600061018085308686610600565b9050601660030b81146101c8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101bf906111f0565b60405180910390fd5b809150509392505050565b600080600167ffffffffffffffff8111156101f1576101f0610b7a565b5b60405190808252806020026020018201604052801561022a57816020015b6102176109c0565b81526020019060019003908161020f5790505b50905061023a601060023061071e565b8160008151811061024e5761024d61114f565b5b60200260200101819052506102616109e0565b87816000018190525086816020018190525085816060018190525030816040019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506001816080019015159081151581525050848160a0019063ffffffff16908163ffffffff1681525050818160e0018190525060008160c0019015159081151581525050610301308561075d565b816101000181905250600080610316836107bb565b91509150601660030b8214610360576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161035790611282565b60405180910390fd5b8094505050505095945050505050565b600080606060008061016773ffffffffffffffffffffffffffffffffffffffff1663278e0b8860e01b8989896040516024016103ae9392919061140f565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516104189190611489565b6000604051808303816000865af19150503d8060008114610455576040519150601f19603f3d011682016040523d82523d6000602084013e61045a565b606091505b5091509150816104b657601560008067ffffffffffffffff81111561048257610481610b7a565b5b6040519080825280602002602001820160405280156104b05781602001602082028036833780820191505090505b506104cb565b808060200190518101906104ca91906115dd565b5b8260030b9250809550819650829750505050505093509350939050565b600080600061016773ffffffffffffffffffffffffffffffffffffffff166349146bde60e01b868660405160240161052192919061164c565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161058b9190611489565b6000604051808303816000865af19150503d80600081146105c8576040519150601f19603f3d011682016040523d82523d6000602084013e6105cd565b606091505b5091509150816105de5760156105f3565b808060200190518101906105f29190611675565b5b60030b9250505092915050565b600080600061016773ffffffffffffffffffffffffffffffffffffffff16635cfc901160e01b8888888860405160240161063d94939291906116a2565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516106a79190611489565b6000604051808303816000865af19150503d80600081146106e4576040519150601f19603f3d011682016040523d82523d6000602084013e6106e9565b606091505b5091509150816106fa57601561070f565b8080602001905181019061070e9190611675565b5b60030b92505050949350505050565b6107266109c0565b60405180604001604052808581526020016107518560405180602001604052806000815250866108dd565b81525090509392505050565b610765610a52565b82816020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505081816040019063ffffffff16908163ffffffff168152505092915050565b60008060008061016773ffffffffffffffffffffffffffffffffffffffff1634639dc711e060e01b876040516024016107f49190611a26565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161085e9190611489565b60006040518083038185875af1925050503d806000811461089b576040519150601f19603f3d011682016040523d82523d6000602084013e6108a0565b606091505b5091509150816108b357601560006108c8565b808060200190518101906108c79190611a86565b5b8160030b915080945081955050505050915091565b6108e5610a95565b600184036109035760018160000190151590811515815250506109b9565b600284036109485781816020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250506109b8565b6003840361095e578281604001819052506109b7565b60048403610974578281606001819052506109b6565b600584036109b55781816080019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250505b5b5b5b5b9392505050565b6040518060400160405280600081526020016109da610a95565b81525090565b6040518061012001604052806060815260200160608152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160608152602001600015158152602001600063ffffffff16815260200160001515815260200160608152602001610a4c610a52565b81525090565b6040518060600160405280600063ffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600063ffffffff1681525090565b6040518060a00160405280600015158152602001600073ffffffffffffffffffffffffffffffffffffffff1681526020016060815260200160608152602001600073ffffffffffffffffffffffffffffffffffffffff1681525090565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610b3182610b06565b9050919050565b610b4181610b26565b8114610b4c57600080fd5b50565b600081359050610b5e81610b38565b92915050565b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610bb282610b69565b810181811067ffffffffffffffff82111715610bd157610bd0610b7a565b5b80604052505050565b6000610be4610af2565b9050610bf08282610ba9565b919050565b600067ffffffffffffffff821115610c1057610c0f610b7a565b5b602082029050602081019050919050565b600080fd5b600080fd5b600067ffffffffffffffff821115610c4657610c45610b7a565b5b610c4f82610b69565b9050602081019050919050565b82818337600083830152505050565b6000610c7e610c7984610c2b565b610bda565b905082815260208101848484011115610c9a57610c99610c26565b5b610ca5848285610c5c565b509392505050565b600082601f830112610cc257610cc1610b64565b5b8135610cd2848260208601610c6b565b91505092915050565b6000610cee610ce984610bf5565b610bda565b90508083825260208201905060208402830185811115610d1157610d10610c21565b5b835b81811015610d5857803567ffffffffffffffff811115610d3657610d35610b64565b5b808601610d438982610cad565b85526020850194505050602081019050610d13565b5050509392505050565b600082601f830112610d7757610d76610b64565b5b8135610d87848260208601610cdb565b91505092915050565b60008060408385031215610da757610da6610afc565b5b6000610db585828601610b4f565b925050602083013567ffffffffffffffff811115610dd657610dd5610b01565b5b610de285828601610d62565b9150509250929050565b60008160070b9050919050565b610e0281610dec565b82525050565b6000602082019050610e1d6000830184610df9565b92915050565b610e2c81610dec565b8114610e3757600080fd5b50565b600081359050610e4981610e23565b92915050565b600080600060608486031215610e6857610e67610afc565b5b6000610e7686828701610b4f565b9350506020610e8786828701610b4f565b9250506040610e9886828701610e3a565b9150509250925092565b6000819050919050565b610eb581610ea2565b82525050565b6000602082019050610ed06000830184610eac565b92915050565b600067ffffffffffffffff821115610ef157610ef0610b7a565b5b610efa82610b69565b9050602081019050919050565b6000610f1a610f1584610ed6565b610bda565b905082815260208101848484011115610f3657610f35610c26565b5b610f41848285610c5c565b509392505050565b600082601f830112610f5e57610f5d610b64565b5b8135610f6e848260208601610f07565b91505092915050565b600063ffffffff82169050919050565b610f9081610f77565b8114610f9b57600080fd5b50565b600081359050610fad81610f87565b92915050565b600080600080600060a08688031215610fcf57610fce610afc565b5b600086013567ffffffffffffffff811115610fed57610fec610b01565b5b610ff988828901610f49565b955050602086013567ffffffffffffffff81111561101a57611019610b01565b5b61102688828901610f49565b945050604086013567ffffffffffffffff81111561104757611046610b01565b5b61105388828901610f49565b935050606061106488828901610f9e565b925050608061107588828901610f9e565b9150509295509295909350565b61108b81610b26565b82525050565b60006020820190506110a66000830184611082565b92915050565b600082825260208201905092915050565b7f4661696c656420746f206d696e74206e6f6e2d66756e6769626c6520746f6b6560008201527f6e00000000000000000000000000000000000000000000000000000000000000602082015250565b60006111196021836110ac565b9150611124826110bd565b604082019050919050565b600060208201905081810360008301526111488161110c565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4661696c656420746f207472616e73666572206e6f6e2d66756e6769626c652060008201527f746f6b656e000000000000000000000000000000000000000000000000000000602082015250565b60006111da6025836110ac565b91506111e58261117e565b604082019050919050565b60006020820190508181036000830152611209816111cd565b9050919050565b7f4661696c656420746f20637265617465206e6f6e2d66756e6769626c6520746f60008201527f6b656e0000000000000000000000000000000000000000000000000000000000602082015250565b600061126c6023836110ac565b915061127782611210565b604082019050919050565b6000602082019050818103600083015261129b8161125f565b9050919050565b600067ffffffffffffffff82169050919050565b6112bf816112a2565b82525050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561132b578082015181840152602081019050611310565b8381111561133a576000848401525b50505050565b600061134b826112f1565b61135581856112fc565b935061136581856020860161130d565b61136e81610b69565b840191505092915050565b60006113858383611340565b905092915050565b6000602082019050919050565b60006113a5826112c5565b6113af81856112d0565b9350836020820285016113c1856112e1565b8060005b858110156113fd57848403895281516113de8582611379565b94506113e98361138d565b925060208a019950506001810190506113c5565b50829750879550505050505092915050565b60006060820190506114246000830186611082565b61143160208301856112b6565b8181036040830152611443818461139a565b9050949350505050565b600081905092915050565b6000611463826112f1565b61146d818561144d565b935061147d81856020860161130d565b80840191505092915050565b60006114958284611458565b915081905092915050565b60008160030b9050919050565b6114b6816114a0565b81146114c157600080fd5b50565b6000815190506114d3816114ad565b92915050565b6114e2816112a2565b81146114ed57600080fd5b50565b6000815190506114ff816114d9565b92915050565b600067ffffffffffffffff8211156115205761151f610b7a565b5b602082029050602081019050919050565b60008151905061154081610e23565b92915050565b600061155961155484611505565b610bda565b9050808382526020820190506020840283018581111561157c5761157b610c21565b5b835b818110156115a557806115918882611531565b84526020840193505060208101905061157e565b5050509392505050565b600082601f8301126115c4576115c3610b64565b5b81516115d4848260208601611546565b91505092915050565b6000806000606084860312156115f6576115f5610afc565b5b6000611604868287016114c4565b9350506020611615868287016114f0565b925050604084015167ffffffffffffffff81111561163657611635610b01565b5b611642868287016115af565b9150509250925092565b60006040820190506116616000830185611082565b61166e6020830184611082565b9392505050565b60006020828403121561168b5761168a610afc565b5b6000611699848285016114c4565b91505092915050565b60006080820190506116b76000830187611082565b6116c46020830186611082565b6116d16040830185611082565b6116de6060830184610df9565b95945050505050565b600081519050919050565b600082825260208201905092915050565b600061170e826116e7565b61171881856116f2565b935061172881856020860161130d565b61173181610b69565b840191505092915050565b61174581610b26565b82525050565b60008115159050919050565b6117608161174b565b82525050565b61176f81610f77565b82525050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b6000819050919050565b6117b4816117a1565b82525050565b600060a0830160008301516117d26000860182611757565b5060208301516117e5602086018261173c565b50604083015184820360408601526117fd8282611340565b915050606083015184820360608601526118178282611340565b915050608083015161182c608086018261173c565b508091505092915050565b600060408301600083015161184f60008601826117ab565b506020830151848203602086015261186782826117ba565b9150508091505092915050565b60006118808383611837565b905092915050565b6000602082019050919050565b60006118a082611775565b6118aa8185611780565b9350836020820285016118bc85611791565b8060005b858110156118f857848403895281516118d98582611874565b94506118e483611888565b925060208a019950506001810190506118c0565b50829750879550505050505092915050565b6060820160008201516119206000850182611766565b506020820151611933602085018261173c565b5060408201516119466040850182611766565b50505050565b600061016083016000830151848203600086015261196a8282611703565b915050602083015184820360208601526119848282611703565b9150506040830151611999604086018261173c565b50606083015184820360608601526119b18282611703565b91505060808301516119c66080860182611757565b5060a08301516119d960a0860182611766565b5060c08301516119ec60c0860182611757565b5060e083015184820360e0860152611a048282611895565b915050610100830151611a1b61010086018261190a565b508091505092915050565b60006020820190508181036000830152611a40818461194c565b905092915050565b6000611a5382610b06565b9050919050565b611a6381611a48565b8114611a6e57600080fd5b50565b600081519050611a8081611a5a565b92915050565b60008060408385031215611a9d57611a9c610afc565b5b6000611aab858286016114c4565b9250506020611abc85828601611a71565b915050925092905056fea2646970667358221220cdc42bff95d0a45152dc9da522a29db234e626280cc22363dd793efc0ff7428664736f6c634300080e0033
Copied!

2. Store your bytecode on the Hedera Network

Store your contract on Hedera using ContractCreateFlow(). This single call performs FileCreateTransaction(),FileAppendTransaction(), and ContractCreateTransaction() for you. See the difference here.
Java
JavaScript
Go
1
// Create contract
2
ContractCreateFlow createContract = new ContractCreateFlow()
3
.setBytecode(bytecode) // Contract bytecode
4
.setGas(150_000); // Increase if revert
5
​
6
TransactionResponse createContractTx = createContract.execute(client);
7
TransactionReceipt createContractRx = createContractTx.getReceipt(client);
8
// Get the new contract ID
9
ContractId newContractId = createContractRx.contractId;
10
11
System.out.println("Contract created with ID: " + newContractId);
Copied!
1
// Create contract
2
const createContract = new ContractCreateFlow()
3
.setGas(150000) // Increase if revert
4
.setBytecode(bytecode); // Contract bytecode
5
const createContractTx = await createContract.execute(client);
6
const createContractRx = await createContractTx.getReceipt(client);
7
const contractId = createContractRx.contractId;
8
​
9
console.log(`Contract created with ID: ${contractId} \n`);
Copied!
1
//Create the transaction
2
createContract := hedera.NewContractCreateFlow().
3
SetGas(150000).
4
SetBytecode([]byte(bytecode))
5
​
6
//Sign the transaction with the client operator key and submit to a Hedera network
7
txResponse, err := createContract.Execute(client)
8
if err != nil {
9
panic(err)
10
}
11
​
12
//Request the receipt of the transaction
13
receipt, err := txResponse.GetReceipt(client)
14
if err != nil {
15
panic(err)
16
}
17
​
18
//Get the contract ID
19
newContractId := *receipt.ContractID
20
​
21
fmt.Printf("The new contract ID is %v\n", newContractId)
Copied!

3. Execute the Contract to Create an NFT

The parameters you need to specify for this contract call are Name, Symbol, Memo, Maximum Supply, and Expiration. Setting an expiration date in seconds is required because entities on Hedera will need to pay a β€œrent” to persist. In this case, the contract entity will pay all NFT auto-renewal fees.
Note that expiration must be between 82 and 91 days specified in seconds. This window will change when HIP-372 replaces HIP-16.
Java
JavaScript
Go
1
// Create NFT using contract
2
ContractExecuteTransaction createToken = new ContractExecuteTransaction()
3
.setContractId(newContractId) // Contract id
4
.setGas(300_000) // Increase if revert
5
.setPayableAmount(new Hbar(20)) // Increase if revert
6
.setFunction("createNft", new ContractFunctionParameters()
7
.addString("Fall Collection") // NFT Name
8
.addString("LEAF") // NFT Symbol
9
.addString("Just a memo") // NFT Memo
10
.addUint32(10) // NFT max supply
11
.addUint32(7_000_000)); // Expiration: Needs to be between 6999999 and 8000001
12
​
13
TransactionResponse createTokenTx = createToken.execute(client);
14
TransactionRecord createTokenRx = createTokenTx.getRecord(client);
15
​
16
String tokenIdSolidityAddr = createTokenRx.contractFunctionResult.getAddress(0);
17
AccountId tokenId = AccountId.fromSolidityAddress(tokenIdSolidityAddr);
18
​
19
System.out.println("Token created with ID: " + tokenId);
Copied!
1
// Create NFT from precompile
2
const createToken = new ContractExecuteTransaction()
3
.setContractId(contractId)
4
.setGas(300000) // Increase if revert
5
.setPayableAmount(20) // Increase if revert
6
.setFunction("createNft",
7
new ContractFunctionParameters()
8
.addString("Fall Collection") // NFT name
9
.addString("LEAF") // NFT symbol
10
.addString("Just a memo") // NFT memo
11
.addUint32(250) // NFT max supply
12
.addUint32(7000000) // Expiration: Needs to be between 6999999 and 8000001
13
);
14
const createTokenTx = await createToken.execute(client);
15
const createTokenRx = await createTokenTx.getRecord(client);
16
const tokenIdSolidityAddr = createTokenRx.contractFunctionResult.getAddress(0);
17
const tokenId = AccountId.fromSolidityAddress(tokenIdSolidityAddr);
18
​
19
console.log(`Token created with ID: ${tokenId} \n`);
Copied!
1
contractParams := hedera.NewContractFunctionParameters().
2
AddString("Fall Collection"). // NFT name
3
AddString("LEAF"). // NFT symbol
4
AddString("Just a memo"). // NFT memo
5
AddUint32(250). // NFT max supply
6
AddUint32(7000000) // Expiration: Needs to be between 6999999 and 8000001
7
//Create NFT
8
createToken, err := hedera.NewContractExecuteTransaction().
9
//The contract ID
10
SetContractID(newContractId).
11
//The max gas
12
SetGas(300000).
13
SetPayableAmount(hedera.NewHbar(20)).
14
//The contract function to call and parameters
15
SetFunction("createNft", contractParams).
16
Execute(client)
17
​
18
if err != nil {
19
panic(err)
20
}
21
​
22
//Get the record
23
txRecord, err := createToken.GetRecord(client)
24
if err != nil {
25
panic(err)
26
}
27
​
28
//Get transaction status
29
contractResult, err := txRecord.GetContractExecuteResult()
30
if err != nil {
31
panic(err)
32
}
33
tokenIdSolidityAddr := hex.EncodeToString(contractResult.GetAddress(0))
34
​
35
tokenId, err := hedera.AccountIDFromSolidityAddress(tokenIdSolidityAddr)
36
if err != nil {
37
panic(err)
38
}
39
​
40
fmt.Printf("Token created with ID: %v\n", tokenId)
Copied!

4. Execute the Contract to Mint a New NFT

After the token ID is created, you mint each NFT under that ID using the mintNft function. For the minting, you must specify the token ID as a Solidity address and the NFT metadata.
Both the NFT image and metadata live in the InterPlanetary File System (IPFS), which provides decentralized storage. The file metadata.json contains the metadata for the NFT. An IPFS URI pointing to the metadata file is used during minting of a new NFT. Notice that the metadata file contains a URI pointing to the NFT image.
For the latest NFT Token Metadata JSON Schema see HIP-412.
Java
JavaScript
Go
1
// Mint NFT
2
ContractExecuteTransaction mintToken = new ContractExecuteTransaction()
3
.setContractId(newContractId)
4
.setGas(1_500_000)
5
.setFunction("mintNft", new ContractFunctionParameters()
6
.addAddress(tokenIdSolidityAddr) // Token address
7
.addBytesArray(byteArray)); // Metadata
8
​
9
TransactionResponse mintTokenTx = mintToken.execute(client);
10
TransactionRecord mintTokenRx = mintTokenTx.getRecord(client);
11
// NFT serial number
12
long serial = mintTokenRx.contractFunctionResult.getInt64(0);
13
​
14
System.out.println("Minted NFT with serial: " + serial);
Copied!
1
// ipfs URI
2
metadata = "ipfs://bafyreie3ichmqul4xa7e6xcy34tylbuq2vf3gnjf7c55trg3b6xyjr4bku/metadata.json";
3
4
// Mint NFT
5
const mintToken = new ContractExecuteTransaction()
6
.setContractId(contractId)
7
.setGas(1000000)
8
.setFunction("mintNft",
9
new ContractFunctionParameters()
10
.addAddress(tokenIdSolidityAddr) // Token address
11
.addBytesArray([Buffer.from(metadata)]) // Metadata
12
);
13
const mintTokenTx = await mintToken.execute(client);
14
const mintTokenRx = await mintTokenTx.getRecord(client);
15
const serial = mintTokenRx.contractFunctionResult.getInt64(0);
16
​
17
console.log(`Minted NFT with serial: ${serial} \n`);
Copied!
1
// ipfs URI
2
metadata := "ipfs://bafyreie3ichmqul4xa7e6xcy34tylbuq2vf3gnjf7c55trg3b6xyjr4bku/metadata.json"
3
bytesArray := [][]byte{}
4
bytesArray = append(bytesArray, []byte(metadata))
5
​
6
// Add token address to params
7
mintParams, err := hedera.NewContractFunctionParameters().
8
AddAddress(tokenIdSolidityAddr)
9
​
10
if err != nil {
11
panic(err)
12
}
13
​
14
// Add metadata to params
15
mintParams = mintParams.AddBytesArray(bytesArray)
16
​
17
// Mint NFT
18
mintToken, err := hedera.NewContractExecuteTransaction().
19
//The contract ID
20
SetContractID(newContractId).
21
//The max gas
22
SetGas(1000000).
23
//The contract function to call and parameters
24
SetFunction("mintNft", mintParams).
25
Execute(client)
26
​
27
if err != nil {
28
panic(err)
29
}
30
​
31
//Get the record
32
mintRecord, err := mintToken.GetRecord(client)
33
if err != nil {
34
panic(err)
35
}
36
​
37
//Get transaction status
38
mintResult, err := mintRecord.GetContractExecuteResult()
39
if err != nil {
40
panic(err)
41
}
42
serial := mintResult.GetInt64(0)
43
​
44
fmt.Printf("Minted NFT with serial: %v\n", serial)
Copied!
metadata.json
1
{
2
"name": "LEAF1.jpg",
3
"creator": "Mother Nature",
4
"description": "Autumn",
5
"type": "image/jpg",
6
"format": "none",
7
"properties": {
8
"city": "Boston",
9
"season": "Fall",
10
"decade": "20's"
11
},
12
"image": "ipfs://bafybeig35bheyqpi4qlnuljpok54ud753bnp62fe6jit343hv3oxhgnbfm/LEAF1.jpg"
13
}
Copied!

5. Execute the Contract to Transfer the NFT

The NFT is minted to the contract address because the contract is the treasury for the token. Now transfer the NFT to another account or contract address. In this example, you will transfer the NFT to Alice. For the transfer, you must specify the token address and NFT serial number.
The transferNft function in the Solidity contract contains a call to an associateToken function that will automatically associate Alice to the token ID. This association transaction must be signed using Alice's private key. After signing, Alice will receive the NFT.
Java
JavaScript
Go
1
// Transfer NFT to Alice
2
ContractExecuteTransaction transferToken = new ContractExecuteTransaction()
3
.setContractId(newContractId)
4
.setGas(1_500_000)
5
.setFunction("transferNft", new ContractFunctionParameters()
6
.addAddress(tokenIdSolidityAddr) // Token id
7
.addAddress(aliceId.toSolidityAddress()) // Token receiver (Alice)
8
.addInt64(serial)) // Serial number
9
.freezeWith(client) // Freeze transaction using client
10
.sign(aliceKey); //Sign using Alice Private Key
11
​
12
TransactionResponse transferTokenTx = transferToken.execute(client);
13
TransactionReceipt transferTokenRx = transferTokenTx.getReceipt(client);
14
​
15
System.out.println("Trasnfer status: " + transferTokenRx.status);
Copied!
1
// Transfer NFT to Alice
2
const transferToken = await new ContractExecuteTransaction()
3
.setContractId(contractId)
4
.setGas(1000000)
5
.setFunction("transferNft",
6
new ContractFunctionParameters()
7
.addAddress(tokenIdSolidityAddr) // Token address
8
.addAddress(aliceId.toSolidityAddress()) // Token receiver (Alice)
9
.addInt64(serial)) // NFT serial number
10
.freezeWith(client) // freezing using client
11
.sign(aliceKey); // Sign transaction with Alice
12
const transferTokenTx = await transferToken.execute(client);
13
const transferTokenRx = await transferTokenTx.getReceipt(client);
14
​
15
console.log(`Transfer status: ${transferTokenRx.status} \n`);
Copied!
1
// Add token address to params
2
transferParams, err := hedera.NewContractFunctionParameters().
3
AddAddress(tokenIdSolidityAddr)
4
// Add Alice address to params
5
transferParams, err = transferParams.AddAddress(aliceAccountId.ToSolidityAddress())
6
if err != nil {
7
panic(err)
8
}
9
transferParams = transferParams.AddInt64(serial)
10
​
11
// Transfer NFT
12
transferToken, err := hedera.NewContractExecuteTransaction().
13
//The contract ID
14
SetContractID(newContractId).
15
//The max gas
16
SetGas(1000000).
17
//The contract function to call and parameters
18
SetFunction("transferNft", transferParams).
19
FreezeWith(client)
20
​
21
if err != nil {
22
panic(err)
23
}
24
​
25
transferSubmit, err := transferToken.Sign(aliceKey).Execute(client)
26
if err != nil {
27
panic(err)
28
}
29
​
30
//Get the record
31
transferRecord, err := transferSubmit.GetReceipt(client)
32
if err != nil {
33
panic(err)
34
}
35
​
36
fmt.Printf("Transfer status: %v\n", transferRecord.Status)
Copied!

Code Check βœ…

Java
JavaScript
Go
1
package _nft_hscs_hts.hedera;
2
​
3
import java.io.IOException;
4
import java.nio.file.Files;
5
import java.nio.file.Paths;
6
import java.util.Objects;
7
import java.util.concurrent.TimeoutException;
8
​
9
import com.hedera.hashgraph.sdk.*;
10
import io.github.cdimascio.dotenv.Dotenv;
11
​
12
public class Deploy {
13
14
// Account creation function
15
private static AccountId accountCreator(PrivateKey pvKey, int iBal , Client client) throws TimeoutException, PrecheckStatusException, ReceiptStatusException {
16
AccountCreateTransaction transaction = new AccountCreateTransaction()
17
.setKey(pvKey.getPublicKey())
18
.setInitialBalance(new Hbar(iBal));
19
​
20
TransactionResponse txResponse = transaction.execute(client);
21
​
22
TransactionReceipt receipt = txResponse.getReceipt(client);
23
​
24
return receipt.accountId;
25
​
26
}
27
​
28
public static void main( String[] args ) throws TimeoutException, PrecheckStatusException, ReceiptStatusException, IOException
29
{
30
// ipfs URI
31
String metadata = ("ipfs://bafyreie3ichmqul4xa7e6xcy34tylbuq2vf3gnjf7c55trg3b6xyjr4bku/metadata.json");
32
byte[][] byteArray = new byte[1][metadata.length()];
33
byteArray[0] = metadata.getBytes();
34
35
AccountId operatorId = AccountId.fromString(Objects.requireNonNull(Dotenv.load().get("ACCOUNT_ID")));
36
PrivateKey operatorKey = PrivateKey.fromString(Objects.requireNonNull(Dotenv.load().get("PRIVATE_KEY")));
37
38
Client client = Client.forTestnet();
39
client.setOperator(operatorId, operatorKey);
40
41
PrivateKey aliceKey = PrivateKey.generateED25519();
42
AccountId aliceId = accountCreator(aliceKey, 100, client);
43
System.out.print(aliceId);
44
45
String bytecode = Files.readString(Paths.get("./NFTCreator_sol_NFTCreator.bin"));
46
47
// Create contract
48
ContractCreateFlow createContract = new ContractCreateFlow()
49
.setBytecode(bytecode) // Contract bytecode
50
.setGas(150_000); // Increase if revert
51
52
TransactionResponse createContractTx = createContract.execute(client);
53
TransactionReceipt createContractRx = createContractTx.getReceipt(client);
54
// Get the new contract ID
55
ContractId newContractId = createContractRx.contractId;
56
57
System.out.println("Contract created with ID: " + newContractId);
58
59
// Create NFT using contract
60
ContractExecuteTransaction createToken = new ContractExecuteTransaction()
61
.setContractId(newContractId) // Contract id
62
.setGas(300_000) // Increase if revert
63
.setPayableAmount(new Hbar(20)) // Increase if revert
64
.setFunction("createNft", new ContractFunctionParameters()
65
.addString("Fall Collection") // NFT Name
66
.addString("LEAF") // NFT Symbol
67
.addString("Just a memo") // NFT Memo
68
.addUint32(10) // NFT max supply
69
.addUint32(7_000_000)); // Expiration: Needs to be between 6999999 and 8000001
70
71
TransactionResponse createTokenTx = createToken.execute(client);
72
TransactionRecord createTokenRx = createTokenTx.getRecord(client);
73
74
String tokenIdSolidityAddr = createTokenRx.contractFunctionResult.getAddress(0);
75
AccountId tokenId = AccountId.fromSolidityAddress(tokenIdSolidityAddr);
76
77
System.out.println("Token created with ID: " + tokenId);
78
79
// Mint NFT
80
ContractExecuteTransaction mintToken = new ContractExecuteTransaction()
81
.setContractId(newContractId)
82
.setGas(1_500_000)
83
.setFunction("mintNft", new ContractFunctionParameters()
84
.addAddress(tokenIdSolidityAddr) // Token address
85
.addBytesArray(byteArray)); // Metadata
86
87
TransactionResponse mintTokenTx = mintToken.execute(client);
88
TransactionRecord mintTokenRx = mintTokenTx.getRecord(client);
89
// NFT serial number
90
long serial = mintTokenRx.contractFunctionResult.getInt64(0);
91
92
System.out.println("Minted NFT with serial: " + serial);
93
94
// Transfer NFT to Alice
95
ContractExecuteTransaction transferToken = new ContractExecuteTransaction()
96
.setContractId(newContractId)
97
.setGas(1_500_000)
98
.setFunction("transferNft", new ContractFunctionParameters()
99
.addAddress(tokenIdSolidityAddr) // Token id
100
.addAddress(aliceId.toSolidityAddress()) // Token receiver (Alice)
101
.addInt64(serial)) // Serial number
102
.freezeWith(client) // Freeze transaction using client
103
.sign(aliceKey); //Sign using Alice Private Key
104
105
TransactionResponse transferTokenTx = transferToken.execute(client);
106
TransactionReceipt transferTokenRx = transferTokenTx.getReceipt(client);
107
108
System.out.println("Trasnfer status: " + transferTokenRx.status);
109
110
}
111
}
Copied!
1
const fs = require('fs');
2
const { AccountId,
3
PrivateKey,
4
Client,
5
ContractCreateFlow,
6
ContractExecuteTransaction,
7
ContractFunctionParameters,
8
AccountCreateTransaction,
9
Hbar
10
} = require('@hashgraph/sdk');
11
12
// Setup your .env path
13
require('dotenv').config({path: __dirname + '/../../.env'});
14
15
// ipfs URI
16
metadata = "ipfs://bafyreie3ichmqul4xa7e6xcy34tylbuq2vf3gnjf7c55trg3b6xyjr4bku/metadata.json";
17
18
const operatorKey = PrivateKey.fromString(process.env.PRIVATE_KEY);
19
const operatorId = AccountId.fromString(process.env.ACCOUNT_ID);
20
21
const client = Client.forTestnet().setOperator(operatorId, operatorKey);
22
23
// Account creation function
24
async function accountCreator(pvKey, iBal) {
25
const response = await new AccountCreateTransaction()
26
.setInitialBalance(new Hbar(iBal))
27
.setKey(pvKey.publicKey)
28
.execute(client);
29
const receipt = await response.getReceipt(client);
30
return receipt.accountId;
31
}
32
33
const main = async () => {
34
35
// Init Alice account
36
const aliceKey = PrivateKey.generateED25519();
37
const aliceId = await accountCreator(aliceKey, 100);
38
39
const bytecode = fs.readFileSync('./binaries/NFTCreator_sol_NFTCreator.bin');
40
41
// Create contract
42
const createContract = new ContractCreateFlow()
43
.setGas(150000) // Increase if revert
44
.setBytecode(bytecode); // Contract bytecode
45
const createContractTx = await createContract.execute(client);
46
const createContractRx = await createContractTx.getReceipt(client);
47
const contractId = createContractRx.contractId;
48
49
console.log(`Contract created with ID: ${contractId} \n`);
50
51
// Create NFT from precompile
52
const createToken = new ContractExecuteTransaction()
53
.setContractId(contractId)
54
.setGas(300000) // Increase if revert
55
.setPayableAmount(20) // Increase if revert
56
.setFunction("createNft",
57
new ContractFunctionParameters()
58
.addString("Fall Collection") // NFT name
59
.addString("LEAF") // NFT symbol
60
.addString("Just a memo") // NFT memo
61
.addUint32(250) // NFT max supply
62
.addUint32(7000000) // Expiration: Needs to be between 6999999 and 8000001
63
);
64
const createTokenTx = await createToken.execute(client);
65
const createTokenRx = await createTokenTx.getRecord(client);
66
const tokenIdSolidityAddr = createTokenRx.contractFunctionResult.getAddress(0);
67
const tokenId = AccountId.fromSolidityAddress(tokenIdSolidityAddr);
68
69
console.log(`Token created with ID: ${tokenId} \n`);
70
71
// Mint NFT
72
const mintToken = new ContractExecuteTransaction()
73
.setContractId(contractId)
74
.setGas(1000000)
75
.setFunction("mintNft",
76
new ContractFunctionParameters()
77
.addAddress(tokenIdSolidityAddr) // Token address
78
.addBytesArray([Buffer.from(metadata)]) // Metadata
79
);
80
const mintTokenTx = await mintToken.execute(client);
81
const mintTokenRx = await mintTokenTx.getRecord(client);
82
const serial = mintTokenRx.contractFunctionResult.getInt64(0);
83
84
console.log(`Minted NFT with serial: ${serial} \n`);
85
86
// Transfer NFT to Alice
87
const transferToken = await new ContractExecuteTransaction()
88
.setContractId(contractId)
89
.setGas(1000000)
90
.setFunction("transferNft",
91
new ContractFunctionParameters()
92
.addAddress(tokenIdSolidityAddr) // Token address
93
.addAddress(aliceId.toSolidityAddress()) // Token receiver (Alice)
94
.addInt64(serial)) // NFT serial number
95
.freezeWith(client) // freezing using client
96
.sign(aliceKey); // Sign transaction with Alice
97
const transferTokenTx = await transferToken.execute(client);
98
const transferTokenRx = await transferTokenTx.getReceipt(client);
99
100
console.log(`Transfer status: ${transferTokenRx.status} \n`);
101
102
}
103
104
main();
Copied!
1
package main
2
​
3
import (
4
"encoding/hex"
5
"fmt"
6
"io/ioutil"
7
"os"
8
​
9
"github.com/hashgraph/hedera-sdk-go/v2"
10
"github.com/joho/godotenv"
11
)
12
​
13
func main() {
14
godotenv.Load("../.env")
15
​
16
metadata := "ipfs://bafyreie3ichmqul4xa7e6xcy34tylbuq2vf3gnjf7c55trg3b6xyjr4bku/metadata.json"
17
bytesArray := [][]byte{}
18
bytesArray = append(bytesArray, []byte(metadata))
19
​
20
var client *hedera.Client
21
var err error
22
​
23
client = hedera.ClientForTestnet()
24
​
25
operatorId, err := hedera.AccountIDFromString(os.Getenv("OPERATOR_ID"))
26
if err != nil {
27
panic(err)
28
}
29
​
30
operatorKey, err := hedera.PrivateKeyFromString(os.Getenv("OPERATOR_PVKEY"))
31
if err != nil {
32
panic(err)
33
}
34
​
35
client.SetOperator(operatorId, operatorKey)
36
​
37
aliceKey, err := hedera.PrivateKeyGenerateEd25519()
38
if err != nil {
39
panic(err)
40
}
41
​
42
//Create the transaction
43
accountCreate := hedera.NewAccountCreateTransaction().
44
SetKey(aliceKey.PublicKey()).
45
SetInitialBalance(hedera.NewHbar(100))
46
​
47
//Sign the transaction with the client operator private key and submit to a Hedera network
48
accountCreateSubmit, err := accountCreate.Execute(client)
49
if err != nil {
50
panic(err)
51
}
52
​
53
//Request the receipt of the transaction
54
accountCreateReceipt, err := accountCreateSubmit.GetReceipt(client)
55
if err != nil {
56
panic(err)
57
}
58
​
59
//Get the account ID
60
aliceAccountId := *accountCreateReceipt.AccountID
61
​
62
// Make sure to close client after running
63
defer func() {
64
err = client.Close()
65
if err != nil {
66
println(err.Error(), ": error closing client")
67
return
68
}
69
}()
70
​
71
// Read bytecode
72
bytecode, err := ioutil.ReadFile("./NFTCreator_sol_NFTCreator.bin")
73
if err != nil {
74
println(err.Error(), ": error reading bytecode")
75
return
76
}
77
​
78
//Create the transaction
79
createContract := hedera.NewContractCreateFlow().
80
SetGas(150000).
81
SetBytecode([]byte(bytecode))
82
​
83
//Sign the transaction with the client operator key and submit to a Hedera network
84
txResponse, err := createContract.Execute(client)
85
if err != nil {
86
panic(err)
87
}
88
​
89
//Request the receipt of the transaction
90
receipt, err := txResponse.GetReceipt(client)
91
if err != nil {
92
panic(err)
93
}
94
​
95
//Get the contract ID
96
newContractId := *receipt.ContractID
97
​
98
fmt.Printf("The new contract ID is %v\n", newContractId)
99
​
100
contractParams := hedera.NewContractFunctionParameters().
101
AddString("Fall Collection"). // NFT name
102
AddString("LEAF"). // NFT symbol
103
AddString("Just a memo"). // NFT memo
104
AddUint32(250). // NFT max supply
105
AddUint32(7000000) // Expiration: Needs to be between 6999999 and 8000001
106
//Create NFT
107
createToken, err := hedera.NewContractExecuteTransaction().
108
//The contract ID
109
SetContractID(newContractId).
110
//The max gas
111
SetGas(300000).
112
SetPayableAmount(hedera.NewHbar(20)).
113
//The contract function to call and parameters
114
SetFunction("createNft", contractParams).
115
Execute(client)
116
​
117
if err != nil {
118
panic(err)
119
}
120
​
121
//Get the record
122
txRecord, err := createToken.GetRecord(client)
123
if err != nil {
124
panic(err)
125
}
126
​
127
//Get transaction status
128
contractResult, err := txRecord.GetContractExecuteResult()
129
if err != nil {
130
panic(err)
131
}
132
tokenIdSolidityAddr := hex.EncodeToString(contractResult.GetAddress(0))
133
​
134
tokenId, err := hedera.AccountIDFromSolidityAddress(tokenIdSolidityAddr)
135
if err != nil {
136
panic(err)
137
}
138
​
139
fmt.Printf("Token created with ID: %v\n", tokenId)
140
​
141
// Add token address to params
142
mintParams, err := hedera.NewContractFunctionParameters().
143
AddAddress(tokenIdSolidityAddr)
144
​
145
if err != nil {
146
panic(err)
147
}
148
​
149
// Add metadata to params
150
mintParams = mintParams.AddBytesArray(bytesArray)
151
​
152
// Mint NFT
153
mintToken, err := hedera.NewContractExecuteTransaction().
154
//The contract ID
155
SetContractID(newContractId).
156
//The max gas
157
SetGas(1000000).
158
//The contract function to call and parameters
159
SetFunction("mintNft", mintParams).
160
Execute(client)
161
​
162
if err != nil {
163
panic(err)
164
}
165
​
166
//Get the record
167
mintRecord, err := mintToken.GetRecord(client)
168
if err != nil {
169
panic(err)
170
}
171
​
172
//Get transaction status
173
mintResult, err := mintRecord.GetContractExecuteResult()