package service import ( "context" "encoding/hex" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" "math/big" "time" ) var ( ethUsdt = common.HexToAddress("0xdAC17F958D2ee523a2206206994597C13D831ec7") ethUsdc = common.HexToAddress("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48") ) var ( transferId, _ = hex.DecodeString("a9059cbb") ) var ( addressTy, _ = abi.NewType("address", "", nil) uint256Ty, _ = abi.NewType("uint256", "", nil) arguments = abi.Arguments{{Type: addressTy}, {Type: uint256Ty}} ) func buildTransferEth(ethClient *ethclient.Client, from, to string, amount *big.Int) (*types.Transaction, error) { fromAddr := common.HexToAddress(from) toAddr := common.HexToAddress(to) return createTransaction(ethClient, &fromAddr, &toAddr, amount, nil) } func buildTransferUsdtOfEth(ethClient *ethclient.Client, from, to string, amount *big.Int) (*types.Transaction, error) { fromAddr := common.HexToAddress(from) toAddr := common.HexToAddress(to) data, err := arguments.Pack(toAddr, amount) if err != nil { return nil, err } return createTransaction(ethClient, &fromAddr, ðUsdt, big.NewInt(0), append(transferId, data...)) } func buildTransferUsdcOfEth(ethClient *ethclient.Client, from, to string, amount *big.Int) (*types.Transaction, error) { fromAddr := common.HexToAddress(from) toAddr := common.HexToAddress(to) data, err := arguments.Pack(toAddr, amount) if err != nil { return nil, err } return createTransaction(ethClient, &fromAddr, ðUsdc, big.NewInt(0), append(transferId, data...)) } func createTransaction(ethClient *ethclient.Client, from, to *common.Address, amount *big.Int, data []byte) (*types.Transaction, error) { tx := &types.DynamicFeeTx{ ChainID: big.NewInt(1), To: to, Value: amount, Data: data, } err := estimateGas(ethClient, from, tx) if err != nil { return nil, err } return types.NewTx(tx), nil } func estimateGas(ethClient *ethclient.Client, from *common.Address, tx *types.DynamicFeeTx) error { ctx, cancel := context.WithTimeout(context.Background(), time.Second*30) defer cancel() head, err := ethClient.HeaderByNumber(ctx, nil) if err != nil { return err } gasTipCap, err := ethClient.SuggestGasTipCap(ctx) if err != nil { return err } gasFeeCap := new(big.Int).Add( gasTipCap, new(big.Int).Mul(head.BaseFee, big.NewInt(2)), ) msg := ethereum.CallMsg{ From: *from, To: tx.To, GasPrice: nil, GasTipCap: gasTipCap, GasFeeCap: gasFeeCap, Value: tx.Value, Data: tx.Data, } gasLimit, err := ethClient.EstimateGas(ctx, msg) if err != nil { return err } nonce, err := ethClient.PendingNonceAt(ctx, *from) if err != nil { return err } tx.Nonce = nonce tx.Gas = gasLimit tx.GasFeeCap = gasFeeCap tx.GasTipCap = gasTipCap return nil }