Files
xrpl-dev-portal/content/tutorial-checks.md

25 KiB

for Checks# Checks Tutorials

Checks in the XRP Ledger are similar to paper personal checks. This tutorial steps through the following processes for using Checks:

Send a Check

Sending a Check involves sending a [CheckCreate transaction][], which creates a Check object in the ledger. Most of the fields of a CheckCreate transaction are similar to the fields of a (push) [Payment][], because a Check is like writing permission for an intended recipient to pull a payment from you. You can create a check for XRP or an issued currency.

{% set send_n = cycler(* range(1,99)) %}

Prerequisites

To send a Check with this tutorial, you need the following:

  • The address and secret key of a funded account to send the Check from.
  • The address of a funded account to receive the Check.
  • A secure way to sign transactions, such as RippleAPI or your own rippled server.
  • A client library that can connect to a rippled server, such as RippleAPI or any HTTP or WebSocket library.

{{send_n.next()}}. Prepare the CheckCreate transaction

Decide how much money the Check is for and who can cash it. Figure out the values of the [CheckCreate transaction][] fields. The following fields are the bare minimum; everything else is either optional or can be auto-filled when signing:

Field Value Description
TransactionType String The value CheckCreate indicates this is a CheckCreate transaction.
Account String (Address) The address of the sender who is creating the Check. (In other words, your address.)
Destination String (Address) The address of the intended recipient who can cash the Check.
SendMax String or Object (Amount) The maximum amount the sender can be debited when this Check gets cashed. For XRP, use a string representing drops of XRP. For issued currencies, use an object with currency, issuer, and value fields. See Specifying Currency Amounts for details. If you want the recipient to be able to cash the Check for an exact amount of a non-XRP currency with a transfer fee, remember to include an extra percentage to pay for the transfer fee.

If you are using RippleAPI, you can use the prepareCheckCreate() helper method.

Note: RippleAPI supports Checks in versions 0.19.0 and up.

Example Check Preparation

This example transaction creates a Check for 100 XRP from rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo to rfkE1aSy9G8Upk4JssnwBxhEv5p4mn2KTy, with no expiration:

JSON-RPC, WebSocket, or Commandline

{
  "TransactionType": "CheckCreate",
  "Account": "rBXsgNkPcDN2runsvWmwxk3Lh97zdgo9za",
  "Destination": "rGPnRH1EBpHeTF2QG8DCAgM7z5pb75LAis",
  "SendMax": "100000000",
  "Expiration": 570113521,
  "InvoiceID": "46060241FABCF692D4D934BA2A6C4427CD4279083E38C77CBE642243E43BE291",
  "DestinationTag": 1,
  "Fee": "12"
}

RippleAPI

{% include 'code_samples/checks/js/prepareCreate.js' %}

{{send_n.next()}}. Sign the CheckCreate transaction

The most secure way to sign a transaction is to do it locally with a signing library, such as RippleAPI. Alternatively, you can sign the transaction using the sign command, but this must be done through a trusted and encrypted connection, or through a local connection, and only to a server you control.

In all cases, note the signed transaction's identifying hash for later.

Example Request

RippleAPI

{% include 'code_samples/checks/js/signCreate.js' %}

WebSocket

{% include 'code_samples/checks/websocket/sign-create-req.json' %}

Commandline

{% include 'code_samples/checks/cli/sign-create-req.sh' %}

Example Response

RippleAPI

{% include 'code_samples/checks/js/sign-create-resp.txt' %}

WebSocket

{% include 'code_samples/checks/websocket/sign-create-resp.json' %}

Commandline

{% include 'code_samples/checks/cli/sign-create-resp.txt' %}

{{send_n.next()}}. Submit the signed transaction

Take the signed transaction blob from the previous step and submit it to a rippled server. You can do this safely even if you do not operate the rippled server. The response contains a provisional result, which should be tesSUCCESS, but this result is usually not final. A provisional response of terQUEUED is also OK, since queued transactions are generally included in the next open ledger version (usually about 10 seconds after submission).

Tip: If the preliminary result is tefMAX_LEDGER, the transaction has failed permanently because its LastLedgerSequence parameter is lower than the current ledger. This happens when you take longer than the expected number of ledger versions between preparing and submitting the transaction. If this occurs, start over from step 1 with a higher LastLedgerSequence value.

