Introduction
This article is similar to our previous one, USDT transaction on Solana network, but in this case we are going to transfer USDT on Polygon(previously called MATIC) network.
Requirements
- Go installed, given that we are going to keep using Go for this job.
Code with comments
Ok so let's start, first let's import the libraries, mostly will be using go-ethereum.
package main import ( "context" "crypto/ecdsa" "errors" "fmt" "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethclient" "golang.org/x/crypto/sha3" ) In this small recipe we'll use Alchemy RPC provider. Alchemy support several blockchains check it out in case you will need it.
When you create a application in Alchemy they will provide you with an API-KEY, which will be needed for connecting to the RPC endpoint. Let's define some constants that we'll need.
// After imports.... const ( // replace <API-KEY> with alchemy api key provided. AlchemyPolygonRPCEndpoint = "https://polygon-mainnet.g.alchemy.com/v2/<API-KEY>" // USDTTokenAddress is USDT contract address for the USDT token on Polygon // network. Can be checked in the following polygonscan link: // https://polygonscan.com/token/0xc2132d05d31c914a87c6611c10748aeb04b58e8f USDTTokenAddress = "0xc2132D05D31c914a87C6611C10748AEb04B58e8F" DefaultGasLimit uint64 = 100000 ) Let's define our client and its constructor.
// Client for making transaction. type Client struct { client *ethclient.Client publickKey common.Address privateKey *ecdsa.PrivateKey } // NewWithPrivateKey creates a new Client with the private key // provided. func NewWithPrivateKey(pKeyStr string) (*Client, error) { client, err := ethclient.Dial(AlchemyPolygonRPCEndpoint) if err != nil { return nil, err } privateKey, err := crypto.HexToECDSA(pKeyStr) if err != nil { return nil, err } publicKey := privateKey.Public() publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey) if !ok { return nil, errors.New("unable to convert publicKey to *ecdsa.PublicKey type") } // extracting public address of the wallet with the supplied private key. pubAddrs := crypto.PubkeyToAddress(*publicKeyECDSA) return &Client{ client: client, publickKey: pubAddrs, privateKey: privateKey, }, nil } The main method will be called TransferUSDT. One main difference in this method and the one from Solana article, is that we cannot send comment in the transaction.
// TransferUSDT make transaction of usdts to the specified address. // The amount should be provided in 6 decimals. // Meaning, 1 USDT should be represented as 1e6. // ctx: context // toAddressStrHex: hexadecimal representation of receiver address(Public Address) // amount: usdt amount to be sent. func (c *Client) TransferUSDT( ctx context.Context, toAddressStrHex string, amount uint64, ) (string, error) { // Retrieving pending nonce. The nonce, according to // ethereum glossary is a: // "An account nonce is a transaction counter in each account, // which is used to prevent replay attacks." nonce, err := c.client.PendingNonceAt(ctx, c.publickKey) if err != nil { return "", err } // given that we are going to transfer // usdts we don't need eths wei (0 eth). value := big.NewInt(0) // receiver address. toAddress := common.HexToAddress(toAddressStrHex) // usdt token address. tokenAddress := common.HexToAddress(USDTTokenAddress) // we will use the transfer method // on the smart contract associated with usdt token // in order to use this method, we need to provide the method id // this is how we get that number. // You could also check it here in this link // https://polygonscan.com/token/0xc2132d05d31c914a87c6611c10748aeb04b58e8f#writeProxyContract#F11 transferFnSignature := []byte("transfer(address,uint256)") hash := sha3.NewLegacyKeccak256() hash.Write(transferFnSignature) methodID := hash.Sum(nil)[:4] // we need to add 32 bytes of zeros to our address. paddedAddress := common.LeftPadBytes(toAddress.Bytes(), 32) // we need to add 32 bytes of zeros to our amount of tokens. // we are assuming this amount of tokens is expressed in 6 decimals. // which are the decimals for usdt. amountBigInt := new(big.Int) amountBigInt.SetUint64(amount) paddedAmount := common.LeftPadBytes(amountBigInt.Bytes(), 32) // now let's put this three parts into // the data we are going to pass in the transaction // part one: methodID // part two: receiver address padded 32 bytes // part three: padded amount to be sent var data []byte data = append(data, methodID...) data = append(data, paddedAddress...) data = append(data, paddedAmount...) // retrieving suggested gas fees and gas price. tipCap, err := c.client.SuggestGasTipCap(ctx) if err != nil { return "", err } feeCap, err := c.client.SuggestGasPrice(ctx) if err != nil { return "", err } // network ID for this client. chainID, err := c.client.NetworkID(ctx) if err != nil { return "", err } // creating our transaction, in this case we are going to use // dynamic fees txns instead of the legacy system. tx := types.NewTx(&types.DynamicFeeTx{ ChainID: chainID, Nonce: nonce, GasTipCap: tipCap, GasFeeCap: feeCap, Gas: DefaultGasLimit, To: &tokenAddress, Value: value, Data: data, }) // sign the transaction with our private key. signedTx, err := types.SignTx(tx, types.LatestSignerForChainID(chainID), c.privateKey) if err != nil { return "", err } // send the transaction. err = c.client.SendTransaction(ctx, signedTx) if err != nil { return "", err } // return the hexadecimal representation of the txnHash. return signedTx.Hash().Hex(), nil } Now writing the main function we got:
func main() { ctx := context.Background() client, err := NewWithPrivateKey("<PRIVATE-KEY>") if err != nil { panic(err) } txnHash, err := client.TransferUSDT(ctx, "<RECEIVER ADDRESS>", 1e6) // Sending 1 usdt. if err != nil { panic(err) } fmt.Println("TXN HASH: ", txnHash) } That's all, feel free to join the parts :).


Top comments (0)