条件に基づくEscrowの送信
1.条件とフルフィルメントの生成
XRP Ledger EscrowにはPREIMAGE-SHA-256 Crypto-Conditionsが必要です。条件とフルフィルメントを適切なフォーマットで計算するには、five-bells-conditionなどのCrypto-conditionsライブラリを使用する必要があります。フルフィルメントについては、以下のフルフィルメントを生成するためのメソッドのいずれかを使用することが推奨されます。
- 暗号論的に安全な乱数ソースを使用して、32バイト以上のランダムバイトを生成します。
- Interledger ProtocolのPSK仕様に従い、ILPパケットのHMAC-SHA-256をフルフィルメントとして使用します。
ランダムなフルフィルメントと条件のJavaScriptコードの例:
const cc = require('five-bells-condition') const crypto = require('crypto') const preimageData = crypto.randomBytes(32) const myFulfillment = new cc.PreimageSha256() myFulfillment.setPreimage(preimageData) const condition = myFulfillment.getConditionBinary().toString('hex').toUpperCase() console.log('Condition:', condition) // (Random hexadecimal, 72 chars in length) // keep secret until you want to finish executing the held payment: const fulfillment = myFulfillment.serializeBinary().toString('hex').toUpperCase() console.log('Fulfillment:', fulfillment) // (Random hexadecimal, 78 chars in length)
後で使用できるように条件とフルフィルメントを保存します。保留中の支払いの実行が完了するまでは、フルフィルメントを公開しないでください。フルフィルメントを知っていれば誰でもEscrowを終了でき、保留中の資金を指定された送金先にリリースできます。
2.リリース時刻または取消し時刻の計算
条件付きEscrow
トランザクションには、CancelAfter
フィールドとFinishAfter
フィールドのいずれか、または両方が含まれている必要があります。CancelAfter
フィールドを使用すると、指定の時刻までに条件を満たすことができなかった場合に送金元へXRPを返金できます。FinishAfter
フィールドに指定される時刻より前の時間は、正しいフルフィルメントが送信されてもEscrowを実行できません。いずれのフィールドでも、将来の時刻を指定する必要があります。
CancelAfter
の時刻を24時間先に設定する例:
const rippleOffset = 946684800 const CancelAfter = Math.floor(Date.now() / 1000) + (24*60*60) - rippleOffset console.log(CancelAfter) // Example:556927412
CancelAfter
またはFinishAfter
フィールドで、UNIX時刻を同等のRipple時刻に変換せずに使用すると、ロック解除時刻が30年先に設定されることになります。3.EscrowCreateトランザクションの送信
EscrowCreateトランザクションに署名して送信します。トランザクションのCondition
フィールドを、保留中の支払いがリリースされる時刻に設定します。Destination
を受取人に設定します。受取人と送金元のアドレスは同じでもかまいません。前の手順で算出したCancelAfter
またはFinishAfter
の時刻も指定します。Amount
を、EscrowするXRP、drop単位の合計額に設定します。
自分が管理していないサーバに秘密鍵を送信しないでください。暗号化されていない秘密鍵をネットワーク経由で送信しないでください。
リクエスト:
{ "id": 1, "command": "submit", "secret": "s████████████████████████████", "tx_json": { "Account": "rEhw9vD98ZrkY4tZPvkZst5H18RysqFdaB", "TransactionType": "EscrowCreate", "Amount": "100000", "Destination": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "Condition": "A0258020E24D9E1473D4DF774F6D8E089067282034E4FA7ECACA2AD2E547953B2C113CBD810120", "CancelAfter": 556927412 } }
レスポンス:
{ "id": 1, "status": "success", "type": "response", "result": { "engine_result": "tesSUCCESS", "engine_result_code": 0, "engine_result_message": "The transaction was applied. Only final in a validated ledger.", "tx_blob": "120001228000000024000000052024213209B46140000000000186A068400000000000000A732103E498E35BC1E109C5995BD3AB0A6D4FFAB61B853C8F6010FABC5DABAF34478B61744730450221008AC8BDC2151D5EF956197F0E6E89A4F49DEADC1AC38367870E444B1EA8D88D97022075E31427B455DFF87F0F22B849C71FC3987A91C19D63B6D0242E808347EC8A8F701127A0258020E24D9E1473D4DF774F6D8E089067282034E4FA7ECACA2AD2E547953B2C113CBD81012081149A2AA667E1517EFA8A6B552AB2EDB859A99F26B283144B4E9C06F24296074F7BC48F92A97916C6DC5EA9", "tx_json": { "Account": "rEhw9vD98ZrkY4tZPvkZst5H18RysqFdaB", "Amount": "100000", "CancelAfter": 556927412, "Condition": "A0258020E24D9E1473D4DF774F6D8E089067282034E4FA7ECACA2AD2E547953B2C113CBD810120", "Destination": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "Fee": "10", "Flags": 2147483648, "Sequence": 5, "SigningPubKey": "03E498E35BC1E109C5995BD3AB0A6D4FFAB61B853C8F6010FABC5DABAF34478B61", "TransactionType": "EscrowCreate", "TxnSignature": "30450221008AC8BDC2151D5EF956197F0E6E89A4F49DEADC1AC38367870E444B1EA8D88D97022075E31427B455DFF87F0F22B849C71FC3987A91C19D63B6D0242E808347EC8A8F", "hash": "E22D1F6EB006CAD35E0DBD3B4F3748427055E4C143EBE95AA6603823AEEAD324" } } }
4.検証の待機
本番環境のネットワークやTestnetでは、レジャーが自動的に閉鎖するまでに4~7秒かかる場合があります。
スタンドアロンモードでrippled
を実行している場合は、[ledger_acceptメソッド][]を使用してレジャーを手動で閉鎖します。
5.Escrowが作成されたことの確認
トランザクションの識別用ハッシュを指定したtxメソッドを使用して、トランザクションの最終ステータスを確認します。特に、Escrowレジャーオブジェクトが作成されたことを示すCreatedNode
をトランザクションメタデータで探します。
リクエスト:
{ "id": 3, "command": "tx", "transaction": "E22D1F6EB006CAD35E0DBD3B4F3748427055E4C143EBE95AA6603823AEEAD324" }
レスポンス:
{ "id": 3, "status": "success", "type": "response", "result": { "Account": "rEhw9vD98ZrkY4tZPvkZst5H18RysqFdaB", "Amount": "100000", "CancelAfter": 556927412, "Condition": "A0258020E24D9E1473D4DF774F6D8E089067282034E4FA7ECACA2AD2E547953B2C113CBD810120", "Destination": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "Fee": "10", "Flags": 2147483648, "Sequence": 5, "SigningPubKey": "03E498E35BC1E109C5995BD3AB0A6D4FFAB61B853C8F6010FABC5DABAF34478B61", "TransactionType": "EscrowCreate", "TxnSignature": "30450221008AC8BDC2151D5EF956197F0E6E89A4F49DEADC1AC38367870E444B1EA8D88D97022075E31427B455DFF87F0F22B849C71FC3987A91C19D63B6D0242E808347EC8A8F", "date": 556841101, "hash": "E22D1F6EB006CAD35E0DBD3B4F3748427055E4C143EBE95AA6603823AEEAD324", "inLedger": 1772019, "ledger_index": 1772019, "meta": { "AffectedNodes": [ { "ModifiedNode": { "LedgerEntryType": "AccountRoot", "LedgerIndex": "13F1A95D7AAB7108D5CE7EEAF504B2894B8C674E6D68499076441C4837282BF8", "PreviousTxnID": "52C4F626FE6F33699B6BE8ADF362836DDCE9B0B1294BFAA15D65D61501350BE6", "PreviousTxnLgrSeq": 1771204 } }, { "ModifiedNode": { "FinalFields": { "Flags": 0, "Owner": "rEhw9vD98ZrkY4tZPvkZst5H18RysqFdaB", "RootIndex": "4B4EBB6D8563075813D47491CC325865DFD3DC2E94889F0F39D59D9C059DD81F" }, "LedgerEntryType": "DirectoryNode", "LedgerIndex": "4B4EBB6D8563075813D47491CC325865DFD3DC2E94889F0F39D59D9C059DD81F" } }, { "ModifiedNode": { "FinalFields": { "Account": "rEhw9vD98ZrkY4tZPvkZst5H18RysqFdaB", "Balance": "9999798970", "Flags": 0, "OwnerCount": 1, "Sequence": 6 }, "LedgerEntryType": "AccountRoot", "LedgerIndex": "5F3B7107F4B524367A173A2B0EAB66E8CC4D2178C1B0C0528CB2F73A8B6BF254", "PreviousFields": { "Balance": "9999898980", "OwnerCount": 0, "Sequence": 5 }, "PreviousTxnID": "52C4F626FE6F33699B6BE8ADF362836DDCE9B0B1294BFAA15D65D61501350BE6", "PreviousTxnLgrSeq": 1771204 } }, { "CreatedNode": { "LedgerEntryType": "Escrow", "LedgerIndex": "E2CF730A31FD419382350C9DBD8DB7CD775BA5AA9B97A9BE9AB07304AA217A75", "NewFields": { "Account": "rEhw9vD98ZrkY4tZPvkZst5H18RysqFdaB", "Amount": "100000", "CancelAfter": 556927412, "Condition": "A0258020E24D9E1473D4DF774F6D8E089067282034E4FA7ECACA2AD2E547953B2C113CBD810120", "Destination": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn" } } } ], "TransactionIndex": 0, "TransactionResult": "tesSUCCESS" }, "validated": true } }
6.EscrowFinishトランザクションの送信
FinishAfter
の時刻が経過した後で資金のリリースを実行するEscrowFinishトランザクションに署名して送信します。トランザクションのOwner
フィールドにEscrowCreateトランザクションのAccount
アドレスを設定し、OfferSequence
にEscrowCreateトランザクションのSequence
番号を設定します。Condition
フィールドとFulfillment
フィールドに、ステップ1で生成した条件値とフルフィルメント値をそれぞれ16進数で設定します。フルフィルメントのサイズ(バイト数)に基づいてFee
(トランザクションコスト)の値を設定します。条件付きEscrowFinishでは、少なくとも330 drop(XRP)と、フルフィルメントのサイズで16バイトごとに10 dropが必要です。
FinishAfter
フィールドが含まれている場合、Escrowの条件として正しいフルフィルメントを指定しても、この時刻よりも前の時点ではこのトランザクションを実行できません。前に閉鎖されたレジャーの閉鎖時刻がFinishAfter
の時刻よりも前である場合、EscrowFinishトランザクションは結果コードtecNO_PERMISSION
で失敗します。Escrowが有効期限切れの場合は、Escrowの取消しだけが可能です。
自分が管理していないサーバに秘密鍵を送信しないでください。暗号化されていない秘密鍵をネットワーク経由で送信しないでください。
{ "id": 4, "command": "submit", "secret": "s████████████████████████████", "tx_json": { "Account": "rEhw9vD98ZrkY4tZPvkZst5H18RysqFdaB", "TransactionType": "EscrowFinish", "Owner": "rEhw9vD98ZrkY4tZPvkZst5H18RysqFdaB", "OfferSequence": 5, "Condition": "A0258020E24D9E1473D4DF774F6D8E089067282034E4FA7ECACA2AD2E547953B2C113CBD810120", "Fulfillment": "A0228020D280D1A02BAD0D2EBC0528B92E9BF37AC3E2530832C2C52620307135156F1048", "Fee": "500" } }
レスポンス:
{ "id": 4, "status": "success", "type": "response", "result": { "engine_result": "tesSUCCESS", "engine_result_code": 0, "engine_result_message": "The transaction was applied. Only final in a validated ledger.", "tx_blob": "120002228000000024000000062019000000056840000000000001F4732103E498E35BC1E109C5995BD3AB0A6D4FFAB61B853C8F6010FABC5DABAF34478B617446304402207DE4EA9C8655E75BA01F96345B3F62074313EB42C15D9C4871E30F02202D2BA50220070E52AD308A31AC71E33BA342F31B68D1D1B2A7A3A3ED6E8552CA3DCF14FBB2701024A0228020D280D1A02BAD0D2EBC0528B92E9BF37AC3E2530832C2C52620307135156F1048701127A0258020E24D9E1473D4DF774F6D8E089067282034E4FA7ECACA2AD2E547953B2C113CBD81012081149A2AA667E1517EFA8A6B552AB2EDB859A99F26B282149A2AA667E1517EFA8A6B552AB2EDB859A99F26B2", "tx_json": { "Account": "rEhw9vD98ZrkY4tZPvkZst5H18RysqFdaB", "Condition": "A0258020E24D9E1473D4DF774F6D8E089067282034E4FA7ECACA2AD2E547953B2C113CBD810120", "Fee": "500", "Flags": 2147483648, "Fulfillment": "A0228020D280D1A02BAD0D2EBC0528B92E9BF37AC3E2530832C2C52620307135156F1048", "OfferSequence": 5, "Owner": "rEhw9vD98ZrkY4tZPvkZst5H18RysqFdaB", "Sequence": 6, "SigningPubKey": "03E498E35BC1E109C5995BD3AB0A6D4FFAB61B853C8F6010FABC5DABAF34478B61", "TransactionType": "EscrowFinish", "TxnSignature": "304402207DE4EA9C8655E75BA01F96345B3F62074313EB42C15D9C4871E30F02202D2BA50220070E52AD308A31AC71E33BA342F31B68D1D1B2A7A3A3ED6E8552CA3DCF14FBB2", "hash": "0E88368CAFC69A722ED829FAE6E2DD3575AE9C192691E60B5ACDF706E219B2BF" } } }
トランザクションの識別用hash
値をメモしておきます。これにより、検証済みレジャーバージョンに記録されるときにその最終ステータスを確認できます。
7.検証の待機
本番環境のネットワークやTestnetでは、レジャーが自動的に閉鎖するまでに4~7秒かかる場合があります。
スタンドアロンモードでrippled
を実行している場合は、[ledger_acceptメソッド][]を使用してレジャーを手動で閉鎖します。
8.最終結果の確認
EscrowFinishトランザクションの識別用ハッシュを指定したtxメソッドを使用して、トランザクションの最終ステータスを確認します。特にトランザクションメタデータ内で、エスクローに預託された支払いの送金先のModifiedNode
(タイプがAccountRoot
)を確認します。オブジェクトのFinalFields
に、Balance
フィールドのXRP返金額の増分が表示されている必要があります。
リクエスト:
{ "id": 20, "command": "tx", "transaction": "0E88368CAFC69A722ED829FAE6E2DD3575AE9C192691E60B5ACDF706E219B2BF" }
レスポンス:
{ "id": 20, "status": "success", "type": "response", "result": { "Account": "rEhw9vD98ZrkY4tZPvkZst5H18RysqFdaB", "Condition": "A0258020E24D9E1473D4DF774F6D8E089067282034E4FA7ECACA2AD2E547953B2C113CBD810120", "Fee": "500", "Flags": 2147483648, "Fulfillment": "A0228020D280D1A02BAD0D2EBC0528B92E9BF37AC3E2530832C2C52620307135156F1048", "OfferSequence": 2, "Owner": "rEhw9vD98ZrkY4tZPvkZst5H18RysqFdaB", "Sequence": 4, "SigningPubKey": "03E498E35BC1E109C5995BD3AB0A6D4FFAB61B853C8F6010FABC5DABAF34478B61", "TransactionType": "EscrowFinish", "TxnSignature": "3045022100925FEBE21C2E57F81C472A4E5869CAB1D0164C472A46532F39F6F9F7ED6846D002202CF9D9063ADC4CC0ADF4C4692B7EE165C5D124CAA855649389E245D993F41D4D", "date": 556838610, "hash": "0E88368CAFC69A722ED829FAE6E2DD3575AE9C192691E60B5ACDF706E219B2BF", "inLedger": 1771204, "ledger_index": 1771204, "meta": { "AffectedNodes": [ { "ModifiedNode": { "FinalFields": { "Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "Balance": "400100000", "Flags": 0, "OwnerCount": 0, "Sequence": 1 }, "LedgerEntryType": "AccountRoot", "LedgerIndex": "13F1A95D7AAB7108D5CE7EEAF504B2894B8C674E6D68499076441C4837282BF8", "PreviousFields": { "Balance": "400000000" }, "PreviousTxnID": "795CBC8AFAAB9DC7BD9944C7FAEABF9BB0802A84520BC649213AD6A2C3256C95", "PreviousTxnLgrSeq": 1770775 } }, { "ModifiedNode": { "FinalFields": { "Flags": 0, "Owner": "rEhw9vD98ZrkY4tZPvkZst5H18RysqFdaB", "RootIndex": "4B4EBB6D8563075813D47491CC325865DFD3DC2E94889F0F39D59D9C059DD81F" }, "LedgerEntryType": "DirectoryNode", "LedgerIndex": "4B4EBB6D8563075813D47491CC325865DFD3DC2E94889F0F39D59D9C059DD81F" } }, { "ModifiedNode": { "FinalFields": { "Account": "rEhw9vD98ZrkY4tZPvkZst5H18RysqFdaB", "Balance": "9999898980", "Flags": 0, "OwnerCount": 0, "Sequence": 5 }, "LedgerEntryType": "AccountRoot", "LedgerIndex": "5F3B7107F4B524367A173A2B0EAB66E8CC4D2178C1B0C0528CB2F73A8B6BF254", "PreviousFields": { "Balance": "9999899480", "OwnerCount": 1, "Sequence": 4 }, "PreviousTxnID": "5C2A1E7B209A7404D3722A010D331A8C1C853109A47DDF620DE5E3D59F026581", "PreviousTxnLgrSeq": 1771042 } }, { "DeletedNode": { "FinalFields": { "Account": "rEhw9vD98ZrkY4tZPvkZst5H18RysqFdaB", "Amount": "100000", "Condition": "A0258020E24D9E1473D4DF774F6D8E089067282034E4FA7ECACA2AD2E547953B2C113CBD810120", "Destination": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", "FinishAfter": 556838185, "Flags": 0, "OwnerNode": "0000000000000000", "PreviousTxnID": "795CBC8AFAAB9DC7BD9944C7FAEABF9BB0802A84520BC649213AD6A2C3256C95", "PreviousTxnLgrSeq": 1770775 }, "LedgerEntryType": "Escrow", "LedgerIndex": "DC524D17B3F650E7A215B332F418E54AE59B0DFC5392E74958B0037AFDFE8C8D" } } ], "TransactionIndex": 1, "TransactionResult": "tesSUCCESS" }, "validated": true } }