Search code examples
ethereumsmartcontractsweb3js

Can I attach a piece of text to a transaction record?


According to the docs for web3.eth.sendTransaction and the docs for eth_sendTransaction:

The transaction object can contain an optional data parameter which should be a String that consists of:

either an ABI byte string containing the data of the function call on a contract, or in the case of a contract-creation transaction the initialisation code.

I want to assign a string to data and have the string be stored along with the record of the transaction on the blockchain, so that I can retrieve that string when I retrieve the record of that transaction later.

const [testAccount] = await window.ethereum.request({ method: "eth_requestAccounts" })
    
const web3 = new Web3(window.ethereum)

if (!testAccount) {
  return
}

let transactionHash = await web3.eth.sendTransaction({
  from: testAccount,
  to: testAccount,
  value:  web3.utils.toWei('0.0003'), 
  data: web3.utils.utf8ToHex(JSON.stringify({ a: 1, b: 2 }))
})

let transaction = await web3.eth.getTransaction(transactionHash)
let data = JSON.parse(web3.utils.hexToUtf8(transaction.data))
console.log(data.a) // should log 1

When I execute sendTransaction (using Metamask, while connected to the Ropsten network), I get the following error:

Error:  Error: TxGasUtil - Trying to call a function on a non-contract address
{
  "originalError": {
    "errorKey": "transactionErrorNoContract",
    "getCodeResponse": "0x"
  }
}

Apparently, you cannot assign any string to data and expect the string to be incorporated in the record of the transaction on the blockchain, out-of-the-box, simply by assigning a value to it. Is this correct?

Question: Do I need to write a custom smart-contract in order to achieve this ?


Solution

  • This is a feature/limitation specific to MetaMask. Possibly to protect their users who want to interact with a smart contract but are connected to a different network where the contract is not deployed.

    However, it is technically possible to send a valid transaction with non-empty data field to a non-contract address. You just need to use a different node provider to broadcast the transaction. Unfortunately the node provider in MetaMask is hardcoded so it's not possible using this wallet.

    Example: This transaction on the Ropsten testnet to the 0xdac1... address that has the USDT token contract deployed on the mainnet, but is a non-contract address on the testnet. It is a valid transaction, successfully bought gas from the sender address to cover the transaction fees, mined in a block, just didn't execute any smart contract code (as there is no smart contract on the recipient address).