Skip to main content

Custom instructions

The Flare Smart Accounts allow XRPL users to make custom function calls on Flare through instructions sent on XRPL. In this guide we will look at how the custom instructions can be developed using a mock version of the MasterAccountController contract.

In a typical workflow the users sends instructions as memo data on XRPL. Those then have to be verified by the FDC on the Flare chain. That process requires waiting, which is less than ideal in a development environment.

For that reason, a mock version of the MasterAccountController contract has been deployed. It implements two additional functions:

  • createFundPersonalAccount
  • executeCustomInstructionDevelopment

The createFundPersonalAccount function creates a new PersonalAccount for the user. It accepts as its argument a string _xrplAddress, which represents and address on XRPL. The string is then concatenated with the msg.sender value; the PersonalAccount is created for this address.

Thus, a developer can create multiple XRPL "addresses". This allows them to more easily test the interactions between different personal accounts. The "address" is combined with their Flare address, so that they can give meaningful names to their "addresses" without a danger of multiple developers' addresses crashing.

The createFundPersonalAccount function is a payable function. And funds sent with the transaction are deposited to the newly created personal account. That way, the personal account can interact with payable functions from the get-go.

The executeCustomInstructionDevelopment function sidesteps the XRP transaction and the FDC Payment verification process. It allows developers to send an array of custom instructions to the MasterAccountController contract directly.

The two parameters this function takes are the _xrplAddress string, and an array of IMasterAccountController.CustomInstruction structs. It first concatenates the input string with the msg.sender value, the same way the createFundPersonalAccount function does. Then, it retrieves the PersonalAccount representing that address, and calls its custom function with the array of custom instructions it received as input.

A simple example

We will now use the Flare Smart Accounts CLI to interact with a simple contract. The contract Foo has a single payable function bar. The bar function accepts a uint256 value as input, and add the fee paid with the transaction to a mapping.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

contract Foo {
mapping(uint256 => uint256) public map;

function bar(uint256 a) public payable {
map[a] = map[a] + msg.value;
}
}

We want to send 1 FLR to the contract, and save it under number 42. The address of the Foo contract is 0x296432C15504Ed465fAce11E54Ce4aac50cCd8A3. Using an online ABI-encoding tool, we get that the following hash for the bar function, with 42 as input: 0x0423a132000000000000000000000000000000000000000000000000000000000000002a.

There are two ways we can go about developing the custom instructions. We will start with an approach, which is what the production code would take. Afterwards, we will use the the mock functions to speed up the development.

Normal approach

Before we can execute the above instructions we need to top up the smart account that will perform the function call. We run the following command, which fails because our account lacks funds on Flare. It is necessary to send some instructions, because that is what creates an account for us in the first place.

./smart_accounts.py bridge custom -a "0x296432C15504Ed465fAce11E54Ce4aac50cCd8A3" -v 1 -d "0423a132000000000000000000000000000000000000000000000000000000000000002a"

We then need to retrieve the smart account address.

./smart_accounts personal-account --from-env print

With the address, we can go to the Flare faucet and request C2FLR for the smart account address. We can also do this through the CLI.

./smart_accounts personal-account --from-env faucet

Afterwards, we can run the following command again. This time, it works.

./smart_accounts.py bridge custom -a "0x296432C15504Ed465fAce11E54Ce4aac50cCd8A3" -v 1 -d "0423a132000000000000000000000000000000000000000000000000000000000000002a"

Mocking

We can speed up the process, as well as simplify it, by using the Flare Smart Accounts CLI. First, we need to create a mock account, which we do with the command. This will only work if our Flare address has sufficient funds.

./smart_accounts mock-create-fund --seed "mockAccount" --value 1

Here we arbitrarily chose the name mockAccount as the account address. Behind the scenes, the string mockAccount will be concatenated with our Flare address.

Then, we execute the custom instructions. We use the string mockAccount as the seed.

./smart_accounts.py debug mock-custom -s "mockAccount" -a "0x296432C15504Ed465fAce11E54Ce4aac50cCd8A3" -v 1 -d "0423a132000000000000000000000000000000000000000000000000000000000000002a"