Cash a Check for a Flexible Amount

Added by the Checks amendment.

As long as the Check is in the ledger and not expired, the specified recipient can cash it to receive a flexible amount by sending a CheckCash transaction with a DeliverMin field. When cashing a Check in this way, the receiver gets as much as is possible to deliver, debiting the Check's sender for the Check's full SendMax amount or as much as is available. Cashing fails if it doesn't deliver at least the DeliverMin amount to the Check's recipient.

You might cash a Check for a flexible amount if you want to get as much as possible from the Check.

The specified recipient can also cash the check for an exact amount.

Prerequisites

The prerequisites for cashing a check are the same whether you are cashing it for an exact amount or a flexible amount.

  • You need the ID of a Check object currently in the ledger.
    • For example, the ID of one Check in these examples is 838766BA2B995C00744175F69A1B11E32C3DBC40E64801A4056FCBD657F57334, although you must use a different ID to go through these steps yourself.
  • The address and secret key of the Check's stated recipient. The address must match the Destination address in the Check object.
  • If the Check is for a token, you (the recipient) must have a trust line to the issuer. Your limit on that trust line must be high enough to hold your previous balance plus the amount you would receive.
  • A secure way to sign transactions.
  • A client library that can connect to the XRP Ledger, or any HTTP or WebSocket client.

1. 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 CheckCash indicates this is a CheckCash transaction.
Account String (Address) The address of the sender who is cashing the Check. (In other words, your address.)
CheckID String The ID of the Check object in the ledger to cash. 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 tokens, 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.

Example CheckCash Preparation for a flexible amount

The following examples show how to prepare a transaction to cash a Check for a flexible amount.

{
  "Account": "rGPnRH1EBpHeTF2QG8DCAgM7z5pb75LAis",
  "TransactionType": "CheckCash",
  "DeliverMin": "95000000",
  "CheckID": "2E0AD0740B79BE0AAE5EDD1D5FC79E3C5C221D23C6A7F771D85569B5B91195C2"
}
'use strict'
const RippleAPI = require('ripple-lib').RippleAPI

// This example connects to a public Test Net server
const api = new RippleAPI({server: 'wss://s.altnet.rippletest.net:51233'})
api.connect().then(() => {
  console.log('Connected')

  const sender = 'rGPnRH1EBpHeTF2QG8DCAgM7z5pb75LAis'
  const options = {
    // Allow up to 60 ledger versions (~5 min) instead of the default 3 versions
    // before this transaction fails permanently.
    "maxLedgerVersionOffset": 60
  }
  return api.prepareCheckCash(sender, {
    "checkID": "C0B27D20669BAB837B3CDF4B8148B988F17CE1EF8EDF48C806AE9BF69E16F441",
    "deliverMin": {
      "currency": "XRP",
      "value": "95" // Cash for at least 95 XRP
    }
  }, options)

}).then(prepared => {
  console.log("txJSON:", prepared.txJSON);

// Disconnect and return
}).then(() => {
  api.disconnect().then(() => {
    console.log('Disconnected')
    process.exit()
  })
}).catch(console.error)


// Example output:
//
// Connected
// txJSON: {"Account":"rGPnRH1EBpHeTF2QG8DCAgM7z5pb75LAis",
//   "TransactionType":"CheckCash",
//   "CheckID":"C0B27D20669BAB837B3CDF4B8148B988F17CE1EF8EDF48C806AE9BF69E16F441",
//   "DeliverMin":"95000000",
//   "Flags":2147483648,
//   "LastLedgerSequence":8006858,
//   "Fee":"12",
//   "Sequence":5}
// Disconnected

2. Sign the CheckCash transaction

The most secure way to sign a transaction is to sign locally with a client library. Alternatively, if you run your own rippled node you can sign the transaction using the sign method, but this must be done through a trusted and encrypted connection, or through a local (same-machine) connection.

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

Example Request

rippled sign s████████████████████████████ '{
  "Account": "rGPnRH1EBpHeTF2QG8DCAgM7z5pb75LAis",
  "TransactionType": "CheckCash",
  "DeliverMin": "95000000",
  "CheckID": "84C61BE9B39B2C4A2267F67504404F1EC76678806C1B901EA781D1E3B4CE0CD9"
}'

