Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: add xrpl.js code snippets over to xrpl-py #443

Merged
merged 16 commits into from
Oct 7, 2022
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ To see the output:
cd docs/_build/html/

# Open the index file to view it in a browser:
open _build/html/index.html
open index.html
```

## Update `definitions.json`
Expand Down
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ If you run into any bugs or other problems with the library, please report them
:maxdepth: 1
:caption: Table of Contents

source/snippets
source/xrpl.account
source/xrpl.ledger
source/xrpl.transaction
Expand Down
5 changes: 5 additions & 0 deletions docs/source/get_transaction.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Get Transaction
==========================

.. autofunction:: snippets.get_transaction.get_transaction
.. literalinclude:: ../../snippets/get_transaction.py
5 changes: 5 additions & 0 deletions docs/source/partial_payment.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Partial Payment
==========================

.. autofunction:: snippets.partial_payment.partial_payment
.. literalinclude:: ../../snippets/partial_payment.py
5 changes: 5 additions & 0 deletions docs/source/paths.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Partial Payment
==========================

.. autofunction:: snippets.paths.create_tx_with_paths
.. literalinclude:: ../../snippets/paths.py
5 changes: 5 additions & 0 deletions docs/source/reliable_transaction_submission.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Reliable Transaction Submission
================================

.. autofunction:: snippets.reliable_transaction_submission.send_reliable_tx
.. literalinclude:: ../../snippets/reliable_transaction_submission.py
5 changes: 5 additions & 0 deletions docs/source/send_escrow.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Send Escrow
==========================

.. autofunction:: snippets.send_escrow.send_escrow
.. literalinclude:: ../../snippets/send_escrow.py
5 changes: 5 additions & 0 deletions docs/source/set_regular_key.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Set Regular Key
==========================

.. autofunction:: snippets.set_regular_key.set_regular_key
.. literalinclude:: ../../snippets/set_regular_key.py
14 changes: 14 additions & 0 deletions docs/source/snippets.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
XRPL Code Snippets
===================

Code snippets to demonstrate basic usage of the xrpl-py library.

.. toctree::
:maxdepth: 1

get_transaction
connorjchen marked this conversation as resolved.
Show resolved Hide resolved
partial_payment
paths
reliable_transaction_submission
send_escrow
set_regular_key
connorjchen marked this conversation as resolved.
Show resolved Hide resolved
connorjchen marked this conversation as resolved.
Show resolved Hide resolved
47 changes: 47 additions & 0 deletions snippets/get_transaction.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""A snippet that walks us through getting a transaction."""
connorjchen marked this conversation as resolved.
Show resolved Hide resolved
from xrpl.clients import JsonRpcClient
from xrpl.models.requests import Ledger, Tx


def get_transaction(client: JsonRpcClient) -> None:
connorjchen marked this conversation as resolved.
Show resolved Hide resolved
"""
Sync snippet that walks us through getting a transaction.

Args:
client: The network client to use to send the request.

Raises:
Exception: if meta not included in the transaction response.
"""
ledger_request = Ledger(transactions=True, ledger_index="validated")
ledger_response = client.request(ledger_request)
print(ledger_response)

transactions = ledger_response.result["ledger"]["transactions"]

if transactions:
tx_request = Tx(transaction=transactions[0])
tx_response = client.request(tx_request)
print(tx_response)

# the meta field would be a string(hex)
# when the `binary` parameter is `true` for the `tx` request.
if tx_response.result["meta"] is None:
raise Exception("meta not included in the response")

# delivered_amount is the amount actually received by the destination account.
# Use this field to determine how much was delivered,
# regardless of whether the transaction is a partial payment.
# https://xrpl.org/transaction-metadata.html#delivered_amount
if type(tx_response.result["meta"] != "string"):
if "delivered_amount" in tx_response.result["meta"]:
print(
"delivered_amount:", tx_response.result["meta"]["delivered_amount"]
)
else:
print("delivered_amount: undefined")


# uncomment the lines below to run the snippet
# client = JsonRpcClient("https://s.altnet.rippletest.net:51234/")
# get_transaction(client)
116 changes: 116 additions & 0 deletions snippets/partial_payment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
"""A snippet that walks us through using a partial payment."""
from xrpl.clients import JsonRpcClient
from xrpl.models.amounts import IssuedCurrencyAmount
from xrpl.models.requests import AccountLines
from xrpl.models.transactions import Payment, PaymentFlag, TrustSet
from xrpl.transaction import (
safe_sign_and_autofill_transaction,
send_reliable_submission,
)
from xrpl.wallet import generate_faucet_wallet


def partial_payment(client: JsonRpcClient) -> None:
"""
Sync snippet that walks us through using a partial payment.

Args:
client: The network client to use to send the request.
"""

# creating wallets as prerequisite
wallet1 = generate_faucet_wallet(client, debug=True)
wallet2 = generate_faucet_wallet(client, debug=True)

# create a trustline to issue an IOU `FOO` and set limit on it
trust_set_tx = TrustSet(
account=wallet2.classic_address,
limit_amount=IssuedCurrencyAmount(
currency="FOO",
value="10000000000",
issuer=wallet1.classic_address,
),
)

signed_trust_set_tx = safe_sign_and_autofill_transaction(
trust_set_tx, wallet2, client
)
send_reliable_submission(signed_trust_set_tx, client)

print("Balances after trustline is claimed:")
print(
(client.request(AccountLines(account=wallet1.classic_address))).result["lines"]
)
print(
(client.request(AccountLines(account=wallet2.classic_address))).result["lines"]
)

# initially, the issuer(wallet1) sends an amount to the other account(wallet2)
issue_quantity = "3840"
payment_tx = Payment(
account=wallet1.classic_address,
amount=IssuedCurrencyAmount(
currency="FOO",
value=issue_quantity,
issuer=wallet1.classic_address,
),
destination=wallet2.classic_address,
)

# submit payment
signed_payment_tx = safe_sign_and_autofill_transaction(payment_tx, wallet1, client)
payment_response = send_reliable_submission(signed_payment_tx, client)
print(payment_response)

print("Balances after wallet1 sends 3840 FOO to wallet2:")
print(
(client.request(AccountLines(account=wallet1.classic_address))).result["lines"]
)
print(
(client.request(AccountLines(account=wallet2.classic_address))).result["lines"]
)

# Send money less than the amount specified on 2 conditions:
# 1. Sender has less money than the aamount specified in the payment Tx.
# 2. Sender has the tfPartialPayment flag activated.

# Other ways to specify flags are by using Hex code and decimal code.
# eg. For partial payment(tfPartialPayment)
# decimal ->131072, hex -> 0x00020000
partial_payment_tx = Payment(
account=wallet2.classic_address,
amount=IssuedCurrencyAmount(
currency="FOO",
value="4000",
issuer=wallet1.classic_address,
),
destination=wallet1.classic_address,
flags=[PaymentFlag.TF_PARTIAL_PAYMENT],
send_max=IssuedCurrencyAmount(
currency="FOO",
value="1000000",
issuer=wallet1.classic_address,
),
)

# submit payment
signed_partial_payment_tx = safe_sign_and_autofill_transaction(
partial_payment_tx, wallet2, client
)
partial_payment_response = send_reliable_submission(
signed_partial_payment_tx, client
)
print(partial_payment_response)

print("Balances after Partial Payment, when wallet2 tried to send 4000 FOOs")
print(
(client.request(AccountLines(account=wallet1.classic_address))).result["lines"]
)
print(
(client.request(AccountLines(account=wallet2.classic_address))).result["lines"]
)


# uncomment the lines below to run the snippet
# client = JsonRpcClient("https://s.altnet.rippletest.net:51234/")
# partial_payment(client)
51 changes: 51 additions & 0 deletions snippets/paths.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"""A snippet that walks us through creating a transaction with a path."""
from xrpl.clients import JsonRpcClient
from xrpl.models.amounts import IssuedCurrencyAmount
from xrpl.models.currencies.xrp import XRP
from xrpl.models.requests import RipplePathFind
from xrpl.models.transactions import Payment
from xrpl.transaction import safe_sign_and_autofill_transaction
from xrpl.wallet import generate_faucet_wallet


def create_tx_with_paths(client: JsonRpcClient) -> None:
"""
Sync snippet that walks us through creating a transaction with a path.

Args:
client: The network client to use to send the request.
"""
wallet = generate_faucet_wallet(client, debug=True)
destination_account = "rKT4JX4cCof6LcDYRz8o3rGRu7qxzZ2Zwj"
destination_amount = IssuedCurrencyAmount(
value="0.001",
currency="USD",
issuer="rVnYNK9yuxBz4uP8zC8LEFokM2nqH3poc",
)

path_request = RipplePathFind(
source_account=wallet.classic_address,
source_currencies=[XRP()],
destination_account=destination_account,
destination_amount=destination_amount,
)

path_response = client.request(path_request)
print(path_response)

paths = path_response.result["alternatives"][0]["paths_computed"]
print(paths)

payment_tx = Payment(
account=wallet.classic_address,
amount=destination_amount,
destination=destination_account,
paths=paths,
)

print("signed: ", safe_sign_and_autofill_transaction(payment_tx, wallet, client))


# uncomment the lines below to run the snippet
# client = JsonRpcClient("https://s.altnet.rippletest.net:51234/")
# create_tx_with_paths(client)
93 changes: 93 additions & 0 deletions snippets/reliable_transaction_submission.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
"""A snippet that walks us through sending a transaction reliably."""
from xrpl.account import get_balance
from xrpl.clients import JsonRpcClient
from xrpl.models.requests import Tx
from xrpl.models.transactions import Payment
from xrpl.transaction import (
safe_sign_and_autofill_transaction,
send_reliable_submission,
)
from xrpl.wallet import generate_faucet_wallet

# When implementing Reliable Transaction Submission, there are many potential
# solutions, each with different trade-offs.
# The main decision points are:
# 1) Transaction preparation:
# - The autofill function as a part of the submitAndWait should be able to
# correctly populate values for the fields Sequence, LastLedgerSequence and Fee.
# 2) Transaction status retrieval. Options include:
# - Poll for transaction status:
# - On a regular interval (e.g. Every 3-5 seconds), or
# - When a new validated ledger is detected
# + (To accommodate an edge case in transaction retrieval,
# check the sending account's Sequence number to confirm that it has the
# expected value; alternatively, wait until a few additional ledgers have
# been validated before deciding that atransaction has definitively not
# been included in a validated ledger)
# - Listen for transaction status: scan all validated transactions to see if our
# transactions are among them
# 3) What do we do when a transaction fails? It is possible to implement retry logic,
# but caution is advised.
# Note that there are a few ways for a transaction to fail:
# A) `tec`: The transaction was included in a ledger but only claimed the
# transaction fee
# B) `tesSUCCESS` but unexpected result: The transaction was successful but did not
# have the expected result. This generally
# does not occur for XRP-to-XRP payments
# C) The transaction was not, and never will be, included in a validated
# ledger [3C].

# References:
# - https://xrpl.org/reliable-transaction-submission.html
# - https://xrpl.org/send-xrp.html
# - https://xrpl.org/look-up-transaction-results.html
# - https://xrpl.org/monitor-incoming-payments-with-websocket.html.

# For the implementation in this example, we have made the following decisions:
# 1) We allow the autofill function as a part of submitAndWait to fill up the account
# sequence, LastLedgerSequence and Fee. Payments are defined upfront, and
# idempotency is not needed. If the script is run a second time, duplicate
# payments will result.
# 2) We will rely on the xrpl.js submitAndWait function to get us the transaction
# submission result after the wait time.
# 3) Transactions will not be automatically retried. Transactions are limited to
# XRP-to-XRP payments and cannot "succeed" in an unexpected way.


def send_reliable_tx(client: JsonRpcClient) -> None:
"""
Sync snippet that walks us through sending a transaction reliably.

Args:
client: The network client to use to send the request.
"""
# creating wallets as prerequisite
wallet1 = generate_faucet_wallet(client, debug=True)
wallet2 = generate_faucet_wallet(client, debug=True)

print("Balances of wallets before Payment tx")
print(get_balance(wallet1.classic_address, client))
print(get_balance(wallet2.classic_address, client))

# create a Payment tx and submit and wait for tx to be validated
payment_tx = Payment(
account=wallet1.classic_address,
amount="1000",
destination=wallet2.classic_address,
)

signed_payment_tx = safe_sign_and_autofill_transaction(payment_tx, wallet1, client)
payment_response = send_reliable_submission(signed_payment_tx, client)
print("\nTransaction was submitted.\n")
tx_response = client.request(Tx(transaction=payment_response.result["hash"]))
# with the following reponse we are able to see that the tx was indeed validated
print("Validated:", tx_response.result["validated"])

print("Balances of wallets after Payment tx:")
print(get_balance(wallet1.classic_address, client))
print(get_balance(wallet2.classic_address, client))


# uncomment the lines below to run the snippet
# client = JsonRpcClient("https://s.altnet.rippletest.net:51234/")
# send_reliable_tx(client)