mirror of
https://github.com/XRPLF/xrpl-dev-portal.git
synced 2026-04-06 11:52:29 +00:00
Compare commits
4 Commits
token-escr
...
add-calcul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b1eaf8c051 | ||
|
|
f2109aab33 | ||
|
|
41788b9323 | ||
|
|
04cfa17880 |
57
_code-samples/calculate-reserves/go/calculate_reserves.go
Normal file
57
_code-samples/calculate-reserves/go/calculate_reserves.go
Normal file
@@ -0,0 +1,57 @@
|
||||
|
||||
// Set up client ----------------------
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Peersyst/xrpl-go/xrpl/queries/account"
|
||||
"github.com/Peersyst/xrpl-go/xrpl/queries/server"
|
||||
"github.com/Peersyst/xrpl-go/xrpl/transaction/types"
|
||||
"github.com/Peersyst/xrpl-go/xrpl/websocket"
|
||||
)
|
||||
|
||||
func main() {
|
||||
client := websocket.NewClient(
|
||||
websocket.NewClientConfig().
|
||||
WithHost("wss://s.devnet.rippletest.net:51233"),
|
||||
)
|
||||
defer client.Disconnect()
|
||||
|
||||
if err := client.Connect(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Look up reserve values ----------------------
|
||||
|
||||
res, err := client.Request(&server.InfoRequest{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
var serverInfo server.InfoResponse
|
||||
if err := res.GetResult(&serverInfo); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
baseReserve := serverInfo.Info.ValidatedLedger.ReserveBaseXRP
|
||||
reserveInc := serverInfo.Info.ValidatedLedger.ReserveIncXRP
|
||||
|
||||
fmt.Printf("Base reserve: %v XRP\n", baseReserve)
|
||||
fmt.Printf("Incremental reserve: %v XRP\n", reserveInc)
|
||||
|
||||
// Look up owner count ----------------------
|
||||
|
||||
address := types.Address("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh")
|
||||
accountInfo, err := client.GetAccountInfo(&account.InfoRequest{Account: address})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ownerCount := accountInfo.AccountData.OwnerCount
|
||||
|
||||
// Calculate total reserve ----------------------
|
||||
|
||||
totalReserve := float64(baseReserve) + (float64(ownerCount) * float64(reserveInc))
|
||||
|
||||
fmt.Printf("Owner count: %v\n", ownerCount)
|
||||
fmt.Printf("Total reserve: %v XRP\n", totalReserve)
|
||||
}
|
||||
16
_code-samples/calculate-reserves/go/go.mod
Normal file
16
_code-samples/calculate-reserves/go/go.mod
Normal file
@@ -0,0 +1,16 @@
|
||||
module calculate-reserves
|
||||
|
||||
go 1.26.1
|
||||
|
||||
require github.com/Peersyst/xrpl-go v0.1.17
|
||||
|
||||
require (
|
||||
github.com/bsv-blockchain/go-sdk v1.2.9 // indirect
|
||||
github.com/decred/dcrd/crypto/ripemd160 v1.0.2 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.1 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||
golang.org/x/crypto v0.44.0 // indirect
|
||||
)
|
||||
30
_code-samples/calculate-reserves/go/go.sum
Normal file
30
_code-samples/calculate-reserves/go/go.sum
Normal file
@@ -0,0 +1,30 @@
|
||||
github.com/Peersyst/xrpl-go v0.1.17 h1:jOI2es/dzzRm6/WMVCjr7H3fci47XB2kRkezfbddDB0=
|
||||
github.com/Peersyst/xrpl-go v0.1.17/go.mod h1:38j60Mr65poIHdhmjvNXnwbcUFNo8J7CBDot7ZWgrb8=
|
||||
github.com/bsv-blockchain/go-sdk v1.2.9 h1:LwFzuts+J5X7A+ECx0LNowtUgIahCkNNlXckdiEMSDk=
|
||||
github.com/bsv-blockchain/go-sdk v1.2.9/go.mod h1:KiHWa/hblo3Bzr+IsX11v0sn1E6elGbNX0VXl5mOq6E=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
|
||||
github.com/decred/dcrd/crypto/ripemd160 v1.0.2 h1:TvGTmUBHDU75OHro9ojPLK+Yv7gDl2hnUvRocRCjsys=
|
||||
github.com/decred/dcrd/crypto/ripemd160 v1.0.2/go.mod h1:uGfjDyePSpa75cSQLzNdVmWlbQMBuiJkvXw/MNKRY4M=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.1 h1:5RVFMOWjMyRy8cARdy79nAmgYw3hK/4HUq48LQ6Wwqo=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.1/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
|
||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
||||
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||
golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU=
|
||||
golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
47
_code-samples/calculate-reserves/java/CalculateReserves.java
Normal file
47
_code-samples/calculate-reserves/java/CalculateReserves.java
Normal file
@@ -0,0 +1,47 @@
|
||||
|
||||
// Set up client ----------------------
|
||||
|
||||
import okhttp3.HttpUrl;
|
||||
import org.xrpl.xrpl4j.client.JsonRpcClientErrorException;
|
||||
import org.xrpl.xrpl4j.client.XrplClient;
|
||||
import org.xrpl.xrpl4j.model.client.accounts.AccountInfoRequestParams;
|
||||
import org.xrpl.xrpl4j.model.client.common.LedgerSpecifier;
|
||||
import org.xrpl.xrpl4j.model.transactions.Address;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class CalculateReserves {
|
||||
public static void main(String[] args) throws JsonRpcClientErrorException {
|
||||
HttpUrl rippledUrl = HttpUrl.get("https://s.devnet.rippletest.net:51234/");
|
||||
XrplClient xrplClient = new XrplClient(rippledUrl);
|
||||
|
||||
// Look up reserve values ----------------------
|
||||
|
||||
var serverInfo = xrplClient.serverInformation();
|
||||
var validatedLedger = serverInfo.info().validatedLedger().get();
|
||||
|
||||
BigDecimal baseReserve = validatedLedger.reserveBaseXrp().toXrp();
|
||||
BigDecimal reserveInc = validatedLedger.reserveIncXrp().toXrp();
|
||||
|
||||
System.out.println("Base reserve: " + baseReserve + " XRP");
|
||||
System.out.println("Incremental reserve: " + reserveInc + " XRP");
|
||||
|
||||
// Look up owner count ----------------------
|
||||
|
||||
Address address = Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh");
|
||||
var accountInfo = xrplClient.accountInfo(
|
||||
AccountInfoRequestParams.builder()
|
||||
.account(address)
|
||||
.ledgerSpecifier(LedgerSpecifier.VALIDATED)
|
||||
.build()
|
||||
);
|
||||
|
||||
long ownerCount = accountInfo.accountData().ownerCount().longValue();
|
||||
|
||||
// Calculate total reserve ----------------------
|
||||
|
||||
BigDecimal totalReserve = baseReserve.add(reserveInc.multiply(BigDecimal.valueOf(ownerCount)));
|
||||
|
||||
System.out.println("Owner count: " + ownerCount);
|
||||
System.out.println("Total reserve: " + totalReserve + " XRP");
|
||||
}
|
||||
}
|
||||
23
_code-samples/calculate-reserves/java/pom.xml
Normal file
23
_code-samples/calculate-reserves/java/pom.xml
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.example</groupId>
|
||||
<artifactId>calculate-reserves</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.xrpl</groupId>
|
||||
<artifactId>xrpl4j-client</artifactId>
|
||||
<version>3.0.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,46 @@
|
||||
// Set up client ----------------------
|
||||
|
||||
import okhttp3.HttpUrl;
|
||||
import org.xrpl.xrpl4j.client.JsonRpcClientErrorException;
|
||||
import org.xrpl.xrpl4j.client.XrplClient;
|
||||
import org.xrpl.xrpl4j.model.client.accounts.AccountInfoRequestParams;
|
||||
import org.xrpl.xrpl4j.model.client.common.LedgerSpecifier;
|
||||
import org.xrpl.xrpl4j.model.transactions.Address;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class CalculateReserves {
|
||||
public static void main(String[] args) throws JsonRpcClientErrorException {
|
||||
HttpUrl rippledUrl = HttpUrl.get("https://s.devnet.rippletest.net:51234/");
|
||||
XrplClient xrplClient = new XrplClient(rippledUrl);
|
||||
|
||||
// Look up reserve values ----------------------
|
||||
|
||||
var serverInfo = xrplClient.serverInformation();
|
||||
var validatedLedger = serverInfo.info().validatedLedger().get();
|
||||
|
||||
BigDecimal baseReserve = validatedLedger.reserveBaseXrp().toXrp();
|
||||
BigDecimal reserveInc = validatedLedger.reserveIncXrp().toXrp();
|
||||
|
||||
System.out.println("Base reserve: " + baseReserve + " XRP");
|
||||
System.out.println("Incremental reserve: " + reserveInc + " XRP");
|
||||
|
||||
// Look up owner count ----------------------
|
||||
|
||||
Address address = Address.of("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh");
|
||||
var accountInfo = xrplClient.accountInfo(
|
||||
AccountInfoRequestParams.builder()
|
||||
.account(address)
|
||||
.ledgerSpecifier(LedgerSpecifier.VALIDATED)
|
||||
.build()
|
||||
);
|
||||
|
||||
long ownerCount = accountInfo.accountData().ownerCount().longValue();
|
||||
|
||||
// Calculate total reserve ----------------------
|
||||
|
||||
BigDecimal totalReserve = baseReserve.add(reserveInc.multiply(BigDecimal.valueOf(ownerCount)));
|
||||
|
||||
System.out.println("Owner count: " + ownerCount);
|
||||
System.out.println("Total reserve: " + totalReserve + " XRP");
|
||||
}
|
||||
}
|
||||
33
_code-samples/calculate-reserves/js/calculate_reserves.js
Normal file
33
_code-samples/calculate-reserves/js/calculate_reserves.js
Normal file
@@ -0,0 +1,33 @@
|
||||
|
||||
// Set up client ----------------------
|
||||
|
||||
import xrpl from 'xrpl'
|
||||
|
||||
const client = new xrpl.Client('wss://s.devnet.rippletest.net:51233')
|
||||
await client.connect()
|
||||
|
||||
// Look up reserve values ----------------------
|
||||
|
||||
const serverInfo = await client.request({ command: 'server_info' })
|
||||
const validatedLedger = serverInfo.result.info.validated_ledger
|
||||
|
||||
const baseReserve = validatedLedger.reserve_base_xrp
|
||||
const reserveInc = validatedLedger.reserve_inc_xrp
|
||||
|
||||
console.log(`Base reserve: ${baseReserve} XRP`)
|
||||
console.log(`Incremental reserve: ${reserveInc} XRP`)
|
||||
|
||||
// Look up owner count ----------------------
|
||||
|
||||
const address = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh" // replace with any address
|
||||
const accountInfo = await client.request({ command: "account_info", account: address })
|
||||
const ownerCount = accountInfo.result.account_data.OwnerCount
|
||||
|
||||
// Calculate total reserve ----------------------
|
||||
|
||||
const totalReserve = baseReserve + (ownerCount * reserveInc)
|
||||
|
||||
console.log(`Owner count: ${ownerCount}`)
|
||||
console.log(`Total reserve: ${totalReserve} XRP`)
|
||||
|
||||
await client.disconnect()
|
||||
34
_code-samples/calculate-reserves/py/calculate_reserves.py
Normal file
34
_code-samples/calculate-reserves/py/calculate_reserves.py
Normal file
@@ -0,0 +1,34 @@
|
||||
|
||||
# Set up client ----------------------
|
||||
|
||||
from xrpl.clients import JsonRpcClient
|
||||
|
||||
client = JsonRpcClient("https://s.devnet.rippletest.net:51234")
|
||||
|
||||
# Look up reserve values ----------------------
|
||||
|
||||
from xrpl.models.requests import ServerInfo
|
||||
|
||||
response = client.request(ServerInfo())
|
||||
validated_ledger = response.result["info"]["validated_ledger"]
|
||||
|
||||
base_reserve = validated_ledger["reserve_base_xrp"]
|
||||
reserve_inc = validated_ledger["reserve_inc_xrp"]
|
||||
|
||||
print(f"Base reserve: {base_reserve} XRP")
|
||||
print(f"Incremental reserve: {reserve_inc} XRP")
|
||||
|
||||
# Look up owner count ----------------------
|
||||
|
||||
from xrpl.models.requests import AccountInfo
|
||||
|
||||
address = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh" # replace with any address
|
||||
response = client.request(AccountInfo(account=address))
|
||||
owner_count = response.result["account_data"]["OwnerCount"]
|
||||
|
||||
# Calculate total reserve ----------------------
|
||||
|
||||
total_reserve = base_reserve + (owner_count * reserve_inc)
|
||||
|
||||
print(f"Owner count: {owner_count}")
|
||||
print(f"Total reserve: {total_reserve} XRP")
|
||||
@@ -1,184 +0,0 @@
|
||||
# Escrow (Go)
|
||||
|
||||
This directory contains Go examples demonstrating how to create, finish, and cancel escrows on the XRP Ledger.
|
||||
|
||||
## Setup
|
||||
|
||||
All commands should be run from this `go/` directory.
|
||||
|
||||
Install dependencies before running any examples:
|
||||
|
||||
```sh
|
||||
go mod tidy
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Send Fungible Token Escrow
|
||||
|
||||
```sh
|
||||
go run ./send-fungible-token-escrow
|
||||
```
|
||||
|
||||
The script issues an MPT and Trust Line Token, setting up both to be escrowable. It then creates and finishes a conditional escrow with the MPT and a timed escrow with the Trust Line Token.
|
||||
|
||||
```sh
|
||||
=== Funding Accounts ===
|
||||
|
||||
Funding Issuer account...
|
||||
Funding Escrow Creator account...
|
||||
Issuer: rsHiso1Qb4vb9GfuWSvmPeBuk6BT1479uD
|
||||
Escrow Creator: rfQVjJ9sRYcLqwxRV2rqSSFm9jusXXo9Sk
|
||||
|
||||
=== Creating MPT ===
|
||||
|
||||
{
|
||||
"Account": "rsHiso1Qb4vb9GfuWSvmPeBuk6BT1479uD",
|
||||
"Flags": 8,
|
||||
"MaximumAmount": "1000000",
|
||||
"TransactionType": "MPTokenIssuanceCreate"
|
||||
}
|
||||
|
||||
Submitting MPTokenIssuanceCreate transaction...
|
||||
MPT created: 00F7A9BD191FD9BB1D11E217CA5643AED429859BDD40EF8B
|
||||
|
||||
=== Escrow Creator Authorizing MPT ===
|
||||
|
||||
{
|
||||
"Account": "rfQVjJ9sRYcLqwxRV2rqSSFm9jusXXo9Sk",
|
||||
"MPTokenIssuanceID": "00F7A9BD191FD9BB1D11E217CA5643AED429859BDD40EF8B",
|
||||
"TransactionType": "MPTokenAuthorize"
|
||||
}
|
||||
|
||||
Submitting MPTokenAuthorize transaction...
|
||||
Escrow Creator authorized for MPT.
|
||||
|
||||
=== Issuer Sending MPTs to Escrow Creator ===
|
||||
|
||||
{
|
||||
"Account": "rsHiso1Qb4vb9GfuWSvmPeBuk6BT1479uD",
|
||||
"Amount": {
|
||||
"mpt_issuance_id": "00F7A9BD191FD9BB1D11E217CA5643AED429859BDD40EF8B",
|
||||
"value": "5000"
|
||||
},
|
||||
"Destination": "rfQVjJ9sRYcLqwxRV2rqSSFm9jusXXo9Sk",
|
||||
"TransactionType": "Payment"
|
||||
}
|
||||
|
||||
Submitting MPT Payment transaction...
|
||||
Successfully sent 5000 MPTs to Escrow Creator.
|
||||
|
||||
=== Creating Conditional MPT Escrow ===
|
||||
|
||||
Condition: A025802057FDC219A423C4F0DA150941EB529B1D927816FAB394617A0430D1DDB39A3EDB810120
|
||||
Fulfillment: A0228020F16E8A8697ABAE14C60A5D812A2D228F9E6F67B8CA4818DC80BBF539004490DB
|
||||
|
||||
{
|
||||
"Account": "rfQVjJ9sRYcLqwxRV2rqSSFm9jusXXo9Sk",
|
||||
"Amount": {
|
||||
"mpt_issuance_id": "00F7A9BD191FD9BB1D11E217CA5643AED429859BDD40EF8B",
|
||||
"value": "1000"
|
||||
},
|
||||
"CancelAfter": 828559916,
|
||||
"Condition": "A025802057FDC219A423C4F0DA150941EB529B1D927816FAB394617A0430D1DDB39A3EDB810120",
|
||||
"Destination": "rsHiso1Qb4vb9GfuWSvmPeBuk6BT1479uD",
|
||||
"TransactionType": "EscrowCreate"
|
||||
}
|
||||
|
||||
Submitting MPT EscrowCreate transaction...
|
||||
Conditional MPT escrow created. Sequence: 16230848
|
||||
|
||||
=== Finishing Conditional MPT Escrow ===
|
||||
|
||||
{
|
||||
"Account": "rfQVjJ9sRYcLqwxRV2rqSSFm9jusXXo9Sk",
|
||||
"Condition": "A025802057FDC219A423C4F0DA150941EB529B1D927816FAB394617A0430D1DDB39A3EDB810120",
|
||||
"Fulfillment": "A0228020F16E8A8697ABAE14C60A5D812A2D228F9E6F67B8CA4818DC80BBF539004490DB",
|
||||
"OfferSequence": 16230848,
|
||||
"Owner": "rfQVjJ9sRYcLqwxRV2rqSSFm9jusXXo9Sk",
|
||||
"TransactionType": "EscrowFinish"
|
||||
}
|
||||
|
||||
Submitting EscrowFinish transaction...
|
||||
Conditional MPT escrow finished successfully: https://testnet.xrpl.org/transactions/37CD7FECDC71CE70C24927969AD0FDAD55F57F2905A6F62867CB4F5AB2EE27BB
|
||||
|
||||
=== Enabling Trust Line Token Escrows on Issuer ===
|
||||
|
||||
{
|
||||
"Account": "rsHiso1Qb4vb9GfuWSvmPeBuk6BT1479uD",
|
||||
"SetFlag": 17,
|
||||
"TransactionType": "AccountSet"
|
||||
}
|
||||
|
||||
Submitting AccountSet transaction...
|
||||
Trust line token escrows enabled by issuer.
|
||||
|
||||
=== Setting Up Trust Line ===
|
||||
|
||||
{
|
||||
"Account": "rfQVjJ9sRYcLqwxRV2rqSSFm9jusXXo9Sk",
|
||||
"LimitAmount": {
|
||||
"currency": "IOU",
|
||||
"issuer": "rsHiso1Qb4vb9GfuWSvmPeBuk6BT1479uD",
|
||||
"value": "10000000"
|
||||
},
|
||||
"TransactionType": "TrustSet"
|
||||
}
|
||||
|
||||
Submitting TrustSet transaction...
|
||||
Trust line successfully created for "IOU" tokens.
|
||||
|
||||
=== Issuer Sending IOU Tokens to Escrow Creator ===
|
||||
|
||||
{
|
||||
"Account": "rsHiso1Qb4vb9GfuWSvmPeBuk6BT1479uD",
|
||||
"Amount": {
|
||||
"currency": "IOU",
|
||||
"issuer": "rsHiso1Qb4vb9GfuWSvmPeBuk6BT1479uD",
|
||||
"value": "5000"
|
||||
},
|
||||
"Destination": "rfQVjJ9sRYcLqwxRV2rqSSFm9jusXXo9Sk",
|
||||
"TransactionType": "Payment"
|
||||
}
|
||||
|
||||
Submitting Trust Line Token payment transaction...
|
||||
Successfully sent 5000 IOU tokens.
|
||||
|
||||
=== Creating Timed Trust Line Token Escrow ===
|
||||
|
||||
Escrow will mature after: 04/03/2026, 12:27:38 PM
|
||||
|
||||
{
|
||||
"Account": "rfQVjJ9sRYcLqwxRV2rqSSFm9jusXXo9Sk",
|
||||
"Amount": {
|
||||
"currency": "IOU",
|
||||
"issuer": "rsHiso1Qb4vb9GfuWSvmPeBuk6BT1479uD",
|
||||
"value": "1000"
|
||||
},
|
||||
"CancelAfter": 828559948,
|
||||
"Destination": "rsHiso1Qb4vb9GfuWSvmPeBuk6BT1479uD",
|
||||
"FinishAfter": 828559658,
|
||||
"TransactionType": "EscrowCreate"
|
||||
}
|
||||
|
||||
Submitting Trust Line Token EscrowCreate transaction...
|
||||
Trust Line Token escrow created. Sequence: 16230851
|
||||
|
||||
=== Waiting For Timed Trust Line Token Escrow to Mature ===
|
||||
|
||||
Waiting for escrow to mature... done.
|
||||
Latest validated ledger closed at: 04/03/2026, 12:27:41 PM
|
||||
Escrow confirmed ready to finish.
|
||||
|
||||
=== Finishing Timed Trust Line Token Escrow ===
|
||||
|
||||
{
|
||||
"Account": "rfQVjJ9sRYcLqwxRV2rqSSFm9jusXXo9Sk",
|
||||
"OfferSequence": 16230851,
|
||||
"Owner": "rfQVjJ9sRYcLqwxRV2rqSSFm9jusXXo9Sk",
|
||||
"TransactionType": "EscrowFinish"
|
||||
}
|
||||
|
||||
Submitting EscrowFinish transaction...
|
||||
Timed Trust Line Token escrow finished successfully: https://testnet.xrpl.org/transactions/9D1937BE3ADFC42078F222B1DBAE8571BBC096DDA7A47911C4715221C83EC22D
|
||||
```
|
||||
@@ -1,23 +0,0 @@
|
||||
module github.com/XRPLF
|
||||
|
||||
go 1.24.3
|
||||
|
||||
require (
|
||||
github.com/Peersyst/xrpl-go v0.1.17
|
||||
github.com/go-interledger/cryptoconditions v0.0.0-20180612102545-aba58e59cef1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/PromonLogicalis/asn1 v0.0.0-20190312173541-d60463189a56 // indirect
|
||||
github.com/bsv-blockchain/go-sdk v1.2.9 // indirect
|
||||
github.com/decred/dcrd/crypto/ripemd160 v1.0.2 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.1 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/kalaspuffar/base64url v0.0.0-20171121144659-483af17b794c // indirect
|
||||
github.com/magiconair/properties v1.8.10 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/stevenroose/asn1 v0.0.0-20170613173945-a0d410e3f79f // indirect
|
||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||
golang.org/x/crypto v0.44.0 // indirect
|
||||
)
|
||||
@@ -1,461 +0,0 @@
|
||||
// This example demonstrates how to create escrows that hold fungible tokens.
|
||||
// It covers MPTs and Trust Line Tokens, and uses conditional and timed escrows.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Peersyst/xrpl-go/pkg/crypto"
|
||||
"github.com/Peersyst/xrpl-go/xrpl/faucet"
|
||||
"github.com/Peersyst/xrpl-go/xrpl/queries/account"
|
||||
"github.com/Peersyst/xrpl-go/xrpl/queries/common"
|
||||
ledgerreq "github.com/Peersyst/xrpl-go/xrpl/queries/ledger"
|
||||
xrpltime "github.com/Peersyst/xrpl-go/xrpl/time"
|
||||
"github.com/Peersyst/xrpl-go/xrpl/transaction"
|
||||
"github.com/Peersyst/xrpl-go/xrpl/transaction/types"
|
||||
"github.com/Peersyst/xrpl-go/xrpl/wallet"
|
||||
"github.com/Peersyst/xrpl-go/xrpl/websocket"
|
||||
wstypes "github.com/Peersyst/xrpl-go/xrpl/websocket/types"
|
||||
"github.com/go-interledger/cryptoconditions"
|
||||
)
|
||||
|
||||
func main() {
|
||||
client := websocket.NewClient(
|
||||
websocket.NewClientConfig().
|
||||
WithHost("wss://s.altnet.rippletest.net:51233").
|
||||
WithFaucetProvider(faucet.NewTestnetFaucetProvider()),
|
||||
)
|
||||
defer client.Disconnect()
|
||||
|
||||
if err := client.Connect(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Fund an issuer account and an escrow creator account ----------------------
|
||||
fmt.Printf("\n=== Funding Accounts ===\n\n")
|
||||
|
||||
createAndFund := func(label string) wallet.Wallet {
|
||||
fmt.Printf("Funding %s account...\n", label)
|
||||
w, err := wallet.New(crypto.ED25519())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := client.FundWallet(&w); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Poll until account is validated on ledger
|
||||
funded := false
|
||||
for range 20 {
|
||||
_, err := client.Request(&account.InfoRequest{
|
||||
Account: w.GetAddress(),
|
||||
LedgerIndex: common.Validated,
|
||||
})
|
||||
if err == nil {
|
||||
funded = true
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
if !funded {
|
||||
panic("Issue funding account: " + w.GetAddress().String())
|
||||
}
|
||||
return w
|
||||
}
|
||||
|
||||
issuer := createAndFund("Issuer")
|
||||
creator := createAndFund("Escrow Creator")
|
||||
fmt.Printf("Issuer: %s\n", issuer.ClassicAddress)
|
||||
fmt.Printf("Escrow Creator: %s\n", creator.ClassicAddress)
|
||||
|
||||
// ====== Conditional MPT Escrow ======
|
||||
|
||||
// Issuer creates an MPT ----------------------
|
||||
fmt.Printf("\n=== Creating MPT ===\n\n")
|
||||
maxAmount := types.XRPCurrencyAmount(1000000)
|
||||
mptCreateTx := transaction.MPTokenIssuanceCreate{
|
||||
BaseTx: transaction.BaseTx{
|
||||
Account: issuer.ClassicAddress,
|
||||
Flags: transaction.TfMPTCanEscrow,
|
||||
},
|
||||
MaximumAmount: &maxAmount,
|
||||
}
|
||||
|
||||
// Flatten() converts the struct to a map and adds the TransactionType field
|
||||
flatMptCreateTx := mptCreateTx.Flatten()
|
||||
mptCreateTxJSON, _ := json.MarshalIndent(flatMptCreateTx, "", " ")
|
||||
fmt.Printf("%s\n", string(mptCreateTxJSON))
|
||||
|
||||
// Submit, sign, and wait for validation
|
||||
fmt.Printf("\nSubmitting MPTokenIssuanceCreate transaction...\n")
|
||||
mptCreateResponse, err := client.SubmitTxAndWait(flatMptCreateTx, &wstypes.SubmitOptions{
|
||||
Autofill: true,
|
||||
Wallet: &issuer,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if mptCreateResponse.Meta.TransactionResult != "tesSUCCESS" {
|
||||
fmt.Printf("MPTokenIssuanceCreate failed: %s\n", mptCreateResponse.Meta.TransactionResult)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Extract the MPT issuance ID from the transaction result
|
||||
mptIssuanceID := string(*mptCreateResponse.Meta.MPTIssuanceID)
|
||||
fmt.Printf("MPT created: %s\n", mptIssuanceID)
|
||||
|
||||
// Escrow Creator authorizes the MPT ----------------------
|
||||
fmt.Printf("\n=== Escrow Creator Authorizing MPT ===\n\n")
|
||||
mptAuthTx := transaction.MPTokenAuthorize{
|
||||
BaseTx: transaction.BaseTx{
|
||||
Account: creator.ClassicAddress,
|
||||
},
|
||||
MPTokenIssuanceID: mptIssuanceID,
|
||||
}
|
||||
|
||||
flatMptAuthTx := mptAuthTx.Flatten()
|
||||
mptAuthTxJSON, _ := json.MarshalIndent(flatMptAuthTx, "", " ")
|
||||
fmt.Printf("%s\n", string(mptAuthTxJSON))
|
||||
|
||||
fmt.Printf("\nSubmitting MPTokenAuthorize transaction...\n")
|
||||
mptAuthResponse, err := client.SubmitTxAndWait(flatMptAuthTx, &wstypes.SubmitOptions{
|
||||
Autofill: true,
|
||||
Wallet: &creator,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if mptAuthResponse.Meta.TransactionResult != "tesSUCCESS" {
|
||||
fmt.Printf("MPTokenAuthorize failed: %s\n", mptAuthResponse.Meta.TransactionResult)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("Escrow Creator authorized for MPT.\n")
|
||||
|
||||
// Issuer sends MPTs to escrow creator ----------------------
|
||||
fmt.Printf("\n=== Issuer Sending MPTs to Escrow Creator ===\n\n")
|
||||
mptPaymentTx := transaction.Payment{
|
||||
BaseTx: transaction.BaseTx{
|
||||
Account: issuer.ClassicAddress,
|
||||
},
|
||||
Destination: creator.ClassicAddress,
|
||||
Amount: types.MPTCurrencyAmount{
|
||||
MPTIssuanceID: mptIssuanceID,
|
||||
Value: "5000",
|
||||
},
|
||||
}
|
||||
|
||||
flatMptPaymentTx := mptPaymentTx.Flatten()
|
||||
mptPaymentTxJSON, _ := json.MarshalIndent(flatMptPaymentTx, "", " ")
|
||||
fmt.Printf("%s\n", string(mptPaymentTxJSON))
|
||||
|
||||
fmt.Printf("\nSubmitting MPT Payment transaction...\n")
|
||||
mptPaymentResponse, err := client.SubmitTxAndWait(flatMptPaymentTx, &wstypes.SubmitOptions{
|
||||
Autofill: true,
|
||||
Wallet: &issuer,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if mptPaymentResponse.Meta.TransactionResult != "tesSUCCESS" {
|
||||
fmt.Printf("MPT Payment failed: %s\n", mptPaymentResponse.Meta.TransactionResult)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("Successfully sent 5000 MPTs to Escrow Creator.\n")
|
||||
|
||||
// Escrow Creator creates a conditional MPT escrow ----------------------
|
||||
fmt.Printf("\n=== Creating Conditional MPT Escrow ===\n\n")
|
||||
|
||||
// Generate crypto-condition
|
||||
preimage := make([]byte, 32)
|
||||
if _, err := rand.Read(preimage); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fulfillment := cryptoconditions.NewPreimageSha256(preimage)
|
||||
fulfillmentBinary, err := fulfillment.Encode()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
conditionBinary, err := fulfillment.Condition().Encode()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fulfillmentHex := strings.ToUpper(hex.EncodeToString(fulfillmentBinary))
|
||||
conditionHex := strings.ToUpper(hex.EncodeToString(conditionBinary))
|
||||
fmt.Printf("Condition: %s\n", conditionHex)
|
||||
fmt.Printf("Fulfillment: %s\n\n", fulfillmentHex)
|
||||
|
||||
// Set expiration (300 seconds from now)
|
||||
cancelAfterRippleTime := xrpltime.UnixTimeToRippleTime(time.Now().Unix()) + 300
|
||||
|
||||
mptEscrowCreateTx := transaction.EscrowCreate{
|
||||
BaseTx: transaction.BaseTx{
|
||||
Account: creator.ClassicAddress,
|
||||
},
|
||||
Destination: issuer.ClassicAddress,
|
||||
Amount: types.MPTCurrencyAmount{
|
||||
MPTIssuanceID: mptIssuanceID,
|
||||
Value: "1000",
|
||||
},
|
||||
Condition: conditionHex,
|
||||
CancelAfter: uint32(cancelAfterRippleTime), // Fungible token escrows require a CancelAfter time
|
||||
}
|
||||
|
||||
flatMptEscrowCreateTx := mptEscrowCreateTx.Flatten()
|
||||
mptEscrowCreateTxJSON, _ := json.MarshalIndent(flatMptEscrowCreateTx, "", " ")
|
||||
fmt.Printf("%s\n", string(mptEscrowCreateTxJSON))
|
||||
|
||||
fmt.Printf("\nSubmitting MPT EscrowCreate transaction...\n")
|
||||
mptEscrowResponse, err := client.SubmitTxAndWait(flatMptEscrowCreateTx, &wstypes.SubmitOptions{
|
||||
Autofill: true,
|
||||
Wallet: &creator,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if mptEscrowResponse.Meta.TransactionResult != "tesSUCCESS" {
|
||||
fmt.Printf("MPT EscrowCreate failed: %s\n", mptEscrowResponse.Meta.TransactionResult)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Save the sequence number to identify the escrow later
|
||||
mptEscrowSeq := mptEscrowResponse.TxJSON.Sequence()
|
||||
fmt.Printf("Conditional MPT escrow created. Sequence: %d\n", mptEscrowSeq)
|
||||
|
||||
// Finish the conditional MPT escrow with the fulfillment ----------------------
|
||||
fmt.Printf("\n=== Finishing Conditional MPT Escrow ===\n\n")
|
||||
mptEscrowFinishTx := transaction.EscrowFinish{
|
||||
BaseTx: transaction.BaseTx{
|
||||
Account: creator.ClassicAddress,
|
||||
},
|
||||
Owner: creator.ClassicAddress,
|
||||
OfferSequence: mptEscrowSeq,
|
||||
Condition: conditionHex,
|
||||
Fulfillment: fulfillmentHex,
|
||||
}
|
||||
|
||||
flatMptEscrowFinishTx := mptEscrowFinishTx.Flatten()
|
||||
mptEscrowFinishTxJSON, _ := json.MarshalIndent(flatMptEscrowFinishTx, "", " ")
|
||||
fmt.Printf("%s\n", string(mptEscrowFinishTxJSON))
|
||||
|
||||
fmt.Printf("\nSubmitting EscrowFinish transaction...\n")
|
||||
mptFinishResponse, err := client.SubmitTxAndWait(flatMptEscrowFinishTx, &wstypes.SubmitOptions{
|
||||
Autofill: true,
|
||||
Wallet: &creator,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if mptFinishResponse.Meta.TransactionResult != "tesSUCCESS" {
|
||||
fmt.Printf("MPT EscrowFinish failed: %s\n", mptFinishResponse.Meta.TransactionResult)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("Conditional MPT escrow finished successfully: https://testnet.xrpl.org/transactions/%s\n", mptFinishResponse.Hash)
|
||||
|
||||
// ====== Timed Trust Line Token Escrow ======
|
||||
|
||||
// Enable trust line token escrows on the issuer ----------------------
|
||||
fmt.Printf("\n=== Enabling Trust Line Token Escrows on Issuer ===\n\n")
|
||||
accountSetTx := transaction.AccountSet{
|
||||
BaseTx: transaction.BaseTx{
|
||||
Account: issuer.ClassicAddress,
|
||||
},
|
||||
SetFlag: transaction.AsfAllowTrustLineLocking,
|
||||
}
|
||||
|
||||
flatAccountSetTx := accountSetTx.Flatten()
|
||||
accountSetTxJSON, _ := json.MarshalIndent(flatAccountSetTx, "", " ")
|
||||
fmt.Printf("%s\n", string(accountSetTxJSON))
|
||||
|
||||
fmt.Printf("\nSubmitting AccountSet transaction...\n")
|
||||
accountSetResponse, err := client.SubmitTxAndWait(flatAccountSetTx, &wstypes.SubmitOptions{
|
||||
Autofill: true,
|
||||
Wallet: &issuer,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if accountSetResponse.Meta.TransactionResult != "tesSUCCESS" {
|
||||
fmt.Printf("AccountSet failed: %s\n", accountSetResponse.Meta.TransactionResult)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("Trust line token escrows enabled by issuer.\n")
|
||||
|
||||
// Escrow Creator sets up a trust line to the issuer ----------------------
|
||||
fmt.Printf("\n=== Setting Up Trust Line ===\n\n")
|
||||
currencyCode := "IOU"
|
||||
|
||||
trustSetTx := transaction.TrustSet{
|
||||
BaseTx: transaction.BaseTx{
|
||||
Account: creator.ClassicAddress,
|
||||
},
|
||||
LimitAmount: types.IssuedCurrencyAmount{
|
||||
Currency: currencyCode,
|
||||
Issuer: issuer.ClassicAddress,
|
||||
Value: "10000000",
|
||||
},
|
||||
}
|
||||
|
||||
flatTrustSetTx := trustSetTx.Flatten()
|
||||
trustSetTxJSON, _ := json.MarshalIndent(flatTrustSetTx, "", " ")
|
||||
fmt.Printf("%s\n", string(trustSetTxJSON))
|
||||
|
||||
fmt.Printf("\nSubmitting TrustSet transaction...\n")
|
||||
trustResponse, err := client.SubmitTxAndWait(flatTrustSetTx, &wstypes.SubmitOptions{
|
||||
Autofill: true,
|
||||
Wallet: &creator,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if trustResponse.Meta.TransactionResult != "tesSUCCESS" {
|
||||
fmt.Printf("TrustSet failed: %s\n", trustResponse.Meta.TransactionResult)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("Trust line successfully created for \"IOU\" tokens.\n")
|
||||
|
||||
// Issuer sends IOU tokens to creator ----------------------
|
||||
fmt.Printf("\n=== Issuer Sending IOU Tokens to Escrow Creator ===\n\n")
|
||||
iouPaymentTx := transaction.Payment{
|
||||
BaseTx: transaction.BaseTx{
|
||||
Account: issuer.ClassicAddress,
|
||||
},
|
||||
Destination: creator.ClassicAddress,
|
||||
Amount: types.IssuedCurrencyAmount{
|
||||
Currency: currencyCode,
|
||||
Value: "5000",
|
||||
Issuer: issuer.ClassicAddress,
|
||||
},
|
||||
}
|
||||
|
||||
flatIouPaymentTx := iouPaymentTx.Flatten()
|
||||
iouPaymentTxJSON, _ := json.MarshalIndent(flatIouPaymentTx, "", " ")
|
||||
fmt.Printf("%s\n", string(iouPaymentTxJSON))
|
||||
|
||||
fmt.Printf("\nSubmitting Trust Line Token payment transaction...\n")
|
||||
iouPayResponse, err := client.SubmitTxAndWait(flatIouPaymentTx, &wstypes.SubmitOptions{
|
||||
Autofill: true,
|
||||
Wallet: &issuer,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if iouPayResponse.Meta.TransactionResult != "tesSUCCESS" {
|
||||
fmt.Printf("Trust Line Token payment failed: %s\n", iouPayResponse.Meta.TransactionResult)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("Successfully sent 5000 %s tokens.\n", currencyCode)
|
||||
|
||||
// Escrow Creator creates a timed trust line token escrow ----------------------
|
||||
fmt.Printf("\n=== Creating Timed Trust Line Token Escrow ===\n\n")
|
||||
delay := 10 // seconds
|
||||
now := time.Now()
|
||||
finishAfterRippleTime := xrpltime.UnixTimeToRippleTime(now.Unix()) + int64(delay)
|
||||
matureTime := now.Add(time.Duration(delay) * time.Second).Format("01/02/2006, 03:04:05 PM")
|
||||
fmt.Printf("Escrow will mature after: %s\n\n", matureTime)
|
||||
|
||||
iouCancelAfterRippleTime := xrpltime.UnixTimeToRippleTime(now.Unix()) + 300
|
||||
|
||||
iouEscrowCreateTx := transaction.EscrowCreate{
|
||||
BaseTx: transaction.BaseTx{
|
||||
Account: creator.ClassicAddress,
|
||||
},
|
||||
Destination: issuer.ClassicAddress,
|
||||
Amount: types.IssuedCurrencyAmount{
|
||||
Currency: currencyCode,
|
||||
Value: "1000",
|
||||
Issuer: issuer.ClassicAddress,
|
||||
},
|
||||
FinishAfter: uint32(finishAfterRippleTime),
|
||||
CancelAfter: uint32(iouCancelAfterRippleTime),
|
||||
}
|
||||
|
||||
flatIouEscrowCreateTx := iouEscrowCreateTx.Flatten()
|
||||
iouEscrowCreateTxJSON, _ := json.MarshalIndent(flatIouEscrowCreateTx, "", " ")
|
||||
fmt.Printf("%s\n", string(iouEscrowCreateTxJSON))
|
||||
|
||||
fmt.Printf("\nSubmitting Trust Line Token EscrowCreate transaction...\n")
|
||||
iouEscrowResponse, err := client.SubmitTxAndWait(flatIouEscrowCreateTx, &wstypes.SubmitOptions{
|
||||
Autofill: true,
|
||||
Wallet: &creator,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if iouEscrowResponse.Meta.TransactionResult != "tesSUCCESS" {
|
||||
fmt.Printf("Trust Line Token EscrowCreate failed: %s\n", iouEscrowResponse.Meta.TransactionResult)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Save the sequence number to identify the escrow later
|
||||
iouEscrowSeq := iouEscrowResponse.TxJSON.Sequence()
|
||||
fmt.Printf("Trust Line Token escrow created. Sequence: %d\n", iouEscrowSeq)
|
||||
|
||||
// Wait for the escrow to mature, then finish it --------------------
|
||||
fmt.Printf("\n=== Waiting For Timed Trust Line Token Escrow to Mature ===\n\n")
|
||||
|
||||
// Countdown delay until escrow matures
|
||||
for i := delay; i >= 0; i-- {
|
||||
fmt.Printf("Waiting for escrow to mature... %ds remaining...\r", i)
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
fmt.Printf("Waiting for escrow to mature... done. \n")
|
||||
|
||||
// Confirm latest validated ledger close time is after the FinishAfter time
|
||||
escrowReady := false
|
||||
for !escrowReady {
|
||||
ledgerResp, err := client.GetLedger(&ledgerreq.Request{
|
||||
LedgerIndex: common.Validated,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ledgerCloseTime := int64(ledgerResp.Ledger.CloseTime)
|
||||
ledgerCloseLocal := time.Unix(xrpltime.RippleTimeToUnixTime(ledgerCloseTime)/1000, 0).Format("01/02/2006, 03:04:05 PM")
|
||||
fmt.Printf("Latest validated ledger closed at: %s\n", ledgerCloseLocal)
|
||||
if ledgerCloseTime > finishAfterRippleTime {
|
||||
escrowReady = true
|
||||
fmt.Printf("Escrow confirmed ready to finish.\n")
|
||||
} else {
|
||||
timeDifference := finishAfterRippleTime - ledgerCloseTime
|
||||
if timeDifference == 0 {
|
||||
timeDifference = 1
|
||||
}
|
||||
fmt.Printf("Escrow needs to wait another %ds.\n", timeDifference)
|
||||
time.Sleep(time.Duration(timeDifference) * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
// Finish the timed trust line token escrow --------------------
|
||||
fmt.Printf("\n=== Finishing Timed Trust Line Token Escrow ===\n\n")
|
||||
iouEscrowFinishTx := transaction.EscrowFinish{
|
||||
BaseTx: transaction.BaseTx{
|
||||
Account: creator.ClassicAddress,
|
||||
},
|
||||
Owner: creator.ClassicAddress,
|
||||
OfferSequence: iouEscrowSeq,
|
||||
}
|
||||
|
||||
flatIouEscrowFinishTx := iouEscrowFinishTx.Flatten()
|
||||
iouEscrowFinishTxJSON, _ := json.MarshalIndent(flatIouEscrowFinishTx, "", " ")
|
||||
fmt.Printf("%s\n", string(iouEscrowFinishTxJSON))
|
||||
|
||||
fmt.Printf("\nSubmitting EscrowFinish transaction...\n")
|
||||
iouFinishResponse, err := client.SubmitTxAndWait(flatIouEscrowFinishTx, &wstypes.SubmitOptions{
|
||||
Autofill: true,
|
||||
Wallet: &creator,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if iouFinishResponse.Meta.TransactionResult != "tesSUCCESS" {
|
||||
fmt.Printf("Trust Line Token EscrowFinish failed: %s\n", iouFinishResponse.Meta.TransactionResult)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("Timed Trust Line Token escrow finished successfully: https://testnet.xrpl.org/transactions/%s\n", iouFinishResponse.Hash)
|
||||
}
|
||||
@@ -20,173 +20,6 @@ node send-timed-escrow.js
|
||||
node send-conditional-escrow.js
|
||||
```
|
||||
|
||||
## Send Fungible Token Escrow
|
||||
|
||||
```sh
|
||||
node sendFungibleTokenEscrow.js
|
||||
```
|
||||
|
||||
The script issues an MPT and Trust Line Token, setting up both to be escrowable. It then creates and finishes a conditional escrow with the MPT and a timed escrow with the Trust Line Token.
|
||||
|
||||
```sh
|
||||
=== Funding Accounts ===
|
||||
|
||||
Issuer: rLqYtjhg56pVNJFKueVVKkiA8z5UtznxQP
|
||||
Escrow Creator: rGRvH4FanVixca934o3ui4MbcrU56x9Qj4
|
||||
|
||||
=== Creating MPT ===
|
||||
|
||||
{
|
||||
"TransactionType": "MPTokenIssuanceCreate",
|
||||
"Account": "rLqYtjhg56pVNJFKueVVKkiA8z5UtznxQP",
|
||||
"MaximumAmount": "1000000",
|
||||
"Flags": 8
|
||||
}
|
||||
|
||||
Submitting MPTokenIssuanceCreate transaction...
|
||||
MPT created: 00F763A2D998FA5E720228B31E1162AC55E6311C7D31F3FC
|
||||
|
||||
=== Escrow Creator Authorizing MPT ===
|
||||
|
||||
{
|
||||
"TransactionType": "MPTokenAuthorize",
|
||||
"Account": "rGRvH4FanVixca934o3ui4MbcrU56x9Qj4",
|
||||
"MPTokenIssuanceID": "00F763A2D998FA5E720228B31E1162AC55E6311C7D31F3FC"
|
||||
}
|
||||
|
||||
Submitting MPTokenAuthorize transaction...
|
||||
Escrow Creator authorized for MPT.
|
||||
|
||||
=== Issuer Sending MPTs to Escrow Creator ===
|
||||
|
||||
{
|
||||
"TransactionType": "Payment",
|
||||
"Account": "rLqYtjhg56pVNJFKueVVKkiA8z5UtznxQP",
|
||||
"Destination": "rGRvH4FanVixca934o3ui4MbcrU56x9Qj4",
|
||||
"Amount": {
|
||||
"mpt_issuance_id": "00F763A2D998FA5E720228B31E1162AC55E6311C7D31F3FC",
|
||||
"value": "5000"
|
||||
}
|
||||
}
|
||||
|
||||
Submitting MPT Payment transaction...
|
||||
Successfully sent 5000 MPTs to Escrow Creator.
|
||||
|
||||
=== Creating Conditional MPT Escrow ===
|
||||
|
||||
Condition: A0258020AA2B8450898500A9E6332B7AD107264982CB09C63E3D16D139D63E997597E6F6810120
|
||||
Fulfillment: A0228020CA07971CB0C63ED20C69931B41EEA7C4C8CC6F214183FDE031CDC7413856977F
|
||||
|
||||
{
|
||||
"TransactionType": "EscrowCreate",
|
||||
"Account": "rGRvH4FanVixca934o3ui4MbcrU56x9Qj4",
|
||||
"Destination": "rLqYtjhg56pVNJFKueVVKkiA8z5UtznxQP",
|
||||
"Amount": {
|
||||
"mpt_issuance_id": "00F763A2D998FA5E720228B31E1162AC55E6311C7D31F3FC",
|
||||
"value": "1000"
|
||||
},
|
||||
"Condition": "A0258020AA2B8450898500A9E6332B7AD107264982CB09C63E3D16D139D63E997597E6F6810120",
|
||||
"CancelAfter": 828504579
|
||||
}
|
||||
|
||||
Submitting MPT EscrowCreate transaction...
|
||||
Conditional MPT escrow created. Sequence: 16212899
|
||||
|
||||
=== Finishing Conditional MPT Escrow ===
|
||||
|
||||
{
|
||||
"TransactionType": "EscrowFinish",
|
||||
"Account": "rGRvH4FanVixca934o3ui4MbcrU56x9Qj4",
|
||||
"Owner": "rGRvH4FanVixca934o3ui4MbcrU56x9Qj4",
|
||||
"OfferSequence": 16212899,
|
||||
"Condition": "A0258020AA2B8450898500A9E6332B7AD107264982CB09C63E3D16D139D63E997597E6F6810120",
|
||||
"Fulfillment": "A0228020CA07971CB0C63ED20C69931B41EEA7C4C8CC6F214183FDE031CDC7413856977F"
|
||||
}
|
||||
|
||||
Submitting EscrowFinish transaction...
|
||||
Conditional MPT escrow finished successfully: https://testnet.xrpl.org/transactions/BB6E8BF8A7F28D15C12C24FFDB215180262ABFAEAD43FB020DCB39E826027078
|
||||
|
||||
=== Enabling Trust Line Token Escrows on Issuer ===
|
||||
|
||||
{
|
||||
"TransactionType": "AccountSet",
|
||||
"Account": "rLqYtjhg56pVNJFKueVVKkiA8z5UtznxQP",
|
||||
"SetFlag": 17
|
||||
}
|
||||
|
||||
Submitting AccountSet transaction...
|
||||
Trust line token escrows enabled by issuer.
|
||||
|
||||
=== Setting Up Trust Line ===
|
||||
|
||||
{
|
||||
"TransactionType": "TrustSet",
|
||||
"Account": "rGRvH4FanVixca934o3ui4MbcrU56x9Qj4",
|
||||
"LimitAmount": {
|
||||
"currency": "IOU",
|
||||
"issuer": "rLqYtjhg56pVNJFKueVVKkiA8z5UtznxQP",
|
||||
"value": "10000000"
|
||||
}
|
||||
}
|
||||
|
||||
Submitting TrustSet transaction...
|
||||
Trust line successfully created for "IOU" tokens.
|
||||
|
||||
=== Issuer Sending IOU Tokens to Escrow Creator ===
|
||||
|
||||
{
|
||||
"TransactionType": "Payment",
|
||||
"Account": "rLqYtjhg56pVNJFKueVVKkiA8z5UtznxQP",
|
||||
"Destination": "rGRvH4FanVixca934o3ui4MbcrU56x9Qj4",
|
||||
"Amount": {
|
||||
"currency": "IOU",
|
||||
"value": "5000",
|
||||
"issuer": "rLqYtjhg56pVNJFKueVVKkiA8z5UtznxQP"
|
||||
}
|
||||
}
|
||||
|
||||
Submitting Trust Line Token payment transaction...
|
||||
Successfully sent 5000 IOU tokens.
|
||||
|
||||
=== Creating Timed Trust Line Token Escrow ===
|
||||
|
||||
Escrow will mature after: 4/2/2026, 9:05:12 PM
|
||||
|
||||
{
|
||||
"TransactionType": "EscrowCreate",
|
||||
"Account": "rGRvH4FanVixca934o3ui4MbcrU56x9Qj4",
|
||||
"Destination": "rLqYtjhg56pVNJFKueVVKkiA8z5UtznxQP",
|
||||
"Amount": {
|
||||
"currency": "IOU",
|
||||
"value": "1000",
|
||||
"issuer": "rLqYtjhg56pVNJFKueVVKkiA8z5UtznxQP"
|
||||
},
|
||||
"FinishAfter": 828504312,
|
||||
"CancelAfter": 828504602
|
||||
}
|
||||
|
||||
Submitting Trust Line Token EscrowCreate transaction...
|
||||
Trust Line Token escrow created. Sequence: 16212902
|
||||
|
||||
=== Waiting For Timed Trust Line Token Escrow to Mature ===
|
||||
|
||||
Waiting for escrow to mature... done.
|
||||
Latest validated ledger closed at: 4/2/2026, 9:05:13 PM
|
||||
Escrow confirmed ready to finish.
|
||||
|
||||
=== Finishing Timed Trust Line Token Escrow ===
|
||||
|
||||
{
|
||||
"TransactionType": "EscrowFinish",
|
||||
"Account": "rGRvH4FanVixca934o3ui4MbcrU56x9Qj4",
|
||||
"Owner": "rGRvH4FanVixca934o3ui4MbcrU56x9Qj4",
|
||||
"OfferSequence": 16212902
|
||||
}
|
||||
|
||||
Submitting EscrowFinish transaction...
|
||||
Timed Trust Line Token escrow finished successfully: https://testnet.xrpl.org/transactions/136402974863BF553706B0A4A341F24DDA5385BB6F93B905038D8FD9863B6D91
|
||||
```
|
||||
|
||||
## List Escrows
|
||||
|
||||
```sh
|
||||
|
||||
@@ -1,358 +0,0 @@
|
||||
// This example demonstrates how to create escrows that hold fungible tokens.
|
||||
// It covers MPTs and Trust Line Tokens, and uses conditional and timed escrows.
|
||||
|
||||
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()
|
||||
|
||||
// Fund an issuer account and an escrow creator account ----------------------
|
||||
console.log(`\n=== Funding Accounts ===\n`)
|
||||
const [
|
||||
{ wallet: issuer },
|
||||
{ wallet: creator }
|
||||
] = await Promise.all([
|
||||
client.fundWallet(),
|
||||
client.fundWallet()
|
||||
])
|
||||
console.log(`Issuer: ${issuer.address}`)
|
||||
console.log(`Escrow Creator: ${creator.address}`)
|
||||
|
||||
// ====== Conditional MPT Escrow ======
|
||||
|
||||
// Issuer creates an MPT ----------------------
|
||||
console.log('\n=== Creating MPT ===\n')
|
||||
const mptCreateTx = {
|
||||
TransactionType: 'MPTokenIssuanceCreate',
|
||||
Account: issuer.address,
|
||||
MaximumAmount: '1000000',
|
||||
Flags: xrpl.MPTokenIssuanceCreateFlags.tfMPTCanEscrow
|
||||
}
|
||||
|
||||
// Validate the transaction structure before submitting
|
||||
xrpl.validate(mptCreateTx)
|
||||
console.log(JSON.stringify(mptCreateTx, null, 2))
|
||||
|
||||
// Submit, sign, and wait for validation
|
||||
console.log(`\nSubmitting MPTokenIssuanceCreate transaction...`)
|
||||
const mptCreateResponse = await client.submitAndWait(mptCreateTx, {
|
||||
wallet: issuer,
|
||||
autofill: true
|
||||
})
|
||||
if (mptCreateResponse.result.meta.TransactionResult !== 'tesSUCCESS') {
|
||||
console.error(`MPTokenIssuanceCreate failed: ${mptCreateResponse.result.meta.TransactionResult}`)
|
||||
await client.disconnect()
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
// Extract the MPT issuance ID from the transaction result
|
||||
const mptIssuanceId = mptCreateResponse.result.meta.mpt_issuance_id
|
||||
console.log(`MPT created: ${mptIssuanceId}`)
|
||||
|
||||
// Escrow Creator authorizes the MPT ----------------------
|
||||
console.log('\n=== Escrow Creator Authorizing MPT ===\n')
|
||||
const mptAuthTx = {
|
||||
TransactionType: 'MPTokenAuthorize',
|
||||
Account: creator.address,
|
||||
MPTokenIssuanceID: mptIssuanceId
|
||||
}
|
||||
|
||||
xrpl.validate(mptAuthTx)
|
||||
console.log(JSON.stringify(mptAuthTx, null, 2))
|
||||
|
||||
console.log(`\nSubmitting MPTokenAuthorize transaction...`)
|
||||
const mptAuthResponse = await client.submitAndWait(mptAuthTx, {
|
||||
wallet: creator,
|
||||
autofill: true
|
||||
})
|
||||
if (mptAuthResponse.result.meta.TransactionResult !== 'tesSUCCESS') {
|
||||
console.error(`MPTokenAuthorize failed: ${mptAuthResponse.result.meta.TransactionResult}`)
|
||||
await client.disconnect()
|
||||
process.exit(1)
|
||||
}
|
||||
console.log('Escrow Creator authorized for MPT.')
|
||||
|
||||
// Issuer sends MPTs to escrow creator ----------------------
|
||||
console.log('\n=== Issuer Sending MPTs to Escrow Creator ===\n')
|
||||
const mptPaymentTx = {
|
||||
TransactionType: 'Payment',
|
||||
Account: issuer.address,
|
||||
Destination: creator.address,
|
||||
Amount: {
|
||||
mpt_issuance_id: mptIssuanceId,
|
||||
value: '5000'
|
||||
}
|
||||
}
|
||||
|
||||
xrpl.validate(mptPaymentTx)
|
||||
console.log(JSON.stringify(mptPaymentTx, null, 2))
|
||||
|
||||
console.log(`\nSubmitting MPT Payment transaction...`)
|
||||
const mptPaymentResponse = await client.submitAndWait(mptPaymentTx, {
|
||||
wallet: issuer,
|
||||
autofill: true
|
||||
})
|
||||
if (mptPaymentResponse.result.meta.TransactionResult !== 'tesSUCCESS') {
|
||||
console.error(`MPT Payment failed: ${mptPaymentResponse.result.meta.TransactionResult}`)
|
||||
await client.disconnect()
|
||||
process.exit(1)
|
||||
}
|
||||
console.log('Successfully sent 5000 MPTs to Escrow Creator.')
|
||||
|
||||
// Escrow Creator creates a conditional MPT escrow ----------------------
|
||||
console.log('\n=== Creating Conditional MPT Escrow ===\n')
|
||||
|
||||
// Generate crypto-condition
|
||||
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}\n`)
|
||||
|
||||
// Set expiration (300 seconds from now)
|
||||
const cancelAfter = new Date()
|
||||
cancelAfter.setSeconds(cancelAfter.getSeconds() + 300)
|
||||
const cancelAfterRippleTime = xrpl.isoTimeToRippleTime(cancelAfter.toISOString())
|
||||
|
||||
const mptEscrowCreateTx = {
|
||||
TransactionType: 'EscrowCreate',
|
||||
Account: creator.address,
|
||||
Destination: issuer.address,
|
||||
Amount: {
|
||||
mpt_issuance_id: mptIssuanceId,
|
||||
value: '1000'
|
||||
},
|
||||
Condition: conditionHex,
|
||||
CancelAfter: cancelAfterRippleTime // Fungible token escrows require a CancelAfter time
|
||||
}
|
||||
|
||||
xrpl.validate(mptEscrowCreateTx)
|
||||
console.log(JSON.stringify(mptEscrowCreateTx, null, 2))
|
||||
|
||||
console.log(`\nSubmitting MPT EscrowCreate transaction...`)
|
||||
const mptEscrowResponse = await client.submitAndWait(mptEscrowCreateTx, {
|
||||
wallet: creator,
|
||||
autofill: true
|
||||
})
|
||||
if (mptEscrowResponse.result.meta.TransactionResult !== 'tesSUCCESS') {
|
||||
console.error(`MPT EscrowCreate failed: ${mptEscrowResponse.result.meta.TransactionResult}`)
|
||||
await client.disconnect()
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
// Save the sequence number to identify the escrow later
|
||||
const mptEscrowSeq = mptEscrowResponse.result.tx_json.Sequence
|
||||
console.log(`Conditional MPT escrow created. Sequence: ${mptEscrowSeq}`)
|
||||
|
||||
// Finish the conditional MPT escrow with the fulfillment ----------------------
|
||||
console.log('\n=== Finishing Conditional MPT Escrow ===\n')
|
||||
const mptEscrowFinishTx = {
|
||||
TransactionType: 'EscrowFinish',
|
||||
Account: creator.address,
|
||||
Owner: creator.address,
|
||||
OfferSequence: mptEscrowSeq,
|
||||
Condition: conditionHex,
|
||||
Fulfillment: fulfillmentHex
|
||||
}
|
||||
|
||||
xrpl.validate(mptEscrowFinishTx)
|
||||
console.log(JSON.stringify(mptEscrowFinishTx, null, 2))
|
||||
|
||||
console.log(`\nSubmitting EscrowFinish transaction...`)
|
||||
const mptFinishResponse = await client.submitAndWait(mptEscrowFinishTx, {
|
||||
wallet: creator,
|
||||
autofill: true
|
||||
})
|
||||
if (mptFinishResponse.result.meta.TransactionResult !== 'tesSUCCESS') {
|
||||
console.error(`MPT EscrowFinish failed: ${mptFinishResponse.result.meta.TransactionResult}`)
|
||||
await client.disconnect()
|
||||
process.exit(1)
|
||||
}
|
||||
console.log(`Conditional MPT escrow finished successfully: https://testnet.xrpl.org/transactions/${mptFinishResponse.result.hash}`)
|
||||
|
||||
// ====== Timed Trust Line Token Escrow ======
|
||||
|
||||
// Enable trust line token escrows on the issuer ----------------------
|
||||
console.log('\n=== Enabling Trust Line Token Escrows on Issuer ===\n')
|
||||
const accountSetTx = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: issuer.address,
|
||||
SetFlag: xrpl.AccountSetAsfFlags.asfAllowTrustLineLocking
|
||||
}
|
||||
|
||||
xrpl.validate(accountSetTx)
|
||||
console.log(JSON.stringify(accountSetTx, null, 2))
|
||||
|
||||
console.log(`\nSubmitting AccountSet transaction...`)
|
||||
const accountSetResponse = await client.submitAndWait(accountSetTx, {
|
||||
wallet: issuer,
|
||||
autofill: true
|
||||
})
|
||||
if (accountSetResponse.result.meta.TransactionResult !== 'tesSUCCESS') {
|
||||
console.error(`AccountSet failed: ${accountSetResponse.result.meta.TransactionResult}`)
|
||||
await client.disconnect()
|
||||
process.exit(1)
|
||||
}
|
||||
console.log('Trust line token escrows enabled by issuer.')
|
||||
|
||||
// Escrow Creator sets up a trust line to the issuer ----------------------
|
||||
console.log('\n=== Setting Up Trust Line ===\n')
|
||||
const currencyCode = 'IOU'
|
||||
|
||||
const trustSetTx = {
|
||||
TransactionType: 'TrustSet',
|
||||
Account: creator.address,
|
||||
LimitAmount: {
|
||||
currency: currencyCode,
|
||||
issuer: issuer.address,
|
||||
value: '10000000'
|
||||
}
|
||||
}
|
||||
|
||||
xrpl.validate(trustSetTx)
|
||||
console.log(JSON.stringify(trustSetTx, null, 2))
|
||||
|
||||
console.log(`\nSubmitting TrustSet transaction...`)
|
||||
const trustResponse = await client.submitAndWait(trustSetTx, {
|
||||
wallet: creator,
|
||||
autofill: true
|
||||
})
|
||||
if (trustResponse.result.meta.TransactionResult !== 'tesSUCCESS') {
|
||||
console.error(`TrustSet failed: ${trustResponse.result.meta.TransactionResult}`)
|
||||
await client.disconnect()
|
||||
process.exit(1)
|
||||
}
|
||||
console.log('Trust line successfully created for "IOU" tokens.')
|
||||
|
||||
// Issuer sends IOU tokens to creator ----------------------
|
||||
console.log('\n=== Issuer Sending IOU Tokens to Escrow Creator ===\n')
|
||||
const iouPaymentTx = {
|
||||
TransactionType: 'Payment',
|
||||
Account: issuer.address,
|
||||
Destination: creator.address,
|
||||
Amount: {
|
||||
currency: currencyCode,
|
||||
value: '5000',
|
||||
issuer: issuer.address
|
||||
}
|
||||
}
|
||||
|
||||
xrpl.validate(iouPaymentTx)
|
||||
console.log(JSON.stringify(iouPaymentTx, null, 2))
|
||||
|
||||
console.log(`\nSubmitting Trust Line Token payment transaction...`)
|
||||
const iouPayResponse = await client.submitAndWait(iouPaymentTx, {
|
||||
wallet: issuer,
|
||||
autofill: true
|
||||
})
|
||||
if (iouPayResponse.result.meta.TransactionResult !== 'tesSUCCESS') {
|
||||
console.error(`Trust Line Token payment failed: ${iouPayResponse.result.meta.TransactionResult}`)
|
||||
await client.disconnect()
|
||||
process.exit(1)
|
||||
}
|
||||
console.log(`Successfully sent 5000 ${currencyCode} tokens.`)
|
||||
|
||||
// Escrow Creator creates a timed trust line token escrow ----------------------
|
||||
console.log('\n=== Creating Timed Trust Line Token Escrow ===\n')
|
||||
const delay = 10 // seconds
|
||||
const now = new Date()
|
||||
const finishAfter = new Date(now.getTime() + delay * 1000)
|
||||
const finishAfterRippleTime = xrpl.isoTimeToRippleTime(finishAfter.toISOString())
|
||||
console.log(`Escrow will mature after: ${finishAfter.toLocaleString()}\n`)
|
||||
|
||||
const iouCancelAfter = new Date(now.getTime() + 300 * 1000)
|
||||
const iouCancelAfterRippleTime = xrpl.isoTimeToRippleTime(iouCancelAfter.toISOString())
|
||||
|
||||
const iouEscrowCreateTx = {
|
||||
TransactionType: 'EscrowCreate',
|
||||
Account: creator.address,
|
||||
Destination: issuer.address,
|
||||
Amount: {
|
||||
currency: currencyCode,
|
||||
value: '1000',
|
||||
issuer: issuer.address
|
||||
},
|
||||
FinishAfter: finishAfterRippleTime,
|
||||
CancelAfter: iouCancelAfterRippleTime
|
||||
}
|
||||
|
||||
xrpl.validate(iouEscrowCreateTx)
|
||||
console.log(JSON.stringify(iouEscrowCreateTx, null, 2))
|
||||
|
||||
console.log(`\nSubmitting Trust Line Token EscrowCreate transaction...`)
|
||||
const iouEscrowResponse = await client.submitAndWait(iouEscrowCreateTx, {
|
||||
wallet: creator,
|
||||
autofill: true
|
||||
})
|
||||
if (iouEscrowResponse.result.meta.TransactionResult !== 'tesSUCCESS') {
|
||||
console.error(`Trust Line Token EscrowCreate failed: ${iouEscrowResponse.result.meta.TransactionResult}`)
|
||||
await client.disconnect()
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
// Save the sequence number to identify the escrow later
|
||||
const iouEscrowSeq = iouEscrowResponse.result.tx_json.Sequence
|
||||
console.log(`Trust Line Token escrow created. Sequence: ${iouEscrowSeq}`)
|
||||
|
||||
// Wait for the escrow to mature, then finish it --------------------
|
||||
console.log(`\n=== Waiting For Timed Trust Line Token Escrow to Mature ===\n`)
|
||||
|
||||
// Sleep function to countdown delay until escrow matures
|
||||
function sleep (delayInSeconds) {
|
||||
return new Promise((resolve) => setTimeout(resolve, delayInSeconds * 1000))
|
||||
}
|
||||
for (let i = delay; i >= 0; i--) {
|
||||
process.stdout.write(`\rWaiting for escrow to mature... ${i}s remaining...`)
|
||||
await sleep(1)
|
||||
}
|
||||
console.log('\rWaiting for escrow to mature... done. ')
|
||||
|
||||
// Confirm latest validated ledger close time is after the FinishAfter time
|
||||
let escrowReady = false
|
||||
while (!escrowReady) {
|
||||
const validatedLedger = await client.request({
|
||||
command: 'ledger',
|
||||
ledger_index: 'validated'
|
||||
})
|
||||
const ledgerCloseTime = validatedLedger.result.ledger.close_time
|
||||
console.log(`Latest validated ledger closed at: ${new Date(xrpl.rippleTimeToISOTime(ledgerCloseTime)).toLocaleString()}`)
|
||||
if (ledgerCloseTime > finishAfterRippleTime) {
|
||||
escrowReady = true
|
||||
console.log('Escrow confirmed ready to finish.')
|
||||
} else {
|
||||
let timeDifference = finishAfterRippleTime - ledgerCloseTime
|
||||
if (timeDifference === 0) { timeDifference = 1 }
|
||||
console.log(`Escrow needs to wait another ${timeDifference}s.`)
|
||||
await sleep(timeDifference)
|
||||
}
|
||||
}
|
||||
|
||||
// Finish the timed trust line token escrow --------------------
|
||||
console.log('\n=== Finishing Timed Trust Line Token Escrow ===\n')
|
||||
const iouEscrowFinishTx = {
|
||||
TransactionType: 'EscrowFinish',
|
||||
Account: creator.address,
|
||||
Owner: creator.address,
|
||||
OfferSequence: iouEscrowSeq
|
||||
}
|
||||
|
||||
xrpl.validate(iouEscrowFinishTx)
|
||||
console.log(JSON.stringify(iouEscrowFinishTx, null, 2))
|
||||
|
||||
console.log(`\nSubmitting EscrowFinish transaction...`)
|
||||
const iouFinishResponse = await client.submitAndWait(iouEscrowFinishTx, {
|
||||
wallet: creator,
|
||||
autofill: true
|
||||
})
|
||||
if (iouFinishResponse.result.meta.TransactionResult !== 'tesSUCCESS') {
|
||||
console.error(`Trust Line Token EscrowFinish failed: ${iouFinishResponse.result.meta.TransactionResult}`)
|
||||
await client.disconnect()
|
||||
process.exit(1)
|
||||
}
|
||||
console.log(`Timed Trust Line Token escrow finished successfully: https://testnet.xrpl.org/transactions/${iouFinishResponse.result.hash}`)
|
||||
|
||||
await client.disconnect()
|
||||
@@ -22,187 +22,6 @@ python send_timed_escrow.py
|
||||
python send_conditional_escrow.py
|
||||
```
|
||||
|
||||
## Send Fungible Token Escrow
|
||||
|
||||
```sh
|
||||
python send_fungible_token_escrow.py
|
||||
```
|
||||
|
||||
The script issues an MPT and Trust Line Token, setting up both to be escrowable. It then creates and finishes a conditional escrow with the MPT and a timed escrow with the Trust Line Token.
|
||||
|
||||
```sh
|
||||
=== Funding Accounts ===
|
||||
|
||||
Attempting to fund address rQBByeTLvRVQy9GLsqvsnczMB3QZ7b7gs2
|
||||
Faucet fund successful.
|
||||
Attempting to fund address rBkkT1Q3E3bm5tM5D5YazgX8cpq3a2V6zU
|
||||
Faucet fund successful.
|
||||
Issuer: rQBByeTLvRVQy9GLsqvsnczMB3QZ7b7gs2
|
||||
Escrow Creator: rBkkT1Q3E3bm5tM5D5YazgX8cpq3a2V6zU
|
||||
|
||||
=== Creating MPT ===
|
||||
|
||||
{
|
||||
"Account": "rQBByeTLvRVQy9GLsqvsnczMB3QZ7b7gs2",
|
||||
"TransactionType": "MPTokenIssuanceCreate",
|
||||
"Flags": 8,
|
||||
"SigningPubKey": "",
|
||||
"MaximumAmount": "1000000"
|
||||
}
|
||||
|
||||
Submitting MPTokenIssuanceCreate transaction...
|
||||
MPT created: 00F7705DFE38372A760229755F9E4F5EADE06F2CE36BDA18
|
||||
|
||||
=== Escrow Creator Authorizing MPT ===
|
||||
|
||||
{
|
||||
"Account": "rBkkT1Q3E3bm5tM5D5YazgX8cpq3a2V6zU",
|
||||
"TransactionType": "MPTokenAuthorize",
|
||||
"SigningPubKey": "",
|
||||
"MPTokenIssuanceID": "00F7705DFE38372A760229755F9E4F5EADE06F2CE36BDA18"
|
||||
}
|
||||
|
||||
Submitting MPTokenAuthorize transaction...
|
||||
Escrow Creator authorized for MPT.
|
||||
|
||||
=== Issuer Sending MPTs to Escrow Creator ===
|
||||
|
||||
{
|
||||
"Account": "rQBByeTLvRVQy9GLsqvsnczMB3QZ7b7gs2",
|
||||
"TransactionType": "Payment",
|
||||
"SigningPubKey": "",
|
||||
"Amount": {
|
||||
"mpt_issuance_id": "00F7705DFE38372A760229755F9E4F5EADE06F2CE36BDA18",
|
||||
"value": "5000"
|
||||
},
|
||||
"Destination": "rBkkT1Q3E3bm5tM5D5YazgX8cpq3a2V6zU"
|
||||
}
|
||||
|
||||
Submitting MPT Payment transaction...
|
||||
Successfully sent 5000 MPTs to Escrow Creator.
|
||||
|
||||
=== Creating Conditional MPT Escrow ===
|
||||
|
||||
Condition: A02580202959C2DFA17829F23F8A7F2F3A81FE73F9E964A56810A250CB836DE1AB851E47810120
|
||||
Fulfillment: A022802079204EBCCCF4816441F0D4F7B15E7003A757675FC90691107AB770044B07697B
|
||||
|
||||
{
|
||||
"Account": "rBkkT1Q3E3bm5tM5D5YazgX8cpq3a2V6zU",
|
||||
"TransactionType": "EscrowCreate",
|
||||
"SigningPubKey": "",
|
||||
"Amount": {
|
||||
"mpt_issuance_id": "00F7705DFE38372A760229755F9E4F5EADE06F2CE36BDA18",
|
||||
"value": "1000"
|
||||
},
|
||||
"Destination": "rQBByeTLvRVQy9GLsqvsnczMB3QZ7b7gs2",
|
||||
"CancelAfter": 828514495,
|
||||
"Condition": "A02580202959C2DFA17829F23F8A7F2F3A81FE73F9E964A56810A250CB836DE1AB851E47810120"
|
||||
}
|
||||
|
||||
Submitting MPT EscrowCreate transaction...
|
||||
Conditional MPT escrow created. Sequence: 16216160
|
||||
|
||||
=== Finishing Conditional MPT Escrow ===
|
||||
|
||||
{
|
||||
"Account": "rBkkT1Q3E3bm5tM5D5YazgX8cpq3a2V6zU",
|
||||
"TransactionType": "EscrowFinish",
|
||||
"SigningPubKey": "",
|
||||
"Owner": "rBkkT1Q3E3bm5tM5D5YazgX8cpq3a2V6zU",
|
||||
"OfferSequence": 16216160,
|
||||
"Condition": "A02580202959C2DFA17829F23F8A7F2F3A81FE73F9E964A56810A250CB836DE1AB851E47810120",
|
||||
"Fulfillment": "A022802079204EBCCCF4816441F0D4F7B15E7003A757675FC90691107AB770044B07697B"
|
||||
}
|
||||
|
||||
Submitting EscrowFinish transaction...
|
||||
Conditional MPT escrow finished successfully: https://testnet.xrpl.org/transactions/4FE4B0AD6FD9D8CD968F5AFD43C3E1F2180C40C3A20DE7416B1E16069D2340DD
|
||||
|
||||
=== Enabling Trust Line Token Escrows on Issuer ===
|
||||
|
||||
{
|
||||
"Account": "rQBByeTLvRVQy9GLsqvsnczMB3QZ7b7gs2",
|
||||
"TransactionType": "AccountSet",
|
||||
"SigningPubKey": "",
|
||||
"SetFlag": 17
|
||||
}
|
||||
|
||||
Submitting AccountSet transaction...
|
||||
Trust line token escrows enabled by issuer.
|
||||
|
||||
=== Setting Up Trust Line ===
|
||||
|
||||
{
|
||||
"Account": "rBkkT1Q3E3bm5tM5D5YazgX8cpq3a2V6zU",
|
||||
"TransactionType": "TrustSet",
|
||||
"SigningPubKey": "",
|
||||
"LimitAmount": {
|
||||
"currency": "IOU",
|
||||
"issuer": "rQBByeTLvRVQy9GLsqvsnczMB3QZ7b7gs2",
|
||||
"value": "10000000"
|
||||
}
|
||||
}
|
||||
|
||||
Submitting TrustSet transaction...
|
||||
Trust line successfully created for "IOU" tokens.
|
||||
|
||||
=== Issuer Sending IOU Tokens to Escrow Creator ===
|
||||
|
||||
{
|
||||
"Account": "rQBByeTLvRVQy9GLsqvsnczMB3QZ7b7gs2",
|
||||
"TransactionType": "Payment",
|
||||
"SigningPubKey": "",
|
||||
"Amount": {
|
||||
"currency": "IOU",
|
||||
"issuer": "rQBByeTLvRVQy9GLsqvsnczMB3QZ7b7gs2",
|
||||
"value": "5000"
|
||||
},
|
||||
"Destination": "rBkkT1Q3E3bm5tM5D5YazgX8cpq3a2V6zU"
|
||||
}
|
||||
|
||||
Submitting Trust Line Token payment transaction...
|
||||
Successfully sent 5000 IOU tokens.
|
||||
|
||||
=== Creating Timed Trust Line Token Escrow ===
|
||||
|
||||
Escrow will mature after: 04/02/2026, 11:50:39 PM
|
||||
|
||||
{
|
||||
"Account": "rBkkT1Q3E3bm5tM5D5YazgX8cpq3a2V6zU",
|
||||
"TransactionType": "EscrowCreate",
|
||||
"SigningPubKey": "",
|
||||
"Amount": {
|
||||
"currency": "IOU",
|
||||
"issuer": "rQBByeTLvRVQy9GLsqvsnczMB3QZ7b7gs2",
|
||||
"value": "1000"
|
||||
},
|
||||
"Destination": "rQBByeTLvRVQy9GLsqvsnczMB3QZ7b7gs2",
|
||||
"CancelAfter": 828514529,
|
||||
"FinishAfter": 828514239
|
||||
}
|
||||
|
||||
Submitting Trust Line Token EscrowCreate transaction...
|
||||
Trust Line Token escrow created. Sequence: 16216163
|
||||
|
||||
=== Waiting For Timed Trust Line Token Escrow to Mature ===
|
||||
|
||||
Waiting for escrow to mature... done.
|
||||
Latest validated ledger closed at: 04/02/2026, 11:50:42 PM
|
||||
Escrow confirmed ready to finish.
|
||||
|
||||
=== Finishing Timed Trust Line Token Escrow ===
|
||||
|
||||
{
|
||||
"Account": "rBkkT1Q3E3bm5tM5D5YazgX8cpq3a2V6zU",
|
||||
"TransactionType": "EscrowFinish",
|
||||
"SigningPubKey": "",
|
||||
"Owner": "rBkkT1Q3E3bm5tM5D5YazgX8cpq3a2V6zU",
|
||||
"OfferSequence": 16216163
|
||||
}
|
||||
|
||||
Submitting EscrowFinish transaction...
|
||||
Timed Trust Line Token escrow finished successfully: https://testnet.xrpl.org/transactions/F3FCFE9D0E9A0A7CC6FA804526A509532833AEAD4C7A7BF1978194F4F1CCDED4
|
||||
```
|
||||
|
||||
## List Escrows
|
||||
|
||||
```sh
|
||||
|
||||
@@ -1,301 +0,0 @@
|
||||
# This example demonstrates how to create escrows that hold fungible tokens.
|
||||
# It covers MPTs and Trust Line Tokens, and uses conditional and timed escrows.
|
||||
|
||||
import json
|
||||
from datetime import datetime, timedelta, UTC
|
||||
from os import urandom
|
||||
from time import sleep
|
||||
|
||||
from cryptoconditions import PreimageSha256
|
||||
from xrpl.clients import JsonRpcClient
|
||||
from xrpl.models import (
|
||||
AccountSet,
|
||||
EscrowCreate,
|
||||
EscrowFinish,
|
||||
MPTokenAuthorize,
|
||||
MPTokenIssuanceCreate,
|
||||
Payment,
|
||||
TrustSet,
|
||||
)
|
||||
from xrpl.models.amounts import IssuedCurrencyAmount, MPTAmount
|
||||
from xrpl.models.requests import Ledger
|
||||
from xrpl.models.transactions.account_set import AccountSetAsfFlag
|
||||
from xrpl.models.transactions.mptoken_issuance_create import MPTokenIssuanceCreateFlag
|
||||
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
|
||||
|
||||
client = JsonRpcClient("https://s.altnet.rippletest.net:51234")
|
||||
|
||||
# Fund an issuer account and an escrow creator account ----------------------
|
||||
print("\n=== Funding Accounts ===\n")
|
||||
issuer = generate_faucet_wallet(client, debug=True)
|
||||
creator = generate_faucet_wallet(client, debug=True)
|
||||
print(f"Issuer: {issuer.address}")
|
||||
print(f"Escrow Creator: {creator.address}")
|
||||
|
||||
# ====== Conditional MPT Escrow ======
|
||||
|
||||
# Issuer creates an MPT ----------------------
|
||||
print("\n=== Creating MPT ===\n")
|
||||
mpt_create_tx = MPTokenIssuanceCreate(
|
||||
account=issuer.address,
|
||||
maximum_amount="1000000",
|
||||
flags=MPTokenIssuanceCreateFlag.TF_MPT_CAN_ESCROW,
|
||||
)
|
||||
|
||||
print(json.dumps(mpt_create_tx.to_xrpl(), indent=2))
|
||||
|
||||
# Submit, sign, and wait for validation
|
||||
print("\nSubmitting MPTokenIssuanceCreate transaction...")
|
||||
mpt_create_response = submit_and_wait(mpt_create_tx, client, issuer)
|
||||
|
||||
if mpt_create_response.result["meta"]["TransactionResult"] != "tesSUCCESS":
|
||||
print(f"MPTokenIssuanceCreate failed: {mpt_create_response.result['meta']['TransactionResult']}")
|
||||
exit(1)
|
||||
|
||||
# Extract the MPT issuance ID from the transaction result
|
||||
mpt_issuance_id = mpt_create_response.result["meta"]["mpt_issuance_id"]
|
||||
print(f"MPT created: {mpt_issuance_id}")
|
||||
|
||||
# Escrow Creator authorizes the MPT ----------------------
|
||||
print("\n=== Escrow Creator Authorizing MPT ===\n")
|
||||
mpt_auth_tx = MPTokenAuthorize(
|
||||
account=creator.address,
|
||||
mptoken_issuance_id=mpt_issuance_id,
|
||||
)
|
||||
|
||||
print(json.dumps(mpt_auth_tx.to_xrpl(), indent=2))
|
||||
|
||||
print("\nSubmitting MPTokenAuthorize transaction...")
|
||||
mpt_auth_response = submit_and_wait(mpt_auth_tx, client, creator)
|
||||
|
||||
if mpt_auth_response.result["meta"]["TransactionResult"] != "tesSUCCESS":
|
||||
print(f"MPTokenAuthorize failed: {mpt_auth_response.result['meta']['TransactionResult']}")
|
||||
exit(1)
|
||||
print("Escrow Creator authorized for MPT.")
|
||||
|
||||
# Issuer sends MPTs to escrow creator ----------------------
|
||||
print("\n=== Issuer Sending MPTs to Escrow Creator ===\n")
|
||||
mpt_payment_tx = Payment(
|
||||
account=issuer.address,
|
||||
destination=creator.address,
|
||||
amount=MPTAmount(
|
||||
mpt_issuance_id=mpt_issuance_id,
|
||||
value="5000",
|
||||
),
|
||||
)
|
||||
|
||||
print(json.dumps(mpt_payment_tx.to_xrpl(), indent=2))
|
||||
|
||||
print("\nSubmitting MPT Payment transaction...")
|
||||
mpt_payment_response = submit_and_wait(mpt_payment_tx, client, issuer)
|
||||
|
||||
if mpt_payment_response.result["meta"]["TransactionResult"] != "tesSUCCESS":
|
||||
print(f"MPT Payment failed: {mpt_payment_response.result['meta']['TransactionResult']}")
|
||||
exit(1)
|
||||
print("Successfully sent 5000 MPTs to Escrow Creator.")
|
||||
|
||||
# Escrow Creator creates a conditional MPT escrow ----------------------
|
||||
print("\n=== Creating Conditional MPT Escrow ===\n")
|
||||
|
||||
# Generate crypto-condition
|
||||
preimage = urandom(32)
|
||||
fulfillment = PreimageSha256(preimage=preimage)
|
||||
fulfillment_hex = fulfillment.serialize_binary().hex().upper()
|
||||
condition_hex = fulfillment.condition_binary.hex().upper()
|
||||
print(f"Condition: {condition_hex}")
|
||||
print(f"Fulfillment: {fulfillment_hex}\n")
|
||||
|
||||
# Set expiration (300 seconds from now)
|
||||
cancel_after = datetime.now(tz=UTC) + timedelta(seconds=300)
|
||||
cancel_after_ripple_time = datetime_to_ripple_time(cancel_after)
|
||||
|
||||
mpt_escrow_create_tx = EscrowCreate(
|
||||
account=creator.address,
|
||||
destination=issuer.address,
|
||||
amount=MPTAmount(
|
||||
mpt_issuance_id=mpt_issuance_id,
|
||||
value="1000",
|
||||
),
|
||||
condition=condition_hex,
|
||||
cancel_after=cancel_after_ripple_time, # Fungible token escrows require a cancel_after time
|
||||
)
|
||||
|
||||
print(json.dumps(mpt_escrow_create_tx.to_xrpl(), indent=2))
|
||||
|
||||
print("\nSubmitting MPT EscrowCreate transaction...")
|
||||
mpt_escrow_response = submit_and_wait(mpt_escrow_create_tx, client, creator)
|
||||
|
||||
if mpt_escrow_response.result["meta"]["TransactionResult"] != "tesSUCCESS":
|
||||
print(f"MPT EscrowCreate failed: {mpt_escrow_response.result['meta']['TransactionResult']}")
|
||||
exit(1)
|
||||
|
||||
# Save the sequence number to identify the escrow later
|
||||
mpt_escrow_seq = mpt_escrow_response.result["tx_json"]["Sequence"]
|
||||
print(f"Conditional MPT escrow created. Sequence: {mpt_escrow_seq}")
|
||||
|
||||
# Finish the conditional MPT escrow with the fulfillment ----------------------
|
||||
print("\n=== Finishing Conditional MPT Escrow ===\n")
|
||||
mpt_escrow_finish_tx = EscrowFinish(
|
||||
account=creator.address,
|
||||
owner=creator.address,
|
||||
offer_sequence=mpt_escrow_seq,
|
||||
condition=condition_hex,
|
||||
fulfillment=fulfillment_hex,
|
||||
)
|
||||
|
||||
print(json.dumps(mpt_escrow_finish_tx.to_xrpl(), indent=2))
|
||||
|
||||
print("\nSubmitting EscrowFinish transaction...")
|
||||
mpt_finish_response = submit_and_wait(mpt_escrow_finish_tx, client, creator)
|
||||
|
||||
if mpt_finish_response.result["meta"]["TransactionResult"] != "tesSUCCESS":
|
||||
print(f"MPT EscrowFinish failed: {mpt_finish_response.result['meta']['TransactionResult']}")
|
||||
exit(1)
|
||||
print(f"Conditional MPT escrow finished successfully: https://testnet.xrpl.org/transactions/{mpt_finish_response.result['hash']}")
|
||||
|
||||
# ====== Timed Trust Line Token Escrow ======
|
||||
|
||||
# Enable trust line token escrows on the issuer ----------------------
|
||||
print("\n=== Enabling Trust Line Token Escrows on Issuer ===\n")
|
||||
account_set_tx = AccountSet(
|
||||
account=issuer.address,
|
||||
set_flag=AccountSetAsfFlag.ASF_ALLOW_TRUSTLINE_LOCKING,
|
||||
)
|
||||
|
||||
print(json.dumps(account_set_tx.to_xrpl(), indent=2))
|
||||
|
||||
print("\nSubmitting AccountSet transaction...")
|
||||
account_set_response = submit_and_wait(account_set_tx, client, issuer)
|
||||
|
||||
if account_set_response.result["meta"]["TransactionResult"] != "tesSUCCESS":
|
||||
print(f"AccountSet failed: {account_set_response.result['meta']['TransactionResult']}")
|
||||
exit(1)
|
||||
print("Trust line token escrows enabled by issuer.")
|
||||
|
||||
# Escrow Creator sets up a trust line to the issuer ----------------------
|
||||
print("\n=== Setting Up Trust Line ===\n")
|
||||
currency_code = "IOU"
|
||||
|
||||
trust_set_tx = TrustSet(
|
||||
account=creator.address,
|
||||
limit_amount=IssuedCurrencyAmount(
|
||||
currency=currency_code,
|
||||
issuer=issuer.address,
|
||||
value="10000000",
|
||||
),
|
||||
)
|
||||
|
||||
print(json.dumps(trust_set_tx.to_xrpl(), indent=2))
|
||||
|
||||
print("\nSubmitting TrustSet transaction...")
|
||||
trust_response = submit_and_wait(trust_set_tx, client, creator)
|
||||
|
||||
if trust_response.result["meta"]["TransactionResult"] != "tesSUCCESS":
|
||||
print(f"TrustSet failed: {trust_response.result['meta']['TransactionResult']}")
|
||||
exit(1)
|
||||
print('Trust line successfully created for "IOU" tokens.')
|
||||
|
||||
# Issuer sends IOU tokens to creator ----------------------
|
||||
print("\n=== Issuer Sending IOU Tokens to Escrow Creator ===\n")
|
||||
iou_payment_tx = Payment(
|
||||
account=issuer.address,
|
||||
destination=creator.address,
|
||||
amount=IssuedCurrencyAmount(
|
||||
currency=currency_code,
|
||||
value="5000",
|
||||
issuer=issuer.address,
|
||||
),
|
||||
)
|
||||
|
||||
print(json.dumps(iou_payment_tx.to_xrpl(), indent=2))
|
||||
|
||||
print("\nSubmitting Trust Line Token payment transaction...")
|
||||
iou_pay_response = submit_and_wait(iou_payment_tx, client, issuer)
|
||||
|
||||
if iou_pay_response.result["meta"]["TransactionResult"] != "tesSUCCESS":
|
||||
print(f"Trust Line Token payment failed: {iou_pay_response.result['meta']['TransactionResult']}")
|
||||
exit(1)
|
||||
print(f"Successfully sent 5000 {currency_code} tokens.")
|
||||
|
||||
# Escrow Creator creates a timed trust line token escrow ----------------------
|
||||
print("\n=== Creating Timed Trust Line Token Escrow ===\n")
|
||||
delay = 10 # seconds
|
||||
now = datetime.now(tz=UTC)
|
||||
finish_after = now + timedelta(seconds=delay)
|
||||
finish_after_ripple_time = datetime_to_ripple_time(finish_after)
|
||||
mature_time = finish_after.astimezone().strftime("%m/%d/%Y, %I:%M:%S %p")
|
||||
print(f"Escrow will mature after: {mature_time}\n")
|
||||
|
||||
iou_cancel_after = now + timedelta(seconds=300)
|
||||
iou_cancel_after_ripple_time = datetime_to_ripple_time(iou_cancel_after)
|
||||
|
||||
iou_escrow_create_tx = EscrowCreate(
|
||||
account=creator.address,
|
||||
destination=issuer.address,
|
||||
amount=IssuedCurrencyAmount(
|
||||
currency=currency_code,
|
||||
value="1000",
|
||||
issuer=issuer.address,
|
||||
),
|
||||
finish_after=finish_after_ripple_time,
|
||||
cancel_after=iou_cancel_after_ripple_time,
|
||||
)
|
||||
|
||||
print(json.dumps(iou_escrow_create_tx.to_xrpl(), indent=2))
|
||||
|
||||
print("\nSubmitting Trust Line Token EscrowCreate transaction...")
|
||||
iou_escrow_response = submit_and_wait(iou_escrow_create_tx, client, creator)
|
||||
|
||||
if iou_escrow_response.result["meta"]["TransactionResult"] != "tesSUCCESS":
|
||||
print(f"Trust Line Token EscrowCreate failed: {iou_escrow_response.result['meta']['TransactionResult']}")
|
||||
exit(1)
|
||||
|
||||
# Save the sequence number to identify the escrow later
|
||||
iou_escrow_seq = iou_escrow_response.result["tx_json"]["Sequence"]
|
||||
print(f"Trust Line Token escrow created. Sequence: {iou_escrow_seq}")
|
||||
|
||||
# Wait for the escrow to mature, then finish it --------------------
|
||||
print("\n=== Waiting For Timed Trust Line Token Escrow to Mature ===\n")
|
||||
|
||||
# Countdown delay until escrow matures
|
||||
for i in range(delay, -1, -1):
|
||||
print(f"Waiting for escrow to mature... {i}s remaining...", end="\r", flush=True)
|
||||
sleep(1)
|
||||
print("Waiting for escrow to mature... done. ")
|
||||
|
||||
# Confirm latest validated ledger close time is after the finish_after time
|
||||
escrow_ready = False
|
||||
while not escrow_ready:
|
||||
validated_ledger = client.request(Ledger(ledger_index="validated"))
|
||||
ledger_close_time = validated_ledger.result["ledger"]["close_time"]
|
||||
ledger_close_local = ripple_time_to_datetime(ledger_close_time).astimezone().strftime("%m/%d/%Y, %I:%M:%S %p")
|
||||
print(f"Latest validated ledger closed at: {ledger_close_local}")
|
||||
if ledger_close_time > finish_after_ripple_time:
|
||||
escrow_ready = True
|
||||
print("Escrow confirmed ready to finish.")
|
||||
else:
|
||||
time_difference = finish_after_ripple_time - ledger_close_time
|
||||
if time_difference == 0:
|
||||
time_difference = 1
|
||||
print(f"Escrow needs to wait another {time_difference}s.")
|
||||
sleep(time_difference)
|
||||
|
||||
# Finish the timed trust line token escrow --------------------
|
||||
print("\n=== Finishing Timed Trust Line Token Escrow ===\n")
|
||||
iou_escrow_finish_tx = EscrowFinish(
|
||||
account=creator.address,
|
||||
owner=creator.address,
|
||||
offer_sequence=iou_escrow_seq,
|
||||
)
|
||||
|
||||
print(json.dumps(iou_escrow_finish_tx.to_xrpl(), indent=2))
|
||||
|
||||
print("\nSubmitting EscrowFinish transaction...")
|
||||
iou_finish_response = submit_and_wait(iou_escrow_finish_tx, client, creator)
|
||||
|
||||
if iou_finish_response.result["meta"]["TransactionResult"] != "tesSUCCESS":
|
||||
print(f"Trust Line Token EscrowFinish failed: {iou_finish_response.result['meta']['TransactionResult']}")
|
||||
exit(1)
|
||||
print(f"Timed Trust Line Token escrow finished successfully: https://testnet.xrpl.org/transactions/{iou_finish_response.result['hash']}")
|
||||
@@ -0,0 +1,150 @@
|
||||
---
|
||||
seo:
|
||||
description: Look up and calculate base and owner reserve requirements for an XRPL account.
|
||||
labels:
|
||||
- Accounts
|
||||
---
|
||||
# Calculate Account Reserves
|
||||
|
||||
This tutorial demonstrates how to look up and calculate the [reserve requirements](https://xrpl.org/docs/concepts/accounts/reserves) for an XRP Ledger account. Reserves are the minimum amount of XRP an account must hold based on its activity on the ledger.
|
||||
|
||||
## Goals
|
||||
|
||||
By the end of this tutorial, you should be able to:
|
||||
- Look up an account's current [base](https://xrpl.org/docs/concepts/accounts/reserves#base-reserve-and-owner-reserve) and incremental reserve values.
|
||||
- Determine an account's [owner reserve](https://xrpl.org/docs/concepts/accounts/reserves#owner-reserves).
|
||||
- Calculate an account's total reserve requirement.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
To complete this tutorial, you need:
|
||||
|
||||
- A basic understanding of the XRP Ledger.
|
||||
- An XRP Ledger [client library](https://xrpl.org/docs/references/client-libraries) set up.
|
||||
|
||||
## Source Code
|
||||
|
||||
You can find this tutorial's example source code in the [code samples section of this website's repository](https://github.com/XRPLF/xrpl-dev-portal/tree/master/_code-samples/calculate-reserves).
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Install dependencies
|
||||
|
||||
Install dependencies for your language from the code sample folder.
|
||||
|
||||
{% tabs %}
|
||||
{% tab label="JavaScript" %}
|
||||
|
||||
```bash
|
||||
npm install xrpl
|
||||
```
|
||||
{% /tab %}
|
||||
{% tab label="Python" %}
|
||||
|
||||
```bash
|
||||
pip install xrpl-py
|
||||
```
|
||||
{% /tab %}
|
||||
{% tab label="Go" %}
|
||||
|
||||
```bash
|
||||
go mod tidy
|
||||
```
|
||||
{% /tab %}
|
||||
{% tab label="Java" %}
|
||||
```bash
|
||||
mvn compile
|
||||
```
|
||||
{% /tab %}
|
||||
{% /tabs %}
|
||||
|
||||
### 2. Set up client
|
||||
|
||||
Import the XRPL library and create a client connection to a testnet server.
|
||||
|
||||
{% tabs %}
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/calculate-reserves/js/calculate_reserves.js" language="js" from="// Set up client" to="// Look up reserve values" /%}
|
||||
{% /tab %}
|
||||
{% tab label="Python" %}
|
||||
{% code-snippet file="/_code-samples/calculate-reserves/py/calculate_reserves.py" language="py" from="# Set up client" to="# Look up reserve values" /%}
|
||||
{% /tab %}
|
||||
{% tab label="Go" %}
|
||||
{% code-snippet file="/_code-samples/calculate-reserves/go/calculate_reserves.go" language="go" from="// Set up client" to="// Look up reserve values" /%}
|
||||
{% /tab %}
|
||||
{% tab label="Java" %}
|
||||
{% code-snippet file="/_code-samples/calculate-reserves/java/CalculateReserves.java" language="java" from="// Set up client" to="// Look up reserve values" /%}
|
||||
{% /tab %}
|
||||
{% /tabs %}
|
||||
|
||||
### 3. Look up reserve values
|
||||
|
||||
Retrieve the base and incremental reserve values using the [`server_info`](https://xrpl.org/docs/references/http-websocket-apis/public-api-methods/server-info-methods/server_info) or [`server_state`](https://xrpl.org/docs/references/http-websocket-apis/public-api-methods/server-info-methods/server_state) method. This example uses `server_info` to return values in decimal XRP instead of integer drops.
|
||||
|
||||
{% tabs %}
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/calculate-reserves/js/calculate_reserves.js" language="js" from="// Look up reserve values" to="// Look up owner count"/%}
|
||||
{% /tab %}
|
||||
{% tab label="Python" %}
|
||||
{% code-snippet file="/_code-samples/calculate-reserves/py/calculate_reserves.py" language="py" from="# Look up reserve values" to="# Look up owner count"/%}
|
||||
{% /tab %}
|
||||
{% tab label="Go" %}
|
||||
{% code-snippet file="/_code-samples/calculate-reserves/go/calculate_reserves.go" language="go" from="// Look up reserve values" to="// Look up owner count"/%}
|
||||
{% /tab %}
|
||||
{% tab label="Java" %}
|
||||
{% code-snippet file="/_code-samples/calculate-reserves/java/CalculateReserves.java" language="java" from="// Look up reserve values" to="// Look up owner count" /%}
|
||||
{% /tab %}
|
||||
{% /tabs %}
|
||||
|
||||
### 4. Determine owner reserve
|
||||
|
||||
Once you have the incremental reserve value, multiply that by the number of objects the account owns to determine the owner reserve. You can call [`account_info`](https://xrpl.org/docs/references/http-websocket-apis/public-api-methods/account-methods/account_info) and take `account_data.OwnerCount` to retrieve an account's total number of objects.
|
||||
|
||||
{% tabs %}
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/calculate-reserves/js/calculate_reserves.js" language="js" from="// Look up owner count" to="// Calculate total reserve"/%}
|
||||
{% /tab %}
|
||||
{% tab label="Python" %}
|
||||
{% code-snippet file="/_code-samples/calculate-reserves/py/calculate_reserves.py" language="py" from="# Look up owner count" to="# Calculate total reserve"/%}
|
||||
{% /tab %}
|
||||
{% tab label="Go" %}
|
||||
{% code-snippet file="/_code-samples/calculate-reserves/go/calculate_reserves.go" language="go" from="// Look up owner count" to="// Calculate total reserve" /%}
|
||||
{% /tab %}
|
||||
{% tab label="Java" %}
|
||||
{% code-snippet file="/_code-samples/calculate-reserves/java/CalculateReserves.java" language="java" from="// Look up owner count" to="// Calculate total reserve" /%}
|
||||
{% /tab %}
|
||||
{% /tabs %}
|
||||
|
||||
### 5. Calculate total reserve
|
||||
|
||||
Use the following formula to calculate an account's total reserve requirement:
|
||||
|
||||
`total reserve = reserve_base_xrp + (OwnerCount × reserve_inc_xrp)`
|
||||
|
||||
{% tabs %}
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/calculate-reserves/js/calculate_reserves.js" language="js" from="// Calculate total reserve"/%}
|
||||
{% /tab %}
|
||||
{% tab label="Python" %}
|
||||
{% code-snippet file="/_code-samples/calculate-reserves/py/calculate_reserves.py" language="py" from="# Calculate total reserve"/%}
|
||||
{% /tab %}
|
||||
{% tab label="Go" %}
|
||||
{% code-snippet file="/_code-samples/calculate-reserves/go/calculate_reserves.go" language="go" from="// Calculate total reserve" /%}
|
||||
{% /tab %}
|
||||
{% tab label="Java" %}
|
||||
{% code-snippet file="/_code-samples/calculate-reserves/java/CalculateReserves.java" language="java" from="// Calculate total reserve" /%}
|
||||
{% /tab %}
|
||||
{% /tabs %}
|
||||
|
||||
## See Also
|
||||
|
||||
Concepts:
|
||||
- [Reserves](https://xrpl.org/docs/concepts/accounts/reserves)
|
||||
|
||||
Tutorials:
|
||||
- [Calculate and Display the Reserve Requirement (Python)](https://xrpl.org/docs/tutorials/sample-apps/build-a-desktop-wallet-in-python#3-display-an-account)
|
||||
|
||||
References:
|
||||
- [server_info](https://xrpl.org/docs/references/http-websocket-apis/public-api-methods/server-info-methods/server_info)
|
||||
- [server_state](https://xrpl.org/docs/references/http-websocket-apis/public-api-methods/server-info-methods/server_state)
|
||||
- [account_info](https://xrpl.org/docs/references/http-websocket-apis/public-api-methods/account-methods/account_info)
|
||||
@@ -1,301 +0,0 @@
|
||||
---
|
||||
seo:
|
||||
description: Create and finish escrows that hold fungible tokens (MPTs and trust line tokens) on the XRP Ledger.
|
||||
metadata:
|
||||
indexPage: true
|
||||
labels:
|
||||
- Escrow
|
||||
---
|
||||
|
||||
# Send Fungible Token Escrows
|
||||
|
||||
This tutorial shows you how to create and finish escrows that hold fungible tokens on the XRP Ledger. It covers two types of fungible token escrows:
|
||||
|
||||
- **Conditional MPT escrow**: An escrow holding [Multi-Purpose Tokens](../../concepts/tokens/fungible-tokens/multi-purpose-tokens.md) that is released when a crypto-condition is fulfilled.
|
||||
- **Timed trust line token escrow**: An escrow holding [trust line tokens](../../concepts/tokens/fungible-tokens/trust-line-tokens.md) that is released after a specified time.
|
||||
|
||||
{% admonition type="info" name="Note" %}
|
||||
Though this tutorial covers these two specific scenarios, both fungible token types can be used in either conditional or timed escrows.
|
||||
{% /admonition %}
|
||||
|
||||
{% amendment-disclaimer name="TokenEscrow" /%}
|
||||
|
||||
|
||||
## Goals
|
||||
|
||||
By the end of this tutorial, you will be able to:
|
||||
|
||||
- Issue an MPT with escrow support enabled.
|
||||
- Create and finish a conditional escrow that holds MPTs.
|
||||
- Enable trust line token escrows on an issuer account.
|
||||
- Create and finish a timed escrow that holds trust line tokens.
|
||||
|
||||
|
||||
## Prerequisites
|
||||
|
||||
To complete this tutorial, you should:
|
||||
|
||||
- Have a basic understanding of the XRP Ledger.
|
||||
- Have an XRP Ledger client library installed. This page provides examples for the following:
|
||||
- **JavaScript** with the [xrpl.js library][]. See [Get Started Using JavaScript][] for setup steps.
|
||||
- **Python** with the [xrpl-py library][]. See [Get Started Using Python][] for setup steps.
|
||||
- **Go** with the [xrpl-go library][]. See [Get Started Using Go][] for setup steps.
|
||||
|
||||
|
||||
## Source Code
|
||||
|
||||
You can find the complete source code for this tutorial's examples in the {% repo-link path="_code-samples/escrow/" %}code samples section of this website's repository{% /repo-link %}.
|
||||
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Install dependencies
|
||||
|
||||
{% tabs %}
|
||||
{% tab label="JavaScript" %}
|
||||
From the code sample folder, use `npm` to install dependencies.
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
{% /tab %}
|
||||
{% tab label="Python" %}
|
||||
From the code sample folder, set up a virtual environment and use `pip` to install dependencies.
|
||||
|
||||
```bash
|
||||
python3 -m venv .venv
|
||||
source .venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
{% /tab %}
|
||||
{% tab label="Go" %}
|
||||
From the code sample folder, use `go` to install dependencies.
|
||||
|
||||
```bash
|
||||
go mod tidy
|
||||
```
|
||||
{% /tab %}
|
||||
{% /tabs %}
|
||||
|
||||
### 2. Set up client and fund accounts
|
||||
|
||||
Import the necessary libraries, instantiate a client to connect to the XRPL, and fund two new accounts (**Issuer** and **Escrow Creator**). This example imports:
|
||||
|
||||
{% tabs %}
|
||||
{% tab label="JavaScript" %}
|
||||
- `xrpl`: Used for XRPL client connection, transaction submission, and wallet handling.
|
||||
- `five-bells-condition` and `crypto`: Used to generate a crypto-condition.
|
||||
|
||||
{% code-snippet file="/_code-samples/escrow/js/sendFungibleTokenEscrow.js" language="js" before="// ====== Conditional MPT Escrow ======" /%}
|
||||
{% /tab %}
|
||||
{% tab label="Python" %}
|
||||
- `xrpl`: Used for XRPL client connection, transaction submission, and wallet handling.
|
||||
- `json`: Used for loading and formatting JSON data.
|
||||
- `os` and `cryptoconditions`: Used to generate a crypto-condition.
|
||||
- `datetime` and `time`: Used for time calculations.
|
||||
|
||||
{% code-snippet file="/_code-samples/escrow/py/send_fungible_token_escrow.py" language="py" before="# ====== Conditional MPT Escrow ======" /%}
|
||||
{% /tab %}
|
||||
{% tab label="Go" %}
|
||||
- `xrpl-go`: Used for XRPL client connection, transaction submission, and wallet handling.
|
||||
- `encoding/json`, `strings`, and `fmt`: Used for formatting and printing results to the console.
|
||||
- `cryptoconditions`, `crypto/rand` and `encoding/hex`: Used to generate a crypto-condition.
|
||||
- `time`: Used for time calculations.
|
||||
|
||||
{% code-snippet file="/_code-samples/escrow/go/send-fungible-token-escrow/main.go" language="go" before="// ====== Conditional MPT Escrow ======" /%}
|
||||
{% /tab %}
|
||||
{% /tabs %}
|
||||
|
||||
### 3. Issue an MPT with escrow support
|
||||
|
||||
Construct an [MPTokenIssuanceCreate transaction][] with the `tfMPTCanEscrow` flag, which enables the token to be held in escrows. Then, retrieve the MPT issuance ID from the transaction result. This example creates an escrow that sends MPTs back to the original issuer. If you wanted to create an escrow for another account, the issuer would also have to set the `tfMPTCanTransfer` flag.
|
||||
|
||||
{% tabs %}
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/escrow/js/sendFungibleTokenEscrow.js" language="js" from="// ====== Conditional MPT Escrow ======" before="// Escrow Creator authorizes the MPT" /%}
|
||||
{% /tab %}
|
||||
{% tab label="Python" %}
|
||||
{% code-snippet file="/_code-samples/escrow/py/send_fungible_token_escrow.py" language="py" from="# ====== Conditional MPT Escrow ======" before="# Escrow Creator authorizes the MPT" /%}
|
||||
{% /tab %}
|
||||
{% tab label="Go" %}
|
||||
{% code-snippet file="/_code-samples/escrow/go/send-fungible-token-escrow/main.go" language="go" from="// ====== Conditional MPT Escrow ======" before="// Escrow Creator authorizes the MPT" /%}
|
||||
{% /tab %}
|
||||
{% /tabs %}
|
||||
|
||||
### 4. Authorize the MPT
|
||||
|
||||
Before the escrow creator can hold the MPT, they must indicate their willingness to hold it with the [MPTokenAuthorize transaction][].
|
||||
|
||||
{% tabs %}
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/escrow/js/sendFungibleTokenEscrow.js" language="js" from="// Escrow Creator authorizes the MPT" before="// Issuer sends MPTs to escrow creator" /%}
|
||||
{% /tab %}
|
||||
{% tab label="Python" %}
|
||||
{% code-snippet file="/_code-samples/escrow/py/send_fungible_token_escrow.py" language="py" from="# Escrow Creator authorizes the MPT" before="# Issuer sends MPTs to escrow creator" /%}
|
||||
{% /tab %}
|
||||
{% tab label="Go" %}
|
||||
{% code-snippet file="/_code-samples/escrow/go/send-fungible-token-escrow/main.go" language="go" from="// Escrow Creator authorizes the MPT" before="// Issuer sends MPTs to escrow creator" /%}
|
||||
{% /tab %}
|
||||
{% /tabs %}
|
||||
|
||||
### 5. Send MPTs to the escrow creator
|
||||
|
||||
Send MPTs from the issuer to the escrow creator using a [Payment transaction][].
|
||||
|
||||
{% tabs %}
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/escrow/js/sendFungibleTokenEscrow.js" language="js" from="// Issuer sends MPTs to escrow creator" before="// Escrow Creator creates a conditional MPT escrow" /%}
|
||||
{% /tab %}
|
||||
{% tab label="Python" %}
|
||||
{% code-snippet file="/_code-samples/escrow/py/send_fungible_token_escrow.py" language="py" from="# Issuer sends MPTs to escrow creator" before="# Escrow Creator creates a conditional MPT escrow" /%}
|
||||
{% /tab %}
|
||||
{% tab label="Go" %}
|
||||
{% code-snippet file="/_code-samples/escrow/go/send-fungible-token-escrow/main.go" language="go" from="// Issuer sends MPTs to escrow creator" before="// Escrow Creator creates a conditional MPT escrow" /%}
|
||||
{% /tab %}
|
||||
{% /tabs %}
|
||||
|
||||
### 6. Create a condition and fulfillment
|
||||
|
||||
Conditional escrows require a fulfillment and its corresponding condition in the format of a PREIMAGE-SHA-256 _crypto-condition_, represented as hexadecimal. To calculate these in the correct format, use a crypto-conditions library. Generally, you want to generate the fulfillment using at least 32 random bytes from a cryptographically secure source of randomness.
|
||||
|
||||
{% tabs %}
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/escrow/js/sendFungibleTokenEscrow.js" language="js" from="// Escrow Creator creates a conditional MPT escrow" before="// Set expiration" /%}
|
||||
{% /tab %}
|
||||
{% tab label="Python" %}
|
||||
{% code-snippet file="/_code-samples/escrow/py/send_fungible_token_escrow.py" language="py" from="# Escrow Creator creates a conditional MPT escrow" before="# Set expiration" /%}
|
||||
{% /tab %}
|
||||
{% tab label="Go" %}
|
||||
{% code-snippet file="/_code-samples/escrow/go/send-fungible-token-escrow/main.go" language="go" from="// Escrow Creator creates a conditional MPT escrow" before="// Set expiration" /%}
|
||||
{% /tab %}
|
||||
{% /tabs %}
|
||||
|
||||
### 7. Create the conditional MPT escrow
|
||||
|
||||
Create a conditional escrow using the generated crypto-condition. Fungible token escrows require an expiration date. This example sets an expiration time of five minutes. After creating the escrow, save the sequence number to reference it later.
|
||||
|
||||
{% tabs %}
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/escrow/js/sendFungibleTokenEscrow.js" language="js" from="// Set expiration" before="// Finish the conditional MPT escrow" /%}
|
||||
{% /tab %}
|
||||
{% tab label="Python" %}
|
||||
{% code-snippet file="/_code-samples/escrow/py/send_fungible_token_escrow.py" language="py" from="# Set expiration" before="# Finish the conditional MPT escrow" /%}
|
||||
{% /tab %}
|
||||
{% tab label="Go" %}
|
||||
{% code-snippet file="/_code-samples/escrow/go/send-fungible-token-escrow/main.go" language="go" from="// Set expiration" before="// Finish the conditional MPT escrow" /%}
|
||||
{% /tab %}
|
||||
{% /tabs %}
|
||||
|
||||
### 8. Finish the conditional MPT escrow
|
||||
|
||||
Finish the escrow by providing the original condition and its matching fulfillment.
|
||||
|
||||
{% tabs %}
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/escrow/js/sendFungibleTokenEscrow.js" language="js" from="// Finish the conditional MPT escrow" before="// ====== Timed Trust Line Token Escrow ======" /%}
|
||||
{% /tab %}
|
||||
{% tab label="Python" %}
|
||||
{% code-snippet file="/_code-samples/escrow/py/send_fungible_token_escrow.py" language="py" from="# Finish the conditional MPT escrow" before="# ====== Timed Trust Line Token Escrow ======" /%}
|
||||
{% /tab %}
|
||||
{% tab label="Go" %}
|
||||
{% code-snippet file="/_code-samples/escrow/go/send-fungible-token-escrow/main.go" language="go" from="// Finish the conditional MPT escrow" before="// ====== Timed Trust Line Token Escrow ======" /%}
|
||||
{% /tab %}
|
||||
{% /tabs %}
|
||||
|
||||
### 9. Enable trust line token escrows
|
||||
|
||||
Token issuers enable trust line token escrows differently from MPTs. Unlike MPTs, which are escrowable at the token level, trust line tokens are escrowable at the account level. When an issuer enables the `asfAllowTrustLineLocking` flag on their account, _all_ trust line tokens issued from that account are escrowable.
|
||||
|
||||
{% tabs %}
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/escrow/js/sendFungibleTokenEscrow.js" language="js" from="// ====== Timed Trust Line Token Escrow ======" before="// Escrow Creator sets up a trust line" /%}
|
||||
{% /tab %}
|
||||
{% tab label="Python" %}
|
||||
{% code-snippet file="/_code-samples/escrow/py/send_fungible_token_escrow.py" language="py" from="# ====== Timed Trust Line Token Escrow ======" before="# Escrow Creator sets up a trust line" /%}
|
||||
{% /tab %}
|
||||
{% tab label="Go" %}
|
||||
{% code-snippet file="/_code-samples/escrow/go/send-fungible-token-escrow/main.go" language="go" from="// ====== Timed Trust Line Token Escrow ======" before="// Escrow Creator sets up a trust line" /%}
|
||||
{% /tab %}
|
||||
{% /tabs %}
|
||||
|
||||
### 10. Set up a trust line
|
||||
|
||||
Establish a trust line between the escrow creator and issuer using the [TrustSet transaction][]. The escrow creator submits this transaction to indicate their willingness to receive the token, defining the currency and maximum amount they're willing to hold.
|
||||
|
||||
{% tabs %}
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/escrow/js/sendFungibleTokenEscrow.js" language="js" from="// Escrow Creator sets up a trust line" before="// Issuer sends IOU tokens to creator" /%}
|
||||
{% /tab %}
|
||||
{% tab label="Python" %}
|
||||
{% code-snippet file="/_code-samples/escrow/py/send_fungible_token_escrow.py" language="py" from="# Escrow Creator sets up a trust line" before="# Issuer sends IOU tokens to creator" /%}
|
||||
{% /tab %}
|
||||
{% tab label="Go" %}
|
||||
{% code-snippet file="/_code-samples/escrow/go/send-fungible-token-escrow/main.go" language="go" from="// Escrow Creator sets up a trust line" before="// Issuer sends IOU tokens to creator" /%}
|
||||
{% /tab %}
|
||||
{% /tabs %}
|
||||
|
||||
### 11. Send IOU tokens to the escrow creator
|
||||
|
||||
Send IOU tokens from the issuer to the escrow creator using a [Payment transaction][].
|
||||
|
||||
{% tabs %}
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/escrow/js/sendFungibleTokenEscrow.js" language="js" from="// Issuer sends IOU tokens to creator" before="// Escrow Creator creates a timed trust line token escrow" /%}
|
||||
{% /tab %}
|
||||
{% tab label="Python" %}
|
||||
{% code-snippet file="/_code-samples/escrow/py/send_fungible_token_escrow.py" language="py" from="# Issuer sends IOU tokens to creator" before="# Escrow Creator creates a timed trust line token escrow" /%}
|
||||
{% /tab %}
|
||||
{% tab label="Go" %}
|
||||
{% code-snippet file="/_code-samples/escrow/go/send-fungible-token-escrow/main.go" language="go" from="// Issuer sends IOU tokens to creator" before="// Escrow Creator creates a timed trust line token escrow" /%}
|
||||
{% /tab %}
|
||||
{% /tabs %}
|
||||
|
||||
### 12. Create a timed trust line token escrow
|
||||
|
||||
To make a timed escrow, set the maturity time of the escrow, which is a timestamp formatted as [seconds since the Ripple Epoch][]. This example sets a maturity time of ten seconds from the time the code executes. Since it is a fungible token escrow, it also sets an expiration time of five minutes. After submitting the [EscrowCreate transaction][], save the sequence number from the transaction result.
|
||||
|
||||
{% tabs %}
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/escrow/js/sendFungibleTokenEscrow.js" language="js" from="// Escrow Creator creates a timed trust line token escrow" before="// Wait for the escrow to mature" /%}
|
||||
{% /tab %}
|
||||
{% tab label="Python" %}
|
||||
{% code-snippet file="/_code-samples/escrow/py/send_fungible_token_escrow.py" language="py" from="# Escrow Creator creates a timed trust line token escrow" before="# Wait for the escrow to mature" /%}
|
||||
{% /tab %}
|
||||
{% tab label="Go" %}
|
||||
{% code-snippet file="/_code-samples/escrow/go/send-fungible-token-escrow/main.go" language="go" from="// Escrow Creator creates a timed trust line token escrow" before="// Wait for the escrow to mature" /%}
|
||||
{% /tab %}
|
||||
{% /tabs %}
|
||||
|
||||
### 13. Wait for escrow to mature and finish
|
||||
|
||||
Wait for the escrow to mature. Before submitting the [EscrowFinish][] transaction, the code checks the current validated ledger to confirm the close time is after the escrow maturation time. This check ensures the escrow is matured on a validated ledger before trying to finish it.
|
||||
|
||||
{% tabs %}
|
||||
{% tab label="JavaScript" %}
|
||||
{% code-snippet file="/_code-samples/escrow/js/sendFungibleTokenEscrow.js" language="js" from="// Wait for the escrow to mature" /%}
|
||||
{% /tab %}
|
||||
{% tab label="Python" %}
|
||||
{% code-snippet file="/_code-samples/escrow/py/send_fungible_token_escrow.py" language="py" from="# Wait for the escrow to mature" /%}
|
||||
{% /tab %}
|
||||
{% tab label="Go" %}
|
||||
{% code-snippet file="/_code-samples/escrow/go/send-fungible-token-escrow/main.go" language="go" from="// Wait for the escrow to mature" /%}
|
||||
{% /tab %}
|
||||
{% /tabs %}
|
||||
|
||||
|
||||
## See Also
|
||||
|
||||
**Concepts**:
|
||||
- [Escrow](../../concepts/payment-types/escrow.md)
|
||||
- [Multi-Purpose Tokens](../../concepts/tokens/fungible-tokens/multi-purpose-tokens.md)
|
||||
- [Trust Line Tokens](../../concepts/tokens/fungible-tokens/trust-line-tokens.md)
|
||||
|
||||
**Tutorials**:
|
||||
- [Look up Escrows](./look-up-escrows.md)
|
||||
- [Cancel an Expired Escrow](./cancel-an-expired-escrow.md)
|
||||
|
||||
**References**:
|
||||
- [EscrowCreate transaction][]
|
||||
- [EscrowFinish transaction][]
|
||||
|
||||
{% raw-partial file="/docs/_snippets/common-links.md" /%}
|
||||
2
package-lock.json
generated
2
package-lock.json
generated
@@ -27,7 +27,7 @@
|
||||
"react18-json-view": "^0.2.6",
|
||||
"smol-toml": "^1.3.1",
|
||||
"use-query-params": "^2.2.1",
|
||||
"xrpl": "^4.2.5"
|
||||
"xrpl": "^4.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"bootstrap": "^4.6.2",
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
"react18-json-view": "^0.2.6",
|
||||
"smol-toml": "^1.3.1",
|
||||
"use-query-params": "^2.2.1",
|
||||
"xrpl": "^4.2.5"
|
||||
"xrpl": "^4.6.0"
|
||||
},
|
||||
"overrides": {
|
||||
"react": "^19.1.0",
|
||||
|
||||
@@ -251,7 +251,6 @@
|
||||
- page: docs/tutorials/payments/create-trust-line-send-currency-in-python.md
|
||||
- page: docs/tutorials/payments/send-a-conditional-escrow.md
|
||||
- page: docs/tutorials/payments/send-a-timed-escrow.md
|
||||
- page: docs/tutorials/payments/send-fungible-token-escrows.md
|
||||
- page: docs/tutorials/payments/look-up-escrows.md
|
||||
- page: docs/tutorials/payments/cancel-an-expired-escrow.md
|
||||
- page: docs/tutorials/payments/send-a-check.md
|
||||
@@ -327,8 +326,7 @@
|
||||
- page: docs/tutorials/best-practices/key-management/remove-a-regular-key-pair.md
|
||||
- page: docs/tutorials/best-practices/key-management/offline-account-setup.md
|
||||
- page: docs/tutorials/best-practices/key-management/set-up-multi-signing.md
|
||||
- page: docs/tutorials/best-practices/key-management/send-a-multi-signed-transaction.md
|
||||
- page: docs/tutorials/best-practices/key-management/delete-an-account.md
|
||||
- page: docs/tutorials/best-practices/key-management/send-a-multi-signed-transaction.md
|
||||
- group: Advanced Developer Topics
|
||||
groupTranslationKey: sidebar.docs.tutorials.advancedDeveloperTopics
|
||||
expanded: false
|
||||
|
||||
Reference in New Issue
Block a user