Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions docs/smart-accounts/1-overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -155,15 +155,15 @@ Instructions for interacting with an Upshift-type vault.

The XRPL memo for the direct-minting flow selects one of the following opcodes in its first byte:

| Memo opcode | Action | Description |
| ----------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `0xFE` | Custom Instruction | Carry `keccak256(PackedUserOperation)` in the memo; the bytes are delivered off-chain by an executor. See [Custom Instruction](/smart-accounts/custom-instruction). |
| `0xFF` | Raw Custom Instruction | Carry the full ABI-encoded `PackedUserOperation` inline in the memo. See [Raw Custom Instruction](/smart-accounts/raw-custom-instruction). |
| `0xE0` | Skip memo | Mark a target XRPL transaction's memo to be skipped on its next direct mint. |
| `0xE1` | Fast-forward nonce | Advance the personal account's memo-instruction 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. |
| Memo opcode | Action | Description |
| ----------- | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `0xFE` | Custom Instruction | Carry `keccak256(PackedUserOperation)` in the memo; the bytes are delivered off-chain by an executor. See [Custom Instruction](/smart-accounts/custom-instruction). |
| `0xFF` | Memo Field Custom Instruction | Carry the full ABI-encoded `PackedUserOperation` inline in the memo. See [Memo Field Custom Instruction](/smart-accounts/memo-field-custom-instruction). |
| `0xE0` | Skip memo | Mark a target XRPL transaction's memo to be skipped on its next direct mint. |
| `0xE1` | Fast-forward nonce | Advance the personal account's memo-instruction 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. |

The [Custom Instruction Comparison](/smart-accounts/custom-instruction-comparison) covers when to choose `0xFE` over `0xFF`.

