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).

Copy
Copied
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:

Copy
Copied
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.

Copy
Copied
function_name = 'mint'
function_arguments = {'count': 3}

We then create the transaction object defining the transaction we want to execute:

Copy
Copied
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.

Copy
Copied
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:

Copy
Copied
tx_data['max_fees'] = r.json()['max_fees']

Finally we can post the transaction request to create the transaction on the system:

Copy
Copied
tx = requests.post(LAM + '/transactions', headers=headers, json=tx_data)

print(tx.json())

Below is the response of that request:

Copy
Copied
{'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:

Copy
Copied
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:

Copy
Copied
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:

Copy
Copied
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:

Copy
Copied
tx = requests.post(LAM + '/transactions', headers=headers, json=tx_data)

which returns the following response:

Copy
Copied
{'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:

Copy
Copied
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

Copyright © Ledger Enterprise Platform 2023. All right reserved.