npx skills add ...
npx skills add flare-foundation/flare-ai-skills --skill flare-smart-accounts
Provides domain knowledge and guidance for Flare Smart Accounts—account abstraction that allows XRPL users to interact with Flare without owning FLR. Use when working with smart accounts, XRPL-to-Flare transactions, MasterAccountController, custom instructions, Firelight/Upshift vault interactions, or the smart-accounts CLI.
npx skills add flare-foundation/flare-ai-skills --skill flare-smart-accounts
This skill provides informational guidance only.
No executable code or automated financial actions are included.
Flare Smart Accounts provide account abstraction that allows XRPL users to perform actions on the Flare chain without owning any FLR token.
Each XRPL address receives a unique smart account on Flare that only that address can control.
Key benefits:
Flare Smart Accounts support two complementary flows:
Payment to the operator's XRPL address, encoding a 32-byte instruction as the payment reference in the memo field.Payment attestation from the FDC.executeInstruction (or reserveCollateral) on MasterAccountController, passing the FDC proof.The contract verifies the proof, retrieves (or creates) the user's smart account, decodes the payment reference, and executes the requested action.
Payment to the FAssets Core Vault XRPL address (per FAssets minting) that mints FXRP to the smart account, with the memo field carrying the instruction.executeDirectMinting; the FAssets AssetManager mints FXRP to MasterAccountController and calls back into handleMintedFAssets.MasterAccountController routes FAssets to the user's PersonalAccount, optionally pays an executor fee, and dispatches any memo instruction (see Memo Opcodes).Minting is FAssets minting, not a CRT instruction. User minting of FXRP no longer uses a Smart Accounts collateral-reservation (CRT) instruction. To mint, send an XRPL
Paymentto the Core Vault with a memo or destination tag as described in FAssets minting. The legacy CRT instructions (0x00,0x10,0x20below) and their CLI encoders may still exist in older tooling but are not the recommended mint path. For mint-and-action in one payment, use a memo-field custom instruction.
Important: XRPL transactions targeting smart accounts must not use a destination tag. A destination tag forces FAssets direct minting to credit the tag-holder instead of the smart account.
All instructions follow this structure:
| Byte Position | Field | Description |
|---|---|---|
| Byte 1 | Instruction ID | First nibble = type (0-F), second nibble = command (0-F) |
| Byte 2 | Wallet ID | Operator-assigned wallet identifier (use 0 if unassigned) |
| Bytes 3-12 | Value | 10-byte encoded amount (lots of FXRP or XRP) |
| Bytes 13+ | Parameters | Instruction-specific data |
0x0_)0x00 — Collateral Reservation (legacy CRT)Reserve collateral for minting FXRP. Legacy: prefer FAssets minting (XRPL payment to the Core Vault). Documented here for older tooling and historical integrations.
| Bytes | Field | Description |
|---|---|---|
| 1 | 0x00 | Instruction ID |
| 2 | walletId | Wallet identifier |
| 3-12 | value | Number of lots to mint (10 bytes) |
| 13-14 | agentVaultId | Agent vault identifier (2 bytes) |
| 15-32 | — | Arbitrary (ignored) |
Example: 0x0000000000000000000000010001000000000000000000000000000000000000
00 (FXRP collateral reservation)0000000000000000000001 (1 lot)00010x01 — Transfer FXRPTransfer FXRP to a Flare address.
| Bytes | Field | Description |
|---|---|---|
| 1 | 0x01 | Instruction ID |
| 2 | walletId | Wallet identifier |
| 3-12 | value | Amount of FXRP to transfer (10 bytes) |
| 13-32 | recipientAddress | Destination Flare address (20 bytes) |
Example: 0x01000000000000000000000af5488132432118596fa13800b68df4c0ff25131d
01 (FXRP transfer)000000000000000000000a (10 FXRP)0xf5488132432118596fa13800b68df4c0ff25131d0x02 — Redeem FXRPRedeem FXRP back to XRP on XRPL.
| Bytes | Field | Description |
|---|---|---|
| 1 | 0x02 | Instruction ID |
| 2 | walletId | Wallet identifier |
| 3-12 | value | Number of lots to redeem (10 bytes) |
| 13-32 | — | Arbitrary (ignored) |
0x1_)Firelight is a vault protocol for stXRP yield.
0x10 — Collateral Reservation + Deposit (legacy CRT)Combined mint FXRP and deposit to Firelight vault. Legacy: prefer FAssets minting then the 0x11 deposit instruction, or a memo-field custom instruction for mint-and-deposit in one payment.
| Bytes | Field | Description |
|---|---|---|
| 1 | 0x10 | Instruction ID |
| 2 | walletId | Wallet identifier |
| 3-12 | value | Number of lots (10 bytes) |
| 13-14 | agentVaultId | Agent vault identifier (2 bytes) |
| 15-16 | vaultId | Firelight vault identifier (2 bytes) |
| 17-32 | — | Arbitrary (ignored) |
0x11 — DepositDeposit existing FXRP to Firelight vault.
| Bytes | Field | Description |
|---|---|---|
| 1 | 0x11 | Instruction ID |
| 2 | walletId | Wallet identifier |
| 3-12 | value | FXRP amount to deposit (10 bytes) |
| 13-14 | — | Arbitrary (ignored) |
| 15-16 | vaultId | Firelight vault identifier (2 bytes) |
| 17-32 | — | Arbitrary (ignored) |
0x12 — Redeem (Initiate Withdrawal)Begin withdrawal from Firelight vault.
| Bytes | Field | Description |
|---|---|---|
| 1 | 0x12 | Instruction ID |
| 2 | walletId | Wallet identifier |
| 3-12 | value | Amount to withdraw (10 bytes) |
| 13-14 | — | Arbitrary (ignored) |
| 15-16 | vaultId | Firelight vault identifier (2 bytes) |
| 17-32 | — | Arbitrary (ignored) |
0x13 — Claim WithdrawComplete pending withdrawal from Firelight vault.
| Bytes | Field | Description |
|---|---|---|
| 1 | 0x13 | Instruction ID |
| 2 | walletId | Wallet identifier |
| 3-12 | value | Amount to claim (10 bytes) |
| 13-14 | — | Arbitrary (ignored) |
| 15-16 | vaultId | Firelight vault identifier (2 bytes) |
| 17-32 | — | Arbitrary (ignored) |
0x2_)Upshift is another vault protocol with time-locked withdrawals.
0x20 — Collateral Reservation + Deposit (legacy CRT)Combined mint FXRP and deposit to Upshift vault. Legacy: prefer FAssets minting then the 0x21 deposit instruction, or a memo-field custom instruction for mint-and-deposit in one payment.
| Bytes | Field | Description |
|---|---|---|
| 1 | 0x20 | Instruction ID |
| 2 | walletId | Wallet identifier |
| 3-12 | value | Number of lots (10 bytes) |
| 13-14 | agentVaultId | Agent vault identifier (2 bytes) |
| 15-16 | vaultId | Upshift vault identifier (2 bytes) |
| 17-32 | — | Arbitrary (ignored) |
0x21 — DepositDeposit existing FXRP to Upshift vault.
| Bytes | Field | Description |
|---|---|---|
| 1 | 0x21 | Instruction ID |
| 2 | walletId | Wallet identifier |
| 3-12 | value | FXRP amount to deposit (10 bytes) |
| 13-14 | — | Arbitrary (ignored) |
| 15-16 | vaultId | Upshift vault identifier (2 bytes) |
| 17-32 | — | Arbitrary (ignored) |
0x22 — Request RedeemRequest withdrawal from Upshift vault (starts waiting period).
| Bytes | Field | Description |
|---|---|---|
| 1 | 0x22 | Instruction ID |
| 2 | walletId | Wallet identifier |
| 3-12 | value | Amount to withdraw (10 bytes) |
| 13-14 | — | Arbitrary (ignored) |
| 15-16 | vaultId | Upshift vault identifier (2 bytes) |
| 17-32 | — | Arbitrary (ignored) |
0x23 — ClaimComplete withdrawal after waiting period expires.
| Bytes | Field | Description |
|---|---|---|
| 1 | 0x23 | Instruction ID |
| 2 | walletId | Wallet identifier |
| 3-12 | value | Date in YYYYMMDD format (e.g., 20251218 for Dec 18, 2025) |
| 13-14 | — | Arbitrary (ignored) |
| 15-16 | vaultId | Upshift vault identifier (2 bytes) |
| 17-32 | — | Arbitrary (ignored) |
When minting FXRP directly to a smart account via the FAssets direct minting path, the XRPL memo carries one of these opcodes in its first byte:
| Memo opcode | Action | Description |
|---|---|---|
0xFE | Custom Instruction | 42-byte memo committing keccak256(PackedUserOperation); bytes delivered off-chain by executor |
0xFF | Memo Field Custom Instruction | Full abi.encode(PackedUserOperation) carried inline in memo (capped at ~1024 bytes) |
0xE0 | Skip memo | Mark a target XRPL transaction's memo to be skipped on its next direct mint. Used to recover FXRP when executeDirectMintingWithData reverted — see Failure Handling & Recovery |
0xE1 | Fast-forward nonce | Advance the personal account's memo-instruction nonce when it is stuck after a partial or abandoned flow — see Fast-forwarding a stuck nonce |
0xE2 | Replace executor fee | Set a replacement executor fee for a stuck XRPL transaction |
0xD0 | Pin executor | Pin a specific executor address to the personal account |
0xD1 | Unpin executor | Unpin the executor from the personal account |
Custom instructions let an XRPL user execute arbitrary contract calls on Flare through an XRPL Payment. The personal account exposes an EIP-4337 style executeUserOp entry point.
Custom instructions are packaged as an EIP-4337 PackedUserOperation. Only three fields are required:
sender — must equal the personal account address (getPersonalAccount(xrplAddress))nonce — must equal the current memo nonce (getNonce(personalAccount))callData — abi.encodeCall(IPersonalAccount.executeUserOp, (calls))Custom Instruction (0xFE) — recommended:
42-byte memo layout:
| Bytes | Field | Description |
|---|---|---|
0 | 0xFE | Instruction ID |
1 | walletId | Wallet identifier |
2-9 | executorFeeUBA | Executor fee (big-endian uint64) |
10-41 | userOpHash | keccak256(abi.encode(userOp)) |
The user delivers the full PackedUserOperation bytes to an executor off-chain. The executor calls executeDirectMintingWithData(proof, data) on AssetManager with msg.value = sum(call.value). The controller verifies keccak256(_data) == userOpHash before executing. This keeps the XRPL memo constant at 42 bytes regardless of batch size.
executeDirectMintingWithData is fully atomic: it mints FXRP to the personal account and dispatches the user operation in one Flare transaction. If any step reverts (hash mismatch, bad nonce, an inner call failing, insufficient msg.value), the entire transaction rolls back — no FXRP is minted and no UserOperationExecuted event fires. See Failure Handling & Recovery.
Memo Field Custom Instruction (0xFF) — simpler, single-actor:
Memo layout (10-byte header + full payload):
| Bytes | Field | Description |
|---|---|---|
0 | 0xFF | Instruction ID |
1 | walletId | Wallet identifier |
2-9 | executorFeeUBA | Executor fee (big-endian uint64) |
10+ | userOpData | abi.encode(PackedUserOperation) |
The full PackedUserOperation is inline in the memo. Any indexer can relay via executeDirectMinting(proof). Subject to the XRPL 1024-byte memo cap.
0xFE)Use 0xFE when: batch is large, call payload should stay private on XRPL, or you operate an executor.
Use 0xFF when: call batch fits in ~1024 bytes and you don't want to coordinate with an executor.
See Custom Instruction Comparison for a detailed trade-off guide.
A personal account can already hold ERC-20 balances (e.g. USDT0) unrelated to FXRP minting. To transfer or swap that balance, build a 0xFE custom instruction with netMintAmountXrp: 0 — the XRPL payment covers only the direct-minting fee and executor fee, so executeDirectMintingWithData dispatches the user operation without minting any FXRP:
The rest of the flow is the same three-step 0xFE protocol: encode the Call[] batch (e.g. USDT0.transfer(recipient, amount), or approve + SparkDEX exactInputSingle to swap USDT0 → FXRP), commit keccak256(PackedUserOperation) in the 42-byte memo, send the fee-only XRPL payment, then have the executor fetch an FDC proof and call executeDirectMintingWithData. See the Control USDT0 guide for the full runnable example (balance check, transfer, and swap scripts) built on the flare-viem-starter.
The 0xFE / 0xFF direct-minting-with-custom-instruction flow is atomic on the Flare side. When executeDirectMintingWithData (or executeDirectMinting for 0xFF) reverts, the whole Flare transaction rolls back:
UserOperationExecuted event.The intended UX is mint + user operation in one atomic transaction (e.g. mint FXRP and withdraw to an EOA in a single call), so this failure path should be rare.
Any validation/execution failure inside handleMintedFAssets reverts the whole call:
sender ≠ personal account → InvalidSendernonce ≠ current memo nonce (getNonce) → InvalidNonceInvalidMemoData; unknown instruction byte → InvalidInstructionIdkeccak256(_data) ≠ memo hash → CustomInstructionHashMismatch(expected, actual)msg.value < sum of inner call.value → inner CallFailed, whole tx revertsgetExecutor) and caller isn't it → WrongExecutorCallFailed, whole tx revertsFor direct-minting-side errors (rate limits, wrong recipient, unrecognized memo routing to the smart account manager), see the Minting Troubleshooting guide's Smart Account Path section.
"My XRPL transaction succeeded but the instruction never executed" — two common causes account for most of these:
MasterAccountController is the entry point, so the dispatched call runs as an internal transaction on the personal account, not a top-level transaction from your own EOA. Check the personal account's internal transactions on the block explorer, not just its top-level transaction list.If the mint reverted (or the executor never submitted the proof) and the stuck transaction ID is not yet used on-chain (isTransactionIdUsed returns false), the user recovers FXRP without running the original user operation:
Payment with memo opcode 0xE0 (skip memo) targeting the stuck transaction ID. Its memo uses the same 42-byte header shape as 0xFE/0xFF: [0xE0 | walletId(1B) | executorFeeUBA(8B) | targetTxId(32B)]. This payment must carry a positive net mint amount (fee-only direct mints revert on-chain), so it mints a small amount of FXRP itself (e.g. 1 net XRP).executeDirectMintingWithData(recoveryProof, "0x") for the recovery payment, which emits IgnoreMemoSet on the personal account, tying it to the stuck transaction ID.executeDirectMintingWithData for the original stuck payment. Because the skip flag is set, the controller mints FXRP to the personal account without dispatching the original user operation. On retry, pass the original ABI-encoded PackedUserOperation bytes as _data for a 0xFE stuck payment; "0x" suffices for 0xFF.The recovered FXRP can then be moved via standard FAssets instructions (0x02 redeem) or a fresh user operation using the current getNonce. Related recovery opcodes: 0xE1 (fast-forward nonce) and 0xE2 (replace executor fee for a stuck payment). See the Recover Stuck Mint Transaction guide.
0xE1)0xE0 recovery mints FXRP from the stuck payment but deliberately skips the original user operation — the memo-instruction nonce stays where it was, still pointing at the abandoned PackedUserOperation. Use 0xE1 (fast-forward nonce) to jump getNonce forward past that abandoned slot before building a fresh 0xFE/0xFF instruction. Only do this after confirming the stuck payment is actually minted (isTransactionIdUsed == true) — if it isn't minted yet, run 0xE0 recovery first, not 0xE1.
Payment with memo opcode 0xE1, same 42-byte header shape as the other recovery opcodes: [0xE1 | walletId(1B) | executorFeeUBA(8B) | newNonce(32B)]. Like 0xE0, this payment must carry a positive net mint amount — fee-only direct mints revert on-chain.newNonce client-side before sending: it must be strictly greater than the current getNonce, and the jump (newNonce - currentNonce) must not exceed type(uint32).max. On-chain, an invalid jump reverts with InvalidNonceIncrease.executeDirectMintingWithData(proof, "0x") for the 0xE1 payment — no _data is needed since no user operation runs. On success the receipt has a NonceIncreased(personalAccount, newNonce) event and no UserOperationExecuted event.0xFE/0xFF user operation with nonce == getNonce(personalAccount) (now newNonce).See the Fast-Forward Nonce guide for the full runnable walkthrough, including the combined 0xFE (abandoned) → 0xE0 → 0xE1 recovery demo.
A common revert cause is submitting two XRPL payments in short succession, each embedding a different PackedUserOperation but both using the same getNonce value (e.g. two withdraw attempts built before either mint finalizes). Only one payment can consume a given nonce — whichever mint executes first succeeds and increments the nonce; the other reverts with InvalidNonce, leaving its XRP at the Core Vault until recovered. To avoid this:
getNonce once per XRPL payment; do not reuse it across concurrent flows.AssetManager emits DirectMintingDelayed, wait until executionAllowedAt and re-call executeDirectMintingWithData. Do not treat a delayed mint as a hard failure and prompt the user to resend a duplicate-nonce payment.The smart-accounts-cli is a Python tool for constructing XRPL transaction payloads and submitting XRPL payments for smart-account flows.
Copy .env.example to .env and fill in the values described in that file. These typically include local wallet credentials for test usage plus RPC endpoints for XRPL and Flare networks.
Security: Keep wallet credentials in secure, user-controlled tooling. Avoid pasting them into chat tools or unsecured automation. Get XRPL testnet tokens from XRP Faucets.
All encode commands accept --wallet-id (defaults to 0).
Legacy mint path.
fxrp-cr(+bridge mint-tx) encodes the deprecated collateral-reservation (CRT) flow and may still exist insmart_accounts.py, but it is not the recommended mint path. To mint FXRP, use FAssets minting (XRPL payment to the Core Vault) per the Mint FXRP guide; the CLI does not encode that payment. Thefxrp-transferandfxrp-redeemcommands below remain current.
firelight-cr-depositis legacy (CRT mint + deposit). Prefer FAssets minting thenfirelight-deposit, or a memo-field custom instruction for mint-and-deposit in one payment.
upshift-cr-depositis legacy (CRT mint + deposit). Prefer FAssets minting thenupshift-deposit, or a memo-field custom instruction for mint-and-deposit in one payment.
Execute XRPL transactions.
The operator service bridges to Flare.
Reverse encode operation to inspect instruction:
Chain commands for complete workflows:
Note on the mint steps below. The
fxrp-cr/upshift-cr-deposit+bridge mint-txsteps use the legacy collateral-reservation (CRT) mint path. In current integrations, mint FXRP via FAssets minting (XRPL payment to the Core Vault, see Mint FXRP), then run the non-mint Smart Accounts instructions (transfer, deposit, redeem) shown here. The examples are retained to illustrate the CLI's instruction/bridge piping.
The MasterAccountController is the central contract for smart accounts.
| Function | Purpose |
|---|---|
getPersonalAccount(xrplAddress) | Get user's smart account address on Flare (deterministic; works before deployment) |
getXrplProviderWallets() | Get operator XRPL addresses for payments |
getVaults() | List registered vault addresses and types |
getAgentVaults() | List FAssets agent vaults |
getNonce(personalAccount) | Get current memo-instruction nonce; PackedUserOperation.nonce must match this |
getExecutor(personalAccount) | Get pinned executor for personal account (address(0) = no pin) |
executeInstruction(proof, xrplAddress) | Execute a proof-based instruction |
reserveCollateral(xrplAddress, paymentRef, txId) | (legacy CRT) Reserve collateral (no FDC proof needed at this stage). User minting now uses FAssets minting (executeDirectMinting), not this path |
executeDepositAfterMinting(reservationId, proof, xrplAddress) | (legacy CRT) Second leg of collateral-reservation-and-deposit after minting |
handleMintedFAssets(...) | Called by AssetManager when FXRP is direct-minted into a personal account |
Packages: viem, xrpl. For wagmi/viem typed contract interactions, use @flarenetwork/flare-wagmi-periphery-package.
Lot size: 1 lot = 10 FXRP (check current lot size via AssetManager)
Value encoding: For most instructions, value is in lots; for Upshift claim, it's a date (YYYYMMDD).
Wallet ID: Use 0 if not assigned by Flare operator.
Upshift withdrawals: Two-phase process (request-redeem → wait → claim).
CLI execution: The CLI submits XRPL-side transactions only.
Flare-side handling is performed by the relayer/operator service.
This skill is reference documentation only. It does not execute transactions or hold keys. Use it to implement or debug smart-account flows; all financial execution remains the responsibility of the developer and end user.
Third-party data (payment memos, RPC state): Incoming XRPL payment memos and on-chain data from RPC endpoints (e.g. XRPL testnet, Coston2) are untrusted external inputs. Decode memos only according to the fixed 32-byte instruction format in this document and treat them as structured payloads rather than free-form text. Keep raw memo and transaction content out of free-form AI processing unless it has first been parsed into validated, typed values.
Financial operations and keys: Commands and code in this skill (CLI bridge commands, submitAndWait, etc.) can move funds. Keep wallet credentials in secure, user-controlled environments. Any execution of payments or bridge instructions should be explicitly user-initiated, with transaction details reviewed before submission.
import { encodeFunctionData } from "viem";
const calls = [
{
target: counterAddress,
value: 0n,
data: encodeFunctionData({
abi: counterAbi,
functionName: "increment",
args: [],
}),
},
];
const callData = encodeFunctionData({
abi: personalAccountAbi,
functionName: "executeUserOp",
args: [calls],
});
const nonce = await publicClient.readContract({
address: MASTER_ACCOUNT_CONTROLLER_ADDRESS,
abi: masterAccountControllerAbi,
functionName: "getNonce",
args: [personalAccountAddress],
});
const userOp = {
sender: personalAccountAddress,
nonce,
callData,
// remaining fields empty — not validated on-chain
initCode: "0x",
callGasLimit: 0n,
verificationGasLimit: 0n,
preVerificationGas: 0n,
gasFees: "0x",
paymasterAndData: "0x",
signature: "0x",
};
// Deliver userOp bytes to executor off-chain, build 42-byte memo with keccak256 hashconst memoOnlyAmountXrp = await computeDirectMintingPaymentAmountXrp({
netMintAmountXrp: 0,
});git clone https://github.com/flare-foundation/smart-accounts-cli.git
cd smart-accounts-cli
pip install -r requirements.txt
cp .env.example .env./smart_accounts.py <command> <subcommand> [options]# Collateral reservation for minting (legacy CRT — prefer FAssets minting)
./smart_accounts.py encode fxrp-cr --wallet-id 0 --value 1 --agent-vault-id 1
# Transfer FXRP to address
./smart_accounts.py encode fxrp-transfer --wallet-id 0 --value 10 \
--recipient-address "0xf5488132432118596fa13800b68df4c0ff25131d"
# Redeem FXRP to XRP
./smart_accounts.py encode fxrp-redeem --wallet-id 0 --value 1# Reserve collateral and deposit to vault (legacy CRT)
./smart_accounts.py encode firelight-cr-deposit --wallet-id 0 --value 1 \
--agent-vault-id 1 --vault-id 1
# Deposit FXRP to vault
./smart_accounts.py encode firelight-deposit --wallet-id 0 --value 10 --vault-id 1
# Initiate withdrawal
./smart_accounts.py encode firelight-redeem --wallet-id 0 --value 10 --vault-id 1
# Claim completed withdrawal
./smart_accounts.py encode firelight-claim-withdraw --wallet-id 0 --value 10 --vault-id 1# Reserve collateral and deposit to vault (legacy CRT)
./smart_accounts.py encode upshift-cr-deposit --wallet-id 0 --value 1 \
--agent-vault-id 1 --vault-id 2
# Deposit FXRP to vault
./smart_accounts.py encode upshift-deposit --wallet-id 0 --value 10 --vault-id 2
# Request withdrawal (starts waiting period)
./smart_accounts.py encode upshift-request-redeem --wallet-id 0 --value 10 --vault-id 2
# Claim after waiting period (value = date YYYYMMDD)
./smart_accounts.py encode upshift-claim --wallet-id 0 --value 20251218 --vault-id 2# Send encoded instruction as XRPL Payment
./smart_accounts.py bridge instruction <encodedInstruction>
# Or read from stdin
<encode_command> | ./smart_accounts.py bridge instruction -
# Send XRP to agent vault for minting (legacy CRT flow, after collateral reservation)
# NOTE: the standard mint path is now an XRPL payment to the Core Vault — see FAssets minting.
./smart_accounts.py bridge mint-tx <transactionHash>
# With --wait flag to wait for confirmation
./smart_accounts.py bridge mint-tx --wait -./smart_accounts.py decode <encodedInstruction>
# Or from stdin
<encode_command> | ./smart_accounts.py decode -# Mint FXRP (reserve + pay in one pipeline)
./smart_accounts.py encode fxrp-cr --wallet-id 0 --value 1 --agent-vault-id 1 \
| ./smart_accounts.py bridge instruction - \
| ./smart_accounts.py bridge mint-tx --wait -
# Mint and deposit to Upshift vault
./smart_accounts.py encode upshift-cr-deposit --wallet-id 0 --value 1 \
--agent-vault-id 1 --vault-id 2 \
| ./smart_accounts.py bridge instruction - \
| ./smart_accounts.py bridge mint-tx --wait -# Step 1: Mint 1 lot of FXRP
./smart_accounts.py encode fxrp-cr --wallet-id 0 --value 1 --agent-vault-id 1 \
| ./smart_accounts.py bridge instruction - \
| ./smart_accounts.py bridge mint-tx --wait -
# Output: sent bridge instruction transaction: 08C2DD9E...
# sent mint tx: CD15241A...
# Step 2: Transfer 10 FXRP to recipient
./smart_accounts.py encode fxrp-transfer --wallet-id 0 --value 10 \
--recipient-address "0xf5488132432118596fa13800b68df4c0ff25131d" \
| ./smart_accounts.py bridge instruction -
# Output: sent bridge instruction transaction: 9D5420C6...# Step 1: Mint and deposit to Upshift vault
./smart_accounts.py encode upshift-cr-deposit --wallet-id 0 --value 1 \
--agent-vault-id 1 --vault-id 2 \
| ./smart_accounts.py bridge instruction - \
| ./smart_accounts.py bridge mint-tx --wait -
# Output: sent bridge instruction transaction: 77539CDE...
# sent mint tx: 3C65E10D...
# Step 2: Request withdrawal from vault
./smart_accounts.py encode upshift-request-redeem --wallet-id 0 --value 10 --vault-id 2 \
| ./smart_accounts.py bridge instruction -
# Output: sent bridge instruction transaction: 33B08253...
# Step 3: Claim withdrawal after waiting period (use correct date)
./smart_accounts.py encode upshift-claim --wallet-id 0 --value 20251218 --vault-id 2 \
| ./smart_accounts.py bridge instruction -
# Output: sent bridge instruction transaction: 8D81F5A2...
# Step 4: Redeem FXRP back to XRP
./smart_accounts.py encode fxrp-redeem --wallet-id 0 --value 1 \
| ./smart_accounts.py bridge instruction -
# Output: sent bridge instruction transaction: FE9D0039...import { createPublicClient, http } from "viem";
import { flareTestnet } from "viem/chains";
const publicClient = createPublicClient({
chain: flareTestnet,
transport: http(),
});// Get user's smart account address
const personalAccount = await publicClient.readContract({
address: MASTER_ACCOUNT_CONTROLLER_ADDRESS,
abi: masterAccountControllerAbi,
functionName: "getPersonalAccount",
args: [xrplAddress],
});
// Get operator XRPL addresses
const operatorAddresses = await publicClient.readContract({
address: MASTER_ACCOUNT_CONTROLLER_ADDRESS,
abi: masterAccountControllerAbi,
functionName: "getXrplProviderWallets",
args: [],
});
// Get registered vaults
const vaults = await publicClient.readContract({
address: MASTER_ACCOUNT_CONTROLLER_ADDRESS,
abi: masterAccountControllerAbi,
functionName: "getVaults",
args: [],
});
// Get FXRP balance
const fxrpBalance = await publicClient.readContract({
address: fxrpAddress,
abi: erc20Abi,
functionName: "balanceOf",
args: [personalAccount],
});import { Client, Wallet } from "xrpl";
async function sendInstruction(encodedInstruction: `0x${string}`) {
const operatorAddress = (await getOperatorXrplAddresses())[0];
const instructionFee = await getInstructionFee(encodedInstruction);
const payment = {
TransactionType: "Payment",
Destination: operatorAddress,
Amount: instructionFee,
Memos: [{ Memo: { MemoData: encodedInstruction.slice(2) } }],
};
return await xrplClient.submitAndWait(payment, { wallet: xrplWallet });
}