mirror of
https://github.com/XRPLF/xrpl-dev-portal.git
synced 2026-02-03 13:35:20 +00:00
Compare commits
160 Commits
rewrite_se
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff6e5932f6 | ||
|
|
776a4f290e | ||
|
|
821ada37ba | ||
|
|
8d83ddcf63 | ||
|
|
61e700ed2b | ||
|
|
1c35d320d9 | ||
|
|
63bf0b61ec | ||
|
|
0324ff52b6 | ||
|
|
fdb839295d | ||
|
|
22eaf502a5 | ||
|
|
104977125b | ||
|
|
8a1fb62712 | ||
|
|
c59e930061 | ||
|
|
2a088dfcba | ||
|
|
3d877de05a | ||
|
|
8e8e2fc676 | ||
|
|
ade482a349 | ||
|
|
d6c68d6a2d | ||
|
|
5d18b40746 | ||
|
|
a5f8580e0a | ||
|
|
794f588008 | ||
|
|
799a51f528 | ||
|
|
fef973d443 | ||
|
|
04c33adeb8 | ||
|
|
6611b82f5b | ||
|
|
1a5762b36f | ||
|
|
92b0d8b9d3 | ||
|
|
b3ff5bf1a4 | ||
|
|
695007d3db | ||
|
|
f9aebc83b9 | ||
|
|
fb94fed151 | ||
|
|
778c676664 | ||
|
|
2b6971a89d | ||
|
|
47fb4632bd | ||
|
|
e32c12a359 | ||
|
|
ab14511bb4 | ||
|
|
75f861cfed | ||
|
|
b60c72cdf3 | ||
|
|
f73ebc41bd | ||
|
|
ab7d6a09e9 | ||
|
|
1c6ade3aba | ||
|
|
d9d884543b | ||
|
|
6d2259e30a | ||
|
|
900a4f01ba | ||
|
|
94e4173441 | ||
|
|
9dffd66faf | ||
|
|
ec6bbff42f | ||
|
|
1a0310bf90 | ||
|
|
d2c2b91b0a | ||
|
|
baf0f4e819 | ||
|
|
db9dd303ae | ||
|
|
e181ee6e0f | ||
|
|
af79cb6cf2 | ||
|
|
98bea864bc | ||
|
|
804e51b6b1 | ||
|
|
3853484deb | ||
|
|
c9a560441f | ||
|
|
a789936ad2 | ||
|
|
ca245d72ee | ||
|
|
b0f04a34ed | ||
|
|
5455108464 | ||
|
|
2b1216012e | ||
|
|
f7f5a2e6cf | ||
|
|
5f40b9633e | ||
|
|
dfc84c21cb | ||
|
|
64b5a727e5 | ||
|
|
8f853ffb0b | ||
|
|
ba7a756e39 | ||
|
|
8e325bf3bb | ||
|
|
faf2a4fa4b | ||
|
|
55c12bac85 | ||
|
|
ba4ac4c923 | ||
|
|
0bee628274 | ||
|
|
12b60d17e2 | ||
|
|
54ccc38d1a | ||
|
|
406741663c | ||
|
|
66652d1dab | ||
|
|
f853d9b38c | ||
|
|
84c1a5de16 | ||
|
|
235fc80c2d | ||
|
|
24ba1687f9 | ||
|
|
e4aa7010d9 | ||
|
|
4eeb2d2d49 | ||
|
|
e4cdb7ccea | ||
|
|
dee67b3e77 | ||
|
|
fc8c6fb30e | ||
|
|
a5475869c5 | ||
|
|
053c4bb5a2 | ||
|
|
9ceb186fb4 | ||
|
|
18542eb915 | ||
|
|
d8655b4a0c | ||
|
|
affbab0e74 | ||
|
|
3497c2e2eb | ||
|
|
60c583d5fe | ||
|
|
1facb7c2d3 | ||
|
|
71e2dae458 | ||
|
|
b0d0212024 | ||
|
|
515add6246 | ||
|
|
16a7ece46d | ||
|
|
3fe0afec39 | ||
|
|
8ac405e3be | ||
|
|
921827d6b2 | ||
|
|
3b276c6f19 | ||
|
|
898e698bec | ||
|
|
e5049e53f9 | ||
|
|
afd636e69d | ||
|
|
a5b914caee | ||
|
|
df7cd95784 | ||
|
|
5a9357553c | ||
|
|
21d27c36bb | ||
|
|
d153a017b2 | ||
|
|
20a873ae55 | ||
|
|
e54a5a4ea6 | ||
|
|
a4c9417a7b | ||
|
|
91e8962c25 | ||
|
|
b5f3449547 | ||
|
|
0d4c6e982a | ||
|
|
8f05a58f12 | ||
|
|
d8849f03f9 | ||
|
|
4b8b714e5b | ||
|
|
b5ff3d806e | ||
|
|
152cc95a63 | ||
|
|
898d067c02 | ||
|
|
acc02da22e | ||
|
|
ea16168700 | ||
|
|
ddafea0fe0 | ||
|
|
5d4904cfd6 | ||
|
|
5e02c839ea | ||
|
|
a44713a903 | ||
|
|
3be9307845 | ||
|
|
e197e4e034 | ||
|
|
337a576d2d | ||
|
|
1534ecfa26 | ||
|
|
9600871944 | ||
|
|
a0b688689a | ||
|
|
7f4004ec30 | ||
|
|
372a9128a1 | ||
|
|
3a339849b3 | ||
|
|
8a4d1851db | ||
|
|
2faba938f7 | ||
|
|
7dadae868f | ||
|
|
da422329f9 | ||
|
|
fa40ba2b71 | ||
|
|
506b1c7b21 | ||
|
|
ac623ef506 | ||
|
|
8f21c5d402 | ||
|
|
938a85eac0 | ||
|
|
ad280c2c1b | ||
|
|
316f6f4fd4 | ||
|
|
682389e4e7 | ||
|
|
5c467f1c9b | ||
|
|
104d07c6bf | ||
|
|
f290941300 | ||
|
|
a71a3fca10 | ||
|
|
d89fdc79b8 | ||
|
|
c6df042c7b | ||
|
|
427d0ce441 | ||
|
|
6be3d0117a | ||
|
|
ed4b18586b | ||
|
|
864c412305 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -8,6 +8,7 @@ yarn-error.log
|
||||
*.iml
|
||||
.venv/
|
||||
_code-samples/*/js/package-lock.json
|
||||
_code-samples/*/js/*[Ss]etup.json
|
||||
|
||||
# PHP
|
||||
composer.lock
|
||||
|
||||
@@ -124,9 +124,9 @@ XRP Ledgerは、スパム対策として、需要に基づいて[トランザク
|
||||
|
||||
XRP Ledgerネットワークはオープンネットワークであり、すべての取引はオープンに公開されています。
|
||||
|
||||
Rippleは Ledgerネットワーク全体のAMLフラグを監視・報告し、該当する疑わしい活動をFinCENに報告することにコミットしています。
|
||||
Rippleは XRP Ledgerネットワーク全体のAMLフラグを監視・報告し、該当する疑わしい活動をFinCENに報告することにコミットしています。
|
||||
|
||||
[XRP Forensics / xrplorer](https://xrplorer.com/)は、XRP Ledgerのマネーロンダリング、詐欺、詐欺、不正使用を追跡し、最小限に抑えるための勧告リストを維持しています。取引所やその他のサービス・プロバイダは、金融犯罪を防止し対応するためにこのサービスを利用することができます。
|
||||
[XRP Forensics / xrplorer](https://xrplorer.com/)は、XRP Ledgerのマネーロンダリング、詐欺、不正使用を追跡し、最小限に抑えるための勧告リストを維持しています。取引所やその他のサービス・プロバイダは、金融犯罪を防止し対応するためにこのサービスを利用することができます。
|
||||
|
||||
|
||||
## セキュリティ上の懸念
|
||||
|
||||
@@ -26,14 +26,14 @@ labels:
|
||||
- `RippleState`
|
||||
- `Check`
|
||||
- アカウントがレジャー内に所有するオブジェクトが1000個未満であること。
|
||||
- トランザクションの送信時、少なくとも1つ分の[所有者準備金](reserves.md)(現在2XRP)に相当する特別な[トランザクションコスト][]を支払う必要があります。
|
||||
- トランザクションの送信時、少なくとも1つ分の[所有者準備金](reserves.md)(現在{% $env.PUBLIC_OWNER_RESERVE %})に相当する特別な[トランザクションコスト][]を支払う必要があります。
|
||||
|
||||
|
||||
## 削除コスト
|
||||
|
||||
{% admonition type="warning" name="注意" %}アカウントの削除要件を満たしていないためにトランザクションが失敗した場合でも、[AccountDeleteトランザクション][]のトランザクションコストは、トランザクションが検証済みレジャーに含まれる場合常に発生します。アカウントを削除できなかった場合に高いトランザクションコストを支払う可能性を減らすには、AccountDeleteトランザクションを送信するときに`fail_hard`オプションを使用してください。{% /admonition %}
|
||||
|
||||
ビットコインや他の多くの暗号通貨とは異なり、XRP Ledgerの公開レジャーチェーンのそれぞれの新しいレジャーバージョンは、レジャーの完全な状態を含んでおり、新しいアカウントが増えるごとにサイズが増加します。そのため、必要な場合を除き、新しいXRP Ledgerアカウントを作成すべきではありません。アカウントを削除することで、アカウントの10XRPの[準備金](reserves.md)の一部を回復することができますが、そのためには少なくとも2XRPを破棄する必要があります。
|
||||
ビットコインや他の多くの暗号通貨とは異なり、XRP Ledgerの公開レジャーチェーンのそれぞれの新しいレジャーバージョンは、レジャーの完全な状態を含んでおり、新しいアカウントが増えるごとにサイズが増加します。そのため、必要な場合を除き、新しいXRP Ledgerアカウントを作成すべきではありません。アカウントを削除することで、アカウントの{% $env.PUBLIC_BASE_RESERVE %}の[準備金](reserves.md)の一部を回復することができますが、そのためには少なくとも{% $env.PUBLIC_OWNER_RESERVE %}を破棄する必要があります。
|
||||
|
||||
取引所など、多くのユーザのために価値の送受信を行う組織は、[**送信元タグ**と**宛先タグ**](../transactions/source-and-destination-tags.md)を使用することで、XRP Ledgerのアカウントを1つだけ(または少数)使用するだけで、ユーザの支払いを区別することができます。
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ Deposit Authorizationが有効化されているアカウントの特徴は次
|
||||
|
||||
- [Paymentトランザクション][]の送信先には**できません**。ただし**以下の例外**は除きます。
|
||||
- 送金先により、支払の送金元が[事前承認](#事前承認)されている場合。{% amendment-disclaimer name="DepositPreauth" /%}
|
||||
- アカウントのXRP残高がアカウントの最低[必要準備金](reserves.md)以下で、XRP PaymentのAmountがアカウントの最低準備金(現時点では10XRP)以下である場合は、このアカウントを送金先に指定できます。これにより、アカウントがトランザクションを送信することも、XRPを受領することもできずに操作不可能な状態になるのを防ぎます。この場合、アカウントの所有者の準備金は関係ありません。
|
||||
- アカウントのXRP残高がアカウントの最低[必要準備金](reserves.md)以下で、XRP PaymentのAmountがアカウントの最低準備金(現時点では{% $env.PUBLIC_BASE_RESERVE %})以下である場合は、このアカウントを送金先に指定できます。これにより、アカウントがトランザクションを送信することも、XRPを受領することもできずに操作不可能な状態になるのを防ぎます。この場合、アカウントの所有者の準備金は関係ありません。
|
||||
- **以下に該当する場合にのみ**[PaymentChannelClaimトランザクション][]からXRPを受領できます。
|
||||
- PaymentChannelClaimトランザクションの送金元がPayment Channelの送金先である場合。
|
||||
- PaymentChannelClaimトランザクションの送金先がPaymentChannelClaimの送金元を[事前承認している](#事前承認)場合。{% amendment-disclaimer name="DepositPreauth" /%}
|
||||
|
||||
@@ -46,7 +46,7 @@ XRP Ledgerでアカウントを取得する一般的な方法は次のとおり
|
||||
|
||||
- 例えば、一般的な取引所でXRPを購入し、その取引所から、指定したアドレスにXRPを出金することができます。
|
||||
|
||||
{% admonition type="warning" name="注意" %}自身のXRP Ledgerアドレスで初めてXRPを受け取る場合は[アカウントの準備金](reserves.md)(現在は10XRP)を支払う必要があります。この金額のXRPは無期限に使用できなくなります。一方で、一般的な取引所では通常、顧客のXRPはすべて、共有されたいくつかのXRP Ledgerアカウントに保有されているため、顧客はその取引所で個々のアカウントの準備金を支払う必要はありません。引き出す前に、XRP Ledgerに直接アカウントを保有することが、金額に見合う価値があるかどうかを検討してください。{% /admonition %}
|
||||
{% admonition type="warning" name="注意" %}自身のXRP Ledgerアドレスで初めてXRPを受け取る場合は[アカウントの準備金](reserves.md)(現在は{% $env.PUBLIC_BASE_RESERVE %})を支払う必要があります。この金額のXRPは無期限に使用できなくなります。一方で、一般的な取引所では通常、顧客のXRPはすべて、共有されたいくつかのXRP Ledgerアカウントに保有されているため、顧客はその取引所で個々のアカウントの準備金を支払う必要はありません。引き出す前に、XRP Ledgerに直接アカウントを保有することが、金額に見合う価値があるかどうかを検討してください。{% /admonition %}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ XRP Ledgerのチケットは、取引をすぐに送信せずに、その取引
|
||||
|
||||
上記の例では、シーケンス番号105または作成した3つのチケットのいずれかを使用してトランザクションを送信できます。チケット103を使ってトランザクションを送信すると、それによってチケット103は元帳から削除されます。その後の次のトランザクションでは、シーケンス番号105、チケット102、またはチケット104を使用できます。
|
||||
|
||||
{% admonition type="warning" name="注意" %}チケットは1枚ごとに[所有者準備金](reserves.md#所有者準備金)としてカウントされますので、チケット1枚につき2XRPを確保する必要があります。 (このXRPは、チケットを使用した後に再び使用可能になります)一度に多くのチケットを作成すると、このコストはすぐに膨れ上がります。{% /admonition %}
|
||||
{% admonition type="warning" name="注意" %}チケットは1枚ごとに[所有者準備金](reserves.md#所有者準備金)としてカウントされますので、チケット1枚につき{% $env.PUBLIC_OWNER_RESERVE %}を確保する必要があります。 (このXRPは、チケットを使用した後に再び使用可能になります)一度に多くのチケットを作成すると、このコストはすぐに膨れ上がります。{% /admonition %}
|
||||
|
||||
シーケンス番号と同様に、トランザクションの送信は、そのトランザクションが[コンセンサス](../consensus-protocol/index.md)によって確認された場合にのみ、チケットを使用します。しかし、意図した通りにならなかった取引でも、[`tec`クラスの結果コード](../../references/protocol/transactions/transaction-results/tec-codes.md)を用いてコンセンサスで確認することができます。
|
||||
|
||||
@@ -51,7 +51,7 @@ XRP Ledgerのチケットは、取引をすぐに送信せずに、その取引
|
||||
- 各チケットは一度しか使用できません。同じチケットシーケンスを使用する複数の異なるトランザクション候補があることは可能ですが、コンセンサスで検証できるのはそのうちの1つだけです。
|
||||
- 各アカウントでは、一度に250枚以上のチケットをレジャーに登録することはできません。また、一度に250枚以上のチケットを作成することもできません。
|
||||
- チケットを使って別のチケットを作ることは _できます_。その場合、使用したチケットは、一度に所持できるチケットの合計数にはカウントされません。
|
||||
- 各チケットは[所有者準備金](reserves.md#所有者準備金)にカウントされるため、まだ使用していないチケット1枚につき2XRPを確保する必要があります。このXRPは、チケットを使用した後、再び使用することができます。
|
||||
- 各チケットは[所有者準備金](reserves.md#所有者準備金)にカウントされるため、まだ使用していないチケット1枚につき{% $env.PUBLIC_OWNER_RESERVE %}を確保する必要があります。このXRPは、チケットを使用した後、再び使用することができます。
|
||||
- 個々の元帳の中では、チケットを使用した取引は、同じ送信者からの他の取引の後に実行されます。1つのアカウントが同じ元帳のバージョンでTicketを使用する複数のトランザクションを持つ場合、それらのTicketは最も低いTicket Sequenceから最も高いTicket Sequenceの順に実行されます。 (詳細については、コンセンサスの[正規順序](../consensus-protocol/consensus-structure.md#xrp-ledgerプロトコル-コンセンサスと検証)に関するドキュメントをご覧ください)。
|
||||
- 個々の元帳の中では、チケットを使用した取引は、同じ送信者からの他の取引の後に実行されます。1つのアカウントが同じ元帳のバージョンでチケットを使用する複数のトランザクションを持つ場合、それらのチケットは最も低いチケット シーケンス番号から最も高いチケット シーケンス番号の順に実行されます。 (詳細については、コンセンサスの[正規順序](../consensus-protocol/consensus-structure.md#xrp-ledgerプロトコル-コンセンサスと検証)に関するドキュメントをご覧ください)。
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
html: consensus-protections.html
|
||||
parent: consensus.html
|
||||
seo:
|
||||
description: Learn how the XRP Ledger Consensus Protocol is protected against various problems and attacks that may occur in a decentralized financial system. #TODO: translate
|
||||
description: 分散型金融システムで発生する可能性のあるさまざまな問題や攻撃から、XRP Ledgerコンセンサスプロトコルがどのように保護されているかを学びます。
|
||||
labels:
|
||||
- ブロックチェーン
|
||||
---
|
||||
|
||||
@@ -12,11 +12,11 @@ NFTをミントし、保有し、販売するためには、XRPを準備金と
|
||||
|
||||
## 基本準備金
|
||||
|
||||
アカウントでは、基本準備金(現在10XRP)を用意する必要があります。基本準備金のXRPの金額は変更される可能性があります。[基本準備金と所有者準備金](../../accounts/reserves.md#基本準備金と所有者準備金)をご覧ください。
|
||||
アカウントでは、基本準備金(現在{% $env.PUBLIC_BASE_RESERVE %})を用意する必要があります。基本準備金のXRPの金額は変更される可能性があります。[基本準備金と所有者準備金](../../accounts/reserves.md#基本準備金と所有者準備金)をご覧ください。
|
||||
|
||||
## 所有者準備金
|
||||
|
||||
XRP Ledgerで所有する各オブジェクトには、現在2XRPの所有者準備金が必要とされています。これは、ユーザが不必要なデータで台帳にスパムをかけることを抑制し、不要になったデータを削除することを促すためのものです。所有者準備金の額は変更される可能性があります。[基本準備金と所有者準備金](../../accounts/reserves.md#基本準備金と所有者準備金)をご覧ください。
|
||||
XRP Ledgerで所有する各オブジェクトには、現在{% $env.PUBLIC_OWNER_RESERVE %}の所有者準備金が必要とされています。これは、ユーザが不必要なデータで台帳にスパムをかけることを抑制し、不要になったデータを削除することを促すためのものです。所有者準備金の額は変更される可能性があります。[基本準備金と所有者準備金](../../accounts/reserves.md#基本準備金と所有者準備金)をご覧ください。
|
||||
|
||||
NFTの場合、 _オブジェクト_ はそれぞれのNFTを指すのではなく、アカウントが所有する`NFTokenPage`オブジェクトを指します。`NFTokenPage`オブジェクトは最大32個のNFTを格納することができます。
|
||||
|
||||
@@ -38,7 +38,7 @@ NFTの保有枚数や保有ページ数によって、所有者準備金の総
|
||||
|
||||
## `NFTokenOffer`の準備金
|
||||
|
||||
各`NFTokenOffer`オブジェクトは、オファーを出すアカウントに対して準備金の1つの増加を必要とします。この記事の執筆時点では、準備金の増分は2XRPです。準備金は、オファーをキャンセルすることで取り戻すことができます。また、オファーが受け入れられると、XRP Ledgerからオファーが削除され、準備金は取り戻されます。
|
||||
各`NFTokenOffer`オブジェクトは、オファーを出すアカウントに対して準備金の1つの増加を必要とします。この記事の執筆時点では、準備金の増分は{% $env.PUBLIC_OWNER_RESERVE %}です。準備金は、オファーをキャンセルすることで取り戻すことができます。また、オファーが受け入れられると、XRP Ledgerからオファーが削除され、準備金は取り戻されます。
|
||||
|
||||
## Practical Considerations
|
||||
|
||||
@@ -55,7 +55,7 @@ NFTをミントし、保有し、売買のオファーをする場合、必要
|
||||
|
||||
{% admonition type="info" name="注記" %}準備金要件ではありませんが、ミントと売却のプロセスにおけるトランザクションの些細な手数料(通常12drops、または.000012XRP)を負担するために、少なくとも必要準備金より1XRPより多く用意しておきくべきです。{% /admonition %}
|
||||
|
||||
仮に200個のNFTをミントし、それぞれに「NFTokenSellOffer」を作成すると、436XRPもの準備金が必要になります。
|
||||
仮に200個のNFTをミントし、それぞれに「NFTokenSellOffer」を作成すると、43.6XRPもの準備金が必要になります。
|
||||
|
||||
| 準備金の種類 | 準備金の額 |
|
||||
|:--------------------|--------:|
|
||||
|
||||
@@ -104,142 +104,16 @@ rippled tx C53ECF838647FA5A4C780377025FEC7999AB4182590510CA461444B207AB74A9 fals
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="WebSocket (Hash)" %}
|
||||
{% code-snippet file="/_api-examples/tx/ws-response-hash.json" language="json" /%}
|
||||
{% tab label="WebSocket" %}
|
||||
{% code-snippet file="/_api-examples/tx/ws-response.json" language="json" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% tab label="WebSocket (CTID)" %}
|
||||
{% code-snippet file="/_api-examples/tx/ws-response-ctid.json" language="json" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% tab label="JSON-RPC (Hash)" %}
|
||||
{% code-snippet file="/_api-examples/tx/jsonrpc-response-hash.json" language="json" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% tab label="JSON-RPC (CTID)" %}
|
||||
{% code-snippet file="/_api-examples/tx/jsonrpc-response-ctid.json" language="json" /%}
|
||||
{% tab label="JSON-RPC" %}
|
||||
{% code-snippet file="/_api-examples/tx/jsonrpc-response.json" language="json" prefix="200 OK\n\n" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% tab label="Commandline" %}
|
||||
```json
|
||||
{
|
||||
"result" : {
|
||||
"Account" : "rhhh49pFH96roGyuC4E5P4CHaNjS1k8gzM",
|
||||
"Fee" : "12",
|
||||
"Flags" : 0,
|
||||
"LastLedgerSequence" : 56865248,
|
||||
"OfferSequence" : 5037708,
|
||||
"Sequence" : 5037710,
|
||||
"SigningPubKey" : "03B51A3EDF70E4098DA7FB053A01C5A6A0A163A30ED1445F14F87C7C3295FCB3BE",
|
||||
"TakerGets" : "15000000000",
|
||||
"TakerPays" : {
|
||||
"currency" : "CNY",
|
||||
"issuer" : "rKiCet8SdvWxPXnAgYarFUXMh1zCPz432Y",
|
||||
"value" : "20160.75"
|
||||
},
|
||||
"TransactionType" : "OfferCreate",
|
||||
"TxnSignature" : "3045022100A5023A0E64923616FCDB6D664F569644C7C9D1895772F986CD6B981B515B02A00220530C973E9A8395BC6FE2484948D2751F6B030FC7FB8575D1BFB406368AD554D9",
|
||||
"date" : 648248020,
|
||||
"hash" : "C53ECF838647FA5A4C780377025FEC7999AB4182590510CA461444B207AB74A9",
|
||||
"inLedger" : 56865245,
|
||||
"ledger_index" : 56865245,
|
||||
"meta" : {
|
||||
"AffectedNodes" : [
|
||||
{
|
||||
"ModifiedNode" : {
|
||||
"FinalFields" : {
|
||||
"ExchangeRate" : "4F04C66806CF7400",
|
||||
"Flags" : 0,
|
||||
"RootIndex" : "02BAAC1E67C1CE0E96F0FA2E8061020536CEDD043FEB0FF54F04C66806CF7400",
|
||||
"TakerGetsCurrency" : "0000000000000000000000000000000000000000",
|
||||
"TakerGetsIssuer" : "0000000000000000000000000000000000000000",
|
||||
"TakerPaysCurrency" : "000000000000000000000000434E590000000000",
|
||||
"TakerPaysIssuer" : "CED6E99370D5C00EF4EBF72567DA99F5661BFB3A"
|
||||
},
|
||||
"LedgerEntryType" : "DirectoryNode",
|
||||
"LedgerIndex" : "02BAAC1E67C1CE0E96F0FA2E8061020536CEDD043FEB0FF54F04C66806CF7400"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode" : {
|
||||
"FinalFields" : {
|
||||
"Account" : "rhhh49pFH96roGyuC4E5P4CHaNjS1k8gzM",
|
||||
"Balance" : "10404767991",
|
||||
"Flags" : 0,
|
||||
"OwnerCount" : 3,
|
||||
"Sequence" : 5037711
|
||||
},
|
||||
"LedgerEntryType" : "AccountRoot",
|
||||
"LedgerIndex" : "1DECD9844E95FFBA273F1B94BA0BF2564DDF69F2804497A6D7837B52050174A2",
|
||||
"PreviousFields" : {
|
||||
"Balance" : "10404768003",
|
||||
"Sequence" : 5037710
|
||||
},
|
||||
"PreviousTxnID" : "4DC47B246B5EB9CCE92ABA8C482479E3BF1F946CABBEF74CA4DE36521D5F9008",
|
||||
"PreviousTxnLgrSeq" : 56865244
|
||||
}
|
||||
},
|
||||
{
|
||||
"DeletedNode" : {
|
||||
"FinalFields" : {
|
||||
"Account" : "rhhh49pFH96roGyuC4E5P4CHaNjS1k8gzM",
|
||||
"BookDirectory" : "02BAAC1E67C1CE0E96F0FA2E8061020536CEDD043FEB0FF54F04C66806CF7400",
|
||||
"BookNode" : "0000000000000000",
|
||||
"Flags" : 0,
|
||||
"OwnerNode" : "0000000000000000",
|
||||
"PreviousTxnID" : "8F5FF57B404827F12BDA7561876A13C3E3B3095CBF75334DBFB5F227391A660C",
|
||||
"PreviousTxnLgrSeq" : 56865244,
|
||||
"Sequence" : 5037708,
|
||||
"TakerGets" : "15000000000",
|
||||
"TakerPays" : {
|
||||
"currency" : "CNY",
|
||||
"issuer" : "rKiCet8SdvWxPXnAgYarFUXMh1zCPz432Y",
|
||||
"value" : "20160.75"
|
||||
}
|
||||
},
|
||||
"LedgerEntryType" : "Offer",
|
||||
"LedgerIndex" : "26AAE6CA8D29E28A47C92ADF22D5D96A0216F0551E16936856DDC8CB1AAEE93B"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode" : {
|
||||
"FinalFields" : {
|
||||
"Flags" : 0,
|
||||
"IndexNext" : "0000000000000000",
|
||||
"IndexPrevious" : "0000000000000000",
|
||||
"Owner" : "rhhh49pFH96roGyuC4E5P4CHaNjS1k8gzM",
|
||||
"RootIndex" : "47FAF5D102D8CE655574F440CDB97AC67C5A11068BB3759E87C2B9745EE94548"
|
||||
},
|
||||
"LedgerEntryType" : "DirectoryNode",
|
||||
"LedgerIndex" : "47FAF5D102D8CE655574F440CDB97AC67C5A11068BB3759E87C2B9745EE94548"
|
||||
}
|
||||
},
|
||||
{
|
||||
"CreatedNode" : {
|
||||
"LedgerEntryType" : "Offer",
|
||||
"LedgerIndex" : "8BAEE3C7DE04A568E96007420FA11ABD0BC9AE44D35932BB5640E9C3FB46BC9B",
|
||||
"NewFields" : {
|
||||
"Account" : "rhhh49pFH96roGyuC4E5P4CHaNjS1k8gzM",
|
||||
"BookDirectory" : "02BAAC1E67C1CE0E96F0FA2E8061020536CEDD043FEB0FF54F04C66806CF7400",
|
||||
"Sequence" : 5037710,
|
||||
"TakerGets" : "15000000000",
|
||||
"TakerPays" : {
|
||||
"currency" : "CNY",
|
||||
"issuer" : "rKiCet8SdvWxPXnAgYarFUXMh1zCPz432Y",
|
||||
"value" : "20160.75"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"TransactionIndex" : 0,
|
||||
"TransactionResult" : "tesSUCCESS"
|
||||
},
|
||||
"status" : "success",
|
||||
"validated" : true
|
||||
}
|
||||
}
|
||||
```
|
||||
{% code-snippet file="/_api-examples/tx/jsonrpc-response.json" language="json" prefix="Loading: \"/etc/opt/ripple/rippled.cfg\"\n2025-Dec-19 03:16:00.638871262 UTC HTTPClient:NFO Connecting to 127.0.0.1:5005\n\n" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
@@ -72,7 +72,7 @@ labels:
|
||||
|
||||
### `NFTokenOffer`の準備金
|
||||
|
||||
各`NFTokenOffer`オブジェクトは、オファーを出すアカウントに1つ分の準備金の増額を要求します。執筆時点では、準備金の増分は2XRPです。この準備金は、オファーをキャンセルすることで取り戻すことができます。
|
||||
各`NFTokenOffer`オブジェクトは、オファーを出すアカウントに1つ分の準備金の増額を要求します。執筆時点では、準備金の増分は{% $env.PUBLIC_OWNER_RESERVE %}です。この準備金は、オファーをキャンセルすることで取り戻すことができます。
|
||||
|
||||
|
||||
### `NFTokenOfferID`のフォーマット
|
||||
|
||||
@@ -48,7 +48,7 @@ AMMを表す[AMMエントリ][]と[特殊なAccountRootエントリ](../../ledge
|
||||
|
||||
## 特殊なトランザクションコスト
|
||||
|
||||
各AMMインスタンスはAccountRootレジャーエントリ、AMMレジャーエントリ、プール内の各トークンのトラストラインを含むため、AMMCreateトランザクションは台帳スパムを抑止するために通常よりもはるかに高い[トランザクションコスト][]を必要とします。標準的な最低0.00001XRPの代わりに、AMMCreateは少なくとも所有者準備金の増分(現在は2XRP)を破棄しなければなりません。これは[AccountDeleteトランザクション][]と同じ特別なトランザクションコストです。
|
||||
各AMMインスタンスはAccountRootレジャーエントリ、AMMレジャーエントリ、プール内の各トークンのトラストラインを含むため、AMMCreateトランザクションは台帳スパムを抑止するために通常よりもはるかに高い[トランザクションコスト][]を必要とします。標準的な最低0.00001XRPの代わりに、AMMCreateは少なくとも所有者準備金の増分(現在は{% $env.PUBLIC_OWNER_RESERVE %})を破棄しなければなりません。これは[AccountDeleteトランザクション][]と同じ特別なトランザクションコストです。
|
||||
|
||||
## エラーケース
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ labels:
|
||||
|
||||
- トランザクションを送信するための十分なXRPが供給されていて、新しい署名者リストの[必要準備金](../../../concepts/accounts/reserves.md)を満たしている資金供給のあるXRP Ledger[アドレス](../../../concepts/accounts/index.md)が必要です。
|
||||
|
||||
- [MultiSignReserve Amendment][]が有効な場合、マルチシグを使用するには、使用する署名と署名者の数に関わらず、アカウントの準備金として2 XRPが必要です。(MultiSignReserve Amendmentは**2019年4月7日**以降、本番環境のXRP Ledgerで有効になっています。)
|
||||
- [MultiSignReserve Amendment][]が有効な場合、マルチシグを使用するには、使用する署名と署名者の数に関わらず、アカウントの準備金として{% $env.PUBLIC_OWNER_RESERVE %}が必要です。(MultiSignReserve Amendmentは**2019年4月7日**以降、本番環境のXRP Ledgerで有効になっています。)
|
||||
|
||||
- [MultiSignReserve Amendment][]が有効ではないテストネットワークでは、マルチシグを使用するには[アカウント準備金](../../../concepts/accounts/reserves.md)に通常よりも多くのXRPが必要となります。必要額は、リストの署名者の数に応じて増加します。
|
||||
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
---
|
||||
html: cancel-an-expired-escrow.html
|
||||
parent: use-escrows.html
|
||||
seo:
|
||||
description: 有効期限切れのEscrowを取り消します。
|
||||
labels:
|
||||
- Escrow
|
||||
- スマートコントラクト
|
||||
---
|
||||
# 有効期限切れEscrowの取消し
|
||||
|
||||
## 1.有効期限切れEscrowの確認
|
||||
|
||||
XRP LedgerのEscrowが有効期限切れとなるのは、その`CancelAfter`の時刻が検証済みレジャーの`close_time`よりも前である場合です。(Escrowに`CancelAfter`時刻が指定されていない場合は、Escrowが有効期限切れになることはありません。)最新の検証済みレジャーの閉鎖時刻は、[ledgerメソッド][]を使用して検索できます。
|
||||
|
||||
リクエスト:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="Websocket" %}
|
||||
{% code-snippet file="/_api-examples/escrow/websocket/ledger-request-expiration.json" language="json" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
レスポンス:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="Websocket" %}
|
||||
{% code-snippet file="/_api-examples/escrow/websocket/ledger-response-expiration.json" language="json" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
|
||||
[account_objectsメソッド][]を使用してEscrowを検索し、`CancelAfter`の時刻と比較できます。
|
||||
|
||||
リクエスト:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="Websocket" %}
|
||||
{% code-snippet file="/_api-examples/escrow/websocket/account_objects-request-expiration.json" language="json" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
レスポンス:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="Websocket" %}
|
||||
{% code-snippet file="/_api-examples/escrow/websocket/account_objects-response-expiration.json" language="json" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
## 2.EscrowCancelトランザクションの送信
|
||||
|
||||
XRP Ledgerでは、[EscrowCancelトランザクション][]に[署名して送信する](../../../../concepts/transactions/index.md#トランザクションへの署名とトランザクションの送信)ことで、***誰でも***有効期限切れのEscrowを取り消すことができます。トランザクションの`Owner`フィールドを、そのEscrowを作成した`EscrowCreate`トランザクションの`Account`に設定します。`OfferSequence`フィールドを、`EscrowCreate`トランザクションの`Sequence`に設定します。
|
||||
|
||||
{% partial file="/@l10n/ja/docs/_snippets/secret-key-warning.md" /%}
|
||||
|
||||
リクエスト:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="Websocket" %}
|
||||
{% code-snippet file="/_api-examples/escrow/websocket/submit-request-escrowcancel.json" language="json" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
レスポンス:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="Websocket" %}
|
||||
{% code-snippet file="/_api-examples/escrow/websocket/submit-response-escrowcancel.json" language="json" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
トランザクションの識別用`hash`値をメモしておきます。これにより、検証済みレジャーバージョンに記録されるときにその最終ステータスを確認できます。
|
||||
|
||||
## 3.検証の待機
|
||||
|
||||
{% partial file="/@l10n/ja/docs/_snippets/wait-for-validation.md" /%}
|
||||
|
||||
## 4.最終結果の確認
|
||||
|
||||
EscrowCancelトランザクションの識別用ハッシュを指定した[txメソッド][]を使用してトランザクションの最終ステータスを確認します。トランザクションのメタデータで`LedgerEntryType`が`Escrow`である`DeletedNode`を探します。また、エスクローに預託された支払いの送金元の`ModifiedNode`(タイプが`AccountRoot`)も探します。オブジェクトの`FinalFields`に、`Balance`フィールドのXRP返金額の増分が表示されている必要があります。
|
||||
|
||||
リクエスト:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="Websocket" %}
|
||||
{% code-snippet file="/_api-examples/escrow/websocket/tx-request-escrowcancel.json" language="json" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
レスポンス:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="Websocket" %}
|
||||
{% code-snippet file="/_api-examples/escrow/websocket/tx-response-escrowcancel.json" language="json" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
上記の例では、`r3wN3v2vTUkr5qd6daqDc2xE4LSysdVjkT`がEscrowの送金元であり、`Balance`が99999**8**9990 dropから99999**9**9990 dropに増加していることから、エスクローに預託されていた10,000 XRP dropが返金されたことがわかります(drop = 0.01XRP) 。
|
||||
|
||||
{% admonition type="success" name="ヒント" %}Escrowを実行する[EscrowFinishトランザクション][]で使用する`OfferSequence`が不明な場合は、Escrowの`PreviousTxnID`フィールドのトランザクションの識別用ハッシュを指定した[txメソッド][]を使用して、そのEscrowを作成したトランザクションを検索します。Escrowを終了するときには、そのトランザクションの`Sequence`の値を`OfferSequence`の値として使用します。{% /admonition %}
|
||||
|
||||
{% raw-partial file="/@l10n/ja/docs/_snippets/common-links.md" /%}
|
||||
@@ -1,80 +0,0 @@
|
||||
---
|
||||
html: look-up-escrows.html
|
||||
parent: use-escrows.html
|
||||
seo:
|
||||
description: 送金元または送金先のアドレスを使って保留中のEscrowを検索します。
|
||||
labels:
|
||||
- Escrow
|
||||
- スマートコントラクト
|
||||
---
|
||||
# Escrowの検索
|
||||
|
||||
保留中のEscrowはすべて[Escrowオブジェクト](../../../../concepts/payment-types/escrow.md)としてレジャーに保管されます。
|
||||
|
||||
Escrowオブジェクトを検索するには、[account_objectsメソッド][]で[送金元のアドレス](#送金元のアドレスによるescrowの検索)または[送金先のアドレス](#送金先のアドレスによるescrowの検索)を使用して検索します。
|
||||
|
||||
## 送金元のアドレスによるEscrowの検索
|
||||
|
||||
[account_objectsメソッド][]を使用して、送金元アドレスからEscrowオブジェクトを検索できます。
|
||||
|
||||
たとえば、送金元アドレスが`rfztBskAVszuS3s5Kq7zDS74QtHrw893fm`である保留中のEscrowオブジェクトをすべて検索するとします。以下のリクエストの例に従ってこの検索を実行できます。この例では送金元アドレスは`account`の値です。
|
||||
|
||||
リクエスト:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="Websocket" %}
|
||||
{% code-snippet file="/_api-examples/escrow/websocket/account_objects-request.json" language="json" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
|
||||
レスポンスは以下の例のようになります。このレスポンスには、送金元アドレスまたは送金先アドレスが`rfztBskAVszuS3s5Kq7zDS74QtHrw893fm`である保留中のEscrowオブジェクトがすべて含まれています。送金元アドレスは`Account`の値であり、送金先アドレスは`Destination`の値です。
|
||||
|
||||
この例では、2番目と4番目のEscrowオブジェクトが検索条件に一致しています。これは、これらのオブジェクトの`Account`(送金元のアドレス)の値が`rfztBskAVszuS3s5Kq7zDS74QtHrw893fm`に設定されているためです。
|
||||
|
||||
レスポンス:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="Websocket" %}
|
||||
{% code-snippet file="/_api-examples/escrow/websocket/account_objects-response.json" language="json" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
## 送金先のアドレスによるEscrowの検索
|
||||
|
||||
[account_objectsメソッド][]を使用して、送金先アドレスからEscrowオブジェクトを検索できます。
|
||||
|
||||
{% admonition type="info" name="注記" %}送金先のアドレスによる保留中のEscrowオブジェクトの検索は、[fix1523 Amendment][]が2017/11/14に有効化された後に作成されたEscrowについてのみ行うことができます。{% /admonition %}
|
||||
|
||||
たとえば、送金先アドレスが`rfztBskAVszuS3s5Kq7zDS74QtHrw893fm`である保留中のEscrowオブジェクトをすべて検索するとします。以下のリクエストの例に従ってこの検索を実行できます。この例では送金先アドレスは`account`の値です。
|
||||
|
||||
リクエスト:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="Websocket" %}
|
||||
{% code-snippet file="/_api-examples/escrow/websocket/account_objects-request.json" language="json" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
|
||||
レスポンスは以下の例のようになります。レスポンスには送金先アドレスまたは送金元アドレスが`rfztBskAVszuS3s5Kq7zDS74QtHrw893fm`である保留中のEscrowオブジェクトがすべて含まれています。送金先アドレスは`Destination`の値であり、送金元アドレスは`Account`の値です。
|
||||
|
||||
この例では、1番目と3番目のEscrowオブジェクトが検索条件に一致しています。これは、これらのオブジェクトの`Destination`(送金先のアドレス)の値が`rfztBskAVszuS3s5Kq7zDS74QtHrw893fm`に設定されているためです。
|
||||
|
||||
レスポンス:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="Websocket" %}
|
||||
{% code-snippet file="/_api-examples/escrow/websocket/account_objects-response.json" language="json" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
{% raw-partial file="/@l10n/ja/docs/_snippets/common-links.md" /%}
|
||||
@@ -1,173 +0,0 @@
|
||||
---
|
||||
html: send-a-conditionally-held-escrow.html
|
||||
parent: use-escrows.html
|
||||
seo:
|
||||
description: 満たされた条件に基づいてリリースとなるEscrowを作成します。
|
||||
labels:
|
||||
- Escrow
|
||||
- スマートコントラクト
|
||||
---
|
||||
# 条件に基づくEscrowの送信
|
||||
|
||||
## 1.条件とフルフィルメントの生成
|
||||
|
||||
XRP Ledger EscrowにはPREIMAGE-SHA-256 [Crypto-Conditions](https://tools.ietf.org/html/draft-thomas-crypto-conditions-03)が必要です。条件とフルフィルメントを適切なフォーマットで計算するには、[five-bells-condition](https://github.com/interledgerjs/five-bells-condition)などのCrypto-conditionsライブラリを使用する必要があります。フルフィルメントについては、以下のフルフィルメントを生成するためのメソッドのいずれかを使用することが推奨されます。
|
||||
|
||||
- 暗号論的に安全な乱数ソースを使用して、32バイト以上のランダムバイトを生成します。
|
||||
- Interledger Protocolの[PSK仕様](https://github.com/interledger/rfcs/blob/master/deprecated/0016-pre-shared-key/0016-pre-shared-key.md)に従い、ILPパケットのHMAC-SHA-256をフルフィルメントとして使用します。
|
||||
|
||||
ランダムなフルフィルメントと条件のJavaScriptコードの例:
|
||||
|
||||
```js
|
||||
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時間先に設定する例:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="JavaScript" %}
|
||||
```js
|
||||
const rippleOffset = 946684800
|
||||
const CancelAfter = Math.floor(Date.now() / 1000) + (24*60*60) - rippleOffset
|
||||
console.log(CancelAfter)
|
||||
// Example:556927412
|
||||
```
|
||||
{% /tab %}
|
||||
|
||||
{% tab label="Python 2/3" %}
|
||||
```python
|
||||
from time import time
|
||||
ripple_offset = 946684800
|
||||
cancel_after = int(time()) + (24*60*60) - 946684800
|
||||
print(cancel_after)
|
||||
# Example: 556927412
|
||||
```
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
{% admonition type="danger" name="警告" %}XRP Ledgerでは、時刻を**Rippleエポック(2000-01-01T00:00:00Z)以降の経過秒数**として指定する必要があります。`CancelAfter`または`FinishAfter`フィールドで、UNIX時刻を同等のRipple時刻に変換せずに使用すると、ロック解除時刻が**30年**先に設定されることになります。{% /admonition %}
|
||||
|
||||
## 3.EscrowCreateトランザクションの送信
|
||||
|
||||
[EscrowCreateトランザクション][]に[署名して送信](../../../../concepts/transactions/index.md#トランザクションへの署名とトランザクションの送信)します。トランザクションの`Condition`フィールドを、保留中の支払いがリリースされる時刻に設定します。`Destination`を受取人に設定します。受取人と送金元のアドレスは同じでもかまいません。前の手順で算出した`CancelAfter`または`FinishAfter`の時刻も指定します。`Amount`を、Escrowする[XRPのdrop数][]の合計額に設定します。
|
||||
|
||||
{% partial file="/@l10n/ja/docs/_snippets/secret-key-warning.md" /%}
|
||||
|
||||
リクエスト:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="Websocket" %}
|
||||
{% code-snippet file="/_api-examples/escrow/websocket/submit-request-escrowcreate-condition.json" language="json" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
レスポンス:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="Websocket" %}
|
||||
{% code-snippet file="/_api-examples/escrow/websocket/submit-response-escrowcreate-condition.json" language="json" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
## 4.検証の待機
|
||||
|
||||
{% partial file="/@l10n/ja/docs/_snippets/wait-for-validation.md" /%}
|
||||
|
||||
## 5.Escrowが作成されたことの確認
|
||||
|
||||
トランザクションの識別用ハッシュを指定した[txメソッド][]を使用して、トランザクションの最終ステータスを確認します。特に、[Escrowレジャーオブジェクト](../../../../concepts/payment-types/escrow.md)が作成されたことを示す`CreatedNode`をトランザクションメタデータで探します。
|
||||
|
||||
リクエスト:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="Websocket" %}
|
||||
{% code-snippet file="/_api-examples/escrow/websocket/tx-request-escrowcreate-condition.json" language="json" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
レスポンス:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="Websocket" %}
|
||||
{% code-snippet file="/_api-examples/escrow/websocket/tx-response-escrowcreate-condition.json" language="json" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
## 6.EscrowFinishトランザクションの送信
|
||||
|
||||
`FinishAfter`の時刻が経過した後で資金のリリースを実行する[EscrowFinishトランザクション][]に[署名して送信](../../../../concepts/transactions/index.md#トランザクションへの署名とトランザクションの送信)します。トランザクションの`Owner`フィールドにEscrowCreateトランザクションの`Account`アドレスを設定し、`OfferSequence` にEscrowCreateトランザクションの`Sequence`番号を設定します。`Condition`フィールドと`Fulfillment`フィールドに、ステップ1で生成した条件値とフルフィルメント値をそれぞれ16進数で設定します。フルフィルメントのサイズ(バイト数)に基づいて`Fee`([トランザクションコスト](../../../../concepts/transactions/transaction-cost.md))の値を設定します。条件付きEscrowFinishでは、少なくとも330 drop(XRP)と、フルフィルメントのサイズで16バイトごとに10 dropが必要です。
|
||||
|
||||
{% admonition type="info" name="注記" %}EscrowCreateトランザクションに`FinishAfter`フィールドが含まれている場合、Escrowの条件として正しいフルフィルメントを指定しても、この時刻よりも前の時点ではこのトランザクションを実行できません。前に閉鎖されたレジャーの閉鎖時刻が`FinishAfter`の時刻よりも前である場合、EscrowFinishトランザクションは[結果コード](../../../../references/protocol/transactions/transaction-results/index.md)`tecNO_PERMISSION`で失敗します。{% /admonition %}
|
||||
|
||||
Escrowが有効期限切れの場合は、[Escrowの取消し](cancel-an-expired-escrow.md)だけが可能です。
|
||||
|
||||
{% partial file="/@l10n/ja/docs/_snippets/secret-key-warning.md" /%}
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="Websocket" %}
|
||||
{% code-snippet file="/_api-examples/escrow/websocket/submit-request-escrowfinish-condition.json" language="json" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
レスポンス:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="Websocket" %}
|
||||
{% code-snippet file="/_api-examples/escrow/websocket/submit-response-escrowfinish-condition.json" language="json" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
トランザクションの識別用`hash`値をメモしておきます。これにより、検証済みレジャーバージョンに記録されるときにその最終ステータスを確認できます。
|
||||
|
||||
## 7.検証の待機
|
||||
|
||||
{% partial file="/@l10n/ja/docs/_snippets/wait-for-validation.md" /%}
|
||||
|
||||
## 8.最終結果の確認
|
||||
|
||||
EscrowFinishトランザクションの識別用ハッシュを指定した[txメソッド][]を使用して、トランザクションの最終ステータスを確認します。特にトランザクションメタデータ内で、エスクローに預託された支払いの送金先の`ModifiedNode`(タイプが`AccountRoot`)を確認します。オブジェクトの`FinalFields`に、`Balance`フィールドのXRP返金額の増分が表示されている必要があります。
|
||||
|
||||
リクエスト:
|
||||
|
||||
{% code-snippet file="/_api-examples/escrow/websocket/tx-request-escrowfinish-condition.json" language="json" /%}
|
||||
|
||||
レスポンス:
|
||||
|
||||
{% code-snippet file="/_api-examples/escrow/websocket/tx-response-escrowfinish-condition.json" language="json" /%}
|
||||
|
||||
{% raw-partial file="/@l10n/ja/docs/_snippets/common-links.md" /%}
|
||||
@@ -1,188 +0,0 @@
|
||||
---
|
||||
html: send-a-time-held-escrow.html
|
||||
parent: use-escrows.html
|
||||
seo:
|
||||
description: 指定した時間が経過することがリリースの唯一の条件であるEscrowを作成します。
|
||||
labels:
|
||||
- Escrow
|
||||
- スマートコントラクト
|
||||
---
|
||||
# 時間に基づくEscrowの送信
|
||||
|
||||
[EscrowCreateトランザクション][]タイプでは、リリースの唯一の条件が特定時刻を経過することであるEscrowを作成できます。このためには、`FinishAfter`フィールドを使用し、`Condition`フィールドを省略します。
|
||||
|
||||
## 1.リリース時刻の計算
|
||||
|
||||
時刻を **[Rippleエポック以降の経過秒数][]** として指定する必要があります。Rippleエポックは、UNIXエポックの946684800秒後です。たとえば、2017年11月13日の午前0時(UTC)に資金をリリースする場合、以下のようになります。
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="JavaScript" %}
|
||||
```js
|
||||
// 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);
|
||||
// 563846400
|
||||
```
|
||||
{% /tab %}
|
||||
|
||||
{% tab label="Python 3" %}
|
||||
```python
|
||||
import datetime
|
||||
release_date_utc = datetime.datetime(2017,11,13,0,0,0,tzinfo=datetime.timezone.utc)
|
||||
release_date_ripple = int(release_date_utc.timestamp()) - 946684800
|
||||
print(release_date_ripple)
|
||||
# 563846400
|
||||
```
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
{% admonition type="danger" name="警告" %}`FinishAfter`フィールドで、UNIX時刻を同等のRipple時刻に変換せずに使用すると、ロック解除時刻が30年先に設定されることになります。{% /admonition %}
|
||||
|
||||
## 2.EscrowCreateトランザクションの送信
|
||||
|
||||
[EscrowCreateトランザクション][]に[署名して送信](../../../../concepts/transactions/index.md#トランザクションへの署名とトランザクションの送信)します。トランザクションの`FinishAfter`フィールドを、保留中の支払いがリリースされる時刻に設定します。`Condition`フィールドを省略して、時刻を保留中の支払いをリリースする唯一の条件とします。`Destination`を受取人に設定します。受取人と送金元のアドレスは同じでもかまいません。`Amount`を、Escrowする[XRPのdrop数][]の合計額に設定します。
|
||||
|
||||
{% partial file="/@l10n/ja/docs/_snippets/secret-key-warning.md" /%}
|
||||
|
||||
リクエスト:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="Websocket" %}
|
||||
{% code-snippet file="/_api-examples/escrow/websocket/submit-request-escrowcreate-time.json" language="json" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
レスポンス:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="Websocket" %}
|
||||
{% code-snippet file="/_api-examples/escrow/websocket/submit-response-escrowcreate-time.json" language="json" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
|
||||
トランザクションの識別用`hash`値をメモしておきます。これにより、検証済みレジャーバージョンに記録されるときにその最終ステータスを確認できます。
|
||||
|
||||
## 3.検証の待機
|
||||
|
||||
{% partial file="/@l10n/ja/docs/_snippets/wait-for-validation.md" /%}
|
||||
|
||||
## 4.Escrowが作成されたことの確認
|
||||
|
||||
トランザクションの識別用ハッシュを指定した[txメソッド][]を使用して、トランザクションの最終ステータスを確認します。[Escrowレジャーオブジェクト](../../../../concepts/payment-types/escrow.md)が作成されたことを示す`CreatedNode`をトランザクションメタデータで探します。
|
||||
|
||||
リクエスト:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="Websocket" %}
|
||||
{% code-snippet file="/_api-examples/escrow/websocket/tx-request-escrowcreate-time.json" language="json" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
レスポンス:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="Websocket" %}
|
||||
{% code-snippet file="/_api-examples/escrow/websocket/tx-response-escrowcreate-time.json" language="json" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
## 5.リリース時刻までの待機
|
||||
|
||||
`FinishAfter`時刻が指定されている保留中の支払いは、Escrowノードの`FinishAfter`時刻よりも後の[`close_time`ヘッダーフィールド](../../../../references/protocol/ledger-data/ledger-header.md)の時刻でレジャーが閉鎖するまでは完了できません。
|
||||
|
||||
最新の検証済みレジャーの閉鎖時刻は、[ledgerメソッド][]を使用して検索できます。
|
||||
|
||||
リクエスト:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="Websocket" %}
|
||||
{% code-snippet file="/_api-examples/escrow/websocket/ledger-request.json" language="json" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
レスポンス:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="Websocket" %}
|
||||
{% code-snippet file="/_api-examples/escrow/websocket/ledger-response.json" language="json" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
|
||||
## 6.EscrowFinishトランザクションの送信
|
||||
|
||||
`FinishAfter`の時刻が経過した後で資金のリリースを実行する[EscrowFinishトランザクション][]に[署名して送信](../../../../concepts/transactions/index.md#トランザクションへの署名とトランザクションの送信)します。トランザクションの`Owner`フィールドにEscrowCreateトランザクションの`Account`アドレスを設定し、`OfferSequence` にEscrowCreateトランザクションの`Sequence`番号を設定します。時刻のみに基づいて保留されているEscrowの場合は、`Condition`フィールドと`Fulfillment`フィールドを省略します。
|
||||
|
||||
{% admonition type="success" name="ヒント" %}XRP Ledgerの状態はトランザクションでしか変更できないため、EscrowFinishトランザクションが必要です。このトランザクションの送信者は、Escrowの受取人、Escrowの元としての送金人、またはその他のXRP Ledgerアドレスのいずれかです。{% /admonition %}
|
||||
|
||||
Escrowが有効期限切れの場合は、[Escrowの取消し](cancel-an-expired-escrow.md)だけが可能です。
|
||||
|
||||
{% partial file="/@l10n/ja/docs/_snippets/secret-key-warning.md" /%}
|
||||
|
||||
リクエスト:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="Websocket" %}
|
||||
{% code-snippet file="/_api-examples/escrow/websocket/submit-request-escrowfinish-time.json" language="json" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
レスポンス:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="Websocket" %}
|
||||
{% code-snippet file="/_api-examples/escrow/websocket/submit-response-escrowfinish-time.json" language="json" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
トランザクションの識別用`hash`値をメモしておきます。これにより、検証済みレジャーバージョンに記録されるときにその最終ステータスを確認できます。
|
||||
|
||||
## 7.検証の待機
|
||||
|
||||
{% partial file="/@l10n/ja/docs/_snippets/wait-for-validation.md" /%}
|
||||
|
||||
## 8.最終結果の確認
|
||||
|
||||
EscrowFinishトランザクションの識別用ハッシュを指定した[txメソッド][]を使用して、トランザクションの最終ステータスを確認します。特にトランザクションメタデータ内で、エスクローに預託された支払いの送金先の`ModifiedNode`(タイプが`AccountRoot`)を確認します。オブジェクトの`FinalFields`に、`Balance`フィールドのXRP返金額の増分が表示されている必要があります。
|
||||
|
||||
リクエスト:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="Websocket" %}
|
||||
{% code-snippet file="/_api-examples/escrow/websocket/tx-request-escrowfinish-time.json" language="json" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
レスポンス:
|
||||
|
||||
{% tabs %}
|
||||
|
||||
{% tab label="Websocket" %}
|
||||
{% code-snippet file="/_api-examples/escrow/websocket/tx-response-escrowfinish-time.json" language="json" /%}
|
||||
{% /tab %}
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
{% raw-partial file="/@l10n/ja/docs/_snippets/common-links.md" /%}
|
||||
@@ -26,7 +26,7 @@ XRP Ledgerの分散型取引所(DEX)には、「アルゴリズムトレード
|
||||
|
||||
裁定取引を行うには、XRP Ledgerの内部と関連する部分の両方で、多くの方法があります。以下の例は潜在的な戦略を説明するためのものですが、他の方法も可能です。
|
||||
|
||||
**循環支払い**を利用して、マルチアセットトレードを完了し利益を得ることができます。XRP Ledgerは、XRPが真ん中のアセットである3つのアセットセットセットと同様に、アセットペア間の重複した取引を自動的に接続します。しかし、XRP Ledgerのプロトコルは、他のより長い、あるいはより複雑な経路のトレードを自動的に見つけて競うことはしません。(可能な限り最善の経路を見つけることは、計算集約型な問題のカテゴリとして知られています。)したがって、XRP Ledgerが独自の経路を見つける場合、XRP Ledgerのプロトコルは自動的に他の、より長い、あるいはより複雑な経路の取引を見つけ、競争させることはありません。したがって、自分で経路探索(PathFinding)を行えば、このような有益な裁定取引の機会を見つけることが可能です。その場合は、[Paymentトランザクション](../../references/protocol/transactions/types/payment.md)でそれらの[経路(Paths)](../../concepts/tokens/fungible-tokens/paths.md)を明示的に指定できます。1つのFOOを使って2つのBARを買い、その2つのBARを使って3つのTSTを買い、最後に3つのTSTを使って1.1 FOOを買えば、0.1 FOOから取引に関わるトークンの[送金手数料](../../concepts/tokens/fungible-tokens/transfer-fees.md)などのコストを差し引いた利益を得ることができます。
|
||||
**循環支払い**を利用して、マルチアセットトレードを完了し利益を得ることができます。XRP Ledgerは、XRPが真ん中のアセットである3つのアセットセットと同様に、アセットペア間の重複した取引を自動的に接続します。しかし、XRP Ledgerのプロトコルは、他のより長い、あるいはより複雑な経路のトレードを自動的に見つけて競うことはしません。(可能な限り最善の経路を見つけることは、計算集約型な問題のカテゴリとして知られています。)したがって、自分で経路探索(PathFinding)を行えば、このような有益な裁定取引の機会を見つけることが可能です。その場合は、[Paymentトランザクション](../../references/protocol/transactions/types/payment.md)でそれらの[経路(Paths)](../../concepts/tokens/fungible-tokens/paths.md)を明示的に指定できます。1つのFOOを使って2つのBARを買い、その2つのBARを使って3つのTSTを買い、最後に3つのTSTを使って1.1 FOOを買えば、0.1 FOOから取引に関わるトークンの[送金手数料](../../concepts/tokens/fungible-tokens/transfer-fees.md)などのコストを差し引いた利益を得ることができます。
|
||||
|
||||
資産の価格が異なる複数の取引所(CEX)に口座を持っている場合、**取引所間の裁定取引**を行うことができます。例えば、ACME取引所でXRPを1XRPあたり0.45ドルで購入し、そのXRPをWayGate取引所に移動して1XRPあたり0.50ドルで売却した場合、XRPあたり0.05ドルの利益を得ることができます。より複雑な例として、ACME取引所でBTC:ETHの価格が変動し、BTCに対してETHが安くなった場合、ある取引所でETH→XRPを売却し、そのXRPをACME取引所に移動し、XRP→BTC→ETHを取引して利益を得ることで、この価格変動を利用できる可能性があります。XRP Ledgerの取引は数秒で決済されますが、イーサリアムの取引は数分、ビットコインの取引は数時間かかることがあるため、XRPをブリッジ通貨として使用することで、ACME取引所でETH→BTC→BTC→ETHと取引するよりも早くこの機会を利用できる可能性があります。(これはもちろん、XRPへの交換が利益以上のコストにならないだけの十分な流動性と狭いスプレッドがある場合にのみ機能します)
|
||||
|
||||
@@ -48,7 +48,7 @@ XRP Ledgerの分散型取引所(DEX)には、「アルゴリズムトレード
|
||||
|
||||
## テストとよくある間違い
|
||||
|
||||
どのような取引でもそうですが、アルゴリズムトレー ドは確実に儲かる方法ではありません。手作業によるトレードと比べると、アルゴリズムトレードはエラーの余地が非常に少なくなります。小さなミスを犯しても、そのミスを大量のトレードで倍増させようとすれば、問題を修正する前に損失があっという間に膨らんでしまいます。したがって、自分のトレード戦略が実際に利益を上げるかどうかを確認するために、さまざまなテストを行うのが賢明です。戦略やその実際の実装(よく _ボット_ と呼ばれます)をテストするために、次のようなことを行うことができます。
|
||||
どのような取引でもそうですが、アルゴリズムトレードは確実に儲かる方法ではありません。手作業によるトレードと比べると、アルゴリズムトレードはエラーの余地が非常に少なくなります。小さなミスを犯しても、そのミスを大量のトレードで倍増させようとすれば、問題を修正する前に損失があっという間に膨らんでしまいます。したがって、自分のトレード戦略が実際に利益を上げるかどうかを確認するために、さまざまなテストを行うのが賢明です。戦略やその実際の実装(よく _ボット_ と呼ばれます)をテストするために、次のようなことを行うことができます。
|
||||
|
||||
- 現在のレジャーの状態または過去のトレードに基づいて、潜在的な利益を手動で計算します。
|
||||
- 過去のデータを記録してボットに送り、ボットがどのようなアクションを取ったかを記録し、実際の過去の値動きと結果を比較します。
|
||||
@@ -61,7 +61,7 @@ XRP Ledgerの分散型取引所(DEX)には、「アルゴリズムトレード
|
||||
- 通常、四捨五入の違いや、計算時と約定時の値動きの違いを考慮し、金額を調整する必要があります。この金額は「スリッページ」と呼ばれ、適切な金額を設定することが重要です。スリッページが低すぎると、トレードがまったく約定しない可能性があります。一方、スリッページが高すぎると、フロントランニングの影響を受けやすくなり、スリッページが高ければ高いほど、値動きによって利益が削られる可能性が高くなります。
|
||||
- **余分なコストと遅延を考慮しないこと**: 例えば、2つのステーブルコインの裏付けが米ドルであるにもかかわらず、ある発行者が0.5%の送金手数料を請求し、別の発行者が0.25%の[送金手数料](../../concepts/tokens/fungible-tokens/transfer-fees.md)を請求した場合、そのステーブルコインの取引価格には約0.25%の差が生じます。トランザクションを送信するためのコストは、通常は少額ですが、その他の潜在的な遅延の影響も忘れないでください。例えば、オフレジャーの取引所が現時点で有利な価格を示していたとしても、その取引所の入金処理に数時間から数日かかる場合、その取引所で事前に流動性を持っていない限り、その価格を利用することはできません。
|
||||
- **稀な事象を考慮していないこと**: 前例のない出来事(「ブラック・スワン」)はさておき、個々の異常値によって計算結果がゆがむことがあります。一例として(これは実話ですが)、あるトレーダーが、ある戦略の潜在的な利益を特定の時間帯で計算したところ、利益の80%以上が、他のユーザが誤って価格にゼロを追加してしまった1つの「入力ミス」の取引によるものであったと報じました。同じ戦略を、これらの異常値の取引を含まない時間範囲に対して計算すると、利益ははるかに少なくなりました。
|
||||
- **トランザクションのフラグを確認しないこ**と: XRP Ledgerのトランザクションのフラグは、そのトランザクションの処理方法や、プロトコルがそれを「成功」とマークするタイミングに大きな影響を与える可能性があります。例えば、"Offer"トランザクションのフラグは、全額がすぐに得られる場合にのみトレードされる"Fill or Kill"注文にすることができます。"Payment"トランザクションのフラグは、意図した宛先に全額を届けることができなくても成功する[partial payments](../../concepts/payment-types/partial-payments.md)にすることができます。トランザクションの`Flags`フィールドを解析するためにビット演算をする必要がありますが、それをスキップしてしまうと、予想と結果が全く異なったものとなってしまう可能性があります。
|
||||
- **トランザクションのフラグを確認しないこと**: XRP Ledgerのトランザクションのフラグは、そのトランザクションの処理方法や、プロトコルがそれを「成功」とマークするタイミングに大きな影響を与える可能性があります。例えば、"Offer"トランザクションのフラグは、全額がすぐに得られる場合にのみトレードされる"Fill or Kill"注文にすることができます。"Payment"トランザクションのフラグは、意図した宛先に全額を届けることができなくても成功する[partial payments](../../concepts/payment-types/partial-payments.md)にすることができます。トランザクションの`Flags`フィールドを解析するためにビット演算をする必要がありますが、それをスキップしてしまうと、予想と結果が全く異なったものとなってしまう可能性があります。
|
||||
|
||||
## 税金とライセンス
|
||||
|
||||
@@ -72,7 +72,7 @@ XRP Ledgerの分散型取引所(DEX)には、「アルゴリズムトレード
|
||||
|
||||
### トレードの発注
|
||||
|
||||
XRP Ledgerの分散型取引所で _代替可能_ トークンとXRPを売買するには、通常[OfferCreateトランザクション](../../references/protocol/transactions/types/offercreate.md)を送信します。この方法でトレードを行うためのコードと技術的ステップの詳細なウォークスルーについては、[分散型取引所でのトレード](../../tutorials/how-tos/use-tokens/trade-in-the-decentralized-exchange.md)をご覧ください。[Paymentトランザクション](../../references/protocol/transactions/types/payment.md)を使用して通貨を両替することも可能です。[クロスカレンしー支払い](../../concepts/payment-types/cross-currency-payments.md)を他のユーザに送ったり、長い[パス](../../concepts/tokens/fungible-tokens/paths.md)を使って裁定取引の機会を1つの操作にまとめることで、自分自身に送り返すこともできます。
|
||||
XRP Ledgerの分散型取引所で _代替可能_ トークンとXRPを売買するには、通常[OfferCreateトランザクション](../../references/protocol/transactions/types/offercreate.md)を送信します。この方法でトレードを行うためのコードと技術的ステップの詳細なウォークスルーについては、[分散型取引所でのトレード](../../tutorials/how-tos/use-tokens/trade-in-the-decentralized-exchange.md)をご覧ください。[Paymentトランザクション](../../references/protocol/transactions/types/payment.md)を使用して通貨を両替することも可能です。[クロスカレンシー支払い](../../concepts/payment-types/cross-currency-payments.md)を他のユーザに送ったり、長い[パス](../../concepts/tokens/fungible-tokens/paths.md)を使って裁定取引の機会を1つの操作にまとめることで、自分自身に送り返すこともできます。
|
||||
|
||||
NFTをトレードするためのコードと技術的な手順については、[JavaScriptを使用したNFTokenの送信](../../tutorials/javascript/nfts/transfer-nfts.md)をご覧ください。
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ XRP Ledger上のスマートコントラクトは、条件付きで保有する
|
||||
|
||||
オラクルのプログラムが条件を満たしたことを検知した後、エスクローの受取人にfulfillmentの16進数値を渡します。この時点以降、オラクルはエスクローを終了させるなど、何も行いません。エスクローの受取人は、ほとんどの場合、エスクローを終了することになります。
|
||||
|
||||
[conditionとfulfillmentの生成](../../tutorials/how-tos/use-specialized-payment-types/use-escrows/send-a-conditionally-held-escrow.md#1-generate-condition-and-fulfillment)をご覧ください。
|
||||
[条件に基づくEscrowの送信](../../tutorials/how-tos/use-specialized-payment-types/use-escrows/send-a-conditional-escrow.md)をご覧ください。
|
||||
|
||||
## 例
|
||||
|
||||
|
||||
@@ -48,9 +48,9 @@ NFTをオークション形式で販売することができます。[NFTオー
|
||||
|
||||
### 準備金要件
|
||||
|
||||
販売用のNFTをミントする際には、XRPの準備金が必要となります。各NFTokenページには、2XRPの準備金が必要です。NFTokenページは16~32個のNFTを保管することができます。
|
||||
販売用のNFTをミントする際には、XRPの準備金が必要となります。各NFTokenページには、{% $env.PUBLIC_OWNER_RESERVE %}の準備金が必要です。NFTokenページは16~32個のNFTを保管することができます。
|
||||
|
||||
各`NFTokenOffer`オブジェクトは、2XRPの準備金が必要です。
|
||||
各`NFTokenOffer`オブジェクトは、{% $env.PUBLIC_OWNER_RESERVE %}の準備金が必要です。
|
||||
|
||||
`NFTokenOffer`を作成したり、NFTを売却したりする際には、些細な送金手数料(およそ6000ドロップ、または0.006 XRP)が発生します。大量に販売する場合、こうした少額の手数料はすぐにかさみますので、ビジネスのコストとして考慮する必要があります。
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ NFTokenのURLは、NFTのコンテンツが保存されている場所へのリ
|
||||
|
||||
[認可Minter](../../concepts/tokens/nfts/authorizing-another-minter.md)をご覧ください。
|
||||
|
||||
ミント済みのNFTは、`NFTokenPage`に記録されます。アカウント上の`NFTokenPage`1つにつき2XRPの準備金が必要です。[NFT準備金](../../concepts/tokens/nfts/reserve-requirements.md)をご覧ください。
|
||||
ミント済みのNFTは、`NFTokenPage`に記録されます。アカウント上の`NFTokenPage`1つにつき{% $env.PUBLIC_OWNER_RESERVE %}の準備金が必要です。[NFT準備金](../../concepts/tokens/nfts/reserve-requirements.md)をご覧ください。
|
||||
|
||||
各「NFTokenPage」は16~32個のNFTを保持します。大量のNFTをミントすると、あなたのXRPを大量に準備金としてロックすることになります。オンデマンドミント(または _遅延ミント_ )を行うことで、XRPを柔軟に維持することができます。[遅延ミント](../../concepts/tokens/nfts/batch-minting.md#mint-on-demand-lazy-minting)と[スクリプトミント](../../concepts/tokens/nfts/batch-minting.md#scripted-minting)をご覧下さい。
|
||||
|
||||
@@ -89,9 +89,9 @@ NFTをオークション形式で販売することができます。[NFTオー
|
||||
|
||||
#### 準備金要件
|
||||
|
||||
販売用のNFTをミントする際には、XRPの準備金が必要となります。各NFTokenページには、2XRPの準備金が必要です。NFTokenページは16~32個のNFTを保管することができます。
|
||||
販売用のNFTをミントする際には、XRPの準備金が必要となります。各NFTokenページには、{% $env.PUBLIC_OWNER_RESERVE %}の準備金が必要です。NFTokenページは16~32個のNFTを保管することができます。
|
||||
|
||||
各`NFTokenOffer`オブジェクトは、2XRPの準備金が必要です。
|
||||
各`NFTokenOffer`オブジェクトは、{% $env.PUBLIC_OWNER_RESERVE %}の準備金が必要です。
|
||||
|
||||
`NFTokenOffer`を作成したり、NFTを売却したりする際には、些細な送金手数料(およそ6000ドロップ、または0.006 XRP)が発生します。大量に販売する場合、こうした少額の手数料はすぐにかさみますので、ビジネスのコストとして考慮する必要があります。
|
||||
|
||||
|
||||
@@ -44,9 +44,9 @@ NFTをオークション形式で販売することができます。[NFTオー
|
||||
|
||||
### 準備金要件
|
||||
|
||||
販売用のNFTをミントする際には、XRPの準備金が必要となります。各NFTokenページには、2XRPの準備金が必要です。NFTokenページは16~32個のNFTを保管することができます。
|
||||
販売用のNFTをミントする際には、XRPの準備金が必要となります。各NFTokenページには、{% $env.PUBLIC_OWNER_RESERVE %}の準備金が必要です。NFTokenページは16~32個のNFTを保管することができます。
|
||||
|
||||
各`NFTokenOffer`オブジェクトは、2XRPの準備金が必要です。
|
||||
各`NFTokenOffer`オブジェクトは、{% $env.PUBLIC_OWNER_RESERVE %}の準備金が必要です。
|
||||
|
||||
`NFTokenOffer`を作成したり、NFTを売却したりする際には、些細な送金手数料(およそ6000ドロップ、または0.006 XRP)が発生します。大量に販売する場合、こうした少額の手数料はすぐにかさみますので、ビジネスのコストとして考慮する必要があります。
|
||||
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
---
|
||||
html: tutorial-structure.html
|
||||
parent: contribute-documentation.html
|
||||
seo:
|
||||
description: 一般的なチュートリアルの構成要素の要約です。
|
||||
---
|
||||
# チュートリアルの構成
|
||||
|
||||
各XRP Ledgerチュートリアルは、同一のフォーマットで構成されています。
|
||||
|
||||
1. チュートリアルで説明する機能の簡単な説明。
|
||||
2. コードを実行するための前提条件(必要な場合)、またはサンプルコードへのリンク。
|
||||
3. チュートリアルの機能の使用例。
|
||||
4. サンプルコードの解説と、そのスクリプトの特徴的な要素の紹介。
|
||||
5. 次のステップとして試すべき概念的な情報や優れたチュートリアルへのリンク。
|
||||
|
||||
セットアップ(前提条件)と使用方法とコード開発は分けて考えましょう。これらはそれぞれ異なる活動であり、それぞれ脳の異なる領域を動かします。この3つの要素を一度に考えようとすると、混乱につながります。
|
||||
|
||||
## 説明
|
||||
|
||||

|
||||
|
||||
そのサンプルが何を示しているかを記載してください。可能であれば、各サンプルには関連する特定のタスクを達成するための手順を記述してください。(NFTの売却オファーの作成、売却オファーの受け入れ、売却オファーの削除など)。チュートリアルで説明されている内容を理解するのに十分なコンセプトに関する情報を記載し、必要であれば、追加情報へのリンクも記載します。
|
||||
|
||||
## 前提条件
|
||||
|
||||

|
||||
|
||||
必要なソフトウェアと、チュートリアルを実行するために必要なすべてのサンプルコードへのリンクを提供します。必要であれば、サードパーティのツールの使い方を簡単に説明しますが、ユーザが自由に深く掘り下げることができるように、ソースとなるウェブサイトへのリンクを提供します。
|
||||
|
||||
## 使用例
|
||||
|
||||

|
||||
|
||||
チュートリアルのアプリケーションの完成した動作例を提供することから始めましょう。これは、ソフトウェアを使って問題を解決するチャンスです。
|
||||
|
||||
チュートリアルの各ステップにはスクリーンショットを使用してください。これによって、ユーザは自分でコードを実行しなくてもチュートリアルを理解することができます。もちろん、コードを実行することが _望ましい_ ですが、これにりユーザに選択肢を与えることができます。
|
||||
|
||||
適切な条件におけるシナリオを記述してください。インターネットへの接続が途切れなければ、アプリケーションは問題なく動作するはずです。チュートリアルに関連しないトラブルシューティングの情報を提供しないでください。
|
||||
|
||||
## コード解説
|
||||
|
||||

|
||||
|
||||
コードを1ブロックずつ見ていきましょう。既に説明したトピックを繰り返さないでください。サンプルコードには、HTML構文のような基本的な部分のプログラミング方法については、その実装に独自なものがない限り、詳細な説明はしないでください。
|
||||
|
||||
強調すべき重要なことは、XRPLとのやりとりはすべてトランザクションかリクエストであり、すべてのトランザクションとリクエストは本質的に同じであるということです。私たちが提供するサンプルコードは、トランザクションやリクエストを準備する方法と、返された結果を処理する方法を示しています。1つのトランザクションやリクエストをどのように送信しどのようなレスポンスを返すかを知ることは、他のトランザクションやリクエストの処理について非常に良いヒントとなります。
|
||||
|
||||
(技術的には、リクエストに似た第3のカテゴリがあります。[Subscriptionメソッド](../../docs/references/http-websocket-apis/public-api-methods/subscription-methods/index.md)をご覧ください)。
|
||||
|
||||
## 関連項目
|
||||
|
||||

|
||||
|
||||
チュートリアルの最後には、追加の資料、概念的な情報、学習のにおいて有益な次のステップとなるチュートリアルへのリンクを提供します。
|
||||
@@ -6,7 +6,7 @@ metadata:
|
||||
---
|
||||
# リソース
|
||||
|
||||
XRP Ledgerの理解や開発ためのリソース。Other resources to help understand the XRPL and develop on it.
|
||||
XRP Ledgerの理解や開発ためのリソース。
|
||||
|
||||
|
||||
{% child-pages /%}
|
||||
|
||||
@@ -155,6 +155,8 @@ amendment.table.status: ステータス
|
||||
amendment.status.enabled: 有効
|
||||
amendment.status.eta: 予定
|
||||
amendment.status.openForVoting: 投票中
|
||||
amendment.status.inactive: 無効
|
||||
amendment.status.inactiveButton: 詳細を取得する
|
||||
|
||||
# index.page.tsx
|
||||
home.hero.h1part1: ビジネスのための
|
||||
|
||||
@@ -23,6 +23,7 @@ type AmendmentsCachePayload = {
|
||||
|
||||
// API data caching
|
||||
const amendmentsEndpoint = 'https://vhs.prod.ripplex.io/v1/network/amendments/vote/main/'
|
||||
const amendmentsInfoEndpoint = 'https://vhs.prod.ripplex.io/v1/network/amendments/info/main/'
|
||||
const amendmentsCacheKey = 'xrpl.amendments.mainnet.cache'
|
||||
const amendmentsTTL = 15 * 60 * 1000 // 15 minutes in milliseconds
|
||||
|
||||
@@ -180,6 +181,8 @@ function AmendmentBadge(props: { amendment: Amendment }) {
|
||||
const enabledLabel = translate("amendment.status.enabled", "Enabled")
|
||||
const votingLabel = translate("amendment.status.openForVoting", "Open for Voting")
|
||||
const etaLabel = translate("amendment.status.eta", "Expected")
|
||||
const inactiveLabel = translate("amendment.status.inactive", "Inactive")
|
||||
const inactiveButton = translate("amendment.status.inactiveButton", "Get details")
|
||||
|
||||
React.useEffect(() => {
|
||||
const amendment = props.amendment
|
||||
@@ -202,10 +205,16 @@ function AmendmentBadge(props: { amendment: Amendment }) {
|
||||
else if (amendment.consensus) {
|
||||
setStatus(`${votingLabel}: ${amendment.consensus}`)
|
||||
setColor('80d0e0')
|
||||
setHref(undefined) // No link for voting amendments
|
||||
setHref(undefined)
|
||||
}
|
||||
}, [props.amendment, enabledLabel, etaLabel, votingLabel])
|
||||
|
||||
// Fallback: amendment is inactive
|
||||
else {
|
||||
setStatus(`${inactiveLabel}: ${inactiveButton}`)
|
||||
setColor('lightgrey')
|
||||
setHref(`/resources/known-amendments#${amendment.name.toLowerCase()}`)
|
||||
}
|
||||
}, [props.amendment, enabledLabel, etaLabel, votingLabel, inactiveLabel])
|
||||
|
||||
// Split the status at the colon to create two-color badge
|
||||
const parts = status.split(':')
|
||||
const label = shieldsIoEscape(parts[0])
|
||||
@@ -257,15 +266,32 @@ export function AmendmentDisclaimer(props: {
|
||||
const response = await fetch(amendmentsEndpoint)
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`)
|
||||
throw new Error(`HTTP error! Status: ${response.status}`)
|
||||
}
|
||||
|
||||
const data: AmendmentsResponse = await response.json()
|
||||
writeAmendmentsCache(data.amendments)
|
||||
|
||||
const found = data.amendments.find(a => a.name === props.name)
|
||||
|
||||
// 3. If not found in live data, try the info endpoint.
|
||||
if (!found) {
|
||||
throw new Error(`Couldn't find ${props.name} amendment in status table.`)
|
||||
|
||||
const infoResponse = await fetch(amendmentsInfoEndpoint)
|
||||
|
||||
if (!infoResponse.ok) {
|
||||
throw new Error(`HTTP error from info endpoint! Status: ${infoResponse.status}`)
|
||||
}
|
||||
|
||||
const infoData: AmendmentsResponse = await infoResponse.json()
|
||||
const foundInInfo = infoData.amendments.find(a => a.name === props.name)
|
||||
|
||||
if (!foundInInfo) {
|
||||
throw new Error(`Couldn't find ${props.name} amendment in status tables.`)
|
||||
}
|
||||
|
||||
setStatus(foundInInfo)
|
||||
return
|
||||
}
|
||||
|
||||
setStatus(found)
|
||||
@@ -389,6 +415,8 @@ export function Badge(props: {
|
||||
"更新": "blue", // ja: updated in
|
||||
"in development": "lightgrey",
|
||||
"開発中": "lightgrey", // ja: in development
|
||||
"inactive": "lightgrey",
|
||||
"無効": "lightgrey" // ja: inactive
|
||||
}
|
||||
|
||||
let childstrings = ""
|
||||
|
||||
@@ -222,7 +222,7 @@ export function NavDropdown(props) {
|
||||
//conditional specific for brand kit
|
||||
if (item2.link === "/XRPL_Brand_Kit.zip") {
|
||||
return (
|
||||
<a key={index2} href="/XRPL_Brand_Kit.zip" className={cls2}>
|
||||
<a target="_blank" key={index2} href="/XRPL_Brand_Kit.zip" className={cls2}>
|
||||
{translate(item2.labelTranslationKey, item2.label)}
|
||||
</a>
|
||||
);
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"id": 2,
|
||||
"command": "account_objects",
|
||||
"account": "r3wN3v2vTUkr5qd6daqDc2xE4LSysdVjkT",
|
||||
"ledger_index": "validated",
|
||||
"type": "escrow"
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"id": 5,
|
||||
"command": "account_objects",
|
||||
"account": "rfztBskAVszuS3s5Kq7zDS74QtHrw893fm",
|
||||
"ledger_index": "validated",
|
||||
"type": "escrow"
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
{
|
||||
"id": 2,
|
||||
"status": "success",
|
||||
"type": "response",
|
||||
"result": {
|
||||
"account": "r3wN3v2vTUkr5qd6daqDc2xE4LSysdVjkT",
|
||||
"account_objects": [
|
||||
{
|
||||
"Account": "r3wN3v2vTUkr5qd6daqDc2xE4LSysdVjkT",
|
||||
"Amount": "10000",
|
||||
"CancelAfter": 559913895,
|
||||
"Destination": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"FinishAfter": 559892324,
|
||||
"Flags": 0,
|
||||
"LedgerEntryType": "Escrow",
|
||||
"OwnerNode": "0000000000000000",
|
||||
"PreviousTxnID": "4756C22BBB7FC23D9081FDB180806939D6FEBC967BE0EC2DB95B166AF9C086E9",
|
||||
"PreviousTxnLgrSeq": 2764813,
|
||||
"index": "7243A9750FA4BE3E63F75F6DACFD79AD6B6C76947F6BDC46CD0F52DBEEF64C89"
|
||||
}
|
||||
],
|
||||
"ledger_hash": "82F24FFA72AED16F467BBE79D387E92FDA39F29038B26E79464CDEDFB506E366",
|
||||
"ledger_index": 2764826,
|
||||
"validated": true
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
{
|
||||
"id": 5,
|
||||
"result": {
|
||||
"account": "rfztBskAVszuS3s5Kq7zDS74QtHrw893fm",
|
||||
"account_objects": [{
|
||||
"Account": "rafD3taonqdnVpaxCCT6sjnScZUeFGf1JG",
|
||||
"Amount": "250",
|
||||
"Destination": "rfztBskAVszuS3s5Kq7zDS74QtHrw893fm",
|
||||
"DestinationNode": "0000000000000000",
|
||||
"FinishAfter": 570672000,
|
||||
"Flags": 0,
|
||||
"LedgerEntryType": "Escrow",
|
||||
"OwnerNode": "0000000000000000",
|
||||
"PreviousTxnID": "A0951691DF3BCBEEB3108F2229A702D078BBBF848268BC601E59B68A2E390AAC",
|
||||
"PreviousTxnLgrSeq": 4602906,
|
||||
"index": "2BF3226ACCA8FF7ACB7201F20A701F51D8666A2FA2FBFBE6A05C9161F9228A18"
|
||||
}, {
|
||||
"Account": "rfztBskAVszuS3s5Kq7zDS74QtHrw893fm",
|
||||
"Amount": "250",
|
||||
"Destination": "r9gyNNzhMtfwZara61u3ycfMLdkTpKJZHX",
|
||||
"DestinationNode": "0000000000000000",
|
||||
"FinishAfter": 570672000,
|
||||
"Flags": 0,
|
||||
"LedgerEntryType": "Escrow",
|
||||
"OwnerNode": "0000000000000000",
|
||||
"PreviousTxnID": "463D5A3CF09F4890B8471027F80414B3B438E6907425B71DC324D7118E90A107",
|
||||
"PreviousTxnLgrSeq": 4603003,
|
||||
"index": "35462CDC28AD830B29D101E8307AF5B6BFBC262F1BDCCA7EB45D1CA3F8B44F53"
|
||||
}, {
|
||||
"Account": "r9gyNNzhMtfwZara61u3ycfMLdkTpKJZHX",
|
||||
"Amount": "250",
|
||||
"Destination": "rfztBskAVszuS3s5Kq7zDS74QtHrw893fm",
|
||||
"DestinationNode": "0000000000000000",
|
||||
"FinishAfter": 570672000,
|
||||
"Flags": 0,
|
||||
"LedgerEntryType": "Escrow",
|
||||
"OwnerNode": "0000000000000000",
|
||||
"PreviousTxnID": "08C9B20AC9EB191238038A108CC4CBBC0243672484B466FB42DED0A7DF6A31A1",
|
||||
"PreviousTxnLgrSeq": 4602954,
|
||||
"index": "A7B0983A1B53D92278E21499064A4F8BBE08CB8D14DB6BBBA8F688AB1D3FDA45"
|
||||
}, {
|
||||
"Account": "rfztBskAVszuS3s5Kq7zDS74QtHrw893fm",
|
||||
"Amount": "250",
|
||||
"Destination": "rafD3taonqdnVpaxCCT6sjnScZUeFGf1JG",
|
||||
"DestinationNode": "0000000000000000",
|
||||
"FinishAfter": 570672000,
|
||||
"Flags": 0,
|
||||
"LedgerEntryType": "Escrow",
|
||||
"OwnerNode": "0000000000000000",
|
||||
"PreviousTxnID": "F4778F528AB3CB945BDB88036EF9FE6C0E899F1629D9E51129E3B93CD488395A",
|
||||
"PreviousTxnLgrSeq": 4602977,
|
||||
"index": "F99A4DDADDDF623908C9A048170AB107AFF78684AB8F3110E9F00BBBC606ABD2"
|
||||
}],
|
||||
"ledger_hash": "1D4850035F175CA6F1CD5CE3B53C01AA83E4F086C13085E4FBC1EEFCCB345A9B",
|
||||
"ledger_index": 4603176,
|
||||
"validated": true
|
||||
},
|
||||
"status": "success",
|
||||
"type": "response"
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"id": 4,
|
||||
"command": "ledger",
|
||||
"ledger_index": "validated"
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"id": 4,
|
||||
"command": "ledger",
|
||||
"ledger_index": "validated"
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"id": 1,
|
||||
"status": "success",
|
||||
"type": "response",
|
||||
"result": {
|
||||
"ledger": {
|
||||
# ... (trimmed) ...
|
||||
|
||||
"close_time": 560302643,
|
||||
"close_time_human": "2017-Oct-02 23:37:23",
|
||||
"close_time_resolution": 10,
|
||||
|
||||
# ... (trimmed) ...
|
||||
},
|
||||
"ledger_hash": "668F0647A6F3CC277496245DBBE9BD2E3B8E70E7AA824E97EF3237FE7E1EE3F2",
|
||||
"ledger_index": 2906341,
|
||||
"validated": true
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
{
|
||||
"id": 4,
|
||||
"status": "success",
|
||||
"type": "response",
|
||||
"result": {
|
||||
"ledger": {
|
||||
"accepted": true,
|
||||
"account_hash": "3B5A8FF5334F94F4D3D09F236F9D1B4C028FCAE30948ACC986D461DDEE1D886B",
|
||||
"close_flags": 0,
|
||||
"close_time": 557256670,
|
||||
"close_time_human": "2017-Aug-28 17:31:10",
|
||||
"close_time_resolution": 10,
|
||||
"closed": true,
|
||||
"hash": "A999223A80174A7CB39D766B625C9E476F24AD2F15860A712CD029EE5ED1C320",
|
||||
"ledger_hash": "A999223A80174A7CB39D766B625C9E476F24AD2F15860A712CD029EE5ED1C320",
|
||||
"ledger_index": "1908253",
|
||||
"parent_close_time": 557256663,
|
||||
"parent_hash": "6A70C5336ACFDA05760D827776079F7A544D2361CFD5B21BD55A92AA20477A61",
|
||||
"seqNum": "1908253",
|
||||
"totalCoins": "99997280690562728",
|
||||
"total_coins": "99997280690562728",
|
||||
"transaction_hash": "49A51DFB1CAB2F134D93D5D1C5FF55A15B12DA36DAF9F5862B17C47EE966647D"
|
||||
},
|
||||
"ledger_hash": "A999223A80174A7CB39D766B625C9E476F24AD2F15860A712CD029EE5ED1C320",
|
||||
"ledger_index": 1908253,
|
||||
"validated": true
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"id": 5,
|
||||
"command": "submit",
|
||||
"secret": "s████████████████████████████",
|
||||
"tx_json": {
|
||||
"Account": "rhgdnc82FwHFUKXp9ZcpgwXWRAxKf5Buqp",
|
||||
"TransactionType": "EscrowCancel",
|
||||
"Owner": "r3wN3v2vTUkr5qd6daqDc2xE4LSysdVjkT",
|
||||
"OfferSequence": 1
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"id": 1,
|
||||
"command": "submit",
|
||||
"secret": "s████████████████████████████",
|
||||
"tx_json": {
|
||||
"Account": "rEhw9vD98ZrkY4tZPvkZst5H18RysqFdaB",
|
||||
"TransactionType": "EscrowCreate",
|
||||
"Amount": "100000",
|
||||
"Destination": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"Condition": "A0258020E24D9E1473D4DF774F6D8E089067282034E4FA7ECACA2AD2E547953B2C113CBD810120",
|
||||
"CancelAfter": 556927412
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"id": 2,
|
||||
"command": "submit",
|
||||
"secret": "s████████████████████████████",
|
||||
"tx_json": {
|
||||
"Account": "rajgkBmMxmz161r8bWYH7CQAFZP5bA9oSG",
|
||||
"TransactionType": "EscrowCreate",
|
||||
"Amount": "10000",
|
||||
"Destination": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"FinishAfter": 557020800
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"id": 4,
|
||||
"command": "submit",
|
||||
"secret": "s████████████████████████████",
|
||||
"tx_json": {
|
||||
"Account": "rEhw9vD98ZrkY4tZPvkZst5H18RysqFdaB",
|
||||
"TransactionType": "EscrowFinish",
|
||||
"Owner": "rEhw9vD98ZrkY4tZPvkZst5H18RysqFdaB",
|
||||
"OfferSequence": 5,
|
||||
"Condition": "A0258020E24D9E1473D4DF774F6D8E089067282034E4FA7ECACA2AD2E547953B2C113CBD810120",
|
||||
"Fulfillment": "A0228020D280D1A02BAD0D2EBC0528B92E9BF37AC3E2530832C2C52620307135156F1048",
|
||||
"Fee": "500"
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"id": 5,
|
||||
"command": "submit",
|
||||
"secret": "s████████████████████████████",
|
||||
"tx_json": {
|
||||
"Account": "rajgkBmMxmz161r8bWYH7CQAFZP5bA9oSG",
|
||||
"TransactionType": "EscrowFinish",
|
||||
"Owner": "rajgkBmMxmz161r8bWYH7CQAFZP5bA9oSG",
|
||||
"OfferSequence": 1
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"id": 5,
|
||||
"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": "1200042280000000240000000320190000000168400000000000000A7321027FB1CF34395F18901CD294F77752EEE25277C6E87A224FC7388AA7EF872DB43D74473045022100AC45749FC4291F7811B2D8AC01CA04FEE38910CB7216FB0C5C0AEBC9C0A95F4302203F213C71C00136A0ADC670EFE350874BCB2E559AC02059CEEDFB846685948F2B81142866B7B47574C8A70D5E71FFB95FFDB18951427B82144E87970CD3EA984CF48B1AA6AB6C77DC4AB059FC",
|
||||
"tx_json": {
|
||||
"Account": "rhgdnc82FwHFUKXp9ZcpgwXWRAxKf5Buqp",
|
||||
"Fee": "10",
|
||||
"Flags": 2147483648,
|
||||
"OfferSequence": 1,
|
||||
"Owner": "r3wN3v2vTUkr5qd6daqDc2xE4LSysdVjkT",
|
||||
"Sequence": 3,
|
||||
"SigningPubKey": "027FB1CF34395F18901CD294F77752EEE25277C6E87A224FC7388AA7EF872DB43D",
|
||||
"TransactionType": "EscrowCancel",
|
||||
"TxnSignature": "3045022100AC45749FC4291F7811B2D8AC01CA04FEE38910CB7216FB0C5C0AEBC9C0A95F4302203F213C71C00136A0ADC670EFE350874BCB2E559AC02059CEEDFB846685948F2B",
|
||||
"hash": "65F36C5514153D94F0ADE5CE747061A5E70B73B56B4C66DA5040D99CAF252831"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"id": 2,
|
||||
"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": "1200012280000000240000000120252133768061400000000000271068400000000000000A732103C3555B7339FFDDB43495A8371A3A87B4C66B67D49D06CB9BA1FDBFEEB57B6E437446304402203C9AA4C21E1A1A7427D41583283E7A513DDBDD967B246CADD3B2705D858A7A8E02201BEA7B923B18910EEB9F306F6DE3B3F53549BBFAD46335B62B4C34A6DCB4A47681143EEB46C355B04EE8D08E8EED00F422895C79EA6A83144B4E9C06F24296074F7BC48F92A97916C6DC5EA9",
|
||||
"tx_json": {
|
||||
"Account": "rajgkBmMxmz161r8bWYH7CQAFZP5bA9oSG",
|
||||
"Amount": "10000",
|
||||
"Destination": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"Fee": "10",
|
||||
"FinishAfter": 557020800,
|
||||
"Flags": 2147483648,
|
||||
"Sequence": 1,
|
||||
"SigningPubKey": "03C3555B7339FFDDB43495A8371A3A87B4C66B67D49D06CB9BA1FDBFEEB57B6E43",
|
||||
"TransactionType": "EscrowCreate",
|
||||
"TxnSignature": "304402203C9AA4C21E1A1A7427D41583283E7A513DDBDD967B246CADD3B2705D858A7A8E02201BEA7B923B18910EEB9F306F6DE3B3F53549BBFAD46335B62B4C34A6DCB4A476",
|
||||
"hash": "55B2057332F8999208C43BA1E7091B423A16E5ED2736C06300B4076085205263"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"id": 5,
|
||||
"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": "1200022280000000240000000220190000000168400000000000000A732103C3555B7339FFDDB43495A8371A3A87B4C66B67D49D06CB9BA1FDBFEEB57B6E4374473045022100923B91BA4FD6450813F5335D71C64BA9EB81304A86859A631F2AD8571424A46502200CCE660D36781B84634C5F23619EB6CFCCF942709F54DCCF27CF6F499AE78C9B81143EEB46C355B04EE8D08E8EED00F422895C79EA6A82143EEB46C355B04EE8D08E8EED00F422895C79EA6A",
|
||||
"tx_json": {
|
||||
"Account": "rajgkBmMxmz161r8bWYH7CQAFZP5bA9oSG",
|
||||
"Fee": "10",
|
||||
"Flags": 2147483648,
|
||||
"OfferSequence": 1,
|
||||
"Owner": "rajgkBmMxmz161r8bWYH7CQAFZP5bA9oSG",
|
||||
"Sequence": 2,
|
||||
"SigningPubKey": "03C3555B7339FFDDB43495A8371A3A87B4C66B67D49D06CB9BA1FDBFEEB57B6E43",
|
||||
"TransactionType": "EscrowFinish",
|
||||
"TxnSignature": "3045022100923B91BA4FD6450813F5335D71C64BA9EB81304A86859A631F2AD8571424A46502200CCE660D36781B84634C5F23619EB6CFCCF942709F54DCCF27CF6F499AE78C9B",
|
||||
"hash": "41856A742B3CAF307E7B4D0B850F302101F0F415B785454F7501E9960A2A1F6B"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"id": 6,
|
||||
"command": "tx",
|
||||
"transaction": "65F36C5514153D94F0ADE5CE747061A5E70B73B56B4C66DA5040D99CAF252831"
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"id": 3,
|
||||
"command": "tx",
|
||||
"transaction": "E22D1F6EB006CAD35E0DBD3B4F3748427055E4C143EBE95AA6603823AEEAD324"
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"id": 3,
|
||||
"command": "tx",
|
||||
"transaction": "55B2057332F8999208C43BA1E7091B423A16E5ED2736C06300B4076085205263"
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"id": 20,
|
||||
"command": "tx",
|
||||
"transaction": "0E88368CAFC69A722ED829FAE6E2DD3575AE9C192691E60B5ACDF706E219B2BF"
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"id": 21,
|
||||
"command": "tx",
|
||||
"transaction": "41856A742B3CAF307E7B4D0B850F302101F0F415B785454F7501E9960A2A1F6B"
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
{
|
||||
"id": 6,
|
||||
"status": "success",
|
||||
"type": "response",
|
||||
"result": {
|
||||
"Account": "rhgdnc82FwHFUKXp9ZcpgwXWRAxKf5Buqp",
|
||||
"Fee": "10",
|
||||
"Flags": 2147483648,
|
||||
"OfferSequence": 1,
|
||||
"Owner": "r3wN3v2vTUkr5qd6daqDc2xE4LSysdVjkT",
|
||||
"Sequence": 3,
|
||||
"SigningPubKey": "027FB1CF34395F18901CD294F77752EEE25277C6E87A224FC7388AA7EF872DB43D",
|
||||
"TransactionType": "EscrowCancel",
|
||||
"TxnSignature": "3045022100AC45749FC4291F7811B2D8AC01CA04FEE38910CB7216FB0C5C0AEBC9C0A95F4302203F213C71C00136A0ADC670EFE350874BCB2E559AC02059CEEDFB846685948F2B",
|
||||
"date": 560302841,
|
||||
"hash": "65F36C5514153D94F0ADE5CE747061A5E70B73B56B4C66DA5040D99CAF252831",
|
||||
"inLedger": 2906406,
|
||||
"ledger_index": 2906406,
|
||||
"meta": {
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "13F1A95D7AAB7108D5CE7EEAF504B2894B8C674E6D68499076441C4837282BF8",
|
||||
"PreviousTxnID": "4756C22BBB7FC23D9081FDB180806939D6FEBC967BE0EC2DB95B166AF9C086E9",
|
||||
"PreviousTxnLgrSeq": 2764813
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rhgdnc82FwHFUKXp9ZcpgwXWRAxKf5Buqp",
|
||||
"Balance": "9999999970",
|
||||
"Flags": 0,
|
||||
"OwnerCount": 0,
|
||||
"Sequence": 4
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "3430FA3A160FA8F9842FA4A8B5549ECDCB3783E585D0F9796A1736DEAE35F6FE",
|
||||
"PreviousFields": {
|
||||
"Balance": "9999999980",
|
||||
"Sequence": 3
|
||||
},
|
||||
"PreviousTxnID": "DA6F5CA8CE13A03B8BC58515E085F2FEF90B3C08230B5AEC8DE4FAF39F79010B",
|
||||
"PreviousTxnLgrSeq": 2906391
|
||||
}
|
||||
},
|
||||
{
|
||||
"DeletedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "r3wN3v2vTUkr5qd6daqDc2xE4LSysdVjkT",
|
||||
"Amount": "10000",
|
||||
"CancelAfter": 559913895,
|
||||
"Destination": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"FinishAfter": 559892324,
|
||||
"Flags": 0,
|
||||
"OwnerNode": "0000000000000000",
|
||||
"PreviousTxnID": "4756C22BBB7FC23D9081FDB180806939D6FEBC967BE0EC2DB95B166AF9C086E9",
|
||||
"PreviousTxnLgrSeq": 2764813
|
||||
},
|
||||
"LedgerEntryType": "Escrow",
|
||||
"LedgerIndex": "7243A9750FA4BE3E63F75F6DACFD79AD6B6C76947F6BDC46CD0F52DBEEF64C89"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Flags": 0,
|
||||
"Owner": "r3wN3v2vTUkr5qd6daqDc2xE4LSysdVjkT",
|
||||
"RootIndex": "DACDBEBD31D14EAC4207A45DB88734AD14D26D908507F41D2FC623BDD91C582F"
|
||||
},
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "DACDBEBD31D14EAC4207A45DB88734AD14D26D908507F41D2FC623BDD91C582F"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "r3wN3v2vTUkr5qd6daqDc2xE4LSysdVjkT",
|
||||
"Balance": "9999999990",
|
||||
"Flags": 0,
|
||||
"OwnerCount": 0,
|
||||
"Sequence": 2
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "F5F1834B80A8B5DA878270AB4DE4EA444281181349375F1D21E46D5F3F0ABAC8",
|
||||
"PreviousFields": {
|
||||
"Balance": "9999989990",
|
||||
"OwnerCount": 1
|
||||
},
|
||||
"PreviousTxnID": "4756C22BBB7FC23D9081FDB180806939D6FEBC967BE0EC2DB95B166AF9C086E9",
|
||||
"PreviousTxnLgrSeq": 2764813
|
||||
}
|
||||
}
|
||||
],
|
||||
"TransactionIndex": 2,
|
||||
"TransactionResult": "tesSUCCESS"
|
||||
},
|
||||
"validated": true
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
{
|
||||
"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
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
{
|
||||
"id": 3,
|
||||
"status": "success",
|
||||
"type": "response",
|
||||
"result": {
|
||||
"Account": "rajgkBmMxmz161r8bWYH7CQAFZP5bA9oSG",
|
||||
"Amount": "10000",
|
||||
"Destination": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"Fee": "10",
|
||||
"FinishAfter": 557020800,
|
||||
"Flags": 2147483648,
|
||||
"Sequence": 1,
|
||||
"SigningPubKey": "03C3555B7339FFDDB43495A8371A3A87B4C66B67D49D06CB9BA1FDBFEEB57B6E43",
|
||||
"TransactionType": "EscrowCreate",
|
||||
"TxnSignature": "304402203C9AA4C21E1A1A7427D41583283E7A513DDBDD967B246CADD3B2705D858A7A8E02201BEA7B923B18910EEB9F306F6DE3B3F53549BBFAD46335B62B4C34A6DCB4A476",
|
||||
"date": 557014081,
|
||||
"hash": "55B2057332F8999208C43BA1E7091B423A16E5ED2736C06300B4076085205263",
|
||||
"inLedger": 1828796,
|
||||
"ledger_index": 1828796,
|
||||
"meta": {
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "13F1A95D7AAB7108D5CE7EEAF504B2894B8C674E6D68499076441C4837282BF8",
|
||||
"PreviousTxnID": "613B28E0890FC975F2CBA3D700F75116F623B1E3FE48CB7CB2EB216EAD6F097D",
|
||||
"PreviousTxnLgrSeq": 1799920
|
||||
}
|
||||
},
|
||||
{
|
||||
"CreatedNode": {
|
||||
"LedgerEntryType": "Escrow",
|
||||
"LedgerIndex": "2B9845CB9DF686B9615BF04F3EC66095A334D985E03E71B893B90FCF6D4DC9E6",
|
||||
"NewFields": {
|
||||
"Account": "rajgkBmMxmz161r8bWYH7CQAFZP5bA9oSG",
|
||||
"Amount": "10000",
|
||||
"Destination": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"FinishAfter": 557020800
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rajgkBmMxmz161r8bWYH7CQAFZP5bA9oSG",
|
||||
"Balance": "9999989990",
|
||||
"Flags": 0,
|
||||
"OwnerCount": 1,
|
||||
"Sequence": 2
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "AE5AB6584A76C37C7382B6880609FC7792D90CDA36FF362AF412EB914C1715D3",
|
||||
"PreviousFields": {
|
||||
"Balance": "10000000000",
|
||||
"OwnerCount": 0,
|
||||
"Sequence": 1
|
||||
},
|
||||
"PreviousTxnID": "F181D45FD094A7417926F791D9DF958B84CE4B7B3D92CC9DDCACB1D5EC59AAAA",
|
||||
"PreviousTxnLgrSeq": 1828732
|
||||
}
|
||||
},
|
||||
{
|
||||
"CreatedNode": {
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "D623EBEEEE701D4323D0ADA5320AF35EA8CC6520EBBEF69343354CD593DABC88",
|
||||
"NewFields": {
|
||||
"Owner": "rajgkBmMxmz161r8bWYH7CQAFZP5bA9oSG",
|
||||
"RootIndex": "D623EBEEEE701D4323D0ADA5320AF35EA8CC6520EBBEF69343354CD593DABC88"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"TransactionIndex": 3,
|
||||
"TransactionResult": "tesSUCCESS"
|
||||
},
|
||||
"validated": true
|
||||
}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
{
|
||||
"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
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
{
|
||||
"id": 21,
|
||||
"status": "success",
|
||||
"type": "response",
|
||||
"result": {
|
||||
"Account": "rajgkBmMxmz161r8bWYH7CQAFZP5bA9oSG",
|
||||
"Fee": "10",
|
||||
"Flags": 2147483648,
|
||||
"OfferSequence": 1,
|
||||
"Owner": "rajgkBmMxmz161r8bWYH7CQAFZP5bA9oSG",
|
||||
"Sequence": 2,
|
||||
"SigningPubKey": "03C3555B7339FFDDB43495A8371A3A87B4C66B67D49D06CB9BA1FDBFEEB57B6E43",
|
||||
"TransactionType": "EscrowFinish",
|
||||
"TxnSignature": "3045022100923B91BA4FD6450813F5335D71C64BA9EB81304A86859A631F2AD8571424A46502200CCE660D36781B84634C5F23619EB6CFCCF942709F54DCCF27CF6F499AE78C9B",
|
||||
"date": 557256681,
|
||||
"hash": "41856A742B3CAF307E7B4D0B850F302101F0F415B785454F7501E9960A2A1F6B",
|
||||
"inLedger": 1908257,
|
||||
"ledger_index": 1908257,
|
||||
"meta": {
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"Balance": "400210000",
|
||||
"Flags": 0,
|
||||
"OwnerCount": 0,
|
||||
"Sequence": 1
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "13F1A95D7AAB7108D5CE7EEAF504B2894B8C674E6D68499076441C4837282BF8",
|
||||
"PreviousFields": {
|
||||
"Balance": "400200000"
|
||||
},
|
||||
"PreviousTxnID": "55B2057332F8999208C43BA1E7091B423A16E5ED2736C06300B4076085205263",
|
||||
"PreviousTxnLgrSeq": 1828796
|
||||
}
|
||||
},
|
||||
{
|
||||
"DeletedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rajgkBmMxmz161r8bWYH7CQAFZP5bA9oSG",
|
||||
"Amount": "10000",
|
||||
"Destination": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"FinishAfter": 557020800,
|
||||
"Flags": 0,
|
||||
"OwnerNode": "0000000000000000",
|
||||
"PreviousTxnID": "55B2057332F8999208C43BA1E7091B423A16E5ED2736C06300B4076085205263",
|
||||
"PreviousTxnLgrSeq": 1828796
|
||||
},
|
||||
"LedgerEntryType": "Escrow",
|
||||
"LedgerIndex": "2B9845CB9DF686B9615BF04F3EC66095A334D985E03E71B893B90FCF6D4DC9E6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rajgkBmMxmz161r8bWYH7CQAFZP5bA9oSG",
|
||||
"Balance": "9999989980",
|
||||
"Flags": 0,
|
||||
"OwnerCount": 0,
|
||||
"Sequence": 3
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "AE5AB6584A76C37C7382B6880609FC7792D90CDA36FF362AF412EB914C1715D3",
|
||||
"PreviousFields": {
|
||||
"Balance": "9999989990",
|
||||
"OwnerCount": 1,
|
||||
"Sequence": 2
|
||||
},
|
||||
"PreviousTxnID": "55B2057332F8999208C43BA1E7091B423A16E5ED2736C06300B4076085205263",
|
||||
"PreviousTxnLgrSeq": 1828796
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Flags": 0,
|
||||
"Owner": "rajgkBmMxmz161r8bWYH7CQAFZP5bA9oSG",
|
||||
"RootIndex": "D623EBEEEE701D4323D0ADA5320AF35EA8CC6520EBBEF69343354CD593DABC88"
|
||||
},
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "D623EBEEEE701D4323D0ADA5320AF35EA8CC6520EBBEF69343354CD593DABC88"
|
||||
}
|
||||
}
|
||||
],
|
||||
"TransactionIndex": 2,
|
||||
"TransactionResult": "tesSUCCESS"
|
||||
},
|
||||
"validated": true
|
||||
}
|
||||
}
|
||||
@@ -1,80 +1,87 @@
|
||||
{
|
||||
"result": {
|
||||
"ledger_hash": "0C445F6F348AA5FF25A631C904F7277980F7FD2A6BACBB3A74FCF95F671D4884",
|
||||
"ledger_index": 82681558,
|
||||
"ledger_hash": "3787026448652A36491493C1202A443B2A6CC6022599BB0B25DDB0802DD7F1E7",
|
||||
"ledger_index": 82681623,
|
||||
"validated": true,
|
||||
"ledger": {
|
||||
"account_hash": "60BF81E9BCA5CEDB629B8D19DE0791F13318B4C6B6886E35A211824F9EB04DE5",
|
||||
"account_hash": "39D34D858A0FD652143ED84B67A09193772DE0CCEBD2D63619E679293B7A3388",
|
||||
"close_flags": 0,
|
||||
"close_time": 748569330,
|
||||
"close_time_human": "2023-Sep-20 23:55:30.000000000 UTC",
|
||||
"close_time": 748569571,
|
||||
"close_time_human": "2023-Sep-20 23:59:31.000000000 UTC",
|
||||
"close_time_resolution": 10,
|
||||
"close_time_iso": "2023-09-20T23:59:31Z",
|
||||
"ledger_hash": "3787026448652A36491493C1202A443B2A6CC6022599BB0B25DDB0802DD7F1E7",
|
||||
"parent_close_time": 748569570,
|
||||
"parent_hash": "674FF6C68956E06CB9628833677C3DD71824C87C0AEFB487984CF98C3964DAEE",
|
||||
"total_coins": "99988406188847858",
|
||||
"transaction_hash": "11EE9C448D6B07B88A80B4FC7935B485E513816B3B47D0976CE9F51E7CF10A85",
|
||||
"ledger_index": 82681623,
|
||||
"closed": true,
|
||||
"ledger_hash": "0C445F6F348AA5FF25A631C904F7277980F7FD2A6BACBB3A74FCF95F671D4884",
|
||||
"ledger_index": "82681558",
|
||||
"parent_close_time": 748569321,
|
||||
"parent_hash": "817E4F1791BE34C1214E78E02CAB794C54615F69E765D140D0BD820EA81BF0E9",
|
||||
"total_coins": "99988406204421588",
|
||||
"transaction_hash": "2D7808600F9CF57E263EC1EC4AA7357586AE949908EA7DBF023D241812CDC9B5",
|
||||
"diff": [
|
||||
{
|
||||
"object_id": "02BAAC1E67C1CE0E96F0FA2E8061020536CEDD043FEB0FF54F0E155AF07E5400",
|
||||
"object_id": "02BAAC1E67C1CE0E96F0FA2E8061020536CEDD043FEB0FF54F0E134815E74400",
|
||||
"object": {
|
||||
"ExchangeRate": "4f0e155af07e5400",
|
||||
"ExchangeRate": "4f0e134815e74400",
|
||||
"Flags": 0,
|
||||
"Indexes": [
|
||||
"4CF31E76F470F4CBE7E7EDD1973CDFA564A59672D14C577C51517A1E3469E53A"
|
||||
"AA0B31FB7FEF4A2546DA2BD0C44E9EC0D3A173EDE92DA1D50F78E61024BAFE4F"
|
||||
],
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"RootIndex": "02BAAC1E67C1CE0E96F0FA2E8061020536CEDD043FEB0FF54F0E155AF07E5400",
|
||||
"RootIndex": "02BAAC1E67C1CE0E96F0FA2E8061020536CEDD043FEB0FF54F0E134815E74400",
|
||||
"TakerGetsCurrency": "0000000000000000000000000000000000000000",
|
||||
"TakerGetsIssuer": "0000000000000000000000000000000000000000",
|
||||
"TakerPaysCurrency": "000000000000000000000000434E590000000000",
|
||||
"TakerPaysIssuer": "CED6E99370D5C00EF4EBF72567DA99F5661BFB3A",
|
||||
"index": "02BAAC1E67C1CE0E96F0FA2E8061020536CEDD043FEB0FF54F0E155AF07E5400"
|
||||
"index": "02BAAC1E67C1CE0E96F0FA2E8061020536CEDD043FEB0FF54F0E134815E74400"
|
||||
}
|
||||
},
|
||||
# ... (trimmed for length) ...
|
||||
{
|
||||
"object_id": "F0B9A528CE25FE77C51C38040A7FEC016C2C841E74C1418D5B0A3845AE4FF3FC",
|
||||
"object_id": "F65CCB13C33A1739BE63CBF6C77636429B0F4F506766D5E427A7CCC6C102037D",
|
||||
"object": {
|
||||
"ExchangeRate": "5b0a3845ae4ff3fc",
|
||||
"Flags": 0,
|
||||
"Indexes": [
|
||||
"7C085618D0A2BC3A8919A032699A2219C08D112CC4020E615CE37C4ABE31A13C"
|
||||
],
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"RootIndex": "F0B9A528CE25FE77C51C38040A7FEC016C2C841E74C1418D5B0A3845AE4FF3FC",
|
||||
"TakerGetsCurrency": "0000000000000000000000005553440000000000",
|
||||
"TakerGetsIssuer": "2ADB0B3959D60A6E6991F729E1918B7163925230",
|
||||
"TakerPaysCurrency": "0000000000000000000000000000000000000000",
|
||||
"TakerPaysIssuer": "0000000000000000000000000000000000000000",
|
||||
"index": "F0B9A528CE25FE77C51C38040A7FEC016C2C841E74C1418D5B0A3845AE4FF3FC"
|
||||
"Balance": {
|
||||
"currency": "MAG",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-0.0157136905"
|
||||
},
|
||||
"Flags": 2228224,
|
||||
"HighLimit": {
|
||||
"currency": "MAG",
|
||||
"issuer": "rwED3Kn7qu2og2nhCiDun5gKfWBDZ1YzfM",
|
||||
"value": "45999776.589682"
|
||||
},
|
||||
"HighNode": "0",
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LowLimit": {
|
||||
"currency": "MAG",
|
||||
"issuer": "rXmagwMmnFtVet3uL26Q2iwk287SRvVMJ",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "8d",
|
||||
"PreviousTxnID": "82783FBAE34A01C1AFA580F105FD716FA083B572BCE91254FD1B93B580E6DD3C",
|
||||
"PreviousTxnLgrSeq": 82681623,
|
||||
"index": "F65CCB13C33A1739BE63CBF6C77636429B0F4F506766D5E427A7CCC6C102037D"
|
||||
}
|
||||
},
|
||||
{
|
||||
"object_id": "F0B9A528CE25FE77C51C38040A7FEC016C2C841E74C1418D5B0A395385B74F22",
|
||||
"object_id": "F7F1E123DC7B155F93DA6E122C4ED86B7032DFB6C399A5514A422635A8459821",
|
||||
"object": ""
|
||||
},
|
||||
{
|
||||
"object_id": "F97B88D103742E8C7CBDB982FF8843DC9E128E968668837B9468B1DB47EABBDC",
|
||||
"object_id": "FA295451E29A37C8BDEC209DB56B2E7D35F714492A1CBD20258FD8E806906E1F",
|
||||
"object": {
|
||||
"Account": "r4AZpDKVoBxVcYUJCWMcqZzyWsHTteC4ZE",
|
||||
"BookDirectory": "623C4C4AD65873DA787AC85A0A1385FE6233B6DE100799474F12ED4BF0EFEAD9",
|
||||
"BookNode": "0",
|
||||
"Account": "rff9KstNpP3eFWDp81uv3vizh5dreQRVZv",
|
||||
"Balance": "11720167",
|
||||
"Domain": "6D61726B6574696E67",
|
||||
"EmailHash": "A5EC2C95531D608F0DB6369F8097A16E",
|
||||
"Flags": 0,
|
||||
"LedgerEntryType": "Offer",
|
||||
"OwnerNode": "0",
|
||||
"PreviousTxnID": "15D26953F0CE5216DC8BC7123E3DB8C8EC210D6127A7F34E182318206E0F2DFE",
|
||||
"PreviousTxnLgrSeq": 82681558,
|
||||
"Sequence": 132450778,
|
||||
"TakerGets": "3677818937",
|
||||
"TakerPays": {
|
||||
"currency": "CNY",
|
||||
"issuer": "rJ1adrpGS3xsnQMb9Cw54tWJVFPuSdZHK",
|
||||
"value": "19593.43327917432"
|
||||
},
|
||||
"index": "F97B88D103742E8C7CBDB982FF8843DC9E128E968668837B9468B1DB47EABBDC"
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"OwnerCount": 1,
|
||||
"PreviousTxnID": "295A3AE6C90436F80EABB833B716DB52EC234C3D148622C2E5A449539C9FB0EE",
|
||||
"PreviousTxnLgrSeq": 82681623,
|
||||
"Sequence": 68507056,
|
||||
"index": "FA295451E29A37C8BDEC209DB56B2E7D35F714492A1CBD20258FD8E806906E1F",
|
||||
"urlgravatar": "http://www.gravatar.com/avatar/a5ec2c95531d608f0db6369f8097a16e"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -87,5 +94,4 @@
|
||||
"message": "This is a clio server. clio only serves validated data. If you want to talk to rippled, include 'ledger_index':'current' in your request"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,7 +6,8 @@
|
||||
"transactions": false,
|
||||
"expand": false,
|
||||
"owner_funds": false,
|
||||
"diff": false
|
||||
"diff": false,
|
||||
"api_version": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,22 @@
|
||||
{
|
||||
"result": {
|
||||
"ledger_hash": "4E2F27F997943EAF522FB0D6AE4B25B1F54FDDE531E0469EF436B18391CFC7D9",
|
||||
"ledger_index": 82681548,
|
||||
"ledger_hash": "3787026448652A36491493C1202A443B2A6CC6022599BB0B25DDB0802DD7F1E7",
|
||||
"ledger_index": 82681623,
|
||||
"validated": true,
|
||||
"ledger": {
|
||||
"account_hash": "608FCCDB3261FEF57B6EB76C89E3FE11B7C8D198DF443831BABF33D08FC8C12A",
|
||||
"account_hash": "39D34D858A0FD652143ED84B67A09193772DE0CCEBD2D63619E679293B7A3388",
|
||||
"close_flags": 0,
|
||||
"close_time": 748569290,
|
||||
"close_time_human": "2023-Sep-20 23:54:50.000000000 UTC",
|
||||
"close_time": 748569571,
|
||||
"close_time_human": "2023-Sep-20 23:59:31.000000000 UTC",
|
||||
"close_time_resolution": 10,
|
||||
"closed": true,
|
||||
"ledger_hash": "4E2F27F997943EAF522FB0D6AE4B25B1F54FDDE531E0469EF436B18391CFC7D9",
|
||||
"ledger_index": "82681548",
|
||||
"parent_close_time": 748569282,
|
||||
"parent_hash": "DCECE701AE72CD9E3C1161EC6C98048DFF5797045CD49AD6038BE6D4610EED93",
|
||||
"total_coins": "99988406204467365",
|
||||
"transaction_hash": "95491C538DC25D4980AADC5E2ABAB90E1D4E20A02E772EA6A1C514BFC19987E4"
|
||||
"close_time_iso": "2023-09-20T23:59:31Z",
|
||||
"ledger_hash": "3787026448652A36491493C1202A443B2A6CC6022599BB0B25DDB0802DD7F1E7",
|
||||
"parent_close_time": 748569570,
|
||||
"parent_hash": "674FF6C68956E06CB9628833677C3DD71824C87C0AEFB487984CF98C3964DAEE",
|
||||
"total_coins": "99988406188847858",
|
||||
"transaction_hash": "11EE9C448D6B07B88A80B4FC7935B485E513816B3B47D0976CE9F51E7CF10A85",
|
||||
"ledger_index": 82681623,
|
||||
"closed": true
|
||||
},
|
||||
"status": "success"
|
||||
},
|
||||
@@ -25,4 +26,4 @@
|
||||
"message": "This is a clio server. clio only serves validated data. If you want to talk to rippled, include 'ledger_index':'current' in your request"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"id": 14,
|
||||
"id": "example_ledger_req",
|
||||
"command": "ledger",
|
||||
"ledger_index": "validated",
|
||||
"transactions": false,
|
||||
"expand": false,
|
||||
"owner_funds": false,
|
||||
"diff": false
|
||||
}
|
||||
"api_version": 2
|
||||
}
|
||||
@@ -9,15 +9,18 @@
|
||||
"close_time": 748569571,
|
||||
"close_time_human": "2023-Sep-20 23:59:31.000000000 UTC",
|
||||
"close_time_resolution": 10,
|
||||
"closed": true,
|
||||
"close_time_iso": "2023-09-20T23:59:31Z",
|
||||
"ledger_hash": "3787026448652A36491493C1202A443B2A6CC6022599BB0B25DDB0802DD7F1E7",
|
||||
"ledger_index": "82681623",
|
||||
"parent_close_time": 748569570,
|
||||
"parent_hash": "674FF6C68956E06CB9628833677C3DD71824C87C0AEFB487984CF98C3964DAEE",
|
||||
"total_coins": "99988406188847858",
|
||||
"transaction_hash": "11EE9C448D6B07B88A80B4FC7935B485E513816B3B47D0976CE9F51E7CF10A85"
|
||||
"transaction_hash": "11EE9C448D6B07B88A80B4FC7935B485E513816B3B47D0976CE9F51E7CF10A85",
|
||||
"ledger_index": 82681623,
|
||||
"closed": true
|
||||
}
|
||||
},
|
||||
"id": "example_ledger_req",
|
||||
"api_version": 2,
|
||||
"status": "success",
|
||||
"type": "response",
|
||||
"warnings": [
|
||||
@@ -26,4 +29,4 @@
|
||||
"message": "This is a clio server. clio only serves validated data. If you want to talk to rippled, include 'ledger_index':'current' in your request"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,23 @@
|
||||
{
|
||||
"result": {
|
||||
"ledger": {
|
||||
"account_hash": "23C1C8F8ACCEFACBDD9A1804CC25E652A324F9EABD7D0BEF103DA56D6E0306E7",
|
||||
"close_flags": 0,
|
||||
"close_time": 752188801,
|
||||
"close_time_human": "2023-Nov-01 21:20:01.000000000 UTC",
|
||||
"close_time_resolution": 10,
|
||||
"closed": true,
|
||||
"ledger_hash": "140B769E9ED61FCD675A6EEC1F005084614314C1D675C2CFDD11A1024BBD2C96",
|
||||
"ledger_index": "83626952",
|
||||
"parent_close_time": 752188800,
|
||||
"parent_hash": "7D169A530960AFA8A0E38D036D8EF960BC2C2E02C4A0CE848A4200B9376AC99C",
|
||||
"total_coins": "99988256304478252",
|
||||
"transaction_hash": "77226182F58D9B5C798262F0E9D8C575D174E434F0C3C7119FB658BA70004CE9"
|
||||
},
|
||||
"ledger_hash": "140B769E9ED61FCD675A6EEC1F005084614314C1D675C2CFDD11A1024BBD2C96",
|
||||
"ledger_index": 83626952,
|
||||
"status": "success",
|
||||
"validated": true
|
||||
}
|
||||
}
|
||||
"result": {
|
||||
"ledger_hash": "9DAAAE85FC0D64E95506608FDB48E8B77706EF64FF144F18EEBC2FC4366D9B20",
|
||||
"ledger_index": 100972465,
|
||||
"validated": true,
|
||||
"ledger": {
|
||||
"account_hash": "6FD2916DDD574886EBCBAA1CE0048D94E5A57E13EA5DD7B0283A7AB63EBF0131",
|
||||
"close_flags": 0,
|
||||
"close_time": 819429360,
|
||||
"close_time_human": "2025-Dec-19 03:16:00.000000000 UTC",
|
||||
"close_time_resolution": 10,
|
||||
"close_time_iso": "2025-12-19T03:16:00Z",
|
||||
"ledger_hash": "9DAAAE85FC0D64E95506608FDB48E8B77706EF64FF144F18EEBC2FC4366D9B20",
|
||||
"parent_close_time": 819429352,
|
||||
"parent_hash": "1FB3618846E1201E38FED328BD13A9D62012469193C0B5BA4ECE6C8BDAA2BFC9",
|
||||
"total_coins": "99985738467416092",
|
||||
"transaction_hash": "B61C7B94F583DBFEEDA58DE348518D6FC2F397053EA0E3AC4B8F2BD440629F19",
|
||||
"ledger_index": 100972465,
|
||||
"closed": true
|
||||
},
|
||||
"status": "success"
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,26 @@
|
||||
{
|
||||
"id": "example_ledger_req",
|
||||
"result": {
|
||||
"ledger": {
|
||||
"account_hash": "B8B2C0C3F9E75E3AEE31D467B2544AB56244E618890BA58679707D6BFC0AF41D",
|
||||
"close_flags": 0,
|
||||
"close_time": 752188602,
|
||||
"close_time_human": "2023-Nov-01 21:16:42.000000000 UTC",
|
||||
"close_time_resolution": 10,
|
||||
"closed": true,
|
||||
"ledger_hash": "1BEECD5D21592EABDEF98D8E4BC038AD10B5700FF7E98011870DF5D6C2A2F39B",
|
||||
"ledger_index": "83626901",
|
||||
"parent_close_time": 752188601,
|
||||
"parent_hash": "6B32CFC42B32C5FB90019AE17F701D96B499A4C8E148A002E18135A434A19D98",
|
||||
"total_coins": "99988256314388830",
|
||||
"transaction_hash": "21586C664DC47E12AF34F22EBF1DB55D23F8C98972542BAC0C39B1009CAC84D4"
|
||||
},
|
||||
"ledger_hash": "1BEECD5D21592EABDEF98D8E4BC038AD10B5700FF7E98011870DF5D6C2A2F39B",
|
||||
"ledger_index": 83626901,
|
||||
"validated": true
|
||||
},
|
||||
"status": "success",
|
||||
"type": "response"
|
||||
}
|
||||
"result": {
|
||||
"ledger_hash": "9D346B0C050C6C5C5172BD731063C33A50C4E1D89EB51F47BBE73E4DA340A684",
|
||||
"ledger_index": 100972403,
|
||||
"validated": true,
|
||||
"ledger": {
|
||||
"account_hash": "3227B0AE820CA0C7B96A761942912785A27CFC5F3407A39AF03DA0BE9C6A4298",
|
||||
"close_flags": 0,
|
||||
"close_time": 819429112,
|
||||
"close_time_human": "2025-Dec-19 03:11:52.000000000 UTC",
|
||||
"close_time_resolution": 10,
|
||||
"close_time_iso": "2025-12-19T03:11:52Z",
|
||||
"ledger_hash": "9D346B0C050C6C5C5172BD731063C33A50C4E1D89EB51F47BBE73E4DA340A684",
|
||||
"parent_close_time": 819429111,
|
||||
"parent_hash": "667CE88E45EC7E9C71436A93970437F2F1C14D5A367F24BE3B571A27846C1EF3",
|
||||
"total_coins": "99985738468528946",
|
||||
"transaction_hash": "BC2E8BC91AF126D924CD4C43F0A28DF0DF5DE271A11A781516697C56488F03F7",
|
||||
"ledger_index": 100972403,
|
||||
"closed": true
|
||||
}
|
||||
},
|
||||
"id": "example_ledger_req",
|
||||
"api_version": 2,
|
||||
"status": "success",
|
||||
"type": "response"
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
{
|
||||
"result": {
|
||||
"tx_json": {
|
||||
"Account": "r3PDtZSa5LiYp1Ysn1vMuMzB59RzV3W9QH",
|
||||
"DeliverMax": {
|
||||
"currency": "USD",
|
||||
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"value": "1"
|
||||
},
|
||||
"Destination": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"Fee": "10",
|
||||
"Flags": 0,
|
||||
"Paths": [
|
||||
[{
|
||||
"account": "r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV",
|
||||
"currency": "USD",
|
||||
"issuer": "r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV",
|
||||
"type": 49
|
||||
}],
|
||||
[{
|
||||
"account": "rD1jovjQeEpvaDwn9wKaYokkXXrqo4D23x",
|
||||
"currency": "USD",
|
||||
"issuer": "rD1jovjQeEpvaDwn9wKaYokkXXrqo4D23x",
|
||||
"type": 49
|
||||
}, {
|
||||
"account": "rB5TihdPbKgMrkFqrqUC3yLdE8hhv4BdeY",
|
||||
"currency": "USD",
|
||||
"issuer": "rB5TihdPbKgMrkFqrqUC3yLdE8hhv4BdeY",
|
||||
"type": 49
|
||||
}, {
|
||||
"account": "r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV",
|
||||
"currency": "USD",
|
||||
"issuer": "r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV",
|
||||
"type": 49
|
||||
}]
|
||||
],
|
||||
"SendMax": {
|
||||
"currency": "USD",
|
||||
"issuer": "r3PDtZSa5LiYp1Ysn1vMuMzB59RzV3W9QH",
|
||||
"value": "1.01"
|
||||
},
|
||||
"Sequence": 88,
|
||||
"SigningPubKey": "02EAE5DAB54DD8E1C49641D848D5B97D1B29149106174322EDF98A1B2CCE5D7F8E",
|
||||
"TransactionType": "Payment",
|
||||
"TxnSignature": "30440220791B6A3E036ECEFFE99E8D4957564E8C84D1548C8C3E80A87ED1AA646ECCFB16022037C5CAC97E34E3021EBB426479F2ACF3ACA75DB91DCC48D1BCFB4CF547CFEAA0",
|
||||
"date": 416445410,
|
||||
"ledger_index": 348734
|
||||
},
|
||||
"ctid": "C005523E00000000",
|
||||
"hash": "E08D6E9754025BA2534A78707605E0601F03ACE063687A0CA1BDDACFCD1698C7",
|
||||
"meta": {
|
||||
"AffectedNodes": [{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "r3PDtZSa5LiYp1Ysn1vMuMzB59RzV3W9QH",
|
||||
"Balance": "59328999119",
|
||||
"Flags": 0,
|
||||
"OwnerCount": 11,
|
||||
"Sequence": 89
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "E0D7BDE68B468FF0B8D948FD865576517DA987569833A05374ADB9A72E870A06",
|
||||
"PreviousFields": {
|
||||
"Balance": "59328999129",
|
||||
"Sequence": 88
|
||||
},
|
||||
"PreviousTxnID": "C26AA6B4F7C3B9F55E17CD0D11F12032A1C7AD2757229FFD277C9447A8815E6E",
|
||||
"PreviousTxnLgrSeq": 348700
|
||||
}
|
||||
}, {
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-1"
|
||||
},
|
||||
"Flags": 131072,
|
||||
"HighLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"value": "100"
|
||||
},
|
||||
"HighNode": "0",
|
||||
"LowLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "r3PDtZSa5LiYp1Ysn1vMuMzB59RzV3W9QH",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "0"
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "EA4BF03B4700123CDFFB6EB09DC1D6E28D5CEB7F680FB00FC24BC1C3BB2DB959",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "0"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "53354D84BAE8FDFC3F4DA879D984D24B929E7FEB9100D2AD9EFCD2E126BCCDC8",
|
||||
"PreviousTxnLgrSeq": 343570
|
||||
}
|
||||
}],
|
||||
"TransactionIndex": 0,
|
||||
"TransactionResult": "tesSUCCESS",
|
||||
"delivered_amount": "unavailable"
|
||||
},
|
||||
"validated": true,
|
||||
"ledger_index": 348734,
|
||||
"ledger_hash": "195F62F34EB2CCFA4C5888BA20387E82EB353DDB4508BAE6A835AF19FB8B0C09",
|
||||
"close_time_iso": "2013-03-12T23:16:50Z",
|
||||
"status": "success"
|
||||
}
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
{
|
||||
"result": {
|
||||
"tx_json": {
|
||||
"Account": "rhhh49pFH96roGyuC4E5P4CHaNjS1k8gzM",
|
||||
"Fee": "12",
|
||||
"Flags": 0,
|
||||
"LastLedgerSequence": 56865248,
|
||||
"OfferSequence": 5037708,
|
||||
"Sequence": 5037710,
|
||||
"SigningPubKey": "03B51A3EDF70E4098DA7FB053A01C5A6A0A163A30ED1445F14F87C7C3295FCB3BE",
|
||||
"TakerGets": "15000000000",
|
||||
"TakerPays": {
|
||||
"currency": "CNY",
|
||||
"issuer": "rKiCet8SdvWxPXnAgYarFUXMh1zCPz432Y",
|
||||
"value": "20160.75"
|
||||
},
|
||||
"TransactionType": "OfferCreate",
|
||||
"TxnSignature": "3045022100A5023A0E64923616FCDB6D664F569644C7C9D1895772F986CD6B981B515B02A00220530C973E9A8395BC6FE2484948D2751F6B030FC7FB8575D1BFB406368AD554D9",
|
||||
"date": 648248020,
|
||||
"ledger_index": 56865245
|
||||
},
|
||||
"ctid": "C363B1DD00000000",
|
||||
"hash": "C53ECF838647FA5A4C780377025FEC7999AB4182590510CA461444B207AB74A9",
|
||||
"meta": {
|
||||
"AffectedNodes": [{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"ExchangeRate": "4f04c66806cf7400",
|
||||
"Flags": 0,
|
||||
"RootIndex": "02BAAC1E67C1CE0E96F0FA2E8061020536CEDD043FEB0FF54F04C66806CF7400",
|
||||
"TakerGetsCurrency": "0000000000000000000000000000000000000000",
|
||||
"TakerGetsIssuer": "0000000000000000000000000000000000000000",
|
||||
"TakerPaysCurrency": "000000000000000000000000434E590000000000",
|
||||
"TakerPaysIssuer": "CED6E99370D5C00EF4EBF72567DA99F5661BFB3A"
|
||||
},
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "02BAAC1E67C1CE0E96F0FA2E8061020536CEDD043FEB0FF54F04C66806CF7400"
|
||||
}
|
||||
}, {
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rhhh49pFH96roGyuC4E5P4CHaNjS1k8gzM",
|
||||
"Balance": "10404767991",
|
||||
"Flags": 0,
|
||||
"OwnerCount": 3,
|
||||
"Sequence": 5037711
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "1DECD9844E95FFBA273F1B94BA0BF2564DDF69F2804497A6D7837B52050174A2",
|
||||
"PreviousFields": {
|
||||
"Balance": "10404768003",
|
||||
"Sequence": 5037710
|
||||
},
|
||||
"PreviousTxnID": "4DC47B246B5EB9CCE92ABA8C482479E3BF1F946CABBEF74CA4DE36521D5F9008",
|
||||
"PreviousTxnLgrSeq": 56865244
|
||||
}
|
||||
}, {
|
||||
"DeletedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rhhh49pFH96roGyuC4E5P4CHaNjS1k8gzM",
|
||||
"BookDirectory": "02BAAC1E67C1CE0E96F0FA2E8061020536CEDD043FEB0FF54F04C66806CF7400",
|
||||
"BookNode": "0",
|
||||
"Flags": 0,
|
||||
"OwnerNode": "0",
|
||||
"PreviousTxnID": "8F5FF57B404827F12BDA7561876A13C3E3B3095CBF75334DBFB5F227391A660C",
|
||||
"PreviousTxnLgrSeq": 56865244,
|
||||
"Sequence": 5037708,
|
||||
"TakerGets": "15000000000",
|
||||
"TakerPays": {
|
||||
"currency": "CNY",
|
||||
"issuer": "rKiCet8SdvWxPXnAgYarFUXMh1zCPz432Y",
|
||||
"value": "20160.75"
|
||||
}
|
||||
},
|
||||
"LedgerEntryType": "Offer",
|
||||
"LedgerIndex": "26AAE6CA8D29E28A47C92ADF22D5D96A0216F0551E16936856DDC8CB1AAEE93B"
|
||||
}
|
||||
}, {
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Flags": 0,
|
||||
"IndexNext": "0",
|
||||
"IndexPrevious": "0",
|
||||
"Owner": "rhhh49pFH96roGyuC4E5P4CHaNjS1k8gzM",
|
||||
"RootIndex": "47FAF5D102D8CE655574F440CDB97AC67C5A11068BB3759E87C2B9745EE94548"
|
||||
},
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "47FAF5D102D8CE655574F440CDB97AC67C5A11068BB3759E87C2B9745EE94548"
|
||||
}
|
||||
}, {
|
||||
"CreatedNode": {
|
||||
"LedgerEntryType": "Offer",
|
||||
"LedgerIndex": "8BAEE3C7DE04A568E96007420FA11ABD0BC9AE44D35932BB5640E9C3FB46BC9B",
|
||||
"NewFields": {
|
||||
"Account": "rhhh49pFH96roGyuC4E5P4CHaNjS1k8gzM",
|
||||
"BookDirectory": "02BAAC1E67C1CE0E96F0FA2E8061020536CEDD043FEB0FF54F04C66806CF7400",
|
||||
"Sequence": 5037710,
|
||||
"TakerGets": "15000000000",
|
||||
"TakerPays": {
|
||||
"currency": "CNY",
|
||||
"issuer": "rKiCet8SdvWxPXnAgYarFUXMh1zCPz432Y",
|
||||
"value": "20160.75"
|
||||
}
|
||||
}
|
||||
}
|
||||
}],
|
||||
"TransactionIndex": 0,
|
||||
"TransactionResult": "tesSUCCESS"
|
||||
},
|
||||
"validated": true,
|
||||
"ledger_index": 56865245,
|
||||
"ledger_hash": "793E56131D8D4ABFB27FA383BFC44F2978B046E023FF46C588D7E0C874C2472A",
|
||||
"close_time_iso": "2020-07-16T20:53:40Z",
|
||||
"status": "success"
|
||||
}
|
||||
}
|
||||
123
_api-examples/tx/jsonrpc-response.json
Normal file
123
_api-examples/tx/jsonrpc-response.json
Normal file
@@ -0,0 +1,123 @@
|
||||
{
|
||||
"result": {
|
||||
"tx_json": {
|
||||
"Account": "rhhh49pFH96roGyuC4E5P4CHaNjS1k8gzM",
|
||||
"Fee": "12",
|
||||
"Flags": 0,
|
||||
"LastLedgerSequence": 56865248,
|
||||
"OfferSequence": 5037708,
|
||||
"Sequence": 5037710,
|
||||
"SigningPubKey": "03B51A3EDF70E4098DA7FB053A01C5A6A0A163A30ED1445F14F87C7C3295FCB3BE",
|
||||
"TakerGets": "15000000000",
|
||||
"TakerPays": {
|
||||
"currency": "CNY",
|
||||
"issuer": "rKiCet8SdvWxPXnAgYarFUXMh1zCPz432Y",
|
||||
"value": "20160.75"
|
||||
},
|
||||
"TransactionType": "OfferCreate",
|
||||
"TxnSignature": "3045022100A5023A0E64923616FCDB6D664F569644C7C9D1895772F986CD6B981B515B02A00220530C973E9A8395BC6FE2484948D2751F6B030FC7FB8575D1BFB406368AD554D9",
|
||||
"ledger_index": 56865245,
|
||||
"ctid": "C363B1DD00000000",
|
||||
"date": 648248020
|
||||
},
|
||||
"hash": "C53ECF838647FA5A4C780377025FEC7999AB4182590510CA461444B207AB74A9",
|
||||
"meta": {
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"ExchangeRate": "4f04c66806cf7400",
|
||||
"Flags": 0,
|
||||
"RootIndex": "02BAAC1E67C1CE0E96F0FA2E8061020536CEDD043FEB0FF54F04C66806CF7400",
|
||||
"TakerGetsCurrency": "0000000000000000000000000000000000000000",
|
||||
"TakerGetsIssuer": "0000000000000000000000000000000000000000",
|
||||
"TakerPaysCurrency": "000000000000000000000000434E590000000000",
|
||||
"TakerPaysIssuer": "CED6E99370D5C00EF4EBF72567DA99F5661BFB3A"
|
||||
},
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "02BAAC1E67C1CE0E96F0FA2E8061020536CEDD043FEB0FF54F04C66806CF7400"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rhhh49pFH96roGyuC4E5P4CHaNjS1k8gzM",
|
||||
"Balance": "10404767991",
|
||||
"Flags": 0,
|
||||
"OwnerCount": 3,
|
||||
"Sequence": 5037711
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "1DECD9844E95FFBA273F1B94BA0BF2564DDF69F2804497A6D7837B52050174A2",
|
||||
"PreviousFields": {
|
||||
"Balance": "10404768003",
|
||||
"Sequence": 5037710
|
||||
},
|
||||
"PreviousTxnID": "4DC47B246B5EB9CCE92ABA8C482479E3BF1F946CABBEF74CA4DE36521D5F9008",
|
||||
"PreviousTxnLgrSeq": 56865244
|
||||
}
|
||||
},
|
||||
{
|
||||
"DeletedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rhhh49pFH96roGyuC4E5P4CHaNjS1k8gzM",
|
||||
"BookDirectory": "02BAAC1E67C1CE0E96F0FA2E8061020536CEDD043FEB0FF54F04C66806CF7400",
|
||||
"BookNode": "0",
|
||||
"Flags": 0,
|
||||
"OwnerNode": "0",
|
||||
"PreviousTxnID": "8F5FF57B404827F12BDA7561876A13C3E3B3095CBF75334DBFB5F227391A660C",
|
||||
"PreviousTxnLgrSeq": 56865244,
|
||||
"Sequence": 5037708,
|
||||
"TakerGets": "15000000000",
|
||||
"TakerPays": {
|
||||
"currency": "CNY",
|
||||
"issuer": "rKiCet8SdvWxPXnAgYarFUXMh1zCPz432Y",
|
||||
"value": "20160.75"
|
||||
}
|
||||
},
|
||||
"LedgerEntryType": "Offer",
|
||||
"LedgerIndex": "26AAE6CA8D29E28A47C92ADF22D5D96A0216F0551E16936856DDC8CB1AAEE93B"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Flags": 0,
|
||||
"IndexNext": "0",
|
||||
"IndexPrevious": "0",
|
||||
"Owner": "rhhh49pFH96roGyuC4E5P4CHaNjS1k8gzM",
|
||||
"RootIndex": "47FAF5D102D8CE655574F440CDB97AC67C5A11068BB3759E87C2B9745EE94548"
|
||||
},
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "47FAF5D102D8CE655574F440CDB97AC67C5A11068BB3759E87C2B9745EE94548"
|
||||
}
|
||||
},
|
||||
{
|
||||
"CreatedNode": {
|
||||
"LedgerEntryType": "Offer",
|
||||
"LedgerIndex": "8BAEE3C7DE04A568E96007420FA11ABD0BC9AE44D35932BB5640E9C3FB46BC9B",
|
||||
"NewFields": {
|
||||
"Account": "rhhh49pFH96roGyuC4E5P4CHaNjS1k8gzM",
|
||||
"BookDirectory": "02BAAC1E67C1CE0E96F0FA2E8061020536CEDD043FEB0FF54F04C66806CF7400",
|
||||
"Sequence": 5037710,
|
||||
"TakerGets": "15000000000",
|
||||
"TakerPays": {
|
||||
"currency": "CNY",
|
||||
"issuer": "rKiCet8SdvWxPXnAgYarFUXMh1zCPz432Y",
|
||||
"value": "20160.75"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"TransactionIndex": 0,
|
||||
"TransactionResult": "tesSUCCESS"
|
||||
},
|
||||
"validated": true,
|
||||
"ledger_index": 56865245,
|
||||
"ledger_hash": "793E56131D8D4ABFB27FA383BFC44F2978B046E023FF46C588D7E0C874C2472A",
|
||||
"close_time_iso": "2020-07-16T20:53:40Z",
|
||||
"ctid": "C363B1DD00000000",
|
||||
"status": "success"
|
||||
}
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
{
|
||||
"result": {
|
||||
"tx_json": {
|
||||
"Account": "r3PDtZSa5LiYp1Ysn1vMuMzB59RzV3W9QH",
|
||||
"DeliverMax": {
|
||||
"currency": "USD",
|
||||
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"value": "1"
|
||||
},
|
||||
"Destination": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"Fee": "10",
|
||||
"Flags": 0,
|
||||
"Paths": [
|
||||
[
|
||||
{
|
||||
"account": "r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV",
|
||||
"currency": "USD",
|
||||
"issuer": "r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV",
|
||||
"type": 49
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"account": "rD1jovjQeEpvaDwn9wKaYokkXXrqo4D23x",
|
||||
"currency": "USD",
|
||||
"issuer": "rD1jovjQeEpvaDwn9wKaYokkXXrqo4D23x",
|
||||
"type": 49
|
||||
},
|
||||
{
|
||||
"account": "rB5TihdPbKgMrkFqrqUC3yLdE8hhv4BdeY",
|
||||
"currency": "USD",
|
||||
"issuer": "rB5TihdPbKgMrkFqrqUC3yLdE8hhv4BdeY",
|
||||
"type": 49
|
||||
},
|
||||
{
|
||||
"account": "r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV",
|
||||
"currency": "USD",
|
||||
"issuer": "r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV",
|
||||
"type": 49
|
||||
}
|
||||
]
|
||||
],
|
||||
"SendMax": {
|
||||
"currency": "USD",
|
||||
"issuer": "r3PDtZSa5LiYp1Ysn1vMuMzB59RzV3W9QH",
|
||||
"value": "1.01"
|
||||
},
|
||||
"Sequence": 88,
|
||||
"SigningPubKey": "02EAE5DAB54DD8E1C49641D848D5B97D1B29149106174322EDF98A1B2CCE5D7F8E",
|
||||
"TransactionType": "Payment",
|
||||
"TxnSignature": "30440220791B6A3E036ECEFFE99E8D4957564E8C84D1548C8C3E80A87ED1AA646ECCFB16022037C5CAC97E34E3021EBB426479F2ACF3ACA75DB91DCC48D1BCFB4CF547CFEAA0",
|
||||
"date": 416445410,
|
||||
"ledger_index": 348734
|
||||
},
|
||||
"ctid": "C005523E00000000",
|
||||
"hash": "E08D6E9754025BA2534A78707605E0601F03ACE063687A0CA1BDDACFCD1698C7",
|
||||
"meta": {
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "r3PDtZSa5LiYp1Ysn1vMuMzB59RzV3W9QH",
|
||||
"Balance": "59328999119",
|
||||
"Flags": 0,
|
||||
"OwnerCount": 11,
|
||||
"Sequence": 89
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "E0D7BDE68B468FF0B8D948FD865576517DA987569833A05374ADB9A72E870A06",
|
||||
"PreviousFields": {
|
||||
"Balance": "59328999129",
|
||||
"Sequence": 88
|
||||
},
|
||||
"PreviousTxnID": "C26AA6B4F7C3B9F55E17CD0D11F12032A1C7AD2757229FFD277C9447A8815E6E",
|
||||
"PreviousTxnLgrSeq": 348700
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-1"
|
||||
},
|
||||
"Flags": 131072,
|
||||
"HighLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"value": "100"
|
||||
},
|
||||
"HighNode": "0",
|
||||
"LowLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "r3PDtZSa5LiYp1Ysn1vMuMzB59RzV3W9QH",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "0"
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "EA4BF03B4700123CDFFB6EB09DC1D6E28D5CEB7F680FB00FC24BC1C3BB2DB959",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "0"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "53354D84BAE8FDFC3F4DA879D984D24B929E7FEB9100D2AD9EFCD2E126BCCDC8",
|
||||
"PreviousTxnLgrSeq": 343570
|
||||
}
|
||||
}
|
||||
],
|
||||
"TransactionIndex": 0,
|
||||
"TransactionResult": "tesSUCCESS",
|
||||
"delivered_amount": "unavailable"
|
||||
},
|
||||
"validated": true,
|
||||
"ledger_index": 348734,
|
||||
"ledger_hash": "195F62F34EB2CCFA4C5888BA20387E82EB353DDB4508BAE6A835AF19FB8B0C09",
|
||||
"close_time_iso": "2013-03-12T23:16:50Z"
|
||||
},
|
||||
"id": "CTID example",
|
||||
"api_version": 2,
|
||||
"status": "success",
|
||||
"type": "response"
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
{
|
||||
"result": {
|
||||
"tx_json": {
|
||||
"Account": "r3PDtZSa5LiYp1Ysn1vMuMzB59RzV3W9QH",
|
||||
"DeliverMax": {
|
||||
"currency": "USD",
|
||||
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"value": "1"
|
||||
},
|
||||
"Destination": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"Fee": "10",
|
||||
"Flags": 0,
|
||||
"Paths": [
|
||||
[
|
||||
{
|
||||
"account": "r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV",
|
||||
"currency": "USD",
|
||||
"issuer": "r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV",
|
||||
"type": 49
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"account": "rD1jovjQeEpvaDwn9wKaYokkXXrqo4D23x",
|
||||
"currency": "USD",
|
||||
"issuer": "rD1jovjQeEpvaDwn9wKaYokkXXrqo4D23x",
|
||||
"type": 49
|
||||
},
|
||||
{
|
||||
"account": "rB5TihdPbKgMrkFqrqUC3yLdE8hhv4BdeY",
|
||||
"currency": "USD",
|
||||
"issuer": "rB5TihdPbKgMrkFqrqUC3yLdE8hhv4BdeY",
|
||||
"type": 49
|
||||
},
|
||||
{
|
||||
"account": "r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV",
|
||||
"currency": "USD",
|
||||
"issuer": "r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV",
|
||||
"type": 49
|
||||
}
|
||||
]
|
||||
],
|
||||
"SendMax": {
|
||||
"currency": "USD",
|
||||
"issuer": "r3PDtZSa5LiYp1Ysn1vMuMzB59RzV3W9QH",
|
||||
"value": "1.01"
|
||||
},
|
||||
"Sequence": 88,
|
||||
"SigningPubKey": "02EAE5DAB54DD8E1C49641D848D5B97D1B29149106174322EDF98A1B2CCE5D7F8E",
|
||||
"TransactionType": "Payment",
|
||||
"TxnSignature": "30440220791B6A3E036ECEFFE99E8D4957564E8C84D1548C8C3E80A87ED1AA646ECCFB16022037C5CAC97E34E3021EBB426479F2ACF3ACA75DB91DCC48D1BCFB4CF547CFEAA0",
|
||||
"date": 416445410,
|
||||
"ledger_index": 348734
|
||||
},
|
||||
"ctid": "C005523E00000000",
|
||||
"hash": "E08D6E9754025BA2534A78707605E0601F03ACE063687A0CA1BDDACFCD1698C7",
|
||||
"meta": {
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "r3PDtZSa5LiYp1Ysn1vMuMzB59RzV3W9QH",
|
||||
"Balance": "59328999119",
|
||||
"Flags": 0,
|
||||
"OwnerCount": 11,
|
||||
"Sequence": 89
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "E0D7BDE68B468FF0B8D948FD865576517DA987569833A05374ADB9A72E870A06",
|
||||
"PreviousFields": {
|
||||
"Balance": "59328999129",
|
||||
"Sequence": 88
|
||||
},
|
||||
"PreviousTxnID": "C26AA6B4F7C3B9F55E17CD0D11F12032A1C7AD2757229FFD277C9447A8815E6E",
|
||||
"PreviousTxnLgrSeq": 348700
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "-1"
|
||||
},
|
||||
"Flags": 131072,
|
||||
"HighLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
|
||||
"value": "100"
|
||||
},
|
||||
"HighNode": "0",
|
||||
"LowLimit": {
|
||||
"currency": "USD",
|
||||
"issuer": "r3PDtZSa5LiYp1Ysn1vMuMzB59RzV3W9QH",
|
||||
"value": "0"
|
||||
},
|
||||
"LowNode": "0"
|
||||
},
|
||||
"LedgerEntryType": "RippleState",
|
||||
"LedgerIndex": "EA4BF03B4700123CDFFB6EB09DC1D6E28D5CEB7F680FB00FC24BC1C3BB2DB959",
|
||||
"PreviousFields": {
|
||||
"Balance": {
|
||||
"currency": "USD",
|
||||
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
|
||||
"value": "0"
|
||||
}
|
||||
},
|
||||
"PreviousTxnID": "53354D84BAE8FDFC3F4DA879D984D24B929E7FEB9100D2AD9EFCD2E126BCCDC8",
|
||||
"PreviousTxnLgrSeq": 343570
|
||||
}
|
||||
}
|
||||
],
|
||||
"TransactionIndex": 0,
|
||||
"TransactionResult": "tesSUCCESS",
|
||||
"delivered_amount": "unavailable"
|
||||
},
|
||||
"validated": true,
|
||||
"ledger_index": 348734,
|
||||
"ledger_hash": "195F62F34EB2CCFA4C5888BA20387E82EB353DDB4508BAE6A835AF19FB8B0C09",
|
||||
"close_time_iso": "2013-03-12T23:16:50Z"
|
||||
},
|
||||
"api_version": 2,
|
||||
"status": "success",
|
||||
"type": "response"
|
||||
}
|
||||
126
_api-examples/tx/ws-response.json
Normal file
126
_api-examples/tx/ws-response.json
Normal file
@@ -0,0 +1,126 @@
|
||||
{
|
||||
"result": {
|
||||
"tx_json": {
|
||||
"Account": "rhhh49pFH96roGyuC4E5P4CHaNjS1k8gzM",
|
||||
"Fee": "12",
|
||||
"Flags": 0,
|
||||
"LastLedgerSequence": 56865248,
|
||||
"OfferSequence": 5037708,
|
||||
"Sequence": 5037710,
|
||||
"SigningPubKey": "03B51A3EDF70E4098DA7FB053A01C5A6A0A163A30ED1445F14F87C7C3295FCB3BE",
|
||||
"TakerGets": "15000000000",
|
||||
"TakerPays": {
|
||||
"currency": "CNY",
|
||||
"issuer": "rKiCet8SdvWxPXnAgYarFUXMh1zCPz432Y",
|
||||
"value": "20160.75"
|
||||
},
|
||||
"TransactionType": "OfferCreate",
|
||||
"TxnSignature": "3045022100A5023A0E64923616FCDB6D664F569644C7C9D1895772F986CD6B981B515B02A00220530C973E9A8395BC6FE2484948D2751F6B030FC7FB8575D1BFB406368AD554D9",
|
||||
"ledger_index": 56865245,
|
||||
"ctid": "C363B1DD00000000",
|
||||
"date": 648248020
|
||||
},
|
||||
"hash": "C53ECF838647FA5A4C780377025FEC7999AB4182590510CA461444B207AB74A9",
|
||||
"meta": {
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"ExchangeRate": "4f04c66806cf7400",
|
||||
"Flags": 0,
|
||||
"RootIndex": "02BAAC1E67C1CE0E96F0FA2E8061020536CEDD043FEB0FF54F04C66806CF7400",
|
||||
"TakerGetsCurrency": "0000000000000000000000000000000000000000",
|
||||
"TakerGetsIssuer": "0000000000000000000000000000000000000000",
|
||||
"TakerPaysCurrency": "000000000000000000000000434E590000000000",
|
||||
"TakerPaysIssuer": "CED6E99370D5C00EF4EBF72567DA99F5661BFB3A"
|
||||
},
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "02BAAC1E67C1CE0E96F0FA2E8061020536CEDD043FEB0FF54F04C66806CF7400"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rhhh49pFH96roGyuC4E5P4CHaNjS1k8gzM",
|
||||
"Balance": "10404767991",
|
||||
"Flags": 0,
|
||||
"OwnerCount": 3,
|
||||
"Sequence": 5037711
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "1DECD9844E95FFBA273F1B94BA0BF2564DDF69F2804497A6D7837B52050174A2",
|
||||
"PreviousFields": {
|
||||
"Balance": "10404768003",
|
||||
"Sequence": 5037710
|
||||
},
|
||||
"PreviousTxnID": "4DC47B246B5EB9CCE92ABA8C482479E3BF1F946CABBEF74CA4DE36521D5F9008",
|
||||
"PreviousTxnLgrSeq": 56865244
|
||||
}
|
||||
},
|
||||
{
|
||||
"DeletedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rhhh49pFH96roGyuC4E5P4CHaNjS1k8gzM",
|
||||
"BookDirectory": "02BAAC1E67C1CE0E96F0FA2E8061020536CEDD043FEB0FF54F04C66806CF7400",
|
||||
"BookNode": "0",
|
||||
"Flags": 0,
|
||||
"OwnerNode": "0",
|
||||
"PreviousTxnID": "8F5FF57B404827F12BDA7561876A13C3E3B3095CBF75334DBFB5F227391A660C",
|
||||
"PreviousTxnLgrSeq": 56865244,
|
||||
"Sequence": 5037708,
|
||||
"TakerGets": "15000000000",
|
||||
"TakerPays": {
|
||||
"currency": "CNY",
|
||||
"issuer": "rKiCet8SdvWxPXnAgYarFUXMh1zCPz432Y",
|
||||
"value": "20160.75"
|
||||
}
|
||||
},
|
||||
"LedgerEntryType": "Offer",
|
||||
"LedgerIndex": "26AAE6CA8D29E28A47C92ADF22D5D96A0216F0551E16936856DDC8CB1AAEE93B"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Flags": 0,
|
||||
"IndexNext": "0",
|
||||
"IndexPrevious": "0",
|
||||
"Owner": "rhhh49pFH96roGyuC4E5P4CHaNjS1k8gzM",
|
||||
"RootIndex": "47FAF5D102D8CE655574F440CDB97AC67C5A11068BB3759E87C2B9745EE94548"
|
||||
},
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "47FAF5D102D8CE655574F440CDB97AC67C5A11068BB3759E87C2B9745EE94548"
|
||||
}
|
||||
},
|
||||
{
|
||||
"CreatedNode": {
|
||||
"LedgerEntryType": "Offer",
|
||||
"LedgerIndex": "8BAEE3C7DE04A568E96007420FA11ABD0BC9AE44D35932BB5640E9C3FB46BC9B",
|
||||
"NewFields": {
|
||||
"Account": "rhhh49pFH96roGyuC4E5P4CHaNjS1k8gzM",
|
||||
"BookDirectory": "02BAAC1E67C1CE0E96F0FA2E8061020536CEDD043FEB0FF54F04C66806CF7400",
|
||||
"Sequence": 5037710,
|
||||
"TakerGets": "15000000000",
|
||||
"TakerPays": {
|
||||
"currency": "CNY",
|
||||
"issuer": "rKiCet8SdvWxPXnAgYarFUXMh1zCPz432Y",
|
||||
"value": "20160.75"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"TransactionIndex": 0,
|
||||
"TransactionResult": "tesSUCCESS"
|
||||
},
|
||||
"validated": true,
|
||||
"ledger_index": 56865245,
|
||||
"ledger_hash": "793E56131D8D4ABFB27FA383BFC44F2978B046E023FF46C588D7E0C874C2472A",
|
||||
"close_time_iso": "2020-07-16T20:53:40Z",
|
||||
"ctid": "C363B1DD00000000"
|
||||
},
|
||||
"id": "example_tx_hash",
|
||||
"api_version": 2,
|
||||
"status": "success",
|
||||
"type": "response"
|
||||
}
|
||||
@@ -1,51 +1,174 @@
|
||||
'use strict'
|
||||
const xrpl = require('xrpl');
|
||||
import { Client, isoTimeToRippleTime, rippleTimeToISOTime, validate, getBalanceChanges } from 'xrpl'
|
||||
|
||||
// Preqrequisites:
|
||||
// 1. Create an escrow using the create-escrow.js snippet
|
||||
// 2. Replace the OfferSequence with the sequence number of the escrow you created
|
||||
// 3. Paste the seed of the account that created the escrow
|
||||
// 4. Run this snippet
|
||||
const client = new Client('wss://s.altnet.rippletest.net:51233')
|
||||
await client.connect()
|
||||
|
||||
const seed = "sEd7jfWyNG6J71dEojB3W9YdHp2KCjy"; // replace with your seed
|
||||
const sequenceNumber = 0; // replace with the sequence number of your escrow
|
||||
console.log('Funding new wallet from faucet...')
|
||||
const { wallet } = await client.fundWallet()
|
||||
// const destinationAddress = 'rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe' // Testnet faucet
|
||||
// Alternative: Get another account to send the escrow to. Use this if you get
|
||||
// a tecDIR_FULL error trying to create escrows to the Testnet faucet.
|
||||
const destinationAddress = (await client.fundWallet()).wallet.address
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
// Connect -------------------------------------------------------------------
|
||||
const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233');
|
||||
await client.connect();
|
||||
// Create an escrow that won't be finished -------------------------------------
|
||||
const cancelDelay = 30
|
||||
const cancelAfter = new Date()
|
||||
cancelAfter.setSeconds(cancelAfter.getSeconds() + cancelDelay)
|
||||
console.log('This escrow will expire after:', cancelAfter)
|
||||
// Convert cancelAfter to seconds since the Ripple Epoch:
|
||||
const cancelAfterRippleTime = isoTimeToRippleTime(cancelAfter.toISOString())
|
||||
const conditionHex = 'A02580200000000000000000000000000000000000000000000000000000000000000000810120'
|
||||
|
||||
// Prepare wallet to sign the transaction -------------------------------------
|
||||
const wallet = await xrpl.Wallet.fromSeed(seed);
|
||||
console.log("Wallet Address: ", wallet.address);
|
||||
console.log("Seed: ", seed);
|
||||
const escrowCreate = {
|
||||
TransactionType: 'EscrowCreate',
|
||||
Account: wallet.address,
|
||||
Destination: destinationAddress,
|
||||
Amount: '123456',
|
||||
Condition: conditionHex,
|
||||
CancelAfter: cancelAfterRippleTime
|
||||
}
|
||||
validate(escrowCreate)
|
||||
|
||||
// Construct the escrow cancel transaction ------------------------------------
|
||||
console.log('Signing and submitting the EscrowCreate transaction.')
|
||||
const response = await client.submitAndWait(escrowCreate, {
|
||||
wallet,
|
||||
autofill: true // Note: fee is higher based on condition size in bytes
|
||||
})
|
||||
console.log(JSON.stringify(response.result, null, 2))
|
||||
const escrowCreateResultCode = response.result.meta.TransactionResult
|
||||
if (escrowCreateResultCode !== 'tesSUCCESS') {
|
||||
console.error(`EscrowCreate failed with code ${escrowCreateResultCode}.`)
|
||||
client.disconnect()
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
if(!sequenceNumber){
|
||||
throw new Error("Please specify the sequence number of the escrow you created");
|
||||
};
|
||||
// Wait for the escrow to expire -----------------------------------------------
|
||||
// Since ledger close times can be rounded by up to 10 seconds, wait an extra
|
||||
// 10 seconds to make sure the escrow has officially expired.
|
||||
console.log(`Waiting ${cancelDelay + 10} seconds for the escrow to expire...`)
|
||||
await sleep(cancelDelay + 10)
|
||||
|
||||
const escrowCancelTransaction = {
|
||||
"Account": wallet.address,
|
||||
"TransactionType": "EscrowCancel",
|
||||
"Owner": wallet.address,
|
||||
"OfferSequence": sequenceNumber, // Sequence number
|
||||
};
|
||||
/* Sleep function that can be used with await */
|
||||
function sleep (delayInSeconds) {
|
||||
const delayInMs = delayInSeconds * 1000
|
||||
return new Promise((resolve) => setTimeout(resolve, delayInMs))
|
||||
}
|
||||
|
||||
xrpl.validate(escrowCancelTransaction);
|
||||
// Look up the official close time of the validated ledger ---------------------
|
||||
const ledger = await client.request({
|
||||
command: 'ledger',
|
||||
ledger_index: 'validated'
|
||||
})
|
||||
if (ledger.error) {
|
||||
console.error(`Error looking up validated ledger: ${ledger.error}`)
|
||||
client.disconnect()
|
||||
process.exit(1)
|
||||
}
|
||||
const closeTime = ledger.result.ledger.close_time
|
||||
console.log('Latest validated ledger closed at',
|
||||
rippleTimeToISOTime(closeTime)
|
||||
)
|
||||
const ledgerHash = ledger.result.ledger.ledger_hash
|
||||
|
||||
// Sign and submit the transaction --------------------------------------------
|
||||
console.log('Signing and submitting the transaction: ', JSON.stringify(escrowCancelTransaction, null, "\t"));
|
||||
const response = await client.submitAndWait(escrowCancelTransaction, { wallet });
|
||||
console.log(`Finished submitting! \n${JSON.stringify(response.result, null, "\t")}`);
|
||||
// Look up escrows connected to the account, handling pagination ---------------
|
||||
let marker
|
||||
let expiredEscrow
|
||||
while (true) {
|
||||
console.log(`Requesting page of account_objects with marker ${marker}`)
|
||||
const resp = await client.request({
|
||||
command: 'account_objects',
|
||||
account: wallet.address,
|
||||
ledger_hash: ledgerHash,
|
||||
type: 'escrow',
|
||||
marker
|
||||
})
|
||||
if (resp.error) {
|
||||
console.error('account_objects failed with error', resp)
|
||||
client.disconnect()
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
await client.disconnect();
|
||||
// Add new escrows to the full list
|
||||
for (const escrow of resp.result.account_objects) {
|
||||
if (!escrow.hasOwnProperty('CancelAfter')) {
|
||||
console.log('This escrow does not have an expiration.')
|
||||
} else if (escrow.CancelAfter < closeTime) {
|
||||
console.log('This escrow has expired.')
|
||||
expiredEscrow = escrow
|
||||
break
|
||||
} else {
|
||||
const expirationTime = rippleTimeToISOTime(escrow.CancelAfter)
|
||||
console.log('This escrow expires at', expirationTime)
|
||||
}
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
if (expiredEscrow) {
|
||||
// Found an expired escrow, stop paginating
|
||||
break
|
||||
}
|
||||
|
||||
// If there's a marker, loop and fetch the next page of results
|
||||
if (resp.result.marker) {
|
||||
marker = resp.result.marker
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
main()
|
||||
if (!expiredEscrow) {
|
||||
console.error('Did not find any expired escrows.')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
// Find the sequence number of the expired escrow ------------------------------
|
||||
let escrow_seq
|
||||
const txResp = await client.request({
|
||||
command: 'tx',
|
||||
transaction: expiredEscrow.PreviousTxnID
|
||||
})
|
||||
if (txResp.error) {
|
||||
console.error("Couldn't get transaction. Maybe this server doesn't have",
|
||||
'enough transaction history available?')
|
||||
client.disconnect()
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
if (txResp.result.tx_json.TransactionType === 'EscrowCreate') {
|
||||
// Save this sequence number for canceling the escrow
|
||||
escrow_seq = txResp.result.tx_json.Sequence
|
||||
if (escrow_seq === 0) {
|
||||
// This transaction used a Ticket, so use TicketSequence instead.
|
||||
escrow_seq = response.result.tx_json.TicketSequence
|
||||
}
|
||||
} else {
|
||||
console.error("This escrow's previous transaction wasn't EscrowCreate!")
|
||||
client.disconnect()
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
// Send EscrowCancel transaction -----------------------------------------------
|
||||
const escrowCancel = {
|
||||
TransactionType: 'EscrowCancel',
|
||||
Account: wallet.address,
|
||||
Owner: expiredEscrow.Account,
|
||||
OfferSequence: escrow_seq
|
||||
}
|
||||
validate(escrowCancel)
|
||||
|
||||
console.log('Signing and submitting the EscrowCancel transaction.')
|
||||
const cancelResponse = await client.submitAndWait(escrowCancel, {
|
||||
wallet,
|
||||
autofill: true
|
||||
})
|
||||
console.log(JSON.stringify(cancelResponse.result, null, 2))
|
||||
const cancelResultCode = cancelResponse.result.meta.TransactionResult
|
||||
if (cancelResultCode !== 'tesSUCCESS') {
|
||||
console.error(`EscrowCancel failed with result code ${cancelResultCode}`)
|
||||
client.disconnect()
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
console.log('Escrow canceled. Balance changes:')
|
||||
console.log(JSON.stringify(getBalanceChanges(cancelResponse.result.meta), null, 2))
|
||||
|
||||
client.disconnect()
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
'use strict'
|
||||
const xrpl = require('xrpl');
|
||||
const cc = require('five-bells-condition');
|
||||
const crypto = require('crypto');
|
||||
|
||||
// Useful Documentation:-
|
||||
// 1. five-bells-condition: https://www.npmjs.com/package/five-bells-condition
|
||||
// 2. Crypto module: https://nodejs.org/api/crypto.html
|
||||
|
||||
// Your seed value, for testing purposes you can make one with the faucet:
|
||||
// https://xrpl.org/resources/dev-tools/xrp-faucets
|
||||
const seed = "sEd7jfWyNG6J71dEojB3W9YdHp2KCjy";
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
|
||||
// Connect ----------------------------------------------------------------
|
||||
const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233');
|
||||
await client.connect();
|
||||
|
||||
// Prepare wallet to sign the transaction ---------------------------------
|
||||
const wallet = await xrpl.Wallet.fromSeed(seed);
|
||||
console.log("Wallet Address: ", wallet.address);
|
||||
console.log("Seed: ", seed);
|
||||
|
||||
// Set the escrow finish time ---------------------------------------------
|
||||
let finishAfter = new Date((new Date().getTime() / 1000) + 120); // 2 minutes from now
|
||||
finishAfter = new Date(finishAfter * 1000);
|
||||
console.log("This escrow will finish after: ", finishAfter);
|
||||
|
||||
// Construct condition and fulfillment ------------------------------------
|
||||
const preimageData = crypto.randomBytes(32);
|
||||
const myFulfillment = new cc.PreimageSha256();
|
||||
myFulfillment.setPreimage(preimageData);
|
||||
const conditionHex = myFulfillment.getConditionBinary().toString('hex').toUpperCase();
|
||||
|
||||
console.log('Condition:', conditionHex);
|
||||
console.log('Fulfillment:', myFulfillment.serializeBinary().toString('hex').toUpperCase());
|
||||
|
||||
// Prepare EscrowCreate transaction ------------------------------------
|
||||
const escrowCreateTransaction = {
|
||||
"TransactionType": "EscrowCreate",
|
||||
"Account": wallet.address,
|
||||
"Destination": wallet.address,
|
||||
"Amount": "6000000", //drops XRP
|
||||
"DestinationTag": 2023,
|
||||
"Condition": conditionHex, // Omit this for time-held escrows
|
||||
"Fee": "12",
|
||||
"FinishAfter": xrpl.isoTimeToRippleTime(finishAfter.toISOString()),
|
||||
};
|
||||
|
||||
xrpl.validate(escrowCreateTransaction);
|
||||
|
||||
// Sign and submit the transaction ----------------------------------------
|
||||
console.log('Signing and submitting the transaction:',
|
||||
JSON.stringify(escrowCreateTransaction, null, "\t"), "\n"
|
||||
);
|
||||
const response = await client.submitAndWait(escrowCreateTransaction, { wallet });
|
||||
console.log(`Sequence number: ${response.result.tx_json.Sequence}`);
|
||||
console.log(`Finished submitting! ${JSON.stringify(response.result, null, "\t")}`);
|
||||
|
||||
await client.disconnect();
|
||||
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
main()
|
||||
@@ -1,60 +0,0 @@
|
||||
'use strict'
|
||||
const xrpl = require('xrpl')
|
||||
|
||||
// Preqrequisites:
|
||||
// 1. Create an escrow using the create-escrow.js snippet
|
||||
// 2. Replace the OfferSequence with the sequence number of the escrow you created
|
||||
// 3. Replace the Condition and Fulfillment with the values from the escrow you created
|
||||
// 4. Paste the seed of the account that created the escrow
|
||||
// 5. Run the snippet
|
||||
|
||||
const seed = "sEd7jfWyNG6J71dEojB3W9YdHp2KCjy"; // Test seed. Don't use
|
||||
const offerSequence = null;
|
||||
const condition = "";
|
||||
const fulfillment = "";
|
||||
|
||||
const main = async () => {
|
||||
try {
|
||||
// Connect ----------------------------------------------------------------
|
||||
const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233');
|
||||
await client.connect();
|
||||
|
||||
// Prepare wallet to sign the transaction ---------------------------------
|
||||
const wallet = await xrpl.Wallet.fromSeed(seed);
|
||||
console.log("Wallet Address: ", wallet.address);
|
||||
console.log("Seed: ", seed);
|
||||
|
||||
if((!offerSequence)|| (condition === "" || fulfillment === "")){
|
||||
throw new Error("Please specify the sequence number, condition and fulfillment of the escrow you created");
|
||||
};
|
||||
|
||||
// Prepare EscrowFinish transaction ---------------------------------
|
||||
const escrowFinishTransaction = {
|
||||
"Account": wallet.address,
|
||||
"TransactionType": "EscrowFinish",
|
||||
"Owner": wallet.address,
|
||||
// This should equal the sequence number of the escrow transaction
|
||||
"OfferSequence": offerSequence,
|
||||
// Crypto condition that must be met before escrow can be completed, passed on escrow creation.
|
||||
// Omit this for time-held escrows.
|
||||
"Condition": condition,
|
||||
// Fulfillment of the condition, passed on escrow creation.
|
||||
// Omit this for time-held escrows.
|
||||
"Fulfillment": fulfillment,
|
||||
};
|
||||
|
||||
xrpl.validate(escrowFinishTransaction);
|
||||
|
||||
// Sign and submit the transaction ----------------------------------------
|
||||
console.log('Signing and submitting the transaction:', JSON.stringify(escrowFinishTransaction, null, "\t"));
|
||||
const response = await client.submitAndWait(escrowFinishTransaction, { wallet });
|
||||
console.log(`Finished submitting! ${JSON.stringify(response.result, null, "\t")}`);
|
||||
|
||||
await client.disconnect();
|
||||
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
main()
|
||||
@@ -1,54 +1,114 @@
|
||||
const xrpl = require('xrpl')
|
||||
import { Client, dropsToXrp, rippleTimeToISOTime } from 'xrpl'
|
||||
|
||||
// List the Escrows on an existing account filtered by source and destination
|
||||
// https://xrpl.org/escrow.html#escrow
|
||||
// https://xrpl.org/account_objects.html#account_objects
|
||||
|
||||
async function main() {
|
||||
// Testnet example: rPRKeXbcFMcn69nR2bovp4bEcP8kZx7x5i
|
||||
account = "rPRKeXbcFMcn69nR2bovp4bEcP8kZx7x5i"
|
||||
|
||||
// Connect to a testnet node
|
||||
console.log("Connecting to Testnet...")
|
||||
const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233/')
|
||||
// Set up client and address
|
||||
const address = 'rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn'
|
||||
console.log('Connecting to Mainnet...')
|
||||
const client = new Client('wss://xrplcluster.com/')
|
||||
await client.connect()
|
||||
|
||||
const response = await client.request({
|
||||
"command": "account_objects",
|
||||
"account": account,
|
||||
"ledger_index": "validated",
|
||||
"type": "escrow"
|
||||
// Look up the official close time of the validated ledger ---------------------
|
||||
const ledger = await client.request({
|
||||
command: 'ledger',
|
||||
ledger_index: 'validated'
|
||||
})
|
||||
if (ledger.error) {
|
||||
console.error(`Error looking up validated ledger: ${ledger.error}`)
|
||||
client.disconnect()
|
||||
process.exit(1)
|
||||
}
|
||||
const close_time = ledger.result.ledger.close_time
|
||||
const ledger_hash = ledger.result.ledger.ledger_hash
|
||||
|
||||
var incoming = []
|
||||
var outgoing = []
|
||||
// Look up objects filtered to escrows, handling pagination --------------------
|
||||
let marker
|
||||
const escrows = []
|
||||
while (true) {
|
||||
console.log(`Requesting page of account_objects with marker ${marker}`)
|
||||
const resp = await client.request({
|
||||
command: 'account_objects',
|
||||
account: address,
|
||||
ledger_hash, // Caution: if you use a shortcut
|
||||
// such as "validated", the ledger may
|
||||
// change during iteration, leading to
|
||||
// inconsistent results.
|
||||
type: 'escrow',
|
||||
marker
|
||||
})
|
||||
if (resp.error) {
|
||||
console.error('account_objects failed with error', resp)
|
||||
client.disconnect()
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
for (var i = 0; i < response.result.account_objects.length; i++) {
|
||||
if (response.result.account_objects[i].Account == account) {
|
||||
outgoing.push(response.result.account_objects[i])
|
||||
// Add new escrows to the full list
|
||||
for (const escrow of resp.result.account_objects) {
|
||||
escrows.push(escrow)
|
||||
}
|
||||
|
||||
// If there's a marker, loop and fetch the next page of results
|
||||
if (resp.result.marker) {
|
||||
marker = resp.result.marker
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Define helper function for displaying amounts -------------------------------
|
||||
function display_amount (amount) {
|
||||
if (typeof amount === 'string') {
|
||||
// amount is drops of XRP.
|
||||
const decimal_xrp = dropsToXrp(amount)
|
||||
return `${decimal_xrp} XRP`
|
||||
} else if (amount.hasOwnProperty('mpt_issuance_id')) {
|
||||
// amount is an MPT.
|
||||
// More info may be available, but that would require looking it up.
|
||||
return `${amount.value} units of MPT ${amount.mpt_issuance_id}`
|
||||
} else if (amount.hasOwnProperty('issuer')) {
|
||||
// amount is a trust line token.
|
||||
// Currency may be 3 chars or hex. For guidelines parsing hex codes,
|
||||
// see "Normalize Currency Codes" code sample.
|
||||
return `${amount.value} ${amount.currency} issued by ${amount.issuer}`
|
||||
}
|
||||
console.error(`Unexpected type of amount: ${amount}`)
|
||||
client.disconnect()
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
// Summarize results -----------------------------------------------------------
|
||||
console.log(`Found ${escrows.length} escrow(s).`)
|
||||
|
||||
for (const escrow of escrows) {
|
||||
if (escrow.Account === address) {
|
||||
console.log(`Outgoing escrow to ${escrow.Destination}`)
|
||||
} else if (escrow.Destination === address) {
|
||||
console.log(`Incoming escrow from ${escrow.Account}`)
|
||||
} else {
|
||||
console.log('Neither incoming nor outgoing? This is unexexpected.')
|
||||
}
|
||||
|
||||
console.log(` Amount: ${display_amount(escrow.Amount)}`)
|
||||
|
||||
if (escrow.hasOwnProperty('Condition')) {
|
||||
console.log(` Condition: ${escrow.Condition}`)
|
||||
}
|
||||
|
||||
if (escrow.FinishAfter) {
|
||||
const mature_time_display = rippleTimeToISOTime(escrow.FinishAfter)
|
||||
if (escrow.FinishAfter < close_time) {
|
||||
console.log(` Matured at ${mature_time_display}`)
|
||||
} else {
|
||||
incoming.push(response.result.account_objects[i])
|
||||
console.log(` Will mature at ${mature_time_display}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log("\nIncoming/Received escrow(s):")
|
||||
for (var i = 0; i < incoming.length; i++) {
|
||||
console.log(`\n${i+1}. Index (ObjectID/keylet): ${incoming[i].index}`)
|
||||
console.log(` - Account: ${incoming[i].Account})`)
|
||||
console.log(` - Destination: ${incoming[i].Destination}`)
|
||||
console.log(` - Amount: ${incoming[i].Amount} drops`)
|
||||
}
|
||||
|
||||
console.log("\nOutgoing/Sent escrow(s):")
|
||||
for (var i = 0; i < outgoing.length; i++) {
|
||||
console.log(`\n${i+1}. Index (ObjectID/keylet): ${outgoing[i].index}`)
|
||||
console.log(` - Account: ${outgoing[i].Account})`)
|
||||
console.log(` - Destination: ${outgoing[i].Destination}`)
|
||||
console.log(` - Amount: ${outgoing[i].Amount} drops`)
|
||||
if (escrow.hasOwnProperty('CancelAfter')) {
|
||||
const cancel_time_display = rippleTimeToISOTime(escrow.CancelAfter)
|
||||
if (escrow.CancelAfter < close_time) {
|
||||
console.log(` EXPIRED at ${cancel_time_display}`)
|
||||
} else {
|
||||
console.log(` Expires at ${cancel_time_display}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
client.disconnect()
|
||||
// End main()
|
||||
}
|
||||
|
||||
main()
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
const cc = require('five-bells-condition')
|
||||
const crypto = require('crypto')
|
||||
|
||||
const preimageData = crypto.randomBytes(32)
|
||||
const myFulfillment = new cc.PreimageSha256()
|
||||
myFulfillment.setPreimage(preimageData)
|
||||
|
||||
console.log('Condition:', myFulfillment.getConditionBinary().toString('hex').toUpperCase())
|
||||
console.log('Fulfillment:', myFulfillment.serializeBinary().toString('hex').toUpperCase())
|
||||
@@ -1,9 +1,10 @@
|
||||
{
|
||||
"name": "escrow-examples",
|
||||
"version": "0.0.3",
|
||||
"version": "2.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"five-bells-condition": "*",
|
||||
"xrpl": "^4.0.0"
|
||||
}
|
||||
"xrpl": "^4.4.0"
|
||||
},
|
||||
"type": "module"
|
||||
}
|
||||
|
||||
89
_code-samples/escrow/js/send-conditional-escrow.js
Normal file
89
_code-samples/escrow/js/send-conditional-escrow.js
Normal file
@@ -0,0 +1,89 @@
|
||||
import xrpl from 'xrpl'
|
||||
import { PreimageSha256 } from 'five-bells-condition'
|
||||
import { randomBytes } from 'crypto'
|
||||
|
||||
const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233')
|
||||
await client.connect()
|
||||
|
||||
console.log('Funding new wallet from faucet...')
|
||||
const { wallet } = await client.fundWallet()
|
||||
// const destination_address = 'rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe' // Testnet faucet
|
||||
// Alternative: Get another account to send the escrow to. Use this if you get
|
||||
// a tecDIR_FULL error trying to create escrows to the Testnet faucet.
|
||||
const destination_address = (await client.fundWallet()).wallet.address
|
||||
|
||||
// Create the crypto-condition for release ----------------------------------
|
||||
const preimage = randomBytes(32)
|
||||
const fulfillment = new PreimageSha256()
|
||||
fulfillment.setPreimage(preimage)
|
||||
const fulfillmentHex = fulfillment.serializeBinary().toString('hex').toUpperCase()
|
||||
const conditionHex = fulfillment.getConditionBinary().toString('hex').toUpperCase()
|
||||
console.log('Condition:', conditionHex)
|
||||
console.log('Fulfillment:', fulfillmentHex)
|
||||
|
||||
// Set the escrow expiration ------------------------------------------------
|
||||
const cancelDelay = 300 // Seconds in the future when the escrow should expire
|
||||
const cancelAfter = new Date() // Current time
|
||||
cancelAfter.setSeconds(cancelAfter.getSeconds() + cancelDelay)
|
||||
console.log('This escrow will expire after:', cancelAfter)
|
||||
// Convert cancelAfter to seconds since the Ripple Epoch:
|
||||
const cancelAfterRippleTime = xrpl.isoTimeToRippleTime(cancelAfter.toISOString())
|
||||
|
||||
// Send EscrowCreate transaction --------------------------------------------
|
||||
const escrowCreate = {
|
||||
TransactionType: 'EscrowCreate',
|
||||
Account: wallet.address,
|
||||
Destination: destination_address,
|
||||
Amount: '123456', // drops of XRP
|
||||
Condition: conditionHex,
|
||||
CancelAfter: cancelAfterRippleTime
|
||||
}
|
||||
xrpl.validate(escrowCreate)
|
||||
|
||||
console.log('Signing and submitting the transaction:',
|
||||
JSON.stringify(escrowCreate, null, 2))
|
||||
const response = await client.submitAndWait(escrowCreate, {
|
||||
wallet,
|
||||
autofill: true // Note: fee is higher based on condition size in bytes
|
||||
})
|
||||
|
||||
// Check result of submitting -----------------------------------------------
|
||||
console.log(JSON.stringify(response.result, null, 2))
|
||||
const escrowCreateResultCode = response.result.meta.TransactionResult
|
||||
if (escrowCreateResultCode === 'tesSUCCESS') {
|
||||
console.log('Escrow created successfully.')
|
||||
} else {
|
||||
console.error(`EscrowCreate failed with code ${escrowCreateResultCode}.`)
|
||||
client.disconnect()
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
// Save the sequence number so you can identify the escrow later.
|
||||
const escrowSeq = response.result.tx_json.Sequence
|
||||
console.log(`Escrow sequence is ${escrowSeq}.`)
|
||||
|
||||
// Send EscrowFinish transaction --------------------------------------------
|
||||
const escrowFinish = {
|
||||
TransactionType: 'EscrowFinish',
|
||||
Account: wallet.address,
|
||||
Owner: wallet.address,
|
||||
OfferSequence: escrowSeq,
|
||||
Condition: conditionHex,
|
||||
Fulfillment: fulfillmentHex
|
||||
}
|
||||
xrpl.validate(escrowFinish)
|
||||
|
||||
console.log('Signing and submitting the transaction:',
|
||||
JSON.stringify(escrowFinish, null, 2))
|
||||
const response2 = await client.submitAndWait(escrowFinish, {
|
||||
wallet,
|
||||
autofill: true // Note: fee is higher based on fulfillment size in bytes
|
||||
})
|
||||
console.log(JSON.stringify(response2.result, null, 2))
|
||||
if (response2.result.meta.TransactionResult === 'tesSUCCESS') {
|
||||
console.log('Escrow finished successfully.')
|
||||
} else {
|
||||
console.log(`Failed with result code ${response2.result.meta.TransactionResult}`)
|
||||
}
|
||||
|
||||
client.disconnect()
|
||||
108
_code-samples/escrow/js/send-timed-escrow.js
Normal file
108
_code-samples/escrow/js/send-timed-escrow.js
Normal file
@@ -0,0 +1,108 @@
|
||||
import xrpl from 'xrpl'
|
||||
|
||||
const client = new xrpl.Client('wss://s.altnet.rippletest.net:51233')
|
||||
await client.connect()
|
||||
|
||||
console.log('Funding new wallet from faucet...')
|
||||
const { wallet } = await client.fundWallet()
|
||||
// const destination_address = 'rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe' // Testnet faucet
|
||||
// Alternative: Get another account to send the escrow to. Use this if you get
|
||||
// a tecDIR_FULL error trying to create escrows to the Testnet faucet.
|
||||
const destination_address = (await client.fundWallet()).wallet.address
|
||||
|
||||
// Set the escrow finish time -----------------------------------------------
|
||||
const delay = 30 // Seconds in the future when the escrow should mature
|
||||
const finishAfter = new Date() // Current time
|
||||
finishAfter.setSeconds(finishAfter.getSeconds() + delay)
|
||||
console.log('This escrow will finish after:', finishAfter)
|
||||
// Convert finishAfter to seconds since the Ripple Epoch:
|
||||
const finishAfterRippleTime = xrpl.isoTimeToRippleTime(finishAfter.toISOString())
|
||||
|
||||
// Send EscrowCreate transaction --------------------------------------------
|
||||
const escrowCreate = {
|
||||
TransactionType: 'EscrowCreate',
|
||||
Account: wallet.address,
|
||||
Destination: destination_address,
|
||||
Amount: '123456', // drops of XRP
|
||||
FinishAfter: finishAfterRippleTime
|
||||
}
|
||||
xrpl.validate(escrowCreate)
|
||||
|
||||
console.log('Signing and submitting the transaction:',
|
||||
JSON.stringify(escrowCreate, null, 2))
|
||||
const response = await client.submitAndWait(escrowCreate, {
|
||||
wallet,
|
||||
autofill: true
|
||||
})
|
||||
console.log(JSON.stringify(response.result, null, 2))
|
||||
const escrowCreateResultCode = response.result.meta.TransactionResult
|
||||
if (escrowCreateResultCode === 'tesSUCCESS') {
|
||||
console.log('Escrow created successfully.')
|
||||
} else {
|
||||
console.error(`EscrowCreate failed with code ${escrowCreateResultCode}.`)
|
||||
client.disconnect()
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
// Save the sequence number so you can identify the escrow later.
|
||||
const escrowSeq = response.result.tx_json.Sequence
|
||||
console.log(`Escrow sequence is ${escrowSeq}.`)
|
||||
|
||||
// Wait for the escrow to be finishable -------------------------------------
|
||||
console.log(`Waiting ${delay} seconds for the escrow to mature...`)
|
||||
await sleep(delay)
|
||||
|
||||
/* Sleep function that can be used with await */
|
||||
function sleep (delayInSeconds) {
|
||||
const delayInMs = delayInSeconds * 1000
|
||||
return new Promise((resolve) => setTimeout(resolve, delayInMs))
|
||||
}
|
||||
|
||||
// Check if escrow can be finished -------------------------------------------
|
||||
let escrowReady = false
|
||||
while (!escrowReady) {
|
||||
// Check the close time of the latest validated ledger.
|
||||
// Close times are rounded by about 10 seconds, so the exact time the escrow
|
||||
// is ready to finish may vary by +/- 10 seconds.
|
||||
const validatedLedger = await client.request({
|
||||
command: 'ledger',
|
||||
ledger_index: 'validated'
|
||||
})
|
||||
const ledgerCloseTime = validatedLedger.result.ledger.close_time
|
||||
console.log('Latest validated ledger closed at',
|
||||
xrpl.rippleTimeToISOTime(ledgerCloseTime))
|
||||
if (ledgerCloseTime > finishAfterRippleTime) {
|
||||
escrowReady = true
|
||||
console.log('Escrow is mature.')
|
||||
} else {
|
||||
let timeDifference = finishAfterRippleTime - ledgerCloseTime
|
||||
if (timeDifference === 0) { timeDifference = 1 }
|
||||
console.log(`Waiting another ${timeDifference} second(s).`)
|
||||
await sleep(timeDifference)
|
||||
}
|
||||
}
|
||||
|
||||
// Send EscrowFinish transaction --------------------------------------------
|
||||
const escrowFinish = {
|
||||
TransactionType: 'EscrowFinish',
|
||||
Account: wallet.address,
|
||||
Owner: wallet.address,
|
||||
OfferSequence: escrowSeq
|
||||
}
|
||||
xrpl.validate(escrowFinish)
|
||||
|
||||
console.log('Signing and submitting the transaction:',
|
||||
JSON.stringify(escrowFinish, null, 2))
|
||||
const response2 = await client.submitAndWait(escrowFinish, {
|
||||
wallet,
|
||||
autofill: true
|
||||
})
|
||||
console.log(JSON.stringify(response2.result, null, 2))
|
||||
if (response2.result.meta.TransactionResult === 'tesSUCCESS') {
|
||||
console.log('Escrow finished successfully. Balance changes:')
|
||||
console.log(
|
||||
JSON.stringify(xrpl.getBalanceChanges(response2.result.meta), null, 2)
|
||||
)
|
||||
}
|
||||
|
||||
client.disconnect()
|
||||
@@ -1,31 +1,136 @@
|
||||
import json
|
||||
from datetime import datetime, timedelta, UTC
|
||||
from time import sleep
|
||||
|
||||
from xrpl.clients import JsonRpcClient
|
||||
from xrpl.models import EscrowCancel
|
||||
from xrpl.models import EscrowCreate, EscrowCancel
|
||||
from xrpl.models.requests import AccountObjects, Ledger, Tx
|
||||
from xrpl.transaction import submit_and_wait
|
||||
from xrpl.utils import datetime_to_ripple_time, ripple_time_to_datetime, get_balance_changes
|
||||
from xrpl.wallet import generate_faucet_wallet
|
||||
|
||||
client = JsonRpcClient("https://s.altnet.rippletest.net:51234") # Connect to the testnetwork
|
||||
# Set up client and get a wallet
|
||||
client = JsonRpcClient("https://s.altnet.rippletest.net:51234")
|
||||
print("Funding new wallet from faucet...")
|
||||
wallet = generate_faucet_wallet(client, debug=True)
|
||||
# destination_address = "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe" # Testnet faucet
|
||||
# Alternative: Get another account to send the escrow to. Use this if you get
|
||||
# a tecDIR_FULL error trying to create escrows to the Testnet faucet.
|
||||
destination_address = generate_faucet_wallet(client, debug=True).address
|
||||
|
||||
# Cancel an escrow
|
||||
# An Escrow can only be canceled if it was created with a CancelAfter time
|
||||
|
||||
escrow_sequence = 30215126
|
||||
|
||||
# Sender wallet object
|
||||
sender_wallet = generate_faucet_wallet(client=client)
|
||||
|
||||
# Build escrow cancel transaction
|
||||
cancel_txn = EscrowCancel(
|
||||
account=sender_wallet.address,
|
||||
owner=sender_wallet.address,
|
||||
offer_sequence=escrow_sequence
|
||||
# Create an escrow that won't be finished --------------------------------------
|
||||
cancel_delay = 30
|
||||
cancel_after = datetime.now(tz=UTC) + timedelta(seconds=cancel_delay)
|
||||
print("This escrow will expire after", cancel_after)
|
||||
cancel_after_rippletime = datetime_to_ripple_time(cancel_after)
|
||||
# Use a crypto-condition that nobody knows the fulfillment for
|
||||
condition_hex = "A02580200000000000000000000000000000000000000000000000000000000000000000810120"
|
||||
escrow_create = EscrowCreate(
|
||||
account=wallet.address,
|
||||
destination=destination_address,
|
||||
amount="123456", # drops of XRP
|
||||
condition=condition_hex,
|
||||
cancel_after=cancel_after_rippletime
|
||||
)
|
||||
print("Signing and submitting the EscrowCreate transaction.")
|
||||
response = submit_and_wait(escrow_create, client, wallet, autofill=True)
|
||||
print(json.dumps(response.result, indent=2))
|
||||
|
||||
# Autofill, sign, then submit transaction and wait for result
|
||||
stxn_response = submit_and_wait(cancel_txn, client, sender_wallet)
|
||||
result_code = response.result["meta"]["TransactionResult"]
|
||||
if result_code != "tesSUCCESS":
|
||||
print(f"EscrowCreate failed with result code {result_code}")
|
||||
exit(1)
|
||||
|
||||
# Parse response and return result
|
||||
stxn_result = stxn_response.result
|
||||
# Wait for the escrow to expire ------------------------------------------------
|
||||
# Since ledger close times can be rounded by up to 10 seconds, wait an extra
|
||||
# 10 seconds to make sure the escrow has officially expired.
|
||||
print(f"Waiting {cancel_delay + 10} seconds for the escrow to expire.")
|
||||
sleep(cancel_delay + 10)
|
||||
|
||||
# Parse result and print out the transaction result and transaction hash
|
||||
print(stxn_result["meta"]["TransactionResult"])
|
||||
print(stxn_result["hash"])
|
||||
# Look up the official close time of the validated ledger ----------------------
|
||||
validated_ledger = client.request(Ledger(ledger_index="validated"))
|
||||
close_time = validated_ledger.result["ledger"]["close_time"]
|
||||
print("Latest validated ledger closed at",
|
||||
ripple_time_to_datetime(close_time)
|
||||
)
|
||||
ledger_hash = validated_ledger.result["ledger"]["ledger_hash"]
|
||||
|
||||
# Look up escrows connected to the account, handling pagination ----------------
|
||||
expired_escrow = None
|
||||
marker = None
|
||||
while True:
|
||||
try:
|
||||
response = client.request(AccountObjects(
|
||||
account=wallet.address,
|
||||
ledger_hash=ledger_hash,
|
||||
type="escrow",
|
||||
marker=marker
|
||||
))
|
||||
except Exception as e:
|
||||
print(f"Error: account_objects failed: {e}")
|
||||
exit(1)
|
||||
|
||||
for escrow in response.result["account_objects"]:
|
||||
if "CancelAfter" not in escrow:
|
||||
print("This escrow does not have an expiration")
|
||||
elif escrow["CancelAfter"] < close_time:
|
||||
print("This escrow has expired.")
|
||||
expired_escrow = escrow
|
||||
break
|
||||
else:
|
||||
expiration_time = ripple_time_to_datetime(escrow["CancelAfter"])
|
||||
print(f"This escrow expires at {expiration_time}.")
|
||||
|
||||
if expired_escrow:
|
||||
# Found an expired escrow, stop paginating
|
||||
break
|
||||
|
||||
if "marker" in response.result.keys():
|
||||
marker=marker
|
||||
else:
|
||||
# This is the last page of results
|
||||
break
|
||||
|
||||
if not expired_escrow:
|
||||
print("Did not find any expired escrows.")
|
||||
exit(1)
|
||||
|
||||
# Find the sequence number of the expired escrow -------------------------------
|
||||
response = client.request(Tx(transaction=expired_escrow["PreviousTxnID"]))
|
||||
if not response.is_successful():
|
||||
print("Couldn't get transaction. Maybe this server doesn't have enough "
|
||||
"transaction history available?")
|
||||
exit(1)
|
||||
|
||||
if response.result["tx_json"]["TransactionType"] == "EscrowCreate":
|
||||
# Save this sequence number for canceling the escrow
|
||||
escrow_seq = response.result["tx_json"]["Sequence"]
|
||||
if escrow_seq == 0:
|
||||
# This transaction used a Ticket, so use the TicketSequence instead.
|
||||
escrow_seq = response.result["tx_json"]["TicketSequence"]
|
||||
else:
|
||||
# Currently, this is impossible since no current transaction can update
|
||||
# an escrow without finishing or canceling it. But in the future, if
|
||||
# that becomes possible, you would have to look at the transaction
|
||||
# metadata to find the previous transaction and repeat until you found
|
||||
# the transaction that created the escrow.
|
||||
print("The escrow's previous transaction wasn't EscrowCreate!")
|
||||
exit(1)
|
||||
|
||||
# Send EscrowCancel transaction ------------------------------------------------
|
||||
escrow_cancel = EscrowCancel(
|
||||
account=wallet.address,
|
||||
owner=expired_escrow["Account"],
|
||||
offer_sequence=escrow_seq
|
||||
)
|
||||
print("Signing and submitting the EscrowCancel transaction.")
|
||||
response2 = submit_and_wait(escrow_cancel, client, wallet, autofill=True)
|
||||
print(json.dumps(response2.result, indent=2))
|
||||
|
||||
result_code = response2.result["meta"]["TransactionResult"]
|
||||
if result_code != "tesSUCCESS":
|
||||
print(f"EscrowCancel failed with result code {result_code}")
|
||||
exit(1)
|
||||
|
||||
print("Escrow canceled. Balance changes:")
|
||||
print(json.dumps(get_balance_changes(response2.result["meta"]), indent=2))
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from xrpl.clients import JsonRpcClient
|
||||
from xrpl.models import EscrowCreate
|
||||
from xrpl.transaction import submit_and_wait
|
||||
from xrpl.utils import datetime_to_ripple_time, xrp_to_drops
|
||||
from xrpl.wallet import generate_faucet_wallet
|
||||
|
||||
# Create Escrow
|
||||
|
||||
client = JsonRpcClient("https://s.altnet.rippletest.net:51234") # Connect to client
|
||||
|
||||
amount_to_escrow = 10.000
|
||||
|
||||
receiver_addr = "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe" # Example: send back to Testnet Faucet
|
||||
|
||||
# Escrow will be available to claim after 3 days
|
||||
claim_date = datetime_to_ripple_time(datetime.now() + timedelta(days=3))
|
||||
|
||||
# Escrow will expire after 5 days
|
||||
expiry_date = datetime_to_ripple_time(datetime.now() + timedelta(days=5))
|
||||
|
||||
# Optional field
|
||||
# You can optionally use a Crypto Condition to allow for dynamic release of funds. For example:
|
||||
condition = "A02580205A0E9E4018BE1A6E0F51D39B483122EFDF1DDEF3A4BE83BE71522F9E8CDAB179810120" # do not use in production
|
||||
|
||||
# sender wallet object
|
||||
sender_wallet = generate_faucet_wallet(client=client)
|
||||
|
||||
# Build escrow create transaction
|
||||
create_txn = EscrowCreate(
|
||||
account=sender_wallet.address,
|
||||
amount=xrp_to_drops(amount_to_escrow),
|
||||
destination=receiver_addr,
|
||||
finish_after=claim_date,
|
||||
cancel_after=expiry_date,
|
||||
condition=condition # Omit this for time-held escrows
|
||||
)
|
||||
|
||||
# Autofill, sign, then submit transaction and wait for result
|
||||
stxn_response = submit_and_wait(create_txn, client, sender_wallet)
|
||||
|
||||
# Return result of transaction
|
||||
stxn_result = stxn_response.result
|
||||
|
||||
|
||||
# Parse result and print out the neccesary info
|
||||
print(stxn_result["tx_json"]["Account"])
|
||||
print(stxn_result["tx_json"]["Sequence"])
|
||||
|
||||
print(stxn_result["meta"]["TransactionResult"])
|
||||
print(stxn_result["hash"])
|
||||
@@ -1,44 +0,0 @@
|
||||
from xrpl.clients import JsonRpcClient
|
||||
from xrpl.models import EscrowFinish
|
||||
from xrpl.transaction import submit_and_wait
|
||||
from xrpl.wallet import generate_faucet_wallet
|
||||
|
||||
client = JsonRpcClient("https://s.altnet.rippletest.net:51234") # Connect to the testnetwork
|
||||
|
||||
# Complete an escrow
|
||||
# Cannot be called until the finish time is reached
|
||||
|
||||
# Required fields (modify to match an escrow you create)
|
||||
escrow_creator = generate_faucet_wallet(client=client).address
|
||||
|
||||
escrow_sequence = 27641268
|
||||
|
||||
# Optional fields
|
||||
|
||||
# Crypto condition that must be met before escrow can be completed, passed on escrow creation
|
||||
condition = "A02580203882E2EB9B44130530541C4CC360D079F265792C4A7ED3840968897CB7DF2DA1810120"
|
||||
|
||||
# Crypto fulfillment of the condtion
|
||||
fulfillment = "A0228020AED2C5FE4D147D310D3CFEBD9BFA81AD0F63CE1ADD92E00379DDDAF8E090E24C"
|
||||
|
||||
# Sender wallet object
|
||||
sender_wallet = generate_faucet_wallet(client=client)
|
||||
|
||||
# Build escrow finish transaction
|
||||
finish_txn = EscrowFinish(
|
||||
account=sender_wallet.address,
|
||||
owner=escrow_creator,
|
||||
offer_sequence=escrow_sequence, # The sequence number of the escrow transaction
|
||||
condition=condition, # Omit this for time-held escrows
|
||||
fulfillment=fulfillment # Omit this for time-held escrows
|
||||
)
|
||||
|
||||
# Autofill, sign, then submit transaction and wait for result
|
||||
stxn_response = submit_and_wait(finish_txn, client, sender_wallet)
|
||||
|
||||
# Parse response and return result
|
||||
stxn_result = stxn_response.result
|
||||
|
||||
# Parse result and print out the transaction result and transaction hash
|
||||
print(stxn_result["meta"]["TransactionResult"])
|
||||
print(stxn_result["hash"])
|
||||
@@ -1,19 +0,0 @@
|
||||
import random
|
||||
from os import urandom
|
||||
|
||||
from cryptoconditions import PreimageSha256
|
||||
|
||||
# """Generate a condition and fulfillment for escrows"""
|
||||
|
||||
# Generate a random preimage with at least 32 bytes of cryptographically-secure randomness.
|
||||
secret = urandom(32)
|
||||
|
||||
# Generate cryptic image from secret
|
||||
fufill = PreimageSha256(preimage=secret)
|
||||
|
||||
# Parse image and return the condition and fulfillment
|
||||
condition = str.upper(fufill.condition_binary.hex()) # conditon
|
||||
fulfillment = str.upper(fufill.serialize_binary().hex()) # fulfillment
|
||||
|
||||
# Print condition and fulfillment
|
||||
print(f"condition: {condition} \n fulfillment {fulfillment}")
|
||||
88
_code-samples/escrow/py/list_escrows.py
Normal file
88
_code-samples/escrow/py/list_escrows.py
Normal file
@@ -0,0 +1,88 @@
|
||||
from xrpl.clients import JsonRpcClient
|
||||
from xrpl.models.requests import AccountObjects, Ledger
|
||||
from xrpl.utils import ripple_time_to_datetime, drops_to_xrp
|
||||
|
||||
address = "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn"
|
||||
client = JsonRpcClient("https://xrplcluster.com/")
|
||||
|
||||
# Look up the official close time of the validated ledger ----------------------
|
||||
validated_ledger = client.request(Ledger(ledger_index="validated"))
|
||||
close_time = validated_ledger.result["ledger"]["close_time"]
|
||||
print("Latest validated ledger closed at",
|
||||
ripple_time_to_datetime(close_time)
|
||||
)
|
||||
ledger_hash = validated_ledger.result["ledger"]["ledger_hash"]
|
||||
|
||||
# Look up objects filtered to escrows, handling pagination ---------------------
|
||||
escrows = []
|
||||
marker = None
|
||||
while True:
|
||||
try:
|
||||
response = client.request(AccountObjects(
|
||||
account=address,
|
||||
ledger_hash=ledger_hash, # Caution: if you use a shortcut such as
|
||||
# ledger_index="validated", the ledger may
|
||||
# change during iteration, leading to
|
||||
# inconsistent results.
|
||||
type="escrow",
|
||||
marker=marker
|
||||
))
|
||||
except Exception as e:
|
||||
print(f"Error: account_objects failed: {e}")
|
||||
exit(1)
|
||||
|
||||
# Concatenate escrows from this page to the full list
|
||||
escrows += response.result["account_objects"]
|
||||
|
||||
# If there's a marker, loop and fetch the next page of results
|
||||
if "marker" in response.result.keys():
|
||||
marker=marker
|
||||
else:
|
||||
break
|
||||
|
||||
# Define helper function for displaying amounts --------------------------------
|
||||
def display_amount(amount):
|
||||
if type(amount) == str:
|
||||
# amount is drops of XRP
|
||||
decimal_xrp = drops_to_xrp(amount)
|
||||
return f"{decimal_xrp} XRP"
|
||||
elif "mpt_issuance_id" in amount.keys():
|
||||
# amount is an MPT.
|
||||
# More info may be available, but that would require looking it up.
|
||||
return f"{amount['value']} units of MPT {amount['mpt_issuance_id']}"
|
||||
elif "issuer" in amount.keys():
|
||||
# amount is a trust line token.
|
||||
# Currency may be 3 chars or hex. For guidelines parsing hex codes,
|
||||
# see "Normalize Currency Codes" code sample.
|
||||
return f"{amount['value']} {amount['currency']} issued by {amount['issuer']}"
|
||||
|
||||
print(f"Unexpected type of amount: {amount}")
|
||||
exit(1)
|
||||
|
||||
# Summarize results ------------------------------------------------------------
|
||||
print(f"Found {len(escrows)} escrow(s).")
|
||||
|
||||
for escrow in escrows:
|
||||
if escrow['Account'] == address:
|
||||
print(f"Outgoing escrow to {escrow['Destination']}")
|
||||
elif escrow['Destination'] == address:
|
||||
print(f"Incoming escrow from {escrow['Account']}")
|
||||
else:
|
||||
print("Neither incoming nor outgoing? This is unexpected.")
|
||||
|
||||
if "Condition" in escrow.keys():
|
||||
print(f" Condition: {escrow['Condition']}")
|
||||
|
||||
if "FinishAfter" in escrow.keys():
|
||||
mature_time_display = ripple_time_to_datetime(escrow['FinishAfter'])
|
||||
if escrow["FinishAfter"] < close_time:
|
||||
print(" Matured at", mature_time_display)
|
||||
else:
|
||||
print(" Will mature at", mature_time_display)
|
||||
|
||||
if "CancelAfter" in escrow.keys():
|
||||
cancel_time_display = ripple_time_to_datetime(escrow['CancelAfter'])
|
||||
if escrow["CancelAfter"] < close_time:
|
||||
print(" EXPIRED AT", cancel_time_display)
|
||||
else:
|
||||
print(" Expires at", cancel_time_display)
|
||||
@@ -1,2 +1,2 @@
|
||||
xrpl-py>=3.0.0
|
||||
cryptoconditions
|
||||
cryptoconditions==0.8.1
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
from xrpl.clients import JsonRpcClient
|
||||
from xrpl.models import Tx
|
||||
|
||||
client = JsonRpcClient("https://s.altnet.rippletest.net:51234") # Connect to the testnetwork
|
||||
|
||||
|
||||
prev_txn_id = "" # should look like this '84503EA84ADC4A65530C6CC91C904FCEE64CFE2BB973C023476184288698991F'
|
||||
# Return escrow seq from `PreviousTxnID` for finishing or cancelling escrows
|
||||
if prev_txn_id == "":
|
||||
print("No transaction id provided. Use create_escrow.py to generate an escrow transaction, then you can look it up by modifying prev_txn_id to use that transaction's id.")
|
||||
|
||||
# Build and send query for PreviousTxnID
|
||||
req = Tx(transaction=prev_txn_id)
|
||||
response = client.request(req)
|
||||
|
||||
# Return the result
|
||||
result = response.result
|
||||
|
||||
# Print escrow sequence if available
|
||||
if "Sequence" in result:
|
||||
print(f'escrow sequence: {result["Sequence"]}')
|
||||
# Use escrow ticket sequence if escrow sequence is not available
|
||||
if "TicketSequence" in result:
|
||||
print(f'escrow ticket sequence: {result["TicketSequence"]}')
|
||||
74
_code-samples/escrow/py/send_conditional_escrow.py
Normal file
74
_code-samples/escrow/py/send_conditional_escrow.py
Normal file
@@ -0,0 +1,74 @@
|
||||
import json
|
||||
from datetime import datetime, timedelta, UTC
|
||||
from os import urandom
|
||||
|
||||
from cryptoconditions import PreimageSha256
|
||||
from xrpl.clients import JsonRpcClient
|
||||
from xrpl.models import EscrowCreate, EscrowFinish
|
||||
from xrpl.transaction import submit_and_wait
|
||||
from xrpl.utils import datetime_to_ripple_time
|
||||
from xrpl.wallet import generate_faucet_wallet
|
||||
|
||||
# Set up client and get a wallet
|
||||
client = JsonRpcClient("https://s.altnet.rippletest.net:51234")
|
||||
print("Funding new wallet from faucet...")
|
||||
wallet = generate_faucet_wallet(client, debug=True)
|
||||
#destination_address = "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe" # Testnet faucet
|
||||
# Alternative: Get another account to send the escrow to. Use this if you get
|
||||
# a tecDIR_FULL error trying to create escrows to the Testnet faucet.
|
||||
destination_address = generate_faucet_wallet(client, debug=True).address
|
||||
|
||||
# Create the crypto-condition for release -----------------------------------
|
||||
preimage = urandom(32)
|
||||
fulfillment = PreimageSha256(preimage=preimage)
|
||||
condition_hex = fulfillment.condition_binary.hex().upper()
|
||||
fulfillment_hex = fulfillment.serialize_binary().hex().upper()
|
||||
print("Condition:", condition_hex)
|
||||
print("Fulfillment:", fulfillment_hex)
|
||||
|
||||
# Set the escrow expiration -------------------------------------------------
|
||||
cancel_delay = 300
|
||||
cancel_after = datetime.now(tz=UTC) + timedelta(seconds=cancel_delay)
|
||||
print("This escrow will expire after", cancel_after)
|
||||
cancel_after_rippletime = datetime_to_ripple_time(cancel_after)
|
||||
|
||||
# Send EscrowCreate transaction ---------------------------------------------
|
||||
escrow_create = EscrowCreate(
|
||||
account=wallet.address,
|
||||
destination=destination_address,
|
||||
amount="123456", # drops of XRP
|
||||
condition=condition_hex,
|
||||
cancel_after=cancel_after_rippletime
|
||||
)
|
||||
|
||||
print("Signing and submitting the EscrowCreate transaction.")
|
||||
response = submit_and_wait(escrow_create, client, wallet, autofill=True)
|
||||
print(json.dumps(response.result, indent=2))
|
||||
|
||||
# Check result of submitting ------------------------------------------------
|
||||
result_code = response.result["meta"]["TransactionResult"]
|
||||
if result_code != "tesSUCCESS":
|
||||
print(f"EscrowCreate failed with result code {result_code}")
|
||||
exit(1)
|
||||
|
||||
# Save the sequence number so you can identify the escrow later
|
||||
escrow_seq = response.result["tx_json"]["Sequence"]
|
||||
|
||||
# Send EscrowFinish transaction ---------------------------------------------
|
||||
escrow_finish = EscrowFinish(
|
||||
account=wallet.address,
|
||||
owner=wallet.address,
|
||||
offer_sequence=escrow_seq,
|
||||
condition=condition_hex,
|
||||
fulfillment=fulfillment_hex
|
||||
)
|
||||
print("Signing and submitting the EscrowFinish transaction.")
|
||||
response2 = submit_and_wait(escrow_finish, client, wallet, autofill=True)
|
||||
print(json.dumps(response2.result, indent=2))
|
||||
|
||||
result_code = response2.result["meta"]["TransactionResult"]
|
||||
if result_code != "tesSUCCESS":
|
||||
print(f"EscrowFinish failed with result code {result_code}")
|
||||
exit(1)
|
||||
|
||||
print("Escrow finished successfully.")
|
||||
86
_code-samples/escrow/py/send_timed_escrow.py
Normal file
86
_code-samples/escrow/py/send_timed_escrow.py
Normal file
@@ -0,0 +1,86 @@
|
||||
import json
|
||||
from datetime import datetime, timedelta, UTC
|
||||
from time import sleep
|
||||
|
||||
from xrpl.clients import JsonRpcClient
|
||||
from xrpl.models import EscrowCreate, EscrowFinish
|
||||
from xrpl.models.requests import Ledger
|
||||
from xrpl.transaction import submit_and_wait
|
||||
from xrpl.utils import datetime_to_ripple_time, ripple_time_to_datetime
|
||||
from xrpl.wallet import generate_faucet_wallet
|
||||
|
||||
# Set up client and get a wallet
|
||||
client = JsonRpcClient("https://s.altnet.rippletest.net:51234")
|
||||
print("Funding new wallet from faucet...")
|
||||
wallet = generate_faucet_wallet(client, debug=True)
|
||||
# destination_address = "rPT1Sjq2YGrBMTttX4GZHjKu9dyfzbpAYe" # Testnet faucet
|
||||
# Alternative: Get another account to send the escrow to. Use this if you get
|
||||
# a tecDIR_FULL error trying to create escrows to the Testnet faucet.
|
||||
destination_address = generate_faucet_wallet(client, debug=True).address
|
||||
|
||||
# Set the escrow finish time ------------------------------------------------
|
||||
delay = 30
|
||||
finish_after = datetime.now(tz=UTC) + timedelta(seconds=delay)
|
||||
print("This escrow will mature after", finish_after)
|
||||
finish_after_rippletime = datetime_to_ripple_time(finish_after)
|
||||
|
||||
# Send EscrowCreate transaction ---------------------------------------------
|
||||
escrow_create = EscrowCreate(
|
||||
account=wallet.address,
|
||||
destination=destination_address,
|
||||
amount="123456", # drops of XRP
|
||||
finish_after=finish_after_rippletime
|
||||
)
|
||||
|
||||
print("Signing and submitting the EscrowCreate transaction.")
|
||||
response = submit_and_wait(escrow_create, client, wallet, autofill=True)
|
||||
print(json.dumps(response.result, indent=2))
|
||||
|
||||
# Check result of submitting ------------------------------------------------
|
||||
result_code = response.result["meta"]["TransactionResult"]
|
||||
if result_code != "tesSUCCESS":
|
||||
print(f"EscrowCreate failed with result code {result_code}")
|
||||
exit(1)
|
||||
|
||||
# Save the sequence number so you can identify the escrow later
|
||||
escrow_seq = response.result["tx_json"]["Sequence"]
|
||||
print(f"Escrow sequence is {escrow_seq}.")
|
||||
|
||||
# Wait for the escrow to be finishable --------------------------------------
|
||||
sleep(delay)
|
||||
|
||||
# Check if escrow can be finished -------------------------------------------
|
||||
escrow_ready = False
|
||||
while not escrow_ready:
|
||||
validated_ledger = client.request(Ledger(ledger_index="validated"))
|
||||
ledger_close_time = validated_ledger.result["ledger"]["close_time"]
|
||||
print("Latest validated ledger closed at",
|
||||
ripple_time_to_datetime(ledger_close_time)
|
||||
)
|
||||
if ledger_close_time > finish_after_rippletime:
|
||||
escrow_ready = True
|
||||
print("Escrow is mature.")
|
||||
else:
|
||||
time_difference = finish_after_rippletime - ledger_close_time
|
||||
if time_difference == 0:
|
||||
time_difference = 1
|
||||
print(f"Waiting another {time_difference} seconds.")
|
||||
sleep(time_difference)
|
||||
|
||||
|
||||
# Send EscrowFinish transaction ---------------------------------------------
|
||||
escrow_finish = EscrowFinish(
|
||||
account=wallet.address,
|
||||
owner=wallet.address,
|
||||
offer_sequence=escrow_seq
|
||||
)
|
||||
print("Signing and submitting the EscrowFinish transaction.")
|
||||
response2 = submit_and_wait(escrow_finish, client, wallet, autofill=True)
|
||||
print(json.dumps(response2.result, indent=2))
|
||||
|
||||
result_code = response2.result["meta"]["TransactionResult"]
|
||||
if result_code != "tesSUCCESS":
|
||||
print(f"EscrowFinish failed with result code {result_code}")
|
||||
exit(1)
|
||||
|
||||
print("Escrow finished successfully.")
|
||||
@@ -1,7 +1,9 @@
|
||||
// @chunk {"steps": ["import-node-tag"]}
|
||||
// Import the library
|
||||
// @chunk {"steps": ["connect-tag"]}
|
||||
import xrpl from "xrpl"
|
||||
// @chunk-end
|
||||
|
||||
// @chunk {"steps": ["connect-tag"]}
|
||||
// Define the network client
|
||||
const SERVER_URL = "wss://s.altnet.rippletest.net:51233/"
|
||||
const client = new xrpl.Client(SERVER_URL)
|
||||
|
||||
@@ -9,8 +9,135 @@ npm i
|
||||
node issue-mpt-with-metadata.js
|
||||
```
|
||||
|
||||
The script should output a validated transaction and end with a line such as the following:
|
||||
The script should output a validated transaction and decoded metadata, similar to the following:
|
||||
|
||||
```text
|
||||
MPToken created successfully with issuance ID 005073C721E14A7613BAAF5E0B1A253459832FF8D0D81278.
|
||||
```sh
|
||||
=== Funding new wallet from faucet...===
|
||||
Issuer address: r9fhoyac7uUM9XZFDJV9wXQ4pcJb6UDpJM
|
||||
|
||||
=== Encoding metadata...===
|
||||
Encoded mpt_metadata_hex: 7B226163223A22727761222C226169223A7B226375736970223A22393132373936525830222C22696E7465726573745F72617465223A22352E303025222C22696E7465726573745F74797065223A227661726961626C65222C226D617475726974795F64617465223A22323034352D30362D3330222C227969656C645F736F75726365223A22552E532E2054726561737572792042696C6C73227D2C226173223A227472656173757279222C2264223A2241207969656C642D62656172696E6720737461626C65636F696E206261636B65642062792073686F72742D7465726D20552E532E205472656173757269657320616E64206D6F6E6579206D61726B657420696E737472756D656E74732E222C2269223A2268747470733A2F2F6578616D706C652E6F72672F7462696C6C2D69636F6E2E706E67222C22696E223A224578616D706C65205969656C6420436F2E222C226E223A22542D42696C6C205969656C6420546F6B656E222C2274223A225442494C4C222C227573223A5B7B2263223A2277656273697465222C2274223A2250726F647563742050616765222C2275223A2268747470733A2F2F6578616D706C657969656C642E636F2F7462696C6C227D2C7B2263223A22646F6373222C2274223A225969656C6420546F6B656E20446F6373222C2275223A2268747470733A2F2F6578616D706C657969656C642E636F2F646F6373227D5D7D
|
||||
|
||||
=== Sending MPTokenIssuanceCreate transaction...===
|
||||
{
|
||||
"TransactionType": "MPTokenIssuanceCreate",
|
||||
"Account": "r9fhoyac7uUM9XZFDJV9wXQ4pcJb6UDpJM",
|
||||
"AssetScale": 4,
|
||||
"MaximumAmount": "50000000",
|
||||
"TransferFee": 0,
|
||||
"Flags": 48,
|
||||
"MPTokenMetadata": "7B226163223A22727761222C226169223A7B226375736970223A22393132373936525830222C22696E7465726573745F72617465223A22352E303025222C22696E7465726573745F74797065223A227661726961626C65222C226D617475726974795F64617465223A22323034352D30362D3330222C227969656C645F736F75726365223A22552E532E2054726561737572792042696C6C73227D2C226173223A227472656173757279222C2264223A2241207969656C642D62656172696E6720737461626C65636F696E206261636B65642062792073686F72742D7465726D20552E532E205472656173757269657320616E64206D6F6E6579206D61726B657420696E737472756D656E74732E222C2269223A2268747470733A2F2F6578616D706C652E6F72672F7462696C6C2D69636F6E2E706E67222C22696E223A224578616D706C65205969656C6420436F2E222C226E223A22542D42696C6C205969656C6420546F6B656E222C2274223A225442494C4C222C227573223A5B7B2263223A2277656273697465222C2274223A2250726F647563742050616765222C2275223A2268747470733A2F2F6578616D706C657969656C642E636F2F7462696C6C227D2C7B2263223A22646F6373222C2274223A225969656C6420546F6B656E20446F6373222C2275223A2268747470733A2F2F6578616D706C657969656C642E636F2F646F6373227D5D7D"
|
||||
}
|
||||
|
||||
=== Checking MPTokenIssuanceCreate results... ===
|
||||
{
|
||||
"close_time_iso": "2025-11-20T18:13:30Z",
|
||||
"ctid": "C0148E8700000002",
|
||||
"hash": "555FAFDB99B239567FDF30DDF22BA3B30F8E70D8D06833B1270AC600E1575948",
|
||||
"ledger_hash": "A7010A2025989778420280F7F96B10F5D3C879E049BE5DA12500FFBB90D162C5",
|
||||
"ledger_index": 1347207,
|
||||
"meta": {
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"CreatedNode": {
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "33468621DEF32177E84C1EBC2C457C908567E245622CBDE03185C4ABC83B7F9D",
|
||||
"NewFields": {
|
||||
"Owner": "r9fhoyac7uUM9XZFDJV9wXQ4pcJb6UDpJM",
|
||||
"RootIndex": "33468621DEF32177E84C1EBC2C457C908567E245622CBDE03185C4ABC83B7F9D"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"CreatedNode": {
|
||||
"LedgerEntryType": "MPTokenIssuance",
|
||||
"LedgerIndex": "6567EE49937AADAB4FC4D5DDBD6A4A6E179E0E5A9DF2FC7ED8B41B807F0DDBF2",
|
||||
"NewFields": {
|
||||
"AssetScale": 4,
|
||||
"Flags": 48,
|
||||
"Issuer": "r9fhoyac7uUM9XZFDJV9wXQ4pcJb6UDpJM",
|
||||
"MPTokenMetadata": "7B226163223A22727761222C226169223A7B226375736970223A22393132373936525830222C22696E7465726573745F72617465223A22352E303025222C22696E7465726573745F74797065223A227661726961626C65222C226D617475726974795F64617465223A22323034352D30362D3330222C227969656C645F736F75726365223A22552E532E2054726561737572792042696C6C73227D2C226173223A227472656173757279222C2264223A2241207969656C642D62656172696E6720737461626C65636F696E206261636B65642062792073686F72742D7465726D20552E532E205472656173757269657320616E64206D6F6E6579206D61726B657420696E737472756D656E74732E222C2269223A2268747470733A2F2F6578616D706C652E6F72672F7462696C6C2D69636F6E2E706E67222C22696E223A224578616D706C65205969656C6420436F2E222C226E223A22542D42696C6C205969656C6420546F6B656E222C2274223A225442494C4C222C227573223A5B7B2263223A2277656273697465222C2274223A2250726F647563742050616765222C2275223A2268747470733A2F2F6578616D706C657969656C642E636F2F7462696C6C227D2C7B2263223A22646F6373222C2274223A225969656C6420546F6B656E20446F6373222C2275223A2268747470733A2F2F6578616D706C657969656C642E636F2F646F6373227D5D7D",
|
||||
"MaximumAmount": "50000000",
|
||||
"Sequence": 1347205
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "r9fhoyac7uUM9XZFDJV9wXQ4pcJb6UDpJM",
|
||||
"Balance": "99999999",
|
||||
"Flags": 0,
|
||||
"OwnerCount": 1,
|
||||
"Sequence": 1347206
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "AB5FC35110CED5BFD2CEA3E37B41E43CC4BBAF89AE66BA85942E04CBC38550FB",
|
||||
"PreviousFields": {
|
||||
"Balance": "100000000",
|
||||
"OwnerCount": 0,
|
||||
"Sequence": 1347205
|
||||
},
|
||||
"PreviousTxnID": "1CDF420134492607EC54838F91FA06A655E07DD296ED69CC7172C1AC356BF22B",
|
||||
"PreviousTxnLgrSeq": 1347205
|
||||
}
|
||||
}
|
||||
],
|
||||
"TransactionIndex": 0,
|
||||
"TransactionResult": "tesSUCCESS",
|
||||
"mpt_issuance_id": "00148E8558E6AEAA301085FBFD01D615F059A7CCE6E38296"
|
||||
},
|
||||
"tx_json": {
|
||||
"Account": "r9fhoyac7uUM9XZFDJV9wXQ4pcJb6UDpJM",
|
||||
"AssetScale": 4,
|
||||
"Fee": "1",
|
||||
"Flags": 48,
|
||||
"LastLedgerSequence": 1347225,
|
||||
"MPTokenMetadata": "7B226163223A22727761222C226169223A7B226375736970223A22393132373936525830222C22696E7465726573745F72617465223A22352E303025222C22696E7465726573745F74797065223A227661726961626C65222C226D617475726974795F64617465223A22323034352D30362D3330222C227969656C645F736F75726365223A22552E532E2054726561737572792042696C6C73227D2C226173223A227472656173757279222C2264223A2241207969656C642D62656172696E6720737461626C65636F696E206261636B65642062792073686F72742D7465726D20552E532E205472656173757269657320616E64206D6F6E6579206D61726B657420696E737472756D656E74732E222C2269223A2268747470733A2F2F6578616D706C652E6F72672F7462696C6C2D69636F6E2E706E67222C22696E223A224578616D706C65205969656C6420436F2E222C226E223A22542D42696C6C205969656C6420546F6B656E222C2274223A225442494C4C222C227573223A5B7B2263223A2277656273697465222C2274223A2250726F647563742050616765222C2275223A2268747470733A2F2F6578616D706C657969656C642E636F2F7462696C6C227D2C7B2263223A22646F6373222C2274223A225969656C6420546F6B656E20446F6373222C2275223A2268747470733A2F2F6578616D706C657969656C642E636F2F646F6373227D5D7D",
|
||||
"MaximumAmount": "50000000",
|
||||
"Sequence": 1347205,
|
||||
"SigningPubKey": "ED1EC65DB85E686A55F8FD9BC6E405E8F2F8EA5E1712AED64E28C97350EB4EF6E7",
|
||||
"TransactionType": "MPTokenIssuanceCreate",
|
||||
"TransferFee": 0,
|
||||
"TxnSignature": "3A671905D57342F051E3BF057CCF65B0D94114C04D255D4AE3CEE01C2D0B368118E94011CEB27EC9BB447D3498B24B750F2691B4D7AB71F82626BC6F49465806",
|
||||
"ctid": "C0148E8700000002",
|
||||
"date": 816977610,
|
||||
"ledger_index": 1347207
|
||||
},
|
||||
"validated": true
|
||||
}
|
||||
|
||||
- MPToken created successfully with issuance ID: 00148E8558E6AEAA301085FBFD01D615F059A7CCE6E38296
|
||||
- Explorer URL: https://devnet.xrpl.org/mpt/00148E8558E6AEAA301085FBFD01D615F059A7CCE6E38296
|
||||
|
||||
=== Confirming MPT Issuance metadata in the validated ledger... ===
|
||||
Decoded MPT metadata:
|
||||
{
|
||||
asset_class: 'rwa',
|
||||
additional_info: {
|
||||
cusip: '912796RX0',
|
||||
interest_rate: '5.00%',
|
||||
interest_type: 'variable',
|
||||
maturity_date: '2045-06-30',
|
||||
yield_source: 'U.S. Treasury Bills'
|
||||
},
|
||||
asset_subclass: 'treasury',
|
||||
desc: 'A yield-bearing stablecoin backed by short-term U.S. Treasuries and money market instruments.',
|
||||
icon: 'https://example.org/tbill-icon.png',
|
||||
issuer_name: 'Example Yield Co.',
|
||||
name: 'T-Bill Yield Token',
|
||||
ticker: 'TBILL',
|
||||
uris: [
|
||||
{
|
||||
category: 'website',
|
||||
title: 'Product Page',
|
||||
uri: 'https://exampleyield.co/tbill'
|
||||
},
|
||||
{
|
||||
category: 'docs',
|
||||
title: 'Yield Token Docs',
|
||||
uri: 'https://exampleyield.co/docs'
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1,35 +1,40 @@
|
||||
import { stringToHex, hexToString } from '@xrplf/isomorphic/dist/utils/index.js'
|
||||
import { MPTokenIssuanceCreateFlags, Client } from 'xrpl'
|
||||
import {
|
||||
MPTokenIssuanceCreateFlags,
|
||||
Client,
|
||||
encodeMPTokenMetadata,
|
||||
decodeMPTokenMetadata
|
||||
} from 'xrpl'
|
||||
|
||||
// Connect to network and get a wallet
|
||||
const client = new Client('wss://s.devnet.rippletest.net:51233')
|
||||
await client.connect()
|
||||
|
||||
console.log('Funding new wallet from faucet...')
|
||||
const { wallet } = await client.fundWallet()
|
||||
console.log('=== Funding new wallet from faucet...===')
|
||||
const { wallet: issuer } = await client.fundWallet()
|
||||
console.log(`Issuer address: ${issuer.address}`)
|
||||
|
||||
// Define metadata as JSON
|
||||
const mpt_metadata = {
|
||||
t: 'TBILL',
|
||||
n: 'T-Bill Yield Token',
|
||||
d: 'A yield-bearing stablecoin backed by short-term U.S. Treasuries and money market instruments.',
|
||||
i: 'https://example.org/tbill-icon.png',
|
||||
ac: 'rwa',
|
||||
as: 'treasury',
|
||||
in: 'Example Yield Co.',
|
||||
us: [
|
||||
const mptMetadata = {
|
||||
ticker: 'TBILL',
|
||||
name: 'T-Bill Yield Token',
|
||||
desc: 'A yield-bearing stablecoin backed by short-term U.S. Treasuries and money market instruments.',
|
||||
icon: 'https://example.org/tbill-icon.png',
|
||||
asset_class: 'rwa',
|
||||
asset_subclass: 'treasury',
|
||||
issuer_name: 'Example Yield Co.',
|
||||
uris: [
|
||||
{
|
||||
u: 'https://exampleyield.co/tbill',
|
||||
c: 'website',
|
||||
t: 'Product Page'
|
||||
uri: 'https://exampleyield.co/tbill',
|
||||
category: 'website',
|
||||
title: 'Product Page'
|
||||
},
|
||||
{
|
||||
u: 'https://exampleyield.co/docs',
|
||||
c: 'docs',
|
||||
t: 'Yield Token Docs'
|
||||
uri: 'https://exampleyield.co/docs',
|
||||
category: 'docs',
|
||||
title: 'Yield Token Docs'
|
||||
}
|
||||
],
|
||||
ai: {
|
||||
additional_info: {
|
||||
interest_rate: '5.00%',
|
||||
interest_type: 'variable',
|
||||
yield_source: 'U.S. Treasury Bills',
|
||||
@@ -38,48 +43,67 @@ const mpt_metadata = {
|
||||
}
|
||||
}
|
||||
|
||||
// Convert JSON to a string (without excess whitespace), then string to hex
|
||||
const mpt_metadata_hex = stringToHex(JSON.stringify(mpt_metadata))
|
||||
// Encode the metadata.
|
||||
// The encodeMPTokenMetadata function shortens standard MPTokenMetadata
|
||||
// field names to a compact key, then converts the JSON metadata object into a
|
||||
// hex-encoded string, following the XLS-89 standard.
|
||||
// https://xls.xrpl.org/xls/XLS-0089-multi-purpose-token-metadata-schema.html
|
||||
console.log('\n=== Encoding metadata...===')
|
||||
const mptMetadataHex = encodeMPTokenMetadata(mptMetadata)
|
||||
console.log('Encoded mptMetadataHex: ', mptMetadataHex)
|
||||
|
||||
// Define the transaction, including other MPT parameters
|
||||
const mpt_issuance_create = {
|
||||
const mptIssuanceCreate = {
|
||||
TransactionType: 'MPTokenIssuanceCreate',
|
||||
Account: wallet.address,
|
||||
Account: issuer.address,
|
||||
AssetScale: 4,
|
||||
MaximumAmount: '50000000',
|
||||
TransferFee: 0,
|
||||
Flags: MPTokenIssuanceCreateFlags.tfMPTCanTransfer |
|
||||
MPTokenIssuanceCreateFlags.tfMPTCanTrade,
|
||||
MPTokenMetadata: mpt_metadata_hex
|
||||
Flags:
|
||||
MPTokenIssuanceCreateFlags.tfMPTCanTransfer |
|
||||
MPTokenIssuanceCreateFlags.tfMPTCanTrade,
|
||||
MPTokenMetadata: mptMetadataHex
|
||||
}
|
||||
|
||||
// Prepare, sign, and submit the transaction
|
||||
console.log('Sending MPTokenIssuanceCreate transaction...')
|
||||
const submit_response = await client.submitAndWait(mpt_issuance_create, { wallet, autofill: true })
|
||||
// Sign and submit the transaction
|
||||
console.log('\n=== Sending MPTokenIssuanceCreate transaction...===')
|
||||
console.log(JSON.stringify(mptIssuanceCreate, null, 2))
|
||||
const submitResponse = await client.submitAndWait(mptIssuanceCreate, {
|
||||
wallet: issuer,
|
||||
autofill: true
|
||||
})
|
||||
|
||||
// Check transaction results and disconnect
|
||||
console.log(JSON.stringify(submit_response, null, 2))
|
||||
if (submit_response.result.meta.TransactionResult !== 'tesSUCCESS') {
|
||||
const result_code = response.result.meta.TransactionResult
|
||||
console.warn(`Transaction failed with result code ${result_code}.`)
|
||||
// Check transaction results
|
||||
console.log('\n=== Checking MPTokenIssuanceCreate results... ===')
|
||||
console.log(JSON.stringify(submitResponse.result, null, 2))
|
||||
if (submitResponse.result.meta.TransactionResult !== 'tesSUCCESS') {
|
||||
const resultCode = submitResponse.result.meta.TransactionResult
|
||||
console.warn(`Transaction failed with result code ${resultCode}.`)
|
||||
await client.disconnect()
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const issuance_id = submit_response.result.meta.mpt_issuance_id
|
||||
console.log(`MPToken created successfully with issuance ID ${issuance_id}.`)
|
||||
const issuanceId = submitResponse.result.meta.mpt_issuance_id
|
||||
console.log(
|
||||
`\n- MPToken created successfully with issuance ID: ${issuanceId}`
|
||||
)
|
||||
// View the MPT issuance on the XRPL Explorer
|
||||
console.log(`- Explorer URL: https://devnet.xrpl.org/mpt/${issuanceId}`)
|
||||
|
||||
// Look up MPT Issuance entry in the validated ledger
|
||||
console.log('Confirming MPT Issuance metadata in the validated ledger.')
|
||||
const ledger_entry_response = await client.request({
|
||||
"command": "ledger_entry",
|
||||
"mpt_issuance": issuance_id,
|
||||
"ledger_index": "validated"
|
||||
console.log('\n=== Confirming MPT Issuance metadata in the validated ledger... ===')
|
||||
const ledgerEntryResponse = await client.request({
|
||||
command: 'ledger_entry',
|
||||
mpt_issuance: issuanceId,
|
||||
ledger_index: 'validated'
|
||||
})
|
||||
|
||||
// Decode the metadata
|
||||
const metadata_blob = ledger_entry_response.result.node.MPTokenMetadata
|
||||
const decoded_metadata = JSON.parse(hexToString(metadata_blob))
|
||||
console.log('Decoded metadata:', decoded_metadata)
|
||||
// Decode the metadata.
|
||||
// The decodeMPTokenMetadata function takes a hex-encoded string representing MPT metadata,
|
||||
// decodes it to a JSON object, and expands any compact field names to their full forms.
|
||||
const metadataBlob = ledgerEntryResponse.result.node.MPTokenMetadata
|
||||
const decodedMetadata = decodeMPTokenMetadata(metadataBlob)
|
||||
console.log('Decoded MPT metadata:\n', decodedMetadata)
|
||||
|
||||
|
||||
client.disconnect()
|
||||
// Disconnect from the client
|
||||
await client.disconnect()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"xrpl": "^4.4.0"
|
||||
"xrpl": "^4.4.3"
|
||||
},
|
||||
"type": "module"
|
||||
}
|
||||
|
||||
@@ -11,8 +11,137 @@ pip install -r requirements.txt
|
||||
python issue-mpt-with-metadata.py
|
||||
```
|
||||
|
||||
The script should output a validated transaction and end with a line such as the following:
|
||||
The script should output a validated transaction and decoded metadata, similar to the following:
|
||||
|
||||
```text
|
||||
MPToken created successfully with issuance ID 0050773D6B8DF8C6BEA497016C8679728A217DE1C4D50AC5.
|
||||
```sh
|
||||
=== Funding new wallet from faucet... ===
|
||||
Attempting to fund address rN1vQBHqgbfXjeAfYVUVpQXMyyZYjAnQkS
|
||||
Faucet fund successful.
|
||||
|
||||
=== Encoding metadata...===
|
||||
Encoded mpt_metadata_hex: 7B226163223A22727761222C226169223A7B226375736970223A22393132373936525830222C22696E7465726573745F72617465223A22352E303025222C22696E7465726573745F74797065223A227661726961626C65222C226D617475726974795F64617465223A22323034352D30362D3330222C227969656C645F736F75726365223A22552E532E2054726561737572792042696C6C73227D2C226173223A227472656173757279222C2264223A2241207969656C642D62656172696E6720737461626C65636F696E206261636B65642062792073686F72742D7465726D20552E532E205472656173757269657320616E64206D6F6E6579206D61726B657420696E737472756D656E74732E222C2269223A2268747470733A2F2F6578616D706C652E6F72672F7462696C6C2D69636F6E2E706E67222C22696E223A224578616D706C65205969656C6420436F2E222C226E223A22542D42696C6C205969656C6420546F6B656E222C2274223A225442494C4C222C227573223A5B7B2263223A2277656273697465222C2274223A2250726F647563742050616765222C2275223A2268747470733A2F2F6578616D706C657969656C642E636F2F7462696C6C227D2C7B2263223A22646F6373222C2274223A225969656C6420546F6B656E20446F6373222C2275223A2268747470733A2F2F6578616D706C657969656C642E636F2F646F6373227D5D7D
|
||||
|
||||
=== Sending MPTokenIssuanceCreate transaction...===
|
||||
{
|
||||
"Account": "rN1vQBHqgbfXjeAfYVUVpQXMyyZYjAnQkS",
|
||||
"TransactionType": "MPTokenIssuanceCreate",
|
||||
"Flags": 48,
|
||||
"SigningPubKey": "",
|
||||
"AssetScale": 4,
|
||||
"MaximumAmount": "50000000",
|
||||
"TransferFee": 0,
|
||||
"MPTokenMetadata": "7B226163223A22727761222C226169223A7B226375736970223A22393132373936525830222C22696E7465726573745F72617465223A22352E303025222C22696E7465726573745F74797065223A227661726961626C65222C226D617475726974795F64617465223A22323034352D30362D3330222C227969656C645F736F75726365223A22552E532E2054726561737572792042696C6C73227D2C226173223A227472656173757279222C2264223A2241207969656C642D62656172696E6720737461626C65636F696E206261636B65642062792073686F72742D7465726D20552E532E205472656173757269657320616E64206D6F6E6579206D61726B657420696E737472756D656E74732E222C2269223A2268747470733A2F2F6578616D706C652E6F72672F7462696C6C2D69636F6E2E706E67222C22696E223A224578616D706C65205969656C6420436F2E222C226E223A22542D42696C6C205969656C6420546F6B656E222C2274223A225442494C4C222C227573223A5B7B2263223A2277656273697465222C2274223A2250726F647563742050616765222C2275223A2268747470733A2F2F6578616D706C657969656C642E636F2F7462696C6C227D2C7B2263223A22646F6373222C2274223A225969656C6420546F6B656E20446F6373222C2275223A2268747470733A2F2F6578616D706C657969656C642E636F2F646F6373227D5D7D"
|
||||
}
|
||||
|
||||
=== Checking MPTokenIssuanceCreate results... ===
|
||||
{
|
||||
"close_time_iso": "2025-11-20T18:21:12Z",
|
||||
"ctid": "C0148F2200000002",
|
||||
"hash": "47D87C3C93C80F2158CE5A688C63386E939BC77CFF4F5B62F84775A97EF991AE",
|
||||
"ledger_hash": "663C9D10B10586009F5C17B4A9A98220ECB00AF64A248A71ECF970D3E7D206F4",
|
||||
"ledger_index": 1347362,
|
||||
"meta": {
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rN1vQBHqgbfXjeAfYVUVpQXMyyZYjAnQkS",
|
||||
"Balance": "99999999",
|
||||
"Flags": 0,
|
||||
"OwnerCount": 1,
|
||||
"Sequence": 1347360
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot",
|
||||
"LedgerIndex": "0B10E7C08910B27DE817A935972FBD91B57E6177627FDA78C9C75CD83D32D973",
|
||||
"PreviousFields": {
|
||||
"Balance": "100000000",
|
||||
"OwnerCount": 0,
|
||||
"Sequence": 1347359
|
||||
},
|
||||
"PreviousTxnID": "2166929BBF80BEAA631AB4FBE6864E03CD669D4AFEE6559BA6AB850602A9151A",
|
||||
"PreviousTxnLgrSeq": 1347359
|
||||
}
|
||||
},
|
||||
{
|
||||
"CreatedNode": {
|
||||
"LedgerEntryType": "DirectoryNode",
|
||||
"LedgerIndex": "5D2D7A2717A4ECF4C865A6F80E0C2C228409B27CE948307F3ED01213C9906AC4",
|
||||
"NewFields": {
|
||||
"Owner": "rN1vQBHqgbfXjeAfYVUVpQXMyyZYjAnQkS",
|
||||
"RootIndex": "5D2D7A2717A4ECF4C865A6F80E0C2C228409B27CE948307F3ED01213C9906AC4"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"CreatedNode": {
|
||||
"LedgerEntryType": "MPTokenIssuance",
|
||||
"LedgerIndex": "886355A55396B5511A96BCA43E73E3DEDC2875776EC307252157142B1D36B852",
|
||||
"NewFields": {
|
||||
"AssetScale": 4,
|
||||
"Flags": 48,
|
||||
"Issuer": "rN1vQBHqgbfXjeAfYVUVpQXMyyZYjAnQkS",
|
||||
"MPTokenMetadata": "7B226163223A22727761222C226169223A7B226375736970223A22393132373936525830222C22696E7465726573745F72617465223A22352E303025222C22696E7465726573745F74797065223A227661726961626C65222C226D617475726974795F64617465223A22323034352D30362D3330222C227969656C645F736F75726365223A22552E532E2054726561737572792042696C6C73227D2C226173223A227472656173757279222C2264223A2241207969656C642D62656172696E6720737461626C65636F696E206261636B65642062792073686F72742D7465726D20552E532E205472656173757269657320616E64206D6F6E6579206D61726B657420696E737472756D656E74732E222C2269223A2268747470733A2F2F6578616D706C652E6F72672F7462696C6C2D69636F6E2E706E67222C22696E223A224578616D706C65205969656C6420436F2E222C226E223A22542D42696C6C205969656C6420546F6B656E222C2274223A225442494C4C222C227573223A5B7B2263223A2277656273697465222C2274223A2250726F647563742050616765222C2275223A2268747470733A2F2F6578616D706C657969656C642E636F2F7462696C6C227D2C7B2263223A22646F6373222C2274223A225969656C6420546F6B656E20446F6373222C2275223A2268747470733A2F2F6578616D706C657969656C642E636F2F646F6373227D5D7D",
|
||||
"MaximumAmount": "50000000",
|
||||
"Sequence": 1347359
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"TransactionIndex": 0,
|
||||
"TransactionResult": "tesSUCCESS",
|
||||
"mpt_issuance_id": "00148F1F983B024FB54CE16CBC7F788C2F71AC9728355EFC"
|
||||
},
|
||||
"tx_json": {
|
||||
"Account": "rN1vQBHqgbfXjeAfYVUVpQXMyyZYjAnQkS",
|
||||
"AssetScale": 4,
|
||||
"Fee": "1",
|
||||
"Flags": 48,
|
||||
"LastLedgerSequence": 1347380,
|
||||
"MPTokenMetadata": "7B226163223A22727761222C226169223A7B226375736970223A22393132373936525830222C22696E7465726573745F72617465223A22352E303025222C22696E7465726573745F74797065223A227661726961626C65222C226D617475726974795F64617465223A22323034352D30362D3330222C227969656C645F736F75726365223A22552E532E2054726561737572792042696C6C73227D2C226173223A227472656173757279222C2264223A2241207969656C642D62656172696E6720737461626C65636F696E206261636B65642062792073686F72742D7465726D20552E532E205472656173757269657320616E64206D6F6E6579206D61726B657420696E737472756D656E74732E222C2269223A2268747470733A2F2F6578616D706C652E6F72672F7462696C6C2D69636F6E2E706E67222C22696E223A224578616D706C65205969656C6420436F2E222C226E223A22542D42696C6C205969656C6420546F6B656E222C2274223A225442494C4C222C227573223A5B7B2263223A2277656273697465222C2274223A2250726F647563742050616765222C2275223A2268747470733A2F2F6578616D706C657969656C642E636F2F7462696C6C227D2C7B2263223A22646F6373222C2274223A225969656C6420546F6B656E20446F6373222C2275223A2268747470733A2F2F6578616D706C657969656C642E636F2F646F6373227D5D7D",
|
||||
"MaximumAmount": "50000000",
|
||||
"Sequence": 1347359,
|
||||
"SigningPubKey": "ED0BFB56FB91211F7DCB245C3863958B8FF5A5BAC4B7293E598C7B4D34265EF0A9",
|
||||
"TransactionType": "MPTokenIssuanceCreate",
|
||||
"TransferFee": 0,
|
||||
"TxnSignature": "4710CCD303902101E6A009E8D459774D1FA9C59E20816588B9248883FF6A37DD8670C1C6EEED1DE5B363A15C88FCA40C1E74319886F3DB8278A63CF0B88CDC0A",
|
||||
"ctid": "C0148F2200000002",
|
||||
"date": 816978072,
|
||||
"ledger_index": 1347362
|
||||
},
|
||||
"validated": true
|
||||
}
|
||||
|
||||
- MPToken created successfully with issuance ID: 00148F1F983B024FB54CE16CBC7F788C2F71AC9728355EFC
|
||||
- Explorer URL: https://devnet.xrpl.org/mpt/00148F1F983B024FB54CE16CBC7F788C2F71AC9728355EFC
|
||||
|
||||
=== Confirming MPT Issuance metadata in the validated ledger... ===
|
||||
Decoded MPT metadata:
|
||||
{
|
||||
"asset_class": "rwa",
|
||||
"additional_info": {
|
||||
"cusip": "912796RX0",
|
||||
"interest_rate": "5.00%",
|
||||
"interest_type": "variable",
|
||||
"maturity_date": "2045-06-30",
|
||||
"yield_source": "U.S. Treasury Bills"
|
||||
},
|
||||
"asset_subclass": "treasury",
|
||||
"desc": "A yield-bearing stablecoin backed by short-term U.S. Treasuries and money market instruments.",
|
||||
"icon": "https://example.org/tbill-icon.png",
|
||||
"issuer_name": "Example Yield Co.",
|
||||
"name": "T-Bill Yield Token",
|
||||
"ticker": "TBILL",
|
||||
"uris": [
|
||||
{
|
||||
"category": "website",
|
||||
"title": "Product Page",
|
||||
"uri": "https://exampleyield.co/tbill"
|
||||
},
|
||||
{
|
||||
"category": "docs",
|
||||
"title": "Yield Token Docs",
|
||||
"uri": "https://exampleyield.co/docs"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import json
|
||||
from xrpl.utils import str_to_hex, hex_to_str
|
||||
from xrpl.utils import encode_mptoken_metadata, decode_mptoken_metadata
|
||||
from xrpl.clients import JsonRpcClient
|
||||
from xrpl.wallet import generate_faucet_wallet
|
||||
from xrpl.transaction import submit_and_wait
|
||||
@@ -7,31 +7,31 @@ from xrpl.models import LedgerEntry, MPTokenIssuanceCreate, MPTokenIssuanceCreat
|
||||
|
||||
# Set up client and get a wallet
|
||||
client = JsonRpcClient("https://s.devnet.rippletest.net:51234")
|
||||
print("Funding new wallet from faucet...")
|
||||
wallet = generate_faucet_wallet(client, debug=True)
|
||||
print("=== Funding new wallet from faucet... ===")
|
||||
issuer = generate_faucet_wallet(client, debug=True)
|
||||
|
||||
# Define metadata as JSON
|
||||
# Define metadata as JSON
|
||||
mpt_metadata = {
|
||||
"t": "TBILL",
|
||||
"n": "T-Bill Yield Token",
|
||||
"d": "A yield-bearing stablecoin backed by short-term U.S. Treasuries and money market instruments.",
|
||||
"i": "example.org/tbill-icon.png",
|
||||
"ac": "rwa",
|
||||
"as": "treasury",
|
||||
"in": "Example Yield Co.",
|
||||
"us": [
|
||||
"ticker": "TBILL",
|
||||
"name": "T-Bill Yield Token",
|
||||
"desc": "A yield-bearing stablecoin backed by short-term U.S. Treasuries and money market instruments.",
|
||||
"icon": "https://example.org/tbill-icon.png",
|
||||
"asset_class": "rwa",
|
||||
"asset_subclass": "treasury",
|
||||
"issuer_name": "Example Yield Co.",
|
||||
"uris": [
|
||||
{
|
||||
"u": "exampleyield.co/tbill",
|
||||
"c": "website",
|
||||
"t": "Product Page"
|
||||
"uri": "https://exampleyield.co/tbill",
|
||||
"category": "website",
|
||||
"title": "Product Page"
|
||||
},
|
||||
{
|
||||
"u": "exampleyield.co/docs",
|
||||
"c": "docs",
|
||||
"t": "Yield Token Docs"
|
||||
"uri": "https://exampleyield.co/docs",
|
||||
"category": "docs",
|
||||
"title": "Yield Token Docs"
|
||||
}
|
||||
],
|
||||
"ai": {
|
||||
"additional_info": {
|
||||
"interest_rate": "5.00%",
|
||||
"interest_type": "variable",
|
||||
"yield_source": "U.S. Treasury Bills",
|
||||
@@ -40,13 +40,18 @@ mpt_metadata = {
|
||||
}
|
||||
}
|
||||
|
||||
# Convert JSON to a string (without excess whitespace), then string to hex
|
||||
mpt_metadata_string = json.dumps(mpt_metadata, separators=(',', ':'))
|
||||
mpt_metadata_hex = str_to_hex(mpt_metadata_string)
|
||||
# Encode the metadata.
|
||||
# The encode_mptoken_metadata function shortens standard MPTokenMetadata
|
||||
# field names to a compact key, then converts the JSON metadata object into a
|
||||
# hex-encoded string, following the XLS-89 standard.
|
||||
# https://xls.xrpl.org/xls/XLS-0089-multi-purpose-token-metadata-schema.html
|
||||
print("\n=== Encoding metadata...===")
|
||||
mpt_metadata_hex = encode_mptoken_metadata(mpt_metadata)
|
||||
print("Encoded mpt_metadata_hex:", mpt_metadata_hex)
|
||||
|
||||
# Define the transaction, including other MPT parameters
|
||||
mpt_issuance_create = MPTokenIssuanceCreate(
|
||||
account=wallet.address,
|
||||
account=issuer.address,
|
||||
asset_scale=4,
|
||||
maximum_amount="50000000",
|
||||
transfer_fee=0,
|
||||
@@ -55,28 +60,33 @@ mpt_issuance_create = MPTokenIssuanceCreate(
|
||||
mptoken_metadata=mpt_metadata_hex
|
||||
)
|
||||
|
||||
# Prepare, sign, and submit the transaction
|
||||
print("Sending MPTokenIssuanceCreate transaction...")
|
||||
response = submit_and_wait(mpt_issuance_create, client, wallet, autofill=True)
|
||||
print(json.dumps(response.result, indent=2))
|
||||
# Sign and submit the transaction
|
||||
print("\n=== Sending MPTokenIssuanceCreate transaction...===")
|
||||
print(json.dumps(mpt_issuance_create.to_xrpl(), indent=2))
|
||||
response = submit_and_wait(mpt_issuance_create, client, issuer, autofill=True)
|
||||
|
||||
# Check transaction results
|
||||
print("\n=== Checking MPTokenIssuanceCreate results... ===")
|
||||
print(json.dumps(response.result, indent=2))
|
||||
result_code = response.result["meta"]["TransactionResult"]
|
||||
if result_code != "tesSUCCESS":
|
||||
print(f"Transaction failed with result code {result_code}")
|
||||
print(f"Transaction failed with result code {result_code}.")
|
||||
exit(1)
|
||||
|
||||
issuance_id = response.result["meta"]["mpt_issuance_id"]
|
||||
print(f"MPToken successfully created with issuance ID {issuance_id}")
|
||||
print(f"\n- MPToken created successfully with issuance ID: {issuance_id}")
|
||||
print(f"- Explorer URL: https://devnet.xrpl.org/mpt/{issuance_id}")
|
||||
|
||||
# Look up MPT Issuance entry in the validated ledger
|
||||
print("Confirming MPT Issuance metadata in the validated ledger.")
|
||||
print("\n=== Confirming MPT Issuance metadata in the validated ledger... ===")
|
||||
ledger_entry_response = client.request(LedgerEntry(
|
||||
mpt_issuance=issuance_id,
|
||||
ledger_index="validated"
|
||||
))
|
||||
|
||||
# Decode the metadata
|
||||
# Decode the metadata.
|
||||
# The decode_mptoken_metadata function takes a hex-encoded string representing MPT metadata,
|
||||
# decodes it to a JSON object, and expands any compact field names to their full forms.
|
||||
metadata_blob = ledger_entry_response.result["node"]["MPTokenMetadata"]
|
||||
decoded_metadata = json.loads(hex_to_str(metadata_blob))
|
||||
print("Decoded metadata:", decoded_metadata)
|
||||
decoded_metadata = decode_mptoken_metadata(metadata_blob)
|
||||
print("Decoded MPT metadata:\n", json.dumps(decoded_metadata, indent=2))
|
||||
|
||||
@@ -1 +1 @@
|
||||
xrpl-py==4.3.0
|
||||
xrpl-py==4.3.1
|
||||
|
||||
3
_code-samples/lending-protocol/README.md
Normal file
3
_code-samples/lending-protocol/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Lending Protocol Examples
|
||||
|
||||
Code samples showing how to create a Loan Broker, deposit and withdraw first-loss capital, create a loan, and manage a loan.
|
||||
329
_code-samples/lending-protocol/js/README.md
Normal file
329
_code-samples/lending-protocol/js/README.md
Normal file
@@ -0,0 +1,329 @@
|
||||
# Lending Protocol Examples (JavaScript)
|
||||
|
||||
This directory contains JavaScript examples demonstrating how to create a Loan Broker, deposit and withdraw first-loss capital, create a loan, and manage a loan.
|
||||
|
||||
## Setup
|
||||
|
||||
Install dependencies before running any examples:
|
||||
|
||||
```sh
|
||||
npm i
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Create a Loan Broker
|
||||
|
||||
```sh
|
||||
node createLoanBroker.js
|
||||
```
|
||||
|
||||
The script should output the LoanBrokerSet transaction, loan broker ID, and loan broker pseudo-account:
|
||||
|
||||
```sh
|
||||
Loan broker/vault owner address: rKL3u76wNGdF2Th4EvCuHV5885T6h2iFTY
|
||||
Vault ID: 33E51DD0333775E37F2CC1EB0DA788F9C663AF919DC23ED595A8D69330E5CD68
|
||||
|
||||
=== Preparing LoanBrokerSet transaction ===
|
||||
|
||||
{
|
||||
"TransactionType": "LoanBrokerSet",
|
||||
"Account": "rKL3u76wNGdF2Th4EvCuHV5885T6h2iFTY",
|
||||
"VaultID": "33E51DD0333775E37F2CC1EB0DA788F9C663AF919DC23ED595A8D69330E5CD68",
|
||||
"ManagementFeeRate": 1000
|
||||
}
|
||||
|
||||
=== Submitting LoanBrokerSet transaction ===
|
||||
|
||||
Loan broker created successfully!
|
||||
|
||||
=== Loan Broker Information ===
|
||||
|
||||
LoanBroker ID: 0AA13C8A8E95D8F2D9EF1FA1B15EF4668EF779A678D1D24D099C532E126E8BBF
|
||||
LoanBroker Psuedo-Account Address: rfhftuQGpqUVRcERZbY9htJshijKur7dS4
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Deposit and Withdraw First-loss Capital
|
||||
|
||||
```sh
|
||||
node coverDepositAndWithdraw.js
|
||||
```
|
||||
|
||||
The script should output the LoanBrokerCoverDeposit, cover balance after the deposit, the LoanBrokerCoverWithdraw transaction, and the cover balance after the withdrawal:
|
||||
|
||||
```sh
|
||||
Loan broker address: rKL3u76wNGdF2Th4EvCuHV5885T6h2iFTY
|
||||
LoanBrokerID: F133118D55342F7F78188BDC9259E8593853010878C9F6CEA0E2F56D829C6B15
|
||||
MPT ID: 0031034FF84EB2E8348A34F0A8889A54F45F180E80F12341
|
||||
|
||||
=== Preparing LoanBrokerCoverDeposit transaction ===
|
||||
|
||||
{
|
||||
"TransactionType": "LoanBrokerCoverDeposit",
|
||||
"Account": "rKL3u76wNGdF2Th4EvCuHV5885T6h2iFTY",
|
||||
"LoanBrokerID": "F133118D55342F7F78188BDC9259E8593853010878C9F6CEA0E2F56D829C6B15",
|
||||
"Amount": {
|
||||
"mpt_issuance_id": "0031034FF84EB2E8348A34F0A8889A54F45F180E80F12341",
|
||||
"value": "2000"
|
||||
}
|
||||
}
|
||||
|
||||
=== Submitting LoanBrokerCoverDeposit transaction ===
|
||||
|
||||
Cover deposit successful!
|
||||
|
||||
=== Cover Balance ===
|
||||
|
||||
LoanBroker Pseudo-Account: rf5FREUsutDyDAaVPPvZnNmoEETr21sPDd
|
||||
Cover balance after deposit: 2000 TSTUSD
|
||||
|
||||
=== Preparing LoanBrokerCoverWithdraw transaction ===
|
||||
|
||||
{
|
||||
"TransactionType": "LoanBrokerCoverWithdraw",
|
||||
"Account": "rKL3u76wNGdF2Th4EvCuHV5885T6h2iFTY",
|
||||
"LoanBrokerID": "F133118D55342F7F78188BDC9259E8593853010878C9F6CEA0E2F56D829C6B15",
|
||||
"Amount": {
|
||||
"mpt_issuance_id": "0031034FF84EB2E8348A34F0A8889A54F45F180E80F12341",
|
||||
"value": "1000"
|
||||
}
|
||||
}
|
||||
|
||||
=== Submitting LoanBrokerCoverWithdraw transaction ===
|
||||
|
||||
Cover withdraw successful!
|
||||
|
||||
=== Updated Cover Balance ===
|
||||
|
||||
LoanBroker Pseudo-Account: rf5FREUsutDyDAaVPPvZnNmoEETr21sPDd
|
||||
Cover balance after withdraw: 1000 TSTUSD
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Create a Loan
|
||||
|
||||
```sh
|
||||
node createLoan.js
|
||||
```
|
||||
|
||||
The script should output the LoanSet transaction, the updated LoanSet transaction with the loan broker signature, the final LoanSet transaction with the borrower signature added, and then the loan information:
|
||||
|
||||
```sh
|
||||
Loan broker address: rKL3u76wNGdF2Th4EvCuHV5885T6h2iFTY
|
||||
Borrower address: r46Ef5jjnaY7CDP7g22sQgSJJPQEBSmbWA
|
||||
LoanBrokerID: F133118D55342F7F78188BDC9259E8593853010878C9F6CEA0E2F56D829C6B15
|
||||
|
||||
=== Preparing LoanSet transaction ===
|
||||
|
||||
{
|
||||
"TransactionType": "LoanSet",
|
||||
"Account": "rKL3u76wNGdF2Th4EvCuHV5885T6h2iFTY",
|
||||
"Counterparty": "r46Ef5jjnaY7CDP7g22sQgSJJPQEBSmbWA",
|
||||
"LoanBrokerID": "F133118D55342F7F78188BDC9259E8593853010878C9F6CEA0E2F56D829C6B15",
|
||||
"PrincipalRequested": 1000,
|
||||
"InterestRate": 500,
|
||||
"PaymentTotal": 12,
|
||||
"PaymentInterval": 2592000,
|
||||
"GracePeriod": 604800,
|
||||
"LoanOriginationFee": 100,
|
||||
"LoanServiceFee": 10,
|
||||
"Flags": 0,
|
||||
"Sequence": 3212122,
|
||||
"LastLedgerSequence": 3212233,
|
||||
"Fee": "2"
|
||||
}
|
||||
|
||||
=== Adding loan broker signature ===
|
||||
|
||||
TxnSignature: 44348B918E780608534A9499B9990470E6A3C8E5C7DAC33BF2A5EFA0C292D17B3267D3A177A363CC832D6C6DA36E41CB64909C39CA5D55CF36D232DA49022400
|
||||
SigningPubKey: ED37EF81218C3C97389A11F07C8339C2880CEAF1A8C6EB539C616D69EF5EBC688C
|
||||
|
||||
Signed loanSetTx for borrower to sign over:
|
||||
{
|
||||
"Account": "rKL3u76wNGdF2Th4EvCuHV5885T6h2iFTY",
|
||||
"Counterparty": "r46Ef5jjnaY7CDP7g22sQgSJJPQEBSmbWA",
|
||||
"Fee": "2",
|
||||
"Flags": 0,
|
||||
"GracePeriod": 604800,
|
||||
"InterestRate": 500,
|
||||
"LastLedgerSequence": 3212233,
|
||||
"LoanBrokerID": "F133118D55342F7F78188BDC9259E8593853010878C9F6CEA0E2F56D829C6B15",
|
||||
"LoanOriginationFee": "100",
|
||||
"LoanServiceFee": "10",
|
||||
"PaymentInterval": 2592000,
|
||||
"PaymentTotal": 12,
|
||||
"PrincipalRequested": "1000",
|
||||
"Sequence": 3212122,
|
||||
"SigningPubKey": "ED37EF81218C3C97389A11F07C8339C2880CEAF1A8C6EB539C616D69EF5EBC688C",
|
||||
"TransactionType": "LoanSet",
|
||||
"TxnSignature": "44348B918E780608534A9499B9990470E6A3C8E5C7DAC33BF2A5EFA0C292D17B3267D3A177A363CC832D6C6DA36E41CB64909C39CA5D55CF36D232DA49022400"
|
||||
}
|
||||
|
||||
=== Adding borrower signature ===
|
||||
|
||||
Borrower TxnSignature: 2D17F5BAED2540CD875B009A99B02649E24A5DCDFDC5BAFCB2DC41F998FE4AFBDD6BDF8BDF1C3C857ED8DD638F10BEA10295812155D9759E3ADED9D6208F150F
|
||||
Borrower SigningPubKey: ED4C7C0127EFEAFD04B2CDFA1CA3A8EF5933227C610031DF2130010B73CBBBDCDA
|
||||
|
||||
Fully signed LoanSet transaction:
|
||||
{
|
||||
"Account": "rKL3u76wNGdF2Th4EvCuHV5885T6h2iFTY",
|
||||
"Counterparty": "r46Ef5jjnaY7CDP7g22sQgSJJPQEBSmbWA",
|
||||
"CounterpartySignature": {
|
||||
"SigningPubKey": "ED4C7C0127EFEAFD04B2CDFA1CA3A8EF5933227C610031DF2130010B73CBBBDCDA",
|
||||
"TxnSignature": "2D17F5BAED2540CD875B009A99B02649E24A5DCDFDC5BAFCB2DC41F998FE4AFBDD6BDF8BDF1C3C857ED8DD638F10BEA10295812155D9759E3ADED9D6208F150F"
|
||||
},
|
||||
"Fee": "2",
|
||||
"Flags": 0,
|
||||
"GracePeriod": 604800,
|
||||
"InterestRate": 500,
|
||||
"LastLedgerSequence": 3212233,
|
||||
"LoanBrokerID": "F133118D55342F7F78188BDC9259E8593853010878C9F6CEA0E2F56D829C6B15",
|
||||
"LoanOriginationFee": "100",
|
||||
"LoanServiceFee": "10",
|
||||
"PaymentInterval": 2592000,
|
||||
"PaymentTotal": 12,
|
||||
"PrincipalRequested": "1000",
|
||||
"Sequence": 3212122,
|
||||
"SigningPubKey": "ED37EF81218C3C97389A11F07C8339C2880CEAF1A8C6EB539C616D69EF5EBC688C",
|
||||
"TransactionType": "LoanSet",
|
||||
"TxnSignature": "44348B918E780608534A9499B9990470E6A3C8E5C7DAC33BF2A5EFA0C292D17B3267D3A177A363CC832D6C6DA36E41CB64909C39CA5D55CF36D232DA49022400"
|
||||
}
|
||||
|
||||
=== Submitting signed LoanSet transaction ===
|
||||
|
||||
Loan created successfully!
|
||||
|
||||
=== Loan Information ===
|
||||
|
||||
{
|
||||
"Borrower": "r46Ef5jjnaY7CDP7g22sQgSJJPQEBSmbWA",
|
||||
"GracePeriod": 604800,
|
||||
"InterestRate": 500,
|
||||
"LoanBrokerID": "F133118D55342F7F78188BDC9259E8593853010878C9F6CEA0E2F56D829C6B15",
|
||||
"LoanOriginationFee": "100",
|
||||
"LoanSequence": 3,
|
||||
"LoanServiceFee": "10",
|
||||
"NextPaymentDueDate": 825408182,
|
||||
"PaymentInterval": 2592000,
|
||||
"PaymentRemaining": 12,
|
||||
"PeriodicPayment": "83.55610375293148956",
|
||||
"PrincipalOutstanding": "1000",
|
||||
"StartDate": 822816182,
|
||||
"TotalValueOutstanding": "1003"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Manage a Loan
|
||||
|
||||
```sh
|
||||
node loanManage.js
|
||||
```
|
||||
|
||||
The script should output the initial status of the loan, the LoanManage transaction, and the updated loan status and grace period after impairment. The script will countdown the grace period before outputting another LoanManage transaction, and then the final flags on the loan.
|
||||
|
||||
```sh
|
||||
Loan broker address: rKL3u76wNGdF2Th4EvCuHV5885T6h2iFTY
|
||||
LoanID: D28764B238CF3F7D7BF4AFD07394838EDD5F278B838F97A55BEAEC1E5152719C
|
||||
|
||||
=== Loan Status ===
|
||||
|
||||
Total Amount Owed: 1001 TSTUSD.
|
||||
Payment Due Date: 2/25/2026, 11:58:20 PM
|
||||
|
||||
=== Preparing LoanManage transaction to impair loan ===
|
||||
|
||||
{
|
||||
"TransactionType": "LoanManage",
|
||||
"Account": "rKL3u76wNGdF2Th4EvCuHV5885T6h2iFTY",
|
||||
"LoanID": "D28764B238CF3F7D7BF4AFD07394838EDD5F278B838F97A55BEAEC1E5152719C",
|
||||
"Flags": 131072
|
||||
}
|
||||
|
||||
=== Submitting LoanManage impairment transaction ===
|
||||
|
||||
Loan impaired successfully!
|
||||
New Payment Due Date: 1/27/2026, 12:05:02 AM
|
||||
Grace Period: 60 seconds
|
||||
|
||||
=== Countdown until loan can be defaulted ===
|
||||
|
||||
Grace period expired. Loan can now be defaulted.
|
||||
|
||||
=== Preparing LoanManage transaction to default loan ===
|
||||
|
||||
{
|
||||
"TransactionType": "LoanManage",
|
||||
"Account": "rKL3u76wNGdF2Th4EvCuHV5885T6h2iFTY",
|
||||
"LoanID": "D28764B238CF3F7D7BF4AFD07394838EDD5F278B838F97A55BEAEC1E5152719C",
|
||||
"Flags": 65536
|
||||
}
|
||||
|
||||
=== Submitting LoanManage default transaction ===
|
||||
|
||||
Loan defaulted successfully!
|
||||
|
||||
=== Checking final loan status ===
|
||||
|
||||
Final loan flags (parsed): {"tfLoanDefault":true,"tfLoanImpair":true}
|
||||
```
|
||||
|
||||
## Pay a Loan
|
||||
|
||||
```sh
|
||||
node loanPay.js
|
||||
```
|
||||
|
||||
The script should output the amount required to totally pay off a loan, the LoanPay transaction, the amount due after the payment, the LoanDelete transaction, and then the status of the loan ledger entry:
|
||||
|
||||
```sh
|
||||
Borrower address: r46Ef5jjnaY7CDP7g22sQgSJJPQEBSmbWA
|
||||
LoanID: 8AC2B4425E604E7BB1082DD2BF2CA902B5087143B7775BE0A4DA954D3F52D06E
|
||||
MPT ID: 0031034FF84EB2E8348A34F0A8889A54F45F180E80F12341
|
||||
|
||||
=== Loan Status ===
|
||||
|
||||
Amount Owed: 1001 TSTUSD
|
||||
Loan Service Fee: 10 TSTUSD
|
||||
Total Payment Due (including fees): 1011 TSTUSD
|
||||
|
||||
=== Preparing LoanPay transaction ===
|
||||
|
||||
{
|
||||
"TransactionType": "LoanPay",
|
||||
"Account": "r46Ef5jjnaY7CDP7g22sQgSJJPQEBSmbWA",
|
||||
"LoanID": "8AC2B4425E604E7BB1082DD2BF2CA902B5087143B7775BE0A4DA954D3F52D06E",
|
||||
"Amount": {
|
||||
"mpt_issuance_id": "0031034FF84EB2E8348A34F0A8889A54F45F180E80F12341",
|
||||
"value": "1011"
|
||||
}
|
||||
}
|
||||
|
||||
=== Submitting LoanPay transaction ===
|
||||
|
||||
Loan paid successfully!
|
||||
|
||||
=== Loan Status After Payment ===
|
||||
|
||||
Outstanding Loan Balance: Loan fully paid off!
|
||||
|
||||
=== Preparing LoanDelete transaction ===
|
||||
|
||||
{
|
||||
"TransactionType": "LoanDelete",
|
||||
"Account": "r46Ef5jjnaY7CDP7g22sQgSJJPQEBSmbWA",
|
||||
"LoanID": "8AC2B4425E604E7BB1082DD2BF2CA902B5087143B7775BE0A4DA954D3F52D06E"
|
||||
}
|
||||
|
||||
=== Submitting LoanDelete transaction ===
|
||||
|
||||
Loan deleted successfully!
|
||||
|
||||
=== Verifying Loan Deletion ===
|
||||
|
||||
Loan has been successfully removed from the XRP Ledger!
|
||||
```
|
||||
108
_code-samples/lending-protocol/js/coverDepositAndWithdraw.js
Normal file
108
_code-samples/lending-protocol/js/coverDepositAndWithdraw.js
Normal file
@@ -0,0 +1,108 @@
|
||||
// IMPORTANT: This example deposits and withdraws first-loss capital from a
|
||||
// preconfigured LoanBroker entry.
|
||||
|
||||
import fs from 'fs'
|
||||
import { execSync } from 'child_process'
|
||||
import xrpl from 'xrpl'
|
||||
|
||||
// Connect to the network ----------------------
|
||||
const client = new xrpl.Client('wss://s.devnet.rippletest.net:51233')
|
||||
await client.connect()
|
||||
|
||||
// This step checks for the necessary setup data to run the lending protocol tutorials.
|
||||
// If missing, lendingSetup.js will generate the data.
|
||||
if (!fs.existsSync('lendingSetup.json')) {
|
||||
console.log(`\n=== Lending tutorial data doesn't exist. Running setup script... ===\n`)
|
||||
execSync('node lendingSetup.js', { stdio: 'inherit' })
|
||||
}
|
||||
|
||||
// Load preconfigured accounts and LoanBrokerID.
|
||||
const setupData = JSON.parse(fs.readFileSync('lendingSetup.json', 'utf8'))
|
||||
|
||||
// You can replace these values with your own
|
||||
const loanBroker = xrpl.Wallet.fromSeed(setupData.loanBroker.seed)
|
||||
const loanBrokerID = setupData.loanBrokerID
|
||||
const mptID = setupData.mptID
|
||||
|
||||
console.log(`\nLoan broker address: ${loanBroker.address}`)
|
||||
console.log(`LoanBrokerID: ${loanBrokerID}`)
|
||||
console.log(`MPT ID: ${mptID}`)
|
||||
|
||||
// Prepare LoanBrokerCoverDeposit transaction ----------------------
|
||||
console.log(`\n=== Preparing LoanBrokerCoverDeposit transaction ===\n`)
|
||||
const coverDepositTx = {
|
||||
TransactionType: 'LoanBrokerCoverDeposit',
|
||||
Account: loanBroker.address,
|
||||
LoanBrokerID: loanBrokerID,
|
||||
Amount: {
|
||||
mpt_issuance_id: mptID,
|
||||
value: '2000'
|
||||
}
|
||||
}
|
||||
|
||||
// Validate the transaction structure before submitting
|
||||
xrpl.validate(coverDepositTx)
|
||||
console.log(JSON.stringify(coverDepositTx, null, 2))
|
||||
|
||||
// Sign, submit, and wait for deposit validation ----------------------
|
||||
console.log(`\n=== Submitting LoanBrokerCoverDeposit transaction ===\n`)
|
||||
const depositResponse = await client.submitAndWait(coverDepositTx, {
|
||||
wallet: loanBroker,
|
||||
autofill: true
|
||||
})
|
||||
if (depositResponse.result.meta.TransactionResult !== 'tesSUCCESS') {
|
||||
const resultCode = depositResponse.result.meta.TransactionResult
|
||||
console.error('Error: Unable to deposit cover:', resultCode)
|
||||
await client.disconnect()
|
||||
process.exit(1)
|
||||
}
|
||||
console.log('Cover deposit successful!')
|
||||
|
||||
// Extract cover balance from the transaction result
|
||||
console.log(`\n=== Cover Balance ===\n`)
|
||||
let loanBrokerNode = depositResponse.result.meta.AffectedNodes.find(node =>
|
||||
node.ModifiedNode?.LedgerEntryType === 'LoanBroker'
|
||||
)
|
||||
// First-loss capital is stored in the LoanBroker's pseudo-account.
|
||||
console.log(`LoanBroker Pseudo-Account: ${loanBrokerNode.ModifiedNode.FinalFields.Account}`)
|
||||
console.log(`Cover balance after deposit: ${loanBrokerNode.ModifiedNode.FinalFields.CoverAvailable} TSTUSD`)
|
||||
|
||||
// Prepare LoanBrokerCoverWithdraw transaction ----------------------
|
||||
console.log(`\n=== Preparing LoanBrokerCoverWithdraw transaction ===\n`)
|
||||
const coverWithdrawTx = {
|
||||
TransactionType: 'LoanBrokerCoverWithdraw',
|
||||
Account: loanBroker.address,
|
||||
LoanBrokerID: loanBrokerID,
|
||||
Amount: {
|
||||
mpt_issuance_id: mptID,
|
||||
value: '1000'
|
||||
}
|
||||
}
|
||||
|
||||
// Validate the transaction structure before submitting
|
||||
xrpl.validate(coverWithdrawTx)
|
||||
console.log(JSON.stringify(coverWithdrawTx, null, 2))
|
||||
|
||||
// Sign, submit, and wait for withdraw validation ----------------------
|
||||
console.log(`\n=== Submitting LoanBrokerCoverWithdraw transaction ===\n`)
|
||||
const withdrawResponse = await client.submitAndWait(coverWithdrawTx, {
|
||||
wallet: loanBroker,
|
||||
autofill: true
|
||||
})
|
||||
if (withdrawResponse.result.meta.TransactionResult !== 'tesSUCCESS') {
|
||||
const resultCode = withdrawResponse.result.meta.TransactionResult
|
||||
console.error('Error: Unable to withdraw cover:', resultCode)
|
||||
await client.disconnect()
|
||||
process.exit(1)
|
||||
}
|
||||
console.log('Cover withdraw successful!')
|
||||
|
||||
// Extract updated cover balance from the transaction result
|
||||
console.log(`\n=== Updated Cover Balance ===\n`)
|
||||
loanBrokerNode = withdrawResponse.result.meta.AffectedNodes.find(node =>
|
||||
node.ModifiedNode?.LedgerEntryType === 'LoanBroker'
|
||||
)
|
||||
console.log(`LoanBroker Pseudo-Account: ${loanBrokerNode.ModifiedNode.FinalFields.Account}`)
|
||||
console.log(`Cover balance after withdraw: ${loanBrokerNode.ModifiedNode.FinalFields.CoverAvailable} TSTUSD`)
|
||||
|
||||
await client.disconnect()
|
||||
130
_code-samples/lending-protocol/js/createLoan.js
Normal file
130
_code-samples/lending-protocol/js/createLoan.js
Normal file
@@ -0,0 +1,130 @@
|
||||
// IMPORTANT: This example creates a loan using a preconfigured
|
||||
// loan broker, borrower, and private vault.
|
||||
|
||||
import fs from 'fs'
|
||||
import { execSync } from 'child_process'
|
||||
import xrpl from 'xrpl'
|
||||
|
||||
// Connect to the network ----------------------
|
||||
const client = new xrpl.Client('wss://s.devnet.rippletest.net:51233')
|
||||
await client.connect()
|
||||
|
||||
// This step checks for the necessary setup data to run the lending protocol tutorials.
|
||||
// If missing, lendingSetup.js will generate the data.
|
||||
if (!fs.existsSync('lendingSetup.json')) {
|
||||
console.log(`\n=== Lending tutorial data doesn't exist. Running setup script... ===\n`)
|
||||
execSync('node lendingSetup.js', { stdio: 'inherit' })
|
||||
}
|
||||
|
||||
// Load preconfigured accounts and LoanBrokerID.
|
||||
const setupData = JSON.parse(fs.readFileSync('lendingSetup.json', 'utf8'))
|
||||
|
||||
// You can replace these values with your own
|
||||
const loanBroker = xrpl.Wallet.fromSeed(setupData.loanBroker.seed)
|
||||
const borrower = xrpl.Wallet.fromSeed(setupData.borrower.seed)
|
||||
const loanBrokerID = setupData.loanBrokerID
|
||||
|
||||
console.log(`\nLoan broker address: ${loanBroker.address}`)
|
||||
console.log(`Borrower address: ${borrower.address}`)
|
||||
console.log(`LoanBrokerID: ${loanBrokerID}`)
|
||||
|
||||
// Prepare LoanSet transaction ----------------------
|
||||
// Account and Counterparty accounts can be swapped, but determines signing order.
|
||||
// Account signs first, Counterparty signs second.
|
||||
console.log(`\n=== Preparing LoanSet transaction ===\n`)
|
||||
|
||||
// Suppress unnecessary console warning from autofilling LoanSet.
|
||||
console.warn = () => {}
|
||||
|
||||
const loanSetTx = await client.autofill({
|
||||
TransactionType: 'LoanSet',
|
||||
Account: loanBroker.address,
|
||||
Counterparty: borrower.address,
|
||||
LoanBrokerID: loanBrokerID,
|
||||
PrincipalRequested: 1000,
|
||||
InterestRate: 500,
|
||||
PaymentTotal: 12,
|
||||
PaymentInterval: 2592000,
|
||||
GracePeriod: 604800,
|
||||
LoanOriginationFee: 100,
|
||||
LoanServiceFee: 10
|
||||
})
|
||||
|
||||
console.log(JSON.stringify(loanSetTx, null, 2))
|
||||
|
||||
// Loan broker signs first
|
||||
console.log(`\n=== Adding loan broker signature ===\n`)
|
||||
const loanBrokerSignature = await client.request({
|
||||
command: 'sign',
|
||||
tx_json: loanSetTx,
|
||||
secret: loanBroker.seed
|
||||
})
|
||||
|
||||
const loanBrokerSignatureResult = loanBrokerSignature.result.tx_json
|
||||
|
||||
console.log(`TxnSignature: ${loanBrokerSignatureResult.TxnSignature}`)
|
||||
console.log(`SigningPubKey: ${loanBrokerSignatureResult.SigningPubKey}\n`)
|
||||
console.log(`Signed loanSetTx for borrower to sign over:\n${JSON.stringify(loanBrokerSignatureResult, null, 2)}`)
|
||||
|
||||
// Borrower signs second
|
||||
console.log(`\n=== Adding borrower signature ===\n`)
|
||||
|
||||
const borrowerSignature = await client.request({
|
||||
command: 'sign',
|
||||
tx_json: loanBrokerSignatureResult,
|
||||
secret: borrower.seed,
|
||||
signature_target: 'CounterpartySignature'
|
||||
})
|
||||
|
||||
const borrowerSignatureResult = borrowerSignature.result.tx_json
|
||||
|
||||
console.log(`Borrower TxnSignature: ${borrowerSignatureResult.CounterpartySignature.TxnSignature}`)
|
||||
console.log(`Borrower SigningPubKey: ${borrowerSignatureResult.CounterpartySignature.SigningPubKey}`)
|
||||
|
||||
// Validate the transaction structure before submitting.
|
||||
xrpl.validate(borrowerSignatureResult)
|
||||
console.log(`\nFully signed LoanSet transaction:\n${JSON.stringify(borrowerSignatureResult, null, 2)}`)
|
||||
|
||||
// Submit and wait for validation ----------------------
|
||||
console.log(`\n=== Submitting signed LoanSet transaction ===\n`)
|
||||
|
||||
// Submit the transaction
|
||||
const submitResult = await client.submit(borrowerSignatureResult)
|
||||
const txHash = submitResult.result.tx_json.hash
|
||||
|
||||
// Helper function to check tx hash is validated
|
||||
async function validateTx (hash, maxRetries = 20) {
|
||||
for (let i = 0; i < maxRetries; i++) {
|
||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||
try {
|
||||
const tx = await client.request({ command: 'tx', transaction: hash })
|
||||
if (tx.result.validated) {
|
||||
return tx
|
||||
}
|
||||
} catch (error) {
|
||||
// Transaction not validated yet, check again
|
||||
}
|
||||
}
|
||||
console.error(`Error: Transaction ${hash} not validated after ${maxRetries} attempts.`)
|
||||
await client.disconnect()
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
// Validate the transaction
|
||||
const submitResponse = await validateTx(txHash)
|
||||
if (submitResponse.result.meta.TransactionResult !== 'tesSUCCESS') {
|
||||
const resultCode = submitResponse.result.meta.TransactionResult
|
||||
console.error('Error: Unable to create loan:', resultCode)
|
||||
await client.disconnect()
|
||||
process.exit(1)
|
||||
}
|
||||
console.log('Loan created successfully!')
|
||||
|
||||
// Extract loan information from the transaction result.
|
||||
console.log(`\n=== Loan Information ===\n`)
|
||||
const loanNode = submitResponse.result.meta.AffectedNodes.find(node =>
|
||||
node.CreatedNode?.LedgerEntryType === 'Loan'
|
||||
)
|
||||
console.log(JSON.stringify(loanNode.CreatedNode.NewFields, null, 2))
|
||||
|
||||
await client.disconnect()
|
||||
66
_code-samples/lending-protocol/js/createLoanBroker.js
Normal file
66
_code-samples/lending-protocol/js/createLoanBroker.js
Normal file
@@ -0,0 +1,66 @@
|
||||
// IMPORTANT: This example creates a loan broker using an existing account
|
||||
// that has already created a PRIVATE vault.
|
||||
// If you want to create a loan broker for a PUBLIC vault, you can replace the vaultID
|
||||
// and loanBroker values with your own.
|
||||
|
||||
import fs from 'fs'
|
||||
import { execSync } from 'child_process'
|
||||
import xrpl from 'xrpl'
|
||||
|
||||
// Connect to the network ----------------------
|
||||
const client = new xrpl.Client('wss://s.devnet.rippletest.net:51233')
|
||||
await client.connect()
|
||||
|
||||
// This step checks for the necessary setup data to run the lending protocol tutorials.
|
||||
// If missing, lendingSetup.js will generate the data.
|
||||
if (!fs.existsSync('lendingSetup.json')) {
|
||||
console.log(`\n=== Lending tutorial data doesn't exist. Running setup script... ===\n`)
|
||||
execSync('node lendingSetup.js', { stdio: 'inherit' })
|
||||
}
|
||||
|
||||
// Load preconfigured accounts and VaultID.
|
||||
const setupData = JSON.parse(fs.readFileSync('lendingSetup.json', 'utf8'))
|
||||
|
||||
// You can replace these values with your own
|
||||
const loanBroker = xrpl.Wallet.fromSeed(setupData.loanBroker.seed)
|
||||
const vaultID = setupData.vaultID
|
||||
|
||||
console.log(`\nLoan broker/vault owner address: ${loanBroker.address}`)
|
||||
console.log(`Vault ID: ${vaultID}`)
|
||||
|
||||
// Prepare LoanBrokerSet transaction ----------------------
|
||||
console.log(`\n=== Preparing LoanBrokerSet transaction ===\n`)
|
||||
const loanBrokerSetTx = {
|
||||
TransactionType: 'LoanBrokerSet',
|
||||
Account: loanBroker.address,
|
||||
VaultID: vaultID,
|
||||
ManagementFeeRate: 1000
|
||||
}
|
||||
|
||||
// Validate the transaction structure before submitting
|
||||
xrpl.validate(loanBrokerSetTx)
|
||||
console.log(JSON.stringify(loanBrokerSetTx, null, 2))
|
||||
|
||||
// Submit, sign, and wait for validation ----------------------
|
||||
console.log(`\n=== Submitting LoanBrokerSet transaction ===\n`)
|
||||
const submitResponse = await client.submitAndWait(loanBrokerSetTx, {
|
||||
wallet: loanBroker,
|
||||
autofill: true
|
||||
})
|
||||
if (submitResponse.result.meta.TransactionResult !== 'tesSUCCESS') {
|
||||
const resultCode = submitResponse.result.meta.TransactionResult
|
||||
console.error('Error: Unable to create loan broker:', resultCode)
|
||||
await client.disconnect()
|
||||
process.exit(1)
|
||||
}
|
||||
console.log('Loan broker created successfully!')
|
||||
|
||||
// Extract loan broker information from the transaction result
|
||||
console.log(`\n=== Loan Broker Information ===\n`)
|
||||
const loanBrokerNode = submitResponse.result.meta.AffectedNodes.find(node =>
|
||||
node.CreatedNode?.LedgerEntryType === 'LoanBroker'
|
||||
)
|
||||
console.log(`LoanBroker ID: ${loanBrokerNode.CreatedNode.LedgerIndex}`)
|
||||
console.log(`LoanBroker Psuedo-Account Address: ${loanBrokerNode.CreatedNode.NewFields.Account}`)
|
||||
|
||||
await client.disconnect()
|
||||
374
_code-samples/lending-protocol/js/lendingSetup.js
Normal file
374
_code-samples/lending-protocol/js/lendingSetup.js
Normal file
@@ -0,0 +1,374 @@
|
||||
import xrpl from 'xrpl'
|
||||
import fs from 'fs'
|
||||
|
||||
// Setup script for lending protocol tutorials
|
||||
|
||||
process.stdout.write('Setting up tutorial: 0/6\r')
|
||||
|
||||
const client = new xrpl.Client('wss://s.devnet.rippletest.net:51233')
|
||||
await client.connect()
|
||||
|
||||
// Create and fund wallets
|
||||
const [
|
||||
{ wallet: loanBroker },
|
||||
{ wallet: borrower },
|
||||
{ wallet: depositor },
|
||||
{ wallet: credentialIssuer }
|
||||
] = await Promise.all([
|
||||
client.fundWallet(),
|
||||
client.fundWallet(),
|
||||
client.fundWallet(),
|
||||
client.fundWallet()
|
||||
])
|
||||
|
||||
process.stdout.write('Setting up tutorial: 1/6\r')
|
||||
|
||||
// Issue MPT with depositor
|
||||
// Create tickets for later use with loanBroker
|
||||
// Set up credentials and domain with credentialIssuer
|
||||
const credentialType = xrpl.convertStringToHex('KYC-Verified')
|
||||
const mptData = {
|
||||
ticker: 'TSTUSD',
|
||||
name: 'Test USD MPT',
|
||||
desc: 'A sample non-yield-bearing stablecoin backed by U.S. Treasuries.',
|
||||
icon: 'https://example.org/tstusd-icon.png',
|
||||
asset_class: 'rwa',
|
||||
asset_subclass: 'stablecoin',
|
||||
issuer_name: 'Example Treasury Reserve Co.',
|
||||
uris: [
|
||||
{
|
||||
uri: 'https://exampletreasury.com/tstusd',
|
||||
category: 'website',
|
||||
title: 'Product Page'
|
||||
},
|
||||
{
|
||||
uri: 'https://exampletreasury.com/tstusd/reserve',
|
||||
category: 'docs',
|
||||
title: 'Reserve Attestation'
|
||||
}
|
||||
],
|
||||
additional_info: {
|
||||
reserve_type: 'U.S. Treasury Bills',
|
||||
custody_provider: 'Example Custodian Bank',
|
||||
audit_frequency: 'Monthly',
|
||||
last_audit_date: '2026-01-15',
|
||||
pegged_currency: 'USD'
|
||||
}
|
||||
}
|
||||
|
||||
const [ticketCreateResponse, mptIssuanceResponse] = await Promise.all([
|
||||
client.submitAndWait({
|
||||
TransactionType: 'TicketCreate',
|
||||
Account: loanBroker.address,
|
||||
TicketCount: 2
|
||||
}, { wallet: loanBroker, autofill: true }),
|
||||
client.submitAndWait({
|
||||
TransactionType: 'MPTokenIssuanceCreate',
|
||||
Account: depositor.address,
|
||||
MaximumAmount: '100000000',
|
||||
TransferFee: 0,
|
||||
Flags:
|
||||
xrpl.MPTokenIssuanceCreateFlags.tfMPTCanTransfer |
|
||||
xrpl.MPTokenIssuanceCreateFlags.tfMPTCanTrade,
|
||||
MPTokenMetadata: xrpl.encodeMPTokenMetadata(mptData)
|
||||
}, { wallet: depositor, autofill: true }),
|
||||
client.submitAndWait({
|
||||
TransactionType: 'Batch',
|
||||
Account: credentialIssuer.address,
|
||||
Flags: xrpl.BatchFlags.tfAllOrNothing,
|
||||
RawTransactions: [
|
||||
{
|
||||
RawTransaction: {
|
||||
TransactionType: 'CredentialCreate',
|
||||
Account: credentialIssuer.address,
|
||||
Subject: loanBroker.address,
|
||||
CredentialType: credentialType,
|
||||
Flags: xrpl.GlobalFlags.tfInnerBatchTxn
|
||||
}
|
||||
},
|
||||
{
|
||||
RawTransaction: {
|
||||
TransactionType: 'CredentialCreate',
|
||||
Account: credentialIssuer.address,
|
||||
Subject: borrower.address,
|
||||
CredentialType: credentialType,
|
||||
Flags: xrpl.GlobalFlags.tfInnerBatchTxn
|
||||
}
|
||||
},
|
||||
{
|
||||
RawTransaction: {
|
||||
TransactionType: 'CredentialCreate',
|
||||
Account: credentialIssuer.address,
|
||||
Subject: depositor.address,
|
||||
CredentialType: credentialType,
|
||||
Flags: xrpl.GlobalFlags.tfInnerBatchTxn
|
||||
}
|
||||
},
|
||||
{
|
||||
RawTransaction: {
|
||||
TransactionType: 'PermissionedDomainSet',
|
||||
Account: credentialIssuer.address,
|
||||
AcceptedCredentials: [
|
||||
{
|
||||
Credential: {
|
||||
Issuer: credentialIssuer.address,
|
||||
CredentialType: credentialType
|
||||
}
|
||||
}
|
||||
],
|
||||
Flags: xrpl.GlobalFlags.tfInnerBatchTxn
|
||||
}
|
||||
}
|
||||
]
|
||||
}, { wallet: credentialIssuer, autofill: true })
|
||||
])
|
||||
|
||||
// Extract ticket sequence numbers
|
||||
const tickets = ticketCreateResponse.result.meta.AffectedNodes
|
||||
.filter(node => node.CreatedNode?.LedgerEntryType === 'Ticket')
|
||||
.map(node => node.CreatedNode.NewFields.TicketSequence)
|
||||
|
||||
// Extract MPT issuance ID
|
||||
const mptID = mptIssuanceResponse.result.meta.mpt_issuance_id
|
||||
|
||||
// Get domain ID
|
||||
const credentialIssuerObjects = await client.request({
|
||||
command: 'account_objects',
|
||||
account: credentialIssuer.address,
|
||||
ledger_index: 'validated'
|
||||
})
|
||||
const domainID = credentialIssuerObjects.result.account_objects.find(node =>
|
||||
node.LedgerEntryType === 'PermissionedDomain'
|
||||
).index
|
||||
|
||||
process.stdout.write('Setting up tutorial: 2/6\r')
|
||||
|
||||
// Accept credentials and authorize MPT for each account
|
||||
await Promise.all([
|
||||
...([loanBroker, borrower].map(wallet =>
|
||||
client.submitAndWait({
|
||||
TransactionType: 'Batch',
|
||||
Account: wallet.address,
|
||||
Flags: xrpl.BatchFlags.tfAllOrNothing,
|
||||
RawTransactions: [
|
||||
{
|
||||
RawTransaction: {
|
||||
TransactionType: 'CredentialAccept',
|
||||
Account: wallet.address,
|
||||
Issuer: credentialIssuer.address,
|
||||
CredentialType: credentialType,
|
||||
Flags: xrpl.GlobalFlags.tfInnerBatchTxn
|
||||
}
|
||||
},
|
||||
{
|
||||
RawTransaction: {
|
||||
TransactionType: 'MPTokenAuthorize',
|
||||
Account: wallet.address,
|
||||
MPTokenIssuanceID: mptID,
|
||||
Flags: xrpl.GlobalFlags.tfInnerBatchTxn
|
||||
}
|
||||
}
|
||||
]
|
||||
}, { wallet, autofill: true })
|
||||
)),
|
||||
// Depositor only needs to accept credentials
|
||||
client.submitAndWait({
|
||||
TransactionType: 'CredentialAccept',
|
||||
Account: depositor.address,
|
||||
Issuer: credentialIssuer.address,
|
||||
CredentialType: credentialType
|
||||
}, { wallet: depositor, autofill: true })
|
||||
])
|
||||
|
||||
process.stdout.write('Setting up tutorial: 3/6\r')
|
||||
|
||||
// Create private vault and distribute MPT to accounts
|
||||
const [vaultCreateResponse] = await Promise.all([
|
||||
client.submitAndWait({
|
||||
TransactionType: 'VaultCreate',
|
||||
Account: loanBroker.address,
|
||||
Asset: {
|
||||
mpt_issuance_id: mptID
|
||||
},
|
||||
Flags: xrpl.VaultCreateFlags.tfVaultPrivate,
|
||||
DomainID: domainID
|
||||
}, { wallet: loanBroker, autofill: true }),
|
||||
client.submitAndWait({
|
||||
TransactionType: 'Batch',
|
||||
Account: depositor.address,
|
||||
Flags: xrpl.BatchFlags.tfAllOrNothing,
|
||||
RawTransactions: [
|
||||
{
|
||||
RawTransaction: {
|
||||
TransactionType: 'Payment',
|
||||
Account: depositor.address,
|
||||
Destination: loanBroker.address,
|
||||
Amount: {
|
||||
mpt_issuance_id: mptID,
|
||||
value: '5000'
|
||||
},
|
||||
Flags: xrpl.GlobalFlags.tfInnerBatchTxn
|
||||
}
|
||||
},
|
||||
{
|
||||
RawTransaction: {
|
||||
TransactionType: 'Payment',
|
||||
Account: depositor.address,
|
||||
Destination: borrower.address,
|
||||
Amount: {
|
||||
mpt_issuance_id: mptID,
|
||||
value: '2500'
|
||||
},
|
||||
Flags: xrpl.GlobalFlags.tfInnerBatchTxn
|
||||
}
|
||||
}
|
||||
]
|
||||
}, { wallet: depositor, autofill: true })
|
||||
])
|
||||
|
||||
const vaultID = vaultCreateResponse.result.meta.AffectedNodes.find(node =>
|
||||
node.CreatedNode?.LedgerEntryType === 'Vault'
|
||||
).CreatedNode.LedgerIndex
|
||||
|
||||
process.stdout.write('Setting up tutorial: 4/6\r')
|
||||
|
||||
// Create LoanBroker and deposit MPT into vault
|
||||
const [loanBrokerSetResponse] = await Promise.all([
|
||||
client.submitAndWait({
|
||||
TransactionType: 'LoanBrokerSet',
|
||||
Account: loanBroker.address,
|
||||
VaultID: vaultID
|
||||
}, { wallet: loanBroker, autofill: true }),
|
||||
client.submitAndWait({
|
||||
TransactionType: 'VaultDeposit',
|
||||
Account: depositor.address,
|
||||
VaultID: vaultID,
|
||||
Amount: {
|
||||
mpt_issuance_id: mptID,
|
||||
value: '50000000'
|
||||
}
|
||||
}, { wallet: depositor, autofill: true })
|
||||
])
|
||||
|
||||
const loanBrokerID = loanBrokerSetResponse.result.meta.AffectedNodes.find(node =>
|
||||
node.CreatedNode?.LedgerEntryType === 'LoanBroker'
|
||||
).CreatedNode.LedgerIndex
|
||||
|
||||
process.stdout.write('Setting up tutorial: 5/6\r')
|
||||
|
||||
// Create 2 identical loans with complete repayment due in 30 days
|
||||
|
||||
// Suppress unnecessary console warning from autofilling LoanSet.
|
||||
console.warn = () => {}
|
||||
|
||||
// Helper function to create and sign a LoanSet transaction
|
||||
async function createSignedLoanSetTx (ticketSequence) {
|
||||
const loanSetTx = await client.autofill({
|
||||
TransactionType: 'LoanSet',
|
||||
Account: loanBroker.address,
|
||||
Counterparty: borrower.address,
|
||||
LoanBrokerID: loanBrokerID,
|
||||
PrincipalRequested: 1000,
|
||||
InterestRate: 500,
|
||||
PaymentTotal: 1,
|
||||
PaymentInterval: 2592000,
|
||||
LoanOriginationFee: 100,
|
||||
LoanServiceFee: 10,
|
||||
Sequence: 0,
|
||||
TicketSequence: ticketSequence
|
||||
})
|
||||
|
||||
const loanBrokerSignature = await client.request({
|
||||
command: 'sign',
|
||||
tx_json: loanSetTx,
|
||||
secret: loanBroker.seed
|
||||
})
|
||||
|
||||
const borrowerSignature = await client.request({
|
||||
command: 'sign',
|
||||
tx_json: loanBrokerSignature.result.tx_json,
|
||||
secret: borrower.seed,
|
||||
signature_target: 'CounterpartySignature'
|
||||
})
|
||||
|
||||
return borrowerSignature.result.tx_json
|
||||
}
|
||||
|
||||
// Create and submit both loans
|
||||
const [signedLoan1, signedLoan2] = await Promise.all([
|
||||
createSignedLoanSetTx(tickets[0]),
|
||||
createSignedLoanSetTx(tickets[1])
|
||||
])
|
||||
|
||||
const [submitLoan1, submitLoan2] = await Promise.all([
|
||||
client.submit(signedLoan1),
|
||||
client.submit(signedLoan2)
|
||||
])
|
||||
const hash1 = submitLoan1.result.tx_json.hash
|
||||
const hash2 = submitLoan2.result.tx_json.hash
|
||||
|
||||
// Helper function to check tx hash is validated
|
||||
async function validateTx (hash, maxRetries = 20) {
|
||||
for (let i = 0; i < maxRetries; i++) {
|
||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||
try {
|
||||
const tx = await client.request({ command: 'tx', transaction: hash })
|
||||
if (tx.result.validated) {
|
||||
return tx
|
||||
}
|
||||
} catch (error) {
|
||||
// Transaction not validated yet, check again
|
||||
}
|
||||
}
|
||||
console.error(`Error: Transaction ${hash} not validated after ${maxRetries} attempts.`)
|
||||
await client.disconnect()
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const [submitResponse1, submitResponse2] = await Promise.all([
|
||||
validateTx(hash1),
|
||||
validateTx(hash2)
|
||||
])
|
||||
|
||||
const loanID1 = submitResponse1.result.meta.AffectedNodes.find(node =>
|
||||
node.CreatedNode?.LedgerEntryType === 'Loan'
|
||||
).CreatedNode.LedgerIndex
|
||||
|
||||
const loanID2 = submitResponse2.result.meta.AffectedNodes.find(node =>
|
||||
node.CreatedNode?.LedgerEntryType === 'Loan'
|
||||
).CreatedNode.LedgerIndex
|
||||
|
||||
process.stdout.write('Setting up tutorial: 6/6\r')
|
||||
|
||||
// Write setup data to JSON file
|
||||
const setupData = {
|
||||
description: 'This file is auto-generated by lendingSetup.js. It stores XRPL account info for use in lending protocol tutorials.',
|
||||
loanBroker: {
|
||||
address: loanBroker.address,
|
||||
seed: loanBroker.seed
|
||||
},
|
||||
borrower: {
|
||||
address: borrower.address,
|
||||
seed: borrower.seed
|
||||
},
|
||||
depositor: {
|
||||
address: depositor.address,
|
||||
seed: depositor.seed
|
||||
},
|
||||
credentialIssuer: {
|
||||
address: credentialIssuer.address,
|
||||
seed: credentialIssuer.seed
|
||||
},
|
||||
domainID,
|
||||
mptID,
|
||||
vaultID,
|
||||
loanBrokerID,
|
||||
loanID1,
|
||||
loanID2
|
||||
}
|
||||
|
||||
fs.writeFileSync('lendingSetup.json', JSON.stringify(setupData, null, 2))
|
||||
|
||||
process.stdout.write('Setting up tutorial: Complete!\n')
|
||||
|
||||
await client.disconnect()
|
||||
144
_code-samples/lending-protocol/js/loanManage.js
Normal file
144
_code-samples/lending-protocol/js/loanManage.js
Normal file
@@ -0,0 +1,144 @@
|
||||
// IMPORTANT: This example impairs an existing loan, which has a 60 second grace period.
|
||||
// After the 60 seconds pass, this example defaults the loan.
|
||||
|
||||
import fs from 'fs'
|
||||
import { execSync } from 'child_process'
|
||||
import xrpl from 'xrpl'
|
||||
|
||||
// Connect to the network ----------------------
|
||||
const client = new xrpl.Client('wss://s.devnet.rippletest.net:51233')
|
||||
await client.connect()
|
||||
|
||||
// This step checks for the necessary setup data to run the lending protocol tutorials.
|
||||
// If missing, lendingSetup.js will generate the data.
|
||||
if (!fs.existsSync('lendingSetup.json')) {
|
||||
console.log(`\n=== Lending tutorial data doesn't exist. Running setup script... ===\n`)
|
||||
execSync('node lendingSetup.js', { stdio: 'inherit' })
|
||||
}
|
||||
|
||||
// Load preconfigured accounts and LoanID.
|
||||
const setupData = JSON.parse(fs.readFileSync('lendingSetup.json', 'utf8'))
|
||||
|
||||
// You can replace these values with your own
|
||||
const loanBroker = xrpl.Wallet.fromSeed(setupData.loanBroker.seed)
|
||||
const loanID = setupData.loanID1
|
||||
|
||||
console.log(`\nLoan broker address: ${loanBroker.address}`)
|
||||
console.log(`LoanID: ${loanID}`)
|
||||
|
||||
// Check loan status before impairment ----------------------
|
||||
console.log(`\n=== Loan Status ===\n`)
|
||||
const loanStatus = await client.request({
|
||||
command: 'ledger_entry',
|
||||
index: loanID,
|
||||
ledger_index: 'validated'
|
||||
})
|
||||
|
||||
console.log(`Total Amount Owed: ${loanStatus.result.node.TotalValueOutstanding} TSTUSD.`)
|
||||
// Convert Ripple Epoch timestamp to local date and time
|
||||
let nextPaymentDueDate = loanStatus.result.node.NextPaymentDueDate
|
||||
let paymentDue = new Date((nextPaymentDueDate + 946684800) * 1000)
|
||||
console.log(`Payment Due Date: ${paymentDue.toLocaleString()}`)
|
||||
|
||||
// Prepare LoanManage transaction to impair the loan ----------------------
|
||||
console.log(`\n=== Preparing LoanManage transaction to impair loan ===\n`)
|
||||
const loanManageImpair = {
|
||||
TransactionType: 'LoanManage',
|
||||
Account: loanBroker.address,
|
||||
LoanID: loanID,
|
||||
Flags: xrpl.LoanManageFlags.tfLoanImpair
|
||||
}
|
||||
|
||||
// Validate the impairment transaction before submitting
|
||||
xrpl.validate(loanManageImpair)
|
||||
console.log(JSON.stringify(loanManageImpair, null, 2))
|
||||
|
||||
// Sign, submit, and wait for impairment validation ----------------------
|
||||
console.log(`\n=== Submitting LoanManage impairment transaction ===\n`)
|
||||
const impairResponse = await client.submitAndWait(loanManageImpair, {
|
||||
wallet: loanBroker,
|
||||
autofill: true
|
||||
})
|
||||
|
||||
if (impairResponse.result.meta.TransactionResult !== 'tesSUCCESS') {
|
||||
const resultCode = impairResponse.result.meta.TransactionResult
|
||||
console.error('Error: Unable to impair loan:', resultCode)
|
||||
await client.disconnect()
|
||||
process.exit(1)
|
||||
}
|
||||
console.log('Loan impaired successfully!')
|
||||
|
||||
// Extract loan impairment info from transaction results ----------------------
|
||||
let loanNode = impairResponse.result.meta.AffectedNodes.find(node =>
|
||||
node.ModifiedNode?.LedgerEntryType === 'Loan'
|
||||
)
|
||||
|
||||
// Check grace period and next payment due date
|
||||
const gracePeriod = loanNode.ModifiedNode.FinalFields.GracePeriod
|
||||
nextPaymentDueDate = loanNode.ModifiedNode.FinalFields.NextPaymentDueDate
|
||||
const defaultTime = nextPaymentDueDate + gracePeriod
|
||||
paymentDue = new Date((nextPaymentDueDate + 946684800) * 1000)
|
||||
|
||||
console.log(`New Payment Due Date: ${paymentDue.toLocaleString()}`)
|
||||
console.log(`Grace Period: ${gracePeriod} seconds`)
|
||||
|
||||
// Convert current time to Ripple Epoch timestamp
|
||||
const currentTime = Math.floor(Date.now() / 1000) - 946684800
|
||||
let secondsUntilDefault = defaultTime - currentTime
|
||||
|
||||
// Countdown until loan can be defaulted ----------------------
|
||||
console.log(`\n=== Countdown until loan can be defaulted ===\n`)
|
||||
|
||||
await new Promise((resolve) => {
|
||||
const countdown = setInterval(() => {
|
||||
if (secondsUntilDefault <= 0) {
|
||||
clearInterval(countdown)
|
||||
process.stdout.write('\rGrace period expired. Loan can now be defaulted.\n')
|
||||
resolve()
|
||||
} else {
|
||||
process.stdout.write(`\r${secondsUntilDefault} seconds...`)
|
||||
secondsUntilDefault--
|
||||
}
|
||||
}, 1000)
|
||||
})
|
||||
|
||||
// Prepare LoanManage transaction to default the loan ----------------------
|
||||
console.log(`\n=== Preparing LoanManage transaction to default loan ===\n`)
|
||||
const loanManageDefault = {
|
||||
TransactionType: 'LoanManage',
|
||||
Account: loanBroker.address,
|
||||
LoanID: loanID,
|
||||
Flags: xrpl.LoanManageFlags.tfLoanDefault
|
||||
}
|
||||
|
||||
// Validate the default transaction before submitting
|
||||
xrpl.validate(loanManageDefault)
|
||||
console.log(JSON.stringify(loanManageDefault, null, 2))
|
||||
|
||||
// Sign, submit, and wait for default validation ----------------------
|
||||
console.log(`\n=== Submitting LoanManage default transaction ===\n`)
|
||||
const defaultResponse = await client.submitAndWait(loanManageDefault, {
|
||||
wallet: loanBroker,
|
||||
autofill: true
|
||||
})
|
||||
|
||||
if (defaultResponse.result.meta.TransactionResult !== 'tesSUCCESS') {
|
||||
const resultCode = defaultResponse.result.meta.TransactionResult
|
||||
console.error('Error: Unable to default loan:', resultCode)
|
||||
await client.disconnect()
|
||||
process.exit(1)
|
||||
}
|
||||
console.log('Loan defaulted successfully!')
|
||||
|
||||
// Verify loan default status from transaction results ----------------------
|
||||
console.log(`\n=== Checking final loan status ===\n`)
|
||||
loanNode = defaultResponse.result.meta.AffectedNodes.find(node =>
|
||||
node.ModifiedNode?.LedgerEntryType === 'Loan'
|
||||
)
|
||||
const loanFlags = loanNode.ModifiedNode.FinalFields.Flags
|
||||
console.log(`Final loan flags (parsed): ${JSON.stringify(xrpl.parseTransactionFlags({
|
||||
TransactionType: 'LoanManage',
|
||||
Flags: loanFlags
|
||||
}))}`)
|
||||
|
||||
await client.disconnect()
|
||||
134
_code-samples/lending-protocol/js/loanPay.js
Normal file
134
_code-samples/lending-protocol/js/loanPay.js
Normal file
@@ -0,0 +1,134 @@
|
||||
// IMPORTANT: This example pays off an existing loan and then deletes it.
|
||||
|
||||
import fs from 'fs'
|
||||
import { execSync } from 'child_process'
|
||||
import xrpl from 'xrpl'
|
||||
|
||||
// Connect to the network ----------------------
|
||||
const client = new xrpl.Client('wss://s.devnet.rippletest.net:51233')
|
||||
await client.connect()
|
||||
|
||||
// This step checks for the necessary setup data to run the lending protocol tutorials.
|
||||
// If missing, lendingSetup.js will generate the data.
|
||||
if (!fs.existsSync('lendingSetup.json')) {
|
||||
console.log(`\n=== Lending tutorial data doesn't exist. Running setup script... ===\n`)
|
||||
execSync('node lendingSetup.js', { stdio: 'inherit' })
|
||||
}
|
||||
|
||||
// Load preconfigured accounts and LoanID.
|
||||
const setupData = JSON.parse(fs.readFileSync('lendingSetup.json', 'utf8'))
|
||||
|
||||
// You can replace these values with your own
|
||||
const borrower = xrpl.Wallet.fromSeed(setupData.borrower.seed)
|
||||
const loanID = setupData.loanID2
|
||||
const mptID = setupData.mptID
|
||||
|
||||
console.log(`\nBorrower address: ${borrower.address}`)
|
||||
console.log(`LoanID: ${loanID}`)
|
||||
console.log(`MPT ID: ${mptID}`)
|
||||
|
||||
// Check initial loan status ----------------------
|
||||
console.log(`\n=== Loan Status ===\n`)
|
||||
const loanStatus = await client.request({
|
||||
command: 'ledger_entry',
|
||||
index: loanID,
|
||||
ledger_index: 'validated'
|
||||
})
|
||||
|
||||
const totalValueOutstanding = loanStatus.result.node.TotalValueOutstanding
|
||||
const loanServiceFee = loanStatus.result.node.LoanServiceFee
|
||||
const totalPayment = (BigInt(totalValueOutstanding) + BigInt(loanServiceFee)).toString()
|
||||
|
||||
console.log(`Amount Owed: ${totalValueOutstanding} TSTUSD`)
|
||||
console.log(`Loan Service Fee: ${loanServiceFee} TSTUSD`)
|
||||
console.log(`Total Payment Due (including fees): ${totalPayment} TSTUSD`)
|
||||
|
||||
// Prepare LoanPay transaction ----------------------
|
||||
console.log(`\n=== Preparing LoanPay transaction ===\n`)
|
||||
|
||||
const loanPayTx = {
|
||||
TransactionType: 'LoanPay',
|
||||
Account: borrower.address,
|
||||
LoanID: loanID,
|
||||
Amount: {
|
||||
mpt_issuance_id: mptID,
|
||||
value: totalPayment
|
||||
}
|
||||
}
|
||||
|
||||
// Validate the transaction structure before submitting
|
||||
xrpl.validate(loanPayTx)
|
||||
console.log(JSON.stringify(loanPayTx, null, 2))
|
||||
|
||||
// Sign, submit, and wait for payment validation ----------------------
|
||||
console.log(`\n=== Submitting LoanPay transaction ===\n`)
|
||||
const payResponse = await client.submitAndWait(loanPayTx, {
|
||||
wallet: borrower,
|
||||
autofill: true
|
||||
})
|
||||
|
||||
if (payResponse.result.meta.TransactionResult !== 'tesSUCCESS') {
|
||||
const resultCode = payResponse.result.meta.TransactionResult
|
||||
console.error('Error: Unable to pay loan:', resultCode)
|
||||
await client.disconnect()
|
||||
process.exit(1)
|
||||
}
|
||||
console.log('Loan paid successfully!')
|
||||
|
||||
// Extract updated loan info from transaction results ----------------------
|
||||
console.log(`\n=== Loan Status After Payment ===\n`)
|
||||
const loanNode = payResponse.result.meta.AffectedNodes.find(node =>
|
||||
node.ModifiedNode?.LedgerEntryType === 'Loan'
|
||||
)
|
||||
|
||||
const finalBalance = loanNode.ModifiedNode.FinalFields.TotalValueOutstanding
|
||||
? `${loanNode.ModifiedNode.FinalFields.TotalValueOutstanding} TSTUSD`
|
||||
: 'Loan fully paid off!'
|
||||
console.log(`Outstanding Loan Balance: ${finalBalance}`)
|
||||
|
||||
// Prepare LoanDelete transaction ----------------------
|
||||
// Either the loan broker or borrower can submit this transaction.
|
||||
console.log(`\n=== Preparing LoanDelete transaction ===\n`)
|
||||
const loanDeleteTx = {
|
||||
TransactionType: 'LoanDelete',
|
||||
Account: borrower.address,
|
||||
LoanID: loanID
|
||||
}
|
||||
|
||||
// Validate the transaction structure before submitting
|
||||
xrpl.validate(loanDeleteTx)
|
||||
console.log(JSON.stringify(loanDeleteTx, null, 2))
|
||||
|
||||
// Sign, submit, and wait for deletion validation ----------------------
|
||||
console.log(`\n=== Submitting LoanDelete transaction ===\n`)
|
||||
const deleteResponse = await client.submitAndWait(loanDeleteTx, {
|
||||
wallet: borrower,
|
||||
autofill: true
|
||||
})
|
||||
|
||||
if (deleteResponse.result.meta.TransactionResult !== 'tesSUCCESS') {
|
||||
const resultCode = deleteResponse.result.meta.TransactionResult
|
||||
console.error('Error: Unable to delete loan:', resultCode)
|
||||
await client.disconnect()
|
||||
process.exit(1)
|
||||
}
|
||||
console.log('Loan deleted successfully!')
|
||||
|
||||
// Verify loan deletion ----------------------
|
||||
console.log(`\n=== Verifying Loan Deletion ===\n`)
|
||||
try {
|
||||
await client.request({
|
||||
command: 'ledger_entry',
|
||||
index: loanID,
|
||||
ledger_index: 'validated'
|
||||
})
|
||||
console.log('Warning: Loan still exists in the ledger.')
|
||||
} catch (error) {
|
||||
if (error.data.error === 'entryNotFound') {
|
||||
console.log('Loan has been successfully removed from the XRP Ledger!')
|
||||
} else {
|
||||
console.error('Error checking loan status:', error)
|
||||
}
|
||||
}
|
||||
|
||||
await client.disconnect()
|
||||
8
_code-samples/lending-protocol/js/package.json
Normal file
8
_code-samples/lending-protocol/js/package.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "lending-protocol-examples",
|
||||
"description": "Example code for creating and managing loans.",
|
||||
"dependencies": {
|
||||
"xrpl": "^4.5.0"
|
||||
},
|
||||
"type": "module"
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user