Expand Down Expand Up @@ -197,7 +197,7 @@ It enforces that the caller is the `AssetManager`, resolves (or deploys) the use
The XRPL user's smart account performs the actions in the instructions.
This can be any of the instructions listed above, reserving collateral for minting FXRP, transferring FXRP to another address, redeeming FXRP, depositing it into a vault ...
Furthermore, custom instructions can be executed - arbitrary function calls on Flare, encoded as an [EIP-4337](https://eips.ethereum.org/EIPS/eip-4337) `PackedUserOperation` and replayed on-chain by the personal account.
The user operation can be committed to as a 32-byte hash with the bytes delivered to Flare by an off-chain executor (opcode `0xFE`, see the [Custom Instruction guide](/smart-accounts/custom-instruction)), or carried in the XRPL memo in full (opcode `0xFF`, see the [Raw Custom Instruction guide](/smart-accounts/raw-custom-instruction)).
The user operation can be committed to as a 32-byte hash with the bytes delivered to Flare by an off-chain executor (opcode `0xFE`, see the [Custom Instruction guide](/smart-accounts/custom-instruction)), or carried in the XRPL memo in full (opcode `0xFF`, see the [Memo Field Custom Instruction guide](/smart-accounts/memo-field-custom-instruction)).
Authorization comes from the XRPL `Payment` signature itself; the on-chain check only validates the `sender` and `nonce` fields of the `PackedUserOperation`.
The [Custom Instruction Comparison](/smart-accounts/custom-instruction-comparison) covers when to pick each.

Expand Down
6 changes: 3 additions & 3 deletions docs/smart-accounts/3-custom-instruction.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ The **custom instruction** (memo opcode `0xFE`) is the recommended way to drive
The XRPL memo is a fixed 42 bytes that commits to a `PackedUserOperation` by carrying only its `keccak256` hash, and an off-chain executor delivers the actual user operation bytes to the FAssets `AssetManager` on Flare.
This keeps the XRPL footprint constant regardless of how complex the call batch is.

For the simpler single-actor variant that ships the entire `PackedUserOperation` inline in the XRPL memo, see the [Raw Custom Instruction](/smart-accounts/raw-custom-instruction); the [comparison guide](/smart-accounts/custom-instruction-comparison) covers when to pick which.
For the simpler single-actor variant that ships the entire `PackedUserOperation` inline in the XRPL memo, see the [Memo Field Custom Instruction](/smart-accounts/memo-field-custom-instruction); the [comparison guide](/smart-accounts/custom-instruction-comparison) covers when to pick which.

:::warning No destination tags
XRPL transactions targeting smart accounts must not use a destination tag.
Expand Down Expand Up @@ -110,7 +110,7 @@ The custom instruction memo is a constant 42 bytes:
| `10-41` | `userOpHash` | `keccak256(abi.encode(userOp))` - the 32-byte commitment |

The memo length is independent of the call batch: a single small call and a 50-call batch both fit in the same 42 bytes, because the user-operation bytes the executor delivers off-chain never touch the XRPL ledger.
This is the main practical advantage over the [Raw Custom Instruction](/smart-accounts/raw-custom-instruction), whose memo carries the entire ABI-encoded `PackedUserOperation` and is therefore subject to the XRPL's 1024-byte memo cap.
This is the main practical advantage over the [Memo Field Custom Instruction](/smart-accounts/memo-field-custom-instruction), whose memo carries the entire ABI-encoded `PackedUserOperation` and is therefore subject to the XRPL's 1024-byte memo cap.

The off-chain delivery also makes the call payload **private on XRPL**.
Only the 32-byte commitment is published; the inner `target`, `value`, and `data` of each call only become visible when the executor submits the user operation to Flare.
Expand Down Expand Up @@ -211,6 +211,6 @@ The minted FXRP remains in the personal account and the user can recover by eith
## Next steps

- Walk through a Viem implementation in the [Custom Instruction TypeScript guide](/smart-accounts/guides/typescript-viem/custom-instruction-ts).
- See the simpler single-actor variant in the [Raw Custom Instruction](/smart-accounts/raw-custom-instruction).
- See the simpler single-actor variant in the [Memo Field Custom Instruction](/smart-accounts/memo-field-custom-instruction).
- Compare the two flows in the [Custom Instruction Comparison](/smart-accounts/custom-instruction-comparison).
- Dig into `IMasterAccountController` in the [reference](/smart-accounts/reference/IMasterAccountController).
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
sidebar_position: 1
slug: raw-custom-instruction
title: Raw Custom Instruction
slug: memo-field-custom-instruction
title: Memo Field Custom Instruction
authors: [nikerzetic]
description: Performing custom function calls in the Flare Smart Accounts by carrying the full PackedUserOperation in the XRPL memo.
tags: [intermediate, ethereum, flare-smart-accounts]
Expand All @@ -16,11 +16,11 @@ keywords:
]
---

The **raw custom instruction** (memo opcode `0xFF`) is a single-actor variant of the [Custom Instruction](/smart-accounts/custom-instruction): instead of committing to a `keccak256(userOp)` hash and relying on an executor to deliver the bytes, the XRPL `Payment` memo carries the entire ABI-encoded `PackedUserOperation` inline immediately after a 10-byte header.
The **memo field custom instruction** (memo opcode `0xFF`) is a single-actor variant of the [Custom Instruction](/smart-accounts/custom-instruction): instead of committing to a `keccak256(userOp)` hash and relying on an executor to deliver the bytes, the XRPL `Payment` memo carries the entire ABI-encoded `PackedUserOperation` inline immediately after a 10-byte header.
The user signs the XRPL `Payment`, ships the payload on XRPL, and the smart account replays the user operation on Flare with no further off-chain data.

The recommended path is the [Custom Instruction](/smart-accounts/custom-instruction) - it lifts the XRPL memo size cap and is what the rest of the smart-accounts tooling defaults to.
Reach for the raw variant when you do not want to operate or coordinate with an executor and your call batch fits inside the XRPL memo cap.
Reach for the memo field variant when you do not want to operate or coordinate with an executor and your call batch fits inside the XRPL memo cap.
The [comparison guide](/smart-accounts/custom-instruction-comparison) breaks down when each is appropriate.

