Merge pull request #1623 from XRPLF/IA-escrow-tutorials

Pull concept info from escrow tutorials.
This commit is contained in:
oeggert
2022-12-14 11:22:56 -08:00
committed by GitHub
6 changed files with 90 additions and 59 deletions

View File

@@ -7,13 +7,17 @@ labels:
---
# Escrow
A traditional escrow is a contract between two parties to facilitate risky financial transactions. Funds are sent to and held by an impartial third party, guaranteeing its availability. The funds are only released to their intended recipients when conditions specified by the contract are met. This method ensures both parties meet their obligations.
A traditional escrow is a contract between two parties to facilitate financial transactions. A sender delivers funds to an impartial third party to hold, guaranteeing its availability to a recipient. The third party only releases the funds to the recipient when conditions specified by the contract are met. This method ensures both parties meet their obligations.
The XRP Ledger takes escrow a step further, replacing the third party with an automated system built into the ledger. An escrow locks up XRP, which can't be used or destroyed until conditions are met. You can specify conditions by:
The XRP Ledger takes escrow a step further, removing the need for a third party to hold the funds. Instead, an escrow locks up XRP on the ledger itself, which can't be used or destroyed until conditions are met.
- Time.
- Crypto-condition.
- A combination of both.
## Types of Escrow
The XRP Ledger supports three types of escrow:
- **Time-based Escrow:** Escrow funds only become available after a certain amount of time passes.
- **Conditional Escrow:** This escrow is created with a corresponding condition and fulfillment. The condition serves as a lock on the funds and won't release until the correct fulfillment key is provided.
- **Combination Escrow:** This escrow combines the features of time-based and conditional escrow. The escrow is completely inaccessible until the specified time passes, after which the funds can be release by providing the correct fulfillment.
## Escrow Lifecycle
@@ -25,10 +29,13 @@ The XRP Ledger takes escrow a step further, replacing the third party with an au
2. After the transaction is processed, the XRP Ledger creates an `Escrow` object that holds the escrowed XRP.
3. The recipient sends an `EscrowFinish` transaction to deliver the XRP. If the conditions have been met, the `Escrow` object is destroyed and the XRP credited to the recipient.
3. When the escrow conditions are met, the funds become available.
4. The recipient sends an `EscrowFinish` transaction to actually deliver the XRP. The `Escrow` object is destroyed and the XRP credited to the recipient.
**Note:** If the escrow has an expiration time and isn't successfully finished before then, the escrow becomes expired. Expired escrows remain in the ledger until an `EscrowCancel` transaction cancels it, destroying the `Escrow` object and returning the XRP to the sender.
***TODO: Are these official escrow statuses you can look up in the XRPL?***
## Escrow States
The following diagram shows the states an Escrow can progress through:
@@ -53,18 +60,6 @@ The diagram shows three different cases for three possible combinations of the e
- Timed releases and expirations resolve according to XRP Ledger close times. In practice, actual release and expiration times can vary by about five seconds as ledgers close.
- The only supported crypto condition type is PREIMAGE-SHA-256.
***TODO: Can we remove this section? It's five years old. Is there any situation where someone's using an old version of the ledger that doesn't have this enabled already?***
## Availability of Escrow
Conditional payments have been enabled by the ["Escrow" Amendment](../../../../amendments/known-amendments.md#escrow) to the XRP Ledger Consensus Protocol since 2017-03-31. A previous version of the same functionality was available on the XRP Ledger Test Net by the name "Suspended Payments" (SusPay) in 2016.
When testing in stand-alone mode, you can force the Escrow feature to be enabled locally regardless of the amendment status. Add the following stanza to your `rippled.cfg`:
[features]
Escrow
You can check the status of the Escrow amendment using the `feature` method.
## Use Cases
### Time-based Lock-Up
@@ -78,14 +73,12 @@ You can check the status of the Escrow amendment using the `feature` method.
Placing the money into escrow sharply limits the amount of XRP that can be stolen or redirected if a malicious actors gains temporary control over Ripple's XRP account. This reduces the risk of catastrophic losses of XRP and increases the time for Ripple to detect, prevent, and track down unintended uses of Ripple's XRP assets.
***TODO: Are interledger payments still a valid use case with an escrow? As I understand it, that was in ILP v1. Payment channels are now recommended for ILP v4.***
### Interledger Payments
***TODO: Think of a smart contract that would see real-world use. The draw of smart contracts is it removes human interaction (I think?), but the example in use-an-escrow-as-a-smart-contract.md still has a person ultimately deciding if someone gets paid.***
### Smart Contracts
**Background:** In the quickly-developing world of financial technology, one of the core challenges is coordinating activities that cross multiple digital money systems, or ledgers. Many proposed solutions to this problem can be reduced to creating "one ledger to rule them all." Ripple doesn't believe a single system can meet everyone's needs; instead, an interconnected network of ledgers—an _interledger_—is the true future of financial technology. The `Interledger Protocol` defines standards for making as many systems as possible connect securely and smoothly.
**Background:**
The most fundamental principle of inter-ledger payments is _conditional transfers_. Multi-hop payments have a risk problem: the more hops in the middle, the more places the payment can fail. Interledger solves this with the financial equivalent of a "[two-phase commit](https://en.wikipedia.org/wiki/Two-phase_commit_protocol)", where the two steps are (1) prepare conditional transfers, then (2) fulfill the conditions to execute the transfers. The Interledger project defined a `crypto-conditions` specification to standardize automated ways to define and verify conditions, and settled on SHA-256 hashes as a "common denominator" of such conditions.
**Solution:** The Escrow feature makes the XRP Ledger ideal for bridging multi-hop payments using the Interledger Protocol, because it natively supports transfers that deliver XRP based on PREIMAGE-SHA-256 crypto-conditions, and it executes those transfers within seconds of being presented with the matching fulfillment.
**Solution:**
## See Also
@@ -99,6 +92,4 @@ The most fundamental principle of inter-ledger payments is _conditional transfer
- [Ledger Reference](ledger-data-formats.html)
- [Escrow object](escrow-object.html)
For more information on Interledger and how conditional transfers enable secure payments across multiple ledgers, see [Interledger Architecture](https://interledger.org/rfcs/0001-interledger-architecture/).
For more information on Ripple's 55-billion XRP lock-up, see [Ripple's Insights Blog](https://ripple.com/insights/ripple-to-place-55-billion-xrp-in-escrow-to-ensure-certainty-into-total-xrp-supply/).

View File

@@ -38,7 +38,7 @@ Sequester XRP until the escrow process either finishes or is canceled.
| `Amount` | String | Amount | Amount of [XRP, in drops][Currency Amount], to deduct from the sender's balance and escrow. Once escrowed, the XRP can either go to the `Destination` address (after the `FinishAfter` time) or returned to the sender (after the `CancelAfter` time). |
| `Destination` | String | AccountID | Address to receive escrowed XRP. The destination can be the same address as the sender. |
| `CancelAfter` | Number | UInt32 | _(Optional)_ The time, in [seconds since the Ripple Epoch][], when this escrow expires. This value is immutable; the funds can only be returned the sender after this time. |
| `FinishAfter` | Number | UInt32 | _(Optional)_ The time, in [seconds since the Ripple Epoch][], when the escrowed XRP can be released to the recipient. This value is immutable, and the funds can't be accessed until this time is reached. |
| `FinishAfter` | Number | UInt32 | _(Optional)_ The time, in [seconds since the Ripple Epoch][], when the escrowed XRP can be released to the recipient. This value is immutable and funds can't be accessed until this time is reached. |
| `Condition` | String | Blob | _(Optional)_ Hex value representing a [PREIMAGE-SHA-256 crypto-condition](https://tools.ietf.org/html/draft-thomas-crypto-conditions-02#section-8.1). The funds can only be delivered to the recipient if this condition is fulfilled. |
| `DestinationTag` | Number | UInt32 | _(Optional)_ Arbitrary tag to further specify the destination for this escrowed payment, such as a hosted recipient at the destination address. |

View File

@@ -8,11 +8,9 @@ labels:
---
# Cancel an Expired Escrow
An escrow in the XRP Ledger is expired when its `CancelAfter` time is lower than the `close_time` of the latest validated ledger. Escrows without a `CancelAfter` time never expire.
## 1. Confirm the expired escrow
## 1. Get the latest validated ledger
Use the [ledger method][] to look up the latest validated ledger and get the `close_time` value.
An escrow in the XRP Ledger is expired when its `CancelAfter` time is lower than the `close_time` of a validated ledger version. (If the escrow does not have a `CancelAfter` time, it never expires.) You can look up the close time of the latest validated ledger with the [ledger method][]:
Request:
@@ -38,10 +36,8 @@ _Websocket_
<!-- MULTICODE_BLOCK_END -->
## 2. Look up the escrow
<!--> Note to Dennis: Maybe include the look up escrows info here and remove the corresponding page entirely? <-->
Use the [account_objects method][] and compare `CancelAfter` to `close_time`:
You can look up the escrow and compare to the `CancelAfter` time using the [account_objects method][]:
Request:
@@ -67,7 +63,7 @@ _Websocket_
<!-- MULTICODE_BLOCK_END -->
## 3. Submit EscrowCancel transaction
## 2. Submit EscrowCancel transaction
***Anyone*** can cancel an expired escrow in the XRP Ledger by [signing and submitting](transaction-basics.html#signing-and-submitting-transactions) an [EscrowCancel transaction][]. Set the `Owner` field of the transaction to the `Account` of the `EscrowCreate` transaction that created this escrow. Set the `OfferSequence` field to the `Sequence` of the `EscrowCreate` transaction.
@@ -99,13 +95,13 @@ _Websocket_
Take note of the transaction's identifying `hash` value so you can check its final status when it is included in a validated ledger version.
## 4. Wait for validation
## 3. Wait for validation
{% include '_snippets/wait-for-validation.md' %} <!--#{ fix md highlighting_ #}-->
## 5. Confirm final result
## 4. Confirm final result
Use the [tx method][] with the `EscrowCancel` transaction's identifying hash to check its final status. Look in the transaction metadata for a `DeletedNode` with `LedgerEntryType` of `Escrow`. Also look for a `ModifiedNode` of type `AccountRoot` for the sender of the escrowed payment. The `FinalFields` of the object should show the increase in XRP in the `Balance` field for the returned XRP.
Use the [tx method][] with the EscrowCancel transaction's identifying hash to check its final status. Look in the transaction metadata for a `DeletedNode` with `LedgerEntryType` of `Escrow`. Also look for a `ModifiedNode` of type `AccountRoot` for the sender of the escrowed payment. The `FinalFields` of the object should show the increase in XRP in the `Balance` field for the returned XRP.
Request:
@@ -133,7 +129,7 @@ _Websocket_
<!-- MULTICODE_BLOCK_END -->
In the above example, `r3wN3v2vTUkr5qd6daqDc2xE4LSysdVjkT` is the sender of the escrow, and the increase in `Balance` from 99999**8**9990 drops to 99999**9**9990 drops represents the return of the escrowed 10,000 drops of XRP (0.01 XRP).
***TODO: Figure out why EscrowFinish is mentioned here. I'm not seeing how it relates to canceling escrows.***
**Tip:** If you don't know what `OfferSequence` to use in the [EscrowFinish transaction][] to execute an escrow, use the [tx method][] to look up the transaction that created the escrow, using the identifying hash of the transaction in the Escrow's `PreviousTxnID` field. Use the `Sequence` value of that transaction as the `OfferSequence` value when finishing the escrow.

View File

@@ -6,14 +6,17 @@ labels:
- Escrow
- Smart Contracts
---
# Look up Escrows
# Look up escrows
All pending escrows are stored in the ledger as [Escrow objects](escrow.html). You can look them up by the sender's address or the destination address.
All pending escrows are stored in the ledger as [Escrow objects](escrow.html).
<!--> Note to Dennis: Is anyone going to be looking up escrows created before 2017? Seems like an extremely niche case to be taking up page space. Remove this maybe? <-->
**Note:** You can only look up pending escrow objects by destination address if those escrows were created after the [fix1523 amendment][] was enabled on 2017-11-14.
You can look up escrow objects by the [sender's address](#look-up-escrows-by-sender-address) or the [destination address](#look-up-escrows-by-destination-address) using the [account_objects method][].
Use the [account_objects][] method, where the sender or destination address is the `account` value.
## Look up escrows by sender address
You can use the [account_objects method][] to look up escrow objects by sender address.
Let's say that you want to look up all pending escrow objects with a sender address of `rfztBskAVszuS3s5Kq7zDS74QtHrw893fm`. You can do this using the following example request, where the sender address is the `account` value.
Request:
@@ -27,7 +30,47 @@ _Websocket_
<!-- MULTICODE_BLOCK_END -->
The response includes all pending escrow objects with `rfztBskAVszuS3s5Kq7zDS74QtHrw893fm`, where the sender address is the `Account` value, or the destination address is the `Destination` value.
The response resembles the following example. Note that the response includes all pending escrow objects with `rfztBskAVszuS3s5Kq7zDS74QtHrw893fm` as the sender or destination address, where the sender address is the `Account` value and the destination address is the `Destination` value.
In this example, the second and fourth escrow objects meet our lookup criteria because their `Account` (sender address) values are set to `rfztBskAVszuS3s5Kq7zDS74QtHrw893fm`.
Response:
<!-- MULTICODE_BLOCK_START -->
_Websocket_
```json
{% include '_code-samples/escrow/websocket/account_objects-response.json' %}
```
<!-- MULTICODE_BLOCK_END -->
## Look up escrows by destination address
You can use the [account_objects method][] to look up escrow objects by destination address.
**Note:** You can only look up pending escrow objects by destination address if those escrows were created after the [fix1523 amendment][] was enabled on 2017-11-14.
Let's say that you want to look up all pending escrow objects with a destination address of `rfztBskAVszuS3s5Kq7zDS74QtHrw893fm`. You can do this using the following example request, where the destination address is the `account` value.
Request:
<!-- MULTICODE_BLOCK_START -->
_Websocket_
```json
{% include '_code-samples/escrow/websocket/account_objects-request.json' %}
```
<!-- MULTICODE_BLOCK_END -->
The response resembles the following example. Note that the response includes all pending escrow objects with `rfztBskAVszuS3s5Kq7zDS74QtHrw893fm` as the destination or sender address, where the destination address is the `Destination` value and the sender address is the `Account` value.
In this example, the first and third escrow objects meet our lookup criteria because their `Destination` (destination address) values are set to `rfztBskAVszuS3s5Kq7zDS74QtHrw893fm`.
Response:

View File

@@ -6,8 +6,8 @@ labels:
- Escrow
- Smart Contracts
---
# Send a Conditionally Held Escrow
<!--> Note to Dennis: This topic is very similar to the use an escrow as a smart contract tutorial. I think the 2 pages can be merged. <-->
# Send a Conditionally-Held Escrow
## 1. Generate condition and fulfillment
XRP Ledger escrows require PREIMAGE-SHA-256 [crypto-conditions][]. To calculate a condition and fulfillment in the proper format, you should use a crypto-conditions library such as [five-bells-condition](https://github.com/interledgerjs/five-bells-condition). To generate the fulfillment:
@@ -36,7 +36,6 @@ console.log('Condition:', condition)
const fulfillment_hex = fulfillment.serializeBinary().toString('hex').toUpperCase()
console.log('Fulfillment:', fulfillment_hex)
```
<!--
_Python_
@@ -53,7 +52,6 @@ print("Condition", fulfillment.condition_binary.hex().upper())
# Keep secret until you want to finish the escrow
print("Fulfillment", fulfillment.serialize_binary().hex().upper())
```
-->
<!-- MULTICODE_BLOCK_END -->

View File

@@ -8,20 +8,18 @@ labels:
---
# Send a Time-Held Escrow
You can configure an escrow to release funds after a specific time has passed.
The [EscrowCreate transaction][] type can create an escrow whose only condition for release is that a specific time has passed. To do this, use the `FinishAfter` field and omit the `Condition` field.
## 1. Calculate release time
You must specify the release time as whole seconds since **[the Ripple Epoch][]**, which you can calculate using this formula:
(Release_Time = Date_in_Unix_Time - 946684800)
***TODO: Format this properly.***
You must specify the time as whole **[seconds since the Ripple Epoch][]**, which is 946684800 seconds after the UNIX epoch. For example, to release funds at midnight UTC on November 13, 2017:
<!-- MULTICODE_BLOCK_START -->
*JavaScript*
```js
// JavaScript Date() is natively expressed in milliseconds; convert to seconds.
// JavaScript Date() is natively expressed in milliseconds; convert to seconds
const release_date_unix = Math.floor( new Date("2017-11-13T00:00:00Z") / 1000 );
const release_date_ripple = release_date_unix - 946684800;
console.log(release_date_ripple);
@@ -43,9 +41,11 @@ print(release_date_ripple)
<!-- MULTICODE_BLOCK_END -->
**Warning:** If you use a UNIX time in the `FinishAfter` field without converting to the equivalent Ripple time first, that sets the unlock time to an extra **30 years** in the future!
## 2. Submit EscrowCreate transaction
<!--> Note to Dennis: I'd like to remove most links taking people out of the tutorial. It breaks the flow of thought and, like you've said earlier, it forces them to think when we're supposed to be doing most of the heavy lifting here. However most of these steps are includes from other pages, so it'd requiring modifying those and I'm not sure how that will affect the other pages they're being referenced. <-->
[Sign and submit](transaction-basics.html#signing-and-submitting-transactions) an [EscrowCreate transaction][]. Set the `FinishAfter` field to the calcualted release time. Set the `Amount` to the total [XRP, in drops][], to escrow.
[Sign and submit](transaction-basics.html#signing-and-submitting-transactions) an [EscrowCreate transaction][]. Set the `FinishAfter` field of the transaction to the time when the held payment should be released. Omit the `Condition` field to make time the only condition for releasing the held payment. Set the `Destination` to the recipient, which may be the same address as the sender. Set the `Amount` to the total amount of [XRP, in drops][], to escrow.
{% include '_snippets/secret-key-warning.md' %} <!--#{ fix md highlighting_ #}-->
@@ -110,7 +110,7 @@ Response:
## 5. Wait for the release time
Held payments release when a ledger closes with a [`close_time` header field](ledger-header.html) that is later than the Escrow node's `FinishAfter` time.
Held payments with a `FinishAfter` time cannot be finished until a ledger has already closed with a [`close_time` header field](ledger-header.html) that is later than the Escrow node's `FinishAfter` time.
You can check the close time of the most recently-validated ledger with the [ledger method][]:
@@ -141,9 +141,12 @@ Response:
## 6. Submit EscrowFinish transaction
[Sign and submit](transaction-basics.html#signing-and-submitting-transactions) an [EscrowFinish transaction][] to execute the release of the funds. Set the `Owner` field of the transaction to the `Account` address from the EscrowCreate transaction, and the `OfferSequence` to the `Sequence` number from the `EscrowCreate` transaction. The sender of this transaction can be any XRP Ledger address.
[Sign and submit](transaction-basics.html#signing-and-submitting-transactions) an [EscrowFinish transaction][] to execute the release of the funds after the `FinishAfter` time has passed. Set the `Owner` field of the transaction to the `Account` address from the EscrowCreate transaction, and the `OfferSequence` to the `Sequence` number from the EscrowCreate transaction. For an escrow held only by time, omit the `Condition` and `Fulfillment` fields.
If the escrow expires, you can only [cancel the escrow](cancel-an-expired-escrow.html).
***TODO: First half of this statement is covered by concept info already. It's also reiterated in escrow.md. The second portion about potential recipients should remain.***
**Tip:** The EscrowFinish transaction is necessary because the XRP Ledger's state can only be modified by transactions. The sender of this transaction may be the recipient of the escrow, the original sender of the escrow, or any other XRP Ledger address.
If the escrow has expired, you can only [cancel the escrow](cancel-an-expired-escrow.html) instead.
{% include '_snippets/secret-key-warning.md' %} <!--#{ fix md highlighting_ #}-->