Me gustaría generar transacciones golang
sin procesar sin ningún go
enlace y me pregunto si hay una biblioteca para codificar dinámicamente mi parámetro de argumento usando go
.
https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
Al usar este recurso, parece que sería una gran cantidad de trabajo codificar dinámicamente cada parámetro manualmente para cada tipo de datos disponibles.
¿Hay alguna forma de hacer esto?
Nuevamente, no estoy buscando enlaces de Ethereum Go ya que necesito devolver los datos de transacción sin firmar sin procesar.
El paquete go-ethereum proporciona una common.LeftPadBytes
función para valores de relleno izquierdo para solidez. Usaría esto para rellenar a 32 bytes, que es el tamaño de palabra que usa EVM.
Aquí hay un ejemplo completo de cómo construir manualmente los datos de transacción para transferir un token ERC-20 que debería darle una buena idea (del libro Ethereum Development with Go ).
package main
import (
"context"
"crypto/ecdsa"
"fmt"
"log"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/ethclient"
)
func main() {
client, err := ethclient.Dial("https://rinkeby.infura.io")
if err != nil {
log.Fatal(err)
}
privateKey, err := crypto.HexToECDSA("fad9c8855b740a0b7ed4c221dbad0f33a83a49cad6b3fe8d5817ac83d38b6a19")
if err != nil {
log.Fatal(err)
}
publicKey := privateKey.Public()
publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
if !ok {
log.Fatal("error casting public key to ECDSA")
}
fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)
nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
if err != nil {
log.Fatal(err)
}
value := big.NewInt(0) // in wei (0 eth)
gasLimit := uint64(2000000) // in units
gasPrice, err := client.SuggestGasPrice(context.Background())
if err != nil {
log.Fatal(err)
}
toAddress := common.HexToAddress("0x4592d8f8d7b001e72cb26a73e4fa1806a51ac79d")
tokenAddress := common.HexToAddress("0x28b149020d2152179873ec60bed6bf7cd705775d")
transferFnSignature := []byte("transfer(address,uint256)")
hash := sha3.NewKeccak256()
hash.Write(transferFnSignature)
methodID := hash.Sum(nil)[:4]
fmt.Println(hexutil.Encode(methodID)) // 0xa9059cbb
paddedAddress := common.LeftPadBytes(toAddress.Bytes(), 32)
fmt.Println(hexutil.Encode(paddedAddress)) // 0x0000000000000000000000004592d8f8d7b001e72cb26a73e4fa1806a51ac79d
amount := new(big.Int)
amount.SetString("1000000000000000000000", 10) // 1000 tokens
paddedAmount := common.LeftPadBytes(amount.Bytes(), 32)
fmt.Println(hexutil.Encode(paddedAmount)) // 0x00000000000000000000000000000000000000000000003635c9adc5dea00000
var data []byte
data = append(data, methodID...)
data = append(data, paddedAddress...)
data = append(data, paddedAmount...)
tx := types.NewTransaction(nonce, tokenAddress, value, gasLimit, gasPrice, data)
signedTx, err := types.SignTx(tx, types.HomesteadSigner{}, privateKey)
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()) // tx sent: 0xa56316b637a94c4cc0331c73ef26389d6c097506d581073f927275e7a6ece0bc
}
Un lugar desde donde empezar sería NewTransaction()
en transaction.go
. Esto es parte del types
paquete.
// NewTransaction creates a new transaction with the given properties.
func NewTransaction(nonce int64, to *Address, amount, gasLimit, gasPrice *BigInt, data []byte) *Transaction {
return &Transaction{types.NewTransaction(uint64(nonce), to.address, amount.bigint, gasLimit.bigint, gasPrice.bigint, data)}
}
Hay innumerables lugares en el código que tienen ejemplos de cómo probar la función, con o sin el paso que realiza la firma.