├── .gitignore ├── tron ├── readme.md ├── addr_decoder_test.go ├── manager_witness_test.go ├── tx_decode_test.go ├── manager_walletRef_test.go ├── manager_keyRef_test.go ├── manager_addr_test.go ├── manager_keyRef.go ├── manager_test.go ├── manager_block_test.go ├── manager_addrRef_test.go ├── manager_account_test.go ├── manager_wallet.go ├── manager_tx_test.go ├── addr_decoder.go ├── config_load.go ├── grpc-gateway │ └── core │ │ ├── TronInventoryItems.pb.go │ │ └── Discover.pb.go ├── manager.go ├── api.go ├── manager_addr.go ├── manager_walletRef.go ├── manager_witness.go ├── blockscanner_test.go ├── contract_test.go ├── blockscanner_db.go ├── manager_block.go ├── config.go ├── contract.go ├── manager_txRef_test.go ├── manager_tx.go ├── manager_account.go ├── tron.go ├── manager_addrRef.go └── models.go ├── openwtester ├── init.go ├── manager_test.go ├── subscribe_test.go ├── transaction_manager_test.go └── transcation_assets_test.go ├── README.md └── go.mod /.gitignore: -------------------------------------------------------------------------------- 1 | *.db 2 | release 3 | .vscode 4 | .idea 5 | *.key 6 | openwtester/conf 7 | -------------------------------------------------------------------------------- /tron/readme.md: -------------------------------------------------------------------------------- 1 | # Filename Declare 2 | 3 | manager_xxRef.go Generated xx by hand-operated 4 | manager_xx.go Call walletnode to genrate xx 5 | 6 | # Key tech be used 7 | 8 | google protocol buffer: like Json to pack/unpack an instance to be an string (almost also is Hex) 9 | -------------------------------------------------------------------------------- /openwtester/init.go: -------------------------------------------------------------------------------- 1 | package openwtester 2 | 3 | import ( 4 | "github.com/blocktree/openwallet/v2/log" 5 | "github.com/blocktree/openwallet/v2/openw" 6 | "github.com/blocktree/tron-adapter/tron" 7 | ) 8 | 9 | func init() { 10 | //注册钱包管理工具 11 | log.Notice("Wallet Manager Load Successfully.") 12 | openw.RegAssets(tron.Symbol, tron.NewWalletManager()) 13 | } 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tron-adapter 2 | 3 | 本项目适配了openwallet.AssetsAdapter接口,给应用提供了底层的区块链协议支持。 4 | 5 | ## 如何测试 6 | 7 | openwtester包下的测试用例已经集成了openwallet钱包体系,创建conf文件,新建TRX.ini文件,编辑如下内容: 8 | 9 | ```ini 10 | 11 | # restful api url 12 | ServerAPI = "http://127.0.0.1:18090" 13 | # Is network test? 14 | isTestNet = false 15 | # feeLimit, the maximum energy is 1000000000 16 | feeLimit = 10000000 17 | # Cache data file directory, default = "", current directory: ./data 18 | dataDir = "" 19 | 20 | ``` 21 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/blocktree/tron-adapter 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/Sereal/Sereal v0.0.0-20191211210414-3a6c62eca003 // indirect 7 | github.com/asdine/storm v2.1.2+incompatible 8 | github.com/astaxie/beego v1.12.0 9 | github.com/blocktree/go-owcdrivers v1.2.0 10 | github.com/blocktree/go-owcrypt v1.1.1 11 | github.com/blocktree/openwallet/v2 v2.0.5 12 | github.com/bndr/gotabulate v1.1.2 13 | github.com/btcsuite/btcutil v0.0.0-20191219182022-e17c9730c422 14 | github.com/golang/protobuf v1.3.2-0.20190517061210-b285ee9cfc6c 15 | github.com/graarh/golang-socketio v0.0.0-20170510162725-2c44953b9b5f 16 | github.com/grpc-ecosystem/grpc-gateway v1.8.5 17 | github.com/imroc/req v0.2.4 18 | github.com/shopspring/decimal v0.0.0-20200105231215-408a2507e114 19 | github.com/tidwall/gjson v1.6.5 20 | google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107 21 | google.golang.org/grpc v1.19.1 22 | ) 23 | 24 | //replace github.com/blocktree/openwallet => ../../openwallet 25 | -------------------------------------------------------------------------------- /tron/addr_decoder_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The openwallet Authors 3 | * This file is part of the openwallet library. 4 | * 5 | * The openwallet library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The openwallet library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package tron 17 | 18 | import ( 19 | "github.com/blocktree/openwallet/v2/log" 20 | "testing" 21 | ) 22 | 23 | func TestEncodeAddress(t *testing.T) { 24 | addr, err := EncodeAddress("412b30841b1705b302b6c431182670e53d32c7b084", false) 25 | if err != nil { 26 | t.Errorf("unexpected error: %v", err) 27 | return 28 | } 29 | log.Infof("addr: %s", addr) 30 | } 31 | -------------------------------------------------------------------------------- /tron/manager_witness_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The openwallet Authors 3 | * This file is part of the openwallet library. 4 | * 5 | * The openwallet library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The openwallet library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package tron 17 | 18 | import ( 19 | "testing" 20 | ) 21 | 22 | func TestListWitnesses(t *testing.T) { 23 | if r, err := tw.ListWitnesses(); err != nil { 24 | t.Errorf("ListWitnesses failed: %v\n", err) 25 | } else { 26 | t.Logf("ListWitnesses return: \n\t%+v\n", r) 27 | } 28 | } 29 | 30 | func TestListNodes(t *testing.T) { 31 | if r, err := tw.ListNodes(); err != nil { 32 | t.Errorf("ListNodes failed: %v\n", err) 33 | } else { 34 | t.Logf("ListNodes return: \n\t%+v\n", r) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tron/tx_decode_test.go: -------------------------------------------------------------------------------- 1 | package tron 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | // var ( 8 | // tc = manager.NewConfig() 9 | // //testApp = "openw" 10 | // testApp = "b4b1962d415d4d30ec71b28769fda585" 11 | // tm *WalletManager 12 | // ) 13 | 14 | // func init() { 15 | // tc.IsTestnet = true 16 | // tc.EnableBlockScan = false 17 | // tc.SupportAssets = []string{ 18 | // "BTC", 19 | // "QTUM", 20 | // "LTC", 21 | // "ETH", 22 | // "NAS", 23 | // "TRON", 24 | // } 25 | // tm = NewWalletManager(tc) 26 | // //tm.Init() 27 | // } 28 | 29 | func testCreateRawTransaction(t *testing.T) { 30 | 31 | // walletID := "WB9335ugSLt7v58D5iyPSRU7Eg16j2vNx9" 32 | // accountID := "59t47qyjHUMZ6PGAdjkJopE9ffAPUkdUhSinJqcWRYZ1" 33 | // to := "d35f9Ea14D063af9B3567064FAB567275b09f03D" 34 | 35 | // err := tm.RefreshAssetsAccountBalance(testApp, accountID) 36 | // if err != nil { 37 | // log.Error("RefreshAssetsAccountBalance failed, unexpected error:", err) 38 | // return 39 | // } 40 | 41 | // rawTx, err := tm.CreateTransaction(testApp, walletID, accountID, "0.1", to, "0.1", "", nil) 42 | 43 | // if err != nil { 44 | // log.Error("CreateTransaction failed, unexpected error:", err) 45 | // return 46 | // } 47 | 48 | // log.Info("rawTx:", rawTx) 49 | 50 | } 51 | -------------------------------------------------------------------------------- /tron/manager_walletRef_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The openwallet Authors 3 | * This file is part of the openwallet library. 4 | * 5 | * The openwallet library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The openwallet library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package tron 17 | 18 | import ( 19 | "fmt" 20 | "testing" 21 | ) 22 | 23 | func TestGetWallets(t *testing.T) { 24 | 25 | if r, err := tw.GetWallets(); err != nil { 26 | t.Errorf("GetWallets failed: %v\n", err) 27 | } else { 28 | tw.printWalletList(r) 29 | t.Logf("GetWallets return: \n%+v\n", r) 30 | } 31 | } 32 | 33 | func TestCreateNewWallet(t *testing.T) { 34 | 35 | var ( 36 | walletName = "simon" 37 | walletPass = "1234qwer" 38 | ) 39 | 40 | if r, s, err := tw.CreateNewWallet(walletName, walletPass); err != nil { 41 | t.Errorf("CreateNewWallet failed: %v\n", err) 42 | } else { 43 | t.Logf("TestCreateTrCreateNewWalletansaction return: \n%+v\n", r) 44 | 45 | fmt.Printf("keyfile = %+v\n", s) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tron/manager_keyRef_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The openwallet Authors 3 | * This file is part of the openwallet library. 4 | * 5 | * The openwallet library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The openwallet library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package tron 17 | 18 | import ( 19 | "encoding/hex" 20 | "fmt" 21 | "testing" 22 | ) 23 | 24 | func TestGetPrivateKeyRef(t *testing.T) { 25 | var ( 26 | walletID = "W4Hv5qiUb3R7GVQ9wgmX8MfhZ1GVR6dqL7" 27 | password = "1234qwer" 28 | index uint64 = 1539142990 29 | serializes uint32 30 | ) 31 | 32 | if r, err := tw.GetPrivateKeyRef(walletID, password, index, serializes); err != nil { 33 | t.Errorf("CreateAddressRef failed: %v\n", err) 34 | } else { 35 | 36 | h, _ := hex.DecodeString(r) 37 | 38 | if addr, err := tw.CreateAddressRef(h, true); err != nil { 39 | t.Errorf("CreateAddressRef failed: %v\n", err) 40 | } else { 41 | fmt.Println("Address = ", addr) 42 | } 43 | 44 | fmt.Printf("GetPrivateKeyRef return: \n\t%+v\n\n", r) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /tron/manager_addr_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The openwallet Authors 3 | * This file is part of the openwallet library. 4 | * 5 | * The openwallet library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The openwallet library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package tron 17 | 18 | import ( 19 | "fmt" 20 | "testing" 21 | ) 22 | 23 | func TestCreateAddress(t *testing.T) { 24 | 25 | var ( 26 | passValue = "7465737470617373776f7264" 27 | 28 | predictBase58checkAddress = "TWwv3YcHJ1NfMemQSmXCPY48RR1tsY3n9N" 29 | // predictAddressHex = "41e61c1205ee029fb4e41f294afd448cc5d578c8ef" 30 | ) 31 | 32 | if r, err := tw.CreateAddress(passValue); err != nil { 33 | t.Errorf("CreateAddress failed: %v\n", err) 34 | } else { 35 | fmt.Printf("CreateAddress return: \n\t%+v\n", r) 36 | 37 | if r != predictBase58checkAddress { 38 | t.Errorf("CreateAddress failed: %v\n", "Data Invalid!") 39 | } 40 | } 41 | } 42 | 43 | func TestGenerateAddress(t *testing.T) { 44 | 45 | if r, err := tw.GenerateAddress(); err != nil { 46 | t.Errorf("GenerateAddress failed: %v\n", err) 47 | } else { 48 | fmt.Printf("GenerateAddress return: \n\t%+v\n", r) 49 | } 50 | } 51 | 52 | func TestValidateAddress(t *testing.T) { 53 | 54 | var addr = OWNERADDRESS 55 | 56 | if err := tw.ValidateAddress(addr); err != nil { 57 | t.Errorf("ValidateAddress failed: %v\n", err) 58 | } else { 59 | fmt.Printf("ValidateAddress return: \n\t%+v\n", "Success!") 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /tron/manager_keyRef.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The openwallet Authors 3 | * This file is part of the openwallet library. 4 | * 5 | * The openwallet library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The openwallet library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package tron 17 | 18 | import ( 19 | "encoding/hex" 20 | "fmt" 21 | ) 22 | 23 | //GetPrivateKeyRef 找到地址索引对应的私钥,返回私钥hex格式字符串 24 | func (wm *WalletManager) GetPrivateKeyRef(walletID, password string, index uint64, serializes uint32) (string, error) { 25 | 26 | //读取钱包文件 27 | w, err := wm.GetWalletInfo(walletID) 28 | if err != nil { 29 | wm.Log.Info("get wallet info failed;unexpected error:%v", err) 30 | return "", err 31 | } 32 | 33 | //解密钱包文件并加载钱包KEY 34 | k, err := w.HDKey(password) 35 | if err != nil { 36 | wm.Log.Info("load wallet key failed;unexpected error:%v", err) 37 | return "", err 38 | } 39 | 40 | derivedPath := fmt.Sprintf("%s/%d", k.RootPath, index) 41 | key, err := k.DerivedKeyWithPath(derivedPath, wm.Config.CurveType) 42 | if err != nil { 43 | wm.Log.Info("derive key with path failed;unexpected error:%v", err) 44 | return "", err 45 | } 46 | 47 | childKey, err := key.GenPrivateChild(uint32(serializes)) 48 | if err != nil { 49 | wm.Log.Info("generate private child key failed;unexpected error:%v", err) 50 | return "", err 51 | } 52 | 53 | keyBytes, err := childKey.GetPrivateKeyBytes() 54 | if err != nil { 55 | wm.Log.Info("get private key failed;unexpected error:%v", err) 56 | return "", err 57 | } 58 | 59 | return hex.EncodeToString(keyBytes), nil 60 | } 61 | -------------------------------------------------------------------------------- /tron/manager_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The openwallet Authors 3 | * This file is part of the openwallet library. 4 | * 5 | * The openwallet library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The openwallet library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package tron 17 | 18 | var ( 19 | tw *WalletManager 20 | 21 | TOADDRESS = "TSdXzXKSQ3RQzQ5Ge8TiYfMQEjofSVQ8ax" // account: t2 22 | OWNERADDRESS = "TNQkiUv4qtDRKWDrKS628FTbDwxLMiqbAz" // account: t1 23 | PRIVATEKEY = "6c5e3afd3d6c0394dc922d9bcaf98fd9c972aa226948b44e14a7e4b0566c69ca" // account: t1 24 | AMOUNT = "0.1" 25 | 26 | TXRAW = "0a7e0a023c462208c84cf406d3b89d2640ffbd85e0fa2c5a67080112630a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412320a1541887661d2e0215851756b1e7933216064526badcd121541b6c1abf9fb31c9077dfb3c25469e6e943ffbfa7a18a08d06" 27 | TXSIGNED = "0a7e0a02d5842208a43b6160eaa543f840f8ffb4a9e12c5a67080112630a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412320a154199fee02e1ee01189bc41a68e9069b7919ef2ad82121541e11973395042ba3c0b52b4cdf4e15ea77818f27518c0843d1241915254f565f20a327047e59327bf7f0b9e5600c09a321e6da45de4be4158f1f14bbf520ac1a0d71da10696ee80dfa5860086a6e470c96e7a275c4433616b8beb00" 28 | ) 29 | 30 | func init() { 31 | 32 | tw = NewWalletManager() 33 | 34 | //tw.Config.ServerAPI = "http://127.0.0.1:28090" 35 | tw.Config.ServerAPI = "https://api.trongrid.io" 36 | tw.Config.IsTestNet = false 37 | // tw.Config.RpcUser = "walletUser" 38 | // tw.Config.RpcPassword = "walletPassword2017" 39 | // token := BasicAuth(tw.Config.RpcUser, tw.Config.RpcPassword) 40 | tw.WalletClient = NewClient(tw.Config.ServerAPI, "", true) 41 | } 42 | -------------------------------------------------------------------------------- /tron/manager_block_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The openwallet Authors 3 | * This file is part of the openwallet library. 4 | * 5 | * The openwallet library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The openwallet library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package tron 17 | 18 | import ( 19 | "testing" 20 | ) 21 | 22 | func TestGetNowBlock(t *testing.T) { 23 | 24 | if r, err := tw.GetNowBlock(); err != nil { 25 | t.Errorf("GetNowBlock failed: %v\n", err) 26 | } else { 27 | // t.Logf("GetNowBlock return: \n\t%+v\n", r) 28 | 29 | printBlock(r) 30 | } 31 | } 32 | 33 | func TestGetBlockByNum(t *testing.T) { 34 | var num uint64 = 3412368 35 | 36 | if r, err := tw.GetBlockByNum(num); err != nil { 37 | t.Errorf("GetBlockByNum failed: %v\n", err) 38 | } else { 39 | t.Logf("GetBlockByNum return: \n\t%+v\n", r) 40 | 41 | printBlock(r) 42 | } 43 | } 44 | 45 | func TestGetBlockByID(t *testing.T) { 46 | 47 | var blockID = "0000000000341190edc6eb2c61e2efd0b6c45177962b43cd13c0cd32da62cc0e" 48 | 49 | if r, err := tw.GetBlockByID(blockID); err != nil { 50 | t.Errorf("GetBlockByID failed: %v\n", err) 51 | } else { 52 | t.Logf("GetBlockByID return: \n\t%+v\n", r) 53 | 54 | printBlock(r) 55 | } 56 | /* 57 | blockID = "0000000000341190edc6eb2c61e2efd0b6c45177962b43cd13c0cd32da62cc0a" // Error ID 58 | if r, err := tw.GetBlockByID(blockID); err != nil { 59 | t.Logf("GetBlockByID return: \n\t%+v\n", r) 60 | } else { 61 | t.Errorf("GetBlockByID failed: %v\n", err) 62 | } 63 | */ 64 | } 65 | 66 | func TestGetBlockByLimitNext(t *testing.T) { 67 | 68 | var startSum, endSum uint64 = 120 * 10000, 120*10000 + 3 69 | 70 | if r, err := tw.GetBlockByLimitNext(startSum, endSum); err != nil { 71 | t.Errorf("GetBlockByLimitNext failed: %v\n", err) 72 | } else { 73 | 74 | for _, v := range r { 75 | printBlock(v) 76 | } 77 | } 78 | } 79 | 80 | func TestGetBlockByLatestNum(t *testing.T) { 81 | 82 | var num uint64 = 3 83 | 84 | if r, err := tw.GetBlockByLatestNum(num); err != nil { 85 | t.Errorf("GetBlockByLatestNum failed: %v\n", err) 86 | } else { 87 | t.Logf("GetBlockByLatestNum return: \n\t%+v\n", r) 88 | 89 | for _, v := range r { 90 | printBlock(v) 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /tron/manager_addrRef_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The openwallet Authors 3 | * This file is part of the openwallet library. 4 | * 5 | * The openwallet library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The openwallet library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package tron 17 | 18 | import ( 19 | "encoding/hex" 20 | "fmt" 21 | "testing" 22 | ) 23 | 24 | func TestCreateAddressRef(t *testing.T) { 25 | 26 | var privateKeyValue, predictedAddr string 27 | 28 | privateKeyValue = "9e9fa25c9d70fecc91c90d23b55daffa2f5f23ffa9eeca823260e50e544cf7be" 29 | predictedAddr = "TQ1TiUzStbSLdEtACUDmzfMDpWUyo8cyCf" 30 | 31 | priKeyBytes, _ := hex.DecodeString(privateKeyValue) 32 | 33 | if r, err := tw.CreateAddressRef(priKeyBytes, true); err != nil { 34 | t.Errorf("CreateAddressRef failed: %v\n", err) 35 | } else { 36 | t.Logf("CreateAddressRef return: \n\t%+v\n", r) 37 | 38 | if r != predictedAddr { 39 | t.Errorf("CreateAddressRef failed: not equal (Predict: %v)!\n", predictedAddr) 40 | 41 | } 42 | 43 | fmt.Printf("Created: %+v\n", r) 44 | fmt.Printf("Predict: %+v\n", predictedAddr) 45 | } 46 | } 47 | 48 | //func TestValidateAddressRef(t *testing.T) { 49 | // 50 | // var addr string 51 | // addr = "TQ1TiUzStbSLdEtACUDmzfMDpWUyo8cyCf" 52 | // addr = OWNERADDRESS 53 | // 54 | // if err := tw.ValidateAddressRef(addr); err != nil { 55 | // t.Errorf("ValidateAddressRef failed: \n\t%+v\n", err) 56 | // } else { 57 | // fmt.Printf("CreateAddressRef return: \n\tSuccess!\n") 58 | // } 59 | //} 60 | 61 | func TestCreateBatchAddress(t *testing.T) { 62 | 63 | var ( 64 | walletID = "W4Hv5qiUb3R7GVQ9wgmX8MfhZ1GVR6dqL7" 65 | password = "1234qwer" 66 | count uint64 = 1000 67 | ) 68 | if s, r, err := tw.CreateBatchAddress(walletID, password, count); err != nil { 69 | t.Errorf("CreateBatchAddress failed: \n\t%+v\n", err) 70 | } else { 71 | fmt.Printf("CreateBatchAddress return: \n\t%+v\n", s) 72 | tw.printAddressList(r) 73 | } 74 | } 75 | 76 | func TestGetAddressesFromLocalDB(t *testing.T) { 77 | 78 | var ( 79 | walletID = "W4Hv5qiUb3R7GVQ9wgmX8MfhZ1GVR6dqL7" 80 | offset int 81 | limit = -1 82 | ) 83 | if r, err := tw.GetAddressesFromLocalDB(walletID, offset, limit); err != nil { 84 | t.Errorf("GetAddressesFromLocalDB failed: \n\t%+v\n", err) 85 | } else { 86 | fmt.Printf("GetAddressesFromLocalDB return: \n\t%+v\n", r) 87 | 88 | tw.printAddressList(r) 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /tron/manager_account_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The openwallet Authors 3 | * This file is part of the openwallet library. 4 | * 5 | * The openwallet library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The openwallet library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package tron 17 | 18 | import ( 19 | "github.com/blocktree/openwallet/v2/log" 20 | "testing" 21 | ) 22 | 23 | func TestGetAccountNet(t *testing.T) { 24 | 25 | var addr string 26 | addr = "TRJJ9Mq4aMjdmKWpTDJAgbYNoY2P9Facg5" 27 | accountNet, err := tw.GetAccountNet(addr) 28 | if err != nil { 29 | t.Errorf("GetAccountNet failed: %v\n", err) 30 | return 31 | } 32 | log.Infof("accountNet: %+v", accountNet) 33 | } 34 | 35 | func TestGetAccountResource(t *testing.T) { 36 | 37 | var addr string 38 | addr = "TRJJ9Mq4aMjdmKWpTDJAgbYNoY2P9Facg5" 39 | account, err := tw.GetAccountResource(addr) 40 | if err != nil { 41 | t.Errorf("GetAccountResource failed: %v\n", err) 42 | return 43 | } 44 | log.Infof("GetAccountResource: %+v", account) 45 | } 46 | 47 | func TestGetAccount(t *testing.T) { 48 | 49 | var addr string 50 | 51 | addr = "TF84rDKSaVXpFyzMvP8SPPzEChQ4QAP75N" 52 | 53 | if r, err := tw.GetAccount(addr); err != nil { 54 | t.Errorf("GetAccount failed: %v\n", err) 55 | } else { 56 | t.Logf("GetAccount return: \n\t%+v\n", r) 57 | } 58 | } 59 | 60 | func TestCreateAccount(t *testing.T) { 61 | 62 | var ownerAddress, accountAddress string = OWNERADDRESS, OWNERADDRESS 63 | 64 | if r, err := tw.CreateAccount(ownerAddress, accountAddress); err != nil { 65 | t.Errorf("CreateAccount failed: %v\n", err) 66 | } else { 67 | t.Logf("CreateAccount return: \n\t%+v\n", r) 68 | } 69 | } 70 | 71 | func TestUpdateAccount(t *testing.T) { 72 | 73 | var accountName, ownerAddress string = "XX2", OWNERADDRESS 74 | 75 | if r, err := tw.UpdateAccount(accountName, ownerAddress); err != nil { 76 | t.Errorf("UpdateAccount failed: %v\n", err) 77 | } else { 78 | t.Logf("UpdateAccount return: \n\t%+v\n", r) 79 | 80 | if r.Get("txID").String() == "" { 81 | t.Errorf("UpdateAccount failed: %v\n", "Data Invalid!") 82 | } 83 | } 84 | } 85 | 86 | func TestGetTRXAccount(t *testing.T) { 87 | 88 | var addr string 89 | 90 | addr = "TNmR1WCd2VD6vqXkmDjkDUPF8nXQAFmzJF" 91 | 92 | if r, _, err := tw.GetTRXAccount(addr); err != nil { 93 | t.Errorf("GetAccount failed: %v\n", err) 94 | } else { 95 | t.Logf("GetAccount return: \n\t%+v\n", r) 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /tron/manager_wallet.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The openwallet Authors 3 | * This file is part of the openwallet library. 4 | * 5 | * The openwallet library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The openwallet library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package tron 17 | 18 | import ( 19 | "github.com/blocktree/openwallet/v2/common" 20 | "github.com/shopspring/decimal" 21 | ) 22 | 23 | //GetWalletBalance 获取钱包余额 24 | func (wm *WalletManager) GetWalletBalance(accountID string) string { 25 | 26 | balance := decimal.New(0, 0) 27 | 28 | return balance.StringFixed(8) 29 | } 30 | 31 | // //DumpWallet 导出钱包所有私钥文件 32 | // func (wm *WalletManager) DumpWallet(filename string) error { 33 | 34 | // request := []interface{}{ 35 | // filename, 36 | // } 37 | 38 | // _, err := wm.WalletClient.Call("dumpwallet", request) 39 | // if err != nil { 40 | // return err 41 | // } 42 | 43 | // return nil 44 | 45 | // } 46 | 47 | // //ImportWallet 导入钱包私钥文件 48 | // func (wm *WalletManager) ImportWallet(filename string) error { 49 | 50 | // request := []interface{}{ 51 | // filename, 52 | // } 53 | 54 | // _, err := wm.WalletClient.Call("importwallet", request) 55 | // if err != nil { 56 | // return err 57 | // } 58 | 59 | // return nil 60 | // } 61 | 62 | //SummaryWallets 执行汇总流程 63 | func (wm *WalletManager) SummaryWallets() { 64 | 65 | wm.Log.Info("[Summary Wallet Start]------%s", common.TimeFormat("2006-01-02 15:04:05")) 66 | 67 | //读取参与汇总的钱包 68 | for wid, wallet := range wm.WalletsInSum { 69 | 70 | //统计钱包最新余额 71 | wb := wm.GetWalletBalance(wid) 72 | 73 | balance, _ := decimal.NewFromString(wb) 74 | //如果余额大于阀值,汇总的地址 75 | if balance.GreaterThan(wm.Config.Threshold) { 76 | 77 | wm.Log.Info("Summary account[%s]balance = %v ", wallet.WalletID, balance) 78 | wm.Log.Info("Summary account[%s]Start Send Transaction", wallet.WalletID) 79 | 80 | txID, err := wm.SendTransaction(wallet.WalletID, wm.Config.SumAddress, balance, wallet.Password, false) 81 | if err != nil { 82 | wm.Log.Info("Summary account[%s]unexpected error: %v", wallet.WalletID, err) 83 | continue 84 | } else { 85 | wm.Log.Info("Summary account[%s]successfully,Received Address[%s], TXID:%s", wallet.WalletID, wm.Config.SumAddress, txID) 86 | } 87 | } else { 88 | wm.Log.Info("Wallet Account[%s]-[%s]Current Balance: %v,below threshold: %v", wallet.Alias, wallet.WalletID, balance, wm.Config.Threshold) 89 | } 90 | } 91 | 92 | wm.Log.Info("[Summary Wallet end]------%s", common.TimeFormat("2006-01-02 15:04:05")) 93 | } 94 | -------------------------------------------------------------------------------- /tron/manager_tx_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The openwallet Authors 3 | * This file is part of the openwallet library. 4 | * 5 | * The openwallet library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The openwallet library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package tron 17 | 18 | import ( 19 | "fmt" 20 | "testing" 21 | ) 22 | 23 | func TestGetTotalTransaction(t *testing.T) { 24 | if r, err := tw.GetTotalTransaction(); err != nil { 25 | t.Errorf("TestGetTotalTransaction failed: %v\n", err) 26 | } else { 27 | t.Logf("TestGetTotalTransaction return: \n\t%+v\n", r) 28 | } 29 | } 30 | 31 | func TestGetTransactionByID(t *testing.T) { 32 | 33 | //var txID = "3fac47cf4c75099044290ee58098ec5a490510d3ade909ac20663cfee6a5c62d" 34 | // 35 | //if r, err := tw.GetTransactionByID(txID); err != nil || r.IsSuccess != true { 36 | // t.Logf("TestGetTransactionByID return: \n\t%+v\n", r) 37 | // t.Errorf("TestGetTransactionByID failed: %v\n", err) 38 | //} else { 39 | // t.Logf("TestGetTransactionByID return: \n\t%+v\n", r) 40 | //} 41 | } 42 | 43 | //func TestCreateTransaction(t *testing.T) { 44 | // 45 | // if r, err := tw.CreateTransaction(TOADDRESS, OWNERADDRESS, AMOUNT); err != nil { 46 | // t.Errorf("TestCreateTransaction failed: %v\n", err) 47 | // } else { 48 | // //t.Logf("TestCreateTransaction return: \n\t%+v\n", r) 49 | // fmt.Println("Tx:=", r) 50 | // } 51 | // 52 | //} 53 | 54 | func TestGetTransactoinSign(t *testing.T) { 55 | 56 | var txRaw = "0a7e0a023c462208c84cf406d3b89d2640ffbd85e0fa2c5a67080112630a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412320a1541887661d2e0215851756b1e7933216064526badcd121541b6c1abf9fb31c9077dfb3c25469e6e943ffbfa7a18a08d06" 57 | 58 | if r, err := tw.GetTransactionSign(txRaw, PRIVATEKEY); err != nil { 59 | t.Errorf("TestCreateTransaction failed: %v\n", err) 60 | } else { 61 | //t.Logf("TestCreateTransaction return: \n\t%+v\n", r) 62 | fmt.Println("signature:=", r) 63 | } 64 | 65 | } 66 | 67 | func TestBroadcastTransaction1(t *testing.T) { 68 | 69 | var raw = "0a7e0a02a1192208d3216b8e04dc955240e0c2c786fb2c5a67080112630a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412320a1541887661d2e0215851756b1e7933216064526badcd121541b6c1abf9fb31c9077dfb3c25469e6e943ffbfa7a18a08d061241fb21995f0edd84ecc68e05026acc85c695dce9ff50ec5a4864f6178caa9465aa16784e787b01d56954d628794138bb0c20416ec3fa96ba1d132329d678ef1a9c00" 70 | 71 | if err := tw.BroadcastTransaction1(raw); err != nil { 72 | t.Errorf("BroadcastTransaction failed: %v\n", err) 73 | } else { 74 | t.Logf("BroadcastTransaction return: \n\t%+v\n", "Success!") 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /tron/addr_decoder.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The openwallet Authors 3 | * This file is part of the openwallet library. 4 | * 5 | * The openwallet library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The openwallet library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package tron 17 | 18 | import ( 19 | "encoding/hex" 20 | "github.com/blocktree/go-owcdrivers/addressEncoder" 21 | "github.com/blocktree/go-owcrypt" 22 | ) 23 | 24 | //AddressDecoderStruct for Interface AddressDecoder 25 | type AddressDecoderStruct struct { 26 | wm *WalletManager //钱包管理者 27 | } 28 | 29 | //NewAddressDecoder 地址解析器 30 | func NewAddressDecoder(wm *WalletManager) *AddressDecoderStruct { 31 | decoder := AddressDecoderStruct{} 32 | decoder.wm = wm 33 | return &decoder 34 | } 35 | 36 | //PrivateKeyToWIF 私钥转WIF 37 | func (decoder *AddressDecoderStruct) PrivateKeyToWIF(priv []byte, isTestnet bool) (string, error) { 38 | return "", nil 39 | } 40 | 41 | //PublicKeyToAddress 公钥转地址 42 | func (decoder *AddressDecoderStruct) PublicKeyToAddress(pub []byte, isTestnet bool) (string, error) { 43 | pubkey := owcrypt.PointDecompress(pub, owcrypt.ECC_CURVE_SECP256K1) 44 | hash := owcrypt.Hash(pubkey[1:], 0, owcrypt.HASH_ALG_KECCAK256) 45 | address, err := decoder.wm.CreateAddressRef(hash[12:], false) // isPrivate == false 46 | if err != nil { 47 | decoder.wm.Log.Info("creat address failed;unexpected error:%v", err) 48 | return "", err 49 | } 50 | return address, nil 51 | } 52 | 53 | //RedeemScriptToAddress 多重签名赎回脚本转地址 54 | func (decoder *AddressDecoderStruct) RedeemScriptToAddress(pubs [][]byte, required uint64, isTestnet bool) (string, error) { 55 | return "", nil 56 | } 57 | 58 | //WIFToPrivateKey WIF转私钥 59 | func (decoder *AddressDecoderStruct) WIFToPrivateKey(wif string, isTestnet bool) ([]byte, error) { 60 | 61 | return nil, nil 62 | 63 | } 64 | 65 | func DecodeAddress(addr string, isTestnet bool) (string, []byte, error) { 66 | codeType := addressEncoder.TRON_mainnetAddress 67 | if isTestnet { 68 | codeType = addressEncoder.TRON_testnetAddress 69 | } 70 | 71 | toAddressBytes, err := addressEncoder.AddressDecode(addr, codeType) 72 | if err != nil { 73 | return "", nil, err 74 | } 75 | toAddressBytes = append(codeType.Prefix, toAddressBytes...) 76 | return hex.EncodeToString(toAddressBytes), toAddressBytes, nil 77 | } 78 | 79 | func EncodeAddress(hexStr string, isTestnet bool) (string, error) { 80 | 81 | codeType := addressEncoder.TRON_mainnetAddress 82 | if isTestnet { 83 | codeType = addressEncoder.TRON_testnetAddress 84 | } 85 | 86 | b, err := hex.DecodeString(hexStr) 87 | if err != nil { 88 | return "", err 89 | } 90 | if len(b) > 20 { 91 | b = b[1:] 92 | } 93 | 94 | addr := addressEncoder.AddressEncode(b, codeType) 95 | return addr, nil 96 | } 97 | -------------------------------------------------------------------------------- /tron/config_load.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The openwallet Authors 3 | * This file is part of the openwallet library. 4 | * 5 | * The openwallet library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The openwallet library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package tron 17 | 18 | import ( 19 | "errors" 20 | "path/filepath" 21 | 22 | "github.com/astaxie/beego/config" 23 | "github.com/shopspring/decimal" 24 | ) 25 | 26 | const ( 27 | maxAddresNum = 10000 28 | ) 29 | 30 | //LoadConfig 读取配置 31 | func (wm *WalletManager) LoadConfig() error { 32 | 33 | var ( 34 | c config.Configer 35 | err error 36 | ) 37 | 38 | //读取配置 39 | absFile := filepath.Join(wm.Config.configFilePath, wm.Config.configFileName) 40 | c, err = config.NewConfig("ini", absFile) 41 | if err != nil { 42 | return errors.New("Config is not setup. Please run 'wmd Config -s ' ") 43 | } 44 | 45 | wm.Config.ServerAPI = c.String("serverAPI") 46 | wm.Config.Threshold, _ = decimal.NewFromString(c.String("threshold")) 47 | wm.Config.SumAddress = c.String("sumAddress") 48 | wm.Config.RPCUser = c.String("rpcUser") 49 | wm.Config.RPCPassword = c.String("rpcPassword") 50 | wm.Config.NodeInstallPath = c.String("nodeInstallPath") 51 | wm.Config.FeeLimit, _ = c.Int64("feeLimit") 52 | wm.Config.FeeMini, _ = c.Int64("feeMini") 53 | wm.Config.IsTestNet, _ = c.Bool("isTestNet") 54 | if wm.Config.IsTestNet { 55 | wm.Config.WalletDataPath = c.String("testNetDataPath") 56 | } else { 57 | wm.Config.WalletDataPath = c.String("mainNetDataPath") 58 | } 59 | wm.Config.IgnoreDustTRX, _ = decimal.NewFromString(c.String("ignoreDustTRX")) 60 | wm.WalletClient = NewClient(wm.Config.ServerAPI, "", false) 61 | 62 | return nil 63 | } 64 | 65 | //LoadAssetsConfig 加载外部配置 66 | func (wm *WalletManager) LoadAssetsConfig(c config.Configer) error { 67 | 68 | //读取配置 69 | //absFile := filepath.Join(wm.Config.configFilePath, wm.Config.configFileName) 70 | //c, err := config.NewConfig("ini", absFile) 71 | //if err != nil { 72 | // return errors.New("Config is not setup. Please run 'wmd Config -s ' ") 73 | //} 74 | wm.Config.ServerAPI = c.String("serverAPI") 75 | //wm.Config.Threshold, _ = decimal.NewFromString(c.String("threshold")) 76 | //wm.Config.SumAddress = c.String("sumAddress") 77 | //wm.Config.RPCUser = c.String("rpcUser") 78 | //wm.Config.RPCPassword = c.String("rpcPassword") 79 | //wm.Config.NodeInstallPath = c.String("nodeInstallPath") 80 | wm.Config.IsTestNet, _ = c.Bool("isTestNet") 81 | wm.Config.FeeLimit, _ = c.Int64("feeLimit") 82 | wm.Config.FeeMini, _ = c.Int64("feeMini") 83 | //if wm.Config.IsTestNet { 84 | // wm.Config.WalletDataPath = c.String("testNetDataPath") 85 | //} else { 86 | // wm.Config.WalletDataPath = c.String("mainNetDataPath") 87 | //} 88 | 89 | wm.WalletClient = NewClient(wm.Config.ServerAPI, "", false) 90 | wm.Config.DataDir = c.String("dataDir") 91 | wm.Config.IgnoreDustTRX, _ = decimal.NewFromString(c.String("ignoreDustTRX")) 92 | 93 | //数据文件夹 94 | wm.Config.makeDataDir() 95 | return nil 96 | } 97 | -------------------------------------------------------------------------------- /tron/grpc-gateway/core/TronInventoryItems.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // source: core/TronInventoryItems.proto 3 | 4 | package core 5 | 6 | import ( 7 | fmt "fmt" 8 | proto "github.com/golang/protobuf/proto" 9 | math "math" 10 | ) 11 | 12 | // Reference imports to suppress errors if they are not otherwise used. 13 | var _ = proto.Marshal 14 | var _ = fmt.Errorf 15 | var _ = math.Inf 16 | 17 | // This is a compile-time assertion to ensure that this generated file 18 | // is compatible with the proto package it is being compiled against. 19 | // A compilation error at this line likely means your copy of the 20 | // proto package needs to be updated. 21 | const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package 22 | 23 | type InventoryItems struct { 24 | Type int32 `protobuf:"varint,1,opt,name=type,proto3" json:"type,omitempty"` 25 | Items [][]byte `protobuf:"bytes,2,rep,name=items,proto3" json:"items,omitempty"` 26 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 27 | XXX_unrecognized []byte `json:"-"` 28 | XXX_sizecache int32 `json:"-"` 29 | } 30 | 31 | func (m *InventoryItems) Reset() { *m = InventoryItems{} } 32 | func (m *InventoryItems) String() string { return proto.CompactTextString(m) } 33 | func (*InventoryItems) ProtoMessage() {} 34 | func (*InventoryItems) Descriptor() ([]byte, []int) { 35 | return fileDescriptor_72fb4db5e1646d4f, []int{0} 36 | } 37 | 38 | func (m *InventoryItems) XXX_Unmarshal(b []byte) error { 39 | return xxx_messageInfo_InventoryItems.Unmarshal(m, b) 40 | } 41 | func (m *InventoryItems) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 42 | return xxx_messageInfo_InventoryItems.Marshal(b, m, deterministic) 43 | } 44 | func (m *InventoryItems) XXX_Merge(src proto.Message) { 45 | xxx_messageInfo_InventoryItems.Merge(m, src) 46 | } 47 | func (m *InventoryItems) XXX_Size() int { 48 | return xxx_messageInfo_InventoryItems.Size(m) 49 | } 50 | func (m *InventoryItems) XXX_DiscardUnknown() { 51 | xxx_messageInfo_InventoryItems.DiscardUnknown(m) 52 | } 53 | 54 | var xxx_messageInfo_InventoryItems proto.InternalMessageInfo 55 | 56 | func (m *InventoryItems) GetType() int32 { 57 | if m != nil { 58 | return m.Type 59 | } 60 | return 0 61 | } 62 | 63 | func (m *InventoryItems) GetItems() [][]byte { 64 | if m != nil { 65 | return m.Items 66 | } 67 | return nil 68 | } 69 | 70 | func init() { 71 | proto.RegisterType((*InventoryItems)(nil), "protocol.InventoryItems") 72 | } 73 | 74 | func init() { proto.RegisterFile("core/TronInventoryItems.proto", fileDescriptor_72fb4db5e1646d4f) } 75 | 76 | var fileDescriptor_72fb4db5e1646d4f = []byte{ 77 | // 158 bytes of a gzipped FileDescriptorProto 78 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4d, 0xce, 0x2f, 0x4a, 79 | 0xd5, 0x0f, 0x29, 0xca, 0xcf, 0xf3, 0xcc, 0x2b, 0x4b, 0xcd, 0x2b, 0xc9, 0x2f, 0xaa, 0xf4, 0x2c, 80 | 0x49, 0xcd, 0x2d, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x00, 0x53, 0xc9, 0xf9, 0x39, 81 | 0x4a, 0x56, 0x5c, 0x7c, 0xa8, 0x2a, 0x84, 0x84, 0xb8, 0x58, 0x4a, 0x2a, 0x0b, 0x52, 0x25, 0x18, 82 | 0x15, 0x18, 0x35, 0x58, 0x83, 0xc0, 0x6c, 0x21, 0x11, 0x2e, 0xd6, 0x4c, 0x90, 0xa4, 0x04, 0x93, 83 | 0x02, 0xb3, 0x06, 0x4f, 0x10, 0x84, 0xe3, 0x14, 0xc0, 0xc5, 0x9f, 0x5f, 0x94, 0xae, 0x57, 0x52, 84 | 0x94, 0x9f, 0x07, 0x31, 0xb7, 0xd8, 0x49, 0x08, 0xd3, 0xca, 0x28, 0xcd, 0xf4, 0xcc, 0x92, 0x8c, 85 | 0xd2, 0x24, 0xbd, 0xe4, 0xfc, 0x5c, 0x7d, 0x90, 0x5a, 0x98, 0xdd, 0xfa, 0xe9, 0x45, 0x05, 0xc9, 86 | 0xba, 0xe9, 0x89, 0x25, 0xa9, 0xe5, 0x89, 0x95, 0xfa, 0x20, 0x07, 0x27, 0xb1, 0x81, 0xe5, 0x8c, 87 | 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0x28, 0xdc, 0x30, 0x0d, 0xbf, 0x00, 0x00, 0x00, 88 | } 89 | -------------------------------------------------------------------------------- /tron/manager.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The openwallet Authors 3 | * This file is part of the openwallet library. 4 | * 5 | * The openwallet library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The openwallet library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package tron 17 | 18 | import ( 19 | "github.com/blocktree/openwallet/v2/hdkeystore" 20 | "github.com/blocktree/openwallet/v2/log" 21 | "github.com/blocktree/openwallet/v2/openwallet" 22 | "github.com/shopspring/decimal" 23 | ) 24 | 25 | var ( 26 | //coinDecimal decimal.Decimal = decimal.NewFromFloat(1000000) 27 | coinDecimal decimal.Decimal = decimal.NewFromFloat(1000000) 28 | ) 29 | 30 | func init() { 31 | // log.SetFlags(log.Lshortfile | log.LstdFlags) 32 | } 33 | 34 | // WalletManager struct 35 | type WalletManager struct { 36 | openwallet.AssetsAdapterBase 37 | 38 | Config *WalletConfig //钱包管理配置 39 | Storage *hdkeystore.HDKeystore //秘钥存取 40 | FullnodeClient *Client // 全节点客户端 41 | WalletClient *Client // 节点客户端 42 | Log *log.OWLogger //日志工具 43 | 44 | WalletsInSum map[string]*openwallet.Wallet //参与汇总的钱包 45 | 46 | Blockscanner *TronBlockScanner //区块扫描器 47 | AddrDecoder openwallet.AddressDecoder //地址编码器 48 | TxDecoder openwallet.TransactionDecoder //交易单编码器 49 | ContractDecoder openwallet.SmartContractDecoder // 50 | } 51 | 52 | // NewWalletManager create instance 53 | func NewWalletManager() *WalletManager { 54 | 55 | wm := WalletManager{} 56 | wm.Config = NewConfig() 57 | wm.Storage = hdkeystore.NewHDKeystore(wm.Config.keyDir, hdkeystore.StandardScryptN, hdkeystore.StandardScryptP) 58 | wm.WalletsInSum = make(map[string]*openwallet.Wallet) 59 | wm.Blockscanner = NewTronBlockScanner(&wm) 60 | wm.AddrDecoder = NewAddressDecoder(&wm) 61 | wm.TxDecoder = NewTransactionDecoder(&wm) 62 | wm.Log = log.NewOWLogger(wm.Symbol()) 63 | wm.ContractDecoder = NewContractDecoder(&wm) 64 | //wm.WalletClient = NewClient("http://192.168.27.124:18090", "", true) 65 | return &wm 66 | } 67 | 68 | //------------------------------------------------------------------------------------------------ 69 | 70 | //CurveType 曲线类型 71 | func (wm *WalletManager) CurveType() uint32 { 72 | return wm.Config.CurveType 73 | } 74 | 75 | //FullName 币种全名 76 | func (wm *WalletManager) FullName() string { 77 | return "TRX" 78 | } 79 | 80 | //Symbol 币种标识 81 | func (wm *WalletManager) Symbol() string { 82 | return wm.Config.Symbol 83 | } 84 | 85 | //Decimal 小数位精度 *1000000 86 | func (wm *WalletManager) Decimal() int32 { 87 | return Decimals 88 | } 89 | 90 | //GetAddressDecode 地址解析器 91 | func (wm *WalletManager) GetAddressDecode() openwallet.AddressDecoder { 92 | return wm.AddrDecoder 93 | } 94 | 95 | //GetTransactionDecoder 交易单解析器 96 | func (wm *WalletManager) GetTransactionDecoder() openwallet.TransactionDecoder { 97 | return wm.TxDecoder 98 | } 99 | 100 | //GetBlockScanner 获取区块链 101 | func (wm *WalletManager) GetBlockScanner() openwallet.BlockScanner { 102 | return wm.Blockscanner 103 | } 104 | 105 | func (this *WalletManager) GetSmartContractDecoder() openwallet.SmartContractDecoder { 106 | return this.ContractDecoder 107 | } 108 | -------------------------------------------------------------------------------- /tron/api.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The openwallet Authors 3 | * This file is part of the openwallet library. 4 | * 5 | * The openwallet library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The openwallet library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package tron 17 | 18 | import ( 19 | "errors" 20 | "fmt" 21 | "github.com/blocktree/openwallet/v2/log" 22 | "github.com/blocktree/openwallet/v2/openwallet" 23 | "github.com/imroc/req" 24 | "github.com/shopspring/decimal" 25 | "github.com/tidwall/gjson" 26 | "net/http" 27 | ) 28 | 29 | // A Client is a Tron RPC client. It performs RPCs over HTTP using JSON 30 | // request and responses. A Client must be configured with a secret token 31 | // to authenticate with other Cores on the network. 32 | type Client struct { 33 | BaseURL string 34 | // AccessToken string 35 | Debug bool 36 | client *req.Req 37 | } 38 | 39 | // NewClient create new client to connect 40 | func NewClient(url, token string, debug bool) *Client { 41 | c := Client{ 42 | BaseURL: url, 43 | // AccessToken: token, 44 | Debug: debug, 45 | } 46 | 47 | api := req.New() 48 | //trans, _ := api.Client().Transport.(*http.Transport) 49 | //trans.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} 50 | c.client = api 51 | 52 | return &c 53 | } 54 | 55 | // Call calls a remote procedure on another node, specified by the path. 56 | func (c *Client) Call(path string, param interface{}) (*gjson.Result, error) { 57 | 58 | if c == nil || c.client == nil { 59 | return nil, errors.New("API url is not setup. ") 60 | } 61 | 62 | url := c.BaseURL + path 63 | authHeader := req.Header{"Accept": "application/json"} 64 | 65 | r, err := req.Post(url, req.BodyJSON(¶m), authHeader) 66 | if err != nil { 67 | log.Errorf("Failed: %+v >\n", err) 68 | return nil, err 69 | } 70 | 71 | if c.Debug { 72 | log.Std.Info("%+v", r) 73 | } 74 | 75 | if r.Response().StatusCode != http.StatusOK { 76 | message := gjson.ParseBytes(r.Bytes()).String() 77 | message = fmt.Sprintf("[%s]%s", r.Response().Status, message) 78 | log.Error(message) 79 | return nil, errors.New(message) 80 | } 81 | 82 | res := gjson.ParseBytes(r.Bytes()) 83 | return &res, nil 84 | } 85 | 86 | //getBalance 获取地址余额 87 | func (wm *WalletManager) getBalance(address string) (*openwallet.Balance, error) { 88 | account, _, err := wm.GetTRXAccount(address) 89 | if err != nil { 90 | return nil, err 91 | } 92 | balance := decimal.New(account.Balance, 0) 93 | balance = balance.Shift(-wm.Decimal()) 94 | obj := openwallet.Balance{} 95 | obj.Address = address 96 | obj.ConfirmBalance = balance.String() 97 | obj.UnconfirmBalance = "0" 98 | obj.Balance = balance.String() 99 | return &obj, nil 100 | } 101 | 102 | func newBalanceByExplorer(json *gjson.Result) *openwallet.Balance { 103 | 104 | obj := openwallet.Balance{} 105 | //解析json 106 | obj.Address = gjson.Get(json.Raw, "addrStr").String() 107 | obj.ConfirmBalance = gjson.Get(json.Raw, "balance").String() 108 | obj.UnconfirmBalance = gjson.Get(json.Raw, "unconfirmedBalance").String() 109 | u, _ := decimal.NewFromString(obj.ConfirmBalance) 110 | b, _ := decimal.NewFromString(obj.UnconfirmBalance) 111 | obj.Balance = u.Add(b).StringFixed(6) 112 | return &obj 113 | } 114 | -------------------------------------------------------------------------------- /openwtester/manager_test.go: -------------------------------------------------------------------------------- 1 | package openwtester 2 | 3 | import ( 4 | "github.com/blocktree/openwallet/v2/log" 5 | "github.com/blocktree/openwallet/v2/openw" 6 | "github.com/blocktree/openwallet/v2/openwallet" 7 | "path/filepath" 8 | "testing" 9 | ) 10 | 11 | var ( 12 | testApp = "assets-adapter" 13 | configFilePath = filepath.Join("conf") 14 | dbFilePath = filepath.Join("data", "db") 15 | dbFileName = "blockchain-trx.db" 16 | ) 17 | 18 | func testInitWalletManager() *openw.WalletManager { 19 | log.SetLogFuncCall(true) 20 | tc := openw.NewConfig() 21 | 22 | tc.ConfigDir = configFilePath 23 | tc.EnableBlockScan = false 24 | tc.SupportAssets = []string{ 25 | "TRX", 26 | } 27 | return openw.NewWalletManager(tc) 28 | //tm.Init() 29 | } 30 | 31 | func TestWalletManager_CreateWallet(t *testing.T) { 32 | tm := testInitWalletManager() 33 | w := &openwallet.Wallet{Alias: "HELLO TRX", IsTrust: true, Password: "12345678"} 34 | nw, key, err := tm.CreateWallet(testApp, w) 35 | if err != nil { 36 | log.Error(err) 37 | return 38 | } 39 | 40 | log.Info("wallet:", nw) 41 | log.Info("key:", key) 42 | 43 | } 44 | 45 | func TestWalletManager_GetWalletInfo(t *testing.T) { 46 | 47 | tm := testInitWalletManager() 48 | 49 | wallet, err := tm.GetWalletInfo(testApp, "W7tue6SDce38fPwerdKqyebUh6yo2nTQLC") 50 | if err != nil { 51 | log.Error("unexpected error:", err) 52 | return 53 | } 54 | log.Info("wallet:", wallet) 55 | } 56 | 57 | func TestWalletManager_GetWalletList(t *testing.T) { 58 | 59 | tm := testInitWalletManager() 60 | 61 | list, err := tm.GetWalletList(testApp, 0, 10000000) 62 | if err != nil { 63 | log.Error("unexpected error:", err) 64 | return 65 | } 66 | for i, w := range list { 67 | log.Info("wallet[", i, "] :", w) 68 | } 69 | log.Info("wallet count:", len(list)) 70 | 71 | tm.CloseDB(testApp) 72 | } 73 | 74 | func TestWalletManager_CreateAssetsAccount(t *testing.T) { 75 | 76 | tm := testInitWalletManager() 77 | 78 | walletID := "WLHdqGtGGZkBHEyXmv1w82s2iZjWJjgWF8" 79 | account := &openwallet.AssetsAccount{Alias: "feesSupport", WalletID: walletID, Required: 1, Symbol: "TRX", IsTrust: true} 80 | account, address, err := tm.CreateAssetsAccount(testApp, walletID, "12345678", account, nil) 81 | if err != nil { 82 | log.Error(err) 83 | return 84 | } 85 | 86 | log.Info("account:", account) 87 | log.Info("address:", address) 88 | 89 | tm.CloseDB(testApp) 90 | } 91 | 92 | func TestWalletManager_GetAssetsAccountList(t *testing.T) { 93 | 94 | tm := testInitWalletManager() 95 | 96 | walletID := "WLHdqGtGGZkBHEyXmv1w82s2iZjWJjgWF8" 97 | list, err := tm.GetAssetsAccountList(testApp, walletID, 0, 10000000) 98 | if err != nil { 99 | log.Error("unexpected error:", err) 100 | return 101 | } 102 | for i, w := range list { 103 | log.Info("account[", i, "] :", w) 104 | } 105 | log.Info("account count:", len(list)) 106 | 107 | tm.CloseDB(testApp) 108 | 109 | } 110 | 111 | func TestWalletManager_CreateAddress(t *testing.T) { 112 | 113 | tm := testInitWalletManager() 114 | 115 | walletID := "WLHdqGtGGZkBHEyXmv1w82s2iZjWJjgWF8" 116 | accountID := "C31rHUi8FJpwhWC2KTb5mMx9LUCSRpNnS1cG2QVMixYN" 117 | address, err := tm.CreateAddress(testApp, walletID, accountID, 1) 118 | if err != nil { 119 | log.Error(err) 120 | return 121 | } 122 | 123 | log.Info("address:", address) 124 | 125 | tm.CloseDB(testApp) 126 | } 127 | 128 | func TestWalletManager_GetAddressList(t *testing.T) { 129 | 130 | tm := testInitWalletManager() 131 | 132 | walletID := "WLHdqGtGGZkBHEyXmv1w82s2iZjWJjgWF8" 133 | accountID := "4pF3jRC2XokaaLZWiiLvxXrD8SKRYNuzcVCFkJdu6rkt" 134 | //accountID := "C31rHUi8FJpwhWC2KTb5mMx9LUCSRpNnS1cG2QVMixYN" 135 | list, err := tm.GetAddressList(testApp, walletID, accountID, 0, -1, false) 136 | if err != nil { 137 | log.Error("unexpected error:", err) 138 | return 139 | } 140 | for i, w := range list { 141 | log.Info("address[", i, "] :", w.Address) 142 | } 143 | log.Info("address count:", len(list)) 144 | 145 | tm.CloseDB(testApp) 146 | } 147 | -------------------------------------------------------------------------------- /tron/manager_addr.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The openwallet Authors 3 | * This file is part of the openwallet library. 4 | * 5 | * The openwallet library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The openwallet library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package tron 17 | 18 | import ( 19 | "errors" 20 | 21 | "github.com/imroc/req" 22 | ) 23 | 24 | // CreateAddress Done! 25 | // Function: Create address from a specified password string (NOT PRIVATE KEY) 26 | // Demo: curl -X POST http://127.0.0.1:8090/wallet/createaddress -d ‘ 27 | // {“value”: “7465737470617373776f7264” }’ 28 | // Parameters: 29 | // value is the password, converted from ascii to hex 30 | // Return value: 31 | // value is the corresponding address for the password, encoded in hex. 32 | // Convert it to base58 to use as the address. 33 | // Warning: 34 | // Please control risks when using this API. To ensure environmental security, please do not invoke APIs provided by other or invoke this very API on a public network. 35 | func (wm *WalletManager) CreateAddress(passValue string) (addr string, err error) { 36 | 37 | params := req.Param{"value": passValue} 38 | r, err := wm.WalletClient.Call("/wallet/createaddress", params) 39 | if err != nil { 40 | return "", err 41 | } 42 | 43 | base58checkAddress := r.Get("base58checkAddress").String() 44 | // addressHex := r.Get("value").String() 45 | 46 | return base58checkAddress, nil 47 | } 48 | 49 | // GenerateAddress Done! 50 | // Function: Generates a random private key and address pair 51 | // Demo:curl -X POST -k http://127.0.0.1:8090/wallet/generateaddress 52 | // Parameters: 53 | // no parameters. 54 | // Return value: 55 | // value is the corresponding address for the password, encoded in hex. 56 | // Convert it to base58 to use as the address. 57 | // Warning: 58 | // Please control risks when using this API. 59 | // To ensure environmental security, please do not invoke APIs provided by other or invoke this very API on a public network. 60 | func (wm *WalletManager) GenerateAddress() (address map[string]string, err error) { 61 | 62 | r, err := wm.WalletClient.Call("/wallet/generateaddress", nil) 63 | if err != nil { 64 | return nil, err 65 | } 66 | 67 | // type AddressPrKeyPairMessage struct { 68 | // Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` 69 | // PrivateKey string `protobuf:"bytes,2,opt,name=privateKey,proto3" json:"privateKey,omitempty"` 70 | // XXX_NoUnkeyedLiteral struct{} `json:"-"` 71 | // XXX_unrecognized []byte `json:"-"` 72 | // XXX_sizecache int32 `json:"-"` 73 | // } 74 | 75 | addr := r.Get("address").String() 76 | pKey := r.Get("privateKey").String() 77 | if addr == "" || pKey == "" { 78 | return nil, errors.New("GenerateAddress: Return none") 79 | } 80 | 81 | address = map[string]string{ 82 | "Address": addr, 83 | "PrivateKey": pKey, 84 | } 85 | return address, nil 86 | } 87 | 88 | // ValidateAddress Done! 89 | // Function:validate address 90 | // Demo: curl -X POST http://127.0.0.1:8090/wallet/validateaddress -d ‘ 91 | // {“address”: “4189139CB1387AF85E3D24E212A008AC974967E561”}’ 92 | // Parameters: 93 | // The address, should be in base58checksum, hexString or base64 format. 94 | // Return value: ture or false 95 | func (wm *WalletManager) ValidateAddress(address string) (err error) { 96 | 97 | params := req.Param{ 98 | "address": address, 99 | } 100 | r, err := wm.WalletClient.Call("/wallet/validateaddress", params) 101 | if err != nil { 102 | return err 103 | } 104 | if r.Get("result").Bool() != true { 105 | return errors.New("Invalid") 106 | } 107 | 108 | return nil 109 | } 110 | -------------------------------------------------------------------------------- /tron/manager_walletRef.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The openwallet Authors 3 | * This file is part of the openwallet library. 4 | * 5 | * The openwallet library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The openwallet library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package tron 17 | 18 | import ( 19 | "fmt" 20 | "path/filepath" 21 | 22 | "github.com/blocktree/openwallet/v2/common/file" 23 | "github.com/blocktree/openwallet/v2/hdkeystore" 24 | "github.com/blocktree/openwallet/v2/openwallet" 25 | "github.com/bndr/gotabulate" 26 | "github.com/btcsuite/btcutil/hdkeychain" 27 | ) 28 | 29 | //GetWallets 获取钱包列表 30 | func (wm *WalletManager) GetWallets() ([]*openwallet.Wallet, error) { 31 | 32 | wallets, err := openwallet.GetWalletsByKeyDir(wm.Config.keyDir) 33 | if err != nil { 34 | wm.Log.Info("get wallet by KeyDir failed;unexpected error:%v", err) 35 | return nil, err 36 | } 37 | 38 | for _, w := range wallets { 39 | w.DBFile = filepath.Join(wm.Config.dbPath, w.FileName()+".db") 40 | } 41 | 42 | return wallets, nil 43 | 44 | } 45 | 46 | //GetWalletInfo 获取钱包列表 47 | func (wm *WalletManager) GetWalletInfo(walletID string) (*openwallet.Wallet, error) { 48 | 49 | wallets, err := wm.GetWallets() 50 | if err != nil { 51 | wm.Log.Info("get wallet failed;unexpected error:%v", err) 52 | return nil, err 53 | } 54 | 55 | //获取钱包余额 56 | for _, w := range wallets { 57 | if w.WalletID == walletID { 58 | return w, nil 59 | } 60 | 61 | } 62 | 63 | return nil, fmt.Errorf("The wallet that your given name is not exist") 64 | } 65 | 66 | //CreateNewWallet 创建钱包 67 | func (wm *WalletManager) CreateNewWallet(name, password string) (*openwallet.Wallet, string, error) { 68 | 69 | var ( 70 | err error 71 | wallets []*openwallet.Wallet 72 | ) 73 | 74 | //检查钱包名是否存在 75 | wallets, err = wm.GetWallets() 76 | for _, w := range wallets { 77 | if w.Alias == name { 78 | return nil, "", fmt.Errorf("The wallet's alias is duplicated") 79 | } 80 | } 81 | 82 | seed, err := hdkeychain.GenerateSeed(32) 83 | if err != nil { 84 | wm.Log.Info("generate seed failed;unexpected error:%v", err) 85 | return nil, "", err 86 | } 87 | 88 | extSeed, err := hdkeystore.GetExtendSeed(seed, wm.Config.MasterKey) 89 | if err != nil { 90 | wm.Log.Info("get extend seed failed;unexpected error:%v", err) 91 | return nil, "", err 92 | } 93 | 94 | key, keyFile, err := hdkeystore.StoreHDKeyWithSeed(wm.Config.keyDir, name, password, extSeed, hdkeystore.StandardScryptN, hdkeystore.StandardScryptP) 95 | if err != nil { 96 | wm.Log.Info("store HDKey with seed failed;unexpected error:%v", err) 97 | return nil, "", err 98 | } 99 | 100 | file.MkdirAll(wm.Config.dbPath) 101 | file.MkdirAll(wm.Config.keyDir) 102 | 103 | w := &openwallet.Wallet{ 104 | WalletID: key.KeyID, 105 | Alias: key.Alias, 106 | KeyFile: keyFile, 107 | DBFile: filepath.Join(wm.Config.dbPath, key.FileName()+".db"), 108 | } 109 | 110 | w.SaveToDB() 111 | 112 | return w, keyFile, nil 113 | } 114 | 115 | // -------------------------------------------------- Functions --------------------------------------------- 116 | //打印钱包列表 117 | func (wm *WalletManager) printWalletList(list []*openwallet.Wallet) { 118 | 119 | tableInfo := make([][]interface{}, 0) 120 | 121 | for i, w := range list { 122 | a := w.SingleAssetsAccount(wm.Config.Symbol) 123 | // a.Balance = wm.GetWalletBalance(a.AccountID) ?500 124 | tableInfo = append(tableInfo, []interface{}{ 125 | i, a.WalletID, a.Alias, a.Balance, 126 | }) 127 | } 128 | 129 | t := gotabulate.Create(tableInfo) 130 | // Set Headers 131 | t.SetHeaders([]string{"No.", "ID", "Name", "Balance"}) 132 | 133 | //打印信息 134 | fmt.Println(t.Render("simple")) 135 | 136 | } 137 | -------------------------------------------------------------------------------- /tron/manager_witness.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The openwallet Authors 3 | * This file is part of the openwallet library. 4 | * 5 | * The openwallet library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The openwallet library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package tron 17 | 18 | // ListWitnesses Writing! 19 | // Function: 20 | // Query the list of Super Representatives 21 | // demo: 22 | // curl -X POSThttp://127.0.0.1:8090/wallet/listwitnesses 23 | // Parameters:None 24 | // Return value:List of all Super Representatives 25 | func (wm *WalletManager) ListWitnesses() (witnesses string, err error) { 26 | 27 | r, err := wm.WalletClient.Call("/wallet/listwitnesses", nil) 28 | if err != nil { 29 | return "", err 30 | } 31 | _ = r 32 | 33 | // // type WitnessList struct { 34 | // // Witnesses []*core.Witness `protobuf:"bytes,1,rep,name=witnesses,proto3" json:"witnesses,omitempty"` 35 | // // XXX_NoUnkeyedLiteral struct{} `json:"-"` 36 | // // XXX_unrecognized []byte `json:"-"` 37 | // // XXX_sizecache int32 `json:"-"` 38 | // // } 39 | // // type Witness struct { 40 | // // Address []byte `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` 41 | // // VoteCount int64 `protobuf:"varint,2,opt,name=voteCount,proto3" json:"voteCount,omitempty"` 42 | // // PubKey []byte `protobuf:"bytes,3,opt,name=pubKey,proto3" json:"pubKey,omitempty"` 43 | // // Url string `protobuf:"bytes,4,opt,name=url,proto3" json:"url,omitempty"` 44 | // // TotalProduced int64 `protobuf:"varint,5,opt,name=totalProduced,proto3" json:"totalProduced,omitempty"` 45 | // // TotalMissed int64 `protobuf:"varint,6,opt,name=totalMissed,proto3" json:"totalMissed,omitempty"` 46 | // // LatestBlockNum int64 `protobuf:"varint,7,opt,name=latestBlockNum,proto3" json:"latestBlockNum,omitempty"` 47 | // // LatestSlotNum int64 `protobuf:"varint,8,opt,name=latestSlotNum,proto3" json:"latestSlotNum,omitempty"` 48 | // // IsJobs bool `protobuf:"varint,9,opt,name=isJobs,proto3" json:"isJobs,omitempty"` 49 | // // XXX_NoUnkeyedLiteral struct{} `json:"-"` 50 | // // XXX_unrecognized []byte `json:"-"` 51 | // // XXX_sizecache int32 `json:"-"` 52 | // // } 53 | // witnesses = &api.WitnessList{} 54 | // if err := gjson.Unmarshal([]byte(r.Raw), witnesses); err != nil { 55 | // return nil, err 56 | // } 57 | 58 | return witnesses, nil 59 | } 60 | 61 | // ListNodes Writing! 62 | // Function: 63 | // List the nodes which the api fullnode is connecting on the network 64 | // demo: 65 | // curl -X POST http://127.0.0.1:8090/wallet/listnodes 66 | // Parameters:None 67 | // Return value:List of nodes 68 | func (wm *WalletManager) ListNodes() (nodes []string, err error) { 69 | 70 | r, err := wm.WalletClient.Call("/wallet/listnodes", nil) 71 | if err != nil { 72 | return nil, err 73 | } 74 | _ = r 75 | 76 | // // Gossip node list 77 | // // type NodeList struct { 78 | // // Nodes []*Node `protobuf:"bytes,1,rep,name=nodes,proto3" json:"nodes,omitempty"` 79 | // // XXX_NoUnkeyedLiteral struct{} `json:"-"` 80 | // // XXX_unrecognized []byte `json:"-"` 81 | // // XXX_sizecache int32 `json:"-"` 82 | // // } 83 | // // Gossip node 84 | // // type Node struct { 85 | // // Address *Address `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` 86 | // // XXX_NoUnkeyedLiteral struct{} `json:"-"` 87 | // // XXX_unrecognized []byte `json:"-"` 88 | // // XXX_sizecache int32 `json:"-"` 89 | // // } 90 | // // type Address struct { 91 | // // Host []byte `protobuf:"bytes,1,opt,name=host,proto3" json:"host,omitempty"` 92 | // // Port int32 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"` 93 | // // XXX_NoUnkeyedLiteral struct{} `json:"-"` 94 | // // XXX_unrecognized []byte `json:"-"` 95 | // // XXX_sizecache int32 `json:"-"` 96 | // // } 97 | // nodes = &api.NodeList{} 98 | // if err := gjson.Unmarshal([]byte(r.Raw), nodes); err != nil { 99 | // return nil, err 100 | // } 101 | 102 | return nodes, nil 103 | } 104 | -------------------------------------------------------------------------------- /openwtester/subscribe_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The openwallet Authors 3 | * This file is part of the openwallet library. 4 | * 5 | * The openwallet library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The openwallet library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package openwtester 17 | 18 | import ( 19 | "github.com/astaxie/beego/config" 20 | "github.com/blocktree/openwallet/v2/common/file" 21 | "github.com/blocktree/openwallet/v2/log" 22 | "github.com/blocktree/openwallet/v2/openw" 23 | "github.com/blocktree/openwallet/v2/openwallet" 24 | "path/filepath" 25 | "testing" 26 | ) 27 | 28 | ////////////////////////// 测试单个扫描器 ////////////////////////// 29 | 30 | type subscriberSingle struct { 31 | } 32 | 33 | //BlockScanNotify 新区块扫描完成通知 34 | func (sub *subscriberSingle) BlockScanNotify(header *openwallet.BlockHeader) error { 35 | log.Notice("header:", header) 36 | return nil 37 | } 38 | 39 | //BlockTxExtractDataNotify 区块提取结果通知 40 | func (sub *subscriberSingle) BlockExtractDataNotify(sourceKey string, data *openwallet.TxExtractData) error { 41 | log.Notice("account:", sourceKey) 42 | 43 | for i, input := range data.TxInputs { 44 | log.Std.Notice("data.TxInputs[%d]: %+v", i, input) 45 | } 46 | 47 | for i, output := range data.TxOutputs { 48 | log.Std.Notice("data.TxOutputs[%d]: %+v", i, output) 49 | } 50 | 51 | log.Std.Notice("data.Transaction: %+v", data.Transaction) 52 | 53 | return nil 54 | } 55 | 56 | //BlockExtractSmartContractDataNotify 区块提取智能合约交易结果通知 57 | func (sub *subscriberSingle) BlockExtractSmartContractDataNotify(sourceKey string, data *openwallet.SmartContractReceipt) error { 58 | 59 | log.Notice("sourceKey:", sourceKey) 60 | log.Std.Notice("data.ContractTransaction: %+v", data) 61 | 62 | for i, event := range data.Events { 63 | log.Std.Notice("data.Events[%d]: %+v", i, event) 64 | } 65 | 66 | return nil 67 | } 68 | 69 | func TestSubscribeAddress(t *testing.T) { 70 | 71 | var ( 72 | endRunning = make(chan bool, 1) 73 | symbol = "TRX" 74 | ) 75 | 76 | scanner := testBlockScanner(symbol) 77 | 78 | if scanner == nil { 79 | log.Error(symbol, "is not support block scan") 80 | return 81 | } 82 | scanner.SetBlockScanTargetFuncV2(testScanTargetFunc(symbol)) 83 | scanner.SetRescanBlockHeight(21335334) 84 | scanner.Run() 85 | 86 | <-endRunning 87 | 88 | } 89 | 90 | 91 | func testScanTargetFunc(symbol string) openwallet.BlockScanTargetFuncV2 { 92 | var ( 93 | addrs = make(map[string]openwallet.ScanTargetResult) 94 | ) 95 | 96 | //添加监听的外部地址 97 | addrs["TCYGCdTkY52bFNDLMMaNqYjwB6ELoLecSj"] = openwallet.ScanTargetResult{SourceKey: "sender", Exist: true} 98 | addrs["THpajU8dxwqQrpdDd49gtUxcHa12htsr27"] = openwallet.ScanTargetResult{SourceKey: "receiver", Exist: true} 99 | 100 | scanTargetFunc := func(target openwallet.ScanTargetParam) openwallet.ScanTargetResult { 101 | if target.ScanTargetType == openwallet.ScanTargetTypeAccountAddress { 102 | return addrs[target.ScanTarget] 103 | } 104 | return openwallet.ScanTargetResult{SourceKey: "", Exist: false, TargetInfo: nil,} 105 | } 106 | 107 | return scanTargetFunc 108 | } 109 | 110 | func testBlockScanner(symbol string) openwallet.BlockScanner { 111 | assetsMgr, err := openw.GetAssetsAdapter(symbol) 112 | if err != nil { 113 | log.Error(symbol, "is not support") 114 | return nil 115 | } 116 | 117 | //读取配置 118 | absFile := filepath.Join(configFilePath, symbol+".ini") 119 | 120 | c, err := config.NewConfig("ini", absFile) 121 | if err != nil { 122 | return nil 123 | } 124 | assetsMgr.LoadAssetsConfig(c) 125 | 126 | assetsLogger := assetsMgr.GetAssetsLogger() 127 | if assetsLogger != nil { 128 | assetsLogger.SetLogFuncCall(true) 129 | } 130 | 131 | //log.Debug("already got scanner:", assetsMgr) 132 | scanner := assetsMgr.GetBlockScanner() 133 | if scanner.SupportBlockchainDAI() { 134 | dbFilePath := filepath.Join("data", "db") 135 | dbFileName := "blockchain.db" 136 | file.MkdirAll(dbFilePath) 137 | dai, err := openwallet.NewBlockchainLocal(filepath.Join(dbFilePath, dbFileName), false) 138 | if err != nil { 139 | log.Error("NewBlockchainLocal err: %v", err) 140 | return nil 141 | } 142 | 143 | scanner.SetBlockchainDAI(dai) 144 | } 145 | sub := subscriberSingle{} 146 | scanner.AddObserver(&sub) 147 | 148 | return scanner 149 | } -------------------------------------------------------------------------------- /tron/blockscanner_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The openwallet Authors 3 | * This file is part of the openwallet library. 4 | * 5 | * The openwallet library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The openwallet library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package tron 17 | 18 | import ( 19 | "fmt" 20 | "github.com/blocktree/openwallet/v2/log" 21 | "github.com/golang/protobuf/proto" 22 | "github.com/golang/protobuf/ptypes/timestamp" 23 | "testing" 24 | ) 25 | 26 | func TestSetRescanBlockHeight(t *testing.T) { 27 | scanner := NewTronBlockScanner(tw) 28 | 29 | err := scanner.SetRescanBlockHeight(5114310) 30 | if err != nil { 31 | t.Errorf("SetRescanBlockHeight failed: %+v", err) 32 | } 33 | } 34 | 35 | func TestScanBlockTask(t *testing.T) { 36 | scanner := NewTronBlockScanner(tw) 37 | scanner.ScanBlockTask() 38 | } 39 | 40 | //func TestGetUnscanRecords(t *testing.T) { 41 | // list, err := tw.GetUnscanRecords() 42 | // if err != nil { 43 | // t.Errorf("GetUnscanRecords failed unexpected error: %v\n", err) 44 | // return 45 | // } 46 | // 47 | // for _, r := range list { 48 | // t.Logf("GetUnscanRecords unscan: %v", r) 49 | // } 50 | //} 51 | 52 | func TestTronBlockScanner_RescanFailedRecord(t *testing.T) { 53 | bs := NewTronBlockScanner(tw) 54 | bs.RescanFailedRecord() 55 | } 56 | 57 | func TestTronBlockScanner_scanning(t *testing.T) { 58 | 59 | //accountID := "WDHupMjR3cR2wm97iDtKajxSPCYEEddoek" 60 | //address := "miphUAzHHeM1VXGSFnw6owopsQW3jAQZAk" 61 | 62 | //wallet, err := tw.GetWalletInfo(accountID) 63 | //if err != nil { 64 | // t.Errorf("ONTBlockScanner_scanning failed unexpected error: %v\n", err) 65 | // return 66 | //} 67 | 68 | bs := NewTronBlockScanner(tw) 69 | 70 | //bs.DropRechargeRecords(accountID) 71 | 72 | bs.SetRescanBlockHeight(5650360) 73 | //tw.SaveLocalNewBlock(1355030, "00000000000000125b86abb80b1f94af13a5d9b07340076092eda92dade27686") 74 | 75 | //bs.AddAddress(address, accountID) 76 | 77 | bs.ScanBlockTask() 78 | } 79 | 80 | func TestTron_GetBalanceByAddress(t *testing.T) { 81 | bs := NewTronBlockScanner(tw) 82 | addr1 := "TLVtj8soinYhgwTnjVF7EpgbZRZ8Np5JNY" 83 | addr2 := "TRUd6CnUusLRFSnXbQXFkxohxymtgfHJZw" 84 | ret, err := bs.GetBalanceByAddress(addr1, addr2) 85 | if err != nil { 86 | fmt.Println("get balance error!!!") 87 | } else { 88 | fmt.Println("ret:", ret[0]) 89 | fmt.Println("ret:", ret[1]) 90 | } 91 | } 92 | 93 | func TestTron_GetScannedBlockHeight(t *testing.T) { 94 | bs := NewTronBlockScanner(tw) 95 | height := bs.GetScannedBlockHeight() 96 | fmt.Println("height:", height) 97 | } 98 | 99 | func TestTron_GetCurrentBlockHeader(t *testing.T) { 100 | bs := NewTronBlockScanner(tw) 101 | header, _ := bs.GetCurrentBlockHeader() 102 | fmt.Println("header:", header) 103 | } 104 | 105 | func TestTron_GetGlobalMaxBlockHeight(t *testing.T) { 106 | bs := NewTronBlockScanner(tw) 107 | maxBlockheight := bs.GetGlobalMaxBlockHeight() 108 | fmt.Println("maxBlockHeight:", maxBlockheight) 109 | } 110 | 111 | func TestTron_GetTransaction(t *testing.T) { 112 | bs := NewTronBlockScanner(tw) 113 | txID := "75efe562e9f2df41c1d38ed33845483e9d6a899fa53f7453c297753d6d5c7f95" 114 | height := uint64(21275089) 115 | tx, err := bs.wm.GetTransaction(txID, "", height, 0) 116 | if err != nil { 117 | fmt.Println("get transaction failed!!!") 118 | } else { 119 | fmt.Println("txFrom:=", tx) 120 | } 121 | } 122 | 123 | func TestDemo(t *testing.T) { 124 | name := proto.MessageName(×tamp.Timestamp{}) 125 | log.Infof("Message name of timestamp: %s", name) 126 | } 127 | 128 | func TestTron_RescanFailedRecord(t *testing.T) { 129 | bs := NewTronBlockScanner(tw) 130 | bs.RescanFailedRecord() 131 | } 132 | 133 | //func TestTron_GetUnscanRecords(t *testing.T) { 134 | // list, err := tw.GetUnscanRecords() 135 | // if err != nil { 136 | // t.Errorf("GetUnscanRecords failed unexpected error: %v\n", err) 137 | // return 138 | // } 139 | // 140 | // for _, r := range list { 141 | // t.Logf("GetUnscanRecords unscan: %v", r) 142 | // } 143 | //} 144 | 145 | func TestBTCBlockScanner_ScanBlock(t *testing.T) { 146 | 147 | //accountID := "WDHupMjR3cR2wm97iDtKajxSPCYEEddoek" 148 | //address := "msnYsBdBXQZqYYqNNJZsjShzwCx9fJVSin" 149 | 150 | bs := tw.Blockscanner 151 | //bs.AddAddress(address, accountID) 152 | bs.ScanBlock(5628677) 153 | } 154 | -------------------------------------------------------------------------------- /tron/contract_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The OpenWallet Authors 3 | * This file is part of the OpenWallet library. 4 | * 5 | * The OpenWallet library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The OpenWallet library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package tron 17 | 18 | import ( 19 | "encoding/hex" 20 | "fmt" 21 | "github.com/blocktree/openwallet/v2/log" 22 | "github.com/blocktree/openwallet/v2/openwallet" 23 | "math/big" 24 | "testing" 25 | ) 26 | 27 | func TestWalletManager_TriggerSmartContract(t *testing.T) { 28 | 29 | contractAddr := "417EA07B5BE5A0FE26A64ACAF451C8D8653FDB56B6" 30 | function := "balanceOf(address)" 31 | tokenOwner := "41EFB6D8A02F4B639605D71FF8DC78C97329759D70" 32 | param, err := makeTransactionParameter("", []SolidityParam{ 33 | SolidityParam{ 34 | SOLIDITY_TYPE_ADDRESS, 35 | tokenOwner, 36 | }, 37 | }) 38 | //ownerAddr := "41BAF6BB7DE44E427FA11CE85EE59843E4DEFA114E" 39 | if err != nil { 40 | t.Errorf("makeTransactionParameter failed: %v\n", err) 41 | return 42 | } 43 | 44 | tx, err := tw.TriggerSmartContract(contractAddr, function, param, 100000, 0, tokenOwner) 45 | if err != nil { 46 | t.Errorf("TriggerSmartContract failed: %v\n", err) 47 | return 48 | } 49 | log.Infof("TriggerSmartContract: %+v", tx) 50 | } 51 | 52 | func TestTRC20TransferData(t *testing.T) { 53 | 54 | toAddrHex := "41EFB6D8A02F4B639605D71FF8DC78C97329759D70" 55 | amount := big.NewInt(1199900000000) 56 | 57 | var funcParams []SolidityParam 58 | funcParams = append(funcParams, SolidityParam{ 59 | ParamType: SOLIDITY_TYPE_ADDRESS, 60 | ParamValue: toAddrHex, 61 | }) 62 | 63 | funcParams = append(funcParams, SolidityParam{ 64 | ParamType: SOLIDITY_TYPE_UINT256, 65 | ParamValue: amount, 66 | }) 67 | 68 | //fmt.Println("make token transfer data, amount:", amount.String()) 69 | dataHex, err := makeTransactionParameter(TRC20_TRANSFER_METHOD_ID, funcParams) 70 | if err != nil { 71 | t.Errorf("makeTransactionParameter failed: %v\n", err) 72 | return 73 | } 74 | log.Infof("makeTransactionParameter: %+v", dataHex) 75 | 76 | contractAddr := "417EA07B5BE5A0FE26A64ACAF451C8D8653FDB56B6" 77 | function := "transfer(address,uint256)" 78 | tokenOwner := "411561161E6AFF4A66BA660651D8E61428C50C57B8" 79 | if err != nil { 80 | t.Errorf("makeTransactionParameter failed: %v\n", err) 81 | return 82 | } 83 | 84 | triggHex, err := makeTransactionParameter("", funcParams) 85 | if err != nil { 86 | t.Errorf("makeTransactionParameter failed: %v\n", err) 87 | return 88 | } 89 | 90 | tx, err := tw.TriggerSmartContract(contractAddr, function, triggHex, 10000000, 0, tokenOwner) 91 | if err != nil { 92 | t.Errorf("TriggerSmartContract failed: %v\n", err) 93 | return 94 | } 95 | log.Infof("TriggerSmartContract: %+v", tx) 96 | } 97 | 98 | func TestWalletManager_GetContract(t *testing.T) { 99 | r, err := tw.GetContractInfo("THvZvKPLHKLJhEFYKiyqj6j8G8nGgfg7ur") 100 | if err != nil { 101 | t.Errorf("GetContract failed: %v\n", err) 102 | return 103 | } 104 | log.Infof("GetContract: %+v", r) 105 | } 106 | 107 | func TestWalletManager_GetTRC20Balance(t *testing.T) { 108 | 109 | balance, err := tw.GetTRC20Balance( 110 | "TXphYHMUvT2ptHt8QtQb5i9T9DWUtfBWha", 111 | "TMWkPhsb1dnkAVNy8ej53KrFNGWy9BJrfu") 112 | if err != nil { 113 | t.Errorf("GetTRC20Balance failed: %v\n", err) 114 | return 115 | } 116 | log.Infof("balance: %+v", balance) 117 | } 118 | 119 | func TestWalletManager_GetTRC10Balance(t *testing.T) { 120 | 121 | balance, err := tw.GetTRC10Balance( 122 | "TXphYHMUvT2ptHt8QtQb5i9T9DWUtfBWha", 123 | "1002000") 124 | if err != nil { 125 | t.Errorf("GetTRC10Balance failed: %v\n", err) 126 | return 127 | } 128 | log.Infof("balance: %+v", balance) 129 | } 130 | 131 | func TestWalletManager_GetTokenBalanceByAddress(t *testing.T) { 132 | 133 | trc10Contract := openwallet.SmartContract{ 134 | Address: "1002000", 135 | Protocol: TRC10, 136 | Decimals: 6, 137 | } 138 | 139 | balance10, err := tw.ContractDecoder.GetTokenBalanceByAddress( 140 | trc10Contract, 141 | "TXphYHMUvT2ptHt8QtQb5i9T9DWUtfBWha") 142 | if err != nil { 143 | t.Errorf("GetTRC10Balance failed: %v\n", err) 144 | return 145 | } 146 | log.Infof("GetTRC10Balance: %+v", balance10[0].Balance) 147 | 148 | trc20Contract := openwallet.SmartContract{ 149 | Address: "TMWkPhsb1dnkAVNy8ej53KrFNGWy9BJrfu", 150 | Protocol: TRC20, 151 | Decimals: 6, 152 | } 153 | 154 | balance20, err := tw.ContractDecoder.GetTokenBalanceByAddress( 155 | trc20Contract, 156 | "TXphYHMUvT2ptHt8QtQb5i9T9DWUtfBWha") 157 | if err != nil { 158 | t.Errorf("GetTRC20Balance failed: %v\n", err) 159 | return 160 | } 161 | log.Infof("GetTRC20Balance: %+v", balance20[0].Balance) 162 | } 163 | 164 | func TestEncodeName(t *testing.T) { 165 | nameBytes, _ := hex.DecodeString("636c617373206f72672e74726f6e2e636f72652e766d2e70726f6772616d2e50726f6772616d244f75744f6654696d65457863657074696f6e203a204350552074696d656f757420666f7220274a554d504445535427206f7065726174696f6e20657865637574696e67") 166 | fmt.Println(string(nameBytes)) 167 | } 168 | 169 | func TestParseTransferEvent(t *testing.T) { 170 | data := "a9059cbb0000000000000000000000415bdf283199369adb124f39dda845ae02c5d3eb5d0000000000000000000000000000000000000000000000000000000001312d00" 171 | to, amount, err := ParseTransferEvent(data) 172 | if err != nil { 173 | t.Errorf("ParseTransferEvent failed: %v\n", err) 174 | return 175 | } 176 | log.Infof("%s: %d", to, amount) 177 | } 178 | -------------------------------------------------------------------------------- /openwtester/transaction_manager_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The openwallet Authors 3 | * This file is part of the openwallet library. 4 | * 5 | * The openwallet library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The openwallet library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package openwtester 17 | 18 | import ( 19 | "github.com/astaxie/beego/config" 20 | "github.com/blocktree/openwallet/v2/openw" 21 | "path/filepath" 22 | "testing" 23 | 24 | "github.com/blocktree/openwallet/v2/log" 25 | "github.com/blocktree/openwallet/v2/openwallet" 26 | ) 27 | 28 | func TestWalletManager_GetTransactions(t *testing.T) { 29 | tm := testInitWalletManager() 30 | list, err := tm.GetTransactions(testApp, 0, -1, "Received", false) 31 | if err != nil { 32 | log.Error("GetTransactions failed, unexpected error:", err) 33 | return 34 | } 35 | for i, tx := range list { 36 | log.Info("trx[", i, "] :", tx) 37 | } 38 | log.Info("trx count:", len(list)) 39 | } 40 | 41 | func TestWalletManager_GetTxUnspent(t *testing.T) { 42 | tm := testInitWalletManager() 43 | list, err := tm.GetTxUnspent(testApp, 0, -1, "Received", false) 44 | if err != nil { 45 | log.Error("GetTxUnspent failed, unexpected error:", err) 46 | return 47 | } 48 | for i, tx := range list { 49 | log.Info("Unspent[", i, "] :", tx) 50 | } 51 | log.Info("Unspent count:", len(list)) 52 | } 53 | 54 | func TestWalletManager_GetTxSpent(t *testing.T) { 55 | tm := testInitWalletManager() 56 | list, err := tm.GetTxSpent(testApp, 0, -1, "Received", false) 57 | if err != nil { 58 | log.Error("GetTxSpent failed, unexpected error:", err) 59 | return 60 | } 61 | for i, tx := range list { 62 | log.Info("Spent[", i, "] :", tx) 63 | } 64 | log.Info("Spent count:", len(list)) 65 | } 66 | 67 | func TestWalletManager_ExtractUTXO(t *testing.T) { 68 | tm := testInitWalletManager() 69 | unspent, err := tm.GetTxUnspent(testApp, 0, -1, "Received", false) 70 | if err != nil { 71 | log.Error("GetTxUnspent failed, unexpected error:", err) 72 | return 73 | } 74 | for i, tx := range unspent { 75 | 76 | _, err := tm.GetTxSpent(testApp, 0, -1, "SourceTxID", tx.TxID, "SourceIndex", tx.Index) 77 | if err == nil { 78 | continue 79 | } 80 | 81 | log.Info("ExtractUTXO[", i, "] :", tx) 82 | } 83 | 84 | } 85 | 86 | func TestWalletManager_GetTransactionByWxID(t *testing.T) { 87 | tm := testInitWalletManager() 88 | wxID := openwallet.GenTransactionWxID(&openwallet.Transaction{ 89 | TxID: "bfa6febb33c8ddde9f7f7b4d93043956cce7e0f4e95da259a78dc9068d178fee", 90 | Coin: openwallet.Coin{ 91 | Symbol: "LTC", 92 | IsContract: false, 93 | ContractID: "", 94 | }, 95 | }) 96 | log.Info("wxID:", wxID) 97 | //"D0+rxcKSqEsFMfGesVzBdf6RloM=" 98 | tx, err := tm.GetTransactionByWxID(testApp, wxID) 99 | if err != nil { 100 | log.Error("GetTransactionByTxID failed, unexpected error:", err) 101 | return 102 | } 103 | log.Info("tx:", tx) 104 | } 105 | 106 | func TestWalletManager_GetAssetsAccountBalance(t *testing.T) { 107 | tm := testInitWalletManager() 108 | walletID := "WGVsUfTTVaCwAMRTqeJiDQsZ3vrWp9DzMA" 109 | accountID := "4pF3jRC2XokaaLZWiiLvxXrD8SKRYNuzcVCFkJdu6rkt" 110 | 111 | balance, err := tm.GetAssetsAccountBalance(testApp, walletID, accountID) 112 | if err != nil { 113 | log.Error("GetAssetsAccountBalance failed, unexpected error:", err) 114 | return 115 | } 116 | log.Info("balance:", balance) 117 | } 118 | 119 | func TestWalletManager_GetAssetsAccountTokenBalance(t *testing.T) { 120 | tm := testInitWalletManager() 121 | walletID := "WGVsUfTTVaCwAMRTqeJiDQsZ3vrWp9DzMA" 122 | accountID := "4pF3jRC2XokaaLZWiiLvxXrD8SKRYNuzcVCFkJdu6rkt" 123 | 124 | //contract := openwallet.SmartContract{ 125 | // Address: "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", 126 | // Symbol: "TRX", 127 | // Name: "Tether USD", 128 | // Token: "USDT", 129 | // Decimals: 6, 130 | // Protocol: "trc20", 131 | //} 132 | 133 | contract := openwallet.SmartContract{ 134 | Address: "THvZvKPLHKLJhEFYKiyqj6j8G8nGgfg7ur", 135 | Symbol: "TRX", 136 | Name: "TRONdice", 137 | Token: "DICE", 138 | Decimals: 6, 139 | Protocol: "trc20", 140 | } 141 | 142 | //contract := openwallet.SmartContract{ 143 | // Address: "1002000", 144 | // Symbol: "TRX", 145 | // Name: "BitTorrent", 146 | // Token: "BTT", 147 | // Decimals: 0, 148 | // Protocol: "trc10", 149 | //} 150 | 151 | balance, err := tm.GetAssetsAccountTokenBalance(testApp, walletID, accountID, contract) 152 | if err != nil { 153 | log.Error("GetAssetsAccountTokenBalance failed, unexpected error:", err) 154 | return 155 | } 156 | log.Info("balance:", balance.Balance) 157 | } 158 | 159 | func TestWalletManager_GetEstimateFeeRate(t *testing.T) { 160 | tm := testInitWalletManager() 161 | coin := openwallet.Coin{ 162 | Symbol: "VSYS", 163 | } 164 | feeRate, unit, err := tm.GetEstimateFeeRate(coin) 165 | if err != nil { 166 | log.Error("GetEstimateFeeRate failed, unexpected error:", err) 167 | return 168 | } 169 | log.Std.Info("feeRate: %s %s/%s", feeRate, coin.Symbol, unit) 170 | } 171 | 172 | func TestGetAddressBalance(t *testing.T) { 173 | symbol := "VSYS" 174 | assetsMgr, err := openw.GetAssetsAdapter(symbol) 175 | if err != nil { 176 | log.Error(symbol, "is not support") 177 | return 178 | } 179 | //读取配置 180 | absFile := filepath.Join(configFilePath, symbol+".ini") 181 | 182 | c, err := config.NewConfig("ini", absFile) 183 | if err != nil { 184 | return 185 | } 186 | assetsMgr.LoadAssetsConfig(c) 187 | bs := assetsMgr.GetBlockScanner() 188 | 189 | addrs := []string{ 190 | "AR5D3fGVWDz32wWCnVbwstsMW8fKtWdzNFT", 191 | "AR9qbgbsmLh3ADSU9ngR22J2HpD5D9ncTCg", 192 | "ARAA8AnUYa4kWwWkiZTTyztG5C6S9MFTx11", 193 | "ARCUYWyLvGDTrhZ6K9jjMh9B5iRVEf3vRzs", 194 | "ARGehumz77nGcfkQrPjK4WUyNevvU9NCNqQ", 195 | "ARJdaB9Fo6Sk2nxBrQP2p4woWotPxjaebCv", 196 | } 197 | 198 | balances, err := bs.GetBalanceByAddress(addrs...) 199 | if err != nil { 200 | log.Errorf(err.Error()) 201 | return 202 | } 203 | for _, b := range balances { 204 | log.Infof("balance[%s] = %s", b.Address, b.Balance) 205 | log.Infof("UnconfirmBalance[%s] = %s", b.Address, b.UnconfirmBalance) 206 | log.Infof("ConfirmBalance[%s] = %s", b.Address, b.ConfirmBalance) 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /tron/blockscanner_db.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The openwallet Authors 3 | * This file is part of the openwallet library. 4 | * 5 | * The openwallet library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The openwallet library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package tron 17 | 18 | import ( 19 | "fmt" 20 | "github.com/blocktree/openwallet/v2/openwallet" 21 | ) 22 | 23 | // //GetCurrentBlockHeader 获取当前区块高度 24 | // func (bs *TronBlockScanner) GetCurrentBlockHeader() (*openwallet.BlockHeader, error) { 25 | 26 | // var ( 27 | // block *core.Block 28 | // blockHeight uint64 = 0 29 | // hash string 30 | // err error 31 | // ) 32 | 33 | // blockHeight, hash = bs.GetLocalNewBlock() 34 | 35 | // //如果本地没有记录,查询接口的高度 36 | // if blockHeight == 0 { 37 | // block, hash, err = bs.wm.GetNowBlock() 38 | // if err != nil { 39 | // return nil, err 40 | // } 41 | // blockHeight = uint64(block.GetBlockHeader().GetRawData().GetNumber()) 42 | // } 43 | 44 | // return &openwallet.BlockHeader{Height: blockHeight, Hash: hash}, nil 45 | // } 46 | 47 | //GetLocalNewBlock 获取本地记录的区块高度和hash 48 | func (bs *TronBlockScanner) GetLocalNewBlock() (uint64, string, error) { 49 | 50 | //var ( 51 | // blockHeight uint64 52 | // blockHash string 53 | //) 54 | // 55 | ////获取本地区块高度 56 | //db, err := storm.Open(filepath.Join(bs.wm.Config.dbPath, bs.wm.Config.BlockchainFile)) 57 | //if err != nil { 58 | // return 0, "" 59 | //} 60 | //defer db.Close() 61 | // 62 | //db.Get(blockchainBucket, "blockHeight", &blockHeight) 63 | //db.Get(blockchainBucket, "blockHash", &blockHash) 64 | // 65 | //return blockHeight, blockHash 66 | 67 | if bs.BlockchainDAI == nil { 68 | return 0, "", fmt.Errorf("Blockchain DAI is not setup ") 69 | } 70 | 71 | header, err := bs.BlockchainDAI.GetCurrentBlockHead(bs.wm.Symbol()) 72 | if err != nil { 73 | return 0, "", err 74 | } 75 | 76 | return header.Height, header.Hash, nil 77 | } 78 | 79 | //GetLocalBlock 获取本地区块数据 80 | func (bs *TronBlockScanner) GetLocalBlock(height uint64) (*Block, error) { 81 | 82 | //var ( 83 | // block Block 84 | //) 85 | // 86 | //db, err := storm.Open(filepath.Join(bs.wm.Config.dbPath, bs.wm.Config.BlockchainFile)) 87 | //if err != nil { 88 | // return nil, err 89 | //} 90 | //defer db.Close() 91 | // 92 | //err = db.One("Height", height, &block) 93 | //if err != nil { 94 | // return nil, err 95 | //} 96 | // 97 | //return &block, nil 98 | 99 | if bs.BlockchainDAI == nil { 100 | return nil, fmt.Errorf("Blockchain DAI is not setup ") 101 | } 102 | 103 | header, err := bs.BlockchainDAI.GetLocalBlockHeadByHeight(height, bs.wm.Symbol()) 104 | if err != nil { 105 | return nil, err 106 | } 107 | 108 | block := &Block{ 109 | Hash: header.Hash, 110 | Height: header.Height, 111 | } 112 | 113 | return block, nil 114 | } 115 | 116 | //SaveUnscanRecord 保存交易记录到钱包数据库 117 | func (bs *TronBlockScanner) SaveUnscanRecord(record *openwallet.UnscanRecord) error { 118 | 119 | //if record == nil { 120 | // return errors.New("the unscan record to save is nil") 121 | //} 122 | // 123 | ////if record.BlockHeight == 0 { 124 | //// return errors.New("unconfirmed transaction do not rescan") 125 | ////} 126 | // 127 | ////获取本地区块高度 128 | //db, err := storm.Open(filepath.Join(bs.wm.Config.dbPath, bs.wm.Config.BlockchainFile)) 129 | //if err != nil { 130 | // return err 131 | //} 132 | //defer db.Close() 133 | // 134 | //return db.Save(record) 135 | 136 | if bs.BlockchainDAI == nil { 137 | return fmt.Errorf("Blockchain DAI is not setup ") 138 | } 139 | 140 | return bs.BlockchainDAI.SaveUnscanRecord(record) 141 | } 142 | 143 | //SaveLocalNewBlock 记录区块高度和hash到本地 144 | func (bs *TronBlockScanner) SaveLocalNewBlock(blockHeight uint64, blockHash string) error { 145 | 146 | //获取本地区块高度 147 | //db, err := storm.Open(filepath.Join(bs.wm.Config.dbPath, bs.wm.Config.BlockchainFile)) 148 | //if err != nil { 149 | // return 150 | //} 151 | //defer db.Close() 152 | // 153 | //db.Set(blockchainBucket, "blockHeight", &blockHeight) 154 | //db.Set(blockchainBucket, "blockHash", &blockHash) 155 | // 156 | //if bs.BlockchainDAI == nil { 157 | // return fmt.Errorf("Blockchain DAI is not setup ") 158 | //} 159 | 160 | header := &openwallet.BlockHeader{ 161 | Hash: blockHash, 162 | Height: blockHeight, 163 | Fork: false, 164 | Symbol: bs.wm.Symbol(), 165 | } 166 | 167 | return bs.BlockchainDAI.SaveCurrentBlockHead(header) 168 | } 169 | 170 | //SaveLocalBlock 记录本地新区块 171 | func (bs *TronBlockScanner) SaveLocalBlock(block *Block) error { 172 | 173 | //db, err := storm.Open(filepath.Join(bs.wm.Config.dbPath, bs.wm.Config.BlockchainFile)) 174 | //if err != nil { 175 | // return 176 | //} 177 | //defer db.Close() 178 | // 179 | //db.Save(block) 180 | 181 | if bs.BlockchainDAI == nil { 182 | return fmt.Errorf("Blockchain DAI is not setup ") 183 | } 184 | 185 | header := &openwallet.BlockHeader{ 186 | Hash: block.Hash, 187 | Merkleroot: "", 188 | Previousblockhash: block.Previousblockhash, 189 | Height: block.Height, 190 | Time: uint64(block.Time), 191 | Symbol: bs.wm.Symbol(), 192 | } 193 | 194 | return bs.BlockchainDAI.SaveLocalBlockHead(header) 195 | } 196 | 197 | //DeleteUnscanRecord 删除指定高度的未扫记录 198 | func (bs *TronBlockScanner) DeleteUnscanRecord(height uint64) error { 199 | ////获取本地区块高度 200 | //db, err := storm.Open(filepath.Join(bs.wm.Config.dbPath, bs.wm.Config.BlockchainFile)) 201 | //if err != nil { 202 | // return err 203 | //} 204 | //defer db.Close() 205 | // 206 | //var list []*UnscanRecord 207 | //err = db.Find("BlockHeight", height, &list) 208 | //if err != nil { 209 | // return err 210 | //} 211 | // 212 | //for _, r := range list { 213 | // db.DeleteStruct(r) 214 | //} 215 | // 216 | //return nil 217 | 218 | if bs.BlockchainDAI == nil { 219 | return fmt.Errorf("Blockchain DAI is not setup ") 220 | } 221 | 222 | return bs.BlockchainDAI.DeleteUnscanRecordByHeight(height, bs.wm.Symbol()) 223 | } 224 | 225 | func (bs *TronBlockScanner) GetUnscanRecords() ([]*openwallet.UnscanRecord, error) { 226 | 227 | if bs.BlockchainDAI == nil { 228 | return nil, fmt.Errorf("Blockchain DAI is not setup ") 229 | } 230 | 231 | return bs.BlockchainDAI.GetUnscanRecords(bs.wm.Symbol()) 232 | } 233 | -------------------------------------------------------------------------------- /tron/manager_block.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The openwallet Authors 3 | * This file is part of the openwallet library. 4 | * 5 | * The openwallet library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The openwallet library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package tron 17 | 18 | import ( 19 | "errors" 20 | "fmt" 21 | "time" 22 | 23 | "github.com/imroc/req" 24 | ) 25 | 26 | func (wm *WalletManager) GetCurrentBlock() (block *Block, err error) { 27 | r, err := wm.WalletClient.Call("/wallet/getnowblock", nil) 28 | if err != nil { 29 | return nil, err 30 | } 31 | block = NewBlock(r, wm.Config.IsTestNet) 32 | if block.GetBlockHashID() == "" || block.GetHeight() <= 0 { 33 | return nil, errors.New("GetNowBlock failed: No found ") 34 | } 35 | return block, nil 36 | } 37 | 38 | // GetNowBlock Done! 39 | // Function:Query the latest block 40 | // demo: curl -X POST http://127.0.0.1:8090/wallet/getnowblock 41 | // Parameters:None 42 | // Return value:Latest block on full node 43 | func (wm *WalletManager) GetNowBlock() (block *Block, err error) { 44 | 45 | r, err := wm.WalletClient.Call("/wallet/getnowblock", nil) 46 | if err != nil { 47 | return nil, err 48 | } 49 | 50 | block = NewBlock(r, wm.Config.IsTestNet) 51 | if block.GetBlockHashID() == "" || block.GetHeight() <= 0 { 52 | return nil, errors.New("GetNowBlock failed: No found ") 53 | } 54 | 55 | // Check for TX 56 | currstamp := time.Now().UnixNano() / (1000 * 1000) // Unit: ms 57 | timestamp := int64(block.Time) 58 | //if timestamp < currstamp-(5*1000) { 59 | // wm.Log.Warningf(fmt.Sprintf("Get block timestamp: %d [%+v]", timestamp, time.Unix(timestamp/1000, 0))) 60 | // wm.Log.Warningf(fmt.Sprintf("Current d timestamp: %d [%+v]", currstamp, time.Unix(currstamp/1000, 0))) 61 | // wm.Log.Warningf("Diff seconds: %ds ", (currstamp-timestamp)/1000) 62 | //} 63 | if timestamp < currstamp-(5*60*1000) { 64 | wm.Log.Error(fmt.Sprintf("Get block timestamp: %d [%+v]", timestamp, time.Unix(timestamp/1000, 0))) 65 | // wm.Log.Error(fmt.Sprintf("Current d timestamp: %d [%+v]", currstamp, time.Unix(currstamp/1000, 0))) 66 | wm.Log.Error(fmt.Sprintf("Now block height: %d", block.GetHeight())) 67 | return nil, errors.New("GetNowBlock returns with unsynced") 68 | } 69 | 70 | return block, nil 71 | } 72 | 73 | // GetBlockByNum Done! 74 | // Function:Query block by height 75 | // demo: curl -X POST http://127.0.0.1:8090/wallet/getblockbynum -d ‘ 76 | // {“num” : 100}’ 77 | // Parameters: 78 | // Num is the height of the block 79 | // Return value:specified Block object 80 | func (wm *WalletManager) GetBlockByNum(num uint64) (block *Block, error error) { 81 | 82 | r, err := wm.WalletClient.Call("/wallet/getblockbynum", req.Param{"num": num}) 83 | if err != nil { 84 | return nil, err 85 | } 86 | block = NewBlock(r, wm.Config.IsTestNet) 87 | if block.GetBlockHashID() == "" || block.GetHeight() <= 0 { 88 | return nil, errors.New("GetBlockByNum failed: No found ") 89 | } 90 | 91 | return block, nil 92 | } 93 | 94 | // GetBlockByID Done! 95 | // Function:Query block by ID 96 | // demo: curl -X POST http://127.0.0.1:8090/wallet/getblockbyid -d ‘ 97 | // {“value”: “0000000000038809c59ee8409a3b6c051e369ef1096603c7ee723c16e2376c73”}’ 98 | // Parameters:Block ID. 99 | // Return value:Block Object 100 | func (wm *WalletManager) GetBlockByID(blockID string) (block *Block, err error) { 101 | 102 | r, err := wm.WalletClient.Call("/wallet/getblockbyid", req.Param{"value": blockID}) 103 | if err != nil { 104 | return nil, err 105 | } 106 | 107 | block = NewBlock(r, wm.Config.IsTestNet) 108 | if block.GetBlockHashID() == "" || block.GetHeight() <= 0 { 109 | return nil, errors.New("GetBlockByID failed: No found ") 110 | } 111 | 112 | return block, nil 113 | } 114 | 115 | // GetBlockByLimitNext Done! 116 | // Function:Query a range of blocks by block height 117 | // demo: curl -X POST http://127.0.0.1:8090/wallet/getblockbylimitnext -d ‘ 118 | // {“startNum”: 1, “endNum”: 2}’ 119 | // Parameters: 120 | // startNum:Starting block height, including this block 121 | // endNum:Ending block height, excluding that block 122 | // Return value:A list of Block Objects 123 | func (wm *WalletManager) GetBlockByLimitNext(startNum, endNum uint64) (blocks []*Block, err error) { 124 | 125 | params := req.Param{ 126 | "startNum": startNum, 127 | "endNum": endNum, 128 | } 129 | 130 | r, err := wm.WalletClient.Call("/wallet/getblockbylimitnext", params) 131 | if err != nil { 132 | return nil, err 133 | } 134 | 135 | blocks = []*Block{} 136 | for _, raw := range r.Get("block").Array() { 137 | b := NewBlock(&raw, wm.Config.IsTestNet) 138 | blocks = append(blocks, b) 139 | } 140 | 141 | return blocks, nil 142 | } 143 | 144 | // GetBlockByLatestNum Done! 145 | // Function:Query the latest blocks 146 | // demo: curl -X POST http://127.0.0.1:8090/wallet/getblockbylatestnum -d ‘ 147 | // {“num”: 5}’ 148 | // Parameters:The number of blocks to query 149 | // Return value:A list of Block Objects 150 | func (wm *WalletManager) GetBlockByLatestNum(num uint64) (blocks []*Block, err error) { 151 | 152 | if num >= 1000 { 153 | return nil, errors.New("Too large with parameter num to search") 154 | } 155 | 156 | r, err := wm.WalletClient.Call("/wallet/getblockbylatestnum", req.Param{"num": num}) 157 | if err != nil { 158 | return nil, err 159 | } 160 | 161 | // blocks = &api.BlockList{} 162 | // if err := gjson.Unmarshal(r, blocks); err != nil { 163 | // return nil, err 164 | // } 165 | blocks = []*Block{} 166 | for _, raw := range r.Get("block").Array() { 167 | b := NewBlock(&raw, wm.Config.IsTestNet) 168 | blocks = append(blocks, b) 169 | } 170 | 171 | return blocks, nil 172 | } 173 | 174 | // ----------------------------------- Functions ----------------------------------------------- 175 | func printBlock(block *Block) { 176 | if block == nil { 177 | fmt.Println("Block == nil") 178 | } 179 | 180 | fmt.Println("\nvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv") 181 | fmt.Println("Transactions:") 182 | for i, tx := range block.GetTransactions() { 183 | fmt.Printf("\t tx%2d: IsSuccess=%v \t\n", i+1, true, "", tx.BlockHeight, tx.BlockHash, "", "") 184 | } 185 | 186 | fmt.Println("Block Header:") 187 | if block != nil { 188 | fmt.Printf("\tRawData: \n", block.GetHeight(), time.Unix(int64(block.Time)/1000, 0), block.Previousblockhash) 189 | } 190 | 191 | fmt.Println("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^") 192 | } 193 | -------------------------------------------------------------------------------- /tron/config.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The openwallet Authors 3 | * This file is part of the openwallet library. 4 | * 5 | * The openwallet library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The openwallet library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package tron 17 | 18 | import ( 19 | "fmt" 20 | "path/filepath" 21 | "strings" 22 | "time" 23 | 24 | owcrypt "github.com/blocktree/go-owcrypt" 25 | "github.com/blocktree/openwallet/v2/common/file" 26 | "github.com/shopspring/decimal" 27 | ) 28 | 29 | /* 30 | 工具可以读取各个币种钱包的默认的配置资料, 31 | 币种钱包的配置资料放在conf/{symbol}.conf,例如:ADA.conf, BTC.conf,ETH.conf。 32 | 执行wmd wallet -s 命令会先检查是否存在该币种钱包的配置文件。 33 | 没有:执行ConfigFlow,配置文件初始化。 34 | 有:执行常规命令。 35 | 使用者还可以通过wmd config -s 进行修改配置文件。 36 | 或执行wmd config flow 重新进行一次配置初始化流程。 37 | 38 | */ 39 | 40 | const ( 41 | // Symbol 币种 42 | Symbol = "TRX" 43 | //MasterKey key for master 44 | MasterKey = "Troncoin seed" 45 | //CurveType to generate ChildKey by BIP32 46 | CurveType = owcrypt.ECC_CURVE_SECP256K1 47 | Decimals = 6 48 | SUN int64 = 1 //最小单位 49 | TRX int64 = SUN * 1000000 //1 TRX = 1000000 * sun 50 | GasPrice = SUN * 140 51 | CreateAccountCost = SUN * 1100000 //1.1 TRX = 1100000 * sun 52 | ) 53 | 54 | //WalletConfig configs for Wallet 55 | type WalletConfig struct { 56 | 57 | //币种 58 | Symbol string 59 | MasterKey string 60 | 61 | //RPCUser RPC认证账户名 62 | RPCUser string 63 | //RPCPassword RPC认证账户密码 64 | RPCPassword string 65 | //证书目录 66 | CertsDir string 67 | //钥匙备份路径 68 | keyDir string 69 | //地址导出路径 70 | addressDir string 71 | //配置文件路径 72 | configFilePath string 73 | //配置文件名 74 | configFileName string 75 | //rpc证书 76 | CertFileName string 77 | //区块链数据文件 78 | BlockchainFile string 79 | //是否测试网络 80 | IsTestNet bool 81 | // 核心钱包是否只做监听 82 | CoreWalletWatchOnly bool 83 | //最大的输入数量 84 | MaxTxInputs int 85 | //本地数据库文件路径 86 | dbPath string 87 | //备份路径 88 | backupDir string 89 | //钱包服务API 90 | ServerAPI string 91 | //钱包安装的路径 92 | NodeInstallPath string 93 | //钱包数据文件目录 94 | WalletDataPath string 95 | //汇总阀值 96 | Threshold decimal.Decimal 97 | //汇总地址 98 | SumAddress string 99 | //汇总执行间隔时间 100 | CycleSeconds time.Duration 101 | //默认配置内容 102 | DefaultConfig string 103 | //曲线类型 104 | CurveType uint32 105 | //小数位长度 106 | CoinDecimal decimal.Decimal 107 | //后台数据源类型 108 | RPCServerType int 109 | //FeeLimit 智能合约最大能量消耗限制,1 Energy = 140 SUN 110 | FeeLimit int64 111 | //FeeMini 智能合约最小能量消耗起,1 Energy = 140 SUN 112 | FeeMini int64 113 | //数据目录 114 | DataDir string 115 | //Ignore the dust trade 116 | IgnoreDustTRX decimal.Decimal 117 | } 118 | 119 | //NewConfig Create config instance 120 | func NewConfig() *WalletConfig { 121 | 122 | c := WalletConfig{} 123 | 124 | //币种 125 | c.Symbol = Symbol 126 | c.MasterKey = MasterKey 127 | c.CurveType = CurveType 128 | 129 | //RPC认证账户名 130 | c.RPCUser = "" 131 | //RPC认证账户密码 132 | c.RPCPassword = "" 133 | //证书目录 134 | c.CertsDir = filepath.Join("data", strings.ToLower(c.Symbol), "certs") 135 | //钥匙备份路径 136 | c.keyDir = filepath.Join("data", strings.ToLower(c.Symbol), "key") 137 | //地址导出路径 138 | c.addressDir = filepath.Join("data", strings.ToLower(c.Symbol), "address") 139 | //区块链数据 140 | //blockchainDir = filepath.Join("data", strings.ToLower(Symbol), "blockchain") 141 | //配置文件路径 142 | c.configFilePath = filepath.Join("conf") 143 | //配置文件名 144 | c.configFileName = c.Symbol + ".ini" 145 | //rpc证书 146 | c.CertFileName = "rpc.cert" 147 | //区块链数据文件 148 | c.BlockchainFile = "blockchain.db" 149 | //是否测试网络 150 | c.IsTestNet = true 151 | // 核心钱包是否只做监听 152 | c.CoreWalletWatchOnly = true 153 | //最大的输入数量 154 | c.MaxTxInputs = 50 155 | //本地数据库文件路径 156 | c.dbPath = filepath.Join("data", strings.ToLower(c.Symbol), "db") 157 | //备份路径 158 | c.backupDir = filepath.Join("data", strings.ToLower(c.Symbol), "backup") 159 | //钱包服务API 160 | c.ServerAPI = "" 161 | //钱包安装的路径 162 | c.NodeInstallPath = "" 163 | //钱包数据文件目录 164 | c.WalletDataPath = "" 165 | //汇总阀值 166 | c.Threshold = decimal.NewFromFloat(5) 167 | //汇总地址 168 | c.SumAddress = "" 169 | //汇总执行间隔时间 170 | c.CycleSeconds = time.Second * 10 171 | //小数位长度 172 | c.CoinDecimal = decimal.NewFromFloat(100000000) 173 | 174 | //默认配置内容 175 | c.DefaultConfig = ` 176 | # start node command 177 | startNodeCMD = "" 178 | # stop node command 179 | stopNodeCMD = "" 180 | # node install path 181 | nodeInstallPath = "" 182 | # mainnet data path 183 | mainNetDataPath = "" 184 | # testnet data path 185 | testNetDataPath = "" 186 | # RPC api url 187 | serverAPI = "" 188 | # RPC Authentication Username 189 | rpcUser = "" 190 | # RPC Authentication Password 191 | rpcPassword = "" 192 | # Is network test? 193 | isTestNet = false 194 | # the safe address that wallet send money to. 195 | sumAddress = "" 196 | # when wallet's balance is over this value, the wallet willl send money to [sumAddress] 197 | threshold = "" 198 | # summary task timer cycle time, sample: 1m , 30s, 3m20s etc 199 | cycleSeconds = "" 200 | # feeLimit, the maximum energy is 1000000000 201 | feeLimit = 10000000 202 | ` 203 | 204 | //创建目录 205 | //file.MkdirAll(c.dbPath) 206 | //file.MkdirAll(c.backupDir) 207 | //file.MkdirAll(c.keyDir) 208 | 209 | return &c 210 | } 211 | 212 | //PrintConfig Print config information 213 | func (wc *WalletConfig) PrintConfig() error { 214 | 215 | wc.InitConfig() 216 | //读取配置 217 | absFile := filepath.Join(wc.configFilePath, wc.configFileName) 218 | //apiURL := c.String("apiURL") 219 | //walletPath := c.String("walletPath") 220 | //threshold := c.String("threshold") 221 | //minSendAmount := c.String("minSendAmount") 222 | //minFees := c.String("minFees") 223 | //sumAddress := c.String("sumAddress") 224 | //isTestNet, _ := c.Bool("isTestNet") 225 | 226 | fmt.Printf("-----------------------------------------------------------\n") 227 | //fmt.Printf("Wallet API URL: %s\n", apiURL) 228 | //fmt.Printf("Wallet Data FilePath: %s\n", walletPath) 229 | //fmt.Printf("Summary Address: %s\n", sumAddress) 230 | //fmt.Printf("Summary Threshold: %s\n", threshold) 231 | //fmt.Printf("Min Send Amount: %s\n", minSendAmount) 232 | //fmt.Printf("Transfer Fees: %s\n", minFees) 233 | //if isTestNet { 234 | // fmt.Printf("Network: TestNet\n") 235 | //} else { 236 | // fmt.Printf("Network: MainNet\n") 237 | //} 238 | file.PrintFile(absFile) 239 | fmt.Printf("-----------------------------------------------------------\n") 240 | 241 | return nil 242 | 243 | } 244 | 245 | //InitConfig 初始化配置文件 246 | func (wc *WalletConfig) InitConfig() { 247 | 248 | //读取配置 249 | absFile := filepath.Join(wc.configFilePath, wc.configFileName) 250 | if !file.Exists(absFile) { 251 | file.MkdirAll(wc.configFilePath) 252 | file.WriteFile(absFile, []byte(wc.DefaultConfig), false) 253 | } 254 | 255 | } 256 | 257 | //创建文件夹 258 | func (wc *WalletConfig) makeDataDir() { 259 | 260 | if len(wc.DataDir) == 0 { 261 | //默认路径当前文件夹./data 262 | wc.DataDir = "data" 263 | } 264 | 265 | //本地数据库文件路径 266 | wc.dbPath = filepath.Join(wc.DataDir, strings.ToLower(wc.Symbol), "db") 267 | 268 | //创建目录 269 | file.MkdirAll(wc.dbPath) 270 | } 271 | -------------------------------------------------------------------------------- /tron/contract.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The OpenWallet Authors 3 | * This file is part of the OpenWallet library. 4 | * 5 | * The OpenWallet library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The OpenWallet library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package tron 17 | 18 | import ( 19 | "encoding/hex" 20 | "fmt" 21 | "github.com/blocktree/openwallet/v2/common" 22 | "github.com/blocktree/openwallet/v2/openwallet" 23 | "github.com/imroc/req" 24 | "math/big" 25 | "strings" 26 | ) 27 | 28 | /* 29 | 30 | 在TRON中检测TRX或TRC10事务涉及4种类型的合同: 31 | 32 | TransferContract(系统合同类型:TRX转账) 33 | TransferAssetContract(系统合同类型:TRC10转账) 34 | CreateSmartContract(智能合约类型) 35 | TriggerSmartContract(智能合约类型:TRC20转账) 36 | Transaction,TransactionInfo 和 Block 的数据包含所有智能合约交易信息。 37 | 38 | 技术细节 39 | https://cn.developers.tron.network/docs/%E4%BA%A4%E6%8D%A2%E4%B8%AD%E7%9A%84trc10%E5%92%8Ctrx%E8%BD%AC%E7%A7%BB 40 | 41 | TRX转账示例 42 | https://tronscan.org/#/transaction/f8f8ac5b4b0df34dad410147231061806c9fa8c207e7f3107cadc6d00925ccbc 43 | 44 | TRC10转账示例 45 | https://tronscan.org/#/transaction/c0edfc83e3535700b46598444f2425696686d20566101d8b5b2aa95c0915a2a0 46 | 47 | TRC20转账示例 48 | https://tronscan.org/#/transaction/a5614f60e7d3b9d8859abe89968d81007c321c5ad83cb9c7abaa736a20401a11 49 | 50 | */ 51 | 52 | const ( 53 | TRC10 = "trc10" 54 | TRC20 = "trc20" 55 | 56 | FeeLimit = 10000000 57 | ) 58 | 59 | const ( 60 | TRC20_BALANCE_OF_METHOD = "balanceOf(address)" 61 | TRC20_TRANSFER_METHOD_ID = "a9059cbb" 62 | TRX_TRANSFER_EVENT_ID = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" 63 | ) 64 | 65 | const ( 66 | SOLIDITY_TYPE_ADDRESS = "address" 67 | SOLIDITY_TYPE_UINT256 = "uint256" 68 | SOLIDITY_TYPE_UINT160 = "uint160" 69 | ) 70 | 71 | type SolidityParam struct { 72 | ParamType string 73 | ParamValue interface{} 74 | } 75 | 76 | func makeRepeatString(c string, count uint) string { 77 | cs := make([]string, 0) 78 | for i := 0; i < int(count); i++ { 79 | cs = append(cs, c) 80 | } 81 | return strings.Join(cs, "") 82 | } 83 | 84 | func makeTransactionParameter(methodId string, params []SolidityParam) (string, error) { 85 | 86 | data := methodId 87 | for i, _ := range params { 88 | var param string 89 | if params[i].ParamType == SOLIDITY_TYPE_ADDRESS { 90 | param = strings.ToLower(params[i].ParamValue.(string)) 91 | param = strings.TrimPrefix(param, "0x") 92 | if len(param) != 42 { 93 | return "", fmt.Errorf("length of address error.") 94 | } 95 | param = makeRepeatString("0", 22) + param 96 | } else if params[i].ParamType == SOLIDITY_TYPE_UINT256 { 97 | intParam := params[i].ParamValue.(*big.Int) 98 | param = intParam.Text(16) 99 | l := len(param) 100 | if l > 64 { 101 | return "", fmt.Errorf("integer overflow.") 102 | } 103 | param = makeRepeatString("0", uint(64-l)) + param 104 | //fmt.Println("makeTransactionData intParam:", intParam.String(), " param:", param) 105 | } else { 106 | return "", fmt.Errorf("not support solidity type") 107 | } 108 | 109 | data += param 110 | } 111 | return data, nil 112 | } 113 | 114 | //TriggerSmartContract 初始智能合约方法 115 | func (wm *WalletManager) TriggerSmartContract( 116 | contractAddress string, 117 | function string, 118 | parameter string, 119 | feeLimit uint64, 120 | callValue uint64, 121 | ownerAddress string) (*TransactionExtention, error) { 122 | params := req.Param{ 123 | "contract_address": contractAddress, 124 | "function_selector": function, 125 | "parameter": parameter, 126 | "fee_limit": feeLimit, 127 | "call_value": callValue, 128 | "owner_address": ownerAddress, 129 | } 130 | r, err := wm.WalletClient.Call("/wallet/triggersmartcontract", params) 131 | if err != nil { 132 | return nil, err 133 | } 134 | return NewTransactionExtention(r), nil 135 | } 136 | 137 | //GetContractInfo 获取智能合约信息 138 | func (wm *WalletManager) GetContractInfo(contractAddress string) (*ContractInfo, error) { 139 | value, _, err := DecodeAddress(contractAddress, wm.Config.IsTestNet) 140 | if err != nil { 141 | return nil, err 142 | } 143 | params := req.Param{ 144 | "value": value, 145 | } 146 | r, err := wm.WalletClient.Call("/wallet/getcontract", params) 147 | if err != nil { 148 | return nil, err 149 | } 150 | return NewContractInfo(r), nil 151 | } 152 | 153 | //GetTokenBalance 获取代币余额 154 | func (wm *WalletManager) GetTRC20Balance(address string, contractAddress string) (*big.Int, error) { 155 | 156 | from, _, err := DecodeAddress(address, wm.Config.IsTestNet) 157 | if err != nil { 158 | return big.NewInt(0), err 159 | } 160 | 161 | caddr, _, err := DecodeAddress(contractAddress, wm.Config.IsTestNet) 162 | if err != nil { 163 | return big.NewInt(0), err 164 | } 165 | param, err := makeTransactionParameter("", []SolidityParam{ 166 | SolidityParam{ 167 | SOLIDITY_TYPE_ADDRESS, 168 | from, 169 | }, 170 | }) 171 | if err != nil { 172 | return big.NewInt(0), err 173 | } 174 | 175 | tx, err := wm.TriggerSmartContract( 176 | caddr, 177 | TRC20_BALANCE_OF_METHOD, 178 | param, 179 | 0, 180 | 0, 181 | from) 182 | if err != nil { 183 | return big.NewInt(0), err 184 | } 185 | 186 | if len(tx.ConstantResult) > 0 { 187 | balance, err := common.StringValueToBigInt(tx.ConstantResult[0], 16) 188 | //balance, err := strconv.ParseInt(tx.ConstantResult[0], 16, 64) 189 | if err != nil { 190 | return big.NewInt(0), err 191 | } 192 | return balance, nil 193 | } else { 194 | nameBytes, _ := hex.DecodeString(tx.Result.Message) 195 | return big.NewInt(0), fmt.Errorf(string(nameBytes)) 196 | } 197 | return big.NewInt(0), nil 198 | } 199 | 200 | //GetTokenBalance 获取代币余额 201 | func (wm *WalletManager) GetTRC10Balance(address string, tokenID string) (*big.Int, error) { 202 | 203 | a, _, err := wm.GetTRXAccount(address) 204 | if err != nil { 205 | return big.NewInt(0), err 206 | } 207 | 208 | return a.AssetV2[tokenID], nil 209 | } 210 | 211 | type ContractDecoder struct { 212 | *openwallet.SmartContractDecoderBase 213 | wm *WalletManager 214 | } 215 | 216 | //NewContractDecoder 智能合约解析器 217 | func NewContractDecoder(wm *WalletManager) *ContractDecoder { 218 | decoder := ContractDecoder{} 219 | decoder.wm = wm 220 | return &decoder 221 | } 222 | 223 | func (decoder *ContractDecoder) GetTokenBalanceByAddress(contract openwallet.SmartContract, address ...string) ([]*openwallet.TokenBalance, error) { 224 | 225 | var tokenBalanceList []*openwallet.TokenBalance 226 | 227 | for i := 0; i < len(address); i++ { 228 | var ( 229 | balance *big.Int 230 | err error 231 | ) 232 | if strings.EqualFold(contract.Protocol, TRC20) { 233 | balance, err = decoder.wm.GetTRC20Balance(address[i], contract.Address) 234 | if err != nil { 235 | decoder.wm.Log.Errorf("get address[%v] token balance failed, err: %v", address[i], err) 236 | } 237 | } else if strings.EqualFold(contract.Protocol, TRC10) { 238 | balance, err = decoder.wm.GetTRC10Balance(address[i], contract.Address) 239 | if err != nil { 240 | decoder.wm.Log.Errorf("get address[%v] token balance failed, err: %v", address[i], err) 241 | } 242 | } 243 | 244 | if err != nil { 245 | if strings.EqualFold(contract.Protocol, TRC20) { 246 | balance, err = decoder.wm.GetTRC20Balance(address[i], contract.Address) 247 | if err != nil { 248 | decoder.wm.Log.Errorf("get address[%v] token balance failed, err: %v", address[i], err) 249 | } 250 | } else if strings.EqualFold(contract.Protocol, TRC10) { 251 | balance, err = decoder.wm.GetTRC10Balance(address[i], contract.Address) 252 | if err != nil { 253 | decoder.wm.Log.Errorf("get address[%v] token balance failed, err: %v", address[i], err) 254 | } 255 | } 256 | } 257 | 258 | tokenBalance := &openwallet.TokenBalance{ 259 | Contract: &contract, 260 | Balance: &openwallet.Balance{ 261 | Address: address[i], 262 | Symbol: contract.Symbol, 263 | Balance: common.BigIntToDecimals(balance, int32(contract.Decimals)).String(), 264 | ConfirmBalance: common.BigIntToDecimals(balance, int32(contract.Decimals)).String(), 265 | UnconfirmBalance: "0", 266 | }, 267 | } 268 | 269 | tokenBalanceList = append(tokenBalanceList, tokenBalance) 270 | } 271 | 272 | return tokenBalanceList, nil 273 | } 274 | -------------------------------------------------------------------------------- /tron/manager_txRef_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The openwallet Authors 3 | * This file is part of the openwallet library. 4 | * 5 | * The openwallet library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The openwallet library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package tron 17 | 18 | import ( 19 | "encoding/hex" 20 | "fmt" 21 | "testing" 22 | ) 23 | 24 | var ( 25 | pTxRaw = "0a7d0a02d0762208239cf236e19b41cf40e887c8a7e12c5a66080112620a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412310a154199fee02e1ee01189bc41a68e9069b7919ef2ad82121541e11973395042ba3c0b52b4cdf4e15ea77818f27518904e" 26 | pTxSigned = "0a7d0a02d0762208239cf236e19b41cf40e887c8a7e12c5a66080112620a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412310a154199fee02e1ee01189bc41a68e9069b7919ef2ad82121541e11973395042ba3c0b52b4cdf4e15ea77818f27518904e124123218536461fff784bd32e206a4c1a7adc05b455aa37cd624724cb3a2826119d434317d121bda9b5352bf0aaa61326471c5167d14376a96a466317d041696c6801" 27 | ) 28 | 29 | func TestHash(t *testing.T) { 30 | txRaw := "0a7e0a0241222208c38f37b66624de47409096f8e1fa2c5a67080112630a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412320a1541887661d2e0215851756b1e7933216064526badcd121541b6c1abf9fb31c9077dfb3c25469e6e943ffbfa7a18a08d06" 31 | hash, _ := getTxHash1(txRaw) 32 | fmt.Println("hash:=", hex.EncodeToString(hash)) 33 | } 34 | 35 | func TestGetbalance(t *testing.T) { 36 | addr := "TAJTMJuzvAqB8wmdUjRBVJW8CozfgrhpX3" 37 | 38 | addrBalance, _ := tw.Getbalance(addr) 39 | fmt.Println(addrBalance.TronBalance) 40 | } 41 | 42 | func TestCreateTransactionRef(t *testing.T) { 43 | 44 | if r, err := tw.CreateTransactionRef(TOADDRESS, OWNERADDRESS, AMOUNT); err != nil { 45 | t.Errorf("TestCreateTransaction failed: %v\n", err) 46 | } else { 47 | /* 48 | t.Logf("TestCreateTransaction return: \n%+v\n", "Success!") 49 | 50 | fmt.Println("") 51 | fmt.Printf("APP Generated: %+v\n", "0a7e0a02adcd220873bf2dfd044f459440e0d4d2f8e12c5a67080112630a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412320a154199fee02e1ee01189bc41a68e9069b7919ef2ad82121541e11973395042ba3c0b52b4cdf4e15ea77818f27518c0843d") 52 | fmt.Printf("Ref Generated: %+v\n\n", r) 53 | */ 54 | fmt.Println("Tx:=", r) 55 | } 56 | } 57 | 58 | /* 59 | func TestSignTransactoinRef(t *testing.T) { 60 | 61 | var txRaw string 62 | txRaw = "0a7e0a0241222208c38f37b66624de47409096f8e1fa2c5a67080112630a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412320a1541887661d2e0215851756b1e7933216064526badcd121541b6c1abf9fb31c9077dfb3c25469e6e943ffbfa7a18a08d06" 63 | if r, err := tw.SignTransactionRef(txRaw, PRIVATEKEY); err != nil { 64 | t.Errorf("SignTransactionRef failed: %v\n", err) 65 | } else { 66 | //t.Logf("SignTransactionRef return: \n\t%+v\n", r) 67 | //debugPrintTx(r) 68 | fmt.Println("signature:=", r) 69 | } 70 | } 71 | */ 72 | 73 | func TestSignTransactionRef1(t *testing.T) { 74 | var txRaw string 75 | txRaw = "0a7e0a023d00220855e3f0172c91725e40c6d9a7aafc2c5a67080112630a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412320a1541887661d2e0215851756b1e7933216064526badcd121541b6c1abf9fb31c9077dfb3c25469e6e943ffbfa7a18a08d06" 76 | hash, err := getTxHash1(txRaw) 77 | if err != nil { 78 | t.Errorf("Get transaction hash failed:%v\n", err) 79 | } 80 | txHash := hex.EncodeToString(hash) 81 | if r, err := tw.SignTransactionRef(txHash, PRIVATEKEY); err != nil { 82 | t.Errorf("SignTransactionRef failed: %v\n", err) 83 | } else { 84 | fmt.Println("signature:=", r) 85 | } 86 | 87 | } 88 | 89 | func TestValidSignedTransactionRef(t *testing.T) { 90 | var txSignedRaw string 91 | //txSignedRaw = TXSIGNED 92 | txSignedRaw = "0a7e0a0289432208607606a10d2e670340e189ccfdfa2c5a67080112630a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412320a1541887661d2e0215851756b1e7933216064526badcd121541b6c1abf9fb31c9077dfb3c25469e6e943ffbfa7a18a08d06124100c8965a5d450bbeb263e852e6578556ba266338c99f887540c6e4ddb73488ef136316d72b36ff88770614a68810de5e2f2924aea0da5c9c5af724c71a34cfe100" 93 | //txSignedRaw = "0a7e0a02fd77220882256bb5fe08d39240d0a7c98fe82c5a67080112630a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412320a154199fee02e1ee01189bc41a68e9069b7919ef2ad82121541e11973395042ba3c0b52b4cdf4e15ea77818f27518c0843d1241373bf54b04e287d902beff4c6bd7369395b7b65527513922ee3b61ac0c4c6e8d0061da08b1b2f361e53c933360c3e5783996339431d44469f8bd57ee8fdfd3d700" 94 | if err := tw.ValidSignedTransactionRef(txSignedRaw); err != nil { 95 | t.Errorf("ValidSignedTransactionRef: %v\n", err) 96 | } else { 97 | t.Logf("GetTransactionSignRef return: \n\t%+v\n", "Success!") 98 | } 99 | } 100 | 101 | func TestBroadcastTransaction(t *testing.T) { 102 | 103 | var raw = "0a7e0a02a71f2208f4735d707a8537a240b0c2f088fb2c5a67080112630a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412320a1541887661d2e0215851756b1e7933216064526badcd121541b6c1abf9fb31c9077dfb3c25469e6e943ffbfa7a18a08d061241cb5ba106fafe57e2e3e6fc801a297aa5cc78d5c0b5358f97ceb5d903ab1e487b213dbb66195c992de2c7d9da5b13ace9880bc32141f28430ab7893291f06056f01" 104 | 105 | if txid, err := tw.BroadcastTransaction(raw); err != nil { 106 | t.Errorf("BroadcastTransaction failed: %v\n", err) 107 | } else { 108 | t.Logf("BroadcastTransaction return: \n\t%+v\n", "Success!") 109 | fmt.Println("txid:=", txid) 110 | } 111 | } 112 | 113 | func TestSuiteTx(t *testing.T) { 114 | 115 | println("Start testsuit...\n") 116 | 117 | var ( 118 | txRaw, txSignedRaw string 119 | err error 120 | ) 121 | 122 | txRaw, err = tw.CreateTransactionRef(TOADDRESS, OWNERADDRESS, AMOUNT) 123 | if err != nil { 124 | t.Errorf("TestCreateTransaction failed: %v\n", err) 125 | return 126 | } 127 | println("txRaw: ", txRaw) 128 | println("------------------------------------------------------------------- Create Done! \n") 129 | 130 | // txRaw = "0a7e0a02b2302208e384c56f2822541840e0f2fed1e82c5a67080112630a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412320a154199fee02e1ee01189bc41a68e9069b7919ef2ad82121541e11973395042ba3c0b52b4cdf4e15ea77818f27518c0843d" 131 | txSignedRaw, err = tw.SignTransactionRef(txRaw, PRIVATEKEY) 132 | if err != nil { 133 | t.Errorf("GetTransactionSignRef failed: %v\n", err) 134 | return 135 | } 136 | println("txSignedRaw: ", txSignedRaw) 137 | println("------------------------------------------------------------------- Sign Done! \n") 138 | 139 | // txSignedRaw = "0a7e0a02b20722088b88797132e6dc8540b09af7d1e82c5a67080112630a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412320a154199fee02e1ee01189bc41a68e9069b7919ef2ad82121541e11973395042ba3c0b52b4cdf4e15ea77818f27518c0843d12415407e6344baced1f933762ab31d1054906b4307a63fc5b3764a3ac803a3c3ceeabe1ac40d2947a8eaf98747de88e0e982cbb5f083d3e798c76280e170657303700" 140 | err = tw.ValidSignedTransactionRef(txSignedRaw) 141 | if err != nil { 142 | t.Errorf("ValidSignedTransactionRef: %v\n", err) 143 | return 144 | } 145 | println("Success!") 146 | println("------------------------------------------------------------------- Valid Done! \n") 147 | 148 | // txSignedRaw := "0a7e0a02b73b2208d971acfd3452661c40f0d68cfce12c5a67080112630a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412320a154199fee02e1ee01189bc41a68e9069b7919ef2ad82121541e11973395042ba3c0b52b4cdf4e15ea77818f27518c0843d1241166ae365792c1918de963cc4121e47417252da11d54783dbeb248f913240f27ea02b1b42f807c4ffb5d7ebecf687f5294400281021e6fefd0f38c50765f9c87200" 149 | txid, err := tw.BroadcastTransaction(txSignedRaw) 150 | if err != nil { 151 | t.Errorf("ValidSignedTransactionRef: %v\n", err) 152 | } else { 153 | println("Success!") 154 | fmt.Println("txid:=", txid) 155 | } 156 | println("------------------------------------------------------------------- Boradcast! \n") 157 | 158 | //tx := &core.Transaction{} 159 | //txRawBytes, _ := hex.DecodeString(txRaw) 160 | //proto.Unmarshal(txRawBytes, tx) 161 | //txIDBytes, _ := getTxHash(tx) 162 | //_ := hex.EncodeToString(txIDBytes) 163 | 164 | //for i := 0; i < 1000; i++ { 165 | // 166 | // tx, _ := tw.GetTransactionByID(txID) 167 | // fmt.Println("Is Success: ", tx.IsSuccess) 168 | // fmt.Println("") 169 | // 170 | // if tx.IsSuccess { 171 | // return 172 | // } 173 | // 174 | // time.Sleep(time.Second * 1) 175 | //} 176 | 177 | } 178 | -------------------------------------------------------------------------------- /tron/manager_tx.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The openwallet Authors 3 | * This file is part of the openwallet library. 4 | * 5 | * The openwallet library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The openwallet library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package tron 17 | 18 | import ( 19 | "encoding/hex" 20 | "fmt" 21 | 22 | "github.com/blocktree/openwallet/v2/log" 23 | "github.com/blocktree/tron-adapter/tron/grpc-gateway/core" 24 | "github.com/golang/protobuf/proto" 25 | "github.com/imroc/req" 26 | ) 27 | 28 | // GetTotalTransaction Done! 29 | // Function:Count all transactions (number) on the network 30 | // demo: curl -X POST http://127.0.0.1:8090/wallet/totaltransaction 31 | // Parameters:Nones 32 | // Return value: 33 | // Total number of transactions. 34 | func (wm *WalletManager) GetTotalTransaction() (num uint64, err error) { 35 | 36 | r, err := wm.WalletClient.Call("/wallet/totaltransaction", nil) 37 | if err != nil { 38 | return 0, err 39 | } 40 | 41 | num = r.Get("num").Uint() 42 | return num, nil 43 | } 44 | 45 | // GetTransactionByID Done! 46 | // Function:Query transaction by ID 47 | // demo: curl -X POST http://127.0.0.1:8090/wallet/gettransactionbyid -d ‘ 48 | // {“value”: “d5ec749ecc2a615399d8a6c864ea4c74ff9f523c2be0e341ac9be5d47d7c2d62”}’ 49 | // Parameters:Transaction ID. 50 | // Return value:Transaction information. 51 | //func (wm *WalletManager) GetTransactionByID(txID string) (tx *Transaction, err error) { 52 | // 53 | // params := req.Param{"value": txID} 54 | // r, err := wm.WalletClient.Call("/wallet/gettransactionbyid", params) 55 | // if err != nil { 56 | // return nil, err 57 | // } 58 | // 59 | // tx = NewTransaction(r) 60 | // return tx, err 61 | //} 62 | 63 | // CreateTransaction Writing! 64 | // Function:Creates a transaction of transfer. If the recipient address does not exist, a corresponding account will be created on the blockchain. 65 | // demo: curl -X POST http://127.0.0.1:8090/wallet/createtransaction -d ‘ 66 | // {“to_address”: “41e9d79cc47518930bc322d9bf7cddd260a0260a8d”, 67 | // “owner_address”: “41D1E7A6BC354106CB410E65FF8B181C600FF14292”, 68 | // “amount”: 1000 }’ P 69 | // Parameters: 70 | // To_address is the transfer address, converted to a hex string; 71 | // owner_address is the transfer transfer address, converted to a hex string; 72 | // amount is the transfer amount 73 | // Return value: 74 | // Transaction contract data 75 | func (wm *WalletManager) CreateTransaction(toAddress, ownerAddress string, amount float64) (raw string, err error) { 76 | 77 | params := req.Param{ 78 | "to_address": toAddress, 79 | "owner_address": ownerAddress, 80 | "amount": amount * 1000000, 81 | } 82 | 83 | r, err := wm.WalletClient.Call("/wallet/createtransaction", params) 84 | if err != nil { 85 | return "", err 86 | } 87 | 88 | // // type Transaction_Contract struct { 89 | // // Type Transaction_Contract_ContractType `protobuf:"varint,1,opt,name=type,proto3,enum=protocol.Transaction_Contract_ContractType" json:"type,omitempty"` 90 | // // Parameter *any.Any `protobuf:"bytes,2,opt,name=parameter,proto3" json:"parameter,omitempty"` 91 | // // Provider []byte `protobuf:"bytes,3,opt,name=provider,proto3" json:"provider,omitempty"` 92 | // // ContractName []byte `protobuf:"bytes,4,opt,name=ContractName,proto3" json:"ContractName,omitempty"` 93 | // // XXX_NoUnkeyedLiteral struct{} `json:"-"` 94 | // // XXX_unrecognized []byte `json:"-"` 95 | // // XXX_sizecache int32 `json:"-"` 96 | // // } 97 | // tx := &core.Transaction_Contract{} 98 | // if err := gjson.Unmarshal([]byte(r.Raw), tx); err != nil { 99 | // log.Errorf("Proto Unmarshal: ", err) 100 | // return "", err 101 | // } 102 | raw = hex.EncodeToString([]byte(r.Raw)) 103 | 104 | return raw, nil 105 | } 106 | 107 | // Writing! No used! 108 | // Function:Sign the transaction, the api has the risk of leaking the private key, please make sure to call the api in a secure environment 109 | // demo: curl -X POST http://127.0.0.1:8090/wallet/gettransactionsign -d ‘ 110 | // { “transaction” : {“txID”:”454f156bf1256587ff6ccdbc56e64ad0c51e4f8efea5490dcbc720ee606bc7b8”, 111 | // ”raw_data”:{ 112 | // “contract”:[{“parameter”:{“value”:{“amount”:1000, 113 | // ”owner_address”:”41e552f6487585c2b58bc2c9bb4492bc1f17132cd0”, 114 | // ”to_address”:”41d1e7a6bc354106cb410e65ff8b181c600ff14292”}, 115 | // ”type_url”:”type.googleapis.com/protocol.TransferContract”}, 116 | // ”type”:”TransferContract”}], 117 | // ”ref_block_bytes”:”267e”, 118 | // ”ref_block_hash”:”9a447d222e8de9f2”, 119 | // ”expiration”:1530893064000, 120 | // ”timestamp”:1530893006233}} 121 | // “privateKey” : “your private key”} }’ 122 | // Parameters: 123 | // Transaction is a contract created by http api, 124 | // privateKey is the user private key 125 | // Return value:Signed Transaction contract data 126 | func (wm *WalletManager) GetTransactionSign(transaction, privateKey string) (rawSinged []byte, err error) { 127 | 128 | params := req.Param{ 129 | "transaction": transaction, 130 | "privateKey": privateKey, 131 | } 132 | 133 | r, err := wm.WalletClient.Call("/wallet/gettransactionsign", params) 134 | if err != nil { 135 | return nil, err 136 | } 137 | fmt.Println("Test = ", r) 138 | 139 | return rawSinged, nil 140 | } 141 | 142 | // BroadcastTransaction Done! 143 | // Function:Broadcast the signed transaction 144 | // demo:curl -X POST http://127.0.0.1:8090/wallet/broadcasttransaction -d ‘ 145 | // {“signature”:[“97c825b41c77de2a8bd65b3df55cd4c0df59c307c0187e42321dcc1cc455ddba583dd9502e17cfec5945b34cad0511985a6165999092a6dec84c2bdd97e649fc01”], 146 | // ”txID”:”454f156bf1256587ff6ccdbc56e64ad0c51e4f8efea5490dcbc720ee606bc7b8”, 147 | // ”raw_data”:{“contract”:[{ 148 | // “parameter”:{ 149 | // “value”:{“amount”:1000, 150 | // ”owner_address”:”41e552f6487585c2b58bc2c9bb4492bc1f17132cd0”, 151 | // ”to_address”: ”41d1e7a6bc354106cb410e65ff8b181c600ff14292”}, 152 | // ”type_url”:”type.googleapis.com/protocol.TransferContract”}, 153 | // ”type”:”TransferContract” 154 | // }], 155 | // ”ref_block_bytes”:”267e”, 156 | // ”ref_block_hash”:”9a447d222e8de9f2”, 157 | // ”expiration”:1530893064000, 158 | // ”timestamp”:1530893006233} 159 | // }’ 160 | // Parameters:Signed Transaction contract data 161 | // Return value:broadcast success or failure 162 | func (wm *WalletManager) BroadcastTransaction1(raw string) error { 163 | 164 | tx := &core.Transaction{} 165 | if txBytes, err := hex.DecodeString(raw); err != nil { 166 | log.Errorf("Hex decode error: %+v", err) 167 | return err 168 | } else { 169 | if err := proto.Unmarshal(txBytes, tx); err != nil { 170 | log.Errorf("Hex decode error: %+v", err) 171 | return err 172 | } 173 | } 174 | 175 | /* Generate Params */ 176 | 177 | var ( 178 | signature []string 179 | txID string 180 | contracts []map[string]interface{} 181 | raw_data map[string]interface{} 182 | ) 183 | 184 | for _, x := range tx.GetSignature() { 185 | signature = append(signature, hex.EncodeToString(x)) // base64 186 | } 187 | 188 | if txHash, err := getTxHash(tx); err != nil { 189 | log.Error(err) 190 | return err 191 | } else { 192 | txID = hex.EncodeToString(txHash) 193 | } 194 | 195 | rawData := tx.GetRawData() 196 | 197 | contracts = []map[string]interface{}{} 198 | for _, c := range rawData.GetContract() { 199 | any := c.GetParameter().GetValue() 200 | 201 | tc := &core.TransferContract{} 202 | if err := proto.Unmarshal(any, tc); err != nil { 203 | return err 204 | } 205 | 206 | contract := map[string]interface{}{ 207 | "type": c.GetType().String(), 208 | "parameter": map[string]interface{}{ 209 | "type_url": c.GetParameter().GetTypeUrl(), 210 | "value": map[string]interface{}{ 211 | "amount": tc.Amount, 212 | "owner_address": hex.EncodeToString(tc.GetOwnerAddress()), 213 | "to_address": hex.EncodeToString(tc.GetToAddress()), 214 | }, 215 | }, 216 | } 217 | contracts = append(contracts, contract) 218 | } 219 | raw_data = map[string]interface{}{ 220 | "ref_block_bytes": hex.EncodeToString(rawData.GetRefBlockBytes()), 221 | "ref_block_hash": hex.EncodeToString(rawData.GetRefBlockHash()), 222 | "expiration": rawData.GetExpiration(), 223 | "timestamp": rawData.GetTimestamp(), 224 | "contract": contracts, 225 | } 226 | params := req.Param{ 227 | "signature": signature, 228 | "txID": txID, 229 | "raw_data": raw_data, 230 | } 231 | 232 | // Call api 233 | r, err := wm.WalletClient.Call("/wallet/broadcasttransaction", params) 234 | if err != nil { 235 | log.Error(err) 236 | return err 237 | } else { 238 | log.Debugf("Test = %+v\n", r) 239 | 240 | if r.Get("result").Bool() != true { 241 | 242 | var err error 243 | 244 | if r.Get("message").String() != "" { 245 | msg, _ := hex.DecodeString(r.Get("message").String()) 246 | err = fmt.Errorf("BroadcastTransaction error message: %+v", string(msg)) 247 | } else { 248 | err = fmt.Errorf("BroadcastTransaction return error: %+v", r) 249 | } 250 | log.Error(err) 251 | 252 | return err 253 | } 254 | } 255 | 256 | return nil 257 | } 258 | -------------------------------------------------------------------------------- /tron/manager_account.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The openwallet Authors 3 | * This file is part of the openwallet library. 4 | * 5 | * The openwallet library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The openwallet library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package tron 17 | 18 | import ( 19 | "encoding/hex" 20 | "errors" 21 | "log" 22 | 23 | "github.com/blocktree/go-owcdrivers/addressEncoder" 24 | "github.com/blocktree/openwallet/v2/openwallet" 25 | "github.com/imroc/req" 26 | "github.com/tidwall/gjson" 27 | ) 28 | 29 | func convertAddrToHex(address string) string { 30 | toAddressBytes, err := addressEncoder.AddressDecode(address, addressEncoder.TRON_mainnetAddress) 31 | if err != nil { 32 | log.Println(err) 33 | } 34 | toAddressBytes = append([]byte{0x41}, toAddressBytes...) 35 | return hex.EncodeToString(toAddressBytes) 36 | } 37 | 38 | // GetAccountNet Done! 39 | // Function:Query bandwidth information. 40 | // demo: curl -X POST http://127.0.0.1:8090/wallet/getaccountnet -d ‘ 41 | // {“address”: “4112E621D5577311998708F4D7B9F71F86DAE138B5”}’ 42 | // Parameters: 43 | // Account address,converted to a hex string 44 | // Return value: 45 | // Bandwidth information for the account. 46 | // If a field doesn’t appear, then the corresponding value is 0. 47 | // {“freeNetUsed”: 557,”freeNetLimit”: 5000,”NetUsed”: 353,”NetLimit”: 5239157853,”TotalNetLimit”: 43200000000,”TotalNetWeight”: 41228} 48 | func (wm *WalletManager) GetAccountNet(address string) (accountNet *AccountNet, err error) { 49 | 50 | address = convertAddrToHex(address) 51 | 52 | params := req.Param{"address": address} 53 | r, err := wm.WalletClient.Call("/wallet/getaccountnet", params) 54 | if err != nil { 55 | return nil, err 56 | } 57 | accountNet = NewAccountNet(r) 58 | return accountNet, nil 59 | } 60 | 61 | // GetAccountResource 62 | func (wm *WalletManager) GetAccountResource(address string) (*AccountResource, error) { 63 | 64 | address = convertAddrToHex(address) 65 | 66 | params := req.Param{"address": address} 67 | r, err := wm.WalletClient.Call("/wallet/getaccountresource", params) 68 | if err != nil { 69 | return nil, err 70 | } 71 | res := NewAccountResource(r) 72 | return res, nil 73 | } 74 | 75 | //deprecated 76 | // GetAccount Done! 77 | // Function:Query bandwidth information. 78 | // Parameters: 79 | // Account address,converted to a base64 string 80 | // Return value: 81 | func (wm *WalletManager) GetAccount(address string) (account *openwallet.AssetsAccount, err error) { 82 | address = convertAddrToHex(address) 83 | 84 | params := req.Param{"address": address} 85 | r, err := wm.WalletClient.Call("/wallet/getaccount", params) 86 | if err != nil { 87 | return nil, err 88 | } 89 | account = &openwallet.AssetsAccount{} 90 | 91 | // // type Account struct { 92 | // // AccountName []byte `protobuf:"bytes,1,opt,name=account_name,json=accountName,proto3" json:"account_name,omitempty"` 93 | // // Type AccountType `protobuf:"varint,2,opt,name=type,proto3,enum=protocol.AccountType" json:"type,omitempty"` 94 | // // // the create address 95 | // // Address []byte `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"` 96 | // // // the trx balance 97 | // // Balance int64 `protobuf:"varint,4,opt,name=balance,proto3" json:"balance,omitempty"` 98 | // // // the votes 99 | // // Votes []*Vote `protobuf:"bytes,5,rep,name=votes,proto3" json:"votes,omitempty"` 100 | // // // the other asset owned by this account 101 | // // Asset map[string]int64 `protobuf:"bytes,6,rep,name=asset,proto3" json:"asset,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` 102 | // // // latest asset operation time 103 | // // // the frozen balance 104 | // // Frozen []*Account_Frozen `protobuf:"bytes,7,rep,name=frozen,proto3" json:"frozen,omitempty"` 105 | // // // bandwidth, get from frozen 106 | // // NetUsage int64 `protobuf:"varint,8,opt,name=net_usage,json=netUsage,proto3" json:"net_usage,omitempty"` 107 | // // // this account create time 108 | // // CreateTime int64 `protobuf:"varint,9,opt,name=create_time,json=createTime,proto3" json:"create_time,omitempty"` 109 | // // // this last operation time, including transfer, voting and so on. //FIXME fix grammar 110 | // // LatestOprationTime int64 `protobuf:"varint,10,opt,name=latest_opration_time,json=latestOprationTime,proto3" json:"latest_opration_time,omitempty"` 111 | // // // witness block producing allowance 112 | // // Allowance int64 `protobuf:"varint,11,opt,name=allowance,proto3" json:"allowance,omitempty"` 113 | // // // last withdraw time 114 | // // LatestWithdrawTime int64 `protobuf:"varint,12,opt,name=latest_withdraw_time,json=latestWithdrawTime,proto3" json:"latest_withdraw_time,omitempty"` 115 | // // // not used so far 116 | // // Code []byte `protobuf:"bytes,13,opt,name=code,proto3" json:"code,omitempty"` 117 | // // IsWitness bool `protobuf:"varint,14,opt,name=is_witness,json=isWitness,proto3" json:"is_witness,omitempty"` 118 | // // IsCommittee bool `protobuf:"varint,15,opt,name=is_committee,json=isCommittee,proto3" json:"is_committee,omitempty"` 119 | // // // frozen asset(for asset issuer) 120 | // // FrozenSupply []*Account_Frozen `protobuf:"bytes,16,rep,name=frozen_supply,json=frozenSupply,proto3" json:"frozen_supply,omitempty"` 121 | // // // asset_issued_name 122 | // // AssetIssuedName []byte `protobuf:"bytes,17,opt,name=asset_issued_name,json=assetIssuedName,proto3" json:"asset_issued_name,omitempty"` 123 | // // LatestAssetOperationTime map[string]int64 `protobuf:"bytes,18,rep,name=latest_asset_operation_time,json=latestAssetOperationTime,proto3" json:"latest_asset_operation_time,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` 124 | // // FreeNetUsage int64 `protobuf:"varint,19,opt,name=free_net_usage,json=freeNetUsage,proto3" json:"free_net_usage,omitempty"` 125 | // // FreeAssetNetUsage map[string]int64 `protobuf:"bytes,20,rep,name=free_asset_net_usage,json=freeAssetNetUsage,proto3" json:"free_asset_net_usage,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` 126 | // // LatestConsumeTime int64 `protobuf:"varint,21,opt,name=latest_consume_time,json=latestConsumeTime,proto3" json:"latest_consume_time,omitempty"` 127 | // // LatestConsumeFreeTime int64 `protobuf:"varint,22,opt,name=latest_consume_free_time,json=latestConsumeFreeTime,proto3" json:"latest_consume_free_time,omitempty"` 128 | // // XXX_NoUnkeyedLiteral struct{} `json:"-"` 129 | // // XXX_unrecognized []byte `json:"-"` 130 | // // XXX_sizecache int32 `json:"-"` 131 | // // } 132 | // account = &core.Account{} 133 | // if err := gjson.Unmarshal([]byte(r.Raw), account); err != nil { 134 | // return nil, err 135 | // } 136 | account.Balance = r.Get("balance").String() 137 | account.Symbol = wm.Config.Symbol 138 | account.Required = 1 139 | 140 | return account, nil 141 | } 142 | 143 | // GetAccount Done! 144 | // Function:Query bandwidth information. 145 | // Parameters: 146 | // Account address,converted to a base64 string 147 | // Return value: 148 | func (wm *WalletManager) GetTRXAccount(address string) (account *Account, exist bool, err error) { 149 | address = convertAddrToHex(address) 150 | 151 | params := req.Param{"address": address} 152 | r, err := wm.WalletClient.Call("/wallet/getaccount", params) 153 | if err != nil { 154 | return nil, false, err 155 | } 156 | account = NewAccount(r) 157 | 158 | if len(account.AddressHex) == 0 { 159 | return account, false, nil 160 | } 161 | 162 | return account, true, nil 163 | } 164 | 165 | // CreateAccount Done! 166 | // Function:Create an account. Uses an already activated account to create a new account 167 | // demo:curl -X POST http://127.0.0.1:8090/wallet/createaccount -d ‘ 168 | // { 169 | // “owner_address”:”41d1e7a6bc354106cb410e65ff8b181c600ff14292”, 170 | // “account_address”: “41e552f6487585c2b58bc2c9bb4492bc1f17132cd0” 171 | // }’ 172 | // Parameters: 173 | // Owner_address is an activated account,converted to a hex String; 174 | // account_address is the address of the new account, converted to a hex string, this address needs to be calculated in advance 175 | // Return value:Create account Transaction raw data 176 | func (wm *WalletManager) CreateAccount(ownerAddress, accountAddress string) (txRaw *gjson.Result, err error) { 177 | 178 | ownerAddress = convertAddrToHex(ownerAddress) 179 | accountAddress = convertAddrToHex(accountAddress) 180 | 181 | params := req.Param{"owner_address": ownerAddress, "account_address": accountAddress} 182 | r, err := wm.WalletClient.Call("/wallet/createaccount", params) 183 | if err != nil { 184 | return nil, err 185 | } 186 | 187 | if r.Get("Error").String() != "" { 188 | return nil, errors.New(r.Get("Error").String()) 189 | } 190 | return r, nil 191 | } 192 | 193 | // UpdateAccount Done! 194 | // Function:Modify account name 195 | // demo:curl -X POSThttp://127.0.0.1:8090/wallet/updateaccount -d ‘ 196 | // { 197 | // “account_name”: “0x7570646174654e616d6531353330383933343635353139” , 198 | // ”owner_address”:”41d1e7a6bc354106cb410e65ff8b181c600ff14292” 199 | // }’ 200 | // Parameters: 201 | // account_name is the name of the account, converted into a hex string; 202 | // owner_address is the account address of the name to be modified, converted to a hex string. 203 | // Return value:modified Transaction Object 204 | func (wm *WalletManager) UpdateAccount(accountName, ownerAddress string) (tx *gjson.Result, err error) { 205 | 206 | params := req.Param{ 207 | "account_name": hex.EncodeToString([]byte(accountName)), 208 | "owner_address": convertAddrToHex(ownerAddress), 209 | } 210 | 211 | r, err := wm.WalletClient.Call("/wallet/updateaccount", params) 212 | if err != nil { 213 | return nil, err 214 | } 215 | 216 | if r.Get("raw_data").Map()["contract"].Array()[0].Map()["parameter"].Map()["value"].Map()["owner_address"].String() != convertAddrToHex(ownerAddress) { 217 | return nil, errors.New("UpdateAccount: Update failed") 218 | } 219 | return r, nil 220 | } 221 | -------------------------------------------------------------------------------- /tron/tron.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The openwallet Authors 3 | * This file is part of the openwallet library. 4 | * 5 | * The openwallet library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The openwallet library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package tron 17 | 18 | import ( 19 | "errors" 20 | "fmt" 21 | "path/filepath" 22 | "strings" 23 | 24 | "github.com/blocktree/openwallet/v2/common" 25 | "github.com/blocktree/openwallet/v2/console" 26 | "github.com/blocktree/openwallet/v2/log" 27 | "github.com/blocktree/openwallet/v2/openwallet" 28 | "github.com/blocktree/openwallet/v2/timer" 29 | "github.com/shopspring/decimal" 30 | ) 31 | 32 | //初始化配置流程 33 | func (wm *WalletManager) InitConfigFlow() error { 34 | 35 | wm.Config.InitConfig() 36 | file := filepath.Join(wm.Config.configFilePath, wm.Config.configFileName) 37 | fmt.Printf("You can run 'vim %s' to edit wallet's Config.\n", file) 38 | return nil 39 | } 40 | 41 | //查看配置信息 42 | func (wm *WalletManager) ShowConfig() error { 43 | return wm.Config.PrintConfig() 44 | } 45 | 46 | //GetWalletList 获取钱包列表 47 | func (wm *WalletManager) GetWalletList() error { 48 | 49 | //先加载是否有配置文件 50 | err := wm.LoadConfig() 51 | if err != nil { 52 | return err 53 | } 54 | 55 | list, err := wm.GetWallets() 56 | 57 | if len(list) == 0 { 58 | wm.Log.Info("No any wallets have created.") 59 | return nil 60 | } 61 | 62 | //打印钱包列表 63 | wm.printWalletList(list) 64 | 65 | return nil 66 | } 67 | 68 | //创建钱包流程 69 | func (wm *WalletManager) CreateWalletFlow() error { 70 | 71 | var ( 72 | password string 73 | name string 74 | err error 75 | keyFile string 76 | ) 77 | 78 | wm.GetWalletList() 79 | 80 | //先加载是否有配置文件 81 | err = wm.LoadConfig() 82 | if err != nil { 83 | return err 84 | } 85 | 86 | // 等待用户输入钱包名字 87 | name, err = console.InputText("Enter wallet's name: ", true) 88 | 89 | // 等待用户输入密码 90 | password, err = console.InputPassword(false, 3) 91 | 92 | _, keyFile, err = wm.CreateNewWallet(name, password) 93 | if err != nil { 94 | return err 95 | } 96 | 97 | fmt.Printf("\n") 98 | fmt.Printf("Wallet create successfully, key path: %s\n", keyFile) 99 | 100 | wm.GetWalletList() 101 | 102 | return nil 103 | 104 | } 105 | 106 | //创建地址流程 107 | func (wm *WalletManager) CreateAddressFlow() error { 108 | 109 | //先加载是否有配置文件 110 | err := wm.LoadConfig() 111 | if err != nil { 112 | return err 113 | } 114 | 115 | //查询所有钱包信息 116 | wallets, err := wm.GetWallets() 117 | if err != nil { 118 | fmt.Printf("The node did not create any wallet!\n") 119 | return err 120 | } 121 | 122 | //打印钱包 123 | wm.printWalletList(wallets) 124 | 125 | fmt.Printf("[Please select a wallet account to create address] \n") 126 | 127 | //选择钱包 128 | num, err := console.InputNumber("Enter wallet number: ", true) 129 | if err != nil { 130 | return err 131 | } 132 | 133 | if int(num) >= len(wallets) { 134 | return errors.New("Input number is out of index! ") 135 | } 136 | 137 | account := wallets[num] 138 | 139 | // 输入地址数量 140 | count, err := console.InputNumber("Enter the number of addresses you want: ", false) 141 | if err != nil { 142 | return err 143 | } 144 | 145 | if count > maxAddresNum { 146 | return errors.New(fmt.Sprintf("The number of addresses can not exceed %d", maxAddresNum)) 147 | } 148 | 149 | //输入密码 150 | password, err := console.InputPassword(false, 3) 151 | 152 | log.Std.Info("Start batch creation") 153 | log.Std.Info("-------------------------------------------------") 154 | 155 | filePath, _, err := wm.CreateBatchAddress(account.WalletID, password, count) 156 | if err != nil { 157 | return err 158 | } 159 | 160 | log.Std.Info("-------------------------------------------------") 161 | log.Std.Info("All addresses have created, file path:%s", filePath) 162 | 163 | return nil 164 | } 165 | 166 | //SendTXFlow 发送交易 167 | func (wm *WalletManager) TransferFlow() error { 168 | 169 | //先加载是否有配置文件 170 | err := wm.LoadConfig() 171 | if err != nil { 172 | return err 173 | } 174 | 175 | list, err := wm.GetWallets() 176 | if err != nil { 177 | return err 178 | } 179 | //打印钱包列表 180 | wm.printWalletList(list) 181 | 182 | fmt.Printf("[Please select a wallet to send transaction] \n") 183 | 184 | //选择钱包 185 | num, err := console.InputNumber("Enter wallet No. : ", true) 186 | if err != nil { 187 | return err 188 | } 189 | 190 | if int(num) >= len(list) { 191 | return errors.New("Input number is out of index! ") 192 | } 193 | 194 | wallet := list[num] 195 | 196 | // 等待用户输入发送数量 197 | amount, err := console.InputRealNumber("Enter amount to send: ", true) 198 | if err != nil { 199 | return err 200 | } 201 | 202 | atculAmount, _ := decimal.NewFromString(amount) 203 | balance, _ := decimal.NewFromString(wm.GetWalletBalance(wallet.WalletID)) 204 | 205 | if atculAmount.GreaterThan(balance) { 206 | return errors.New("Input amount is greater than balance! ") 207 | } 208 | 209 | // 等待输入接收着地址 210 | receiver, err := console.InputText("Enter receiver address: ", true) 211 | if err != nil { 212 | return err 213 | } 214 | 215 | //输入密码解锁钱包 216 | password, err := console.InputPassword(false, 3) 217 | if err != nil { 218 | return err 219 | } 220 | _ = password 221 | 222 | /* Transaction */ 223 | 224 | to_address := receiver 225 | owner_address := "" 226 | //amountR, _ := strconv.ParseFloat(amount, 64) // 500 227 | 228 | // 构建交易单 229 | if _, err := wm.CreateTransactionRef(to_address, owner_address, amount); err != nil { 230 | return err 231 | } 232 | // fmt.Println(r) 233 | // 交易单签名 234 | // 广播 235 | // fmt.Printf("Send transaction successfully, TXID:%s\n", txID) 236 | 237 | return nil 238 | } 239 | 240 | //备份钱包流程 241 | func (wm *WalletManager) BackupWalletFlow() error { 242 | 243 | return nil 244 | } 245 | 246 | //RestoreWalletFlow 恢复钱包流程 247 | func (wm *WalletManager) RestoreWalletFlow() error { 248 | 249 | return nil 250 | } 251 | 252 | //汇总钱包流程 253 | 254 | /* 255 | 256 | 汇总执行流程: 257 | 1. 执行启动汇总某个币种命令。 258 | 2. 列出该币种的全部可用钱包信息。 259 | 3. 输入需要汇总的钱包序号数组(以,号分隔)。 260 | 4. 输入每个汇总钱包的密码,完成汇总登记。 261 | 5. 工具启动定时器监听钱包,并输出日志到log文件夹。 262 | 6. 待已登记的汇总钱包达到阀值,发起账户汇总到配置下的地址。 263 | 264 | */ 265 | 266 | // SummaryFollow 汇总流程 267 | func (wm *WalletManager) SummaryFollow() error { 268 | 269 | var ( 270 | endRunning = make(chan bool, 1) 271 | ) 272 | 273 | //先加载是否有配置文件 274 | err := wm.LoadConfig() 275 | if err != nil { 276 | return err 277 | } 278 | 279 | //判断汇总地址是否存在 280 | if len(wm.Config.SumAddress) == 0 { 281 | 282 | return errors.New(fmt.Sprintf("Summary address is not set. Please set it in './conf/%s.ini' \n", Symbol)) 283 | } 284 | 285 | //查询所有钱包信息 286 | wallets, err := wm.GetWallets() 287 | if err != nil { 288 | fmt.Printf("The node did not create any wallet!\n") 289 | return err 290 | } 291 | 292 | //打印钱包 293 | wm.printWalletList(wallets) 294 | 295 | fmt.Printf("[Please select the wallet to summary, and enter the numbers split by ','." + 296 | " For example: 0,1,2,3] \n") 297 | 298 | // 等待用户输入钱包名字 299 | nums, err := console.InputText("Enter the No. group: ", true) 300 | if err != nil { 301 | return err 302 | } 303 | 304 | //分隔数组 305 | array := strings.Split(nums, ",") 306 | 307 | for _, numIput := range array { 308 | if common.IsNumberString(numIput) { 309 | numInt := common.NewString(numIput).Int() 310 | if numInt < len(wallets) { 311 | w := wallets[numInt] 312 | 313 | fmt.Printf("Register summary wallet [%s]-[%s]\n", w.Alias, w.WalletID) 314 | //输入钱包密码完成登记 315 | password, err := console.InputPassword(false, 3) 316 | if err != nil { 317 | return err 318 | } 319 | 320 | //解锁钱包验证密码 321 | _, err = w.HDKey(password) 322 | if err != nil { 323 | wm.Log.Info("The password to unlock wallet is incorrect! ") 324 | continue 325 | } 326 | 327 | w.Password = password 328 | 329 | // wm.AddWalletInSummary(w.WalletID, w) 500 330 | } else { 331 | return errors.New("The input No. out of index! ") 332 | } 333 | } else { 334 | return errors.New("The input No. is not numeric! ") 335 | } 336 | } 337 | 338 | if len(wm.WalletsInSum) == 0 { 339 | return errors.New("Not summary wallets to register! ") 340 | } 341 | 342 | fmt.Printf("The timer for summary has started. Execute by every %v seconds.\n", wm.Config.CycleSeconds.Seconds()) 343 | 344 | //启动钱包汇总程序 345 | sumTimer := timer.NewTask(wm.Config.CycleSeconds, wm.SummaryWallets) 346 | sumTimer.Start() 347 | 348 | <-endRunning 349 | 350 | return nil 351 | } 352 | 353 | //------------------------------------------------------------------------------------------------ 354 | 355 | // //SetConfigFlow 初始化配置流程 356 | // func (wm *WalletManager) SetConfigFlow(subCmd string) error { 357 | // file := wm.Config.configFilePath + wm.Config.configFileName 358 | // fmt.Printf("You can run 'vim %s' to edit %s Config.\n", file, subCmd) 359 | // return nil 360 | // } 361 | 362 | // //ShowConfigInfo 查看配置信息 363 | // func (wm *WalletManager) ShowConfigInfo(subCmd string) error { 364 | // wm.Config.PrintConfig() 365 | // return nil 366 | // } 367 | 368 | //ImportWatchOnlyAddress 导入观测地址 369 | func (wm *WalletManager) ImportWatchOnlyAddress(address ...*openwallet.Address) error { 370 | 371 | return nil 372 | } 373 | 374 | //GetAssetsLogger 获取资产账户日志工具 375 | func (wm *WalletManager) GetAssetsLogger() *log.OWLogger { 376 | return wm.Log 377 | } 378 | 379 | //GetAddressWithBalance 获取地址对应的余额 380 | func (wm *WalletManager) GetAddressWithBalance(address ...*openwallet.Address) error { 381 | 382 | var ( 383 | addressMap = make(map[string]*openwallet.Address) 384 | searchAddrs = make([]string, 0) 385 | ) 386 | 387 | //先加载是否有配置文件 388 | err := wm.LoadConfig() 389 | if err != nil { 390 | return err 391 | } 392 | 393 | for _, address := range address { 394 | searchAddrs = append(searchAddrs, address.Address) 395 | addressMap[address.Address] = address 396 | } 397 | 398 | // //查找核心钱包确认数大于0的 399 | // utxos, err := wm.ListUnspent(0, searchAddrs...) 400 | // if err != nil { 401 | // return err 402 | // } 403 | // log.Debug(utxos) 404 | // //balanceDel := decimal.New(0, 0) 405 | 406 | // //批量插入到本地数据库 407 | // //设置utxo的钱包账户 408 | // for _, utxo := range utxos { 409 | // a := addressMap[utxo.Address] 410 | // a.Balance = utxo.Amount 411 | 412 | // } 413 | 414 | return nil 415 | } 416 | -------------------------------------------------------------------------------- /tron/manager_addrRef.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The openwallet Authors 3 | * This file is part of the openwallet library. 4 | * 5 | * The openwallet library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The openwallet library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package tron 17 | 18 | import ( 19 | "errors" 20 | "fmt" 21 | "log" 22 | "path/filepath" 23 | "time" 24 | 25 | "github.com/asdine/storm/q" 26 | "github.com/blocktree/go-owcdrivers/addressEncoder" 27 | "github.com/blocktree/go-owcrypt" 28 | "github.com/blocktree/openwallet/v2/common" 29 | "github.com/blocktree/openwallet/v2/common/file" 30 | "github.com/blocktree/openwallet/v2/hdkeystore" 31 | "github.com/blocktree/openwallet/v2/openwallet" 32 | "github.com/bndr/gotabulate" 33 | ) 34 | 35 | func createAddressByPkRef(pubKey []byte) (addr string, err error) { 36 | 37 | /* 38 | // First: calculate sha3-256 of PublicKey, get Hash as pkHash 39 | pkHash := owcrypt.Hash(pubKey, 0, owcrypt.HASH_ALG_KECCAK256)[12:32] 40 | // Second: expend 0x41 as prefix of pkHash to mark Tron 41 | address := append([]byte{0x41}, pkHash...) 42 | // Third: double sha256 to generate Checksum 43 | sha256_0_1 := owcrypt.Hash(address, 0, owcrypt.HASh_ALG_DOUBLE_SHA256) 44 | // Fourth: Append checksum to pkHash from sha256_0_1 with the last 4 45 | addrBytes = append(address, sha256_0_1[0:4]...) 46 | */ 47 | cfg := addressEncoder.TRON_mainnetAddress 48 | addr = addressEncoder.AddressEncode(pubKey, cfg) 49 | return addr, nil 50 | } 51 | 52 | // CreateAddressRef Done! 53 | // Function: Create address from a specified private key string 54 | func (wm *WalletManager) CreateAddressRef(key []byte, isPrivate bool) (addr string, err error) { 55 | 56 | var pubKey []byte 57 | 58 | if isPrivate { 59 | r, res := owcrypt.GenPubkey(key, owcrypt.ECC_CURVE_SECP256K1) 60 | if res != owcrypt.SUCCESS { 61 | err := errors.New("Error from owcrypt.GenPubkey: failed") 62 | log.Println(err) 63 | return "", err 64 | } 65 | pubKey = r 66 | } else { 67 | pubKey = key 68 | } 69 | addr, err = createAddressByPkRef(pubKey) 70 | if err != nil { 71 | return "", err 72 | } 73 | return addr, nil 74 | } 75 | 76 | // ValidateAddressRef Done! 77 | //func (wm *WalletManager) ValidateAddressRef(addrBase58 string) (err error) { 78 | // 79 | // addressBytes, err := base58.Decode(addrBase58, base58.BitcoinAlphabet) 80 | // if err != nil { 81 | // return err 82 | // } 83 | // 84 | // l := len(addressBytes) 85 | // addressBytes, checksum := addressBytes[:l-4], addressBytes[l-4:] 86 | // sha256_0_1 := owcrypt.Hash(addressBytes, 0, owcrypt.HASh_ALG_DOUBLE_SHA256) 87 | // 88 | // if hex.EncodeToString(sha256_0_1[0:4]) != hex.EncodeToString(checksum) { 89 | // return errors.New("Address invalid") 90 | // } 91 | // 92 | // return nil 93 | //} 94 | 95 | // ------------------------------------------------------------------------------------------------------------------------------- 96 | 97 | //CreateBatchAddress 批量创建地址 98 | func (wm *WalletManager) CreateBatchAddress(name, password string, count uint64) (string, []*openwallet.Address, error) { 99 | 100 | var ( 101 | synCount uint64 = 20 102 | quit = make(chan struct{}) 103 | done = 0 //完成标记 104 | shouldDone = 0 //需要完成的总数 105 | ) 106 | 107 | //读取钱包 108 | w, err := wm.GetWalletInfo(name) 109 | if err != nil { 110 | log.Println(err) 111 | return "", nil, err 112 | } 113 | 114 | //加载钱包 115 | key, err := w.HDKey(password) 116 | if err != nil { 117 | log.Println(err) 118 | return "", nil, err 119 | } 120 | 121 | timestamp := time.Now() 122 | filename := "address-" + common.TimeFormat("20060102150405", timestamp) + ".txt" 123 | filePath := filepath.Join(wm.Config.addressDir, filename) 124 | 125 | //生产通道 126 | producer := make(chan []*openwallet.Address) 127 | defer close(producer) 128 | 129 | //消费通道 130 | worker := make(chan []*openwallet.Address) 131 | defer close(worker) 132 | 133 | //保存地址过程 134 | saveAddressWork := func(addresses chan []*openwallet.Address, filename string, wallet *openwallet.Wallet) { 135 | 136 | var ( 137 | saveErr error 138 | ) 139 | 140 | for { 141 | //回收创建的地址 142 | getAddrs := <-addresses 143 | 144 | //批量写入数据库 145 | saveErr = wm.saveAddressToDB(getAddrs, wallet) 146 | //数据保存成功才导出文件 147 | if saveErr == nil { 148 | //导出一批地址 149 | wm.exportAddressToFile(getAddrs, filename) 150 | } 151 | 152 | //累计完成的线程数 153 | done++ 154 | if done == shouldDone { 155 | close(quit) //关闭通道,等于给通道传入nil 156 | } 157 | } 158 | } 159 | 160 | /* 开启导出的线程,监听新地址,批量导出 */ 161 | go saveAddressWork(worker, filePath, w) 162 | 163 | /* 计算synCount个线程,内部运行的次数 */ 164 | //每个线程内循环的数量,以synCount个线程并行处理 165 | runCount := count / synCount 166 | otherCount := count % synCount 167 | 168 | if runCount > 0 { 169 | for i := uint64(0); i < synCount; i++ { 170 | 171 | //开始创建地址 172 | fmt.Printf("Start create address thread[%d]\n", i+1) 173 | s := i * runCount 174 | e := (i + 1) * runCount 175 | go wm.createAddressWork(key, producer, name, uint64(timestamp.Unix()), s, e) 176 | 177 | shouldDone++ 178 | } 179 | } 180 | 181 | if otherCount > 0 { 182 | 183 | //开始创建地址 184 | fmt.Println("Start create address thread[REST]") 185 | s := count - otherCount 186 | e := count 187 | go wm.createAddressWork(key, producer, name, uint64(timestamp.Unix()), s, e) 188 | 189 | shouldDone++ 190 | } 191 | 192 | values := make([][]*openwallet.Address, 0) 193 | outputAddress := make([]*openwallet.Address, 0) 194 | 195 | //以下使用生产消费模式 196 | for { 197 | 198 | var activeWorker chan<- []*openwallet.Address 199 | var activeValue []*openwallet.Address 200 | 201 | //当数据队列有数据时,释放顶部,激活消费 202 | if len(values) > 0 { 203 | activeWorker = worker 204 | activeValue = values[0] 205 | 206 | } 207 | 208 | select { 209 | 210 | //生成者不断生成数据,插入到数据队列尾部 211 | case pa := <-producer: 212 | values = append(values, pa) 213 | outputAddress = append(outputAddress, pa...) 214 | //log.Std.Info("completed %d", len(pa)) 215 | fmt.Printf("\tcompleted %d \n", len(pa)) 216 | //当激活消费者后,传输数据给消费者,并把顶部数据出队 217 | case activeWorker <- activeValue: 218 | //log.Std.Info("Get %d", len(activeValue)) 219 | fmt.Printf("\tExport to file: %d\n", len(activeValue)) 220 | values = values[1:] 221 | 222 | case <-quit: 223 | //退出 224 | log.Println("\tAll addresses have been created!") 225 | return filePath, outputAddress, nil 226 | } 227 | } 228 | 229 | // return filePath, outputAddress, nil 230 | } 231 | 232 | //createAddressWork 创建地址过程 233 | func (wm *WalletManager) createAddressWork(k *hdkeystore.HDKey, producer chan<- []*openwallet.Address, walletID string, index, start, end uint64) { 234 | 235 | fmt.Printf("createAddressWork: index=%d, start=%d, end=%d \n", index, start, end) 236 | 237 | runAddress := make([]*openwallet.Address, 0) 238 | 239 | derivedPath := fmt.Sprintf("%s/%d", k.RootPath, index) 240 | childKey, err := k.DerivedKeyWithPath(derivedPath, wm.Config.CurveType) 241 | if err != nil { 242 | producer <- make([]*openwallet.Address, 0) 243 | return 244 | } 245 | 246 | // Generate address 247 | for i := start; i < end; i++ { 248 | 249 | // childKey, err := childKey.GenPrivateChild(uint32(i)) 250 | // priKeyBytes, err := childKey.GetPrivateKeyBytes() 251 | 252 | childKey, err := childKey.GenPublicChild(uint32(i)) 253 | if err != nil { 254 | log.Println(err) 255 | return 256 | } 257 | pubKeyBytes := childKey.GetPublicKeyBytes() 258 | 259 | addrBase58, err := wm.CreateAddressRef(pubKeyBytes, false) 260 | if err != nil { 261 | log.Println(err) 262 | return 263 | } 264 | 265 | address := &openwallet.Address{ 266 | Address: addrBase58, 267 | AccountID: k.KeyID, 268 | HDPath: fmt.Sprintf("%s/%d", derivedPath, i), 269 | CreatedTime: time.Now().Unix(), 270 | Symbol: wm.Config.Symbol, 271 | Index: index, 272 | WatchOnly: false, 273 | } 274 | 275 | runAddress = append(runAddress, address) 276 | } 277 | 278 | //生成完成 279 | producer <- runAddress 280 | 281 | fmt.Println("Producer done!") 282 | } 283 | 284 | //exportAddressToFile 导出地址到文件中 285 | func (wm *WalletManager) exportAddressToFile(addrs []*openwallet.Address, filePath string) { 286 | 287 | var ( 288 | content string 289 | ) 290 | 291 | for _, a := range addrs { 292 | content = content + a.Address + "\n" 293 | } 294 | 295 | file.MkdirAll(wm.Config.addressDir) 296 | file.WriteFile(filePath, []byte(content), true) 297 | } 298 | 299 | //saveAddressToDB 保存地址到数据库 300 | func (wm *WalletManager) saveAddressToDB(addrs []*openwallet.Address, wallet *openwallet.Wallet) error { 301 | db, err := wallet.OpenDB() 302 | if err != nil { 303 | return err 304 | } 305 | defer db.Close() 306 | 307 | tx, err := db.Begin(true) 308 | if err != nil { 309 | return err 310 | } 311 | defer tx.Rollback() 312 | 313 | for _, a := range addrs { 314 | err = tx.Save(a) 315 | if err != nil { 316 | continue 317 | } 318 | } 319 | 320 | return tx.Commit() 321 | } 322 | 323 | //GetAddressesFromLocalDB 从本地数据库 324 | func (wm *WalletManager) GetAddressesFromLocalDB(walletID string, offset, limit int) ([]*openwallet.Address, error) { 325 | 326 | wallet, err := wm.GetWalletInfo(walletID) 327 | if err != nil { 328 | return nil, err 329 | } 330 | 331 | db, err := wallet.OpenDB() 332 | if err != nil { 333 | return nil, err 334 | } 335 | defer db.Close() 336 | 337 | var addresses []*openwallet.Address 338 | if limit > 0 { 339 | query := db.Select(q.Eq("AccountID", walletID)).Limit(limit).Skip(offset).OrderBy("Index", "HDPath") 340 | err = query.Find(&addresses) 341 | } else { 342 | query := db.Select(q.Eq("AccountID", walletID)).Reverse().OrderBy("Index", "HDPath") 343 | err = query.Find(&addresses) 344 | } 345 | 346 | if err != nil { 347 | return nil, err 348 | } 349 | 350 | return addresses, nil 351 | 352 | } 353 | 354 | /* -------------------------------------------------------------------------------------------------------------- */ 355 | 356 | //打印地址列表 357 | func (wm *WalletManager) printAddressList(list []*openwallet.Address) { 358 | 359 | tableInfo := make([][]interface{}, 0) 360 | 361 | for i, w := range list { 362 | // a.Balance = wm.GetWalletBalance(a.AccountID) ?500 363 | tableInfo = append(tableInfo, []interface{}{ 364 | i, w.AccountID, w.Address, w.Index, w.HDPath, w.IsChange, w.ExtParam, 365 | }) 366 | } 367 | 368 | t := gotabulate.Create(tableInfo) 369 | // Set Headers 370 | t.SetHeaders([]string{"No.", "AccountID", "Address", "Index", "HDPath", "IsChange", "Extparam"}) 371 | 372 | //打印信息 373 | fmt.Println(t.Render("simple")) 374 | 375 | } 376 | -------------------------------------------------------------------------------- /openwtester/transcation_assets_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The openwallet Authors 3 | * This file is part of the openwallet library. 4 | * 5 | * The openwallet library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The openwallet library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package openwtester 17 | 18 | import ( 19 | "github.com/blocktree/openwallet/v2/openw" 20 | "testing" 21 | 22 | "github.com/blocktree/openwallet/v2/log" 23 | "github.com/blocktree/openwallet/v2/openwallet" 24 | ) 25 | 26 | func testGetAssetsAccountBalance(tm *openw.WalletManager, walletID, accountID string) { 27 | balance, err := tm.GetAssetsAccountBalance(testApp, walletID, accountID) 28 | if err != nil { 29 | log.Error("GetAssetsAccountBalance failed, unexpected error:", err) 30 | return 31 | } 32 | log.Info("balance:", balance) 33 | } 34 | 35 | func testGetAssetsAccountTokenBalance(tm *openw.WalletManager, walletID, accountID string, contract openwallet.SmartContract) { 36 | balance, err := tm.GetAssetsAccountTokenBalance(testApp, walletID, accountID, contract) 37 | if err != nil { 38 | log.Error("GetAssetsAccountTokenBalance failed, unexpected error:", err) 39 | return 40 | } 41 | log.Info("token balance:", balance.Balance) 42 | } 43 | 44 | func testCreateTransactionStep(tm *openw.WalletManager, walletID, accountID, to, amount, feeRate string, contract *openwallet.SmartContract) (*openwallet.RawTransaction, error) { 45 | 46 | //err := tm.RefreshAssetsAccountBalance(testApp, accountID) 47 | //if err != nil { 48 | // log.Error("RefreshAssetsAccountBalance failed, unexpected error:", err) 49 | // return nil, err 50 | //} 51 | 52 | rawTx, err := tm.CreateTransaction(testApp, walletID, accountID, amount, to, feeRate, "", contract) 53 | 54 | if err != nil { 55 | log.Error("CreateTransaction failed, unexpected error:", err) 56 | return nil, err 57 | } 58 | 59 | return rawTx, nil 60 | } 61 | 62 | func testCreateSummaryTransactionStep( 63 | tm *openw.WalletManager, 64 | walletID, accountID, summaryAddress, minTransfer, retainedBalance, feeRate string, 65 | start, limit int, 66 | contract *openwallet.SmartContract, 67 | feeSupportAccount *openwallet.FeesSupportAccount) ([]*openwallet.RawTransactionWithError, error) { 68 | 69 | rawTxArray, err := tm.CreateSummaryRawTransactionWithError(testApp, walletID, accountID, summaryAddress, minTransfer, 70 | retainedBalance, feeRate, start, limit, contract, feeSupportAccount) 71 | 72 | if err != nil { 73 | log.Error("CreateSummaryTransaction failed, unexpected error:", err) 74 | return nil, err 75 | } 76 | 77 | return rawTxArray, nil 78 | } 79 | 80 | func testSignTransactionStep(tm *openw.WalletManager, rawTx *openwallet.RawTransaction) (*openwallet.RawTransaction, error) { 81 | 82 | _, err := tm.SignTransaction(testApp, rawTx.Account.WalletID, rawTx.Account.AccountID, "12345678", rawTx) 83 | if err != nil { 84 | log.Error("SignTransaction failed, unexpected error:", err) 85 | return nil, err 86 | } 87 | 88 | log.Infof("rawTx: %+v", rawTx) 89 | return rawTx, nil 90 | } 91 | 92 | func testVerifyTransactionStep(tm *openw.WalletManager, rawTx *openwallet.RawTransaction) (*openwallet.RawTransaction, error) { 93 | 94 | //log.Info("rawTx.Signatures:", rawTx.Signatures) 95 | 96 | _, err := tm.VerifyTransaction(testApp, rawTx.Account.WalletID, rawTx.Account.AccountID, rawTx) 97 | if err != nil { 98 | log.Error("VerifyTransaction failed, unexpected error:", err) 99 | return nil, err 100 | } 101 | 102 | log.Infof("rawTx: %+v", rawTx) 103 | return rawTx, nil 104 | } 105 | 106 | func testSubmitTransactionStep(tm *openw.WalletManager, rawTx *openwallet.RawTransaction) (*openwallet.RawTransaction, error) { 107 | 108 | tx, err := tm.SubmitTransaction(testApp, rawTx.Account.WalletID, rawTx.Account.AccountID, rawTx) 109 | if err != nil { 110 | log.Error("SubmitTransaction failed, unexpected error:", err) 111 | return nil, err 112 | } 113 | 114 | log.Std.Info("tx: %+v", tx) 115 | log.Info("wxID:", tx.WxID) 116 | log.Info("txID:", rawTx.TxID) 117 | 118 | return rawTx, nil 119 | } 120 | 121 | func TestTransfer_TRX(t *testing.T) { 122 | tm := testInitWalletManager() 123 | walletID := "WLHdqGtGGZkBHEyXmv1w82s2iZjWJjgWF8" 124 | accountID := "4pF3jRC2XokaaLZWiiLvxXrD8SKRYNuzcVCFkJdu6rkt" 125 | to := "TRJJ9Mq4aMjdmKWpTDJAgbYNoY2P9Facg5" 126 | //to := "TCa3csiJd8Xhx75GPWP9S3kyXX9PonMx7n" 127 | 128 | testGetAssetsAccountBalance(tm, walletID, accountID) 129 | 130 | rawTx, err := testCreateTransactionStep(tm, walletID, accountID, to, "0.1", "", nil) 131 | if err != nil { 132 | return 133 | } 134 | 135 | log.Std.Info("rawTx: %+v", rawTx) 136 | 137 | _, err = testSignTransactionStep(tm, rawTx) 138 | if err != nil { 139 | return 140 | } 141 | 142 | _, err = testVerifyTransactionStep(tm, rawTx) 143 | if err != nil { 144 | return 145 | } 146 | 147 | _, err = testSubmitTransactionStep(tm, rawTx) 148 | if err != nil { 149 | return 150 | } 151 | 152 | } 153 | 154 | func TestTransfer_TRC20(t *testing.T) { 155 | tm := testInitWalletManager() 156 | walletID := "WLHdqGtGGZkBHEyXmv1w82s2iZjWJjgWF8" 157 | accountID := "4pF3jRC2XokaaLZWiiLvxXrD8SKRYNuzcVCFkJdu6rkt" 158 | //to := "TRJJ9Mq4aMjdmKWpTDJAgbYNoY2P9Facg5" 159 | to := "TCa3csiJd8Xhx75GPWP9S3kyXX9PonMx7n" 160 | 161 | contract := openwallet.SmartContract{ 162 | Address: "THvZvKPLHKLJhEFYKiyqj6j8G8nGgfg7ur", 163 | Symbol: "TRX", 164 | Name: "TRONdice", 165 | Token: "DICE", 166 | Decimals: 6, 167 | Protocol: "trc20", 168 | } 169 | 170 | //contract := openwallet.SmartContract{ 171 | // Address: "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", 172 | // Symbol: "TRX", 173 | // Name: "Tether USD", 174 | // Token: "USDT", 175 | // Decimals: 6, 176 | // Protocol: "trc20", 177 | //} 178 | 179 | testGetAssetsAccountBalance(tm, walletID, accountID) 180 | 181 | testGetAssetsAccountTokenBalance(tm, walletID, accountID, contract) 182 | 183 | rawTx, err := testCreateTransactionStep(tm, walletID, accountID, to, "1", "", &contract) 184 | if err != nil { 185 | return 186 | } 187 | //log.Infof("rawHex: %+v", rawTx.RawHex) 188 | _, err = testSignTransactionStep(tm, rawTx) 189 | if err != nil { 190 | return 191 | } 192 | 193 | _, err = testVerifyTransactionStep(tm, rawTx) 194 | if err != nil { 195 | return 196 | } 197 | 198 | //_, err = testSubmitTransactionStep(tm, rawTx) 199 | //if err != nil { 200 | // return 201 | //} 202 | 203 | } 204 | 205 | func TestTransfer_TRC10(t *testing.T) { 206 | tm := testInitWalletManager() 207 | walletID := "WLHdqGtGGZkBHEyXmv1w82s2iZjWJjgWF8" 208 | accountID := "4pF3jRC2XokaaLZWiiLvxXrD8SKRYNuzcVCFkJdu6rkt" 209 | //to := "TRJJ9Mq4aMjdmKWpTDJAgbYNoY2P9Facg5" 210 | to := "TCa3csiJd8Xhx75GPWP9S3kyXX9PonMx7n" 211 | 212 | contract := openwallet.SmartContract{ 213 | Address: "1002000", 214 | Symbol: "TRX", 215 | Name: "BitTorrent", 216 | Token: "BTT", 217 | Decimals: 6, 218 | Protocol: "trc10", 219 | } 220 | 221 | testGetAssetsAccountBalance(tm, walletID, accountID) 222 | 223 | testGetAssetsAccountTokenBalance(tm, walletID, accountID, contract) 224 | 225 | rawTx, err := testCreateTransactionStep(tm, walletID, accountID, to, "0.001", "", &contract) 226 | if err != nil { 227 | return 228 | } 229 | log.Infof("rawHex: %+v", rawTx.RawHex) 230 | _, err = testSignTransactionStep(tm, rawTx) 231 | if err != nil { 232 | return 233 | } 234 | 235 | _, err = testVerifyTransactionStep(tm, rawTx) 236 | if err != nil { 237 | return 238 | } 239 | 240 | //_, err = testSubmitTransactionStep(tm, rawTx) 241 | //if err != nil { 242 | // return 243 | //} 244 | 245 | } 246 | 247 | func TestSummary(t *testing.T) { 248 | tm := testInitWalletManager() 249 | walletID := "WGVsUfTTVaCwAMRTqeJiDQsZ3vrWp9DzMA" 250 | //accountID := "4pF3jRC2XokaaLZWiiLvxXrD8SKRYNuzcVCFkJdu6rkt" 251 | accountID := "C31rHUi8FJpwhWC2KTb5mMx9LUCSRpNnS1cG2QVMixYN" 252 | summaryAddress := "TRJJ9Mq4aMjdmKWpTDJAgbYNoY2P9Facg5" 253 | //summaryAddress := "TS11WZyPnT8qidwREcR8VDzNULCXxFeBMa" 254 | 255 | testGetAssetsAccountBalance(tm, walletID, accountID) 256 | 257 | rawTxArray, err := testCreateSummaryTransactionStep(tm, walletID, accountID, 258 | summaryAddress, "", "", "", 259 | 0, 100, nil, nil) 260 | if err != nil { 261 | log.Errorf("CreateSummaryTransaction failed, unexpected error: %v", err) 262 | return 263 | } 264 | 265 | //执行汇总交易 266 | for _, rawTxWithErr := range rawTxArray { 267 | 268 | if rawTxWithErr.Error != nil { 269 | log.Error(rawTxWithErr.Error.Error()) 270 | continue 271 | } 272 | 273 | _, err = testSignTransactionStep(tm, rawTxWithErr.RawTx) 274 | if err != nil { 275 | return 276 | } 277 | 278 | _, err = testVerifyTransactionStep(tm, rawTxWithErr.RawTx) 279 | if err != nil { 280 | return 281 | } 282 | 283 | _, err = testSubmitTransactionStep(tm, rawTxWithErr.RawTx) 284 | if err != nil { 285 | return 286 | } 287 | } 288 | 289 | } 290 | 291 | func TestSummary_TRC10(t *testing.T) { 292 | tm := testInitWalletManager() 293 | walletID := "WGVsUfTTVaCwAMRTqeJiDQsZ3vrWp9DzMA" 294 | //accountID := "4pF3jRC2XokaaLZWiiLvxXrD8SKRYNuzcVCFkJdu6rkt" 295 | accountID := "C31rHUi8FJpwhWC2KTb5mMx9LUCSRpNnS1cG2QVMixYN" 296 | summaryAddress := "TRJJ9Mq4aMjdmKWpTDJAgbYNoY2P9Facg5" 297 | //summaryAddress := "TS11WZyPnT8qidwREcR8VDzNULCXxFeBMa" 298 | 299 | feesSupport := openwallet.FeesSupportAccount{ 300 | AccountID: "5Tm3sqFap329wj3Du4DVXMkjAe85FVH3MaB6HSV8joj1", 301 | FixSupportAmount: "1", 302 | //FeesSupportScale: "1.3", 303 | } 304 | 305 | contract := openwallet.SmartContract{ 306 | Address: "1002000", 307 | Symbol: "TRX", 308 | Name: "BitTorrent", 309 | Token: "BTT", 310 | Decimals: 6, 311 | Protocol: "trc10", 312 | } 313 | 314 | testGetAssetsAccountBalance(tm, walletID, accountID) 315 | 316 | testGetAssetsAccountTokenBalance(tm, walletID, accountID, contract) 317 | 318 | rawTxArray, err := testCreateSummaryTransactionStep(tm, walletID, accountID, 319 | summaryAddress, "", "", "", 320 | 0, 100, &contract, &feesSupport) 321 | if err != nil { 322 | log.Errorf("CreateSummaryTransaction failed, unexpected error: %v", err) 323 | return 324 | } 325 | 326 | //执行汇总交易 327 | for _, rawTxWithErr := range rawTxArray { 328 | 329 | if rawTxWithErr.Error != nil { 330 | log.Error(rawTxWithErr.Error.Error()) 331 | continue 332 | } 333 | 334 | _, err = testSignTransactionStep(tm, rawTxWithErr.RawTx) 335 | if err != nil { 336 | return 337 | } 338 | 339 | _, err = testVerifyTransactionStep(tm, rawTxWithErr.RawTx) 340 | if err != nil { 341 | return 342 | } 343 | 344 | _, err = testSubmitTransactionStep(tm, rawTxWithErr.RawTx) 345 | if err != nil { 346 | return 347 | } 348 | } 349 | 350 | } 351 | 352 | func TestSummary_TRC20(t *testing.T) { 353 | tm := testInitWalletManager() 354 | walletID := "WGVsUfTTVaCwAMRTqeJiDQsZ3vrWp9DzMA" 355 | //accountID := "4pF3jRC2XokaaLZWiiLvxXrD8SKRYNuzcVCFkJdu6rkt" 356 | accountID := "C31rHUi8FJpwhWC2KTb5mMx9LUCSRpNnS1cG2QVMixYN" 357 | summaryAddress := "TRJJ9Mq4aMjdmKWpTDJAgbYNoY2P9Facg5" 358 | //summaryAddress := "TS11WZyPnT8qidwREcR8VDzNULCXxFeBMa" 359 | 360 | feesSupport := openwallet.FeesSupportAccount{ 361 | AccountID: "5Tm3sqFap329wj3Du4DVXMkjAe85FVH3MaB6HSV8joj1", 362 | FixSupportAmount: "0.5", 363 | //FeesSupportScale: "1.3", 364 | } 365 | 366 | contract := openwallet.SmartContract{ 367 | Address: "THvZvKPLHKLJhEFYKiyqj6j8G8nGgfg7ur", 368 | Symbol: "TRX", 369 | Name: "TRONdice", 370 | Token: "DICE", 371 | Decimals: 6, 372 | Protocol: "trc20", 373 | } 374 | 375 | //contract := openwallet.SmartContract{ 376 | // Address: "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", 377 | // Symbol: "TRX", 378 | // Name: "Tether USD", 379 | // Token: "USDT", 380 | // Decimals: 6, 381 | // Protocol: "trc20", 382 | //} 383 | 384 | testGetAssetsAccountBalance(tm, walletID, accountID) 385 | 386 | testGetAssetsAccountTokenBalance(tm, walletID, accountID, contract) 387 | 388 | rawTxArray, err := testCreateSummaryTransactionStep(tm, walletID, accountID, 389 | summaryAddress, "", "", "", 390 | 0, 100, &contract, &feesSupport) 391 | if err != nil { 392 | log.Errorf("CreateSummaryTransaction failed, unexpected error: %v", err) 393 | return 394 | } 395 | 396 | //执行汇总交易 397 | for _, rawTxWithErr := range rawTxArray { 398 | 399 | if rawTxWithErr.Error != nil { 400 | log.Error(rawTxWithErr.Error.Error()) 401 | continue 402 | } 403 | 404 | _, err = testSignTransactionStep(tm, rawTxWithErr.RawTx) 405 | if err != nil { 406 | return 407 | } 408 | 409 | _, err = testVerifyTransactionStep(tm, rawTxWithErr.RawTx) 410 | if err != nil { 411 | return 412 | } 413 | 414 | _, err = testSubmitTransactionStep(tm, rawTxWithErr.RawTx) 415 | if err != nil { 416 | return 417 | } 418 | } 419 | 420 | } 421 | -------------------------------------------------------------------------------- /tron/grpc-gateway/core/Discover.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // source: core/Discover.proto 3 | 4 | package core 5 | 6 | import ( 7 | fmt "fmt" 8 | proto "github.com/golang/protobuf/proto" 9 | math "math" 10 | ) 11 | 12 | // Reference imports to suppress errors if they are not otherwise used. 13 | var _ = proto.Marshal 14 | var _ = fmt.Errorf 15 | var _ = math.Inf 16 | 17 | // This is a compile-time assertion to ensure that this generated file 18 | // is compatible with the proto package it is being compiled against. 19 | // A compilation error at this line likely means your copy of the 20 | // proto package needs to be updated. 21 | const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package 22 | 23 | type Endpoint struct { 24 | Address []byte `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` 25 | Port int32 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"` 26 | NodeId []byte `protobuf:"bytes,3,opt,name=nodeId,proto3" json:"nodeId,omitempty"` 27 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 28 | XXX_unrecognized []byte `json:"-"` 29 | XXX_sizecache int32 `json:"-"` 30 | } 31 | 32 | func (m *Endpoint) Reset() { *m = Endpoint{} } 33 | func (m *Endpoint) String() string { return proto.CompactTextString(m) } 34 | func (*Endpoint) ProtoMessage() {} 35 | func (*Endpoint) Descriptor() ([]byte, []int) { 36 | return fileDescriptor_0471e8a4adb61f9e, []int{0} 37 | } 38 | 39 | func (m *Endpoint) XXX_Unmarshal(b []byte) error { 40 | return xxx_messageInfo_Endpoint.Unmarshal(m, b) 41 | } 42 | func (m *Endpoint) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 43 | return xxx_messageInfo_Endpoint.Marshal(b, m, deterministic) 44 | } 45 | func (m *Endpoint) XXX_Merge(src proto.Message) { 46 | xxx_messageInfo_Endpoint.Merge(m, src) 47 | } 48 | func (m *Endpoint) XXX_Size() int { 49 | return xxx_messageInfo_Endpoint.Size(m) 50 | } 51 | func (m *Endpoint) XXX_DiscardUnknown() { 52 | xxx_messageInfo_Endpoint.DiscardUnknown(m) 53 | } 54 | 55 | var xxx_messageInfo_Endpoint proto.InternalMessageInfo 56 | 57 | func (m *Endpoint) GetAddress() []byte { 58 | if m != nil { 59 | return m.Address 60 | } 61 | return nil 62 | } 63 | 64 | func (m *Endpoint) GetPort() int32 { 65 | if m != nil { 66 | return m.Port 67 | } 68 | return 0 69 | } 70 | 71 | func (m *Endpoint) GetNodeId() []byte { 72 | if m != nil { 73 | return m.NodeId 74 | } 75 | return nil 76 | } 77 | 78 | type PingMessage struct { 79 | From *Endpoint `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` 80 | To *Endpoint `protobuf:"bytes,2,opt,name=to,proto3" json:"to,omitempty"` 81 | Version int32 `protobuf:"varint,3,opt,name=version,proto3" json:"version,omitempty"` 82 | Timestamp int64 `protobuf:"varint,4,opt,name=timestamp,proto3" json:"timestamp,omitempty"` 83 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 84 | XXX_unrecognized []byte `json:"-"` 85 | XXX_sizecache int32 `json:"-"` 86 | } 87 | 88 | func (m *PingMessage) Reset() { *m = PingMessage{} } 89 | func (m *PingMessage) String() string { return proto.CompactTextString(m) } 90 | func (*PingMessage) ProtoMessage() {} 91 | func (*PingMessage) Descriptor() ([]byte, []int) { 92 | return fileDescriptor_0471e8a4adb61f9e, []int{1} 93 | } 94 | 95 | func (m *PingMessage) XXX_Unmarshal(b []byte) error { 96 | return xxx_messageInfo_PingMessage.Unmarshal(m, b) 97 | } 98 | func (m *PingMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 99 | return xxx_messageInfo_PingMessage.Marshal(b, m, deterministic) 100 | } 101 | func (m *PingMessage) XXX_Merge(src proto.Message) { 102 | xxx_messageInfo_PingMessage.Merge(m, src) 103 | } 104 | func (m *PingMessage) XXX_Size() int { 105 | return xxx_messageInfo_PingMessage.Size(m) 106 | } 107 | func (m *PingMessage) XXX_DiscardUnknown() { 108 | xxx_messageInfo_PingMessage.DiscardUnknown(m) 109 | } 110 | 111 | var xxx_messageInfo_PingMessage proto.InternalMessageInfo 112 | 113 | func (m *PingMessage) GetFrom() *Endpoint { 114 | if m != nil { 115 | return m.From 116 | } 117 | return nil 118 | } 119 | 120 | func (m *PingMessage) GetTo() *Endpoint { 121 | if m != nil { 122 | return m.To 123 | } 124 | return nil 125 | } 126 | 127 | func (m *PingMessage) GetVersion() int32 { 128 | if m != nil { 129 | return m.Version 130 | } 131 | return 0 132 | } 133 | 134 | func (m *PingMessage) GetTimestamp() int64 { 135 | if m != nil { 136 | return m.Timestamp 137 | } 138 | return 0 139 | } 140 | 141 | type PongMessage struct { 142 | From *Endpoint `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` 143 | Echo int32 `protobuf:"varint,2,opt,name=echo,proto3" json:"echo,omitempty"` 144 | Timestamp int64 `protobuf:"varint,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"` 145 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 146 | XXX_unrecognized []byte `json:"-"` 147 | XXX_sizecache int32 `json:"-"` 148 | } 149 | 150 | func (m *PongMessage) Reset() { *m = PongMessage{} } 151 | func (m *PongMessage) String() string { return proto.CompactTextString(m) } 152 | func (*PongMessage) ProtoMessage() {} 153 | func (*PongMessage) Descriptor() ([]byte, []int) { 154 | return fileDescriptor_0471e8a4adb61f9e, []int{2} 155 | } 156 | 157 | func (m *PongMessage) XXX_Unmarshal(b []byte) error { 158 | return xxx_messageInfo_PongMessage.Unmarshal(m, b) 159 | } 160 | func (m *PongMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 161 | return xxx_messageInfo_PongMessage.Marshal(b, m, deterministic) 162 | } 163 | func (m *PongMessage) XXX_Merge(src proto.Message) { 164 | xxx_messageInfo_PongMessage.Merge(m, src) 165 | } 166 | func (m *PongMessage) XXX_Size() int { 167 | return xxx_messageInfo_PongMessage.Size(m) 168 | } 169 | func (m *PongMessage) XXX_DiscardUnknown() { 170 | xxx_messageInfo_PongMessage.DiscardUnknown(m) 171 | } 172 | 173 | var xxx_messageInfo_PongMessage proto.InternalMessageInfo 174 | 175 | func (m *PongMessage) GetFrom() *Endpoint { 176 | if m != nil { 177 | return m.From 178 | } 179 | return nil 180 | } 181 | 182 | func (m *PongMessage) GetEcho() int32 { 183 | if m != nil { 184 | return m.Echo 185 | } 186 | return 0 187 | } 188 | 189 | func (m *PongMessage) GetTimestamp() int64 { 190 | if m != nil { 191 | return m.Timestamp 192 | } 193 | return 0 194 | } 195 | 196 | type FindNeighbours struct { 197 | From *Endpoint `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` 198 | TargetId []byte `protobuf:"bytes,2,opt,name=targetId,proto3" json:"targetId,omitempty"` 199 | Timestamp int64 `protobuf:"varint,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"` 200 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 201 | XXX_unrecognized []byte `json:"-"` 202 | XXX_sizecache int32 `json:"-"` 203 | } 204 | 205 | func (m *FindNeighbours) Reset() { *m = FindNeighbours{} } 206 | func (m *FindNeighbours) String() string { return proto.CompactTextString(m) } 207 | func (*FindNeighbours) ProtoMessage() {} 208 | func (*FindNeighbours) Descriptor() ([]byte, []int) { 209 | return fileDescriptor_0471e8a4adb61f9e, []int{3} 210 | } 211 | 212 | func (m *FindNeighbours) XXX_Unmarshal(b []byte) error { 213 | return xxx_messageInfo_FindNeighbours.Unmarshal(m, b) 214 | } 215 | func (m *FindNeighbours) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 216 | return xxx_messageInfo_FindNeighbours.Marshal(b, m, deterministic) 217 | } 218 | func (m *FindNeighbours) XXX_Merge(src proto.Message) { 219 | xxx_messageInfo_FindNeighbours.Merge(m, src) 220 | } 221 | func (m *FindNeighbours) XXX_Size() int { 222 | return xxx_messageInfo_FindNeighbours.Size(m) 223 | } 224 | func (m *FindNeighbours) XXX_DiscardUnknown() { 225 | xxx_messageInfo_FindNeighbours.DiscardUnknown(m) 226 | } 227 | 228 | var xxx_messageInfo_FindNeighbours proto.InternalMessageInfo 229 | 230 | func (m *FindNeighbours) GetFrom() *Endpoint { 231 | if m != nil { 232 | return m.From 233 | } 234 | return nil 235 | } 236 | 237 | func (m *FindNeighbours) GetTargetId() []byte { 238 | if m != nil { 239 | return m.TargetId 240 | } 241 | return nil 242 | } 243 | 244 | func (m *FindNeighbours) GetTimestamp() int64 { 245 | if m != nil { 246 | return m.Timestamp 247 | } 248 | return 0 249 | } 250 | 251 | type Neighbours struct { 252 | From *Endpoint `protobuf:"bytes,1,opt,name=from,proto3" json:"from,omitempty"` 253 | Neighbours []*Endpoint `protobuf:"bytes,2,rep,name=neighbours,proto3" json:"neighbours,omitempty"` 254 | Timestamp int64 `protobuf:"varint,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"` 255 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 256 | XXX_unrecognized []byte `json:"-"` 257 | XXX_sizecache int32 `json:"-"` 258 | } 259 | 260 | func (m *Neighbours) Reset() { *m = Neighbours{} } 261 | func (m *Neighbours) String() string { return proto.CompactTextString(m) } 262 | func (*Neighbours) ProtoMessage() {} 263 | func (*Neighbours) Descriptor() ([]byte, []int) { 264 | return fileDescriptor_0471e8a4adb61f9e, []int{4} 265 | } 266 | 267 | func (m *Neighbours) XXX_Unmarshal(b []byte) error { 268 | return xxx_messageInfo_Neighbours.Unmarshal(m, b) 269 | } 270 | func (m *Neighbours) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 271 | return xxx_messageInfo_Neighbours.Marshal(b, m, deterministic) 272 | } 273 | func (m *Neighbours) XXX_Merge(src proto.Message) { 274 | xxx_messageInfo_Neighbours.Merge(m, src) 275 | } 276 | func (m *Neighbours) XXX_Size() int { 277 | return xxx_messageInfo_Neighbours.Size(m) 278 | } 279 | func (m *Neighbours) XXX_DiscardUnknown() { 280 | xxx_messageInfo_Neighbours.DiscardUnknown(m) 281 | } 282 | 283 | var xxx_messageInfo_Neighbours proto.InternalMessageInfo 284 | 285 | func (m *Neighbours) GetFrom() *Endpoint { 286 | if m != nil { 287 | return m.From 288 | } 289 | return nil 290 | } 291 | 292 | func (m *Neighbours) GetNeighbours() []*Endpoint { 293 | if m != nil { 294 | return m.Neighbours 295 | } 296 | return nil 297 | } 298 | 299 | func (m *Neighbours) GetTimestamp() int64 { 300 | if m != nil { 301 | return m.Timestamp 302 | } 303 | return 0 304 | } 305 | 306 | type BackupMessage struct { 307 | Flag bool `protobuf:"varint,1,opt,name=flag,proto3" json:"flag,omitempty"` 308 | Priority int32 `protobuf:"varint,2,opt,name=priority,proto3" json:"priority,omitempty"` 309 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 310 | XXX_unrecognized []byte `json:"-"` 311 | XXX_sizecache int32 `json:"-"` 312 | } 313 | 314 | func (m *BackupMessage) Reset() { *m = BackupMessage{} } 315 | func (m *BackupMessage) String() string { return proto.CompactTextString(m) } 316 | func (*BackupMessage) ProtoMessage() {} 317 | func (*BackupMessage) Descriptor() ([]byte, []int) { 318 | return fileDescriptor_0471e8a4adb61f9e, []int{5} 319 | } 320 | 321 | func (m *BackupMessage) XXX_Unmarshal(b []byte) error { 322 | return xxx_messageInfo_BackupMessage.Unmarshal(m, b) 323 | } 324 | func (m *BackupMessage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 325 | return xxx_messageInfo_BackupMessage.Marshal(b, m, deterministic) 326 | } 327 | func (m *BackupMessage) XXX_Merge(src proto.Message) { 328 | xxx_messageInfo_BackupMessage.Merge(m, src) 329 | } 330 | func (m *BackupMessage) XXX_Size() int { 331 | return xxx_messageInfo_BackupMessage.Size(m) 332 | } 333 | func (m *BackupMessage) XXX_DiscardUnknown() { 334 | xxx_messageInfo_BackupMessage.DiscardUnknown(m) 335 | } 336 | 337 | var xxx_messageInfo_BackupMessage proto.InternalMessageInfo 338 | 339 | func (m *BackupMessage) GetFlag() bool { 340 | if m != nil { 341 | return m.Flag 342 | } 343 | return false 344 | } 345 | 346 | func (m *BackupMessage) GetPriority() int32 { 347 | if m != nil { 348 | return m.Priority 349 | } 350 | return 0 351 | } 352 | 353 | func init() { 354 | proto.RegisterType((*Endpoint)(nil), "protocol.Endpoint") 355 | proto.RegisterType((*PingMessage)(nil), "protocol.PingMessage") 356 | proto.RegisterType((*PongMessage)(nil), "protocol.PongMessage") 357 | proto.RegisterType((*FindNeighbours)(nil), "protocol.FindNeighbours") 358 | proto.RegisterType((*Neighbours)(nil), "protocol.Neighbours") 359 | proto.RegisterType((*BackupMessage)(nil), "protocol.BackupMessage") 360 | } 361 | 362 | func init() { proto.RegisterFile("core/Discover.proto", fileDescriptor_0471e8a4adb61f9e) } 363 | 364 | var fileDescriptor_0471e8a4adb61f9e = []byte{ 365 | // 361 bytes of a gzipped FileDescriptorProto 366 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x92, 0x4f, 0x4b, 0xf3, 0x40, 367 | 0x10, 0xc6, 0xc9, 0x9f, 0xf6, 0xcd, 0x3b, 0xed, 0xfb, 0x0a, 0x2b, 0x48, 0x10, 0x0f, 0x21, 0x07, 368 | 0xa9, 0x07, 0x13, 0xa8, 0x1f, 0x40, 0x28, 0x5a, 0xe8, 0x41, 0x29, 0x39, 0x7a, 0xdb, 0x26, 0xdb, 369 | 0xed, 0x62, 0xb3, 0x13, 0x76, 0xb7, 0x95, 0x7e, 0x01, 0xef, 0x7e, 0x63, 0xc9, 0xda, 0xad, 0x7f, 370 | 0x50, 0xaa, 0x9e, 0x32, 0x4f, 0xe6, 0x49, 0x7e, 0xcf, 0x0c, 0x03, 0x87, 0x25, 0x2a, 0x96, 0x5f, 371 | 0x09, 0x5d, 0xe2, 0x9a, 0xa9, 0xac, 0x51, 0x68, 0x90, 0x44, 0xf6, 0x51, 0xe2, 0x32, 0x9d, 0x42, 372 | 0x74, 0x2d, 0xab, 0x06, 0x85, 0x34, 0x24, 0x86, 0x3f, 0xb4, 0xaa, 0x14, 0xd3, 0x3a, 0xf6, 0x12, 373 | 0x6f, 0xd0, 0x2f, 0x9c, 0x24, 0x04, 0xc2, 0x06, 0x95, 0x89, 0xfd, 0xc4, 0x1b, 0x74, 0x0a, 0x5b, 374 | 0x93, 0x23, 0xe8, 0x4a, 0xac, 0xd8, 0xa4, 0x8a, 0x03, 0x6b, 0xde, 0xaa, 0xf4, 0xc9, 0x83, 0xde, 375 | 0x54, 0x48, 0x7e, 0xc3, 0xb4, 0xa6, 0x9c, 0x91, 0x53, 0x08, 0xe7, 0x0a, 0x6b, 0xfb, 0xcb, 0xde, 376 | 0x90, 0x64, 0x0e, 0x9d, 0x39, 0x6e, 0x61, 0xfb, 0x24, 0x05, 0xdf, 0xa0, 0x25, 0x7c, 0xee, 0xf2, 377 | 0x0d, 0xb6, 0x09, 0xd7, 0x4c, 0x69, 0x81, 0xd2, 0x42, 0x3b, 0x85, 0x93, 0xe4, 0x04, 0xfe, 0x1a, 378 | 0x51, 0x33, 0x6d, 0x68, 0xdd, 0xc4, 0x61, 0xe2, 0x0d, 0x82, 0xe2, 0xf5, 0x45, 0xca, 0xa1, 0x37, 379 | 0xc5, 0x9f, 0x47, 0x22, 0x10, 0xb2, 0x72, 0x81, 0x6e, 0xec, 0xb6, 0x7e, 0x0f, 0x0a, 0x3e, 0x82, 380 | 0x14, 0xfc, 0x1f, 0x0b, 0x59, 0xdd, 0x32, 0xc1, 0x17, 0x33, 0x5c, 0x29, 0xfd, 0x6d, 0xd6, 0x31, 381 | 0x44, 0x86, 0x2a, 0xce, 0xcc, 0xa4, 0xb2, 0xbc, 0x7e, 0xb1, 0xd3, 0x7b, 0x98, 0x8f, 0x1e, 0xc0, 382 | 0x2f, 0x80, 0x43, 0x00, 0xb9, 0xfb, 0x2a, 0xf6, 0x93, 0xe0, 0x0b, 0xf7, 0x1b, 0xd7, 0x9e, 0x20, 383 | 0x97, 0xf0, 0x6f, 0x44, 0xcb, 0xfb, 0x55, 0xe3, 0xf6, 0x4c, 0x20, 0x9c, 0x2f, 0x29, 0xb7, 0x51, 384 | 0xa2, 0xc2, 0xd6, 0xed, 0x9c, 0x8d, 0x12, 0xa8, 0x84, 0xd9, 0x6c, 0xf7, 0xba, 0xd3, 0xa3, 0x31, 385 | 0x1c, 0xa0, 0xe2, 0x99, 0x51, 0x28, 0x5f, 0x82, 0xe8, 0x51, 0xe4, 0x2e, 0xf7, 0xee, 0x8c, 0x0b, 386 | 0xb3, 0x58, 0xcd, 0xb2, 0x12, 0xeb, 0xbc, 0x75, 0xb8, 0xa4, 0x39, 0x57, 0x4d, 0x79, 0xce, 0xa9, 387 | 0x61, 0x0f, 0x74, 0x93, 0xb7, 0xd7, 0x3e, 0xeb, 0xda, 0xde, 0xc5, 0x73, 0x00, 0x00, 0x00, 0xff, 388 | 0xff, 0x4a, 0x9a, 0x1b, 0xf5, 0xfc, 0x02, 0x00, 0x00, 389 | } 390 | -------------------------------------------------------------------------------- /tron/models.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 The openwallet Authors 3 | * This file is part of the openwallet library. 4 | * 5 | * The openwallet library is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * The openwallet library is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser General Public License for more details. 14 | */ 15 | 16 | package tron 17 | 18 | import ( 19 | "encoding/hex" 20 | "fmt" 21 | "github.com/blocktree/openwallet/v2/common" 22 | "github.com/blocktree/openwallet/v2/crypto" 23 | "github.com/blocktree/openwallet/v2/openwallet" 24 | "github.com/shopspring/decimal" 25 | "github.com/tidwall/gjson" 26 | "math/big" 27 | ) 28 | 29 | type Block struct { 30 | /* 31 | { 32 | "blockID":"000000000035e1c0f60afaa8387fd17fd9b84fe4381265ff084d739f814558ea", 33 | "block_header":{ 34 | "raw_data":{"number":3531200, 35 | "txTrieRoot":"9d98f6cbbde8302774ab87c003831333e132c89e00009cb1f7da35e1e59ae8ca", 36 | "witness_address":"41d1dbde8b8f71b48655bec4f6bb532a0142b88bc0", 37 | "parentHash":"000000000035e1bfb3b6f244e5316ce408aa8cea4c348eabe2545247f5a4600c", 38 | "version":3, 39 | "timestamp":1540545240000}, 40 | "witness_signature":"6ceedcacd8d0111b48eb4131484de3d13f27a2f4bd8156279d03d4208690158e20a641b77d900e026ee33adc328f9ec674f6483ea7b1ca5a27fa24d7fb23964100" 41 | }, 42 | "transactions":[ 43 | {"ret":[{"contractRet":"SUCCESS"}], 44 | "signature":["40aa520f01cebf12948615b9c5a5df5fe7d57e1a7f662d53907b4aa14f647a3a47be2a097fdb58159d0bee7eb1ff0a15ac738f24643fe5114cab8ec0d52cc04d01"], 45 | "txID":"ac005b0a195a130914821a6c28db1eec44b4ec3a2358388ceb6c87b677866f1f", 46 | "raw_data":{ 47 | "contract":[ 48 | {"parameter":{"value":{"amount":1,"asset_name":"48756f6269546f6b656e","owner_address":"416b201fb7b9f2b97bbdaf5e0920191229767c30ee","to_address":"412451d09536fca47760ea6513372bbbbef8583105"}, 49 | "type_url":"type.googleapis.com/protocol.TransferAssetContract"}, 50 | "type":"TransferAssetContract"} 51 | ], 52 | "ref_block_bytes":"e1be", 53 | "ref_block_hash":"8dbf5f0cf4c324f2", 54 | "expiration":1540545294000, 55 | "timestamp":1540545235358} 56 | }, 57 | ...] 58 | } 59 | */ 60 | Hash string // 这里采用 BlockID 61 | tx []*Transaction 62 | Previousblockhash string 63 | Height uint64 `storm:"id"` 64 | Version uint64 65 | Time int64 66 | Fork bool 67 | txHash []string 68 | // Merkleroot string 69 | //Confirmations uint64 70 | } 71 | 72 | func NewBlock(json *gjson.Result, isTestnet bool) *Block { 73 | 74 | header := gjson.Get(json.Raw, "block_header").Get("raw_data") 75 | // 解析json 76 | b := &Block{} 77 | b.Hash = gjson.Get(json.Raw, "blockID").String() 78 | b.Previousblockhash = header.Get("parentHash").String() 79 | b.Height = header.Get("number").Uint() 80 | b.Version = header.Get("version").Uint() 81 | b.Time = header.Get("timestamp").Int() 82 | 83 | txs := make([]*Transaction, 0) 84 | for _, x := range gjson.Get(json.Raw, "transactions").Array() { 85 | tx := NewTransaction(&x, b.Hash, b.Height, b.Time, isTestnet) 86 | txs = append(txs, tx) 87 | } 88 | b.tx = txs 89 | return b 90 | } 91 | 92 | func (block *Block) GetHeight() uint64 { 93 | return block.Height 94 | } 95 | 96 | func (block *Block) GetBlockHashID() string { 97 | return block.Hash 98 | } 99 | 100 | func (block *Block) GetTransactions() []*Transaction { 101 | return block.tx 102 | } 103 | 104 | //状态 105 | const ( 106 | SUCCESS = "SUCCESS" 107 | ) 108 | 109 | //交易单类型 110 | const ( 111 | TransferContract = "TransferContract" 112 | TransferAssetContract = "TransferAssetContract" 113 | TriggerSmartContract = "TriggerSmartContract" 114 | ) 115 | 116 | type Result struct { 117 | Ret string 118 | Fee int64 119 | ContractRet string 120 | } 121 | 122 | func NewResult(json gjson.Result) *Result { 123 | // 解析json 124 | b := &Result{} 125 | b.Ret = gjson.Get(json.Raw, "ret").String() 126 | b.Fee = gjson.Get(json.Raw, "fee").Int() 127 | b.ContractRet = gjson.Get(json.Raw, "contractRet").String() 128 | return b 129 | } 130 | 131 | type Contract struct { 132 | TxID string 133 | BlockHash string 134 | BlockHeight uint64 135 | BlockTime int64 136 | Type string 137 | Parameter gjson.Result 138 | Provider []byte 139 | ContractName []byte 140 | From string 141 | To string 142 | Amount *big.Int 143 | ContractAddress string 144 | SourceKey string 145 | ContractRet string 146 | Protocol string 147 | } 148 | 149 | func NewContract(json gjson.Result, isTestnet bool) *Contract { 150 | 151 | var err error 152 | 153 | // 解析json 154 | b := &Contract{} 155 | b.Type = gjson.Get(json.Raw, "type").String() 156 | b.Parameter = gjson.Get(json.Raw, "parameter") 157 | switch b.Type { 158 | case TransferContract: //TRX 159 | 160 | b.From, err = EncodeAddress(b.Parameter.Get("value.owner_address").String(), isTestnet) 161 | if err != nil { 162 | return &Contract{} 163 | } 164 | b.To, err = EncodeAddress(b.Parameter.Get("value.to_address").String(), isTestnet) 165 | if err != nil { 166 | return &Contract{} 167 | } 168 | b.Amount = common.StringNumToBigIntWithExp(b.Parameter.Get("value.amount").String(), 0) 169 | //b.Amount = b.Parameter.Get("value.amount").Int() 170 | b.Protocol = "" 171 | case TransferAssetContract: //TRC10 172 | 173 | b.From, err = EncodeAddress(b.Parameter.Get("value.owner_address").String(), isTestnet) 174 | if err != nil { 175 | return &Contract{} 176 | } 177 | b.To, err = EncodeAddress(b.Parameter.Get("value.to_address").String(), isTestnet) 178 | if err != nil { 179 | return &Contract{} 180 | } 181 | b.Amount = common.StringNumToBigIntWithExp(b.Parameter.Get("value.amount").String(), 0) 182 | //b.Amount = b.Parameter.Get("value.amount").Int() 183 | assetsByte, err := hex.DecodeString(b.Parameter.Get("value.asset_name").String()) 184 | if err != nil { 185 | return &Contract{} 186 | } 187 | b.ContractAddress = string(assetsByte) 188 | b.Protocol = TRC10 189 | case TriggerSmartContract: //TRC20 190 | 191 | b.From, err = EncodeAddress(b.Parameter.Get("value.owner_address").String(), isTestnet) 192 | if err != nil { 193 | return &Contract{} 194 | } 195 | 196 | b.ContractAddress, err = EncodeAddress(b.Parameter.Get("value.contract_address").String(), isTestnet) 197 | if err != nil { 198 | return &Contract{} 199 | } 200 | 201 | data := b.Parameter.Get("value.data").String() 202 | to, amount, err := ParseTransferEvent(data) 203 | if err != nil { 204 | return &Contract{} 205 | } 206 | b.To, err = EncodeAddress(to, isTestnet) 207 | if err != nil { 208 | return &Contract{} 209 | } 210 | 211 | b.Amount = amount 212 | b.Protocol = TRC20 213 | } 214 | 215 | return b 216 | } 217 | 218 | func ParseTransferEvent(data string) (string, *big.Int, error) { 219 | 220 | const ( 221 | TransferDataLength = 68 * 2 222 | ) 223 | 224 | var ( 225 | to string 226 | amount = big.NewInt(0) 227 | ) 228 | 229 | if len(data) != TransferDataLength { 230 | return "", amount, fmt.Errorf("call data is not transfer") 231 | } 232 | if data[0:8] != TRC20_TRANSFER_METHOD_ID { 233 | return "", amount, fmt.Errorf("call method is not transfer") 234 | } 235 | to = data[32:72] 236 | amount, _ = new(big.Int).SetString(data[72:], 16) 237 | //log.Infof("bigAmount = %s", bigAmount.String()) 238 | return to, amount, nil 239 | 240 | //amount, err := strconv.ParseInt(data[72:], 16, 64) 241 | //if err != nil { 242 | // return "", 0, err 243 | //} 244 | //return to, amount, nil 245 | } 246 | 247 | type Transaction struct { 248 | /* 249 | { 250 | "ret": [ 251 | { 252 | "contractRet": "SUCCESS" 253 | } 254 | ], 255 | "signature": [ 256 | "b6fbefec182a1db9759104e3d5709343f25acc1866c77deb050d9bf0f6a5c3342237fbbf076377ea26d1a09edd46e599534a8499998814da0e9187e07260382001" 257 | ], 258 | "txID": "86b5a123b5cc50047532f1a55ed627f29012bba41e6590b0545f903289e7099a", 259 | "raw_data": { 260 | "contract": [ 261 | { 262 | "parameter": { 263 | "value": { 264 | "amount": 10000, 265 | "owner_address": "415bdf283199369adb124f39dda845ae02c5d3eb5d", 266 | "to_address": "41bb65606e20dbdd7f0cfe6a66ae2858a6534f2d45" 267 | }, 268 | "type_url": "type.googleapis.com/protocol.TransferContract" 269 | }, 270 | "type": "TransferContract" 271 | } 272 | ], 273 | "ref_block_bytes": "2298", 274 | "ref_block_hash": "26478922abba48a0", 275 | "expiration": 1551957595231 276 | } 277 | } 278 | */ 279 | TxID string 280 | BlockHash string 281 | BlockHeight uint64 282 | BlockTime int64 283 | IsCoinBase bool 284 | Ret []*Result 285 | Contract []*Contract 286 | } 287 | 288 | func NewTransaction(json *gjson.Result, blockHash string, blockHeight uint64, blocktime int64, isTestnet bool) *Transaction { 289 | 290 | rawData := gjson.Get(json.Raw, "raw_data") 291 | // 解析json 292 | b := &Transaction{} 293 | b.TxID = gjson.Get(json.Raw, "txID").String() 294 | b.BlockHash = blockHash 295 | b.BlockHeight = blockHeight 296 | b.BlockTime = blocktime 297 | 298 | b.Ret = make([]*Result, 0) 299 | if rets := gjson.Get(json.Raw, "ret"); rets.IsArray() { 300 | for _, r := range rets.Array() { 301 | ret := NewResult(r) 302 | b.Ret = append(b.Ret, ret) 303 | } 304 | } 305 | 306 | b.Contract = make([]*Contract, 0) 307 | if contracts := rawData.Get("contract"); contracts.IsArray() { 308 | for i, c := range contracts.Array() { 309 | contract := NewContract(c, isTestnet) 310 | contract.TxID = b.TxID 311 | contract.BlockHash = blockHash 312 | contract.BlockHeight = blockHeight 313 | contract.BlockTime = blocktime 314 | if len(b.Ret) > i { 315 | contract.ContractRet = b.Ret[i].ContractRet 316 | } 317 | b.Contract = append(b.Contract, contract) 318 | } 319 | } 320 | 321 | return b 322 | } 323 | 324 | type TransactionExtention struct { 325 | Transaction gjson.Result `json:"transaction" ` 326 | Txid string `json:"txid"` 327 | ConstantResult []string `json:"constant_result"` 328 | Result *Return `json:"result"` 329 | } 330 | 331 | type Return struct { 332 | Result bool `json:"result"` 333 | Code int64 `json:"code"` 334 | Message string `json:"message"` 335 | } 336 | 337 | func NewReturn(json *gjson.Result) *Return { 338 | b := &Return{} 339 | b.Result = json.Get("result").Bool() 340 | b.Code = json.Get("code").Int() 341 | msg, _ := hex.DecodeString(json.Get("message").String()) 342 | b.Message = string(msg) 343 | return b 344 | } 345 | 346 | func NewTransactionExtention(json *gjson.Result) *TransactionExtention { 347 | 348 | // 解析json 349 | b := &TransactionExtention{} 350 | b.Transaction = json.Get("transaction") 351 | result := json.Get("result") 352 | b.Result = NewReturn(&result) 353 | b.Txid = json.Get("txid").String() 354 | 355 | b.ConstantResult = make([]string, 0) 356 | if constant_result := json.Get("constant_result"); constant_result.IsArray() { 357 | for _, c := range constant_result.Array() { 358 | b.ConstantResult = append(b.ConstantResult, c.String()) 359 | } 360 | } 361 | 362 | return b 363 | } 364 | 365 | //UnscanRecords 扫描失败的区块及交易 366 | type UnscanRecord struct { 367 | ID string `storm:"id"` // primary key 368 | BlockHeight uint64 369 | TxID string 370 | Reason string 371 | } 372 | 373 | func NewUnscanRecord(height uint64, txID, reason string) *UnscanRecord { 374 | obj := UnscanRecord{} 375 | obj.BlockHeight = height 376 | obj.TxID = txID 377 | obj.Reason = reason 378 | obj.ID = hex.EncodeToString(crypto.SHA256([]byte(fmt.Sprintf("%d_%s", height, txID)))) 379 | return &obj 380 | } 381 | 382 | //BlockHeader 区块链头 383 | func (b *Block) Blockheader() *openwallet.BlockHeader { 384 | obj := openwallet.BlockHeader{} 385 | //解析josn 386 | obj.Merkleroot = "" 387 | obj.Hash = b.Hash 388 | obj.Previousblockhash = b.Previousblockhash 389 | obj.Height = b.Height 390 | obj.Version = uint64(b.Version) 391 | obj.Time = uint64(b.Time) 392 | obj.Symbol = Symbol 393 | return &obj 394 | } 395 | 396 | type AccountNet struct { 397 | FreeNetUsed int64 398 | FreeNetLimit int64 399 | NetUsed int64 400 | NetLimit int64 401 | AssetNetUsed map[string]int64 402 | AssetNetLimit map[string]int64 403 | TotalNetLimit int64 404 | TotalNetWeight int64 405 | } 406 | 407 | func NewAccountNet(json *gjson.Result) *AccountNet { 408 | obj := &AccountNet{} 409 | obj.FreeNetUsed = json.Get("freeNetUsed").Int() 410 | obj.FreeNetLimit = json.Get("freeNetLimit").Int() 411 | obj.NetUsed = json.Get("NetUsed").Int() 412 | obj.TotalNetLimit = json.Get("TotalNetLimit").Int() 413 | obj.TotalNetWeight = json.Get("TotalNetWeight").Int() 414 | return obj 415 | } 416 | 417 | type AccountResource struct { 418 | FreeNetUsed int64 419 | FreeNetLimit int64 420 | NetUsed int64 421 | NetLimit int64 422 | EnergyUsed int64 423 | EnergyLimit int64 424 | StorageUsed int64 425 | StorageLimit int64 426 | } 427 | 428 | func NewAccountResource(json *gjson.Result) *AccountResource { 429 | obj := &AccountResource{} 430 | obj.FreeNetUsed = json.Get("freeNetUsed").Int() 431 | obj.FreeNetLimit = json.Get("freeNetLimit").Int() 432 | obj.NetUsed = json.Get("NetUsed").Int() 433 | obj.NetLimit = json.Get("NetLimit").Int() 434 | obj.EnergyUsed = json.Get("EnergyUsed").Int() 435 | obj.EnergyLimit = json.Get("EnergyLimit").Int() 436 | obj.StorageUsed = json.Get("StorageUsed").Int() 437 | obj.StorageLimit = json.Get("StorageLimit").Int() 438 | return obj 439 | } 440 | 441 | type txFeeInfo struct { 442 | GasUsed int64 443 | GasPrice decimal.Decimal 444 | Fee decimal.Decimal 445 | } 446 | 447 | func (f *txFeeInfo) CalcFee() error { 448 | fee := f.GasPrice.Mul(decimal.New(f.GasUsed, 0)) 449 | f.Fee = fee 450 | return nil 451 | } 452 | 453 | type ContractInfo struct { 454 | Bytecode string 455 | Name string 456 | ConsumeUserResourcePercent uint64 457 | ContractAddress string 458 | ABI string 459 | } 460 | 461 | func NewContractInfo(json *gjson.Result) *ContractInfo { 462 | obj := &ContractInfo{} 463 | obj.Bytecode = json.Get("bytecode").String() 464 | obj.Name = json.Get("name").String() 465 | obj.ConsumeUserResourcePercent = json.Get("consume_user_resource_percent").Uint() 466 | obj.ContractAddress = json.Get("contract_address").String() 467 | obj.ABI = json.Get("abi.entrys").Raw 468 | return obj 469 | } 470 | 471 | type Account struct { 472 | AddressHex string 473 | Balance int64 474 | FreeNetUsage int64 475 | AssetV2 map[string]*big.Int 476 | FreeAssetNetUsageV2 map[string]int64 477 | 478 | /* 479 | { 480 | "address": "41efb6d8a02f4b639605d71ff8dc78c97329759d70", 481 | "balance": 1058035120983, 482 | "create_time": 1546868937000, 483 | "latest_opration_time": 1553592429000, 484 | "free_net_usage": 4763, 485 | "latest_consume_free_time": 1553590113000, 486 | "account_resource": { 487 | "latest_consume_time_for_energy": 1553590494000 488 | }, 489 | "assetV2": [ 490 | { 491 | "key": "1001064", 492 | "value": 10 493 | } 494 | ], 495 | "free_asset_net_usageV2": [ 496 | { 497 | "key": "1001064", 498 | "value": 0 499 | } 500 | ] 501 | } 502 | 503 | */ 504 | } 505 | 506 | func NewAccount(json *gjson.Result) *Account { 507 | obj := &Account{} 508 | obj.AddressHex = json.Get("address").String() 509 | obj.Balance = json.Get("balance").Int() 510 | obj.FreeNetUsage = json.Get("free_net_usage").Int() 511 | 512 | obj.AssetV2 = make(map[string]*big.Int, 0) 513 | assetV2 := json.Get("assetV2") 514 | if assetV2.IsArray() { 515 | for _, as := range assetV2.Array() { 516 | obj.AssetV2[as.Get("key").String()] = common.StringNumToBigIntWithExp(as.Get("value").String(), 0) 517 | } 518 | } 519 | 520 | obj.FreeAssetNetUsageV2 = make(map[string]int64, 0) 521 | freeAssetNetUsageV2 := json.Get("free_asset_net_usageV2") 522 | if freeAssetNetUsageV2.IsArray() { 523 | for _, as := range freeAssetNetUsageV2.Array() { 524 | obj.FreeAssetNetUsageV2[as.Get("key").String()] = as.Get("value").Int() 525 | } 526 | } 527 | return obj 528 | } 529 | --------------------------------------------------------------------------------