Tron 블록체인은 저렴한 수수료와 빠른 블록 생성 시간으로 인해 많은 Web3 빌더들이 이용하고 있는 네트워크입니다.
특히 예전부터 하루에 일정량 무료로 트랜잭션을 전송할 수 있도록 하여 접근성도 좋은 편인 것 같습니다.
또한 여러 시스템 컨트랙트(Actuator)가 빌더들을 위한 기능들을 제공하고 있기도 합니다.
최근 Sun Pump가 Tron 네트워크에 릴리즈되면서 활성 어카운트가 증가하고 있습니다. 이에따라 자산 관련 TPS 까지 증가되고 있죠.
저는 증가하는 관심도에 따라 온체인 데이터를 보고 이해하는 것이 더더욱 중요하다고 생각했습니다.
따라서 이 글을 통해 Tron 의 온체인 데이터를 분석하여 누구나 온체인 데이터를 이해하고 설명할 수 있도록 공유하고자 합니다.
#1 Tron 데이터를 파헤치기 전에
이번 글에서는 자산과 관련된 온체인 데이터를 분석해볼 것입니다.
자산은 흔히 알고있는 TRX
, TRC-10
, TRC-20, 721, 1155
등의 코인과 토큰들 입니다.
데이터를 분석하기에 앞서 선행되면 좋은 Tron 의 간단한 설명과 관련 용어를 알아보도록 하겠습니다.
좀 더 깊은 지식을 원하신다면 Tron 문서를 참고해주세요!
#1-1 Resource Model
Resource Model 은 크게 Bandwidth, Energy 두 가지로 나눌 수 있습니다.
이 두 모델은 네트워크의 컴퓨팅 파워를 사용하거나, 네트워크상의 전송 비용 등을 표현합니다.
node의 wallet/getaccountresource
API 를 통해 Account의 리소스 상태를 확인할 수 있습니다.
Bandwidth Point (BP)
BP
는 하루에 Account가 사용할 수 있는 bytes의 수와 같습니다.
예를 들어 네트워크의 트랜잭션을 전송할 때 트랜잭션의 bytes가 200이면 200 BP가 소모되게 됩니다.
직접 BP 를 얻을 수도 있습니다. 방법은 TRX를 동결해서 BP를 얻는 방식입니다.
전체 네트워크의 동결된 자산의 양과 계산식에 따라 변동될 수 있습니다.
계산식은 아래와 같습니다:
BP = amount of TRX staked / total amount of TRX staked * 43_200_000_000
Tron 네트워크는 매일 무료로 BP를 제공합니다.
Account당 하루에 600 BP가 무료로 제공되며 계정 잔액이 동결되지 않았거나 BP를 모두 소진한 경우에만 사용할 수 있습니다.
과거에는 5000 BP, 1500 BP 도 제공했으나 최근 v4.7.2 버전 부터는 600 BP가 제공되고 있네요. 만약 BP가 부족한 경우, 소유하고 있는 TRX를 사용하게 됩니다.
Energy
Energy
는 스마트 컨트랙트를 실행하는 동안 소모되는 리소스입니다.
BP와 달리 무료로 제공받을 수는 없고 TRX를 스테이킹해야만 얻을 수 있습니다.
계산식은 아래와 같습니다:
amount of energy obtained = amount of TRX staked / total amount of TRX staked for obtaining energy in the whole network * 90_000_000_000
여기서 90_000_000_000
은 일일 총 Energy 공급량입니다.
Energy 역시 부족한 경우, 소유하고 있는 TRX를 사용하게 됩니다.
그 외, Dynamic Energy Model 이 존재하는데 이는 리소스 균형 메커니즘으로 리소스 점유에 따라 에너지 소비를 동적으로 조정할 수 있는 모델입니다.
데이터를 볼 때 당장 중요하지는 않으므로 자세한 내용이 궁금하시면 아래 참조를 확인해주세요.
#1-2 TRX, TRC-10
먼저 TRX
는 Tron의 공식 코인입니다. 코어에서 Account 구조의 일부입니다.
네트워크에서 블록 보상과 수수료 모델에 가장 중요한 역할을 하죠.
가장 작은 단위는 SUN
이며 1,000,000 SUN 에 1 TRX 입니다.
TRC-10
은 Tron 코어에서 발행되는 토큰입니다.
흔히 알고있는 ERC-20 과 형태는 비슷하나 스마트 컨트랙트는 아니며 코어 내부에서 관리됩니다. 실제로 Solidity 언어에서 TRX 뿐만 아니라 TRC-10 도 다룰 수 있도록 되어 있습니다.
이 토큰을 발행하려면 1024 TRX 가 필요하며 TIP-10 제안을 통해 순차적인 id 값이 생성됩니다. TRC-20(ERC-20) 처럼 스마트 컨트랙트를 배포해서 Account Address가 존재하는건 아닙니다. id 가 유일성을 보장합니다.
제가 현재까지 분석한 바로는 한 Account 당 한 개의 TRC-10 이 배포되는 것 같습니다.
TRC-10도 온체인 데이터 이므로 아래에서 자세하게 다뤄보도록 하겠습니다.
#1-3 TRC-20, 721, 1155
TRC-20, 721, 1155
는 Ethereum 에서 ERC-20, 721, 1155 토큰 표준과 동일합니다.
#1-4 Transaction
블록체인을 좋아하는 분들은 누구나 알고있는 블록체인에 상태를 변경하는 가장 기본적인 단위라 볼 수 있습니다.
Tron 역시 트랜잭션으로 자산을 전송하거나 스마트 컨트랙트를 호출하려면 트랜잭션을 생성 하고 서명해서 블록에 포함되어야 합니다.
Transaction
이 블록에 포함되면 Transaction Info
를 확인 할 수 있으며 Info에는 Receipt
, Log(event)
, Internal Transaction
정보가 포함됩니다.
Tron은 core 에서 다양한 기능들을 미리 구현해뒀습니다. 이러한 기능들은 System Contract(Actuator)
로 불리며 트랜잭션을 통해 사용해볼 수 있습니다.
제가 조사해봤을 때는 System Contract는 약 40개 정도 존재하는 것으로 파악했습니다. 또한 구현되어 있지만 네트워크 상에서 사용되지 않는 케이스도 있었습니다.
Transaction은 온체인 데이터를 분석할 때 매우 중요힙니다.
이번 글에서 Transaction과 몇 가지 주요 System Contract를 다뤄보도록 하겠습니다.
#2 온체인 데이터 파헤치기
이제 본격적으로 앞서 언급했던 자산과 관련된 온체인 데이터를 분석해보겠습니다.
Transaction과 주요 System Contract 들에 대해서 상세하게 파악해보고 앞으로 Tron 데이터를 읽을 때 많은 도움이 되었으면 좋겠습니다.
데이터는 Tron Node 에서 HTTP API
, gRPC
, JSONRPC(Ethereum 호환)
를 통해 온체인 데이터를 조회할 수 있습니다.
아마 대부분 익숙한 JSONRPC 로 온체인 데이터를 조회할텐데요.
JSONRPC 를 통해 Tron 데이터를 조회하면 일부 데이터에 대해서는 조회가 불가능할 것입니다.
따라서 저는 HTTP API 를 통해서 분석해보도록 하겠습니다.
참고로 java-tron, tronprotocol에서 어떤 Contract 들이 존재하는지 확인 해보실 수 있습니다.
관심있으시면 더 상세한 정보들도 확인해보세요!
#2-1 Transaction과 Transaction Info
가장 기본적으로 Transaction
과 Transaction Info
에 대해 먼저 알아야 합니다.
수수료가 어떻게 쓰였고, 어떤 System Contract를 호출했는지 등의 기본적인 정보들을 다 가지고 있습니다.
wallet/gettransactionbyid
, wallet/gettransactioninfobyid
API를 통해서 조회할 수 있습니다.
Transaction Response
{
"signature": [...],
"txID": "...",
"raw_data": {
"contract": [{
...,
"type": "..."
}],
"ref_block_bytes": "...",
"ref_block_hash": "...",
"expiration": ...
},
"raw_data_hex": "..."
}
signature
가 배열인 이유는 Multi-Signature 때문입니다. 보통은 배열에 하나의 요소만 존재할 것입니다.
데이터를 분석하기에 가장 중요한 field는 raw_data.contract
입니다.
앞서 설명드린 것처럼 Tron 은 모든 트랜잭션이 System Contract를 통해서 처리됩니다. 그 부분이 raw_data.contract
에서 System Contract 데이터가 달라지는 것이죠.
raw_data.contract.type
에서 어떤 컨트랙트 타입을 호출했는지 확인할 수 있습니다.
가장 기본적인 코인 전송 수량이 안보이시죠? raw_data.contract
안에서 볼 수 있으며 type 에 따라 field 명이 달라집니다. 아래에서 상세하게 다뤄보도록 하겠습니다.
raw_data.contract
를 자세히 보시면 배열 형태를 나타내고 있는데 실제 머나먼 과거 데이터에서 배열로 들어오던 케이스가 있었습니다. 하지만 현재는 배열 안에 단 하나의 요소만 있으니, 단일 요소만 있다고 파악하시면 됩니다.
contract 에 대한 상세 내용은 아래에서 다루도록 하겠습니다. 여기에선 기본적인 데이터만 이해하시면 됩니다.
나머지 데이터들은 당장 중요하지 않으니 넘어가도록 하겠습니다.
참고로 System Contract Type 은 tronprotocol에서 자세한 스펙을 확인해보실 수 있습니다.
Transaction Info
{
"id": "...",
"fee": ...,
"blockNumber": ...,
"blockTimeStamp": ...,
"contract_address": "...",
"receipt": {
"energy_usage": ...,
"energy_fee": ...,
"origin_energy_usage": ...,
"energy_usage_total": ...,
"net_usage": ...,
"net_fee": ...,
"energy_penalty_total": ...,
"result": "SUCCESS", // FAILED
...
},
"log": [...],
"internal_transactions": [...],
...
}
Transaction Info 역시 System Contract 에 따라 다양한 데이터가 포함됩니다.
일단 위의 데이터는 핵심 데이터 위주로만 작성했습니다.
id
는 transaction의 txID와 동일합니다. field 이름의 통일성이 없는게 조금 아쉽네요.
fee
는 이 트랜잭션 수수료로 사용한 전체 TRX 총량입니다. 여기서 조금 헷갈릴 수 있지만 나머지 설명을 끝내고 정리하겠습니다.
block_number
, block_timestamp
은 트랜잭션이 포함된 블록의 정보입니다.
contract_address
는 TriggerSmartContract
를 통해 호출한 contract 주소 입니다. TriggerSmartContract 는 흔히 알고있는 Smart Contract를 호출할 때 쓰이는 System Contract 입니다.
receipt
은 트랜잭션의 성공 실패나 상세한 수수료 정보를 포함하고 있습니다. fee 와 동일하게 아래에서 상세하게 설명하겠습니다.
log
는 스마트 컨트랙트의 event 입니다.
internal_transactions
는 호출했던 스마트 컨트랙트가 내부 로직에서 다른 컨트랙트를 호출할 때 TRX, TRC-10 자산 이동이 있었는지 알 수 있는 데이터입니다.
다만 아쉬운 점이 있는데 내부에서 어떤 기능을 호출했는지를 알 수는 없었습니다. 아래에서 다시 다루도록 하겠습니다.
수수료
다시 fee 와 receipt 에 대해서 분석해보겠습니다.
선행으로 배웠던 Resource Model 에서 Bandwidth(net), Energy 가 부족할 대 TRX를 사용한다고 했습니다.
먼저 리소스 소모량은 receipt 에 _usage
가 붙은 데이터에서 확인 가능합니다. receipt.energy_usage
, receipt.net_usage
, receipt.origin_energy_usage
이 되겠군요.
여기서 receipt.origin_energy_usage
는 스마트 컨트랙트를 배포할 때 사용된 Energy 수량입니다.
receipt.energy_usage_total
는 전체 Energy 소모량이 됩니다. 여기서 헷갈릴 수도 있는데 Energy 수량이 부족해서 TRX를 사용하게 되도 이 값은 존재하게 되는데요.
이는 1 Energy 당 210 SUN 으로 계산됩니다.
receipt.energy_usage_total = receipt.energy_usage + receipt.origin_energy_usage
or
receipt.energy_usage_total = energy_fee / 210
사용할 리소스가 없을 땐 _fee
를 통해 TRX 소모량을 확인할 수 있습니다. receipt.energy_fee
, receipt.net_fee
가 리소스를 대체한 TRX 소모량입니다.
이 데이터를 합산한 것이 위에 설명한 것처럼 Info의 fee
가 됩니다.
fee = receipt.energy_fee + receipt.net_fee
마지막으로 receipt.energy_penalty_total
은 Dynamic Energy Model 과 관련있습니다.
Tron 은 독특하게 인기있는 스마트 컨트랙트에게 패널티를 부여합니다. 이는 Resource가 한정적이기 때문에 그렇다고 하네요.
예시
{
"id": "9735cac6d402d17056ed4505e0071ea77512273be9422bd4937806158e546a82",
"fee": 13499850,
"blockNumber": 67844603,
"blockTimeStamp": 1734184338000,
"contract_address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"receipt": {
"energy_fee": 13499850,
"energy_usage_total": 64285,
"net_usage": 345,
"result": "SUCCESS",
"energy_penalty_total": 49635
},
"log": [...],
...
}
이 데이터는 USDT 토큰의 Transfer 함수를 실행한 Transaction Info 입니다.
먼저 Tron 에서 가장 활발한 스마트 컨트랙트이기 때문에 패널티가 붙은 모습을 볼 수 있네요.
energy_fee
를 보니 Energy Resource 가 부족해서 TRX 를 사용했나봅니다. 전체 합계인 fee
와 동일하네요.
energy_usage_total
는 energy_fee / 210 으로 계산하면 되겠죠? (64285 = 13499850 / 210)
net_usage
를 사용하셨네요. BP 가 충분했나봅니다.
이제 tronscan을 통해서 보면,
이제 트랜잭션을 볼 때 어떻게 TRX 가 사용되었는지, Resource 가 사용되었는지 이해하셨습니다.
#2-2 Internal Transaction
위에서 설명한 것처럼 Transaction Info 에 포함되어 있습니다. 다만 이 데이터를 API 를 통해 보려면 node 에 아래 값들을 활성화시켜줘야 됩니다.
vm = {
...
saveInternalTx = true
saveFeaturedInternalTx = true
...
}
하지만 활성화 시점부터 조회가 가능합니다. 이전 데이터는 Tron 에서 제공하는 Node Snapshot 을 이용하거나 Genesis Block 부터 다시 받아야 됩니다.
데이터는 다음과 같습니다:
// Transaction Info 의 일부
{
...,
"internal_transaction": [
"hash": "...",
"caller_address": "...",
"transferTo_address": "...",
callValueInfo: [
{
"callValue": ...,
"tokenId": "",
},
...
],
"note": ...,
"rejected": ...
]
}
hash
는 Internal Transaction의 고유한 값을 나타냅니다. Transaction의 id 값과 다릅니다.
caller_address
와 transferTo_address
는 흔히 알고 있는 from, to 주소 정보가 됩니다. Internal Transaction 이므로 caller_address 는 스마트 컨트랙트의 주소가 될 것입니다.
callValueInfo
가 자산과 관련된 정보입니다. TRC-10 도 스마트 컨트랙트에서 TRX 처럼 전송이 가능합니다. 그래서 tokenId
값이 어떤 TRC-10 인지 알 수 있습니다.
만약 tokenId 가 비어있으면 TRX 를 전송한 것입니다. 수량은 callValue
를 통해 알 수 있습니다.
개인적으로 어떤 기능을 호출했는지 input 값이 있었더라면 좋았을 것 같네요.
#2-3 System Contract
이제 본격적으로 Transaction 에서 raw_data.contract
에 해당하는 System Contract 에 대해서 분석해봅시다.
#2-3-1 AccountCreateContract
AccountCreateContract
는 새로운 Account를 네트워크에 활성화시킵니다.
Tron 은 Account 를 활성화 시켜야 블록체인 원장에 기록됩니다.
Node의 wallet/createaccount
API 를 통해서 Account를 활성화 시키지만, 굳이 사용하지 않고도 TRX
, TRC-10
전송만으로 새로운 Account가 활성화 됩니다. 현재 필요로하는 수수료를 보고 판단할 수는 있겠으나 과거에는 지금과 달라서 판단이 어렵기도 합니다.
자산 이동과 관련된건 아니지만 알고있으면 좋을 것 같아서 넣어봤습니다.
예제
{
"signature": [...],
"txID": "0409c784cd51543340ad13c2ecf300201a1a9678934fc6392d45ce8bbbad1d9f",
"raw_data": {
"contract": [
{
"parameter": {
"value": {
"owner_address": "TW5nGmU4KuZZoactLZ7y7FZnhx6H1jTxLj",
"account_address": "TMmXir2ohc7eTZFZxn1P6AeTbJnwLrT7b5"
},
"type_url": "type.googleapis.com/protocol.AccountCreateContract"
},
"type": "AccountCreateContract"
}
],
"ref_block_bytes": "8ad8",
"ref_block_hash": "c4c1dc14e7f872d2",
"expiration": 1530784992000
},
"raw_data_hex": "..."
}
raw_data.contract
만 보면 됩니다. type
이 AccountCreateContract 라고 친절히 설명해주고 있네요.
데이터를 분석하면 owner_address
가 신규 account_address
Account 를 활성화 시켰다로 볼 수 있습니다.
#2-3-2 TransferContract
TransferContract
는 가장 기본적인 TRX 전송 컨트랙트입니다.
예제
{
"signature": [...],
"txID": "0e40b1141a41ca6f4acb52341f17b2e5cbcdb161150362ca40e1eff3ae16eceb",
"raw_data": {
"contract": [
{
"parameter": {
"value": {
"amount": 100000,
"owner_address": "TGPnfvkVkUdyCWmrVGnQ9jFW5Ca1S7XH6h",
"to_address": "T9yxiz8M6EJ3RcDPMJo22HrGAwUZ2753u7"
},
"type_url": "type.googleapis.com/protocol.TransferContract"
},
"type": "TransferContract"
}
],
"ref_block_bytes": "07da",
"ref_block_hash": "7ad993fc087fce41",
"expiration": 1529897868000,
"timestamp": 1529897570464000000
},
"raw_data_hex": "..."
}
owner_address
가 to_address
에게 amount
만큼 전송했네요.
amount는 SUN 단위이므로 TRX 로 환산하면 0.1 TRX 를 전송했습니다.
#2-3-3 TransferAssetContract
TransferAssetContract
는 TRC-10 을 전송하는 컨트랙트입니다.
asset 으로 TRC-10 을 표현했는데 Internal Transaction 에서 보셨던 것처럼 token 으로 표현하기도 합니다. 개인적으로 field 이름을 통일성있게 설계했으면 가독성이 좋았을 것 같네요.
예제 1
{
...
"txID": "3426db0be3d16fd1601b674e84c5ff31947aee0e2fbd99a830ff84298c3de564",
"raw_data": {
"contract": [
{
"parameter": {
"value": {
"amount": 1,
"asset_name": "Bitcoin",
"owner_address": "TAEvaU3YDxjcQBHNv4PLAMJqvcJdSWdhiM",
"to_address": "TCHLAjmhPBEpR1Qi9g9KAmBPiuMQkjNrRp"
},
"type_url": "type.googleapis.com/protocol.TransferAssetContract"
},
"type": "TransferAssetContract"
}
],
"ref_block_bytes": "8b52",
"ref_block_hash": "2dbca869a78e9721",
"expiration": 1535515809000,
"timestamp": 1535515750703
},
...
}
TRX 전송 컨트랙트와 크게 다르지 않습니다.
owner_address
가 to_address
에게 amount
만큼 asset_name
을 전송했네요.
그런데 왜 TRC-10 의 id 가 아닌 asset_name 일까요?
위의 예제 1 의 트랜잭션은 2018 년 9월 달의 트랜잭션 입니다. 최근 트랜잭션에서는 id 값으로 조회됩니다.
예제 2
{
...,
"txID": "2860325a5c7a0a4402451cc026f9c6a87e0410febe860f1501efdbac06b2c4a1",
"raw_data": {
"contract": [
{
"parameter": {
"value": {
"amount": 11654260000,
"asset_name": "1002000",
"owner_address": "TXdaiUHATBx1y2z9PMihv8ssqNJarWxyrU",
"to_address": "TYYWL9khqAfNC7goamRMF4guVahupoHSAy"
},
"type_url": "type.googleapis.com/protocol.TransferAssetContract"
},
"type": "TransferAssetContract"
}
],
...
}
이 트랜잭션은 asset_name
이 id 값입니다.
즉 과거에는 field 이름의 의미대로 name 이 나왔지만 현재는 id 로 결과가 나온다는 것입니다.
정확하게는 TIP-10
전과 후로 나뉩니다.
TIP-10 에 대해서 간단히 설명하면 name 중복이 불가능했다가 가능하도록 변경하자는 제안입니다. 또한 이때 부터 id 가 추가되었고 ERC-20 의 decimal 처럼 precision 가 추가되어 소수점 표기를 가능하게 했네요.
TransactionAssetContact 도 영향을 받습니다. asset_name 이름은 과거부터 있었기 때문에 호환성을 위해 이름과 값 타입을 변경하지 않고 값 자체만 변경한 것입니다.
그렇다면 예제 1 의 asset_name 은 어떤 TRC-10 일까요?
tronscan 보기
예제 1
의 Bitcoin 을 찾아내고 있네요.
Amount 의 BTC 를 클릭하면 해당 TRC-10 토큰 정보 페이지로 넘어갑니다.
스캔도 알고 있으니 우리도 직접 분석해낼 수 있습니다.
TIP-10 이전의 토큰 찾기
이젠 asset_name 은 중복이 가능합니다. 따라서 asset_name 으로 TRC-10 을 찾을 땐 유일성이 보장되지 않죠.
하지만 찾는 방법은 매우 간단합니다.
방법은 wallet/getassetissuelistbyname
에서 가장 낮은 id 찾는 것입니다.
예제 1
처럼 asset_name 이 id 가 아닌 트랜잭션은 asset_name 그 자체 토큰이 TIP-10 이전에는 단 하나였다는 겁니다.
즉, 배포 시점이 가장 오래된 TRC-10 토큰이겠죠.
예제 1 의 "Bitcoin" 이름을 갖는 TRC-10 토큰으로 확인해보겠습니다.
{
"assetIssue": [
{
"owner_address": "TV7Tkx7XiFVYUCy8q7dkn3iQsBNuuGvoCK",
"name": "Bitcoin",
"abbr": "BTC",
"total_supply": 21000000,
"trx_num": 1000000,
"num": 1,
"start_time": 1529991531000,
"end_time": 1561441020000,
"description": "Bitcoin is an innovative payment network and a new kind of money.",
"url": "http://bitcoin",
"id": "1000004"
},
{
"owner_address": "TBNmtwdvevnd6uHUimUFLDD7odEzEFJegD",
"name": "Bitcoin",
"abbr": "BTC",
"total_supply": 21000000000000,
"frozen_supply": [
{
"frozen_amount": 20000000000000,
"frozen_days": 30
}
],
"trx_num": 1000000,
"precision": 6,
"num": 1000000,
"start_time": 1553184000000,
"end_time": 1561132800000,
"description": "True Bitcoin",
"url": "https://bitcoin.org",
"id": "1002211"
},
{
"owner_address": "THBFadZJEk8Wg8dVuYRJUhbJky1HLtfn7y",
"name": "Bitcoin",
"abbr": "BTW",
"total_supply": 2.1e18,
"trx_num": 888000000,
"precision": 4,
"num": 247980000,
"start_time": 1609023600000,
"end_time": 1609110000000,
"description": "Bitcoin Token ses peer-to-peer technology to operate with no central authority or banks; managing transactions and the issuing of bitcoins is carried out collectively by the network.",
"url": "https://bitcoin.org/",
"id": "1003591"
},
{
"owner_address": "TH8kLNBptvnV4w5LbokEeApc9mhqwt2YLH",
"name": "Bitcoin",
"abbr": "BITCOIN",
"total_supply": 25000000,
"trx_num": 1000000,
"precision": 1,
"num": 10,
"start_time": 1640732400000,
"end_time": 1640818800000,
"description": "Bitcoin uses peer-to-peer technology to operate with no central authority or banks; managing transactions and the issuing of bitcoins is carried out collectively by the network. Bitcoin is open-source",
"url": "https://bitcoin.org/",
"id": "1004673"
}
]
}
id가 1000004 인 TRC-10 토큰의 TransactionAssetContract 트랜잭션이었네요.
TIP-10 에 대해서 자세한 내용은 tronprotocol/tips를 참고해주세요.
#2-3-4 ParticipateAssetIssueContract
ParticipateAssetIssueContract
는 TRX 로 TRC-10 을 구매하는 컨트랙트입니다.
예제
{
...,
"txID": "bcae3954e4157cb904c67b6a3de9aea7224f6a4713fd805176cb9aef15f81de9",
"raw_data": {
"contract": [
{
"parameter": {
"value": {
"amount": 25000000,
"asset_name": "$EED",
"owner_address": "TXw7nYSoxrzUHtXqC61AWqtVdyr75byoLa",
"to_address": "TVWbwZ13tPjRUgXn1rKHmR1Nf6szgEftB8"
},
"type_url": "type.googleapis.com/protocol.ParticipateAssetIssueContract"
},
"type": "ParticipateAssetIssueContract"
}
],
"ref_block_bytes": "3464",
"ref_block_hash": "c45fbc3133f9bcf2",
"expiration": 1533081996000,
"timestamp": 1533081945183
},
...
}
여기서 살짝 헷갈리 수 있습니다.
owner_address
가 amount
를 주고 to_address
에서 asset_name
을 구매한 것입니다. 그런데 몇 개의 TRC-10 토큰을 구매한지는 알 수 없습니다. 별도 계산이 필요한데요.
먼저 알아야할 사항은 TRC-10 의 trx_num
, num
데이터들 입니다. wallet/getasset...
API 들을 통해 확인할 수 있습니다.
$EED 토큰으로 분석해보죠.
토큰 정보 찾기
우리가 아는 사실은 asset_name 뿐이니wallet/getassetissuelistbyname
으로 조회해보도록 하겠습니다.{ "assetIssue": [ { "owner_address": "TVWbwZ13tPjRUgXn1rKHmR1Nf6szgEftB8", "name": "$EED", "abbr": "$EED", "total_supply": 1000000000000, "trx_num": 1000000, "num": 2, "start_time": 1532814900950, "end_time": 1564338660950, "description": "SEED", "url": "sesameseed.org", "id": "1000301" } ] }
trx_num
,num
으로 구매한 TRC-10 개수 확인하기
계산식은 매우 간단합니다. (코드)// java-tron 코드 일부 long exchangeAmount = Math.multiplyExact(cost, assetIssueCapsule.getNum()); exchangeAmount = Math.floorDiv(exchangeAmount, assetIssueCapsule.getTrxNum()); ownerAccount.addAssetAmountV2(key, exchangeAmount, dynamicStore, assetIssueStore); ... AccountCapsule toAccount = accountStore.get(toAddress); toAccount.setBalance(Math.addExact(toAccount.getBalance(), cost)); if (!toAccount.reduceAssetAmountV2(key, exchangeAmount, dynamicStore, assetIssueStore)) { throw new ContractExeException("reduceAssetAmount failed !"); }`
코드를 통해 얻은 계산 식은 아래와 같습니다.
TRC-10 수량 = amount(cost) x num / trx_num
정리하면,
owner_address
가to_address
에게amount
=25000000 를 주고,to_address
가asset_name
토큰을 25000000 x 2 / 1000000 =50
을 전송
#2-3-5 TriggerSmartContract
TriggerSmartContract
는 스마트 컨트랙트를 호출할 때 사용됩니다.
TRC-20 을 전송하는 트랜잭션이라면 TriggerSmartContract 타입의 트랜잭션이죠.
예제
{
...,
"txID": "e81456cb9523cf6abf36347d714f2c9a04504d1a47639b4b553a2d195da9937b",
"raw_data": {
"contract": [
{
"parameter": {
"value": {
"data": "a3082be900000000000000000000000000000000000000000000000000000000000000090000000000000000000000000000000000000000000000000000000000000001",
"owner_address": "TB4XxoJQ2vyyYffNJgi3ge81QfbiuGzHdm",
"contract_address": "TEEXEWrkMFKapSMJ6mErg39ELFKDqEs6w3",
"call_value": 250000000
},
"type_url": "type.googleapis.com/protocol.TriggerSmartContract"
},
"type": "TriggerSmartContract"
}
],
"ref_block_bytes": "4ba2",
"ref_block_hash": "be22ab2ceb21bd29",
"expiration": 1545002346000,
"fee_limit": 6000000,
"timestamp": 1545002289587
},
...
}
이 트랜잭션은 owner_address
가 contract_address
스마트 컨트랙트에게 data
를 실행하면서 call_value
만큼 TRX 를 전송하고 있네요.
TRX 뿐만 아니라 TRC-10 도 전송할 수 있습니다.
아래에 구조를 확인해보시면,
message TriggerSmartContract {
bytes owner_address = 1;
bytes contract_address = 2;
int64 call_value = 3;
bytes data = 4;
int64 call_token_value = 5;
int64 token_id = 6;
}
call_token_value
, token_id
를 볼 수 있습니다.
이 값들이 존재한다면 TRC-10 도 컨트랙트에게 전송한 것으로 분석하면 됩니다.
보통 _value
를 전송하게 된다면 Internal Transaction 도 있을 수 있습니다. 가능하면 정확한 자산 이동을 분석하기 위해 Internal Transaction 까지 분석하는게 좋겠네요.
#2-3-6 ExchangeCreateContract
Tron 은 TRX <-> TRC-10, TRC-10 <-> TRC-10 DEX 가 코어에 존재합니다.
Exchange 라고 불리고 API 로 쉽게 사용할 수 있습니다. 현재는 잘 사용되지는 않지만 과거에 사용되었던 자산 이동은 이미 벌어진 일이니 데이터를 읽을 수는 있어야 합니다.
또한 개선되거나 새로운 기능이 추가될 수도 있죠. 아무튼 그 중에 첫 번째로 ExchangeCreateContract
를 분석해보겠습니다.
이 컨트랙트는 이름 그대로 Exchange를 새롭게 생성합니다.
예제 1
...,
"txID": "11115b0e5bc868b94cc26b4d4c273f0aa641f6f202f2ac9aa2e674f8f1beeccc",
"raw_data": {
"contract": [
{
"parameter": {
"value": {
"first_token_balance": 1875000,
"first_token_id": "LoveHearts",
"owner_address": "TJPTRXBBYdqWHRb4gZ3uG2KARrmetoveoL",
"second_token_id": "TRONGOLD",
"second_token_balance": 1500000
},
"type_url": "type.googleapis.com/protocol.ExchangeCreateContract"
},
"type": "ExchangeCreateContract"
}
],
"ref_block_bytes": "45a7",
"ref_block_hash": "f80086d084652c6d",
"expiration": 1542991974000
},
...
}
owner_address
는 새로운 Pair(Exchange)를 생성합니다.
first, second 모두 token_id 에 이름이 있는 것을 보니 TRC-10 <-> TRC-10 쌍을 생성하고 있네요.
first_token_id
의 first_token_balance
와 second_token_id
의 second_token_balance
만큼 쌍을 생성하고 있습니다.
모두 owner_address
에서 자산이 이동되었습니다.
추가로 Transaction Info를 보면,
{
"id": "11115b0e5bc868b94cc26b4d4c273f0aa641f6f202f2ac9aa2e674f8f1beeccc",
"fee": 1024000000,
"blockNumber": 4343209,
"blockTimeStamp": 1542991680000,
"contractResult": [
""
],
"receipt": {
"net_usage": 269
},
"exchange_id": 91
}
exchange_id
가 생성된 것을 볼 수 있습니다.
앞으로 wallet/getexchangebyid
API 를 통해서 pair 정보를 확인할 수 있게 됩니다.
그리고 TRX <-> TRC-10 도 가능하다고 했는데요.
TRX 는 token_id 가 없어서 _
으로 표시됩니다.
아래 예제 2를 보시면,
예제 2
{
...,
"txID": "b4735fdbf6ae79bc57f20f303c2fc2df7a858365bd09532262d4f410c9294fa1",
"raw_data": {
"contract": [
{
"parameter": {
"value": {
"first_token_balance": 10000,
"first_token_id": "TRONATLAS",
"owner_address": "TNfR9coWH76XNFwhJd4XS5ysFcYW3JfxD8",
"second_token_id": "_",
"second_token_balance": 1000000
},
"type_url": "type.googleapis.com/protocol.ExchangeCreateContract"
},
"type": "ExchangeCreateContract"
}
],
"ref_block_bytes": "7a92",
"ref_block_hash": "c367c7f169708863",
"expiration": 1544221803000
},
...
}
second_token_id 이 _
으로 되어있으니 TRX 를 1000000 SUN 만큼 쌍으로 만들었다고 보시면 됩니다.
#2-3-7 ExchangeInjectContract
ExchangeInjectContract
는 Exchange 에 Pair에 어느 한족 토큰을 추가로 주입하는 컨트랙트입니다.
예제
{
...,
"txID": "3d11aa9806b6eb45f4c26fbdaccfe915e83c2e027402c4bb565aace9597353fd",
"raw_data": {
"contract": [
{
"parameter": {
"value": {
"exchange_id": 134,
"token_id": "_",
"owner_address": "TYftfpnCitoxju9rMYx6XNegUHmFoPMary",
"quant": 100000000000
},
"type_url": "type.googleapis.com/protocol.ExchangeInjectContract"
},
"type": "ExchangeInjectContract"
}
],
"ref_block_bytes": "e906",
"ref_block_hash": "12026db87bb2c539",
"expiration": 1545132804000
},
...
}
owner_address
가 quant
만큼 token_id
를 exchange_id
에 주입시켰네요.
token_id 가 _
이니까 owner_address 는 100,000,000,000 SUN (100,000 TRX) 만큼 사용했습니다.
#2-3-8 ExchangeWithdrawContract
ExchangeWithdrawContract
은 Exchange 에서 자신이 Pair에 주입했던 토큰을 출금하는 컨트랙트입니다.
예제
{
...,
"txID": "9a2e31c618b7ff066637966b0e1f26d28e28593919842698325c1fd09ae79229",
"raw_data": {
"contract": [
{
"parameter": {
"value": {
"exchange_id": 46,
"token_id": "_",
"owner_address": "TJhZzCtF5macLpJuEYFRSMgcvi7g2e3tKo",
"quant": 159059000000
},
"type_url": "type.googleapis.com/protocol.ExchangeWithdrawContract"
},
"type": "ExchangeWithdrawContract"
}
],
"ref_block_bytes": "cef0",
"ref_block_hash": "31e87e7d8963bfe3",
"expiration": 1542500319000
},
...
}
owner_address
가 quant
만큼 token_id
를 exchange_id
에서 출금했습니다.
owner_address 는 자신의 지갑에 TRX 가 증가하고 Pair 에서는 TRX 수량이 줄어들었겠네요.
#2-3-9 ExchangeTransactionContract
ExchangeTransactionContract
는 Pair 에서 쌍이되는 토큰을 교환하는 컨트랙트입니다.
Swap 이라고도 부릅니다.
예제
{
...,
"txID": "f5bc35c6ab42bcc4aaa537e02910d072830a99a9c741b3e7236518a876d72db5",
"raw_data": {
"contract": [
{
"parameter": {
"value": {
"exchange_id": 69,
"token_id": "ReynaToken",
"expected": 1978730300,
"owner_address": "TBAL1iNxXo63922jgnBCphktwv3CPmfcQa",
"quant": 1000000
},
"type_url": "type.googleapis.com/protocol.ExchangeTransactionContract"
},
"type": "ExchangeTransactionContract"
}
],
"ref_block_bytes": "a8dd",
"ref_block_hash": "54e7ff8921310e6b",
"expiration": 1543659708000
},
...
}
owner_address
가 quant
만큼 token_id
를 exchange_id
Pair 에서 상대 토큰과 교환합니다.
트랜잭션에서 expected
를 통해 기대 값을 확인할 수 있지만 실제로 상대 토큰의 교환 수량은 다릅니다.
실제 수량은 Transaction Info 에서 확인할 수 있습니다.
{
"id": "f5bc35c6ab42bcc4aaa537e02910d072830a99a9c741b3e7236518a876d72db5",
"fee": 2680,
"blockNumber": 4565215,
"blockTimeStamp": 1543659414000,
"contractResult": [
""
],
"receipt": {
"net_fee": 2680
},
"exchange_received_amount": 2055561166
}
exchange_received_amount
이 실제 수량입니다.
상대 토큰이 무엇인지 확인하려면 트랜잭션에서 exchange_id
가 있으니 wallet/getexchangebyid
API 를 통해 확인 가능합니다.
"first_token_id": "31303030383933"
...
"second_token_id": "5f"
해당 값은 byte string 으로서 변환시키면 first_token_id는 1000893 이고 second_token_id는 _ 으로 TRX 입니다.
그렇다면 owner_address 는 2,055,561,166 SUN (2,055.561166 TRX) 를 얻으셨네요.
#3 결론
여기까지 대표적인 자산 이동과 관련된 온체인 데이터를 분석해봤습니다.
아마 현재 Tron 에서는 TRC-20 등의 스마트 컨트랙트 자산들이 매우 활성화되어 있을겁니다. 이에 따라 Account 도 늘어나고 있습니다.
또한 자산을 동결 및 스테이킹하여 네트워크의 Resource 를 얻을 수 있는 FreezeBalanceV2Contract
, UnFreezeBalanceV2Contract
System Contract 도 존재합니다.
자기 자신의 자산을 동결하는 정도라 이번에는 다루지 않았습니다.
앞으로 Tron 은 TIP 를 통해 계속 발전할 것입니다. 이 또한 온체인 상에서 제안에 대한 투표를 진행하죠.
계속해서 새로운 데이터들도 생기는 것이니 온체인 데이터에 대한 안목을 넓히는게 중요합니다.
Tron 온체인 데이터에 가까워 졌을거라 생각하며 이만 마치겠습니다.
긴 글 읽어주셔서 감사합니다.
안녕하세요 스팀잇 세계에 오신것을 환영합니다.
저는 여러분이 스팀잇에 잘 적응 할 수 있도록 응원하고 있습니다.
이 포스팅을 한번 끝까지 읽어보시고 STEEMIT-초보자를위한 가이드
혹시나 궁금하신 내용이 있으면 언제든
@ayogom, @jungjunghoon, @powerego, @tworld, @dorian-lee, @bitai, @kinghyunn, @maikuraki, @hiyosbi, @nasoe, @angma, @raah 님께 댓글 주시면 친절하게 알려드리겠습니다.
카카오톡 방에서 궁금한 점도 한번 해결해 보세요. 많은 스팀잇 경험자 분들께서 언제나 궁금한 부분을 즉시 해결해 주실 것입니다. 카카오톡 대화방 바로가기 패스워드(1004)
Downvoting a post can decrease pending rewards and make it less visible. Common reasons:
Submit
12/1~20 사이에 처음 가입하신분들은 아래 포스팅을 읽고 이벤트 참여해보세요. 30스팀을 드립니다.
https://steemit.com/kr/@goodpost-kr/30-12-1-20
Downvoting a post can decrease pending rewards and make it less visible. Common reasons:
Submit