Skip to content

Commit f8627c2

Browse files
authored
Merge pull request #144 from 0xMiden/wiktor-adjust-fpi-tutorial
fix: Adjust the FPI tutorial to 0.12
2 parents ea827c7 + 838d70e commit f8627c2

File tree

2 files changed

+224
-261
lines changed

2 files changed

+224
-261
lines changed

docs/src/web-client/foreign_procedure_invocation_tutorial.md

Lines changed: 107 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -136,12 +136,10 @@ export async function foreignProcedureInvocation(): Promise<void> {
136136
AccountComponent,
137137
AccountId,
138138
AccountType,
139-
AssemblerUtils,
139+
MidenArrays,
140+
SecretKey,
140141
StorageSlot,
141-
TransactionKernel,
142142
TransactionRequestBuilder,
143-
TransactionScript,
144-
TransactionScriptInputPairArray,
145143
ForeignAccount,
146144
AccountStorageRequirements,
147145
WebClient,
@@ -159,62 +157,60 @@ export async function foreignProcedureInvocation(): Promise<void> {
159157

160158
// Count reader contract code in Miden Assembly (exactly from count_reader.masm)
161159
const countReaderCode = `
162-
use.miden::account
160+
use.miden::active_account
161+
use miden::native_account
163162
use.miden::tx
164163
use.std::sys
165164
166165
# => [account_id_prefix, account_id_suffix, get_count_proc_hash]
167166
export.copy_count
168167
exec.tx::execute_foreign_procedure
169168
# => [count]
170-
171-
debug.stack
172-
# => [count]
173-
169+
174170
push.0
175171
# [index, count]
176-
177-
exec.account::set_item
178-
# => []
179-
180-
push.1 exec.account::incr_nonce
172+
173+
debug.stack
174+
175+
exec.native_account::set_item dropw
181176
# => []
182177
183178
exec.sys::truncate_stack
184179
# => []
185180
end
186-
`;
187-
188-
// Prepare assembler (debug mode = true)
189-
let assembler = TransactionKernel.assembler().withDebugMode(true);
181+
`;
190182

191-
let countReaderComponent = AccountComponent.compile(
183+
const builder = client.createScriptBuilder();
184+
const countReaderComponent = AccountComponent.compile(
192185
countReaderCode,
193-
assembler,
186+
builder,
194187
[StorageSlot.emptyValue()],
195188
).withSupportsAllTypes();
196189

197-
const seed = new Uint8Array(32);
198-
crypto.getRandomValues(seed);
190+
const walletSeed = new Uint8Array(32);
191+
crypto.getRandomValues(walletSeed);
199192

200-
let countReaderContract = new AccountBuilder(seed)
193+
const secretKey = SecretKey.rpoFalconWithRNG(walletSeed);
194+
const authComponent = AccountComponent.createAuthComponent(secretKey);
195+
196+
const countReaderContract = new AccountBuilder(walletSeed)
201197
.accountType(AccountType.RegularAccountImmutableCode)
202198
.storageMode(AccountStorageMode.public())
199+
.withAuthComponent(authComponent)
203200
.withComponent(countReaderComponent)
204201
.build();
205202

203+
await client.addAccountSecretKeyToWebStore(secretKey);
204+
await client.syncState();
205+
206206
// Create the count reader contract account (using available WebClient API)
207207
console.log("Creating count reader contract account...");
208208
console.log(
209209
"Count reader contract ID:",
210210
countReaderContract.account.id().toString(),
211211
);
212212

213-
await client.newAccount(
214-
countReaderContract.account,
215-
countReaderContract.seed,
216-
false,
217-
);
213+
await client.newAccount(countReaderContract.account, false);
218214

219215
// -------------------------------------------------------------------------
220216
// STEP 2: Build & Get State of the Counter Contract
@@ -223,7 +219,7 @@ export async function foreignProcedureInvocation(): Promise<void> {
223219

224220
// Define the Counter Contract account id from counter contract deploy (same as Rust)
225221
const counterContractId = AccountId.fromHex(
226-
"0xb32d619dfe9e2f0000010ecb441d3f",
222+
"0xe59d8cd3c9ff2a0055da0b83ed6432",
227223
);
228224

229225
// Import the counter contract
@@ -250,144 +246,131 @@ export async function foreignProcedureInvocation(): Promise<void> {
250246

251247
// Counter contract code (exactly from counter.masm)
252248
const counterContractCode = `
253-
use.miden::account
254-
use.std::sys
255-
256-
# => []
257-
export.get_count
258-
push.0
259-
# => [index]
260-
261-
exec.account::get_item
262-
# => [count]
263-
264-
exec.sys::truncate_stack
265-
# => []
266-
end
267-
268-
# => []
269-
export.increment_count
270-
push.0
271-
# => [index]
272-
273-
exec.account::get_item
274-
# => [count]
275-
276-
push.1 add
277-
# => [count+1]
278-
279-
# debug statement with client
280-
debug.stack
281-
282-
push.0
283-
# [index, count+1]
284-
285-
exec.account::set_item
286-
# => []
287-
288-
push.1 exec.account::incr_nonce
289-
# => []
290-
291-
exec.sys::truncate_stack
292-
# => []
293-
end
294-
`;
249+
use.miden::active_account
250+
use miden::native_account
251+
use.std::sys
252+
253+
const.COUNTER_SLOT=0
254+
255+
#! Inputs: []
256+
#! Outputs: [count]
257+
export.get_count
258+
push.COUNTER_SLOT
259+
# => [index]
260+
261+
exec.active_account::get_item
262+
# => [count]
263+
264+
# clean up stack
265+
movdn.4 dropw
266+
# => [count]
267+
end
268+
269+
#! Inputs: []
270+
#! Outputs: []
271+
export.increment_count
272+
push.COUNTER_SLOT
273+
# => [index]
274+
275+
exec.active_account::get_item
276+
# => [count]
277+
278+
add.1
279+
# => [count+1]
280+
281+
debug.stack
282+
283+
push.COUNTER_SLOT
284+
# [index, count+1]
285+
286+
exec.native_account::set_item
287+
# => [OLD_VALUE]
288+
289+
dropw
290+
# => []
291+
end
292+
`;
295293

296294
// Create the counter contract component to get the procedure hash (following Rust pattern)
297-
let counterContractComponent = AccountComponent.compile(
295+
const counterContractComponent = AccountComponent.compile(
298296
counterContractCode,
299-
assembler,
300-
[],
297+
builder,
298+
[StorageSlot.emptyValue()],
301299
).withSupportsAllTypes();
302300

303-
let getCountProcHash = counterContractComponent.getProcedureHash("get_count");
301+
const getCountProcHash =
302+
counterContractComponent.getProcedureHash("get_count");
304303

305304
// Build the script that calls the count reader contract (exactly from reader_script.masm with replacements)
306-
let fpiScriptCode = `
305+
const fpiScriptCode = `
307306
use.external_contract::count_reader_contract
308307
use.std::sys
309308
310309
begin
311-
push.${getCountProcHash}
312-
# => [GET_COUNT_HASH]
310+
push.${getCountProcHash}
311+
# => [GET_COUNT_HASH]
313312
314-
push.${counterContractAccount.id().suffix()}
315-
# => [account_id_suffix, GET_COUNT_HASH]
313+
push.${counterContractAccount.id().suffix()}
314+
# => [account_id_suffix, GET_COUNT_HASH]
316315
317-
push.${counterContractAccount.id().prefix()}
318-
# => [account_id_prefix, account_id_suffix, GET_COUNT_HASH]
316+
push.${counterContractAccount.id().prefix()}
317+
# => [account_id_prefix, account_id_suffix, GET_COUNT_HASH]
319318
320-
call.count_reader_contract::copy_count
321-
# => []
319+
call.count_reader_contract::copy_count
320+
# => []
322321
323-
exec.sys::truncate_stack
324-
# => []
322+
exec.sys::truncate_stack
323+
# => []
325324
326325
end
327-
`;
328-
329-
console.log("fpiScript", fpiScriptCode);
330-
331-
// Empty inputs to the transaction script
332-
const inputs = new TransactionScriptInputPairArray();
326+
`;
333327

334328
// Create the library for the count reader contract
335-
let countReaderLib = AssemblerUtils.createAccountComponentLibrary(
336-
assembler,
329+
const countReaderLib = builder.buildLibrary(
337330
"external_contract::count_reader_contract",
338331
countReaderCode,
339332
);
340-
333+
builder.linkDynamicLibrary(countReaderLib);
334+
.
341335
// Compile the transaction script with the count reader library
342-
let txScript = TransactionScript.compile(
343-
fpiScriptCode,
344-
assembler.withLibrary(countReaderLib),
345-
);
336+
const txScript = builder.compileTxScript(fpiScriptCode);
346337

347338
// foreign account
348-
let storageRequirements = new AccountStorageRequirements();
349-
350-
let foreignAccount = ForeignAccount.public(
339+
const storageRequirements = new AccountStorageRequirements();
340+
const foreignAccount = ForeignAccount.public(
351341
counterContractId,
352342
storageRequirements,
353343
);
354344

355345
// Build a transaction request with the custom script
356-
let txRequest = new TransactionRequestBuilder()
346+
const txRequest = new TransactionRequestBuilder()
357347
.withCustomScript(txScript)
358-
359-
.withForeignAccounts([foreignAccount])
360-
348+
.withForeignAccounts(new MidenArrays.ForeignAccountArray([foreignAccount]))
361349
.build();
362350

363-
console.log("HERE");
364-
365-
// Execute the transaction locally on the count reader contract (following Rust pattern)
366-
let txResult = await client.newTransaction(
351+
// Execute the transaction on the count reader contract and send it to the network (following Rust pattern)
352+
const txResult = await client.submitNewTransaction(
367353
countReaderContract.account.id(),
368354
txRequest,
369355
);
370356

371-
console.log("HERE1");
372357
console.log(
373358
"View transaction on MidenScan: https://testnet.midenscan.com/tx/" +
374-
txResult.executedTransaction().id().toHex(),
359+
txResult.toHex(),
375360
);
376361

377-
// Submit transaction to the network
378-
await client.submitTransaction(txResult);
379362
await client.syncState();
380363

381364
// Retrieve updated contract data to see the results (following Rust pattern)
382-
let updatedCounterContract = await client.getAccount(
365+
const updatedCounterContract = await client.getAccount(
383366
counterContractAccount.id(),
384367
);
385368
console.log(
386369
"counter contract storage:",
387370
updatedCounterContract?.storage().getItem(0)?.toHex(),
388371
);
389372

390-
let updatedCountReaderContract = await client.getAccount(
373+
const updatedCountReaderContract = await client.getAccount(
391374
countReaderContract.account.id(),
392375
);
393376
console.log(
@@ -396,7 +379,7 @@ export async function foreignProcedureInvocation(): Promise<void> {
396379
);
397380

398381
// Log the count value copied via FPI
399-
let countReaderStorage = updatedCountReaderContract?.storage().getItem(0);
382+
const countReaderStorage = updatedCountReaderContract?.storage().getItem(0);
400383
if (countReaderStorage) {
401384
const countValue = Number(
402385
BigInt(
@@ -470,7 +453,8 @@ Foreign Procedure Invocation Transaction completed!
470453
The count reader smart contract contains a `copy_count` procedure that uses `tx::execute_foreign_procedure` to call the `get_count` procedure in the counter contract.
471454

472455
```masm
473-
use.miden::account
456+
use.miden::active_account
457+
use miden::native_account
474458
use.miden::tx
475459
use.std::sys
476460
@@ -479,16 +463,12 @@ export.copy_count
479463
exec.tx::execute_foreign_procedure
480464
# => [count]
481465
482-
debug.stack
483-
# => [count]
484-
485466
push.0
486467
# [index, count]
487468
488-
exec.account::set_item
489-
# => []
469+
debug.stack
490470
491-
push.1 exec.account::incr_nonce
471+
exec.native_account::set_item dropw
492472
# => []
493473
494474
exec.sys::truncate_stack
@@ -561,7 +541,7 @@ let foreignAccount = ForeignAccount.public(
561541

562542
let txRequest = new TransactionRequestBuilder()
563543
.withCustomScript(txScript)
564-
.withForeignAccounts([foreignAccount])
544+
.withForeignAccounts(new MidenArrays.ForeignAccountArray([foreignAccount]))
565545
.build();
566546
```
567547

@@ -570,11 +550,11 @@ let txRequest = new TransactionRequestBuilder()
570550
We create a library for the count reader contract so our transaction script can call its procedures:
571551

572552
```ts
573-
let countReaderLib = AssemblerUtils.createAccountComponentLibrary(
574-
assembler,
553+
const countReaderLib = builder.buildLibrary(
575554
"external_contract::count_reader_contract",
576555
countReaderCode,
577556
);
557+
builder.linkDynamicLibrary(countReaderLib);
578558
```
579559

580560
## Summary

0 commit comments

Comments
 (0)