├── ToolsDemo ├── doc.go ├── go.mod └── main.go ├── doc.go ├── README.md ├── go.mod ├── tools_test.go └── tools.go /ToolsDemo/doc.go: -------------------------------------------------------------------------------- 1 | // ToolsDemo project doc.go 2 | 3 | /* 4 | ToolsDemo document 5 | */ 6 | package main 7 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | // cocos-tools project doc.go 2 | 3 | /* 4 | cocos-tools document 5 | */ 6 | package CocosGoSDKTool 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cocos-tools 2 | Cocos sdk tools 3 | # Test 4 | ``` 5 | git clone https://github.com/Cocos-BCX/CocosGoSDKTool.git 6 | 7 | cd CocosGoSDKTool/ToolsDemo 8 | 9 | go build 10 | 11 | ``` 12 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module CocosGoSDKTool 2 | 3 | replace CocosSDK => github.com/Cocos-BCX/Go-SDK master 4 | 5 | go 1.13 6 | 7 | require ( 8 | CocosSDK v0.0.0-00010101000000-000000000000 9 | github.com/tidwall/gjson v1.3.5 10 | ) -------------------------------------------------------------------------------- /ToolsDemo/go.mod: -------------------------------------------------------------------------------- 1 | module CocosGoSDKTool 2 | 3 | replace CocosSDK => github.com/Cocos-BCX/Go-SDK master 4 | 5 | go 1.13 6 | 7 | require ( 8 | CocosSDK v0.0.0-00010101000000-000000000000 9 | github.com/tidwall/gjson v1.3.5 10 | ) -------------------------------------------------------------------------------- /ToolsDemo/main.go: -------------------------------------------------------------------------------- 1 | // ToolsDemo project main.go 2 | package main 3 | 4 | import ( 5 | "fmt" 6 | "log" 7 | 8 | tools "CocosGoSDKTool" 9 | sdk "CocosSDK" 10 | ) 11 | 12 | func main() { 13 | sdk.InitSDK("test.cocosbcx.net", 80, false) 14 | sdk.Wallet.ImportAccount("gggg1", "12345678") 15 | sdk.Wallet.SetDefaultAccount("gggg1", "12345678") 16 | log.Println(tools.CreateAccount("sqctwe123", "0x02703d7df82c35218fbc459f49f3ae918c29fc68665f4689b8248808bbf79bddc2")) 17 | txs, _ := tools.TxsForAddress("gggg1") 18 | fmt.Println(txs) 19 | hash := tools.UnsignedTxHash("c1ac4bb7bd7d94874a1cb98b39a8a582421d03d022dfa4be8c70567076e03ad008bcc75d6e5f01f4cf5d010016000000000000001a00000000000000a08601000000000000000000000000000103d53f078f6ea92d7d33a06bf0e23569e376baf516ed0f5efe9a1b714be5f031d1030ed1f4745aeb7194e1eea53bf6c4a217ba3b8f7d63ebad2e22543b99469bb0326e614f3b308beaa01081355d8f9325a76997c83b2dfb17652e0000") 20 | fmt.Println(hash) 21 | } 22 | -------------------------------------------------------------------------------- /tools_test.go: -------------------------------------------------------------------------------- 1 | package CocosGoSDKTool 2 | 3 | import ( 4 | sdk "CocosSDK" 5 | "CocosSDK/rpc" 6 | "encoding/json" 7 | "testing" 8 | ) 9 | 10 | const MAIN_NET_FAUCET = "https://faucet.cocosbcx.net/api/v1/accounts" 11 | const TEST_FAUCET = "https://test-faucet.cocosbcx.net/api/v1/accounts" 12 | 13 | func TestInitSdk(t *testing.T) { 14 | sdk.InitSDK("test.cocosbcx.net", true) 15 | sdk.Wallet.ImportAccount("ggggxxx", "12345678") 16 | sdk.Wallet.SetDefaultAccount("ggggxxx", "12345678") 17 | t.Log(rpc.GetDynamicGlobalProperties()) 18 | } 19 | 20 | func TestCreateAccountByFaucet(t *testing.T) { 21 | t.Log(CreateAccountByFaucet("hicocos1234", MAIN_NET_FAUCET, "0x024ae3a12eaf1c1a1f80979fdca3271c6e830df0ea59df2f1956fe7c692703c6ea")) 22 | t.Log(CreateAccountByFaucet("hicocos10086", MAIN_NET_FAUCET, 23 | "0x03f9f960dca747a6920162f391d4b99729d1a6e96eef5031c433d7007bcfaabe88", 24 | "0x0357560c27f4152ee1e041015c9a844be33ba5b430cd8d9436b67c07a93477c1e7")) 25 | 26 | } 27 | 28 | func TestGetTransaction(t *testing.T) { 29 | tx, err := GetTransaction("4432a6f92b95ade128f52e378f376eec87bfa50230c26584974554d1ab730c66") 30 | t.Log(err) 31 | byte_s, err := json.Marshal(tx) 32 | if err == nil { 33 | t.Log(string(byte_s)) 34 | } 35 | } 36 | func TestDeserialize(t *testing.T) { 37 | var hex_str string = "1ae3653a3105800f5722c5bda2b55530d0e9e8654314e2f3dc6d2b010da641c5cd27a29b23cab399e75d010063490000000000003000000000000000a0860100000000000000000000000000010103679b27673fea2846434ca659ffe65ea8c0ec6e751aa9c326bbfbfcf8affa673b0354702c8f8a62a9b0ec52ff6ef3d439cad11ddec8a105af00deab548788ab56fd99f3124df33a81401047e1947d6e104ec19ac290bb159e71960000" 38 | tx, err := Deserialize(hex_str) 39 | byte_s, err := json.Marshal(tx) 40 | if err == nil { 41 | t.Log(string(byte_s)) 42 | } 43 | } 44 | 45 | func TestDeserializeTransactions(t *testing.T) { 46 | sign_tx, _ := DeserializeTransactions("1ae3653a3105800f5722c5bda2b55530d0e9e8654314e2f3dc6d2b010da641c5cd27a29b23cab299e75d010063490000000000003000000000000000a0860100000000000000000000000000010004787878780000") 47 | byte_s, err := json.Marshal(sign_tx) 48 | if err == nil { 49 | t.Log(string(byte_s)) 50 | } 51 | } 52 | 53 | func TestTxsForAddress(t *testing.T) { 54 | txs, err := TxsForAddress("ggggxxx") //, 10, "263c47271171a5f99c839475f232a742074f848ddaba558e1b151106bf8dfbd1") 55 | byte_s, err := json.Marshal(txs) 56 | if err == nil { 57 | t.Log(string(byte_s)) 58 | } 59 | } 60 | 61 | func TestPuk2Addr(t *testing.T) { 62 | t.Log(PublicToAddress("0x02703d7df82c35218fbc459f49f3ae918c29fc68665f4689b8248808bbf79bddc2")) 63 | } 64 | 65 | func TestAddr2Puk(t *testing.T) { 66 | t.Log(AddressToPublic("ggggxxx")) 67 | } 68 | 69 | func TestGetBlockCount(t *testing.T) { 70 | t.Log(Getblockcount()) 71 | } 72 | 73 | /* 74 | func TestGetrawmempool(t *testing.T) { 75 | t.Log(Getrawmempool()) 76 | }*/ 77 | 78 | func TestGetblocktxs(t *testing.T) { 79 | txs, err := Getblocktxs(77559) 80 | byte_s, err := json.Marshal(txs) 81 | if err == nil { 82 | t.Log(string(byte_s)) 83 | } 84 | } 85 | 86 | func TestBalanceForAddress(t *testing.T) { 87 | balances := BalanceForAddress("ggggxxx") 88 | byte_s, err := json.Marshal(balances) 89 | if err == nil { 90 | t.Log(string(byte_s)) 91 | } 92 | } 93 | 94 | func TestBalanceForAddressForCoinCode(t *testing.T) { 95 | balances := BalanceForAddressForCoinCode("test1", "COCOS") 96 | byte_s, err := json.Marshal(balances) 97 | if err == nil { 98 | t.Log(string(byte_s)) 99 | } 100 | balances = BalanceForAddressForCoinCode("test1", "1.3.1") 101 | byte_s, err = json.Marshal(balances) 102 | if err == nil { 103 | t.Log(string(byte_s)) 104 | } 105 | } 106 | func TestSignTransaction(t *testing.T) { 107 | tx, err := SignTransaction("c1ac4bb7bd7d94874a1cb98b39a8a582421d03d022dfa4be8c70567076e03ad0486711d2c551899dc85d010016000000000000001a00000000000000a08601000000000000000000000000000103d53f078f6ea92d7d33a06bf0e23569e376baf516ed0f5efe9a1b714be5f031d1030ed1f4745aeb7194e1eea53bf6c4a217ba3b8f7d63ebad2e22543b99469bb032b4d412ed0c8e38561077883f0dfb4c3f8e1068c92ef3e9653f0000", 108 | []string{"202c76ab413de66315922a95c65b0dc77073bf1f9a7e809b0aa51db9f1592e359c2de34ed115c039d356ca573e0d4dc818a258acfc0af48c44c6e4c8d2c9d57508"}) 109 | 110 | byte_s, err := json.Marshal(tx) 111 | if err == nil { 112 | t.Log(string(byte_s)) 113 | } 114 | } 115 | 116 | func TestBuildTransaction(t *testing.T) { 117 | hex_str,acct_info, err := BuildTransaction("ggggxxx", "test1", 1, "COCOS") 118 | t.Log(acct_info) 119 | t.Log(err) 120 | t.Log(hex_str) 121 | } 122 | func TestUnsignedTxHash(t *testing.T) { 123 | hash := UnsignedTxHash("c1ac4bb7bd7d94874a1cb98b39a8a582421d03d022dfa4be8c70567076e03ad008bcc75d6e5f01f4cf5d010016000000000000001a00000000000000a08601000000000000000000000000000103d53f078f6ea92d7d33a06bf0e23569e376baf516ed0f5efe9a1b714be5f031d1030ed1f4745aeb7194e1eea53bf6c4a217ba3b8f7d63ebad2e22543b99469bb0326e614f3b308beaa01081355d8f9325a76997c83b2dfb17652e0000") 124 | if hash == "263c47271171a5f99c839475f232a742074f848ddaba558e1b151106bf8dfbd1" { 125 | t.Log("Test Unsigned Tx Hash success!!") 126 | } else { 127 | t.Error("Test Unsigned Tx Hash Error!") 128 | } 129 | } 130 | 131 | func TestCreateAccount(t *testing.T) { 132 | t.Log(CreateAccount("sqctccc123", "0x02703d34f82c35218fbc459f49f3ae918c29fc68665f4689b8248808bbf79bddc2")) 133 | 134 | } 135 | -------------------------------------------------------------------------------- /tools.go: -------------------------------------------------------------------------------- 1 | package CocosGoSDKTool 2 | 3 | import ( 4 | sdk "CocosSDK" 5 | . "CocosSDK/common" 6 | "CocosSDK/rpc" 7 | . "CocosSDK/type" 8 | "CocosSDK/wallet" 9 | "crypto/sha256" 10 | "encoding/hex" 11 | "encoding/json" 12 | "errors" 13 | "fmt" 14 | "io/ioutil" 15 | "log" 16 | "net/http" 17 | "strconv" 18 | "strings" 19 | "time" 20 | 21 | "github.com/tidwall/gjson" 22 | ) 23 | 24 | type UTXO struct { 25 | Value uint64 `json:"value"` 26 | Address string `json:"address"` 27 | Sn int64 `json:"sn"` 28 | } 29 | 30 | type Tx struct { 31 | TxHash string `json:"tx_hash,omitempty"` 32 | Inputs []UTXO `json:"inputs"` 33 | Outputs []UTXO `json:"outputs"` 34 | TxAt string `json:"tx_at"` 35 | BlockNumber int64 `json:"block_no,omitempty"` 36 | ConfirmedAt string `json:"confirmed_at,omitempty"` 37 | Extra map[string]string `json:"extra"` 38 | } 39 | 40 | const ( 41 | BTCPrecision = 8 42 | ) 43 | 44 | func createAssetId(id int64) ObjectId { 45 | return ObjectId(fmt.Sprintf("1.3.%d", id)) 46 | } 47 | func createAccountId(id int64) ObjectId { 48 | return ObjectId(fmt.Sprintf("1.2.%d", id)) 49 | } 50 | 51 | func DeserializeTransactions(tx_raw_hex string) (sign_tx *wallet.Signed_Transaction, err error) { 52 | var byte_s []byte 53 | //去除chainId 54 | tx_raw_hex = tx_raw_hex[64:] 55 | byte_s, err = hex.DecodeString(tx_raw_hex) 56 | if err != nil { 57 | return 58 | } 59 | sign_tx = new(wallet.Signed_Transaction) 60 | sign_tx.RefBlockNum = uint64(UintVar(byte_s[:2])) 61 | sign_tx.RefBlockPrefix = uint64(UintVar(byte_s[2:6])) 62 | sign_tx.Signatures = []string{} 63 | sign_tx.Operations = []Operation{} 64 | sign_tx.ExtensionsData = []interface{}{} 65 | time_bytes := byte_s[6:10] 66 | uinx_time := UintVar(time_bytes) 67 | sign_tx.Expiration = Expiration(time.Unix(int64(uinx_time), 0).In(UTCZone).Format(TIME_FORMAT)) 68 | byte_s = byte_s[10:] 69 | op_len_bytes := []byte{byte_s[0]} 70 | for i := 0; byte_s[i] > 0x80; i++ { 71 | op_len_bytes = append(op_len_bytes, byte_s[i+1]) 72 | } 73 | op_len := Intvar(op_len_bytes) 74 | byte_s = byte_s[len(op_len_bytes):] 75 | for i := 0; i < int(op_len); i++ { 76 | if byte_s[0] != OP_TRANSFER { 77 | sign_tx = nil 78 | err = errors.New("op code id is not OP_TRANSFER!!!") 79 | return 80 | } 81 | byte_s = byte_s[1:] 82 | from_bytes := byte_s[0:8] 83 | byte_s = byte_s[8:] 84 | to_bytes := byte_s[0:8] 85 | byte_s = byte_s[8:] 86 | amount := UintVar(byte_s[0:8]) 87 | amount_asset_id_bytes := byte_s[8:16] 88 | byte_s = byte_s[16:] 89 | from_id := UintVar(from_bytes) 90 | to_id := UintVar(to_bytes) 91 | amount_asset_id := UintVar(amount_asset_id_bytes) 92 | tx := Transaction{ 93 | From: createAccountId(from_id), 94 | To: createAccountId(to_id), 95 | ExtensionsData: []interface{}{}, 96 | AmountData: Amount{Amount: uint64(amount), AssetID: createAssetId(amount_asset_id)}, 97 | } 98 | if byte_s[0] != 0 { 99 | byte_s = byte_s[1:] 100 | if byte_s[0] == 0 { 101 | byte_s = byte_s[1:] 102 | memo_len_bytes := []byte{byte_s[0]} 103 | for i := 0; byte_s[i] > 0x80; i++ { 104 | memo_len_bytes = append(op_len_bytes, byte_s[i+1]) 105 | } 106 | memo_len := Intvar(memo_len_bytes) 107 | memo_str_byte := byte_s[len(op_len_bytes) : len(op_len_bytes)+int(memo_len)] 108 | tx.MemoData = &OpMemo{Int(0), String(string(memo_str_byte))} 109 | } else if byte_s[0] == 1 { 110 | //移除公钥信息 111 | from_bytes := make([]byte, 33) 112 | copy(from_bytes, byte_s[1:34]) 113 | byte_s = byte_s[34:] 114 | to_bytes := make([]byte, 33) 115 | copy(to_bytes, byte_s[:33]) 116 | byte_s = byte_s[33:] 117 | //移除nonce信息 118 | nonce_bytes := byte_s[:8] 119 | byte_s = byte_s[8:] 120 | m := &Memo{ 121 | From: wallet.PublicKey(from_bytes).ToBase58String(), 122 | To: wallet.PublicKey(to_bytes).ToBase58String(), 123 | Nonce: uint64(UintVar(nonce_bytes))} 124 | msg_len_bytes := []byte{byte_s[0]} 125 | 126 | for n := 0; byte_s[n] > 0x80; n++ { 127 | msg_len_bytes = append(msg_len_bytes, byte_s[n+1]) 128 | } 129 | byte_s = byte_s[len(msg_len_bytes):] 130 | //移除msg信息 131 | msg_len := Intvar(msg_len_bytes) 132 | m.Message = hex.EncodeToString(byte_s[:msg_len]) 133 | byte_s = byte_s[msg_len:] 134 | tx.MemoData = &OpMemo{Int(1), m} 135 | } 136 | } else { 137 | tx.MemoData = nil 138 | } 139 | sign_tx.Operations = append(sign_tx.Operations, Operation{OP_TRANSFER, tx}) 140 | } 141 | return 142 | } 143 | 144 | func Deserialize(tx_raw_hex string) (tx *Tx, err error) { 145 | var byte_s []byte 146 | tx_hash := GetTXHash(tx_raw_hex) 147 | /*if tx, err = GetTransaction(tx_hash); err == nil { 148 | return 149 | }*/ 150 | //去除chainId 151 | tx_raw_hex = tx_raw_hex[64:] 152 | byte_s, err = hex.DecodeString(tx_raw_hex) 153 | if err != nil { 154 | return 155 | } 156 | time_bytes := byte_s[6:10] 157 | uinx_time := UintVar(time_bytes) 158 | tx_at := time.Unix(int64(uinx_time), 0).In(UTCZone).Format(TIME_FORMAT) 159 | byte_s = byte_s[10:] 160 | op_len_bytes := []byte{byte_s[0]} 161 | for i := 0; byte_s[i] > 0x80; i++ { 162 | op_len_bytes = append(op_len_bytes, byte_s[i+1]) 163 | } 164 | op_len := Intvar(op_len_bytes) 165 | byte_s = byte_s[len(op_len_bytes):] 166 | inputs := []UTXO{} 167 | outputs := []UTXO{} 168 | memo := "" 169 | for i := 0; i < int(op_len); i++ { 170 | if byte_s[0] == byte(OP_TRANSFER) { 171 | byte_s = byte_s[1:] 172 | from_bytes := byte_s[0:8] 173 | byte_s = byte_s[8:] 174 | to_bytes := byte_s[0:8] 175 | byte_s = byte_s[8:] 176 | amount := UintVar(byte_s[0:8]) 177 | amount_asset_id_bytes := byte_s[8:16] 178 | byte_s = byte_s[16:] 179 | //c_fees := sdk.GetCurrentFees() 180 | //fee_amount := c_fees[OP_TRANSFER].Get("fee").Int() 181 | if byte_s[0] != 0 { 182 | byte_s = byte_s[1:] 183 | if byte_s[0] == 0 { 184 | byte_s = byte_s[1:] 185 | memo_len_bytes := []byte{byte_s[0]} 186 | for i := 0; byte_s[i] > 0x80; i++ { 187 | memo_len_bytes = append(op_len_bytes, byte_s[i+1]) 188 | } 189 | memo_len := Intvar(memo_len_bytes) 190 | memo_bytes := byte_s[len(op_len_bytes):len(op_len_bytes)+int(memo_len)] 191 | memo = string(memo_bytes) 192 | byte_s = byte_s[len(op_len_bytes)+int(memo_len):] 193 | //fee_amount += c_fees[OP_TRANSFER].Get("price_per_kbyte").Int() * (2 + int64(len(memo_len_bytes)) + memo_len) / 1024 194 | } else if byte_s[0] == 1 { 195 | //移除公钥信息 196 | byte_s = byte_s[67:] 197 | //移除nonce信息 198 | byte_s = byte_s[8:] 199 | msg_len_bytes := []byte{byte_s[0]} 200 | for n := 0; byte_s[n] > 0x80; n++ { 201 | msg_len_bytes = append(msg_len_bytes, byte_s[n+1]) 202 | } 203 | byte_s = byte_s[len(msg_len_bytes):] 204 | //移除msg信息 205 | msg_len := Intvar(msg_len_bytes) 206 | byte_s = byte_s[msg_len:] 207 | //fee_amount += c_fees[OP_TRANSFER].Get("price_per_kbyte").Int() * (76 + int64(len(msg_len_bytes)) + msg_len) / 1024 208 | } 209 | } 210 | amount_asset_id := UintVar(amount_asset_id_bytes) 211 | //asset_info := rpc.GetTokenInfo(fmt.Sprintf("1.3.%d", amount_asset_id)) 212 | //asset_precision := math.Pow10(BTCPrecision - asset_info.Precision) 213 | from_id := UintVar(from_bytes) 214 | to_id := UintVar(to_bytes) 215 | //from_info := rpc.GetAccountInfo(fmt.Sprintf("1.2.%d", from_id)) 216 | //to_info := rpc.GetAccountInfo(fmt.Sprintf("1.2.%d", to_id)) 217 | in := UTXO{ 218 | // Value: uint64(float64(amount) * asset_precision), 219 | Value: uint64(amount), 220 | Address: fmt.Sprintf("1.2.%d", from_id), 221 | Sn: amount_asset_id, 222 | } 223 | /* 224 | if fmt.Sprintf("1.3.%d", amount_asset_id) != COCOS_ID { 225 | fee := UTXO{ 226 | Sn: 0, 227 | Address: from_info.Name, 228 | Value: fee_amount} 229 | inputs = append(inputs, fee) 230 | } else { 231 | in.Value += fee_amount 232 | }*/ 233 | 234 | out := UTXO{ 235 | // Value: uint64(float64(amount) * asset_precision), 236 | Value: uint64(amount), 237 | Address: fmt.Sprintf("1.2.%d", to_id), 238 | Sn: amount_asset_id, 239 | } 240 | inputs = append(inputs, in) 241 | outputs = append(outputs, out) 242 | } 243 | } 244 | tx = &Tx{ 245 | TxHash: tx_hash, 246 | Inputs: inputs, 247 | Outputs: outputs, 248 | TxAt: tx_at, 249 | Extra: make(map[string]string), 250 | } 251 | tx.Extra["memo"] = memo 252 | return 253 | } 254 | 255 | func UnsignedTxHash(tx_raw_hex string) (tx_hash string) { 256 | 257 | if data_bytes, err := hex.DecodeString(tx_raw_hex); err == nil { 258 | sha := sha256.New() 259 | sha.Write(data_bytes) 260 | raw_data := sha.Sum(nil) 261 | tx_hash = hex.EncodeToString(raw_data) 262 | } 263 | return 264 | } 265 | 266 | func PublicToAddress(hex_puk string) (address string, err error) { 267 | var byte_s []byte 268 | if strings.HasPrefix(hex_puk, "0x") { 269 | hex_puk = hex_puk[2:] 270 | } 271 | if len(hex_puk) != 66 { 272 | return "", errors.New("puk length error!!!") 273 | } 274 | byte_s, err = hex.DecodeString(hex_puk) 275 | if err != nil { 276 | return 277 | } 278 | acct := rpc.GetAccountInfoByPublicKey(wallet.PublicKey(byte_s).ToBase58String()) 279 | if acct != nil { 280 | address = acct.Name 281 | } else { 282 | err = errors.New("not found the public key in database.") 283 | } 284 | return 285 | } 286 | 287 | func AddressToPublic(address string) (hex_puk string, err error) { 288 | acct := rpc.GetAccountInfoByName(address) 289 | if acct != nil { 290 | puk := wallet.PukFromBase58String(acct.GetActivePuKey()) 291 | hex_puk = "0x" + hex.EncodeToString(puk) 292 | } else { 293 | err = errors.New("not found the name in database.") 294 | } 295 | return 296 | } 297 | 298 | func Getblockcount() int { 299 | return rpc.GetDynamicGlobalProperties().HeadBlockNumber 300 | } 301 | 302 | func Getrawmempool() (txs []Tx, err error) { 303 | txs = []Tx{} 304 | defer func() { 305 | if recover() != nil { 306 | txs = nil 307 | err = errors.New("Getrawmempool Is Error!") 308 | } 309 | }() 310 | dgp := rpc.GetDynamicGlobalProperties() 311 | for no := dgp.LastIrreversibleBlockNum + 1; no <= dgp.HeadBlockNumber; no++ { 312 | tx_s, _ := Getblocktxs(int64(no)) 313 | txs = append(txs, tx_s...) 314 | } 315 | return 316 | } 317 | 318 | func Getblocktxs(count int64) (txs []Tx, err error) { 319 | block := sdk.GetBlock(count) 320 | defer func() { 321 | if recover() != nil { 322 | txs = nil 323 | err = errors.New("Getblocktxs Is Error!") 324 | } 325 | }() 326 | txs = []Tx{} 327 | for _, tx_info := range block.Transactions { 328 | if byte_s, err := json.Marshal(tx_info); err == nil { 329 | tx := gjson.ParseBytes(byte_s) 330 | tx_hash := tx.Get("0").String() 331 | tx_operations := tx.Get("1.operations").Array() 332 | inputs := []UTXO{} 333 | outputs := []UTXO{} 334 | 335 | //tx_at := tx.Get("1.expiration").String() 336 | memo := "" 337 | for index, operation := range tx_operations { 338 | tx_op_code := operation.Get("0").Int() 339 | tx_op_data := operation.Get("1") 340 | if tx_op_code != OP_TRANSFER { 341 | continue 342 | } 343 | fee_amount := tx.Get(fmt.Sprintf("1.operation_results.%d.1.fees.0.amount", index)).Int() 344 | fee_asset_id_str := tx.Get(fmt.Sprintf("1.operation_results.%d.1.fees.0.asset_id", index)).String() 345 | fee_asset_id, _ := strconv.ParseInt( 346 | strings.Split( 347 | fee_asset_id_str, `.`)[2], 348 | 10, 64) 349 | out_amount := tx_op_data.Get("amount.amount").Int() 350 | out_asset_id, _ := strconv.ParseInt( 351 | strings.Split( 352 | tx_op_data.Get("amount.asset_id").String(), `.`)[2], 353 | 10, 64) 354 | from_info := rpc.GetAccountInfo(tx_op_data.Get("from").String()) 355 | to_info := rpc.GetAccountInfo(tx_op_data.Get("to").String()) 356 | memo_sign := tx_op_data.Get("memo.0").Uint() 357 | if memo_sign == 0{ 358 | memo = tx_op_data.Get("memo.1").String() 359 | } 360 | //asset_info := rpc.GetTokenInfo(fmt.Sprintf("1.3.%d", out_asset_id)) 361 | //asset_precision := math.Pow10(BTCPrecision - asset_info.Precision) 362 | in := UTXO{ 363 | //Value: uint64(float64(out_amount) * asset_precision), 364 | Value: uint64(out_amount), 365 | Address: from_info.Name, 366 | Sn: out_asset_id, 367 | } 368 | if fee_asset_id == out_asset_id { 369 | in.Value += uint64(fee_amount) 370 | } 371 | out := UTXO{ 372 | //Value: uint64(float64(out_amount) * asset_precision), 373 | Value: uint64(out_amount), 374 | Address: to_info.Name, 375 | Sn: out_asset_id, 376 | } 377 | inputs = append(inputs, in) 378 | outputs = append(outputs, out) 379 | } 380 | if len(inputs) > 0 && len(outputs) > 0 { 381 | tx := Tx{ 382 | TxHash: tx_hash, 383 | Inputs: inputs, 384 | Outputs: outputs, 385 | TxAt: block.Timestamp, 386 | ConfirmedAt: block.Timestamp, 387 | Extra: make(map[string]string), 388 | } 389 | tx.Extra["memo"] = memo 390 | txs = append(txs, tx) 391 | } 392 | } 393 | } 394 | return 395 | } 396 | 397 | type Balance struct { 398 | AssetID string 399 | Amount int64 400 | } 401 | 402 | func translateBalance(balance rpc.Balance) Balance { 403 | return Balance{ 404 | AssetID: balance.AssetID, 405 | Amount: balance.Amount.Int64(), 406 | } 407 | } 408 | 409 | func BalanceForAddress(address string) []Balance { 410 | balances := sdk.GetAccountBalances(address) 411 | trans_balances := []Balance{} 412 | for _, balance := range *balances { 413 | trans_balances = append(trans_balances, translateBalance(balance)) 414 | } 415 | return trans_balances 416 | } 417 | 418 | func BalanceForAddressForCoinCode(address string, symbolOrId string) *Balance { 419 | balances := sdk.GetAccountBalances(address) 420 | if balances == nil { 421 | return nil 422 | } 423 | asset_info := sdk.GetTokenInfoBySymbol(symbolOrId) 424 | if asset_info != nil { 425 | symbolOrId = string(asset_info.ID) 426 | } 427 | for _, balance := range *balances { 428 | if balance.AssetID == symbolOrId { 429 | trans_balance := translateBalance(balance) 430 | return &trans_balance 431 | } 432 | } 433 | return nil 434 | } 435 | 436 | func TxsForAddress(address string, args ...interface{}) (txs []Tx, err error) { 437 | acct_info := rpc.GetAccountInfoByName(address) 438 | limit := 50 439 | since_hash := "" 440 | defer func() { 441 | if cover := recover(); cover != nil { 442 | txs = nil 443 | log.Println(cover) 444 | err = errors.New("Get Txs For Address Is Error!") 445 | } 446 | }() 447 | if len(args) >= 1 { 448 | if l, ok := args[0].(int); ok { 449 | limit = l 450 | } 451 | } 452 | if len(args) >= 2 { 453 | if str, ok := args[1].(string); ok { 454 | if len(str) != 64 { 455 | err = errors.New("since hash error!!!") 456 | return 457 | } 458 | since_hash = str 459 | } 460 | } 461 | txs = []Tx{} 462 | tx_infos := sdk.GetAccountHistorys(acct_info.ID) 463 | is_start := false 464 | for idx:=0;idx < len(tx_infos);idx++{ 465 | tx_info := tx_infos[idx] 466 | if byte_s, err := json.Marshal(tx_info); err == nil { 467 | tx := gjson.ParseBytes(byte_s) 468 | operation := tx.Get("op") 469 | tx_op_code := operation.Get("0").Int() 470 | if tx_op_code != OP_TRANSFER { 471 | continue 472 | } 473 | block_num := tx.Get("block_num").Int() 474 | trx_in_block := tx.Get("trx_in_block").Int() 475 | block := sdk.GetBlock(block_num) 476 | tx_info := block.Transactions[trx_in_block] 477 | if byte_s, err := json.Marshal(tx_info); err == nil { 478 | tx := gjson.ParseBytes(byte_s) 479 | if !is_start{ 480 | if since_hash != ""{ 481 | if tx.Get("0").String() == since_hash { 482 | is_start = true 483 | } 484 | continue 485 | }else{ 486 | is_start = true 487 | } 488 | } 489 | if since_hash != "" && 490 | tx.Get("0").String() == since_hash { 491 | break 492 | } 493 | tx_hash := tx.Get("0").String() 494 | //tx_at := tx.Get("1.expiration").String() 495 | tx_operations := tx.Get("1.operations").Array() 496 | inputs := []UTXO{} 497 | outputs := []UTXO{} 498 | memo := "" 499 | for index, operation := range tx_operations { 500 | tx_op_code := operation.Get("0").Int() 501 | tx_op_data := operation.Get("1") 502 | if tx_op_code != OP_TRANSFER { 503 | continue 504 | } 505 | fee_amount := tx.Get(fmt.Sprintf("1.operation_results.%d.1.fees.0.amount", index)).Int() 506 | fee_asset_id_str := tx.Get(fmt.Sprintf("1.operation_results.%d.1.fees.0.asset_id", index)).String() 507 | fee_asset_id, _ := strconv.ParseInt( 508 | strings.Split( 509 | fee_asset_id_str, `.`)[2], 510 | 10, 64) 511 | out_amount := tx_op_data.Get("amount.amount").Int() 512 | out_asset_id, _ := strconv.ParseInt( 513 | strings.Split( 514 | tx_op_data.Get("amount.asset_id").String(), `.`)[2], 515 | 10, 64) 516 | from_info := rpc.GetAccountInfo(tx_op_data.Get("from").String()) 517 | to_info := rpc.GetAccountInfo(tx_op_data.Get("to").String()) 518 | memo_sign := tx_op_data.Get("memo.0").Uint() 519 | if memo_sign == 0{ 520 | memo = tx_op_data.Get("memo.1").String() 521 | } 522 | //asset_info := rpc.GetTokenInfo(fmt.Sprintf("1.3.%d", out_asset_id)) 523 | //asset_precision := math.Pow10(BTCPrecision - asset_info.Precision) 524 | in := UTXO{ 525 | //Value: uint64(float64(out_amount) * asset_precision), 526 | Value: uint64(out_amount), 527 | Address: from_info.Name, 528 | Sn: out_asset_id, 529 | } 530 | if fee_asset_id == out_asset_id { 531 | in.Value += uint64(fee_amount) 532 | } 533 | out := UTXO{ 534 | //Value: uint64(float64(out_amount) * asset_precision), 535 | Value: uint64(out_amount), 536 | Address: to_info.Name, 537 | Sn: out_asset_id, 538 | } 539 | inputs = append(inputs, in) 540 | outputs = append(outputs, out) 541 | } 542 | if len(inputs) > 0 && len(outputs) > 0 { 543 | tx := Tx{ 544 | TxHash: tx_hash, 545 | Inputs: inputs, 546 | Outputs: outputs, 547 | TxAt: block.Timestamp, 548 | BlockNumber: block_num, 549 | ConfirmedAt: block.Timestamp, 550 | Extra: make(map[string]string), 551 | } 552 | tx.Extra["memo"] = memo 553 | if len(txs) >= limit { 554 | break 555 | } 556 | txs = append(txs , tx) 557 | } 558 | } 559 | } 560 | } 561 | return 562 | } 563 | 564 | func GetTransaction(tx_hash string) (tx *Tx, err error) { 565 | defer func() { 566 | if recover() != nil { 567 | tx = nil 568 | err = errors.New("Get Transaction Error!") 569 | } 570 | }() 571 | tx_info := sdk.GetTransactionById(tx_hash) 572 | block_info := sdk.GetTransactionInBlock(tx_hash) 573 | block := sdk.GetBlock(block_info.BlockNum) 574 | if tx_info == nil { 575 | err = errors.New("transaction not found!!!!") 576 | return 577 | } 578 | defer func() { 579 | if recover() != nil { 580 | tx = nil 581 | err = errors.New("Getblocktxs Is Error!") 582 | } 583 | }() 584 | if byte_s, err := json.Marshal(tx_info); err == nil { 585 | tx_data := gjson.ParseBytes(byte_s) 586 | //tx_at := tx_data.Get("expiration").String() 587 | tx_operations := tx_data.Get("operations").Array() 588 | inputs := []UTXO{} 589 | outputs := []UTXO{} 590 | memo := "" 591 | for index, operation := range tx_operations { 592 | tx_op_code := operation.Get("0") 593 | tx_op_data := operation.Get("1") 594 | if tx_op_code.Int() != OP_TRANSFER { 595 | continue 596 | } 597 | fee_amount := tx_data.Get(fmt.Sprintf("operation_results.%d.1.fees.0.amount", index)).Int() 598 | fee_asset_id_str := tx_data.Get(fmt.Sprintf("operation_results.%d.1.fees.0.asset_id", index)).String() 599 | fee_asset_id, _ := strconv.ParseInt( 600 | strings.Split( 601 | fee_asset_id_str, `.`)[2], 602 | 10, 64) 603 | out_amount := tx_op_data.Get("amount.amount").Int() 604 | out_asset_id, _ := strconv.ParseInt( 605 | strings.Split( 606 | tx_op_data.Get("amount.asset_id").String(), `.`)[2], 607 | 10, 64) 608 | from_info := rpc.GetAccountInfo(tx_op_data.Get("from").String()) 609 | to_info := rpc.GetAccountInfo(tx_op_data.Get("to").String()) 610 | memo_sign := tx_op_data.Get("memo.0").Uint() 611 | if memo_sign == 0{ 612 | memo = tx_op_data.Get("memo.1").String() 613 | } 614 | in := UTXO{ 615 | Value: uint64(out_amount), 616 | Address: from_info.Name, 617 | Sn: out_asset_id, 618 | } 619 | if fee_asset_id == out_asset_id { 620 | in.Value += uint64(fee_amount) 621 | } 622 | out := UTXO{ 623 | Value: uint64(out_amount), 624 | Address: to_info.Name, 625 | Sn: out_asset_id, 626 | } 627 | inputs = append(inputs, in) 628 | outputs = append(outputs, out) 629 | } 630 | if len(inputs) > 0 && len(outputs) > 0 { 631 | tx = &Tx{ 632 | TxHash: tx_hash, 633 | Inputs: inputs, 634 | Outputs: outputs, 635 | BlockNumber: block_info.BlockNum, 636 | ConfirmedAt: block.Timestamp, 637 | TxAt: block.Timestamp, 638 | Extra: make(map[string]string), 639 | } 640 | tx.Extra["memo"] = memo 641 | } 642 | } 643 | return 644 | } 645 | /*memo 必须传,没有可以传空字符串*/ 646 | func BuildTransaction(from, to, memo string, amount uint64, symbol ...string) (tx_raw_hex string,acct_infos map[string]string, err error) { 647 | asset_id := COCOS_ID 648 | acct_infos = make(map[string]string) 649 | var tk_info *rpc.TokenInfo 650 | from_info := rpc.GetAccountInfoByName(from) 651 | to_info := rpc.GetAccountInfoByName(to) 652 | if from_info == nil || to_info == nil { 653 | err = errors.New("from or to is not exits!!") 654 | return 655 | } 656 | acct_infos[from_info.ID] = from 657 | acct_infos[to_info.ID] = to 658 | if len(symbol) > 0 { 659 | tk_info = rpc.GetTokenInfoBySymbol(symbol[0]) 660 | } else { 661 | tk_info = rpc.GetTokenInfo(asset_id) 662 | } 663 | if tk_info == nil { 664 | err = errors.New("asset is not exit!") 665 | return 666 | } 667 | t := &Transaction{ 668 | AmountData: Amount{Amount: amount, AssetID: ObjectId(tk_info.ID)}, 669 | ExtensionsData: []interface{}{}, 670 | From: ObjectId(from_info.ID), 671 | To: ObjectId(to_info.ID), 672 | MemoData: &OpMemo{Int(0), String(memo)}, 673 | } 674 | op := Operation{OP_TRANSFER, t} 675 | dgp := rpc.GetDynamicGlobalProperties() 676 | timestamp, _ := time.Parse(TIME_FORMAT, dgp.Time) 677 | expiration := Expiration(time.Unix(timestamp.Unix()+60*60*2,0).In(UTCZone).Format(TIME_FORMAT)) 678 | st := &wallet.Signed_Transaction{ 679 | RefBlockNum: dgp.Get_ref_block_num(), 680 | RefBlockPrefix: dgp.Get_ref_block_prefix(), 681 | Expiration: expiration, 682 | Operations: []Operation{op}, 683 | ExtensionsData: []interface{}{}, 684 | Signatures: []string{}, 685 | } 686 | byte_s := st.GetBytes() 687 | var cid []byte 688 | if cid, err = hex.DecodeString(sdk.Chain.Properties.ChainID); err != nil { 689 | return 690 | } 691 | byte_s = append(cid, byte_s...) 692 | tx_raw_hex = hex.EncodeToString(byte_s) 693 | return 694 | } 695 | 696 | func CreateAccountByFaucet(name string, faucet_url string, hex_puks ...string) (result string, err error) { 697 | var byte_s []byte 698 | defer func() { 699 | if r := recover(); r != nil { 700 | err = errors.New("CreateAccountByFaucet Is Error!") 701 | } 702 | }() 703 | if len(hex_puks) <= 0 { 704 | err = errors.New("puk number is error!!!") 705 | return 706 | } 707 | for idx := 0; idx < len(hex_puks); idx++ { 708 | if strings.HasPrefix(hex_puks[idx], "0x") { 709 | hex_puks[idx] = hex_puks[idx][2:] 710 | } 711 | if len(hex_puks[idx]) != 66 { 712 | err = errors.New("puk length error!!!") 713 | return 714 | } 715 | } 716 | byte_s, err = hex.DecodeString(hex_puks[0]) 717 | if err != nil { 718 | return 719 | } 720 | active_PubKey := wallet.PublicKey(byte_s) 721 | owner_Pubkey := wallet.PublicKey(byte_s) 722 | if len(hex_puks) > 1 { 723 | byte_s, err = hex.DecodeString(hex_puks[1]) 724 | if err != nil { 725 | return 726 | } 727 | owner_Pubkey = wallet.PublicKey(byte_s) 728 | } 729 | params := make(map[string]interface{}) 730 | account := make(map[string]string) 731 | account["name"] = name 732 | account["owner_key"] = owner_Pubkey.ToBase58String() 733 | account["memo_key"] = active_PubKey.ToBase58String() 734 | account["active_key"] = active_PubKey.ToBase58String() 735 | account["referror"] = "" 736 | params["account"] = account 737 | params_data, _ := json.Marshal(params) 738 | request, err := http.NewRequest("POST", faucet_url, strings.NewReader(string(params_data))) 739 | request.Header.Set("Authorization", "YnVmZW5nQDIwMThidWZlbmc=") 740 | //post数据并接收http响应 741 | var resp *http.Response 742 | resp, err = http.DefaultClient.Do(request) 743 | if err != nil { 744 | return 745 | } else { 746 | if byte_s, err = ioutil.ReadAll(resp.Body); err == nil { 747 | result = string(byte_s) 748 | } 749 | return 750 | } 751 | } 752 | 753 | func CreateAccount(name, hex_puk string) (tx_hash string, err error) { 754 | var byte_s []byte 755 | defer func() { 756 | if r := recover(); r != nil { 757 | tx_hash = "" 758 | err = errors.New("CreateAccount Is Error!") 759 | } 760 | }() 761 | if strings.HasPrefix(hex_puk, "0x") { 762 | hex_puk = hex_puk[2:] 763 | } 764 | if len(hex_puk) != 66 { 765 | return "", errors.New("puk length error!!!") 766 | } 767 | if sdk.Wallet.Default.Info == nil { 768 | sdk.Wallet.Default.Info = rpc.GetAccountInfoByName(sdk.Wallet.Default.Name) 769 | } 770 | byte_s, err = hex.DecodeString(hex_puk) 771 | if err != nil { 772 | return 773 | } 774 | puk := wallet.PublicKey(byte_s) 775 | if _, err := PublicToAddress(puk.ToBase58String()); err == nil { 776 | return "", errors.New("puk in database is exist!!") 777 | } 778 | if _, err := AddressToPublic(name); err == nil { 779 | return "", errors.New("name in database is exist!!") 780 | } 781 | c := CreateRegisterData(puk.ToBase58String(), puk.ToBase58String(), name, sdk.Wallet.Default.Info.ID, sdk.Wallet.Default.Info.ID) 782 | tx_hash, err = sdk.Wallet.SignAndSendTX(OP_CREATE_ACCOUNT, c) 783 | return tx_hash, err 784 | } 785 | 786 | func GetTXHash(tx_raw_hex string) (tx_hash string) { 787 | byte_s, _ := hex.DecodeString(tx_raw_hex[64:]) 788 | hash := sha256.Sum256(byte_s) 789 | tx_hash = hex.EncodeToString(hash[:]) 790 | return 791 | } 792 | 793 | func SignTransaction(tx_raw_hex string, signatures []string) (tx *Tx, e error) { 794 | sign_tx, err := DeserializeTransactions(tx_raw_hex) 795 | if err != nil { 796 | return tx, err 797 | } 798 | if byte_s, err := json.Marshal(sign_tx); err == nil { 799 | tx_json := gjson.ParseBytes(byte_s) 800 | acct_id := tx_json.Get("operations.0.1.from").String() 801 | acct_info := rpc.GetAccountInfo(acct_id) 802 | for _, signature := range signatures { 803 | if !wallet.VerifySignature(tx_raw_hex, signature, acct_info.GetActivePuKey()) { 804 | err = errors.New("Verify Signature error!") 805 | return tx, err 806 | } 807 | } 808 | sign_tx.Signatures = append(sign_tx.Signatures, signatures...) 809 | if hash, err := rpc.BroadcastTransaction(sign_tx); err == nil { 810 | for i := 0; i <= 20; i++ { 811 | if tx, err = GetTransaction(hash); err == nil { 812 | return tx, err 813 | } 814 | time.Sleep(time.Second) 815 | } 816 | return tx, err 817 | } else { 818 | return tx, err 819 | } 820 | } else { 821 | return tx, err 822 | } 823 | } 824 | --------------------------------------------------------------------------------