[C#] 如何使用 C# 解析 TRC20 交易資料的 raw_data_hex

2025-02-26

在區塊鏈開發中,了解如何解析交易資料是非常重要的一環,尤其是在處理像 TRC20 這樣的合約交易時。TRC20 是 Tron 網絡上的一個代幣標準,它的交易資料通常包含有關發送方、接收方、合約地址以及轉帳金額的資訊。在本篇文章中,我將介紹如何利用 C# 語言來解析 TRC20 交易資料中的重要信息 今天來解析一下 trongrid 常常回應一個參數  raw_data_hex
每筆 TRC20 交易的資料會以原始字串形式存儲在區塊鏈上,稱為 raw_data_hex。這個資料通常會以十六進制(hex)格式存儲,其中包括了合約呼叫、發送地址、接收地址、以及交易金額等詳細資訊。要解讀這些資訊,我們需要將十六進制數據轉換成我們需要的格式,例如 Base58Check 地址格式或者金額數值。

其實透過解析可以在裡面拿到很多資訊 ,其中 基於 TRX 與 USDT 合約轉帳交易解析:如何獲取完整的交易資料 其中的 GetTransactionByTXId 繼續寫下去


我們測試資料基於這個 https://tronscan.org/#/transaction/70cfc24c7fd731e1ea523268a3c9fdf738fe8ffa6ed410f520e1a32631d7b33e

txid 為 70cfc24c7fd731e1ea523268a3c9fdf738fe8ffa6ed410f520e1a32631d7b33e

首先我們先得到該 txid 的資料 ,下面也附上 response 的 json 結果

//var contractTransResult = GetTransactionByTXId("70cfc24c7fd731e1ea523268a3c9fdf738fe8ffa6ed410f520e1a32631d7b33e"); 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; } } { "ret":[ { "contractRet":"SUCCESS" } ], "signature":[ "5ae90e3633da3003aab99f0c798d36fe863e8e73e71669355e20cc47bf13472256c741d992838e0c5261fdc9f003c2837824c503186931d13e61a861c9c8bee501" ], "txID":"70cfc24c7fd731e1ea523268a3c9fdf738fe8ffa6ed410f520e1a32631d7b33e", "raw_data":{ "contract":[ { "parameter":{ "value":{ "data":"a9059cbb000000000000000000000000e8b0ed1cfead30b0c6119265c12611b05f76b9a40000000000000000000000000000000000000000000000000000000ce6282c40", "amount":0, "owner_address":"415b5978f75571b9f2525a421a2666f9b1bbbf2b10", "to_address":null }, "type_url":"type.googleapis.com/protocol.TriggerSmartContract" }, "type":"TriggerSmartContract" } ], "ref_block_bytes":"3263", "ref_block_hash":"e725af08821ee7de", "expiration":1740472008000, "timestamp":1740471951323 }, "raw_data_hex":"0a0232632208e725af08821ee7de40c0fadce1d3325aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a15415b5978f75571b9f2525a421a2666f9b1bbbf2b10121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb000000000000000000000000e8b0ed1cfead30b0c6119265c12611b05f76b9a40000000000000000000000000000000000000000000000000000000ce6282c4070dbbfd9e1d332900180c2d72f" }


這裡面我一值對其中的 raw_data_hex 很在意,因為我覺得應該在裡面可以拿到所有的資料,接下來就是我這邊測試的結果

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(); } var contractTransResult = GetTransactionByTXId("70cfc24c7fd731e1ea523268a3c9fdf738fe8ffa6ed410f520e1a32631d7b33e"); int methodOffset = contractTransResult.raw_data_hex.IndexOf("a9059cbb"); if (methodOffset == -1) { Console.WriteLine("這不是 TRC20 轉帳交易&#65281;"); return; } var rawDataHex = contractTransResult.raw_data_hex; // 顯示結果 原始 rawdata_hex Console.WriteLine(rawDataHex); Console.WriteLine("-"); //From Address int fromIndex = rawDataHex.IndexOf("0a15"); // "0a15" 是 owner_address 的標誌 if (fromIndex == -1) { Console.WriteLine("找不到 owner_address"); return; } string fromHex = rawDataHex.Substring(fromIndex + 4, 42); var fromAddress = ConvertHexToBase58Check(fromHex); Console.WriteLine("接收端地址: " + fromAddress); //To Address int toIndex = rawDataHex.IndexOf("a9059cbb"); if (toIndex == -1) { Console.WriteLine("找不到 to 地址"); return; } string toHex = rawDataHex.Substring(toIndex + 8 + 24, 40); string toAddress = ConvertHexToBase58Check("41" + toHex); Console.WriteLine("接收端地址: " + toAddress); //Contract Address int contractIndex = fromIndex + 4 + 42 + 4; // 4 是 TRON Protobuf 格式的 offset string contractHex = rawDataHex.Substring(contractIndex, 42); string contractAddress = ConvertHexToBase58Check(contractHex); Console.WriteLine("合約地址: " + contractAddress); ///金額 int amountStartIndex = methodOffset + 8 + 64; // 64 = 32 bytes (To Address) string amountHex = rawDataHex.Substring(amountStartIndex, 64); // 擷取 32 個 hex 字符 (16 bytes) BigInteger amount = BigInteger.Parse(amountHex, NumberStyles.HexNumber); Console.WriteLine("轉帳金額 (Amount): " + amount);


result:

0a0232632208e725af08821ee7de40c0fadce1d3325aae01081f12a9010a31747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e54726967676572536d617274436f6e747261637412740a15415b5978f75571b9f2525a421a2666f9b1bbbf2b10121541a614f803b6fd780986a42c78ec9c7f77e6ded13c2244a9059cbb000000000000000000000000e8b0ed1cfead30b0c6119265c12611b05f76b9a40000000000000000000000000000000000000000000000000000000ce6282c4070dbbfd9e1d332900180c2d72f

-

接收端地址: TJJDgB8hzrZZ785TthVnD2TZDRwPFevnRp

接收端地址: TXBZicX2GdcztXPM6YuCdpAUeQXQoC2cnT

合約地址: TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t

轉帳金額 (Amount): 55401000000


看起來很簡單花了一點時間跟  ChatGPT 一起處理,希望有機會幫助大家比較簡單去處理



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