Example Response

Loading: "/etc/opt/ripple/rippled.cfg"
2018-Apr-03 00:09:53 HTTPClient:NFO Connecting to 127.0.0.1:5005

{
   "result" : {
      "status" : "success",
      "tx_blob" : "12001122800000002400000004501884C61BE9B39B2C4A2267F67504404F1EC76678806C1B901EA781D1E3B4CE0CD968400000000000000A6A4000000005A995C073210361ACFCB478BCAE01451F95060AF94F70365BF00D7B4661EC2C69EA383762516C7446304402203D7EC220D48AA040D6915C160275D202F7F808E2B58F11B1AB05FB5E5CFCC6C00220304BBD3AD32E13150E0ED7247F2ADFAE83D0ECE329E20CFE0F8DF352934DD2FC8114A8B6B9FF3246856CADC4A0106198C066EA1F9C39",
      "tx_json" : {
         "Account" : "rGPnRH1EBpHeTF2QG8DCAgM7z5pb75LAis",
         "CheckID" : "84C61BE9B39B2C4A2267F67504404F1EC76678806C1B901EA781D1E3B4CE0CD9",
         "DeliverMin" : "95000000",
         "Fee" : "10",
         "Flags" : 2147483648,
         "Sequence" : 4,
         "SigningPubKey" : "0361ACFCB478BCAE01451F95060AF94F70365BF00D7B4661EC2C69EA383762516C",
         "TransactionType" : "CheckCash",
         "TxnSignature" : "304402203D7EC220D48AA040D6915C160275D202F7F808E2B58F11B1AB05FB5E5CFCC6C00220304BBD3AD32E13150E0ED7247F2ADFAE83D0ECE329E20CFE0F8DF352934DD2FC",
         "hash" : "A0AFE572E4736CBF49FF4D0D3FF8FDB0C4D31BD10CB4EB542230F85F0F2DD222"
      }
   }
}

3. Submit the signed CheckCash 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 run 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

rippled submit 12001122800000002400000004501884C61BE9B39B2C4A2267F67504404F1EC76678806C1B901EA781D1E3B4CE0CD968400000000000000A6A4000000005A995C073210361ACFCB478BCAE01451F95060AF94F70365BF00D7B4661EC2C69EA383762516C7446304402203D7EC220D48AA040D6915C160275D202F7F808E2B58F11B1AB05FB5E5CFCC6C00220304BBD3AD32E13150E0ED7247F2ADFAE83D0ECE329E20CFE0F8DF352934DD2FC8114A8B6B9FF3246856CADC4A0106198C066EA1F9C39

Example Response

Loading: "/etc/opt/ripple/rippled.cfg"
2018-Apr-03 00:10:30 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" : "12001122800000002400000004501884C61BE9B39B2C4A2267F67504404F1EC76678806C1B901EA781D1E3B4CE0CD968400000000000000A6A4000000005A995C073210361ACFCB478BCAE01451F95060AF94F70365BF00D7B4661EC2C69EA383762516C7446304402203D7EC220D48AA040D6915C160275D202F7F808E2B58F11B1AB05FB5E5CFCC6C00220304BBD3AD32E13150E0ED7247F2ADFAE83D0ECE329E20CFE0F8DF352934DD2FC8114A8B6B9FF3246856CADC4A0106198C066EA1F9C39",
      "tx_json" : {
         "Account" : "rGPnRH1EBpHeTF2QG8DCAgM7z5pb75LAis",
         "CheckID" : "84C61BE9B39B2C4A2267F67504404F1EC76678806C1B901EA781D1E3B4CE0CD9",
         "DeliverMin" : "95000000",
         "Fee" : "10",
         "Flags" : 2147483648,
         "Sequence" : 4,
         "SigningPubKey" : "0361ACFCB478BCAE01451F95060AF94F70365BF00D7B4661EC2C69EA383762516C",
         "TransactionType" : "CheckCash",
         "TxnSignature" : "304402203D7EC220D48AA040D6915C160275D202F7F808E2B58F11B1AB05FB5E5CFCC6C00220304BBD3AD32E13150E0ED7247F2ADFAE83D0ECE329E20CFE0F8DF352934DD2FC",
         "hash" : "A0AFE572E4736CBF49FF4D0D3FF8FDB0C4D31BD10CB4EB542230F85F0F2DD222"
      }
   }
}

