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
First of all INFURA does not allows to send unsigned transactions, so you have to sign them firstly and then pass them to INFURA.
To do this, you have to:
- prepare the transaction
- sign it
- send it (using INFURA)
Please check INFURA documentation.
There is an example below:
const Web3 = require('web3')
const Tx = require('ethereumjs-tx')
// connect to Infura node
const web3 = new Web3(new Web3.providers.HttpProvider('https://mainnet.infura.io/INFURA_KEY'))
// the address that will send the test transaction
const addressFrom = '0x1889EF49cDBaad420EB4D6f04066CA4093088Bbd'
const privKey = 'PRIVATE_KEY'
// the destination address
const addressTo = '0x1463500476a3ADDa33ef1dF530063fE126203186'
// Signs the given transaction data and sends it. Abstracts some of the details
// of buffering and serializing the transaction for web3.
function sendSigned(txData, cb) {
const privateKey = new Buffer(config.privKey, 'hex')
const transaction = new Tx(txData)
transaction.sign(privateKey)
const serializedTx = transaction.serialize().toString('hex')
web3.eth.sendSignedTransaction('0x' + serializedTx, cb)
}
// get the number of transactions sent so far so we can create a fresh nonce
web3.eth.getTransactionCount(addressFrom).then(txCount => {
// construct the transaction data
const txData = {
nonce: web3.utils.toHex(txCount),
gasLimit: web3.utils.toHex(25000),
gasPrice: web3.utils.toHex(10e9), // 10 Gwei
to: addressTo,
from: addressFrom,
value: web3.utils.toHex(web3.utils.toWei(123, 'wei'))
}
// fire away!
sendSigned(txData, function(err, result) {
if (err) return console.log('error', err)
console.log('sent', result)
})
})
Best Answer
It seems that your function checks is the valid owner, hence you have a revert error message
Nethereum.JsonRpc.Client.RpcResponseException: execution reverted: Ownable: caller is not the owner
. This is the output after making aCallAsync
and getting the solidityrevert
message.If you want to change the state of the contract (mainly write to the contract / ethereum) you need to use
SendTransactionAsync
instead of aCallAsync
Back to the first issue, as you are working "untyped", (interacting using strings and not specific contract definitions), you need to set the
from
parameter to your account when making a CallAsync. You can use theaccount.Address
for this. Mainly when doing a call / query to the smart contract, setting thefrom
value in the CallAsync will make that themsg.sender
in solidity as in a transaction call.Check this example http://playground.nethereum.com/csharp/id/1045 (very big example not fit for here) on how to interact that way.
In the long run I recommend using the code generator with typed contract definitions, it is much easier in the long run (also gives you support for structs, generate your events, and multiple output, auto estimate gas, etc)