Mint and transfer NFTs
In this tutorial, we will present how you can mint and transfer NFTs using the Ledger Enterprise API. This will leverage the Smart Contract Interaction (SCI) capability of the platform as well as the /transactions
API functionality.
For this tutorial, we will use the following NFT collection https://goerli-nfts.vercel.app/ on the Goerli testnet to experiment with SCI.
The corresponding contract address is 0x932Ca55B9Ef0b3094E8Fa82435b3b4c50d713043
and the contract can be inspected on Etherscan here: https://goerli.etherscan.io/address/0x932Ca55B9Ef0b3094E8Fa82435b3b4c50d713043
Requirements
Before we get started, you need to have access to your workspace's Ledger Authentication Module (LAM) and have the necessary credentials, i.e. an API account and API key (if applicable).
LAM = '<your_LAM_address>'
headers = {'X-Ledger-API-User': '<your_api_username>', 'X-Ledger-API-Key': '<your_api_key>'}
The Ethereum account you will use to mint and transfer NFTs must also be configured so that the API user is authorized to create transaction requests from this particular account.
Minting NFTs
Let's start with minting a batch of NFTs. We first define the account from which we want to interact with the NFT contract, as well as the contract we want to interact with:
account_name = 'ETH-RESERVE' # name of account on Ledger Vault
nft_contract = '0x932Ca55B9Ef0b3094E8Fa82435b3b4c50d713043'
We then need to define the contract function we want to call, as well as the corresponding arguments. In this example, we want to mint 3 NFTs, so we want to call the mint
function of the contract, with the argument 'count': 3
.
function_name = 'mint'
function_arguments = {'count': 3}
We then create the transaction object defining the transaction we want to execute:
tx_data = {
'account_name': account_name,
'amount': '0',
'coin_fields': {
'contract_interaction': {
'function_arguments': function_arguments,
'function_name': function_name,
}
},
'recipient': nft_contract,
'speed': 'NORMAL'
}
Before creating the transaction, we can estimate the transaction fees for that particular smart contract interaction using the /transactions/fees
endpoint.
import requests
r = requests.post(LAM + '/transactions/fees', headers=headers, json=tx_data)
The max_fees
estimated by the previous request can be attached to the transaction object before being sent to the LAM:
tx_data['max_fees'] = r.json()['max_fees']
Finally we can post the transaction request to create the transaction on the system:
tx = requests.post(LAM + '/transactions', headers=headers, json=tx_data)
print(tx.json())
Below is the response of that request:
{'account_id': 44,
'account_index': 6,
'amount': '0',
'block': None,
'broadcast_on': None,
'coin_fields': {'gas_limit': '191440',
'gas_price': '93190727250',
'contract_interaction': {'contract_data': '6ecd23060000000000000000000000000000000000000000000000000000000000000003',
'contract_name': None,
'dapp': 'NFT',
'function_arguments': {'count': 3},
'function_name': 'mint',
'smart_contract_interaction_type': 'UNKNOWN'},
'type': 'EthereumAndEvm'},
'confirmations': 0,
'created_by': 18,
'created_on': '2023-04-04T03:15:45.090170+00:00',
'currency': 'ethereum_goerli',
'fees': None,
'id': 1048,
'interaction_type': 'UNKNOWN',
'last_request': 859,
'max_fees': '17840432824740000',
'metadata': None,
'min_confirmations': 30,
'notes': [{'content': '', 'title': ''}],
'recipient': '0x932Ca55B9Ef0b3094E8Fa82435b3b4c50d713043',
'senders': None,
'speed': 'NORMAL',
'status': 'APPROVED',
'tx_hash': None,
'type': 'SEND',
'uid': None}
In this example, the account governance is set so that the transaction does not require additional approval to be signed and broadcasted.
From the id
of the previous response, we can fetch a confirmation of the transaction that will provide the transaction hash, which we can use to check the transaction on a blockchain explorer:
tx_id = tx.json()['id']
tx_confirmation = requests.get(LAM + f'/transactions/{tx_id}', headers=headers)
tx_hash = tx_confirmation.json()['tx_hash']
print(f'Transaction on explorer: https://goerli.etherscan.io/tx/{tx_hash}')
which returns:
Transaction on explorer:
https://goerli.etherscan.io/tx/0xb1e6407c1d52c09d02fb938e458a6e6d53a4ab30bf8632d11ed1dc335707ee89
From the explorer we can see that we minted 3 NFTs with ids: 6668
, 6669
and 6670
.
Transfer NFT
Let's now transfer the NFT 6670
to an external wallet. For that, we need to call the function safeTransferFrom
and provide the corresponding parameters:
function_name = 'safeTransferFrom'
function_arguments = {
'from': account_address,
'to': '0xa1825189E6CedB72afAf829cbc30f05D5ad40ECA', # external wallet destination
'tokenId': 6670
}
We then create the corresponding transaction object, and estimate fees for that transactions:
tx_data = {
'account_name': account_name,
'amount': '0',
'coin_fields': {
'contract_interaction': {
'function_arguments': function_arguments,
'function_name': function_name,
}
},
'recipient': nft_contract,
'speed': 'NORMAL'
}
r = requests.post(LAM + '/transactions/fees', headers=headers, json=tx_data)
tx_data['max_fees'] = r.json()['max_fees']
Finally, we post the transaction request:
tx = requests.post(LAM + '/transactions', headers=headers, json=tx_data)
which returns the following response:
{'account_id': 44,
'account_index': 6,
'amount': '0',
'block': None,
'broadcast_on': None,
'coin_fields': {'gas_limit': '77938',
'gas_price': '104507380024',
'contract_interaction': {'contract_data': '42842e0e0000000000000000000000002ce3895fa3ad9a4eacc37fed6ac8c35e5ae8c5cf000000000000000000000000a1825189e6cedb72afaf829cbc30f05d5ad40eca0000000000000000000000000000000000000000000000000000000000001a0e',
'contract_name': None,
'dapp': 'NFT',
'function_arguments': {'from': '0x2CE3895Fa3ad9a4EAcC37feD6ac8c35e5AE8c5cF',
'to': '0xa1825189E6CedB72afAf829cbc30f05D5ad40ECA',
'tokenId': 6670},
'function_name': 'safeTransferFrom',
'smart_contract_interaction_type': 'TRANSFER_ERC721'},
'type': 'EthereumAndEvm'},
'confirmations': 0,
'created_by': 18,
'created_on': '2023-04-04T03:17:24.105170+00:00',
'currency': 'ethereum_goerli',
'fees': None,
'id': 1049,
'interaction_type': 'TRANSFER_ERC721',
'last_request': 860,
'max_fees': '8201438098697564',
'metadata': None,
'min_confirmations': 30,
'notes': [{'content': '', 'title': ''}],
'recipient': '0x932Ca55B9Ef0b3094E8Fa82435b3b4c50d713043',
'senders': None,
'speed': 'NORMAL',
'status': 'APPROVED',
'tx_hash': None,
'type': 'SEND',
'uid': None}
As before, we can get the transaction hash of the NFT transfer to validate it on-chain:
tx_id = tx.json()['id']
tx_confirmation = requests.get(LAM + f'/transactions/{tx_id}', headers=headers)
tx_hash = tx_confirmation.json()['tx_hash']
print(f'Tx on explorer: https://goerli.etherscan.io/tx/{tx_hash}')
which returns:
Tx on explorer:
https://goerli.etherscan.io/tx/0xb76bb1207b52b577533d215073b0fbd75e599f2532b9879c4f3903cc97271101