[C#] TRX 與 USDT 合約轉帳交易解析:如何獲取完整的交易資料

2024-12-17

上一篇文章 透過 Trongrid 準確獲取 Tron 區塊內的完整交易資料,抓到區塊的每一筆  txid ,這時候我們要去抓取該 txid 最原始的資料

這時候有分成一般轉 trx 跟 使用 contract 的轉帳,這邊就是紀錄一下



1. 這裡面我都透過 RestSharp 處理 關於 http 的相關事情

2. 這邊我舉例兩個 txid 

2.1 純轉帳 trx - https://tronscan.org/#/transaction/497e9d02f78d22c9f19bab58b25384290d26b3eeac2362f0321d90b8515ea11a

我們透過呼叫 https://developers.tron.network/reference/wallet-gettransactionbyid

這個來測試,回應結果

{ "ret":[ { "contractRet":"SUCCESS" } ], "signature":[ "02c4d9cbba952c63c955b52e64ee9c0b853f794157009cfd6421bed05bd3217b0348ba4a97fe8a45bfe34055a32060a926f5a3cbd9ecb9cc4d50f18a26a9620b01" ], "txID":"497e9d02f78d22c9f19bab58b25384290d26b3eeac2362f0321d90b8515ea11a", "raw_data":{ "contract":[ { "parameter":{ "value":{ "amount":18465000001, "owner_address":"41d0a0baa3a5cec391d923cb61d722fdd538bc71ef", "to_address":"4130760c7e10b1d3509d8d64a7e9eb9ab94bc83495" }, "type_url":"type.googleapis.com/protocol.TransferContract" }, "type":"TransferContract" } ], "ref_block_bytes":"af85", "ref_block_hash":"c79b4046669d955a", "expiration":1725621000000, "timestamp":1725620940000 }, "raw_data_hex":"0a02af852208c79b4046669d955a40c0ae9bb89c325a69080112650a2d747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e73666572436f6e747261637412340a1541d0a0baa3a5cec391d923cb61d722fdd538bc71ef12154130760c7e10b1d3509d8d64a7e9eb9ab94bc8349518c194e6e44470e0d997b89c32" }

這時候我們看到裡面資料有 to_address 跟 amount 這樣看起來要抓取比較簡單


2.2 合約轉帳 USDT - https://tronscan.org/#/transaction/ff67cb02dd3b358f4e8c0b1aa9de90e819ec9c564832d961619973f0d393ee9a

我們依樣透過 https://developers.tron.network/reference/wallet-gettransactionbyid

回應結果

{ "ret":[ { "contractRet":"SUCCESS" } ], "signature":[ "3d936cb99f0ee5f9b58bbf60d4c49c37df62af18fa0cbe38e10b6c84ed574bb26ccb94d5e5103d55cf53f77f48ea7bd59a4fa80051f377eecf2ed1f68ac960a91c" ], "txID":"ff67cb02dd3b358f4e8c0b1aa9de90e819ec9c564832d961619973f0d393ee9a", "raw_data":{ "contract":[ { "parameter":{ "value":{ "data":"a9059cbb000000000000000000000000345a55f0532f765c7b19be1992801b1a572f462e0000000000000000000000000000000000000000000000000000000055f32c80", "owner_address":"41bb068c78fb5289221e71e52bd2c8d448f978de54", "contract_address":"41a614f803b6fd780986a42c78ec9c7f77e6ded13c" }, "type_url":"type.googleapis.com/protocol.TriggerSmartContract" }, "type":"TriggerSmartContract" } ], "ref_block_bytes":"af83", "ref_block_hash":"69d8c494caa23522", "expiration":1725703794000, "fee_limit":150000000, "timestamp":1725620934785 }, "raw_data_hex":"0a02af83220869d8c494caa2352240d0dad8df9c325aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a1541bb068c78fb5289221e71e52bd2c8d448f978de54121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb000000000000000000000000345a55f0532f765c7b19be1992801b1a572f462e0000000000000000000000000000000000000000000000000000000055f32c807081b197b89c32900180a3c347" }

這時候竟然 to_address 跟 amount 消失了 但是,我們可以透過 contract.parameter.value.data 中間去取得接下來就是看我程式碼的部分


3. 取得該 txid 資料印出 from , to , amount 

static string ConvertHexToBase58Check(string hexAddress) { byte[] addressBytes = HexToBytes(hexAddress); // 計算雙重 SHA-256 校驗碼 using (SHA256 sha256 = SHA256.Create()) { byte[] hash1 = sha256.ComputeHash(addressBytes); byte[] hash2 = sha256.ComputeHash(hash1); // 取前 4 位作為校驗碼 byte[] checksum = hash2.Take(4).ToArray(); // 拼接地址與校驗碼 byte[] addressWithChecksum = addressBytes.Concat(checksum).ToArray(); // 轉換為 Base58 return EncodeBase58(addressWithChecksum); } } static byte[] HexToBytes(string hex) { return Enumerable.Range(0, hex.Length / 2) .Select(x => Convert.ToByte(hex.Substring(x * 2, 2), 16)) .ToArray(); } static string EncodeBase58(byte[] input) { var Base58Chars = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; var intData = new BigInteger(input.Reverse().Concat(new byte[] { 0 }).ToArray()); string result = ""; while (intData > 0) { int remainder = (int)(intData % 58); intData /= 58; result = Base58Chars[remainder] + result; } // 保留前導 0 foreach (byte b in input) { if (b == 0) result = '1' + result; else break; } return result; } public class GetTransactionByIdResponse { public List<Ret> ret { get; set; } public List<string> signature { get; set; } public string txID { get; set; } public RawData raw_data { get; set; } public string raw_data_hex { get; set; } public class Ret { public string contractRet { get; set; } } public class RawData { public List<Contract> contract { get; set; } public string ref_block_bytes { get; set; } public string ref_block_hash { get; set; } public long expiration { get; set; } public long timestamp { get; set; } public class Contract { public Parameter parameter { get; set; } public string type { get; set; } public class Parameter { public Value value { get; set; } public string type_url { get; set; } public class Value { public string data { get; set; } public long amount { get; set; } public string owner_address { get; set; } public string to_address { get; set; } } } } } } static GetTransactionByIdResponse GetTransactionByTXId(string txId) { string apiUrl = "https://api.trongrid.io/wallet/gettransactionbyid"; var client = new RestClient(apiUrl); var request = new RestRequest("", Method.Post); request.AddHeader("accept", "application/json"); request.AddHeader("content-type", "application/json"); request.AddJsonBody(new { value = txId }); var response = client.Execute(request); if (response.IsSuccessful) { //Console.WriteLine(response.Content); return JsonConvert.DeserializeObject<GetTransactionByIdResponse>(response.Content); } else { Console.WriteLine($"Error: {response.StatusCode} - {response.ErrorMessage}"); return null; } } //轉帳 TRX Console.WriteLine("Transfer TRX txid:497e9d02f78d22c9f19bab58b25384290d26b3eeac2362f0321d90b8515ea11a"); var trxTransResult = GetTransactionByTXId("497e9d02f78d22c9f19bab58b25384290d26b3eeac2362f0321d90b8515ea11a"); var from = ConvertHexToBase58Check(trxTransResult.raw_data.contract[0].parameter.value.owner_address); var to = ConvertHexToBase58Check(trxTransResult.raw_data.contract[0].parameter.value.to_address); Console.WriteLine("from:" + from + " ,to:" + to + " ,amount:" + trxTransResult.raw_data.contract[0].parameter.value.amount); Console.WriteLine("-------------"); //轉帳 USDT Console.WriteLine("Transfer Contract Token txid:ff67cb02dd3b358f4e8c0b1aa9de90e819ec9c564832d961619973f0d393ee9a"); //如果是 contract 的交易 to 跟 amount 要用原始資料去抓 var contractTransResult = GetTransactionByTXId("ff67cb02dd3b358f4e8c0b1aa9de90e819ec9c564832d961619973f0d393ee9a"); from = ConvertHexToBase58Check(contractTransResult.raw_data.contract[0].parameter.value.owner_address); //前面要加上"41" 轉 trx 地址 //從32 位 往後抓 40 個就是 to 地址 to = ConvertHexToBase58Check("41" + (contractTransResult.raw_data.contract[0].parameter.value.data.Substring(32, 40))); // 取後 20 bytes //最後64位就是金額 var amount = BigInteger.Parse(contractTransResult.raw_data.contract[0].parameter.value.data.Substring(contractTransResult.raw_data.contract[0].parameter.value.data.Length - 64, 64), NumberStyles.AllowHexSpecifier); Console.WriteLine("from:" + from + " ,to:" + to + " ,amount:" + amount);


result:

Transfer TRX txid:497e9d02f78d22c9f19bab58b25384290d26b3eeac2362f0321d90b8515ea11a

from:TUzL6cNCgRdee1fSCv6x3oKZhSJ4CKast9 ,to:TEPSrSYPDSQ7yXpMFPq91Fb1QEWpMkRGfn ,amount:18465000001

-------------

Transfer Contract Token txid:ff67cb02dd3b358f4e8c0b1aa9de90e819ec9c564832d961619973f0d393ee9a

from:TT27CwjDsqWxrFLzs96xeKVhFhihkD1DjG ,to:TEk2MfjDGuM4UMgmCqZwj2WRgtkwbmtrL7 ,amount:1442000000



詳細我都寫在程式碼裡面了,希望有幫助到想要分析資料的人 :)



當麻許的碎念筆記 2014 | Donma Hsu Design.