Go语言开发以太坊:如何转移ETH

在本课程中,您将学习如何将ETH从一个帐户转移到另一个帐户。如果您已经熟悉以太坊,那么您就知道一笔交易包括您要转让的以太币数量,汽油限额,汽油价格,随机数,接收地址以及可选的数据。在将交易广播到网络之前,必须使用发送者的私钥对其进行签名。


假设您已经连接了客户端,则下一步是加载私钥。


privateKey, err := crypto.HexToECDSA("fad9c8855b740a0b7ed4c221dbad0f33a83a49cad6b3fe8d5817ac83d38b6a19")if err != nil {
  log.Fatal(err)}

之后,我们需要获取帐户随机数。每笔交易都需要随机数。根据定义,随机数是仅使用一次的数字。如果这是一个发出交易的新帐户,则随机数为0。帐户中的每笔新交易都必须具有一个随机数,该随机数的前一个随机数递增1。很难手动跟踪所有随机数,因此以太坊客户端提供了一个助手方法PendingNonceAt,该方法将返回您应使用的下一个随机数。

该函数需要我们发送的帐户的公共地址-我们可以从私钥中获取该地址。

publicKey := privateKey.Public()publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)if !ok {
  log.Fatal("cannot assert type: publicKey is not of type *ecdsa.PublicKey")}fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)

在这里,privateKey.Public()返回一个包含我们的公钥的接口。我们使用类型声明publicKey.(<expectedType>)来明确设置publicKey变量的类型,并将其分配给publicKeyECDSA这使我们可以在程序需要输入type的地方使用它*ecdsa.PublicKey

在,我们可以读取应该用于帐户交易的随机数。

nonce, err := client.PendingNonceAt(context.Background(), fromAddress)if err != nil {
  log.Fatal(err)}

下一步是设置我们将要转移的ETH数量。然而,我们必须转换醚魏因为那是什么复仇 blockchain用途。醚最多支持18位小数,因此1 ETH是1加18个零。这是一个帮助您在ETH和wei之间转换的小工具:https : //etherconverter.online

value := big.NewInt(1000000000000000000) // in wei (1 eth)

标准ETH传输的气体限制为21000单位。

gasLimit := uint64(21000) // in units

该天然气价格必须在魏来设置。在撰写本文时,将使您的交易非常迅速地包含在一个区块中的汽油价格为30 gwei。

gasPrice := big.NewInt(30000000000) // in wei (30 gwei)

但是,天然气价格始终根据市场需求和用户愿意支付的价格而波动,因此硬编码天然气价格有时并不理想。在去 - 复仇客户端提供了SuggestGasPrice用于获取平均功能气体基于价格x之前的块数。

gasPrice, err := client.SuggestGasPrice(context.Background())if err != nil {
  log.Fatal(err)}

我们确定要向谁发送ETH。

toAddress := common.HexToAddress("0x4592d8f8d7b001e72cb26a73e4fa1806a51ac79d")

现在,我们终于可以生成我们的无符号的复仇通过导入交易走 - 复仇 core/types包和调用NewTransaction这需要在现时,到地址值,气体的限制,天然气价格,以及可选的数据。数据字段仅nil用于发送ETH。与智能合约进行交互时,我们将使用数据字段。

tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, nil)

下一步是使用发送者的私钥对交易进行签名。为此,我们调用SignTx接收未签名事务的方法和我们先前构建的私钥。该SignTx方法需要EIP155签名者,我们从客户端获取链ID。

chainID, err := client.NetworkID(context.Background())if err != nil {
  log.Fatal(err)}signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), privateKey)if err != nil {
  log.Fatal(err)}

现在,我们终于可以通过调用SendTransaction接受已签名交易的客户端,准备将交易广播到整个网络

err = client.SendTransaction(context.Background(), signedTx)if err != nil {
  log.Fatal(err)}fmt.Printf("tx sent: %s", signedTx.Hash().Hex()) // tx sent: 0x77006fcb3938f648e2cc65bafd27dec30b9bfbe9df41f78498b9c8b7322a249e

之后,您可以在诸如Etherscan的块浏览器上检查进度:https://rinkeby.etherscan.io/tx/0x77006fcb3938f648e2cc65bafd27dec30b9bfbe9df41f78498b9c8b7322a249e


完整代码

transfer_eth.go

package mainimport (    "context"
    "crypto/ecdsa"
    "fmt"
    "log"
    "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")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("cannot assert type: publicKey is not of type *ecdsa.PublicKey")
    }
    fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)
    nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
    if err != nil {
        log.Fatal(err)
    }
    value := big.NewInt(1000000000000000000) // in wei (1 eth)
    gasLimit := uint64(21000)                // in units
    gasPrice, err := client.SuggestGasPrice(context.Background())
    if err != nil {
        log.Fatal(err)
    }
    toAddress := common.HexToAddress("0x4592d8f8d7b001e72cb26a73e4fa1806a51ac79d")    var data []byte
    tx := types.NewTransaction(nonce, toAddress, value, gasLimit, gasPrice, data)
    chainID, err := client.NetworkID(context.Background())
    if err != nil {
        log.Fatal(err)
    }
    signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), 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())}


链客

2019.12.10
4950
收藏

个评论:

发表评论

感谢您的善举,每一次解答会成为新人的灯塔。回答被采纳后获得20算力和相应LK币奖励。

关闭