I'm a beginner and trying to learn web3 and want to implement a transfer-button for NFTs (same as you have on Opensea, where you can transfer your NFT to another address).

I have started of by having a React-website where you can connect your Metamask wallet and thereafter I scan the connected wallet for all NFTs using the alchemy-sdk to get contract, ids and so on.

Next step is to do the actual transaction and here I'm a bit lost.

I see that the same library has a method for sending a transaction with


But here I first need a signed transaction and here I'm a bit stuck.

For a normal ETH-transfer it seems a transaction looks something like this (found when I searched)

let transaction = {
    to: "TO-ACCOUNT",
    value: Utils.parseEther("0.001"),
    gasLimit: "21000",
    maxPriorityFeePerGas: Utils.parseUnits("5", "gwei"),
    maxFeePerGas: Utils.parseUnits("20", "gwei"),
    nonce: nonce,
    type: 2,
    chainId: 5,

But how does a transaction looks like when sending an NFT, and how do I sign it in Metamask before using the sendTransaction method?

Or is there another way I should approach this problem :)

1 Answer 1


I finally figured it out by myself, so here is the answer if anyone else is wondering about how to do it.

To transfer an NFT you need to create a eth_sendTransaction request

         const transactionParameters = {
             to: nftContractAddress,
             from:  ownerAddress,
             value: '0',
             data: encodedData

         const txHash = window.ethereum.request({
             method: 'eth_sendTransaction',
             params: [transactionParameters],

Where the encodedData is an encoded transaction containing the toAddress, fromAddress and tokenId.

Since NFTS follow the ERC729-standard they all have a method called safeTransferFrom.

You can create the encoded data doing the following using the ethers package that will use for all NFTs following the standard.

  let iface = new ethers.utils.Interface(erc729Abi)
  return iface.encodeFunctionData("safeTransferFrom", [
    ethers.utils.getAddress(ownerAddress), ethers.utils.getAddress(toAddress), tokenId

Here **erc729Abi** is an ABI containing just the safeTransferFrom, but I suppose passing the whole contract also will work.

stripped erc729Abi I use above
    "inputs": [
        "internalType": "address",
        "name": "from",
        "type": "address"
        "internalType": "address",
        "name": "to",
        "type": "address"
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
    "name": "safeTransferFrom",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.