Blockchain on Golang Part3: Transfer Operations
This chapter will explain how to transfer coins between blockchain wallets.
The previous section, Part2: Balance Operations. Before I explained how to check balance.
Step 1: Configure Transaction Options
At this stage, the configurations that will be required during the transaction are created. These configurations are;
- Nonce
PendingNonceAt returns the account nonce of the given account in the pending state. This is the nonce that should be used for the next transaction. This function takes context and publicKey as parameters. publicKey type should be common.Address type.
nonce, err := client.PendingNonceAt(context.Background(), publicKey)
- Gas Price
SuggestGasPrice retrieves the currently suggested gas price to allow a timely execution of a transaction. This function takes just context as a parameter.
gasPrice, err := client.SuggestGasPrice(context.Background())
- Chain ID
NetworkID returns the network ID (also known as the chain ID) for this chain. This function takes just context as a parameter.
gasPrice, err := client.SuggestGasPrice(context.Background())
- GasLimit
Gas limit means the most gas money you are willing to spend on a certain transaction.
gasLimit := uint64(21000)
Step 2: TransactionOptions Function
I made a struct called Configurations that includes all configurations and I create TransactionOptions function. This function takes publicKey as a common.Address type and returns Configurations struct.
type Configurations struct {
Nonce uint64
GasPrice *big.Int
ChainID *big.Int
GasLimit uint64
}func TransferOptions(publicKey common.Address) Configurations {
var configure Configurations
nonce, err := client.PendingNonceAt(context.Background(), publicKey)
if err != nil {
log.Fatal(err)
}
gasPrice, err := client.SuggestGasPrice(context.Background())
if err != nil {
log.Fatal(err)
}
chainID, err := client.NetworkID(context.Background())
if err != nil {
log.Fatal(err)
}
configure.Nonce = nonce
configure.GasPrice = gasPrice
configure.ChainID = chainID
configure.GasLimit = uint64(21000)
return configure
}
Step 3: ToWei Method
This method helps to convert any type to *big.Int type. For example, you want to send 2.5 Avax to another wallet, this method converts wei 2500000000000000000 .
func ToWei(iAmount interface{}, decimals int) *big.Int {
amount := decimal.NewFromFloat(0)
switch v := iAmount.(type) {
case string:
amount, _ = decimal.NewFromString(v)
case float64:
amount = decimal.NewFromFloat(v)
case int64:
amount = decimal.NewFromFloat(float64(v))
case decimal.Decimal:
amount = v
case *decimal.Decimal:
amount = *v
}
mul := decimal.NewFromFloat(float64(10)).Pow(decimal.NewFromFloat(float64(decimals)))
result := amount.Mul(mul)
wei := new(big.Int)
wei.SetString(result.String(), 10)
return wei
}
Step 4: Create Transaction
This new transaction uses nonce, receiver public address, amount as a wei, gas price, gas limit, and data as a byte array.
tx := types.NewTransaction(transactionConfigs.Nonce, toPublicAddress, weiAmount, transactionConfigs.GasLimit, transactionConfigs.GasPrice, data)
This is the signer code. The function needs to sign this transaction. The signer needs ChainID and signer privateKey(our private key).
signedTx, err := types.SignTx(tx, types.NewEIP155Signer(transactionConfigs.ChainID), fromPrivateAddress)
And let's send the transaction
err = client.SendTransaction(context.Background(), signedTx)fmt.Printf("tx sent: %s", signedTx.Hash().Hex())
//output : tx sent: 0x994bc......4f1b788bbc886e06602629
Finally, the Transaction function is here!
Transfer function takes fromPublicAddress, fromPrivateAddress, toPublicKey and amount. and performs the transaction.
func Transfer(fromPublicAddress common.Address, fromPrivateAddress *ecdsa.PrivateKey, toPublicAddress common.Address, amount string) {
weiAmount := ToWei(amount, 18)
transactionConfigs := TransferOptions(fromPublicAddress)
var data []byte
tx := types.NewTransaction(transactionConfigs.Nonce, toPublicAddress, weiAmount, transactionConfigs.GasLimit, transactionConfigs.GasPrice, data)
signedTx, err := types.SignTx(tx, types.NewEIP155Signer(transactionConfigs.ChainID), fromPrivateAddress)
if err != nil {
log.Fatal(err)
}
err = client.SendTransaction(context.Background(), signedTx)
if err != nil {
log.Fatal(err)
}
fmt.Printf("tx sent: %s", signedTx.Hash().Hex())
}
Final Step: Full Code
Conclusion
By using these codes, you can be able to transfer coins between wallets.
Project Codes