4. Wait for validation

On a live network (including Mainnet, Testnet, or Devnet), you can wait 4-7 seconds for the ledger to close automatically.

If you're running rippled in stand-alone mode, use the ledger_accept method to manually close the ledger.

5. 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.

Example Request

rippled tx A0AFE572E4736CBF49FF4D0D3FF8FDB0C4D31BD10CB4EB542230F85F0F2DD222

Example Response

Loading: "/etc/opt/ripple/rippled.cfg"
2018-Apr-03 00:11:17 HTTPClient:NFO Connecting to 127.0.0.1:5005

{
   "result" : {
      "Account" : "rGPnRH1EBpHeTF2QG8DCAgM7z5pb75LAis",
      "CheckID" : "84C61BE9B39B2C4A2267F67504404F1EC76678806C1B901EA781D1E3B4CE0CD9",
      "DeliverMin" : "95000000",
      "Fee" : "10",
      "Flags" : 2147483648,
      "Sequence" : 4,
      "SigningPubKey" : "0361ACFCB478BCAE01451F95060AF94F70365BF00D7B4661EC2C69EA383762516C",
      "TransactionType" : "CheckCash",
      "TxnSignature" : "304402203D7EC220D48AA040D6915C160275D202F7F808E2B58F11B1AB05FB5E5CFCC6C00220304BBD3AD32E13150E0ED7247F2ADFAE83D0ECE329E20CFE0F8DF352934DD2FC",
      "date" : 576029432,
      "hash" : "A0AFE572E4736CBF49FF4D0D3FF8FDB0C4D31BD10CB4EB542230F85F0F2DD222",
      "inLedger" : 8005386,
      "ledger_index" : 8005386,
      "meta" : {
         "AffectedNodes" : [
            {
               "ModifiedNode" : {
                  "FinalFields" : {
                     "Flags" : 0,
                     "Owner" : "rBXsgNkPcDN2runsvWmwxk3Lh97zdgo9za",
                     "RootIndex" : "3F248A0715ECCAFC3BEE0C63C8F429ACE54ABC403AAF5F2885C2B65D62D1FAC1"
                  },
                  "LedgerEntryType" : "DirectoryNode",
                  "LedgerIndex" : "3F248A0715ECCAFC3BEE0C63C8F429ACE54ABC403AAF5F2885C2B65D62D1FAC1"
               }
            },
            {
               "ModifiedNode" : {
                  "FinalFields" : {
                     "Account" : "rGPnRH1EBpHeTF2QG8DCAgM7z5pb75LAis",
                     "Balance" : "10099999960",
                     "Flags" : 0,
                     "OwnerCount" : 2,
                     "Sequence" : 5
                  },
                  "LedgerEntryType" : "AccountRoot",
                  "LedgerIndex" : "7939126A732EBBDEC715FD3CCB056EB31E65228CA17E3B2901E7D30B90FD03D3",
                  "PreviousFields" : {
                     "Balance" : "9999999970",
                     "Sequence" : 4
                  },
                  "PreviousTxnID" : "0283465F0D21BE6B1E91ABDE17266C24C1B4915BAAA9A88CC098A98D5ECD3E9E",
                  "PreviousTxnLgrSeq" : 8005334
               }
            },
            {
               "DeletedNode" : {
                  "FinalFields" : {
                     "Account" : "rBXsgNkPcDN2runsvWmwxk3Lh97zdgo9za",
                     "Destination" : "rGPnRH1EBpHeTF2QG8DCAgM7z5pb75LAis",
                     "DestinationNode" : "0000000000000000",
                     "DestinationTag" : 1,
                     "Flags" : 0,
                     "InvoiceID" : "46060241FABCF692D4D934BA2A6C4427CD4279083E38C77CBE642243E43BE291",
                     "OwnerNode" : "0000000000000000",
                     "PreviousTxnID" : "09D992D4C89E2A24D4BA9BB57ED81C7003815940F39B7C87ADBF2E49034380BB",
                     "PreviousTxnLgrSeq" : 7841263,
                     "SendMax" : "100000000",
                     "Sequence" : 4
                  },
                  "LedgerEntryType" : "Check",
                  "LedgerIndex" : "84C61BE9B39B2C4A2267F67504404F1EC76678806C1B901EA781D1E3B4CE0CD9"
               }
            },
            {
               "ModifiedNode" : {
                  "FinalFields" : {
                     "Account" : "rBXsgNkPcDN2runsvWmwxk3Lh97zdgo9za",
                     "Balance" : "9899999920",
                     "Flags" : 0,
                     "OwnerCount" : 2,
                     "Sequence" : 8
                  },
                  "LedgerEntryType" : "AccountRoot",
                  "LedgerIndex" : "A9A591BA661F69433D5BEAA49F10BA2B8DEA5183EF414B9130BFE5E0328FE875",
                  "PreviousFields" : {
                     "Balance" : "9999999920",
                     "OwnerCount" : 3
                  },
                  "PreviousTxnID" : "54A7A917BE9AC13962251BCF1D09803C7BBE75882B8BFC987B5933A566A48215",
                  "PreviousTxnLgrSeq" : 8004870
               }
            },
            {
               "ModifiedNode" : {
                  "FinalFields" : {
                     "Flags" : 0,
                     "Owner" : "rGPnRH1EBpHeTF2QG8DCAgM7z5pb75LAis",
                     "RootIndex" : "C6A30AD85346718C7148D161663F84A96A4F0CE7F4D68C3C74D176A6C50BA6B9"
                  },
                  "LedgerEntryType" : "DirectoryNode",
                  "LedgerIndex" : "C6A30AD85346718C7148D161663F84A96A4F0CE7F4D68C3C74D176A6C50BA6B9"
               }
            }
         ],
         "TransactionIndex" : 4,
         "TransactionResult" : "tesSUCCESS"
      },
      "status" : "success",
      "validated" : true
   }
}

