Skip to content

Commit 7852e86

Browse files
feat: get MasterAccountController address from FlareContractRegistry (#1243)
2 parents 2ae1d7f + 191b0da commit 7852e86

3 files changed

Lines changed: 44 additions & 47 deletions

File tree

docs/smart-accounts/guides/typescript-viem/01-state-lookup.mdx

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ The function returns an array of XRPL addresses; these are all the registered op
9898
```typescript
9999
export async function getOperatorXrplAddresses() {
100100
const result = await publicClient.readContract({
101-
address: MASTER_ACCOUNT_CONTROLLER_ADDRESS,
101+
address: await getMasterAccountControllerAddress(),
102102
abi: coston2.iMasterAccountControllerAbi,
103103
functionName: "getXrplProviderWallets",
104104
args: [],
@@ -107,12 +107,28 @@ export async function getOperatorXrplAddresses() {
107107
}
108108
```
109109
110-
Because the Flare smart accounts are still in development, the `MasterAccountController` contract has not yet been added to the `FlareContractRegistry` contract.
111-
That is the reason why the address of the `MasterAccountController` has been hardcoded in the example repository.
110+
We define a helper function for retrieving the address of the `MasterAccountController` contract from the `FlareContractsRegistry`.
112111
113112
```typescript
114-
export const MASTER_ACCOUNT_CONTROLLER_ADDRESS =
115-
"0x32F662C63c1E24bB59B908249962F00B61C6638f";
113+
export async function getMasterAccountControllerAddress(): Promise<Address> {
114+
return getContractAddressByName("MasterAccountController");
115+
}
116+
```
117+
118+
With the mainnet launch of the Flare smart accounts, the `MasterAccountController` has been added to the list of official Flare contracts.
119+
Its address can be obtained from the `FlareContractRegistry` contract by calling its `getContractAddressByName` function.
120+
121+
```typescript
122+
export async function getContractAddressByName(name: string) {
123+
const contractAddress = await publicClient.readContract({
124+
address: FLARE_CONTRACT_REGISTRY_ADDRESS,
125+
abi: coston2.iFlareContractRegistryAbi,
126+
functionName: "getContractAddressByName",
127+
args: [name],
128+
});
129+
130+
return contractAddress;
131+
}
116132
```
117133
118134
## Personal account of an XRPL address
@@ -125,7 +141,7 @@ It calls the `getPersonalAccount` function of the `MasterAccountController` cont
125141
```typescript
126142
export async function getPersonalAccountAddress(xrplAddress: string) {
127143
const personalAccountAddress = await publicClient.readContract({
128-
address: MASTER_ACCOUNT_CONTROLLER_ADDRESS,
144+
address: await getMasterAccountControllerAddress(),
129145
abi: coston2.iMasterAccountControllerAbi,
130146
functionName: "getPersonalAccount",
131147
args: [xrplAddress],
@@ -176,17 +192,6 @@ export async function getAssetManagerFXRPAddress(): Promise<Address> {
176192
await getContractAddressByName("AssetManagerFXRP");
177193
return assetManagerAddress;
178194
}
179-
180-
export async function getContractAddressByName(name: string) {
181-
const contractAddress = await publicClient.readContract({
182-
address: FLARE_CONTRACT_REGISTRY_ADDRESS,
183-
abi: coston2.iFlareContractRegistryAbi,
184-
functionName: "getContractAddressByName",
185-
args: [name],
186-
});
187-
188-
return contractAddress;
189-
}
190195
```
191196
192197
## Vaults and vault balances
@@ -215,7 +220,7 @@ export type GetVaultsReturnType = [bigint[], string[], number[]];
215220
216221
export async function getVaults(): Promise<Vault[]> {
217222
const _vaults = (await publicClient.readContract({
218-
address: MASTER_ACCOUNT_CONTROLLER_ADDRESS,
223+
address: await getMasterAccountControllerAddress(),
219224
abi: coston2.iMasterAccountControllerAbi,
220225
functionName: "getVaults",
221226
args: [],
@@ -271,7 +276,7 @@ export type GetAgentVaultsReturnType = [bigint[], string[]];
271276
272277
export async function getAgentVaults(): Promise<AgentVault[]> {
273278
const _vaults = await publicClient.readContract({
274-
address: MASTER_ACCOUNT_CONTROLLER_ADDRESS,
279+
address: await getMasterAccountControllerAddress(),
275280
abi: coston2.iMasterAccountControllerAbi,
276281
functionName: "getAgentVaults",
277282
args: [],

docs/smart-accounts/guides/typescript-viem/03-custom-instruction.mdx

Lines changed: 19 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@ The full code showcased in this guide is available on [GitHub](https://github.co
4040

4141
## Contracts
4242

43-
{/* TODO:(Nik) fix contract addresses and links */}
44-
4543
The first contract is a `Checkpoint` that counts how many times each user has called its `passCheckpoint` function.
4644
It is useless as anything other than an example.
4745
The first call of our custom instruction will be to call the `passCheckpoint` function of this contract, deploy at the address [`0xEE6D54382aA623f4D16e856193f5f8384E487002`](https://coston2-explorer.flare.network/address/0xEE6D54382aA623f4D16e856193f5f8384E487002?tab=contract).
@@ -212,8 +210,6 @@ const customInstructions = [
212210

213211
## Registering an instruction
214212

215-
{/* TODO:(Nik) fix the code for this when the contract gets fixed to not revert if the instruction has already been registered */}
216-
217213
Next, we need to register the custom instruction with the `MasterAccountController` contract.
218214
In order to read from the Flare chain, we first need to create a [Viem public client](https://viem.sh/docs/clients/public).
219215

@@ -227,33 +223,29 @@ export const publicClient = createPublicClient({
227223
});
228224
```
229225

230-
{/* TODO:(Nik) Update once MasterAccountController gets added to the FlareContractRegistry */}
231-
232-
We also need the address of the `MasterAccountController` contract.
233-
Since the Flare smart accounts are still in development, we cannot query the `FlareContractRegistry` for the `MasterAccountController` address.
234-
Instead, we need to hardcode it.
235-
236-
```typescript
237-
export const MASTER_ACCOUNT_CONTROLLER_ADDRESS =
238-
"0x32F662C63c1E24bB59B908249962F00B61C6638f";
239-
```
240-
241-
{/* TODO:(Nik) Check that the following is still relevant - how the register function works */}
242226
To register a custom instruction, we call the `registerCustomInstruction` function on the `MasterAccountController` contract and provide the custom instruction array as the argument.
243227
As recommended by the [Viem documentation](https://viem.sh/docs/contract/writeContract#writecontract), we first use the `simulateContract` function to prepare the request.
244228
Then we call the `writeContract` Viem function, and actually register the instruction.
245229

246230
If the instruction has already been registered, a `CustomInstructionAlreadyRegistered` event is emitted.
247231
Otherwise, the instruction is registered, and a `CustomInstructionRegistered` event is emitted instead.
248232

233+
We also need the address of the `MasterAccountController` contract, which we can look up by name using `getContractAddressByName` from the Flare Contract Registry.
234+
249235
```typescript
236+
export type CustomInstruction = {
237+
targetContract: Address;
238+
value: bigint;
239+
data: `0x${string}`;
240+
};
241+
250242
export async function registerCustomInstruction(
251243
instructions: CustomInstruction[],
252244
): Promise<`0x${string}`> {
253245
const { request } = await publicClient.simulateContract({
254246
account: account,
255-
address: MASTER_ACCOUNT_CONTROLLER_ADDRESS,
256-
abi: abi,
247+
address: await getMasterAccountControllerAddress(),
248+
abi: iCustomInstructionsFacetAbi,
257249
functionName: "registerCustomInstruction",
258250
args: [instructions],
259251
});
@@ -282,13 +274,13 @@ We need to replace the first two bytes with the following values:
282274
- 2nd byte: wallet identifier `walletId` described above
283275

284276
```typescript
285-
async function encodeCustomInstruction(
277+
export async function encodeCustomInstruction(
286278
instructions: CustomInstruction[],
287279
walletId: number,
288280
) {
289281
const encodedInstruction = (await publicClient.readContract({
290-
address: MASTER_ACCOUNT_CONTROLLER_ADDRESS,
291-
abi: abi,
282+
address: await getMasterAccountControllerAddress(),
283+
abi: iCustomInstructionsFacetAbi,
292284
functionName: "encodeCustomInstruction",
293285
args: [instructions],
294286
})) as `0x${string}`;
@@ -347,7 +339,7 @@ export async function getInstructionFee(encodedInstruction: string) {
347339
console.log("instructionIdDecimal:", instructionIdDecimal, "\n");
348340

349341
const requestFee = await publicClient.readContract({
350-
address: MASTER_ACCOUNT_CONTROLLER_ADDRESS,
342+
address: await getMasterAccountControllerAddress(),
351343
abi: coston2.iMasterAccountControllerAbi,
352344
functionName: "getInstructionFee",
353345
args: [instructionIdDecimal],
@@ -367,8 +359,6 @@ const xrplWallet = Wallet.fromSeed(process.env.XRPL_SEED!);
367359

368360
## Wait for instruction execution
369361

370-
{/* TODO:(Nik) update ABI */}
371-
372362
Lastly, we need to wait for the operator to bridge the instruction from XRPL to Flare, and for the instruction to be executed.
373363
Once it does, our personal account executes the instruction, and the `CustomInstructionExecuted` event is emitted by the `MasterAccountController` contract.
374364
We watch for such events with the [`watchContractEvent`](https://viem.sh/docs/contract/watchContractEvent#watchcontractevent) Viem function.
@@ -383,7 +373,7 @@ If the value is `false`, we wait for `10` seconds, then check again.
383373
Once the value has been found, we stop observing the contract and return the event.
384374

385375
```typescript
386-
async function waitForCustomInstructionExecutedEvent({
376+
export async function waitForCustomInstructionExecutedEvent({
387377
encodedInstruction,
388378
personalAccountAddress,
389379
}: {
@@ -396,7 +386,7 @@ async function waitForCustomInstructionExecutedEvent({
396386
let customInstructionExecutedEventFound = false;
397387

398388
const unwatchCustomInstructionExecuted = publicClient.watchContractEvent({
399-
address: MASTER_ACCOUNT_CONTROLLER_ADDRESS,
389+
address: await getMasterAccountControllerAddress(),
400390
abi: iInstructionsFacetAbi,
401391
eventName: "CustomInstructionExecuted",
402392
onLogs: (logs) => {
@@ -432,6 +422,7 @@ The vehicle for bridging the instruction is the [Flare Data Connector](/fdc/over
432422
## Full script
433423

434424
The repository with the above example is available on [GitHub](https://github.com/flare-foundation/flare-smart-accounts-viem).
425+
In the example repository, certain functions are isolated into separate files in the `src/utils` directory.
435426

436427
<CodeBlock language="typescript" title="src/custom-instructions.ts">
437428
{CustomInstructionsScript}
@@ -470,7 +461,7 @@ request: {
470461
type: 'function'
471462
}
472463
],
473-
address: '0x434936d47503353f06750Db1A444DBDC5F0AD37c',
464+
address: '0x32F662C63c1E24bB59B908249962F00B61C6638f',
474465
args: [ [ [Object], [Object], [Object] ] ],
475466
dataSuffix: undefined,
476467
functionName: 'registerCustomInstruction',
@@ -508,7 +499,7 @@ CustomInstructionExecuted event: {
508499
callHash: '0x0000e54bf1b4e93c5306e08d919864ec111211c4fb36960261e8018da9959791',
509500
customInstruction: [ [Object], [Object], [Object] ]
510501
},
511-
address: '0x434936d47503353f06750db1a444dbdc5f0ad37c',
502+
address: '0x32f662c63c1e24bb59b908249962f00b61c6638f',
512503
topics: [
513504
'0x1c09418c54894f576841186935c5f666b3bedd66c29f3a03bcab4051fe2509f3',
514505
'0x000000000000000000000000fd2f0eb6b9fa4fe5bb1f7b26fee3c647ed103d9f',

lychee.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,5 @@ exclude = [
2626
'^https://coston2\.testnet\.flarescan\.com/',
2727
'^https://jq-verifier-test\.flare\.rocks',
2828
'^https://jq-verifier-test.flare.rocks',
29+
'^https://console\.cloud\.google\.com/',
2930
]

0 commit comments

Comments
 (0)