diff --git a/_code-samples/claim-payment-channel/js/claimPayChannel.ts b/_code-samples/claim-payment-channel/js/claimPayChannel.ts index 097a8fcf22..364adc6f3d 100644 --- a/_code-samples/claim-payment-channel/js/claimPayChannel.ts +++ b/_code-samples/claim-payment-channel/js/claimPayChannel.ts @@ -12,13 +12,11 @@ import { const client = new Client('wss://s.altnet.rippletest.net:51233') -void claimPayChannel() - // The snippet walks us through creating and claiming a Payment Channel. async function claimPayChannel(): Promise { await client.connect() - // creating wallets as prerequisite + // Creating wallets as prerequisite const { wallet: wallet1 } = await client.fundWallet() const { wallet: wallet2 } = await client.fundWallet() @@ -26,16 +24,17 @@ async function claimPayChannel(): Promise { console.log(`Balance of ${wallet1.address} is ${await client.getXrpBalance(wallet1.address)} XRP`) console.log(`Balance of ${wallet2.address} is ${await client.getXrpBalance(wallet2.address)} XRP`) - // create a Payment Channel and submit and wait for tx to be validated + // Create a Payment Channel transaction const paymentChannelCreate: PaymentChannelCreate = { TransactionType: 'PaymentChannelCreate', Account: wallet1.classicAddress, - Amount: '100', + Amount: '3000000', // 3 XRP in drops Destination: wallet2.classicAddress, - SettleDelay: 86400, + SettleDelay: 86400, // 1 day in seconds PublicKey: wallet1.publicKey, } - + + // Submit and wait for the transaction to be validated console.log("Submitting a PaymentChannelCreate transaction...") const paymentChannelResponse = await client.submitAndWait( paymentChannelCreate, @@ -44,7 +43,7 @@ async function claimPayChannel(): Promise { console.log("PaymentChannelCreate transaction response:") console.log(paymentChannelResponse) - // check that the object was actually created + // Check that the object was actually created const accountObjectsRequest: AccountObjectsRequest = { command: 'account_objects', account: wallet1.classicAddress, @@ -55,14 +54,14 @@ async function claimPayChannel(): Promise { console.log("Account Objects:", accountObjects) - // destination claims the Payment Channel and we see the balances to verify. + // Destination claims the Payment Channel and we see the balances to verify. const paymentChannelClaim: PaymentChannelClaim = { Account: wallet2.classicAddress, TransactionType: 'PaymentChannelClaim', Channel: hashes.hashPaymentChannel( wallet1.classicAddress, wallet2.classicAddress, - paymentChannelResponse.result.Sequence ?? 0, + paymentChannelResponse.result.tx_json.Sequence ?? 0, ), Amount: '100', } @@ -70,7 +69,7 @@ async function claimPayChannel(): Promise { console.log("Submitting a PaymentChannelClaim transaction...") const channelClaimResponse = await client.submit(paymentChannelClaim, { - wallet: wallet1, + wallet: wallet2, }) console.log("PaymentChannelClaim transaction response:") console.log(channelClaimResponse) @@ -81,3 +80,5 @@ async function claimPayChannel(): Promise { await client.disconnect() } + +void claimPayChannel() diff --git a/_code-samples/claim-payment-channel/py/claim_pay_channel.py b/_code-samples/claim-payment-channel/py/claim_pay_channel.py new file mode 100644 index 0000000000..79a9a05d33 --- /dev/null +++ b/_code-samples/claim-payment-channel/py/claim_pay_channel.py @@ -0,0 +1,97 @@ +""" +Create, claim and verify a Payment Channel. +Reference: https://xrpl.org/paychannel.html +""" +from xrpl.clients import JsonRpcClient +from xrpl.models import ( + AccountObjects, + PaymentChannelCreate, + PaymentChannelClaim, +) +from xrpl.wallet import generate_faucet_wallet +from xrpl.transaction import submit_and_wait, submit +from xrpl.account import get_balance + + +def claim_pay_channel(): + """The snippet walks us through creating and claiming a Payment Channel.""" + + client = JsonRpcClient("https://s.altnet.rippletest.net:51234") + + try: + # Creating wallets as prerequisite + print("Creating and funding wallets...") + wallet1 = generate_faucet_wallet(client, debug=True) + wallet2 = generate_faucet_wallet(client, debug=True) + + print("Balances of wallets before Payment Channel is claimed:") + balance1 = get_balance(wallet1.address, client) + balance2 = get_balance(wallet2.address, client) + print(f"Balance of {wallet1.address} is {balance1} XRP") + print(f"Balance of {wallet2.address} is {balance2} XRP") + + # Create a Payment Channel transaction + payment_channel_create = PaymentChannelCreate( + account=wallet1.address, + amount="3000000", # 3 XRP in drops + destination=wallet2.address, + settle_delay=86400, + public_key=wallet1.public_key, + ) + + # Submit and wait for the transaction to be validated + print("Submitting a PaymentChannelCreate transaction...") + payment_channel_response = submit_and_wait( + payment_channel_create, + client, + wallet1 + ) + print("PaymentChannelCreate transaction response:") + print(payment_channel_response) + + # Check that the object was actually created and get the channel ID + account_objects_request = AccountObjects( + account=wallet1.address, + ) + account_objects_response = client.request(account_objects_request) + account_objects = account_objects_response.result["account_objects"] + + # Find the payment channel from account objects and get its ID + channel_id = None + for obj in account_objects: + if obj.get("LedgerEntryType") == "PayChannel": + channel_id = obj["index"] + break + + if not channel_id: + raise Exception("Could not find PayChannel in account objects") + + print(f"Payment Channel ID: {channel_id}") + + # Destination claims the Payment Channel + payment_channel_claim = PaymentChannelClaim( + account=wallet2.address, + channel=channel_id, + amount="100", + sequence=payment_channel_response.result["tx_json"]["Sequence"], + fee="12", # Fee in drops (0.000012 XRP) + ) + + print("Submitting a PaymentChannelClaim transaction...") + channel_claim_response = submit( + payment_channel_claim, + wallet2, + ) + print("PaymentChannelClaim transaction response:") + print(channel_claim_response) + + print("Balances of wallets after Payment Channel is claimed:") + print(f"Balance of {wallet1.address} is {get_balance(wallet1.address, client)} XRP") + print(f"Balance of {wallet2.address} is {get_balance(wallet2.address, client)} XRP") + + except Exception as e: + print(f"An error occurred: {e}") + + +if __name__ == "__main__": + claim_pay_channel() diff --git a/_code-samples/claim-payment-channel/py/requirements.txt b/_code-samples/claim-payment-channel/py/requirements.txt new file mode 100644 index 0000000000..71865ab3a4 --- /dev/null +++ b/_code-samples/claim-payment-channel/py/requirements.txt @@ -0,0 +1 @@ +xrpl-py>=2.0.0 diff --git a/docs/tutorials/how-tos/use-specialized-payment-types/use-payment-channels/create-and-claim-payment-channel.md b/docs/tutorials/how-tos/use-specialized-payment-types/use-payment-channels/create-and-claim-payment-channel.md new file mode 100644 index 0000000000..c7f0bf53c7 --- /dev/null +++ b/docs/tutorials/how-tos/use-specialized-payment-types/use-payment-channels/create-and-claim-payment-channel.md @@ -0,0 +1,136 @@ +--- +seo: + description: Learn how to create and claim a payment channel using the XRP Ledger SDKs. +cta_text: Create and Claim a Payment Channel with the XRPL SDKs +labels: + - Payment Channels +--- +# Create and Claim a Payment Channel with the SDK Libraries + +This tutorial explains how to create, verify, and claim a payment channel using `xrpl.js` for JavaScript, and `xrpl-py` for Python. + +{% admonition type="success" name="Tip" %}Check out the [Code Samples](https://github.com/XRPLF/xrpl-dev-portal/tree/master/_code-samples/claim-payment-channel) for a complete version of the code used in this tutorial.{% /admonition %} + +## Prerequisites + + + + + +To interact with the XRP Ledger, you need to set up a dev environment with the necessary tools. This tutorial provides examples using the following options: + +- **JavaScript** with the [`xrpl.js` library](https://github.com/XRPLF/xrpl.js/). See [Get Started Using JavaScript](../../../javascript/build-apps/get-started.md) for setup steps. +- **Python** with the [`xrpl-py` library](https://xrpl-py.readthedocs.io/). See [Get Started using Python](../../../python/build-apps/get-started.md) for setup steps. + +## 1. Connect to a Testnet Server + +First, you must connect to an XRP Ledger server. The following code initializes the XRP Ledger client and connects to a public Testnet server: + +{% tabs %} + +{% tab label="JavaScript" %} +{% code-snippet file="/_code-samples/claim-payment-channel/js/claimPayChannel.ts" from="import" before="// Creating wallets" language="js" /%} +{% /tab %} + +{% tab label="Python" %} +{% code-snippet file="/_code-samples/claim-payment-channel/py/claim_pay_channel.py" from="xrpl.clients" before="try:" language="py" /%} +{% /tab %} + +{% /tabs %} + + + +## 2. Create Testnet Wallets + +Create two Testnet wallets and log their initial XRP balances: + +{% tabs %} + +{% tab label="JavaScript" %} +{% code-snippet file="/_code-samples/claim-payment-channel/js/claimPayChannel.ts" from="// Creating wallets" before="// Create a Payment Channel" language="js" /%} +{% /tab %} + +{% /tabs %} + +For this example, `wallet1` represents the _payer_, and `wallet2` is the _payee_. + +The payer can be an individual person or institution using the XRP Ledger who is a customer of the payee. The payee is a person or business who receives XRP or fungible tokens as payment for goods or services. + +## 3. Create and Submit the Payment Channel Transaction + +Next, prepare the [`PaymentChannelCreate`](../../../../references/protocol/transactions/types/paymentchannelcreate) transaction. + +{% tabs %} + +{% tab label="JavaScript" %} +{% code-snippet file="/_code-samples/claim-payment-channel/js/claimPayChannel.ts" from="// Create a Payment Channel" before="// Submit and wait for the transaction" language="js" /%} +{% /tab %} + +{% /tabs %} + +The key fields in this transaction are: + +| Field | Description | +| :---------------------- | :---------- | +| `TransactionType` | The type of transaction to be submitted (i.e., `PaymentChannelCreate`). | +| `Account` | The _payer_ (source) address of the transaction, which in this example is `wallet1`. | +| `Amount` | The amount of XRP, in drops, to deduct from the sender's balance and set aside in the payment channel. For this example, we are setting this to 3 XRP. | +| `SettleDelay` | The amount of time the source address must wait before closing the channel if it has unclaimed XRP. This is set to 1 day (in seconds). | +| `PublicKey` | The public key of the key pair used to sign claims against the payment channel. | +| `Destination` | The _payee_ (destination) address to receive claims against this channel, which in this example is `wallet2`. | + +Submit and wait for the transaction to be validated on the ledger: + +{% tabs %} + +{% tab label="JavaScript" %} +{% code-snippet file="/_code-samples/claim-payment-channel/js/claimPayChannel.ts" from="// Submit and wait for the transaction" before="// Check that the object " language="js" /%} +{% /tab %} + +{% /tabs %} + +## 4. Verify the Payment Channel is Created + +{% tabs %} + +{% tab label="JavaScript" %} +{% code-snippet file="/_code-samples/claim-payment-channel/js/claimPayChannel.ts" from="// Check that the object" before="// Destination claims" language="js" /%} +{% /tab %} + +{% /tabs %} + +## 5. Claim the Payment Channel + +Create a `PaymentChannelClaim` transaction: + +{% tabs %} + +{% tab label="JavaScript" %} +{% code-snippet file="/_code-samples/claim-payment-channel/js/claimPayChannel.ts" from="// Destination claims" before="" language="js" /%} +{% /tab %} + +{% /tabs %} + +Submit and wait for the transaction to be validated: + +{% tabs %} + +{% tab label="JavaScript" %} +{% code-snippet file="/_code-samples/claim-payment-channel/js/claimPayChannel.ts" from="console.log(\"Submitting" before="console.log('Balances" language="js" /%} +{% /tab %} + +{% /tabs %} + +## 6. Check Balances after Payment Channel is Claimed + +Finally, we check the balance of both `wallet1` and `wallet2`, after the claiming the payment channel. Then, we close the client connection. + +{% tabs %} + +{% tab label="JavaScript" %} +{% code-snippet file="/_code-samples/claim-payment-channel/js/claimPayChannel.ts" from="console.log('Balances" language="js" /%} +{% /tab %} + +{% /tabs %} diff --git a/docs/tutorials/how-tos/use-specialized-payment-types/use-payment-channels/index.md b/docs/tutorials/how-tos/use-specialized-payment-types/use-payment-channels/index.md index 380d35d8dc..6aed140471 100644 --- a/docs/tutorials/how-tos/use-specialized-payment-types/use-payment-channels/index.md +++ b/docs/tutorials/how-tos/use-specialized-payment-types/use-payment-channels/index.md @@ -84,7 +84,7 @@ Content-Type: application/json "fee_mult_max": 1000 }] } -```json +``` Response: diff --git a/sidebars.yaml b/sidebars.yaml index d6acf43f65..073c929462 100644 --- a/sidebars.yaml +++ b/sidebars.yaml @@ -299,6 +299,7 @@ expanded: false items: - page: docs/tutorials/how-tos/use-specialized-payment-types/use-payment-channels/open-a-payment-channel-to-enable-an-inter-exchange-network.md + - page: docs/tutorials/how-tos/use-specialized-payment-types/use-payment-channels/create-and-claim-payment-channel.md - page: docs/tutorials/how-tos/use-specialized-payment-types/use-checks/index.md expanded: false items: