在區塊鏈開發中,了解如何解析交易資料是非常重要的一環,尤其是在處理像 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(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 轉帳交易!");
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 一起處理,希望有機會幫助大家比較簡單去處理