본문으로 건너뛰기
버전: 3.3.0

송금 성공 판단 방법

iost, irc20, irc21 토큰의 송금을 판정하는 방법은 거의 동일하며, receipt에서 토큰 심볼만 구분하면 됩니다.

송금 트랜잭션의 성공 판정

트랜잭션이 송금을 포함하고 그 송금이 성공했음을 확인하려면 다음 두 가지를 판단해야 합니다. 트랜잭션이 불가역(irreversible) 상태인지, 그리고 트랜잭션이 송금 정보를 포함하면서 성공적으로 실행되었는지입니다.

트랜잭션의 불가역 여부 판단

트랜잭션이 불가역인지 판단하는 방법은 세 가지가 있습니다.

  • getTxByHash API를 호출하여 반환값의 status 필드가 IRREVERSIBLE이면 트랜잭션이 불가역입니다.
  • getTxReceiptByTxHash API를 호출(이 API는 불가역 트랜잭션에 대해서만 TxReceipt를 반환합니다)하여 반환값이 존재하면 트랜잭션이 불가역입니다.
  • getBlockByNumber 또는 getBlockByHash API를 호출하여 반환값의 status 필드가 IRREVERSIBLE이면 해당 블록의 모든 트랜잭션이 불가역입니다.

트랜잭션이 송금을 포함하며 성공 실행되었는지 판단

트랜잭션에 송금이 포함되어 있는지 판단하는 유일한 방법은 tx_receipt의 receipts 필드를 확인하는 것입니다. tx_receipt는 getTxByHash API와 getTxReceiptByTxHash API로 얻을 수 있고, getBlockByNumbergetBlockByHash API가 반환하는 블록 구조에도 트랜잭션들의 tx_receipt가 포함됩니다. 성공한 송금 트랜잭션의 receipts는 다음과 같은 형태입니다.

"tx_receipt": {
"tx_hash": "CHeKFLzzpcfZ2Fo9gHwRM7PFkZy5SoEKSda2ZrTYfHQf",
"gas_usage": 8750,
"ram_usage": {},
"status_code": "SUCCESS",
"message": "",
"returns": [
"[]"
],
"receipts": [
{
"func_name": "token.iost/transfer",
"content": "[\"iost\",\"fromacc\",\"toacc\",\"1.0000\",\"\"]"
}
]
},

receipts 필드는 리스트입니다. 한 항목의 func_name 필드가 token.iost/transfer이면 그 트랜잭션에 송금이 포함된 것입니다(iost든 irc20이든 irc21이든 func_name은 동일하게 token.iost/transfer입니다). 송금의 토큰 심볼, 계정, 금액은 해당 항목의 content 필드에서 추가로 파싱해야 합니다. content 필드는 다섯 개의 문자열을 담은 배열의 JSON 직렬화 결과입니다. JSON 역직렬화하면 첫 번째 요소가 토큰 심볼(토큰 심볼은 모든 토큰에서 유일합니다), 두 번째가 송금 계정명, 세 번째가 수령 계정명, 네 번째가 송금 금액, 다섯 번째가 memo입니다. 네 번째 요소인 송금 금액을 다룰 때 [0-9.] 이외의 문자가 포함된 문자열이 발견되면 그 송금은 무시해야 합니다. 그 외의 경우라면 해당 문자열을 직접 float으로 변환해 후속 처리에 사용할 수 있습니다.

트랜잭션 실행이 성공했음을 확인하려면 tx_receiptstatus_code 필드가 SUCCESS와 같은지 확인해야 합니다.

자주 발생하는 실수

actions로 송금 성공을 판정

actions는 트랜잭션의 동작 목록이고 receipts는 트랜잭션의 실행 결과입니다. 트랜잭션의 actions 필드만 보고 송금의 성공을 판정하는 것은 엄밀하지 않습니다. 일부 특수한 경우(예: 지연 트랜잭션)에서는 tx_receipt의 status_codeSUCCESS라도 트랜잭션이 실제로 성공적으로 실행되지 않았을 수 있고, 반대로 송금 트랜잭션이 실제로 성공했다면 반드시 receipts가 있어야 합니다. 따라서 송금 성공 여부는 actions가 아니라 receipts 필드로만 판단해야 합니다.

송금 금액 문자열을 직접 float으로 변환

메인넷 token.iost 컨트랙트의 송금은 토큰 decimal에 맞춰 송금 금액을 절단한 뒤 그 결과를 float으로 변환하는 방식으로 처리됩니다. 따라서 다음과 같은 송금에서

"receipts": [
{
"func_name": "token.iost/transfer",
"content": "[\"iost\",\"aaaaa\",\"bbbbb\",\"1.20294517598E7\",\"\"]"
}
]

실제로 송금된 토큰 양은 1.20294517입니다. "1.20294517598E7"를 그대로 float으로 변환하면 예상과 다른 결과가 나올 수 있습니다. 따라서 송금 금액 문자열에 [0-9.] 이외의 문자가 포함되어 있으면 해당 송금은 무시할 것을 권장합니다.

토큰 심볼 미확인

송금을 판정할 때 반드시 토큰 이름, 즉 content 필드의 첫 번째 요소를 확인해야 합니다. 다음과 같은 송금에서 토큰 이름을 확인하지 않고 iost 토큰 송금으로 처리하면 문제가 발생합니다.

"receipts": [
{
"func_name": "token.iost/transfer",
"content": "[\"sometoken\",\"aaaaa\",\"bbbbb\",\"1.20294517\",\"\"]"
}
]

트랜잭션 실행 상태를 확인하지 않음

ram이 부족할 때 송금 트랜잭션은 실패해도 receipts는 여전히 생성됩니다. 예를 들어 다음과 같은 경우입니다.

"tx_receipt": {
"tx_hash": "xxxxxxxxxxxxxxxxx",
"gas_usage": 186277,
"ram_usage": {},
"status_code": "BALANCE_NOT_ENOUGH",
"message": "balance not enough after executing actions: pay ram failed. id: irisye need 335, actual 115",
"returns": [
"[\"\"]"
],
"receipts": [
{
"func_name": "token.iost/transfer",
"content": "[\"iost\",\"aaaaaaa\",\"vote.iost\",\"10\",\"\"]"
}
]
},

status_code 필드를 확인하지 않으면 송금이 성공했다고 잘못 판단하게 됩니다.

요약

송금 성공을 확인하려면 다음을 모두 판단해야 합니다.

  • 트랜잭션이 불가역이어야 합니다.
  • tx_receipt.status_codeSUCCESS여야 합니다.
  • tx_receipt.receiptsfunc_nametoken.iost/transfer인 항목이 있어야 합니다.
  • content 필드의 첫 번째 요소(토큰 심볼)가 기대하는 값인지 확인합니다.
  • content 필드의 네 번째 요소(금액)에 부적절한 문자가 없는지 확인합니다.