You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Flare Smart Accounts allow users to execute custom function calls on the Flare chain through instructions on XRPL.
23
-
The process expands on the workflow for other actions by including an additional step at the beginning.
24
-
25
-
In order for the `MasterAccountController` contract to be able to give a custom instruction to a personal account, the custom action must first be registered with the said contract.
26
-
The custom instruction is stored in a mapper, with its 30-byte hash as a key.
27
-
That hash is then sent as the payment reference, along with the byte representation of the hexadecimal number `ff` (decimal `255`) in the first byte and the `walletId` in the second byte.
28
-
The `walletId` is a Flare-designated value, used by the operator for wallet identification.
29
-
30
-
<div
31
-
style={{
32
-
width: "90%",
33
-
margin: "0 auto",
34
-
display: "flex",
35
-
justifyContent: "center",
36
-
}}
37
-
>
38
-
<ThemedImage
39
-
alt="Breakdown of bytes in payment reference for the custom action"
We expand the workflow described in the [Flare Smart Accounts overview](/smart-accounts/overview) with an additional step before the first.
55
-
56
-
0. A custom instruction is registered with the `MasterAccountController` contract.
57
-
1. The XRPL user sends instructions as a `Payment` transaction to a specific XRPL address, with instructions encoded as the payment reference in the memo field.
58
-
2. The operator interacts with the [Flare Data Connector](/fdc/overview) to procure a `Payment` proof.
59
-
It then calls the `executeTransaction` function on the `MasterAccountController` contract, with the `Payment` proof and the XRPL address that made the transaction.
60
-
3. The XRPL user's smart account performs the actions given in the instructions.
61
-
62
-
## Custom Instructions
63
-
64
-
Custom instructions are an array of the `CustomInstructions.CustomCall` Solidity struct.
65
-
The struct contains three fields:
66
-
67
-
-`targetContract`: the address of the smart contract that will execute the custom function
68
-
-`value`: the amount of FLR paid to the contract
69
-
-`data`: transaction calldata, which includes a function selector and values of the function's arguments
70
-
71
-
Each of the custom instructions in the array will be performed in order.
72
-
A call to the `targetContract` address is made, with the specified `value` and the calldata `data`.
73
-
74
-
In Solidity, we can obtain the calldata by doing the following:
where `<functionName>` is the name of the function that we want to call, `<type1>`, `<type2>`, . . . , `<typeN>` are its argument types, and `<value1>`, `<value2>`, . . . , `<valueN>` their values.
22
+
Flare Smart Accounts let an XRPL user execute arbitrary contract calls on Flare trough the [`Payment`](https://xrpl.org/docs/references/protocol/transactions/types/payment) transaction on the XRPL blockchain.
23
+
Each personal account exposes an [EIP-4337](https://eips.ethereum.org/EIPS/eip-4337) style `executeUserOp` entry point that the [`MasterAccountController`](/smart-accounts/reference/IMasterAccountController) invokes when it processes a custom instruction memo.
81
24
82
-
Only function calls with specific parameter values included can be registered.
83
-
That means that a new custom instruction needs to be registered for each unique action (though this can be done just seconds in advance).
84
-
It is also the reason why special FAsset actions have their own IDs, instead of defaulting to the custom call - it allows us to also specify certain parameters within the instructions on XRPL.
25
+
Custom instructions carry the full call payload in the XRPL **memo** field.
26
+
The user signs a `PackedUserOperation`, ships it on XRPL, and the smart account replays it on the Flare blockchain.
85
27
86
-
:::warning
87
-
Encoding calldata by hand is error prone.
88
-
It is recommended to use established libraries, or an [online tool](https://abi.hashex.org/) (if you want to quickly check something).
28
+
:::warning No destination tags
29
+
XRPL transactions targeting smart accounts must not use a destination tag.
30
+
A destination tag forces [FAssets direct minting](/fassets/direct-minting) to credit the tag-holder, which would let an unrelated party front-run the user operation.
89
31
:::
90
32
91
-
## Call hash
33
+
## User operation payload
92
34
93
-
To produce the custom instructions calldata, we first ABI encode the array of the `CustomInstructions.CustomCall` struct.
94
-
We then take the `keccak256` hash of that value, and drop the first two bytes (`(1 << 240) - 1` shifts the number binary number `1` left `30*8` times, and replaces it with `0` and all the `0`s that follow it with `1`; essentially, we create a mask of length `30*8` of only `1`s).
95
-
That is the call hash that is provided as the payment reference for the custom action, and the ID under which the custom instructions are stored in the `MasterAccountController` contract.
35
+
The custom instruction payload has two layers: the outer EIP-4337 [`PackedUserOperation`](https://eips.ethereum.org/EIPS/eip-4337#useroperation) carried in the XRPL memo, and the inner [`executeUserOp(Call[])`](/smart-accounts/reference/IPersonalAccount#executeuserop) that the personal account runs once the controller dispatches it.
Only three fields from the [`PackedUserOperation`](https://eips.ethereum.org/EIPS/eip-4337#useroperation) struct are required for Flare Smart Accounts:
38
+
39
+
-`sender`**must** equal the address of the personal account derived from the XRPL sender.
40
+
Use [`getPersonalAccount`](/smart-accounts/reference/IMasterAccountController#getpersonalaccount) to look it up — the address is deterministic, so you can fetch it before the account is even deployed.
41
+
-`nonce`**must** equal the personal account's current nonce returned by [`getNonce`](/smart-accounts/reference/IMasterAccountController#getnonce).
42
+
The nonce auto-increments on every successful execution to prevent replay.
43
+
-`callData` is the calldata that the controller invokes on the personal account.
44
+
In practice, this is `abi.encodeCall(IPersonalAccount.executeUserOp, (calls))` — anything else either reverts or is rejected by the personal account's `onlyController` modifier.
45
+
46
+
The remaining fields are not validated on-chain and can be left empty.
47
+
Authorization comes from the XRPL signature on the `Payment` XRPL payment transaction itself: only the XRPL key for `sender`'s `xrplOwner` can deliver the memo.
48
+
If the personal account has pinned an executor via [`getExecutor`](/smart-accounts/reference/IMasterAccountController#getexecutor), only that executor is permitted to relay the mint.
100
49
101
-
The call hash can also be obtained through the `encodeCustomInstruction` helper function of the `MasterAccountController` contract.
The personal account's [`executeUserOp(Call[])`](/smart-accounts/reference/IPersonalAccount#executeuserop) runs each entry in the `Call[]` in order, forwarding it with its supplied `value` and `data`:
53
+
54
+
```solidity
55
+
struct Call {
56
+
address target;
57
+
uint256 value;
58
+
bytes data;
59
+
}
60
+
61
+
function executeUserOp(Call[] calldata _calls) external payable;
109
62
```
110
63
111
-
Behind the scenes, the `MasterAccountController` contract calls the `encodeCustomInstruction` function of the `CustomInstructions` library.
64
+
Each call is dispatched with the personal account as `msg.sender`.
65
+
If any call reverts, the whole user operation reverts with [`CallFailed`](/smart-accounts/reference/IPersonalAccount#callfailed) — partial execution is not possible.
66
+
67
+
The `executeUserOp` function is `payable`, so the user operation can forward native tokens (e.g. FLR) alongside the calls.
68
+
To fund the personal account, send FLR to the address using the [Flare faucet](https://faucet.flare.network/).
You can build the `callData` in TypeScript using the [`encodeFunctionData`](https://viem.sh/docs/contract/encodeFunctionData#encodefunctiondata) function from the `viem` library:
122
73
74
+
```typescript
75
+
import { encodeFunctionData } from"viem";
76
+
77
+
const calls = [
78
+
{
79
+
target: counterAddress,
80
+
value: 0n,
81
+
data: encodeFunctionData({
82
+
abi: counterAbi,
83
+
functionName: "increment",
84
+
args: [],
85
+
}),
86
+
},
87
+
];
88
+
89
+
const callData =encodeFunctionData({
90
+
abi: personalAccountAbi,
91
+
functionName: "executeUserOp",
92
+
args: [calls],
93
+
});
123
94
```
124
95
125
-
## 0. Register custom instructions
126
-
127
-
We register a custom instruction by calling the `registerCustomInstruction` function on the `MasterAccountController` contract.
128
-
The `CustomInstructions.CustomCall` array is provided as an argument.
129
-
It is encoded as described above and stored in a `CustomInstructions` mapping.
130
-
131
-
To obtain the instruction that can be sent as the memo of an XRPL Payment transaction, we take the call hash produced by the `encodeCustomInstruction` function and modify it the following way.
132
-
First, we remove the initial two bytes from this hash.
133
-
Next, we prepend the hexadecimal value `ff` followed by the `walletId`.
The encoded `callData` becomes the `callData` field of the `PackedUserOperation` struct placed in the XRPL payment memo field.
97
+
98
+
## Replay protection
99
+
100
+
Each personal account maintains a monotonically increasing nonce, accessible via [`getNonce`](/smart-accounts/reference/IMasterAccountController#getnonce).
101
+
A successful `executeUserOp` increments the nonce and emits [`UserOperationExecuted`](/smart-accounts/reference/IMasterAccountController#useroperationexecuted), so the same `PackedUserOperation` cannot be re-executed.
102
+
103
+
## Failure Handling
104
+
105
+
The whole pipeline is atomic with respect to the user operation:
106
+
107
+
- If `sender` does not match the personal account, the call reverts with [`InvalidSender`](/smart-accounts/reference/IMasterAccountController#invalidsender).
108
+
- If `nonce` is not the expected value, it reverts with [`InvalidNonce`](/smart-accounts/reference/IMasterAccountController#invalidnonce).
109
+
- If the memo body has the wrong length for its instruction ID, it reverts with [`InvalidMemoData`](/smart-accounts/reference/IMasterAccountController#invalidmemodata); an unrecognized instruction byte reverts with [`InvalidInstructionId`](/smart-accounts/reference/IMasterAccountController#invalidinstructionid).
110
+
- If any inner call reverts, the personal account surfaces it as [`CallFailed`](/smart-accounts/reference/IPersonalAccount#callfailed) and the entire user operation reverts.
111
+
112
+
Because the FXRP transfer is performed before the memo is decoded, **the mint succeeds even if the user operation reverts** — see [`DirectMintingExecuted`](/smart-accounts/reference/IMasterAccountController#directmintingexecuted).
113
+
The freshly minted FXRP remains in the personal account, and the user can either re-submit a fixed user operation or transfer the FXRP to another address via standard [FAssets instructions](/smart-accounts/fasset-instructions).
Copy file name to clipboardExpand all lines: docs/smart-accounts/guides/cli/01-introduction.mdx
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -21,7 +21,7 @@ import ThemedImage from "@theme/ThemedImage";
21
21
importuseBaseUrlfrom"@docusaurus/useBaseUrl";
22
22
23
23
The [Flare Smart Accounts CLI](https://github.com/flare-foundation/smart-accounts-cli) is a tool written in Python that streamlines the Flare Smart Accounts process by properly structuring and sending XRPL transactions/instructions.
24
-
It has commands corresponding to each Flare Smart Accounts action ([table of instructions](/smart-accounts/overview#1-instructions-on-xrpl)), as well as other useful debugging features.
24
+
It has commands corresponding to each Flare Smart Accounts action ([table of instructions](/smart-accounts/overview#instructions-on-xrpl)), as well as other useful debugging features.
25
25
26
26
:::note
27
27
The CLI executes **only** the transaction on XRPL.
0 commit comments