Handling Errors

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 tokens, either due to trust line limits or because the sender does not have enough balance of the token to send (including the issuer's transfer fee, if there is one). 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.

6. 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 delivered_amount field in the metadata shows the exact amount delivered. (This field is only provided if the Check was cashed for a flexible amount. If the check was successfully cashed for a fixed amount, then the delivered amount is equal to the Amount of the CheckCash transaction.)

  • 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 example, the following ModifiedNode shows that the account rGPnRH1EBpHeTF2QG8DCAgM7z5pb75LAis, the Check's recipient and the sender of this CheckCash transaction, had its XRP balance change from 9999999970 drops to 10099999960 drops, meaning the recipient was credited a net of 99.99999 XRP as a result of processing the transaction.

      {
        "ModifiedNode": {
          "FinalFields": {
             "Account": "rGPnRH1EBpHeTF2QG8DCAgM7z5pb75LAis",
             "Balance": "10099999960",
             "Flags": 0,
             "OwnerCount": 2,
             "Sequence": 5
          },
          "LedgerEntryType": "AccountRoot",
          "LedgerIndex": "7939126A732EBBDEC715FD3CCB056EB31E65228CA17E3B2901E7D30B90FD03D3",
          "PreviousFields": {
             "Balance": "9999999970",
             "Sequence": 4
          },
          "PreviousTxnID": "0283465F0D21BE6B1E91ABDE17266C24C1B4915BAAA9A88CC098A98D5ECD3E9E",
          "PreviousTxnLgrSeq": 8005334
        }
      }
    

    The net amount of 99.99999 XRP includes deducting the transaction cost that is destroyed to pay for sending this CheckCash transaction. The following part of the transaction instructions shows that the transaction cost (the Fee field) was 10 drops of XRP. By adding this to the net balance change, we conclude that the recipient, rGPnRH1EBpHeTF2QG8DCAgM7z5pb75LAis, was credited a gross amount of exactly 100 XRP for cashing the Check.

    "Account" : "rGPnRH1EBpHeTF2QG8DCAgM7z5pb75LAis",
    "TransactionType" : "CheckCash",
    "DeliverMin" : "95000000",
    "Fee" : "10",
    
  • For tokens 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 tokens 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 token 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.)