Skip to content
This repository was archived by the owner on Oct 28, 2025. It is now read-only.

Commit bf958b5

Browse files
mvadariCopilot
andauthored
feat: add stuff for Apex (#51)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent abff05b commit bf958b5

File tree

11 files changed

+323
-93
lines changed

11 files changed

+323
-93
lines changed

APEX.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Apex Workshop Notes
2+
3+
## Getting Started
4+
5+
1. Install Rust (https://rust-lang.org/tools/install)
6+
1. Install Docker (https://docs.docker.com/engine/install)
7+
1. Clone the repo at https://github.com/ripple/craft
8+
1. Type `craft` to start the CLI and install dependencies
9+
10+
## Running an Example
11+
12+
We will be walking through the `kyc` example. This example will only allow the escrow to be finished if the destination has created a "Terms and Conditions" example to itself.
13+
14+
### Build the example
15+
16+
```sh
17+
% craft
18+
> What would you like to do? Build WASM module
19+
Configuring WASM build settings...
20+
> Select WASM project: kyc
21+
> Select build mode: Release (optimized, no debug info)
22+
> Select optimization level: Aggressive (-Oz: optimize aggressively for size)
23+
Building WASM module...
24+
Running cargo build...
25+
args: ["build", "--target", "wasm32-unknown-unknown", "--release"]
26+
27+
Finished `release` profile [optimized] target(s) in 0.03s
28+
29+
30+
Build completed successfully!
31+
32+
WASM file location:
33+
/Users/mvadari/Documents/craft/projects/kyc/target/wasm32-unknown-unknown/release/kyc.wasm
34+
Size: 1198 bytes
35+
WASM Fingerprint: w7HwHG281DxCQf43VyE7tx1CFheTop12cM # note, this might be wrong
36+
> Would you like to export the WASM as hex (copied to clipboard)? No
37+
Optimizing WASM module...
38+
Optimization complete!
39+
> What would you like to do next? Exit
40+
```
41+
42+
### Run the example
43+
44+
In a separate Terminal window:
45+
46+
```sh
47+
# open Docker Desktop
48+
docker pull rippleci/rippled:smart_escrow
49+
docker run --rm -p 5005:5005 -p 6006:6006 --volume "/$(pwd)/reference/rippled_cfg/":"/opt/etc/ripple/" --platform linux/amd64 rippleci/rippled:smart_escrow "-a"
50+
```
51+
52+
In your main Terminal window:
53+
54+
```sh
55+
# run scripts
56+
node reference/js/deploy_sample_standalone.js kyc
57+
# Record the Origin, Destination, and Destination Secret from the output above
58+
node reference/js/finish_escrow_kyc.js [DestinationAccount] [DestinationSecret] [OriginAccount] [EscrowSequence]
59+
```

projects/kyc/src/lib.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,29 @@
11
#![no_std]
22

3-
use xrpl_std::get_current_escrow_account_id;
3+
use xrpl_std::get_current_escrow_destination;
4+
use xrpl_std::host::trace::{DataRepr, trace_data, trace_num};
45
use xrpl_std::keylet::credential_keylet;
56

67
#[unsafe(no_mangle)]
78
pub extern "C" fn finish() -> bool {
8-
let account = match get_current_escrow_account_id() {
9+
let account = match get_current_escrow_destination() {
910
Some(v) => v,
1011
None => return false,
1112
};
13+
14+
// "termsandconditions" in hex
1215
let cred_type: &[u8] = b"termsandconditions";
13-
match credential_keylet(&account, &account, &cred_type) {
14-
Some(_v) => return true,
16+
let cred_keylet = match credential_keylet(&account, &account, &cred_type) {
17+
Some(v) => v,
1518
None => return false,
1619
};
20+
let _ = trace_data("cred_keylet", &cred_keylet, DataRepr::AsHex);
21+
22+
let slot =
23+
unsafe { xrpl_std::host::cache_ledger_obj(cred_keylet.as_ptr(), cred_keylet.len(), 0) };
24+
if slot < 0 {
25+
let _ = trace_num("CACHE ERROR", i64::from(slot));
26+
return false;
27+
};
28+
return true;
1729
}

reference/js/deploy_sample_standalone.js

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -89,14 +89,16 @@ async function deploy() {
8989
wallet2 = xrpl.Wallet.generate()
9090
}
9191

92+
const finish = getFinishFunctionFromFile(process.argv[2])
93+
9294
await fundWallet(wallet)
9395
await fundWallet(wallet2)
9496

9597
console.log(`\nFunded accounts:`)
96-
console.log(`Account 1 - Address: ${wallet.address}`)
97-
console.log(`Account 1 - Secret: ${wallet.seed}`)
98-
console.log(`Account 2 - Address: ${wallet2.address}`)
99-
console.log(`Account 2 - Secret: ${wallet2.seed}\n`)
98+
console.log(`Account 1 (Origin) - Address: ${wallet.address}`)
99+
console.log(`Account 1 (Origin) - Secret: ${wallet.seed}`)
100+
console.log(`Account 2 (Destination) - Address: ${wallet2.address}`)
101+
console.log(`Account 2 (Destination) - Secret: ${wallet2.seed}\n`)
100102

101103
const close_time = (
102104
await client.request({
@@ -105,15 +107,12 @@ async function deploy() {
105107
})
106108
).result.ledger.close_time
107109

108-
const finish = getFinishFunctionFromFile(process.argv[2])
109-
console.log(finish)
110-
111110
const response1 = await submit({
112111
TransactionType: 'EscrowCreate',
113112
Account: wallet.address,
114113
Amount: "100000",
115114
Destination: wallet2.address,
116-
CancelAfter: close_time + 200,
115+
CancelAfter: close_time + 2000,
117116
FinishAfter: close_time + 5,
118117
FinishFunction: finish,
119118
Data: xrpl.xrpToDrops(70),

reference/js/finish_escrow_kyc.js

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
const xrpl = require("xrpl")
2+
3+
if (process.argv.length != 6) {
4+
console.error(
5+
'Usage: ' +
6+
process.argv[0] +
7+
' ' +
8+
process.argv[1] +
9+
' <Account> <AccountSecret> <Owner> <OfferSequence>',
10+
)
11+
process.exit(1)
12+
}
13+
14+
function sleep(ms) {
15+
return new Promise(resolve => setTimeout(resolve, ms));
16+
}
17+
18+
const url = "ws://127.0.0.1:6006"
19+
const client = new xrpl.Client(url)
20+
21+
const [, , account, accountSecret, owner, offerSequence] = process.argv
22+
23+
async function submit(tx, wallet, debug = true) {
24+
const result = await client.submitAndWait(tx, {autofill: true, wallet})
25+
console.log("SUBMITTED " + tx.TransactionType)
26+
if (debug)
27+
console.log(result.result ?? result)
28+
else
29+
console.log("Result code: " + result.result?.meta?.TransactionResult)
30+
return result
31+
}
32+
33+
async function finishEscrow() {
34+
let interval
35+
try {
36+
await client.connect()
37+
console.log(`Connected to ${url}`)
38+
await client.request({command: 'ledger_accept'})
39+
40+
interval = setInterval(() => {if (client.isConnected()) client.request({command: 'ledger_accept'})},1000)
41+
42+
const wallet = xrpl.Wallet.fromSeed(accountSecret)
43+
44+
// Verify the account matches the wallet
45+
if (wallet.address !== account) {
46+
console.error("Error: Provided account doesn't match the wallet derived from the secret")
47+
process.exit(1)
48+
}
49+
50+
console.log("\nTransaction Details:")
51+
console.log(`Account (Finishing Escrow): ${account}`)
52+
console.log(`Owner (Created Escrow): ${owner}`)
53+
console.log(`Offer Sequence: ${offerSequence}\n`)
54+
55+
await sleep(2000)
56+
57+
const txFail = {
58+
TransactionType: 'EscrowFinish',
59+
Account: account,
60+
Owner: owner,
61+
OfferSequence: parseInt(offerSequence),
62+
ComputationAllowance: 1000000,
63+
}
64+
65+
console.log("Submitting EscrowFinish transaction... (this should fail)")
66+
const responseFail = await submit(txFail, wallet)
67+
68+
if (responseFail.result.meta.TransactionResult === "tesSUCCESS") {
69+
console.log("\nEscrow finished successfully!")
70+
} else {
71+
console.error("\nFailed to finish escrow:", responseFail.result.meta.TransactionResult)
72+
}
73+
74+
await sleep(2000)
75+
76+
const credTx = {
77+
TransactionType: 'CredentialCreate',
78+
Account: account,
79+
Subject: account,
80+
CredentialType: xrpl.convertStringToHex('termsandconditions'),
81+
URI: xrpl.convertStringToHex("https://example.com/terms"),
82+
}
83+
84+
console.log("Submitting CredentialCreate transaction...")
85+
const credResponse = await submit(credTx, wallet)
86+
87+
if (credResponse.result.meta.TransactionResult === "tesSUCCESS") {
88+
console.log("Credential created successfully!")
89+
} else {
90+
console.error("\nFailed to create credential:", credResponse.result.meta.TransactionResult)
91+
}
92+
93+
await sleep(2000)
94+
95+
const tx = {
96+
TransactionType: 'EscrowFinish',
97+
Account: account,
98+
Owner: owner,
99+
OfferSequence: parseInt(offerSequence),
100+
ComputationAllowance: 1000000,
101+
}
102+
103+
console.log("Submitting EscrowFinish transaction...")
104+
const response = await submit(tx, wallet)
105+
106+
if (response.result.meta.TransactionResult === "tesSUCCESS") {
107+
console.log("\nEscrow finished successfully!")
108+
} else {
109+
console.error("\nFailed to finish escrow:", response.result.meta.TransactionResult)
110+
}
111+
112+
} catch (error) {
113+
console.error("Error:", error.message)
114+
} finally {
115+
await client.disconnect()
116+
clearInterval(interval)
117+
console.log("Disconnected")
118+
}
119+
}
120+
121+
finishEscrow()

reference/rippled-cfg/smart-escrow-rippled.cfg renamed to reference/rippled_cfg/rippled.cfg

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,6 @@ pool.ntp.org
7272
[ips]
7373
r.ripple.com 51235
7474

75-
[validators_file]
76-
validators.txt
77-
7875
[rpc_startup]
7976
{ "command": "log_level", "severity": "info" }
8077

@@ -110,8 +107,6 @@ validators.txt
110107
63456
111108

112109
[features]
113-
# EscrowExtensions
114-
SmartEscrow
115110
# Devnet amendments as of June 28th, 2023
116111
NegativeUNL
117112
fixRemoveNFTokenAutoTrustLine
@@ -173,34 +168,47 @@ AMM
173168
Clawback
174169
fixReducedOffersV1
175170
fixNFTokenRemint
176-
# 2.0.0-b4 Amendments
171+
# 2.0.0 Amendments
177172
XChainBridge
178173
DID
179-
# 2.2.0-b3 Amendments
174+
# 2.2.0 Amendments
180175
fixNFTokenReserve
181176
fixInnerObjTemplate
182177
fixAMMOverflowOffer
183178
PriceOracle
184179
fixEmptyDID
185180
fixXChainRewardRounding
186181
fixPreviousTxnID
182+
fixAMMv1_1
187183
# 2.3.0 Amendments
188-
# fixAMMv1_1
189-
# fixAMMv1_2
190-
# AMMClawback
191-
# InvariantsV1_1
192-
# Credentials
193-
# NFTokenMintOffer
194-
# MPTokensV1
195-
# fixNFTokenPageLinks
196-
# fixInnerObjTemplate2
197-
# fixEnforceNFTokenTrustline
198-
# fixReducedOffersV2
199-
# DeepFreeze
200-
# PermissionedDomains
184+
AMMClawback
185+
Credentials
186+
NFTokenMintOffer
187+
MPTokensV1
188+
fixAMMv1_2
189+
fixNFTokenPageLinks
190+
fixInnerObjTemplate2
191+
fixEnforceNFTokenTrustline
192+
fixReducedOffersV2
193+
# 2.4.0 Amendments
194+
DeepFreeze
195+
DynamicNFT
196+
PermissionedDomains
197+
fixFrozenLPTokenTransfer
198+
fixInvalidTxFlags
199+
# 2.5.0 Amendments
200+
fixEnforceNFTokenTrustlineV2
201+
fixAMMv1_3
202+
PermissionDelegation
203+
Batch
204+
TokenEscrow
205+
PermissionedDEX
206+
SingleAssetVault
207+
fixPayChanCancelAfter
208+
201209

202210
# This section can be used to simulate various FeeSettings scenarios for rippled node in standalone mode
203211
[voting]
204-
reference_fee = 200 # 200 drops
205-
account_reserve = 20000000 # 20 XRP
206-
owner_reserve = 5000000 # 5 XRP
212+
reference_fee = 10 # 10 drops
213+
account_reserve = 1000000 # 1 XRP
214+
owner_reserve = 200000 # 0.2 XRP

xrpl-std/src/core/tx/current_transaction.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
use crate::core::amount::xrp_amount::XrpAmount;
21
use crate::core::amount::Amount;
32
use crate::core::amount::Amount::Xrp;
3+
use crate::core::amount::xrp_amount::XrpAmount;
44
use crate::core::field_codes::{
55
SF_ACCOUNT, SF_ACCOUNT_TXN_ID, SF_CONDITION, SF_FEE, SF_FLAGS, SF_FULFILLMENT, SF_HASH,
66
SF_LAST_LEDGER_SEQUENCE, SF_NETWORK_ID, SF_OFFER_SEQUENCE, SF_OWNER, SF_SEQUENCE,

0 commit comments

Comments
 (0)