Example Request

RippleAPI

{% include 'code_samples/checks/js/submitCreate.js' %}

WebSocket

{% include 'code_samples/checks/websocket/submit-create-req.json' %}

Commandline

{% include 'code_samples/checks/cli/submit-create-req.sh' %}

Example Response

RippleAPI

{% include 'code_samples/checks/js/submit-create-resp.txt' %}

WebSocket

{% include 'code_samples/checks/websocket/submit-create-resp.json' %}

Commandline

{% include 'code_samples/checks/cli/submit-create-resp.txt' %}

{{send_n.next()}}. Wait for validation

{% include 'snippets/wait-for-validation.md' %}

{{send_n.next()}}. Confirm final result

Use the tx method with the CheckCreate transaction's identifying hash to check its status. Look for a "TransactionResult": "tesSUCCESS" field in the transaction's metadata, indicating that the transaction succeeded, and the field "validated": true in the result, indicating that this result is final.

Look for a CreatedNode object in the transaction metadata to indicate that the transaction created a Check ledger object. The LedgerIndex of this object is the ID of the Check. In the following example, the Check's ID is 49647F0D748DC3FE26BDACBC57F251AADEFFF391403EC9BF87C97F67E9977FB0.

TODO: Add code to look up the Check ID using account_objects in RippleAPI or to calculate the ID deterministically. Also, if https://github.com/ripple/ripple-lib/issues/876 gets resolved, there will be an easier way to get the Check ID from the RippleAPI response.

Example Request

RippleAPI

{% include 'code_samples/checks/js/getCreateTx.js' %}

Example Response

RippleAPI

{% include 'code_samples/checks/js/get-create-tx-resp.txt' %}

WebSocket

{% include 'code_samples/checks/websocket/tx-create-resp.json' %}

Commandline

{% include 'code_samples/checks/cli/tx-create-resp.txt' %}

Cancel a Check

Canceling a Check involves sending a [CheckCancel transaction][], which removes a Check object from the ledger without redeeming it. Either the sender or the recipient of a Check can cancel it before it has been redeemed. If the Check has expired, anyone can cancel it (and no one can cash it).

{% set cancel_n = cycler(* range(1,99)) %}

Prerequisites

To cancel a Check with this tutorial, you need the following:

  • You need the ID of a Check object currently in the ledger.
    • For example, the ID of the Check created in the WebSocket examples above was 84C61BE9B39B2C4A2267F67504404F1EC76678806C1B901EA781D1E3B4CE0CD9, although you must use a different ID to go through these steps yourself.
  • The address and secret key of a funded account to send the CheckCancel transaction. This address must be either the sender or the recipient of the Check, unless the Check is expired.
  • A secure way to sign transactions, such as RippleAPI or your own rippled server.
  • A client library that can connect to a rippled server, such as RippleAPI or any HTTP or WebSocket library.

{{cancel_n.next()}}. Prepare the CheckCancel transaction

Figure out the values of the [CheckCancel transaction][] fields. The following fields are the bare minimum; everything else is either optional or can be auto-filled when signing:

Field Value Description
TransactionType String The value CheckCancel indicates this is a CheckCancel transaction.
Account String (Address) The address of the sender who is canceling the Check. (In other words, your address.)
CheckID String The ID of the Check object in the ledger to cancel. You can get this information by looking up the metadata of the CheckCreate transaction using the tx method or by looking for Checks using the account_objects method.

If you are using RippleAPI, you can use the prepareCheckCancel() helper method.

Note: RippleAPI supports Checks in versions 0.19.0 and up.

{{cancel_n.next()}}. Sign the CheckCancel transaction

TODO: separate signing/submitting of CheckCancel

$ ./rippled submit snkuWqxoqt6aeykTbkEWrTMJHrWGM '{
>     "Account": "rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo",
>     "TransactionType": "CheckCancel",
>     "CheckID": "49647F0D748DC3FE26BDACBC57F251AADEFFF391403EC9BF87C97F67E9977FB0",
>     "Fee": "12"
> }'
Loading: "/home/mduo13/.config/ripple/rippled.cfg"
2018-Jan-24 01:11:07 HTTPClient:NFO Connecting to 127.0.0.1:5005