This page covers only what differs from the [Custom Instruction](/smart-accounts/custom-instruction).
Expand All @@ -37,7 +37,7 @@ The XRPL memo carries a 10-byte instruction header followed by the ABI-encoded `

| Bytes | Field | Meaning |
| ----- | ---------------- | --------------------------------------------------------------------------- |
| `0` | `instructionId` | `0xFF` - raw custom instruction |
| `0` | `instructionId` | `0xFF` - memo field custom instruction |
| `1` | `walletId` | One-byte wallet identifier assigned by Flare; `0` if not registered |
| `2-9` | `executorFeeUBA` | Executor fee in the FAsset's smallest unit, big-endian `uint64` |
| `10+` | `userOpData` | `abi.encode(PackedUserOperation)` - the call payload the controller decodes |
Expand Down Expand Up @@ -70,7 +70,7 @@ The freshly minted FXRP remains in the personal account, and the user can either

## Next Steps

- Walk through a Viem implementation in the [Raw Custom Instruction TypeScript guide](/smart-accounts/guides/typescript-viem/raw-custom-instruction-ts).
- Walk through a Viem implementation in the [Memo Field Custom Instruction TypeScript guide](/smart-accounts/guides/typescript-viem/memo-field-custom-instruction-ts).
- Read the [Custom Instruction](/smart-accounts/custom-instruction) for the recommended hash-commitment variant.
- Compare the two flows in the [Custom Instruction Comparison](/smart-accounts/custom-instruction-comparison).
- Dig into `IMasterAccountController` in the [reference](/smart-accounts/reference/IMasterAccountController).
16 changes: 8 additions & 8 deletions docs/smart-accounts/5-custom-instruction-comparison.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ sidebar_position: 1
slug: custom-instruction-comparison
title: Custom Instruction Comparison
authors: [nikerzetic]
description: Comparing the raw (0xFF) and hash-based (0xFE) custom instruction flows for Flare Smart Accounts.
description: Comparing the memo field (0xFF) and hash-based (0xFE) custom instruction flows for Flare Smart Accounts.
tags: [intermediate, ethereum, flare-smart-accounts]
keywords:
[
Expand All @@ -20,7 +20,7 @@ Flare Smart Accounts expose two custom instruction memo opcodes that ultimately

- [**Custom Instruction**](/smart-accounts/custom-instruction) - opcode `0xFE`.
The XRPL memo carries only `keccak256(userOp)` in fixed 42 bytes; an off-chain executor delivers the ABI-encoded custom instruction (`userOp`) via `executeDirectMintingWithData`.
- [**Raw Custom Instruction**](/smart-accounts/raw-custom-instruction) - opcode `0xFF`.
- [**Memo Field Custom Instruction**](/smart-accounts/memo-field-custom-instruction) - opcode `0xFF`.
The XRPL memo contains the ABI-encoded `PackedUserOperation` in full.

Both flows are validated on-chain against the same `(sender, nonce)` rules and emit the same [`UserOperationExecuted`](/smart-accounts/reference/IMasterAccountController#useroperationexecuted) event.
Expand All @@ -31,7 +31,7 @@ The `0xFE` memo is a constant 42 bytes regardless of the user's operation size,

## Comparison

| Dimension | [Custom Instruction](/smart-accounts/custom-instruction) (`0xFE`) | [Raw Custom Instruction](/smart-accounts/raw-custom-instruction) (`0xFF`) |
| Dimension | [Custom Instruction](/smart-accounts/custom-instruction) (`0xFE`) | [Memo Field Custom Instruction](/smart-accounts/memo-field-custom-instruction) (`0xFF`) |
| ---------------------------------- | --------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| XRPL memo payload | 10-byte header + `keccak256(userOp)` (fixed 42 bytes) | 10-byte header + `abi.encode(PackedUserOperation)` |
| XRPL memo size | Constant 42 bytes regardless of batch size | Grows linearly with batch and argument sizes; capped at ~1024 bytes |
Expand All @@ -41,7 +41,7 @@ The `0xFE` memo is a constant 42 bytes regardless of the user's operation size,
| AssetManager entry point | `executeDirectMintingWithData(proof, data)` | `executeDirectMinting(proof)` |
| `msg.value` on the inner call | Whatever the executor attaches; forwarded to `executeUserOp` | Whatever the relayer attaches; forwarded to `executeUserOp` |
| Confirmation | Same event lives in the executor's transaction receipt | Watch for `UserOperationExecuted` after the `MasterAccountController` dispatches the memo |
| Replay protection | Same as raw - plus the on-chain hash check pins `_data` to the memo's commitment | Personal account nonce + `usedTransactionIds` |
| Replay protection | Same as memo field - plus the on-chain hash check pins `_data` to the memo's commitment | Personal account nonce + `usedTransactionIds` |
| Failure modes specific to the flow | `CustomInstructionHashMismatch` if `keccak256(_data)` differs from the commitment | None beyond shared ones |

**Use the custom instruction (`0xFE`) when**
Expand All @@ -52,15 +52,15 @@ The `0xFE` memo is a constant 42 bytes regardless of the user's operation size,
- You already operate an executor that observes XRPL payments and submits Flare transactions - the custom instruction lets that executor batch deliveries or rate-limit submissions without splitting user operations into multiple XRPL payments.
- You need fee predictability: the XRPL memo is always 42 bytes, so the XRPL fee is constant regardless of how complex the user operation is.

**Use the raw custom instruction (`0xFF`) when**
**Use the memo field custom instruction (`0xFF`) when**

- The call batch fits comfortably inside the XRPL ~1024-byte memo (most single-call user operations and small batches do).
- You do not need to hide the call payload from public XRPL observers.
- You do not want to operate or coordinate with an executor service.
- You want the simplest possible on-chain integration: a single FAssets transaction `executeDirectMinting(proof)` carries the whole thing.

In short, the custom instruction trades a small amount of off-chain coordination (and one extra on-chain proof-binding check) for a fixed memo size and private payloads.
The raw custom instruction trades memo bandwidth for end-to-end simplicity.
The memo field custom instruction trades memo bandwidth for end-to-end simplicity.

## Similarities

Expand All @@ -78,13 +78,13 @@ The two flows share more than they differ:
The example helpers in [`flare-viem-starter`](https://github.com/flare-foundation/flare-viem-starter) mirror the two flows directly:

- Custom Instruction: [`sendHashInstruction`](/smart-accounts/guides/typescript-viem/custom-instruction-ts#step-1-send-the-hash-memo-on-xrpl) + [`executeDirectMintingWithData`](/smart-accounts/guides/typescript-viem/custom-instruction-ts#step-2-executor-submits-the-proof-and-the-bytes) + [`findUserOperationExecuted`](/smart-accounts/guides/typescript-viem/custom-instruction-ts#step-3-confirm-execution-from-the-receipt) - three calls, one per actor.
- Raw Custom Instruction: [`sendMemoFieldInstruction`](/smart-accounts/guides/typescript-viem/raw-custom-instruction-ts#sending-the-user-operation) - one call, waits for the event.
- Memo Field Custom Instruction: [`sendMemoFieldInstruction`](/smart-accounts/guides/typescript-viem/memo-field-custom-instruction-ts#sending-the-user-operation) - one call, waits for the event.

A practical decision rule when integrating:

1. Default to the custom instruction (`0xFE`).
It fits every call batch and keeps the call payload off the public XRPL ledger.
2. Reach for the raw custom instruction (`0xFF`) only when you do not want to operate or coordinate with an executor service, and you can guarantee `abi.encode(userOp)` stays well under ~900 bytes (leaving room for the 10-byte header and XRPL framing).
2. Reach for the memo field custom instruction (`0xFF`) only when you do not want to operate or coordinate with an executor service, and you can guarantee `abi.encode(userOp)` stays well under ~900 bytes (leaving room for the 10-byte header and XRPL framing).

## Reference

Expand Down
Loading
Loading