使用Go语言构建TronLink风格的钱包应用
使用Go语言构建TronLink风格的钱包应用
本文将详细介绍如何使用Go语言构建一个类似TronLink的钱包应用,包含私钥管理、交易签名、TRX和TRC20代币转账等核心功能。
一、TronLink钱包简介
TronLink是波场(TRON)区块链上最受欢迎的钱包之一,提供账户管理、资产转账、智能合约交互等功能。我们将使用Go语言实现其核心功能,创建一个轻量级命令行钱包。
二、项目架构设计
我们的钱包将包含以下核心模块:
1.密钥管理-生成和存储私钥
2.交易构建-创建TRX和TRC20转账交易
3.网络通信-与TRON节点交互
4.用户界面-命令行交互
三、核心代码实现
1.初始化项目
首先创建项目目录结构:
tron-wallet/
├──cmd/
│└──main.go
├──internal/
│├──crypto/
│├──wallet/
│└──tron/
├──go.mod
└──go.sum
初始化go.mod文件:
modulegithub.com/yourname/tron-wallet
go1.21
require(
github.com/btcsuite/btcd/btcec/v2v2.3.2
github.com/ethereum/go-ethereumv1.13.4
github.com/fatih/colorv1.16.0
github.com/shengdoushi/base58v1.0.0
github.com/tyler-smith/go-bip39v1.1.0
google.golang.org/grpcv1.59.0
google.golang.org/protobufv1.31.0
)
2.密钥管理实现
internal/crypto/keys.go
:
packagecrypto
import(
"crypto/ecdsa"
"encoding/hex"
"errors"
"fmt"
"github.com/btcsuite/btcd/btcec/v2"
"github.com/ethereum/go-ethereum/crypto"
"github.com/tyler-smith/go-bip39"
)
//GenerateMnemonic生成BIP39助记词
funcGenerateMnemonic()(string,error){
entropy,err:=bip39.NewEntropy(128)
iferr!=nil{
return"",err
}
returnbip39.NewMnemonic(entropy)
}
//MnemonicToPrivateKey从助记词派生私钥
funcMnemonicToPrivateKey(mnemonicstring)(ecdsa.PrivateKey,error){
if!bip39.IsMnemonicValid(mnemonic){
returnnil,errors.New("invalidmnemonic")
}
seed:=bip39.NewSeed(mnemonic,"")
privateKey,err:=crypto.ToECDSA(seed[:32])
iferr!=nil{
returnnil,err
}
returnprivateKey,nil
}
//PrivateKeyToAddress从私钥生成TRON地址
funcPrivateKeyToAddress(privateKeyecdsa.PrivateKey)(string,error){
publicKey:=privateKey.Public()
publicKeyECDSA,ok:=publicKey.(ecdsa.PublicKey)
if!ok{
return"",errors.New("errorcastingpublickeytoECDSA")
}
//TRON地址是公钥的Keccak-256哈希的最后20字节,前面加上0x41
pubBytes:=crypto.FromECDSAPub(publicKeyECDSA)
addressBytes:=crypto.Keccak256(pubBytes[1:])[12:]
addressBytes=append([]byte{0x41},addressBytes...)
returnEncodeBase58(addressBytes),nil
}
//EncodeBase58TRON使用的Base58编码
funcEncodeBase58(input[]byte)string{
constalphabet="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
varresult[]byte
x:=new(big.Int).SetBytes(input)
base:=big.NewInt(58)
zero:=big.NewInt(0)
mod:=new(big.Int)
forx.Cmp(zero)!=0{
x.DivMod(x,base,mod)
result=append(result,alphabet[mod.Int64()])
}
//反转结果
fori,j:=0,len(result)-1;i<j;i,j=i+1,j-1{
result[i],result[j]=result[j],result[i]
}
returnstring(result)
}
3.钱包核心实现
internal/wallet/wallet.go
:
packagewallet
import(
"crypto/ecdsa"
"encoding/json"
"errors"
"fmt"
"os"
"path/filepath"
"github.com/yourname/tron-wallet/internal/crypto"
)
typeWalletstruct{
PrivateKeyecdsa.PrivateKey
Addressstring
}
//NewWallet创建新钱包
funcNewWallet()(Wallet,error){
mnemonic,err:=crypto.GenerateMnemonic()
iferr!=nil{
returnnil,err
}
returnFromMnemonic(mnemonic)
}
//FromMnemonic从助记词恢复钱包
funcFromMnemonic(mnemonicstring)(Wallet,error){
privateKey,err:=crypto.MnemonicToPrivateKey(mnemonic)
iferr!=nil{
returnnil,err
}
address,err:=crypto.PrivateKeyToAddress(privateKey)
iferr!=nil{
returnnil,err
}
return&Wallet{
PrivateKey:privateKey,
Address:address,
},nil
}
//FromPrivateKey从私钥恢复钱包
funcFromPrivateKey(privateKeyHexstring)(Wallet,error){
privateKeyBytes,err:=hex.DecodeString(privateKeyHex)
iferr!=nil{
returnnil,err
}
privateKey,err:=crypto.ToECDSA(privateKeyBytes)
iferr!=nil{
returnnil,err
}
address,err:=crypto.PrivateKeyToAddress(privateKey)
iferr!=nil{
returnnil,err
}
return&Wallet{
PrivateKey:privateKey,
Address:address,
},nil
}
//SaveToFile将钱包保存到文件
func(wWallet)SaveToFile(pathstring)error{
privateKeyBytes:=crypto.FromECDSA(w.PrivateKey)
data:=map[string]string{
"privateKey":hex.EncodeToString(privateKeyBytes),
"address":w.Address,
}
jsonData,err:=json.MarshalIndent(data,"","")
iferr!=nil{
returnerr
}
iferr:=os.MkdirAll(filepath.Dir(path),0700);err!=nil{
returnerr
}
returnos.WriteFile(path,jsonData,0600)
}
//LoadFromFile从文件加载钱包
funcLoadFromFile(pathstring)(Wallet,error){
data,err:=os.ReadFile(path)
iferr!=nil{
returnnil,err
}
varwalletDatamap[string]string
iferr:=json.Unmarshal(data,&walletData);err!=nil{
returnnil,err
}
returnFromPrivateKey(walletData["privateKey"])
}
4.TRON网络交互
internal/tron/client.go
:
packagetron
import(
"context"
"encoding/hex"
"errors"
"fmt"
"math/big"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"github.com/tronprotocol/grpc-gateway/api"
"github.com/tronprotocol/grpc-gateway/core"
)
typeClientstruct{
api.WalletClient
conngrpc.ClientConn
}
//NewClient创建TRONGRPC客户端
funcNewClient(nodeURLstring)(Client,error){
conn,err:=grpc.Dial(nodeURL,grpc.WithTransportCredentials(insecure.NewCredentials()))
iferr!=nil{
returnnil,err
}
return&Client{
WalletClient:api.NewWalletClient(conn),
conn:conn,
},nil
}
//Close关闭连接
func(cClient)Close()error{
returnc.conn.Close()
}
//GetAccount获取账户信息
func(cClient)GetAccount(addressstring)(core.Account,error){
ctx,cancel:=context.WithTimeout(context.Background(),10time.Second)
defercancel()
account:=&core.Account{
Address:common.Hex2Bytes(address),
}
returnc.GetAccount(ctx,account)
}
//GetNowBlock获取最新区块
func(cClient)GetNowBlock()(core.Block,error){
ctx,cancel:=context.WithTimeout(context.Background(),10time.Second)
defercancel()
returnc.GetNowBlock(ctx,&api.EmptyMessage{})
}
//CreateTransaction创建TRX转账交易
func(cClient)CreateTransaction(from,tostring,amountint64)(core.Transaction,error){
ctx,cancel:=context.WithTimeout(context.Background(),10time.Second)
defercancel()
transferContract:=&core.TransferContract{
OwnerAddress:common.Hex2Bytes(from),
ToAddress:common.Hex2Bytes(to),
Amount:amount,
}
returnc.CreateTransaction(ctx,transferContract)
}
//SignTransaction签名交易
funcSignTransaction(txcore.Transaction,privateKeyecdsa.PrivateKey)error{
rawData,err:=tx.GetRawData().Marshal()
iferr!=nil{
returnerr
}
hash:=crypto.Keccak256(rawData)
signature,err:=crypto.Sign(hash,privateKey)
iferr!=nil{
returnerr
}
tx.Signature=append(tx.Signature,signature)
returnnil
}
//BroadcastTransaction广播交易
func(cClient)BroadcastTransaction(txcore.Transaction)(api.Return,error){
ctx,cancel:=context.WithTimeout(context.Background(),10time.Second)
defercancel()
returnc.BroadcastTransaction(ctx,tx)
}
//GetTRC20Balance获取TRC20代币余额
func(cClient)GetTRC20Balance(contractAddress,ownerAddressstring)(big.Int,error){
ctx,cancel:=context.WithTimeout(context.Background(),10time.Second)
defercancel()
//TRC20balanceOf函数调用
data:="0x70a08231000000000000000000000000"+ownerAddress[2:]
trigger:=&core.TriggerSmartContract{
ContractAddress:common.Hex2Bytes(contractAddress),
OwnerAddress:common.Hex2Bytes(ownerAddress),
Data:common.Hex2Bytes(data),
}
result,err:=c.TriggerConstantContract(ctx,trigger)
iferr!=nil{
returnnil,err
}
if!result.GetResult().GetResult(){
returnnil,errors.New("contractcallfailed:"+string(result.GetResult().GetMessage()))
}
balance:=new(big.Int).SetBytes(result.GetConstantResult()[0])
returnbalance,nil
}
5.命令行界面
cmd/main.go
:
packagemain
import(
"bufio"
"context"
"encoding/hex"
"fmt"
"log"
"os"
"strconv"
"strings"
"github.com/fatih/color"
"github.com/yourname/tron-wallet/internal/crypto"
"github.com/yourname/tron-wallet/internal/tron"
"github.com/yourname/tron-wallet/internal/wallet"
)
const(
walletFile="./wallet.json"
nodeURL="grpc.trongrid.io:50051"
)
funcmain(){
fmt.Println(color.GreenString("TRONWalletCLI"))
fmt.Println("---------------------")
varwwallet.Wallet
varerrerror
//检查钱包文件是否存在
if_,err:=os.Stat(walletFile);os.IsNotExist(err){
fmt.Println("Nowalletfound.Createanewone.")
w,err=createNewWallet()
iferr!=nil{
log.Fatal("Failedtocreatewallet:",err)
}
}else{
fmt.Println("Loadingexistingwallet...")
w,err=wallet.LoadFromFile(walletFile)
iferr!=nil{
log.Fatal("Failedtoloadwallet:",err)
}
}
fmt.Printf("Youraddress:%s\n",color.BlueString(w.Address))
fmt.Println()
//创建TRON客户端
client,err:=tron.NewClient(nodeURL)
iferr!=nil{
log.Fatal("FailedtoconnecttoTRONnode:",err)
}
deferclient.Close()
//主循环
reader:=bufio.NewReader(os.Stdin)
for{
printMenu()
fmt.Print(">")
input,_:=reader.ReadString('\n')
input=strings.TrimSpace(input)
switchinput{
case"1":
showAccountInfo(client,w.Address)
case"2":
sendTRX(client,w)
case"3":
checkTRC20Balance(client,w.Address)
case"4":
sendTRC20(client,w)
case"5":
showPrivateKey(w)
case"6":
fmt.Println("Exiting...")
return
default:
fmt.Println("Invalidoption")
}
}
}
funcprintMenu(){
fmt.Println("\nMenu:")
fmt.Println("1.Showaccountinfo")
fmt.Println("2.SendTRX")
fmt.Println("3.CheckTRC20balance")
fmt.Println("4.SendTRC20tokens")
fmt.Println("5.Showprivatekey")
fmt.Println("6.Exit")
}
funccreateNewWallet()(wallet.Wallet,error){
w,err:=wallet.NewWallet()
iferr!=nil{
returnnil,err
}
iferr:=w.SaveToFile(walletFile);err!=nil{
returnnil,err
}
fmt.Println("Newwalletcreatedsuccessfully!")
fmt.Println("Pleasebackupyourprivatekeyandmnemonicphrasesecurely.")
returnw,nil
}
funcshowAccountInfo(clienttron.Client,addressstring){
account,err:=client.GetAccount(address)
iferr!=nil{
fmt.Println("Failedtogetaccountinfo:",err)
return
}
fmt.Println("\nAccountInformation:")
fmt.Printf("Address:%s\n",color.BlueString(address))
fmt.Printf("Balance:%dTRX\n",account.GetBalance())
fmt.Printf("Bandwidth:%d\n",account.GetNetUsage())
fmt.Printf("Energy:%d\n",account.GetAccountResource().GetEnergyUsage())
}
funcsendTRX(clienttron.Client,wwallet.Wallet){
reader:=bufio.NewReader(os.Stdin)
fmt.Print("Recipientaddress:")
to,_:=reader.ReadString('\n')
to=strings.TrimSpace(to)
fmt.Print("Amount(TRX):")
amountStr,_:=reader.ReadString('\n')
amountStr=strings.TrimSpace(amountStr)
amount,err:=strconv.ParseInt(amountStr,10,64)
iferr!=nil{
fmt.Println("Invalidamount:",err)
return
}
//1TRX=1,000,000SUN
amountInSun:=amount1000000
tx,err:=client.CreateTransaction(w.Address,to,amountInSun)
iferr!=nil{
fmt.Println("Failedtocreatetransaction:",err)
return
}
iferr:=tron.SignTransaction(tx,w.PrivateKey);err!=nil{
fmt.Println("Failedtosigntransaction:",err)
return
}
result,err:=client.BroadcastTransaction(tx)
iferr!=nil{
fmt.Println("Failedtobroadcasttransaction:",err)
return
}
ifresult.GetResult(){
fmt.Println(color.GreenString("Transactionsentsuccessfully!"))
fmt.Printf("TxID:%s\n",hex.EncodeToString(tx.GetTxid()))
}else{
fmt.Println(color.RedString("Transactionfailed:"),result.GetMessage())
}
}
funccheckTRC20Balance(clienttron.Client,addressstring){
reader:=bufio.NewReader(os.Stdin)
fmt.Print("TRC20contractaddress:")
contractAddr,_:=reader.ReadString('\n')
contractAddr=strings.TrimSpace(contractAddr)
balance,err:=client.GetTRC20Balance(contractAddr,address)
iferr!=nil{
fmt.Println("Failedtogetbalance:",err)
return
}
fmt.Printf("Balance:%stokens\n",balance.String())
}
funcsendTRC20(clienttron.Client,wwallet.Wallet){
reader:=bufio.NewReader(os.Stdin)
fmt.Print("TRC20contractaddress:")
contractAddr,_:=reader.ReadString('\n')
contractAddr=strings.TrimSpace(contractAddr)
fmt.Print("Recipientaddress:")
to,_:=reader.ReadString('\n')
to=strings.TrimSpace(to)
fmt.Print("Amount(insmallestunit):")
amountStr,_:=reader.ReadString('\n')
amountStr=strings.TrimSpace(amountStr)
amount,ok:=new(big.Int).SetString(amountStr,10)
if!ok{
fmt.Println("Invalidamount")
return
}
//构建TRC20transfer函数调用数据
data
转载请注明出处: TronLink官网下载-TRON-TRX-波场-波比-波币-波宝|官网-钱包-苹果APP|安卓-APP-下载
本文的链接地址: https://tianjinfa.org/post/3129
扫描二维码,在手机上阅读
文章作者:
文章标题:使用Go语言构建TronLink风格的钱包应用
文章链接:https://tianjinfa.org/post/3129
本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明来自 !
文章标题:使用Go语言构建TronLink风格的钱包应用
文章链接:https://tianjinfa.org/post/3129
本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明来自 !
打赏
如果觉得文章对您有用,请随意打赏。
您的支持是我们继续创作的动力!
微信扫一扫
支付宝扫一扫
您可能对以下文章感兴趣
-
使用Go语言构建TronLink钱包:完整源码与实现指南
10小时前
-
TronLink钱包网页版实现(PHP+CSS+JS+HTML5+JSON)
7小时前
-
TronLink钱包集成开发指南:PHP+CSS+JS+HTML5实现
7小时前
-
使用Go语言构建TronLink钱包:完整源码与实现指南
8小时前
-
原创TronLink钱包HTML5实现方案-SEO优化版
8小时前
-
TronLink钱包集成开发指南
8小时前
-
TronLink钱包集成开发指南:使用PHP+CSS+JS+HTML5+JSON实现
8小时前
-
TronLink钱包集成开发指南
9小时前
-
TronLink钱包开发指南:使用JavaScript构建去中心化应用
9小时前
-
使用PHP+CSS+JS+HTML5+JSON构建TronLink风格钱包应用(无MySQL)
9小时前