{
   "result" : {
      "engine_result" : "tesSUCCESS",
      "engine_result_code" : 0,
      "engine_result_message" : "The transaction was applied. Only final in a validated ledger.",
      "status" : "success",
      "tx_blob" : "12001222800000002400000003501849647F0D748DC3FE26BDACBC57F251AADEFFF391403EC9BF87C97F67E9977FB068400000000000000C7321022C53CD19049F32F31848DD3B3BE5CEF6A2DD1EFDA7971AB3FA49B1BAF12AEF78744630440220615F9D19FA182F08530CD978A4C216C8676D0BA9EDB53A620AC909AA0EF0FE7E02203A09CC34C3DB85CCCB3137E78081F8F2B441FB0A3B9E40901F312D3CBA0A67A181147990EC5D1D8DF69E070A968D4B186986FDF06ED0",
      "tx_json" : {
         "Account" : "rUn84CUYbNjRoTQ6mSW7BVJPSVJNLb1QLo",
         "CheckID" : "49647F0D748DC3FE26BDACBC57F251AADEFFF391403EC9BF87C97F67E9977FB0",
         "Fee" : "12",
         "Flags" : 2147483648,
         "Sequence" : 3,
         "SigningPubKey" : "022C53CD19049F32F31848DD3B3BE5CEF6A2DD1EFDA7971AB3FA49B1BAF12AEF78",
         "TransactionType" : "CheckCancel",
         "TxnSignature" : "30440220615F9D19FA182F08530CD978A4C216C8676D0BA9EDB53A620AC909AA0EF0FE7E02203A09CC34C3DB85CCCB3137E78081F8F2B441FB0A3B9E40901F312D3CBA0A67A1",
         "hash" : "414558223CA8595916BB1FEF238B3BB601B7C0E52659292251CE613E6B4370F9"
      }
   }
}

{{cancel_n.next()}}. Submit the signed CheckCancel transaction

TODO: examples of submitting signed blob

{{cancel_n.next()}}. Wait for validation

{% include 'snippets/wait-for-validation.md' %}

{{cancel_n.next()}}. Confirm final result

Use the tx method with the CheckCancel transaction's identifying hash to check its status. Look for a "TransactionResult": "tesSUCCESS" field in the transaction's metadata, indicating that the transaction succeeded, and the field "validated": true in the result, indicating that this result is final.

Look for a DeletedNode object in the transaction metadata with "LedgerEntryType": "Check" to indicate that the transaction removed a Check ledger object. The LedgerIndex of this object should match the ID of the Check.

Example Request

Commandline

{% include 'code_samples/checks/cli/tx-cancel-req.sh' %}

Example Response

Commandline

{% include 'code_samples/checks/cli/tx-cancel-resp.txt' %}

Cash a Check for an exact amount

As long as the Check is in the ledger and not expired, the specified recipient can cash it to receive any exact amount up to the amount specified in the Check by sending a [CheckCash transaction][] with an Amount field.

The specified recipient can also cash the check for a flexible amount.

{% set cash_exact_n = cycler(* range(1,99)) %}

Prerequisites

{% include 'snippets/checkcash-prereqs.md' %}

{{cash_exact_n.next()}}. Prepare the CheckCash transaction

TODO: Uses check id: 838766BA2B995C00744175F69A1B11E32C3DBC40E64801A4056FCBD657F57334

Figure out the values of the [CheckCash transaction][] fields. To cash a check for an exact amount, the following fields are the bare minimum; everything else is either optional or can be auto-filled when signing:

Field Value Description
TransactionType String The value CheckCancel indicates this is a CheckCancel transaction.
Account String (Address) The address of the sender who is canceling the Check. (In other words, your address.)
CheckID String The ID of the Check object in the ledger to cancel. You can get this information by looking up the metadata of the CheckCreate transaction using the tx method or by looking for Checks using the account_objects method.
Amount String or Object (Amount) The amount to redeem from the Check. For XRP, this must be a string specifying drops of XRP. For issued currencies, this is an object with currency, issuer, and value fields. The currency and issuer fields must match the corresponding fields in the Check object, and the value must be less than or equal to the amount in the Check object. For more information on specifying currency amounts, see Specifying Currency Amounts.

