raw-transaction – Using Nethereum with Infura/RPC Clients – A Comprehensive Guide

c#infuranethereumraw-transaction

I am having a heck of a time getting transactions to post on mainnet. The issue is not my wallet balance or gas related. A balance lookup on the same contract works correctly.. However, i cannot get this offlinesignedtransaction (raw transaction equivalent,)

I have tried all manners of passing various parameters, i have set the defaultGas/Price via the transaction manager and used the SendTransactionAsync() method with the overloads that do no require them. I have sent the method with the contract parameters individually (not in an object array as below). I double checked the nonce – it appears as 0. I tried both this and the andwaitforreceipt variant.

var contract = web3.Eth.GetContract(contractAbi,contractAddress);
var function = contract.GetFunction("transfer");
hash = await function.SendTransactionAsync(@from: accountAddress, gas: new HexBigInteger(60000),
       gasPrice: HexBigInteger(40), value: null, functionInput: new object[] {  recipient, Web3.Convert.ToWei(value) });

The contract is a standard ERC20 Token. Any insight as to why the transaction returns no errors, however infura does not broadcast? I used this very same code many times with a regular private geth node.

Edit: Ive also been trying to get some of the other RPC JSON APIs. If anyone is familiar, would you confirm this is the correct way to do it by sending the data payload way? I get an "underpriced error" from the etherscan api

        var contract = web3.Eth.GetContract(contractAbi, contractAddress);
        var function = contract.GetFunction("transfer");
        string fdata = function.GetData(new object[] { recipient, Web3.Convert.ToWei(value) });
        var txCount = await web3.Eth.Transactions.GetTransactionCount.SendRequestAsync(accountAddress);

        var encoded = Web3.OfflineTransactionSigner.SignTransaction(privateKey: accountKey, to: contractAddress, amount: 0, nonce: txCount.Value, gasPrice: new BigInteger(70), gasLimit: new HexBigInteger(60000), data: fdata);
        encoded = "0x" + encoded;

Best Answer

I can see the price that you are using is rather low already (it needs to be converted from Gwei to Wei), but you will also benefit of estimating the gas of the transaction, and use other features of Nethereum.

First of all, we can just have a TransferFunction. This is mainly an object that describes the Transfer function from the ERC20 contract and the different parameters. This inherits from ContractMessage, which includes other properties like AddressFrom, Gas, GasPrice, Value (Ether value) which are part of a normal Transaction.

[Function("transfer", "bool")]
public class TransferFunction : ContractMessage
{
    [Parameter("address", "_to", 1)]
    public string To { get; set; }

    [Parameter("uint256", "_value", 2)]
    public BigInteger TokenAmount { get; set; }
}

Now let's define our custom variables:

var senderAddress = "0x12890d2cce102216644c59daE5baed380d84830c";
var receiverAddress = "0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe";
var privatekey = "0xb5b1870957d373ef0eeffecc6e4812c0fd08f554b37b233526acc331bf1544f7";
var url = "https://rinkeby.infura.io/";

and create a new instance of Web3.

var web3 =  new Web3.Web3(new Account(privatekey), url);

This instance of Web3 has been created using a new Account object using the private key. This mainly enables Web3 to sign any transactions "offline" before sending them, so you don't need to craft everything yourself.

The next step is to create an instance of the message we are going to send.

var transactionMessage = new TransferFunction()
            {
                FromAddress = senderAddress,
                To = receiverAddress,
                TokenAmount = 100,
                //Set our own price
                GasPrice =  Web3.Web3.Convert.ToWei(25, UnitConversion.EthUnit.Gwei)

            };

Here it has been populated the FromAddress (this is not necessary as this will be picked from the Account already set), the receiver (To) from the smart contract, the amount and finally the GasPrice.

This GasPrice is a custom price (not using the Nethereum default which might be too expensive due to price fluctuation, and it is now).

To set the price we have converted it from Gwei which is the unit is normally used for pricing to Wei.

Now that we have our "message" / transaction ready we can create a transaction handler, which will be responsible to send the transaction.

var transferHandler = web3.Eth.GetContractTransactionHandler<TransferFunction>();

Another step (which is optional) as this is done automatically for you is to estimate the cost (in gas) of the transaction.

var estimate = await transferHandler.EstimateGasAsync(transactionMessage, ContractAddress);
transactionMessage.Gas = estimate.Value;

And finally send the transaction:

var transactionHash = await transferHandler.SendRequestAsync(transactionMessage, ContractAddress);

You can find the full sample here: https://github.com/Nethereum/Nethereum.CQS.SimpleTokenTransfer/blob/master/Nethereum.CQS.SimpleTokenTransfer/Program.cs#L111-L155