本文编写于 932 天前,最后修改于 932 天前,其中某些信息可能已经过时。

gotron-sdk的简要介绍

gotron-sdk是基于gRPC的Go SDK实现和cli工具

这东西看起来大多数人都是作cli使用,如果想要拿来当go-ethereum,没有任何文档的可以用来参考,唯一能做的,只能翻源码……

为了让更多人少踩坑,特作此简易教程,愿能帮助到深受波场毒害的科学家们(

连接到gRPC节点

gotron-sdk仅支持gRPC方式的连接

NewGrpcClient方法可以传入gRPC地址,默认将Start时使用grpc.trongrid.io:50051,返回GrpcClient实例

请注意,NewGrpcClient并不会真正建立RPC连接,需要调用Start方法,可变参为grpc.DialOption

import "github.com/fbsobreira/gotron-sdk/pkg/client"
rpcClient := client.NewGrpcClient("")
err := rpcClient.Start(grpc.WithInsecure())

地址转换

波场地址以大写字母 T 开头,是以太坊地址前增加字节 0x41 后 Base58check 得到的,共34位字符

import "github.com/fbsobreira/gotron-sdk/pkg/address"
addr, err := address.Base58ToAddress("TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t")
log.Println(addr.String())

另:gotron-sdk中大多数对外方法都使用string,并且在每个方法中都调用Base58ToAddress

私钥导入

需要注意下列方法导入并非临时使用,而是真的导入了本地存储,之后可以凭借钱包地址与密码直接使用

import "github.com/fbsobreira/gotron-sdk/pkg/account"
accountName, err := account.ImportFromPrivateKey(privateKey, "", accountPassword)
accountName, err := account.ImportKeyStore("keystoreFilePath", "", accountPassword)

TODO:目前没有找到临时使用的方法

合约调用

调用无参constant方法

调用TRC20代币的name()查询代币名称,这里以USDT为例

为展示TRC20Call的用法,这里不使用已经封装好的TRC20GetName

import "github.com/fbsobreira/gotron-sdk/pkg/common"
// 获得方法名的SHA-3
nameSign := common.BytesToHexString(abi.Signature("name()"))
result, err := rpcClient.TRC20Call("", "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", nameSign, true, 0)
if err != nil {
    log.Println(err)
    return
}
data, _ := rpcClient.ParseTRC20StringProperty(common.BytesToHexString(result.GetConstantResult()[0]))
log.Println(data)

调用有参与需要签名的方法

没有文档,真的坑啊!这里演示如何与有参数、需要签名的方法进行交互

参数的构建

在client的TriggerContract方法里,有jsonString 这样一个奇怪的参数……常规来说,这肯定是ABI的参数,但是,怎么用,这是个问题(

阅读abi.LoadFromJSONabi.GetPaddedParam的源码,可以确定,这个jsonString应该长成这样:

// ABI(有简化
{
    "inputs": [
        {
            "name": "_to",
            "type": "address"
        },
        {
            "name": "_value",
            "type": "uint256"
        }
    ],
    "name": "transfer"
}
// jsonString是以类型为key,值为value的数组,且uint应使用字符串类型
[
    {
        "address": "TWRhFW2AQg8Ae2j8BynFnGNfj7xg95qhvQ"
    },
    {
        "uint256": "100000"
    }
]

以transfer为例

本例调用USDT的transfer方法对其他地址进行转账,直接上代码,为了简洁err省略,实际使用还请认真处理

一定要注意,TriggerContract方法并不会发送Tx,这可以说是这个包最坑的地方了

// 携带的数据
triggerData := "[{\"address\":\"TWRhFW2AQg8Ae2j8BynFnGNfj7xg95qhvQ\"},{\"uint256\":\"100000\"}]"

// 构建Tx,注意,此处只是构造,tx并没有被发送
// 参数分别为 发送者地址 合约地址 调用方法(正常字符串) gas Tx发送的TRX数量 Tx发送的TRC20代币 代币数量
tx, _ := rpcClient.TriggerContract(wallet, contract, "transfer(address,uint256)", triggerData, 300000000, 0, "", 0)

// 获得keystore与account
ks, acct, _ := store.UnlockedKeystore(wallet, accountPassword)
// 封装Tx
ctrlr := transaction.NewController(rpcClient, ks, acct, tx.Transaction)
// 真正执行Tx,并判断执行结果
if err = ctrlr.ExecuteTransaction(); err != nil {
    log.Println(err.Error())
    return
}
// 此时Tx才上链
log.Println(common.BytesToHexString(tx.GetTxid()))
log.Println(common.BytesToHexString(tx.GetResult().GetMessage()))