{{cash_exact_n.next()}}. Sign the CheckCash transaction

{{cash_exact_n.next()}}. Submit the signed CheckCancel transaction

TODO: examples of submitting signed blob

$ ./rippled submit sn2Zh1tRZyodU9qNy9tMnQr9UbBss '{
>     "Account": "rfkE1aSy9G8Upk4JssnwBxhEv5p4mn2KTy",
>     "TransactionType": "CheckCash",
>     "Amount": "100000000",
>     "CheckID": "838766BA2B995C00744175F69A1B11E32C3DBC40E64801A4056FCBD657F57334",
>     "Fee": "12"
> }'
Loading: "/home/mduo13/.config/ripple/rippled.cfg"
2018-Jan-24 01:17:54 HTTPClient:NFO Connecting to 127.0.0.1:5005

{
   "result" : {
      "engine_result" : "tesSUCCESS",
      "engine_result_code" : 0,
      "engine_result_message" : "The transaction was applied. Only final in a validated ledger.",
      "status" : "success",
      "tx_blob" : "120011228000000024000000015018838766BA2B995C00744175F69A1B11E32C3DBC40E64801A4056FCBD657F57334614000000005F5E10068400000000000000C732102F135B14C552968B0ABE8493CC4C5795A7484D73F6BFD01379F73456F725F66ED74473045022100C64278AC90B841CD3EA9889A4847CAB3AC9927057A34130810FAA7FAC0C6E3290220347260A4C0A6DC9B699DA12510795B2B3414E1FA222AF743226345FBAAEF937C811449FF0C73CA6AF9733DA805F76CA2C37776B7C46B",
      "tx_json" : {
         "Account" : "rfkE1aSy9G8Upk4JssnwBxhEv5p4mn2KTy",
         "Amount" : "100000000",
         "CheckID" : "838766BA2B995C00744175F69A1B11E32C3DBC40E64801A4056FCBD657F57334",
         "Fee" : "12",
         "Flags" : 2147483648,
         "Sequence" : 1,
         "SigningPubKey" : "02F135B14C552968B0ABE8493CC4C5795A7484D73F6BFD01379F73456F725F66ED",
         "TransactionType" : "CheckCash",
         "TxnSignature" : "3045022100C64278AC90B841CD3EA9889A4847CAB3AC9927057A34130810FAA7FAC0C6E3290220347260A4C0A6DC9B699DA12510795B2B3414E1FA222AF743226345FBAAEF937C",
         "hash" : "0521707D510858BC8AF69D2227E1D1ADA7DB7C5B4B74115BCD0D91B62AFA8EDC"
      }
   }
}

{{cash_exact_n.next()}}. Wait for validation

{% include 'snippets/wait-for-validation.md' %}

{{cash_exact_n.next()}}. Confirm final result

Use the tx method with the CheckCash transaction's identifying hash to check its status. Look for a "TransactionResult": "tesSUCCESS" field in the transaction's metadata, indicating that the transaction succeeded, and the field "validated": true in the result, indicating that this result is final.

If the check was cashed for an exact Amount and succeeded, you can assume that the recipient was credited for exactly that amount (with possible rounding for very large or very small amounts of issued currencies).

If cashing the Check failed,

Cash a Check for a flexible amount

TODO: description

{% set cash_flex_n = cycler(* range(1,99)) %}

Prerequisites

{% include 'snippets/checkcash-prereqs.md' %}

{{cash_flex_n.next()}}. Prepare the CheckCash transaction

Figure out the values of the [CheckCash transaction][] fields. To cash a check for a flexible amount, the following fields are the bare minimum; everything else is either optional or can be auto-filled when signing:

