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

  • 1312
  • 0
  • 2025-11-18

上一篇文章 透過 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 { get; set; }
     public List 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 { 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(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

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

--
本文原文首發於我的個人部落格:TRX 與 USDT 合約轉帳交易解析:如何獲取完整的交易資料

---

Yesterday I wrote down the code. I bet I could be your hero. I am a mighty little programmer.