Field Value Description
TransactionType String The value CheckCancel indicates this is a CheckCancel transaction.
Account String (Address) The address of the sender who is canceling the Check. (In other words, your address.)
CheckID String The ID of the Check object in the ledger to cancel. You can get this information by looking up the metadata of the CheckCreate transaction using the tx method or by looking for Checks using the account_objects method.
DeliverMin String or Object (Amount) A minimum amount to receive from the Check. If you cannot receive at least this much, cashing the Check fails, leaving the Check in the ledger so you can try again. For XRP, this must be a string specifying drops of XRP. For issued currencies, this is an object with currency, issuer, and value fields. The currency and issuer fields must match the corresponding fields in the Check object, and the value must be less than or equal to the amount in the Check object. For more information on specifying currency amounts, see Specifying Currency Amounts.

{{cash_flex_n.next()}}. Sign the CheckCash transaction

{{cash_flex_n.next()}}. Submit the signed CheckCash transaction

TODO: examples of submitting signed blob

{{cash_flex_n.next()}}. Wait for validation

{% include 'snippets/wait-for-validation.md' %}

{{cash_flex_n.next()}}. Confirm final result

Use the tx method with the CheckCash transaction's identifying hash to check its status. Look for a "TransactionResult": "tesSUCCESS" field in the transaction's metadata, indicating that the transaction succeeded, and the field "validated": true in the result, indicating that this result is final.

If cashing the Check failed with a tec-class code, look up the code in the Full Transaction Response List and respond accordingly. Some common possibilities for CheckCash transactions:

Result Code Meaning How to Respond
tecEXPIRED The Check has expired. Cancel the Check and ask the sender to create a new Check with a later Expiration time.
tecNO_ENTRY The Check ID doesn't exist. Confirm that the CheckID from the CheckCash transaction is correct. Confirm that the Check has not already been canceled or successfully cashed.
tecNO_LINE The recipient doesn't have a trust line for the Check's currency. If you want to hold this currency from this issuer, create a trust line for the specified currency and issuer with a reasonable limit using a [TrustSet transaction][], then try to cash the check again.
tecNO_PERMISSION The sender of the CheckCash transaction isn't the Destination of the Check. Double-check the Destination of the Check.
tecNO_AUTH The issuer of the currency from the check is using Authorized Trust Lines but the recipient's trust line to the issuer is not approved. Ask the issuer to authorize this trust line, then try again to cash the Check after they do.
tecPATH_PARTIAL The Check could not deliver enough issued currency, either due to trust line limits or because the sender does not have enough balance of the currency to send (after including the issuer's transfer fee, if there is one). TODO: confirm this. If the problem is the trust line limit, send a [TrustSet transaction][] to increase your limit (if desired) or lower your balance by spending some of the currency, then try to cash the Check again. If the problem is the sender's balance, wait for the sender to have more of the Check's currency, or try again to cash the Check for a lesser amount.
tecUNFUNDED_PAYMENT The Check could not deliver enough XRP. Wait for the sender to have more XRP, or try again to cash the Check for a lesser amount.

{{cash_flex_n.next()}}. Confirm delivered amount

If the Check was cashed for a flexible DeliverMin amount and succeeded, you can assume that the Check was cashed for at least the DeliverMin amount. To get the exact amount delivered, check the transaction metadata. The metadata's AffectedNodes array contains one or two objects that reflect the change in balances from cashing the Check, depending on the type of currency.

  • For XRP, the AccountRoot object of the Check's sender has its XRP Balance field debited. The AccountRoot object of the Check's recipient (the one who sent the CheckCash transaction) has its XRP Balance credited for at least the DeliverMin of the CheckCash transaction minus the transaction cost of sending the transaction.
  • For issued currencies where the sender or recipient of the check is the issuer, the RippleState object representing the trust line between those accounts has its Balance adjusted in the favor of the Check's recipient.
  • For issued currencies with a third-party issuer, there are changes to two RippleState objects, representing the trust lines connecting the sender to the issuer, and the issuer to the recipient. The RippleState object representing the relationship between the Check's sender and the issuer has its Balance changed in favor of the issuer, and the RippleState object representing the relationship between the issuer and the recipient has its Balance changed in favor of the recipient.
    • If the issued currency has a transfer fee, the Check's sender may be debited more than the recipient is credited. (The difference is the transfer fee, which is returned to the issuer as a decreased net obligation.)

TODO: clarify the above with more precise examples?

{% include 'snippets/tx-type-links.md' %}