From 071ee480f301eabf93463057ea9ee30c716073c5 Mon Sep 17 00:00:00 2001 From: Wiktor Starczewski Date: Thu, 26 Feb 2026 01:00:48 +0100 Subject: [PATCH 01/14] chore(web-client): update SDK dependency to local build --- web-client/package.json | 4 ++-- web-client/yarn.lock | 14 +++++++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/web-client/package.json b/web-client/package.json index 2a78ff2..d37dad3 100644 --- a/web-client/package.json +++ b/web-client/package.json @@ -9,8 +9,8 @@ "lint": "next lint" }, "dependencies": { - "@miden-sdk/miden-sdk": "0.13.0", - "@miden-sdk/react": "0.13.2", + "@miden-sdk/miden-sdk": "file:../../miden-client/crates/web-client", + "@miden-sdk/react": "file:../../miden-client/packages/react-sdk", "next": "15.3.2", "react": "^19.0.0", "react-dom": "^19.0.0" diff --git a/web-client/yarn.lock b/web-client/yarn.lock index 5c08f48..27d528c 100644 --- a/web-client/yarn.lock +++ b/web-client/yarn.lock @@ -234,15 +234,18 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" -"@miden-sdk/miden-sdk@0.13.0": +"@miden-sdk/miden-sdk@file:../../miden-client/crates/web-client": version "0.13.0" - resolved "https://registry.yarnpkg.com/@miden-sdk/miden-sdk/-/miden-sdk-0.13.0.tgz#df7f639f90931d279761a62bb513374366d755e4" - integrity sha512-N0qUCZW9Dvk3Oqj37IrGmm0b0v3Nq5qHsX3BtQIzZIwDXKXKPBxy/0lO40oCwDtwI8AfriZQyMLbJR81Fo4Vpg== dependencies: "@rollup/plugin-typescript" "^12.3.0" dexie "^4.0.1" glob "^11.0.0" +"@miden-sdk/react@file:../../miden-client/packages/react-sdk": + version "0.13.2" + dependencies: + zustand "^5.0.0" + "@napi-rs/wasm-runtime@^1.0.7": version "1.0.7" resolved "https://registry.yarnpkg.com/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.7.tgz#dcfea99a75f06209a235f3d941e3460a51e9b14c" @@ -1039,3 +1042,8 @@ wrap-ansi@^8.1.0: ansi-styles "^6.1.0" string-width "^5.0.1" strip-ansi "^7.0.1" + +zustand@^5.0.0: + version "5.0.11" + resolved "https://registry.yarnpkg.com/zustand/-/zustand-5.0.11.tgz#99f912e590de1ca9ce6c6d1cab6cdb1f034ab494" + integrity sha512-fdZY+dk7zn/vbWNCYmzZULHRrss0jx5pPFiOuMZ/5HJN6Yv3u+1Wswy/4MpZEkEGhtNH+pwxZB8OKgUBPzYAGg== From ba82d168fa7a4ff094e1981636ac4124a1286737 Mon Sep 17 00:00:00 2001 From: Wiktor Starczewski Date: Thu, 26 Feb 2026 01:00:51 +0100 Subject: [PATCH 02/14] feat(web-client): migrate counter contract tutorial to MidenClient API --- web-client/lib/incrementCounterContract.ts | 119 ++++++--------------- 1 file changed, 32 insertions(+), 87 deletions(-) diff --git a/web-client/lib/incrementCounterContract.ts b/web-client/lib/incrementCounterContract.ts index 1ed7b7e..b3796e0 100644 --- a/web-client/lib/incrementCounterContract.ts +++ b/web-client/lib/incrementCounterContract.ts @@ -5,24 +5,14 @@ export async function incrementCounterContract(): Promise { return; } - // dynamic import → only in the browser, so WASM is loaded client‑side - const { - Address, - AccountBuilder, - AccountComponent, - AccountStorageMode, - AccountType, - AuthSecretKey, - StorageSlot, - TransactionRequestBuilder, - WebClient, - } = await import('@miden-sdk/miden-sdk'); - - const nodeEndpoint = 'https://rpc.testnet.miden.io'; - const client = await WebClient.createClient(nodeEndpoint); - console.log('Current block number: ', (await client.syncState()).blockNum()); - - // Counter contract code in Miden Assembly + const { AuthSecretKey, StorageSlot, MidenClient } = await import( + '@miden-sdk/miden-sdk' + ); + + const nodeEndpoint = 'http://localhost:57291'; + const client = await MidenClient.create({ rpcUrl: nodeEndpoint }); + console.log('Current block number: ', (await client.sync()).blockNum()); + const counterContractCode = ` use miden::protocol::active_account use miden::protocol::native_account @@ -58,65 +48,27 @@ export async function incrementCounterContract(): Promise { end `; - // Building the counter contract - // Counter contract account id on testnet - const counterContractId = Address.fromBech32( - 'mtst1arjemrxne8lj5qz4mg9c8mtyxg954483', - ).accountId(); - - // Reading the public state of the counter contract from testnet, - // and importing it into the WebClient - let counterContractAccount = await client.getAccount(counterContractId); - if (!counterContractAccount) { - await client.importAccountById(counterContractId); - await client.syncState(); - counterContractAccount = await client.getAccount(counterContractId); - if (!counterContractAccount) { - throw new Error(`Account not found after import: ${counterContractId}`); - } - } - - const builder = client.createCodeBuilder(); const counterSlotName = 'miden::tutorials::counter'; - const counterStorageSlot = StorageSlot.emptyValue(counterSlotName); - const counterComponentCode = - builder.compileAccountComponentCode(counterContractCode); - const counterAccountComponent = AccountComponent.compile( - counterComponentCode, - [counterStorageSlot], - ).withSupportsAllTypes(); + const counterAccountComponent = await client.compile.component({ + code: counterContractCode, + slots: [StorageSlot.emptyValue(counterSlotName)], + }); const walletSeed = new Uint8Array(32); crypto.getRandomValues(walletSeed); + const auth = AuthSecretKey.rpoFalconWithRNG(walletSeed); - const secretKey = AuthSecretKey.rpoFalconWithRNG(walletSeed); - const authComponent = - AccountComponent.createAuthComponentFromSecretKey(secretKey); - - const accountBuilderResult = new AccountBuilder(walletSeed) - .accountType(AccountType.RegularAccountImmutableCode) - .storageMode(AccountStorageMode.public()) - .withAuthComponent(authComponent) - .withComponent(counterAccountComponent) - .build(); - - await client.addAccountSecretKeyToWebStore( - accountBuilderResult.account.id(), - secretKey, - ); - await client.newAccount(accountBuilderResult.account, false); - - await client.syncState(); - - const accountCodeLib = builder.buildLibrary( - 'external_contract::counter_contract', - counterContractCode, - ); + const account = await client.accounts.create({ + type: 'ImmutableContract', + storage: 'public', + seed: walletSeed, + auth, + components: [counterAccountComponent], + }); - builder.linkDynamicLibrary(accountCodeLib); + await client.sync(); - // Building the transaction script which will call the counter contract const txScriptCode = ` use external_contract::counter_contract begin @@ -124,31 +76,24 @@ export async function incrementCounterContract(): Promise { end `; - const txScript = builder.compileTxScript(txScriptCode); - const txIncrementRequest = new TransactionRequestBuilder() - .withCustomScript(txScript) - .build(); + const script = await client.compile.txScript({ + code: txScriptCode, + libraries: [{ namespace: 'external_contract::counter_contract', code: counterContractCode }], + }); - // Executing the transaction script against the counter contract - await client.submitNewTransaction( - counterContractAccount.id(), - txIncrementRequest, - ); + await client.transactions.execute({ + account: account.id(), + script, + }); - // Sync state - await client.syncState(); + await client.sync(); - // Logging the count of counter contract - const counter = await client.getAccount(counterContractAccount.id()); + console.log('Counter contract ID:', account.id().toString()); - // Here we get the first Word from storage of the counter contract - // A word is comprised of 4 Felts, 2**64 - 2**32 + 1 + const counter = await client.accounts.get(account.id()); const count = counter?.storage().getItem(counterSlotName); - - // Converting the Word represented as a hex to a single integer value const counterValue = Number( BigInt('0x' + count!.toHex().slice(-16).match(/../g)!.reverse().join('')), ); - console.log('Count: ', counterValue); } From 1edbf3e59f031c015733428159a57607d71bce26 Mon Sep 17 00:00:00 2001 From: Wiktor Starczewski Date: Thu, 26 Feb 2026 01:00:53 +0100 Subject: [PATCH 03/14] feat(web-client): rewrite FPI tutorial as self-contained MidenClient example --- web-client/lib/foreignProcedureInvocation.ts | 303 ++++++++----------- 1 file changed, 121 insertions(+), 182 deletions(-) diff --git a/web-client/lib/foreignProcedureInvocation.ts b/web-client/lib/foreignProcedureInvocation.ts index 79c2eda..badb633 100644 --- a/web-client/lib/foreignProcedureInvocation.ts +++ b/web-client/lib/foreignProcedureInvocation.ts @@ -5,32 +5,49 @@ export async function foreignProcedureInvocation(): Promise { return; } - // dynamic import → only in the browser, so WASM is loaded client‑side - const { - AccountBuilder, - AccountComponent, - Address, - AccountType, - AuthSecretKey, - StorageSlot, - TransactionRequestBuilder, - ForeignAccount, - ForeignAccountArray, - AccountStorageRequirements, - WebClient, - AccountStorageMode, - } = await import('@miden-sdk/miden-sdk'); - - const nodeEndpoint = 'https://rpc.testnet.miden.io'; - const client = await WebClient.createClient(nodeEndpoint); - console.log('Current block number: ', (await client.syncState()).blockNum()); + const { AuthSecretKey, StorageSlot, MidenClient } = await import( + '@miden-sdk/miden-sdk' + ); - // ------------------------------------------------------------------------- - // STEP 1: Create the Count Reader Contract - // ------------------------------------------------------------------------- - console.log('\n[STEP 1] Creating count reader contract.'); + const nodeEndpoint = 'http://localhost:57291'; + const client = await MidenClient.create({ rpcUrl: nodeEndpoint }); + console.log('Current block number: ', (await client.sync()).blockNum()); + + const counterContractCode = ` + use miden::protocol::active_account + use miden::protocol::native_account + use miden::core::word + use miden::core::sys + + const COUNTER_SLOT = word("miden::tutorials::counter") + + #! Inputs: [] + #! Outputs: [count] + pub proc get_count + push.COUNTER_SLOT[0..2] exec.active_account::get_item + # => [count] + + exec.sys::truncate_stack + # => [count] + end + + #! Inputs: [] + #! Outputs: [] + pub proc increment_count + push.COUNTER_SLOT[0..2] exec.active_account::get_item + # => [count] + + add.1 + # => [count+1] + + push.COUNTER_SLOT[0..2] exec.native_account::set_item + # => [] + + exec.sys::truncate_stack + # => [] + end +`; - // Count reader contract code in Miden Assembly (exactly from count_reader.masm) const countReaderCode = ` use miden::protocol::active_account use miden::protocol::native_account @@ -44,7 +61,7 @@ export async function foreignProcedureInvocation(): Promise { pub proc copy_count exec.tx::execute_foreign_procedure # => [count] - + push.COUNT_READER_SLOT[0..2] # [slot_id_prefix, slot_id_suffix, count] @@ -59,71 +76,76 @@ export async function foreignProcedureInvocation(): Promise { end `; - const countReaderSlotName = 'miden::tutorials::count_reader'; const counterSlotName = 'miden::tutorials::counter'; + const countReaderSlotName = 'miden::tutorials::count_reader'; - const builder = client.createCodeBuilder(); - const countReaderComponentCode = - builder.compileAccountComponentCode(countReaderCode); - const countReaderComponent = AccountComponent.compile( - countReaderComponentCode, - [StorageSlot.emptyValue(countReaderSlotName)], - ).withSupportsAllTypes(); - - const walletSeed = new Uint8Array(32); - crypto.getRandomValues(walletSeed); + // ------------------------------------------------------------------------- + // STEP 1: Deploy the Counter Contract + // ------------------------------------------------------------------------- + console.log('\n[STEP 1] Deploying counter contract.'); + + const counterComponent = await client.compile.component({ + code: counterContractCode, + slots: [StorageSlot.emptyValue(counterSlotName)], + }); + + const counterSeed = new Uint8Array(32); + crypto.getRandomValues(counterSeed); + const counterAuth = AuthSecretKey.rpoFalconWithRNG(counterSeed); + + const counterAccount = await client.accounts.create({ + type: 'ImmutableContract', + storage: 'public', + seed: counterSeed, + auth: counterAuth, + components: [counterComponent], + }); + + // Deploy the counter to the node by executing a transaction on it + const deployScript = await client.compile.txScript({ + code: ` + use external_contract::counter_contract + begin + call.counter_contract::increment_count + end + `, + libraries: [{ namespace: 'external_contract::counter_contract', code: counterContractCode }], + }); + + // Wait for the deploy transaction to be committed to a block + // before using it as a foreign account in FPI + await client.transactions.execute({ + account: counterAccount.id(), + script: deployScript, + waitForConfirmation: true, + }); + await client.sync(); + console.log('Counter contract ID:', counterAccount.id().toString()); - const secretKey = AuthSecretKey.rpoFalconWithRNG(walletSeed); - const authComponent = AccountComponent.createAuthComponentFromSecretKey( - secretKey, - ); + // ------------------------------------------------------------------------- + // STEP 2: Create the Count Reader Contract + // ------------------------------------------------------------------------- + console.log('\n[STEP 2] Creating count reader contract.'); - const countReaderContract = new AccountBuilder(walletSeed) - .accountType(AccountType.RegularAccountImmutableCode) - .storageMode(AccountStorageMode.public()) - .withAuthComponent(authComponent) - .withComponent(countReaderComponent) - .build(); + const countReaderComponent = await client.compile.component({ + code: countReaderCode, + slots: [StorageSlot.emptyValue(countReaderSlotName)], + }); - await client.addAccountSecretKeyToWebStore( - countReaderContract.account.id(), - secretKey, - ); - await client.syncState(); + const readerSeed = new Uint8Array(32); + crypto.getRandomValues(readerSeed); + const readerAuth = AuthSecretKey.rpoFalconWithRNG(readerSeed); - // Create the count reader contract account (using available WebClient API) - console.log('Creating count reader contract account...'); - console.log( - 'Count reader contract ID:', - countReaderContract.account.id().toString(), - ); + const countReaderAccount = await client.accounts.create({ + type: 'ImmutableContract', + storage: 'public', + seed: readerSeed, + auth: readerAuth, + components: [countReaderComponent], + }); - await client.newAccount(countReaderContract.account, false); - - // ------------------------------------------------------------------------- - // STEP 2: Build & Get State of the Counter Contract - // ------------------------------------------------------------------------- - console.log('\n[STEP 2] Building counter contract from public state'); - - // Define the Counter Contract account id from counter contract deploy (same as Rust) - const counterContractId = Address.fromBech32( - 'mtst1arjemrxne8lj5qz4mg9c8mtyxg954483', - ).accountId(); - - // Import the counter contract - let counterContractAccount = await client.getAccount(counterContractId); - if (!counterContractAccount) { - await client.importAccountById(counterContractId); - await client.syncState(); - counterContractAccount = await client.getAccount(counterContractId); - if (!counterContractAccount) { - throw new Error(`Account not found after import: ${counterContractId}`); - } - } - console.log( - 'Account storage slot:', - counterContractAccount.storage().getItem(counterSlotName)?.toHex(), - ); + await client.sync(); + console.log('Count reader contract ID:', countReaderAccount.id().toString()); // ------------------------------------------------------------------------- // STEP 3: Call the Counter Contract via Foreign Procedure Invocation (FPI) @@ -132,54 +154,8 @@ export async function foreignProcedureInvocation(): Promise { '\n[STEP 3] Call counter contract with FPI from count reader contract', ); - // Counter contract code (exactly from counter.masm) - const counterContractCode = ` - use miden::protocol::active_account - use miden::protocol::native_account - use miden::core::word - use miden::core::sys - - const COUNTER_SLOT = word("miden::tutorials::counter") - - #! Inputs: [] - #! Outputs: [count] - pub proc get_count - push.COUNTER_SLOT[0..2] exec.active_account::get_item - # => [count] - - exec.sys::truncate_stack - # => [count] - end - - #! Inputs: [] - #! Outputs: [] - pub proc increment_count - push.COUNTER_SLOT[0..2] exec.active_account::get_item - # => [count] - - add.1 - # => [count+1] - - push.COUNTER_SLOT[0..2] exec.native_account::set_item - # => [] - - exec.sys::truncate_stack - # => [] - end -`; - - // Create the counter contract component to get the procedure hash (following Rust pattern) - const counterContractComponentCode = - builder.compileAccountComponentCode(counterContractCode); - const counterContractComponent = AccountComponent.compile( - counterContractComponentCode, - [StorageSlot.emptyValue(counterSlotName)], - ).withSupportsAllTypes(); + const getCountProcHash = counterComponent.getProcedureHash('get_count'); - const getCountProcHash = - counterContractComponent.getProcedureHash('get_count'); - - // Build the script that calls the count reader contract (exactly from reader_script.masm with replacements) const fpiScriptCode = ` use external_contract::count_reader_contract use miden::core::sys @@ -188,10 +164,10 @@ export async function foreignProcedureInvocation(): Promise { push.${getCountProcHash} # => [GET_COUNT_HASH] - push.${counterContractAccount.id().suffix()} + push.${counterAccount.id().suffix()} # => [account_id_suffix, GET_COUNT_HASH] - push.${counterContractAccount.id().prefix()} + push.${counterAccount.id().prefix()} # => [account_id_prefix, account_id_suffix, GET_COUNT_HASH] call.count_reader_contract::copy_count @@ -203,63 +179,26 @@ export async function foreignProcedureInvocation(): Promise { end `; - // Create the library for the count reader contract - const countReaderLib = builder.buildLibrary( - 'external_contract::count_reader_contract', - countReaderCode, - ); - builder.linkDynamicLibrary(countReaderLib); + const script = await client.compile.txScript({ + code: fpiScriptCode, + libraries: [{ namespace: 'external_contract::count_reader_contract', code: countReaderCode }], + }); - // Compile the transaction script with the count reader library - const txScript = builder.compileTxScript(fpiScriptCode); + await client.transactions.execute({ + account: countReaderAccount.id(), + script, + foreignAccounts: [{ id: counterAccount.id() }], + }); - // foreign account - const storageRequirements = new AccountStorageRequirements(); - const foreignAccount = ForeignAccount.public( - counterContractId, - storageRequirements, - ); - - // Build a transaction request with the custom script - const txRequest = new TransactionRequestBuilder() - .withCustomScript(txScript) - .withForeignAccounts(new ForeignAccountArray([foreignAccount])) - .build(); + await client.sync(); - // Execute the transaction on the count reader contract and send it to the network (following Rust pattern) - const txResult = await client.submitNewTransaction( - countReaderContract.account.id(), - txRequest, + const updatedCountReaderContract = await client.accounts.get( + countReaderAccount.id(), ); - - console.log( - 'View transaction on MidenScan: https://testnet.midenscan.com/tx/' + - txResult.toHex(), - ); - - await client.syncState(); - - // Retrieve updated contract data to see the results (following Rust pattern) - const updatedCounterContract = await client.getAccount( - counterContractAccount.id(), - ); - console.log( - 'counter contract storage:', - updatedCounterContract?.storage().getItem(counterSlotName)?.toHex(), - ); - - const updatedCountReaderContract = await client.getAccount( - countReaderContract.account.id(), - ); - console.log( - 'count reader contract storage:', - updatedCountReaderContract?.storage().getItem(countReaderSlotName)?.toHex(), - ); - - // Log the count value copied via FPI const countReaderStorage = updatedCountReaderContract ?.storage() .getItem(countReaderSlotName); + if (countReaderStorage) { const countValue = Number( BigInt( From 044d0046645ee5cb27a8b44a0b48b96dfa80c47f Mon Sep 17 00:00:00 2001 From: Wiktor Starczewski Date: Thu, 26 Feb 2026 01:00:55 +0100 Subject: [PATCH 04/14] docs: update web-client tutorials to use MidenClient API --- .../web-client/counter_contract_tutorial.md | 225 ++++++++++-------- docs/src/web-client/create_deploy_tutorial.md | 77 +++--- .../creating_multiple_notes_tutorial.md | 198 ++++++--------- .../foreign_procedure_invocation_tutorial.md | 211 ++++++---------- .../mint_consume_create_tutorial.md | 158 ++++++------ .../web-client/unauthenticated_note_how_to.md | 128 ++++------ 6 files changed, 421 insertions(+), 576 deletions(-) diff --git a/docs/src/web-client/counter_contract_tutorial.md b/docs/src/web-client/counter_contract_tutorial.md index 718b10b..e3b98f7 100644 --- a/docs/src/web-client/counter_contract_tutorial.md +++ b/docs/src/web-client/counter_contract_tutorial.md @@ -11,7 +11,7 @@ In this tutorial, we will interact with a counter contract already deployed on c Using a script, we will invoke the increment function within the counter contract to update the count. This tutorial provides a foundational understanding of interacting with custom smart contracts on Miden. -## What we'll cover +## What we'll cover - Interacting with a custom smart contract on Miden - Calling procedures in an account from a script @@ -96,7 +96,7 @@ export default function Home() { } ``` -## Step 3 — Incrementing the Count of the Counter Contract +## Step 3 — Incrementing the Count of the Counter Contract Create the file `lib/incrementCounterContract.ts` and add the following code. @@ -116,140 +116,110 @@ export async function incrementCounterContract(): Promise { } // dynamic import → only in the browser, so WASM is loaded client‑side - const { - Address, - AccountBuilder, - AccountComponent, - AccountStorageMode, - AccountType, - AuthSecretKey, - StorageSlot, - TransactionRequestBuilder, - WebClient, - } = await import('@miden-sdk/miden-sdk'); + const { Address, AuthSecretKey, StorageSlot, MidenClient } = await import( + '@miden-sdk/miden-sdk' + ); const nodeEndpoint = 'https://rpc.testnet.miden.io'; - const client = await WebClient.createClient(nodeEndpoint); - console.log('Current block number: ', (await client.syncState()).blockNum()); + const client = await MidenClient.create({ rpcUrl: nodeEndpoint }); + console.log('Current block number: ', (await client.sync()).blockNum()); // Counter contract code in Miden Assembly const counterContractCode = ` - use miden::protocol::active_account - use miden::protocol::native_account - use miden::core::word - use miden::core::sys - - const COUNTER_SLOT = word("miden::tutorials::counter") - - #! Inputs: [] - #! Outputs: [count] - pub proc get_count - push.COUNTER_SLOT[0..2] exec.active_account::get_item - # => [count] - - exec.sys::truncate_stack - # => [count] - end - - #! Inputs: [] - #! Outputs: [] - pub proc increment_count - push.COUNTER_SLOT[0..2] exec.active_account::get_item - # => [count] - - add.1 - # => [count+1] - - push.COUNTER_SLOT[0..2] exec.native_account::set_item - # => [] - - exec.sys::truncate_stack - # => [] - end + use miden::protocol::active_account + use miden::protocol::native_account + use miden::core::word + use miden::core::sys + + const COUNTER_SLOT = word("miden::tutorials::counter") + + #! Inputs: [] + #! Outputs: [count] + pub proc get_count + push.COUNTER_SLOT[0..2] exec.active_account::get_item + # => [count] + + exec.sys::truncate_stack + # => [count] + end + + #! Inputs: [] + #! Outputs: [] + pub proc increment_count + push.COUNTER_SLOT[0..2] exec.active_account::get_item + # => [count] + + add.1 + # => [count+1] + + push.COUNTER_SLOT[0..2] exec.native_account::set_item + # => [] + + exec.sys::truncate_stack + # => [] + end `; - // Building the counter contract // Counter contract account id on testnet const counterContractId = Address.fromBech32( 'mtst1arjemrxne8lj5qz4mg9c8mtyxg954483', ).accountId(); // Reading the public state of the counter contract from testnet, - // and importing it into the WebClient - let counterContractAccount = await client.getAccount(counterContractId); - if (!counterContractAccount) { - await client.importAccountById(counterContractId); - await client.syncState(); - counterContractAccount = await client.getAccount(counterContractId); - if (!counterContractAccount) { - throw new Error(`Account not found after import: ${counterContractId}`); - } - } + // and importing it into the client + const counterContractAccount = + await client.accounts.getOrImport(counterContractId); - const builder = client.createCodeBuilder(); const counterSlotName = 'miden::tutorials::counter'; - const counterStorageSlot = StorageSlot.emptyValue(counterSlotName); - const counterComponentCode = - builder.compileAccountComponentCode(counterContractCode); - const counterAccountComponent = AccountComponent.compile( - counterComponentCode, - [counterStorageSlot], - ).withSupportsAllTypes(); + // Compile the counter component + const counterAccountComponent = await client.compile.component({ + code: counterContractCode, + slots: [StorageSlot.emptyValue(counterSlotName)], + }); const walletSeed = new Uint8Array(32); crypto.getRandomValues(walletSeed); - const secretKey = AuthSecretKey.rpoFalconWithRNG(walletSeed); - const authComponent = - AccountComponent.createAuthComponentFromSecretKey(secretKey); - - const accountBuilderResult = new AccountBuilder(walletSeed) - .accountType(AccountType.RegularAccountImmutableCode) - .storageMode(AccountStorageMode.public()) - .withAuthComponent(authComponent) - .withComponent(counterAccountComponent) - .build(); - - await client.addAccountSecretKeyToWebStore( - accountBuilderResult.account.id(), - secretKey, - ); - await client.newAccount(accountBuilderResult.account, false); - - await client.syncState(); + const auth = AuthSecretKey.rpoFalconWithRNG(walletSeed); - const accountCodeLib = builder.buildLibrary( - 'external_contract::counter_contract', - counterContractCode, - ); + // Create the counter contract account + const account = await client.accounts.create({ + type: 'ImmutableContract', + storage: 'public', + seed: walletSeed, + auth, + components: [counterAccountComponent], + }); - builder.linkDynamicLibrary(accountCodeLib); + await client.sync(); // Building the transaction script which will call the counter contract const txScriptCode = ` -use external_contract::counter_contract -begin -call.counter_contract::increment_count -end + use external_contract::counter_contract + begin + call.counter_contract::increment_count + end `; - const txScript = builder.compileTxScript(txScriptCode); - const txIncrementRequest = new TransactionRequestBuilder() - .withCustomScript(txScript) - .build(); + const script = await client.compile.txScript({ + code: txScriptCode, + libraries: [ + { namespace: 'external_contract::counter_contract', code: counterContractCode }, + ], + }); // Executing the transaction script against the counter contract - await client.submitNewTransaction( - counterContractAccount.id(), - txIncrementRequest, - ); + await client.transactions.execute({ + account: account.id(), + script, + }); // Sync state - await client.syncState(); + await client.sync(); // Logging the count of counter contract - const counter = await client.getAccount(counterContractAccount.id()); + const counter = await client.accounts.get(counterContractAccount.id()); // Here we get the first Word from storage of the counter contract // A word is comprised of 4 Felts, 2**64 - 2**32 + 1 @@ -343,6 +313,55 @@ This `NoAuth` component allows any user to interact with the smart contract with **Note**: _Adding the `account::incr_nonce` to a state changing procedure allows any user to call the procedure._ +### Compiling the account component + +Use `client.compile.component()` to compile MASM code and its storage slots into an `AccountComponent`. Each call creates a fresh compiler instance so compilations are fully independent: + +```ts +const counterAccountComponent = await client.compile.component({ + code: counterContractCode, + slots: [StorageSlot.emptyValue(counterSlotName)], +}); +``` + +### Creating the contract account + +Use `client.accounts.create()` with `type: 'ImmutableContract'` to build and register the contract. You must supply a `seed` (for deterministic ID derivation) and a raw `AuthSecretKey` — the client stores the key automatically: + +```ts +const auth = AuthSecretKey.rpoFalconWithRNG(walletSeed); + +const account = await client.accounts.create({ + type: 'ImmutableContract', + storage: 'public', + seed: walletSeed, + auth, + components: [counterAccountComponent], +}); +``` + +### Compiling and executing the custom script + +Use `client.compile.txScript()` to compile a transaction script. Pass any needed libraries inline — the client links them dynamically: + +```ts +const script = await client.compile.txScript({ + code: txScriptCode, + libraries: [ + { namespace: 'external_contract::counter_contract', code: counterContractCode }, + ], +}); +``` + +Then execute it with `client.transactions.execute()`: + +```ts +await client.transactions.execute({ + account: account.id(), + script, +}); +``` + ### Custom script This is the Miden assembly script that calls the `increment_count` procedure during the transaction. diff --git a/docs/src/web-client/create_deploy_tutorial.md b/docs/src/web-client/create_deploy_tutorial.md index 80666c2..a887f58 100644 --- a/docs/src/web-client/create_deploy_tutorial.md +++ b/docs/src/web-client/create_deploy_tutorial.md @@ -123,16 +123,17 @@ export async function createMintConsume(): Promise { .} .// dynamic import → only in the browser, so WASM is loaded client‑side -.const { WebClient } = +.const { MidenClient } = ..await import('@miden-sdk/miden-sdk'); .// Connect to Miden testnet RPC endpoint -.const nodeEndpoint = 'https://rpc.testnet.miden.io'; -.const client = await WebClient.createClient(nodeEndpoint); +.const client = await MidenClient.create({ +..rpcUrl: 'https://rpc.testnet.miden.io', +.}); .// 1. Sync with the latest blockchain state .// This fetches the latest block header and state commitments -.const state = await client.syncState(); +.const state = await client.sync(); .console.log('Latest block number:', state.blockNum()); .// At this point, your client is connected and synchronized @@ -219,24 +220,22 @@ export async function createMintConsume(): Promise { ..return; .} -.const { WebClient, AccountStorageMode, AuthScheme } = await import( -.."@miden-sdk/miden-sdk" -.); +.const { MidenClient } = await import('@miden-sdk/miden-sdk'); -.const nodeEndpoint = 'https://rpc.testnet.miden.io'; -.const client = await WebClient.createClient(nodeEndpoint); +.const client = await MidenClient.create({ +..rpcUrl: 'https://rpc.testnet.miden.io', +.}); .// 1. Sync with the latest blockchain state -.const state = await client.syncState(); +.const state = await client.sync(); .console.log('Latest block number:', state.blockNum()); .// 2. Create Alice's account .console.log('Creating account for Alice…'); -.const alice = await client.newWallet( -..AccountStorageMode.public(), // Public: account state is visible on-chain -..true, // Mutable: account code can be upgraded later -..AuthScheme.AuthRpoFalcon512 // Auth Scheme: RPO Falcon 512 -.); +.const alice = await client.accounts.create({ +..type: 'MutableWallet', // Mutable: account code can be upgraded later +..storage: 'public', // Public: account state is visible on-chain +.}); .console.log('Alice ID:', alice.id().toString()); }` }, }} reactFilename="lib/react/createMintConsume.tsx" tsFilename="lib/createMintConsume.ts" /> @@ -262,14 +261,13 @@ console.log('Setup complete.');`}, typescript: { code:`// 3. Deploy a fungible faucet // A faucet is an account that can mint new tokens console.log('Creating faucet…'); -const faucetAccount = await client.newFaucet( -.AccountStorageMode.public(), // Public: faucet operations are transparent -.false, // Immutable: faucet rules cannot be changed -."MID", // Token symbol (like ETH, BTC, etc.) -.8, // Decimals (8 means 1 MID = 100,000,000 base units) -.BigInt(1_000_000), // Max supply: total tokens that can ever be minted -.AuthScheme.AuthRpoFalcon512 // Auth Scheme: RPO Falcon 512 -); +const faucetAccount = await client.accounts.create({ +.type: 'FungibleFaucet', // Fungible faucet: can mint divisible tokens +.symbol: 'MID', // Token symbol (like ETH, BTC, etc.) +.decimals: 8, // Decimals (8 means 1 MID = 100,000,000 base units) +.maxSupply: BigInt(1_000_000), // Max supply: total tokens that can ever be minted +.storage: 'public', // Public: faucet operations are transparent +}); console.log('Faucet account ID:', faucetAccount.id().toString()); console.log('Setup complete.');` }, @@ -349,35 +347,34 @@ export async function createMintConsume(): Promise { .} .// dynamic import → only in the browser, so WASM is loaded client‑side -.const { WebClient, AccountStorageMode, AuthScheme } = +.const { MidenClient } = ..await import('@miden-sdk/miden-sdk'); -.const nodeEndpoint = 'https://rpc.testnet.miden.io'; -.const client = await WebClient.createClient(nodeEndpoint); +.const client = await MidenClient.create({ +..rpcUrl: 'https://rpc.testnet.miden.io', +.}); .// 1. Sync with the latest blockchain state -.const state = await client.syncState(); +.const state = await client.sync(); .console.log('Latest block number:', state.blockNum()); .// 2. Create Alice's account .console.log('Creating account for Alice…'); -.const alice = await client.newWallet( -..AccountStorageMode.public(), -..true, -..AuthScheme.AuthRpoFalcon512, -.); +.const alice = await client.accounts.create({ +..type: 'MutableWallet', +..storage: 'public', +.}); .console.log('Alice ID:', alice.id().toString()); .// 3. Deploy a fungible faucet .console.log('Creating faucet…'); -.const faucet = await client.newFaucet( -..AccountStorageMode.public(), -..false, -..'MID', -..8, -..BigInt(1_000_000), -..AuthScheme.AuthRpoFalcon512, -.); +.const faucet = await client.accounts.create({ +..type: 'FungibleFaucet', +..symbol: 'MID', +..decimals: 8, +..maxSupply: BigInt(1_000_000), +..storage: 'public', +.}); .console.log('Faucet ID:', faucet.id().toString()); .console.log('Setup complete.'); diff --git a/docs/src/web-client/creating_multiple_notes_tutorial.md b/docs/src/web-client/creating_multiple_notes_tutorial.md index 08ed894..cfe71e4 100644 --- a/docs/src/web-client/creating_multiple_notes_tutorial.md +++ b/docs/src/web-client/creating_multiple_notes_tutorial.md @@ -39,7 +39,7 @@ _How does it work?_ When a user choses to use delegated proving, they send off a Anyone can run their own delegated prover server. If you are building a product on Miden, it may make sense to run your own delegated prover server for your users. To run your own delegated proving server, follow the instructions here: https://crates.io/crates/miden-proving-service -The code below uses `submitNewTransaction`, which handles proving via the network's delegated +The code below uses `client.transactions.submit()`, which handles proving via the network's delegated proving service. This means your browser never has to generate the full ZK proof locally. ## Step 1: Initialize your Next.js project @@ -179,23 +179,17 @@ export default function MultiSendWithDelegatedProver() { .if (typeof window === 'undefined') return console.warn('Run in browser'); .const { -..WebClient, -..AccountStorageMode, -..AuthScheme, -..Address, -..NoteType, -..Note, -..NoteAssets, +..MidenClient, +..createP2IDNote, ..OutputNoteArray, -..NoteAttachment, -..FungibleAsset, ..TransactionRequestBuilder, -..OutputNote, .} = await import('@miden-sdk/miden-sdk'); -.const client = await WebClient.createClient('https://rpc.testnet.miden.io'); +.const client = await MidenClient.create({ +..rpcUrl: 'https://rpc.testnet.miden.io', +.}); -.console.log('Latest block:', (await client.syncState()).blockNum()); +.console.log('Latest block:', (await client.sync()).blockNum()); }` }, }} reactFilename="lib/react/multiSendWithDelegatedProver.tsx" tsFilename="lib/multiSendWithDelegatedProver.ts" /> @@ -237,48 +231,40 @@ const noteIds = notes.map((n) => n.inputNoteRecord().id().toString()); await consume({ accountId: aliceId, noteIds });`}, typescript: { code:`// ── Creating new account ────────────────────────────────────────────────────── console.log('Creating account for Alice…'); -const alice = await client.newWallet( -.AccountStorageMode.public(), -.true, -.AuthScheme.AuthRpoFalcon512, -); +const alice = await client.accounts.create({ +.type: 'MutableWallet', +.storage: 'public', +}); console.log('Alice account ID:', alice.id().toString()); // ── Creating new faucet ────────────────────────────────────────────────────── -const faucet = await client.newFaucet( -.AccountStorageMode.public(), -.false, -.'MID', -.8, -.BigInt(1_000_000), -.AuthScheme.AuthRpoFalcon512, -); +const faucet = await client.accounts.create({ +.type: 'FungibleFaucet', +.symbol: 'MID', +.decimals: 8, +.maxSupply: BigInt(1_000_000), +.storage: 'public', +}); console.log('Faucet ID:', faucet.id().toString()); // ── mint 10 000 MID to Alice ────────────────────────────────────────────────────── -await client.submitNewTransaction( -.faucet.id(), -.client.newMintTransactionRequest( -..alice.id(), -..faucet.id(), -..NoteType.Public, -..BigInt(10_000), -.), -); +const mintTxId = await client.transactions.mint({ +.account: faucet.id(), +.to: alice.id(), +.amount: BigInt(10_000), +.type: 'public', +}); console.log('waiting for settlement'); -await new Promise((r) => setTimeout(r, 7_000)); -await client.syncState(); +await client.transactions.waitFor(mintTxId.toHex()); +await client.sync(); // ── consume the freshly minted notes ────────────────────────────────────────────── -const noteList = (await client.getConsumableNotes(alice.id())).map((rec) => -.rec.inputNoteRecord().toNote(), -); - -await client.submitNewTransaction( -.alice.id(), -.client.newConsumeTransactionRequest(noteList), -);` }, +const noteList = await client.notes.listAvailable({ account: alice.id() }); +await client.transactions.consume({ +.account: alice.id(), +.notes: noteList.map((n) => n.inputNoteRecord().id().toString()), +});` }, }} reactFilename="lib/react/multiSendWithDelegatedProver.tsx" tsFilename="lib/multiSendWithDelegatedProver.ts" /> ## Step 5 — Build and Create P2ID notes @@ -306,25 +292,19 @@ const recipientAddresses = [ .'mtst1arpee6y9cm8t7ypn33pc8fzj6gkzz7kd', ]; -const assets = new NoteAssets([new FungibleAsset(faucet.id(), BigInt(100))]); - -const p2idNotes = recipientAddresses.map((addr) => { -.const receiverAccountId = Address.fromBech32(addr).accountId(); -.const note = Note.createP2IDNote( -..alice.id(), -..receiverAccountId, -..assets, -..NoteType.Public, -..new NoteAttachment(), -.); - -.return OutputNote.full(note); -}); +const p2idNotes = recipientAddresses.map((addr) => +.createP2IDNote({ +..from: alice.id(), +..to: addr, +..assets: { token: faucet.id(), amount: BigInt(100) }, +..type: 'public', +.}), +); // ── create all P2ID notes ─────────────────────────────────────────────────────────────── const builder = new TransactionRequestBuilder(); const txRequest = builder.withOwnOutputNotes(new OutputNoteArray(p2idNotes)).build(); -await client.submitNewTransaction(alice.id(), txRequest); +await client.transactions.submit(alice.id(), txRequest); console.log('All notes created ✅');` }, }} reactFilename="lib/react/multiSendWithDelegatedProver.tsx" tsFilename="lib/multiSendWithDelegatedProver.ts" /> @@ -423,68 +403,54 @@ export async function multiSendWithDelegatedProver(): Promise { .if (typeof window === 'undefined') return console.warn('Run in browser'); .const { -..WebClient, -..AccountStorageMode, -..AuthScheme, -..Address, -..NoteType, -..Note, -..NoteAssets, +..MidenClient, +..createP2IDNote, ..OutputNoteArray, -..FungibleAsset, -..NoteAttachment, ..TransactionRequestBuilder, -..OutputNote, .} = await import('@miden-sdk/miden-sdk'); -.const client = await WebClient.createClient('https://rpc.testnet.miden.io'); +.const client = await MidenClient.create({ +..rpcUrl: 'https://rpc.testnet.miden.io', +.}); -.console.log('Latest block:', (await client.syncState()).blockNum()); +.console.log('Latest block:', (await client.sync()).blockNum()); .// ── Creating new account ────────────────────────────────────────────────────── .console.log('Creating account for Alice…'); -.const alice = await client.newWallet( -..AccountStorageMode.public(), -..true, -..AuthScheme.AuthRpoFalcon512, -.); +.const alice = await client.accounts.create({ +..type: 'MutableWallet', +..storage: 'public', +.}); .console.log('Alice account ID:', alice.id().toString()); .// ── Creating new faucet ────────────────────────────────────────────────────── -.const faucet = await client.newFaucet( -..AccountStorageMode.public(), -..false, -..'MID', -..8, -..BigInt(1_000_000), -..AuthScheme.AuthRpoFalcon512, -.); +.const faucet = await client.accounts.create({ +..type: 'FungibleFaucet', +..symbol: 'MID', +..decimals: 8, +..maxSupply: BigInt(1_000_000), +..storage: 'public', +.}); .console.log('Faucet ID:', faucet.id().toString()); .// ── mint 10 000 MID to Alice ────────────────────────────────────────────────────── -.await client.submitNewTransaction( -..faucet.id(), -..client.newMintTransactionRequest( -...alice.id(), -...faucet.id(), -...NoteType.Public, -...BigInt(10_000), -..), -.); +.const mintTxId = await client.transactions.mint({ +..account: faucet.id(), +..to: alice.id(), +..amount: BigInt(10_000), +..type: 'public', +.}); .console.log('waiting for settlement'); -.await new Promise((r) => setTimeout(r, 7_000)); -.await client.syncState(); +.await client.transactions.waitFor(mintTxId.toHex()); +.await client.sync(); .// ── consume the freshly minted notes ────────────────────────────────────────────── -.const noteList = (await client.getConsumableNotes(alice.id())).map((rec) => -..rec.inputNoteRecord().toNote(), -.); - -.await client.submitNewTransaction( -..alice.id(), -..client.newConsumeTransactionRequest(noteList), -.); +.const noteList = await client.notes.listAvailable({ account: alice.id() }); +.await client.transactions.consume({ +..account: alice.id(), +..notes: noteList.map((n) => n.inputNoteRecord().id().toString()), +.}); .// ── build 3 P2ID notes (100 MID each) ───────────────────────────────────────────── .const recipientAddresses = [ @@ -493,25 +459,19 @@ export async function multiSendWithDelegatedProver(): Promise { ..'mtst1arpee6y9cm8t7ypn33pc8fzj6gkzz7kd', .]; -.const assets = new NoteAssets([new FungibleAsset(faucet.id(), BigInt(100))]); - -.const p2idNotes = recipientAddresses.map((addr) => { -..const receiverAccountId = Address.fromBech32(addr).accountId(); -..const note = Note.createP2IDNote( -...alice.id(), -...receiverAccountId, -...assets, -...NoteType.Public, -...new NoteAttachment(), -..); - -..return OutputNote.full(note); -.}); +.const p2idNotes = recipientAddresses.map((addr) => +..createP2IDNote({ +...from: alice.id(), +...to: addr, +...assets: { token: faucet.id(), amount: BigInt(100) }, +...type: 'public', +..}), +.); .// ── create all P2ID notes ─────────────────────────────────────────────────────────────── .const builder = new TransactionRequestBuilder(); .const txRequest = builder.withOwnOutputNotes(new OutputNoteArray(p2idNotes)).build(); -.await client.submitNewTransaction(alice.id(), txRequest); +.await client.transactions.submit(alice.id(), txRequest); .console.log('All notes created ✅'); }` }, diff --git a/docs/src/web-client/foreign_procedure_invocation_tutorial.md b/docs/src/web-client/foreign_procedure_invocation_tutorial.md index 1998a78..8631d9d 100644 --- a/docs/src/web-client/foreign_procedure_invocation_tutorial.md +++ b/docs/src/web-client/foreign_procedure_invocation_tutorial.md @@ -131,24 +131,13 @@ export async function foreignProcedureInvocation(): Promise { } // dynamic import → only in the browser, so WASM is loaded client‑side - const { - AccountBuilder, - AccountComponent, - Address, - AccountType, - AuthSecretKey, - StorageSlot, - TransactionRequestBuilder, - ForeignAccount, - ForeignAccountArray, - AccountStorageRequirements, - WebClient, - AccountStorageMode, - } = await import('@miden-sdk/miden-sdk'); + const { Address, AuthSecretKey, StorageSlot, MidenClient } = await import( + '@miden-sdk/miden-sdk' + ); const nodeEndpoint = 'https://rpc.testnet.miden.io'; - const client = await WebClient.createClient(nodeEndpoint); - console.log('Current block number: ', (await client.syncState()).blockNum()); + const client = await MidenClient.create({ rpcUrl: nodeEndpoint }); + console.log('Current block number: ', (await client.sync()).blockNum()); // ------------------------------------------------------------------------- // STEP 1: Create the Count Reader Contract @@ -169,7 +158,7 @@ export async function foreignProcedureInvocation(): Promise { pub proc copy_count exec.tx::execute_foreign_procedure # => [count] - + push.COUNT_READER_SLOT[0..2] # [slot_id_prefix, slot_id_suffix, count] @@ -187,63 +176,44 @@ export async function foreignProcedureInvocation(): Promise { const countReaderSlotName = 'miden::tutorials::count_reader'; const counterSlotName = 'miden::tutorials::counter'; - const builder = client.createCodeBuilder(); - const countReaderComponentCode = - builder.compileAccountComponentCode(countReaderCode); - const countReaderComponent = AccountComponent.compile( - countReaderComponentCode, - [StorageSlot.emptyValue(countReaderSlotName)], - ).withSupportsAllTypes(); + // Compile the count reader component + const countReaderComponent = await client.compile.component({ + code: countReaderCode, + slots: [StorageSlot.emptyValue(countReaderSlotName)], + }); const walletSeed = new Uint8Array(32); crypto.getRandomValues(walletSeed); - const secretKey = AuthSecretKey.rpoFalconWithRNG(walletSeed); - const authComponent = - AccountComponent.createAuthComponentFromSecretKey(secretKey); - - const countReaderContract = new AccountBuilder(walletSeed) - .accountType(AccountType.RegularAccountImmutableCode) - .storageMode(AccountStorageMode.public()) - .withAuthComponent(authComponent) - .withComponent(countReaderComponent) - .build(); - - await client.addAccountSecretKeyToWebStore( - countReaderContract.account.id(), - secretKey, - ); - await client.syncState(); + const auth = AuthSecretKey.rpoFalconWithRNG(walletSeed); - // Create the count reader contract account (using available WebClient API) + // Create the count reader contract account console.log('Creating count reader contract account...'); - console.log( - 'Count reader contract ID:', - countReaderContract.account.id().toString(), - ); + const countReaderAccount = await client.accounts.create({ + type: 'ImmutableContract', + storage: 'public', + seed: walletSeed, + auth, + components: [countReaderComponent], + }); + + console.log('Count reader contract ID:', countReaderAccount.id().toString()); - await client.newAccount(countReaderContract.account, false); + await client.sync(); // ------------------------------------------------------------------------- // STEP 2: Build & Get State of the Counter Contract // ------------------------------------------------------------------------- console.log('\n[STEP 2] Building counter contract from public state'); - // Define the Counter Contract account id from counter contract deploy (same as Rust) + // Define the Counter Contract account id from counter contract deploy const counterContractId = Address.fromBech32( 'mtst1arjemrxne8lj5qz4mg9c8mtyxg954483', ).accountId(); // Import the counter contract - let counterContractAccount = await client.getAccount(counterContractId); - if (!counterContractAccount) { - await client.importAccountById(counterContractId); - await client.syncState(); - counterContractAccount = await client.getAccount(counterContractId); - if (!counterContractAccount) { - throw new Error(`Account not found after import: ${counterContractId}`); - } - } + const counterContractAccount = + await client.accounts.getOrImport(counterContractId); console.log( 'Account storage slot:', counterContractAccount.storage().getItem(counterSlotName)?.toHex(), @@ -292,18 +262,16 @@ export async function foreignProcedureInvocation(): Promise { end `; - // Create the counter contract component to get the procedure hash (following Rust pattern) - const counterContractComponentCode = - builder.compileAccountComponentCode(counterContractCode); - const counterContractComponent = AccountComponent.compile( - counterContractComponentCode, - [StorageSlot.emptyValue(counterSlotName)], - ).withSupportsAllTypes(); + // Compile the counter contract component to get the procedure hash + const counterContractComponent = await client.compile.component({ + code: counterContractCode, + slots: [StorageSlot.emptyValue(counterSlotName)], + }); const getCountProcHash = counterContractComponent.getProcedureHash('get_count'); - // Build the script that calls the count reader contract (exactly from reader_script.masm with replacements) + // Build the script that calls the count reader contract const fpiScriptCode = ` use external_contract::count_reader_contract use miden::core::sys @@ -327,44 +295,30 @@ export async function foreignProcedureInvocation(): Promise { end `; - // Create the library for the count reader contract - const countReaderLib = builder.buildLibrary( - 'external_contract::count_reader_contract', - countReaderCode, - ); - builder.linkDynamicLibrary(countReaderLib); - // Compile the transaction script with the count reader library - const txScript = builder.compileTxScript(fpiScriptCode); - - // foreign account - const storageRequirements = new AccountStorageRequirements(); - const foreignAccount = ForeignAccount.public( - counterContractId, - storageRequirements, - ); - - // Build a transaction request with the custom script - const txRequest = new TransactionRequestBuilder() - .withCustomScript(txScript) - .withForeignAccounts(new ForeignAccountArray([foreignAccount])) - .build(); - - // Execute the transaction on the count reader contract and send it to the network (following Rust pattern) - const txResult = await client.submitNewTransaction( - countReaderContract.account.id(), - txRequest, - ); + const script = await client.compile.txScript({ + code: fpiScriptCode, + libraries: [ + { namespace: 'external_contract::count_reader_contract', code: countReaderCode }, + ], + }); + + // Execute the transaction on the count reader contract and send it to the network + const txId = await client.transactions.execute({ + account: countReaderAccount.id(), + script, + foreignAccounts: [{ id: counterContractId }], + }); console.log( 'View transaction on MidenScan: https://testnet.midenscan.com/tx/' + - txResult.toHex(), + txId.toHex(), ); - await client.syncState(); + await client.sync(); - // Retrieve updated contract data to see the results (following Rust pattern) - const updatedCounterContract = await client.getAccount( + // Retrieve updated contract data to see the results + const updatedCounterContract = await client.accounts.get( counterContractAccount.id(), ); console.log( @@ -372,8 +326,8 @@ export async function foreignProcedureInvocation(): Promise { updatedCounterContract?.storage().getItem(counterSlotName)?.toHex(), ); - const updatedCountReaderContract = await client.getAccount( - countReaderContract.account.id(), + const updatedCountReaderContract = await client.accounts.get( + countReaderAccount.id(), ); console.log( 'count reader contract storage:', @@ -423,27 +377,6 @@ Count reader contract ID: 0x90128b4e27f34500000720bedaa49b Account storage slot: 0x0000000000000000000000000000000000000000000000001200000000000000 [STEP 3] Call counter contract with FPI from count reader contract -fpiScript - use external_contract::count_reader_contract - use miden::core::sys - - begin - push.0x92495ca54d519eb5e4ba22350f837904d3895e48d74d8079450f19574bb84cb6 - # => [GET_COUNT_HASH] - - push.297741160627968 - # => [account_id_suffix, GET_COUNT_HASH] - - push.12911083037950619392 - # => [account_id_prefix, account_id_suffix, GET_COUNT_HASH] - - call.count_reader_contract::copy_count - # => [] - - exec.sys::truncate_stack - # => [] - - end View transaction on MidenScan: https://testnet.midenscan.com/tx/0xffff3dc5454154d1ccf64c1ad170bdef2df471c714f6fe6ab542d060396b559f counter contract storage: 0x0000000000000000000000000000000000000000000000001200000000000000 count reader contract storage: 0x0000000000000000000000000000000000000000000000001200000000000000 @@ -532,38 +465,40 @@ This script: ### Getting Procedure Hashes -In the WebClient, we get the procedure hash using the [`getProcedureHash`](https://github.com/0xMiden/miden-tutorials/blob/7bfa1996979cbb221b8cab455596093535787784/web-client/lib/foreignProcedureInvocation.ts#L176) method: +Compile the counter contract component using `client.compile.component()` and call `getProcedureHash()` to obtain the hash needed by the FPI script: ```ts -let getCountProcHash = counterContractComponent.getProcedureHash('get_count'); +const counterContractComponent = await client.compile.component({ + code: counterContractCode, + slots: [StorageSlot.emptyValue(counterSlotName)], +}); + +const getCountProcHash = counterContractComponent.getProcedureHash('get_count'); ``` -### Foreign Accounts +### Compiling the Transaction Script with a Library -To execute foreign procedure calls, we need to specify the foreign account in our transaction request: +Use `client.compile.txScript()` and pass the count reader library inline. The library is linked dynamically so the script can call its procedures: ```ts -let foreignAccount = ForeignAccount.public( - counterContractId, - storageRequirements, -); - -let txRequest = new TransactionRequestBuilder() - .withCustomScript(txScript) - .withForeignAccounts(new ForeignAccountArray([foreignAccount])) - .build(); +const script = await client.compile.txScript({ + code: fpiScriptCode, + libraries: [ + { namespace: 'external_contract::count_reader_contract', code: countReaderCode }, + ], +}); ``` -### Account Component Libraries +### Foreign Accounts -We create a library for the count reader contract so our transaction script can call its procedures: +Pass the foreign account directly in the `execute()` call using the `foreignAccounts` option. The client creates the `ForeignAccount` and `AccountStorageRequirements` internally — no manual construction needed: ```ts -const countReaderLib = builder.buildLibrary( - 'external_contract::count_reader_contract', - countReaderCode, -); -builder.linkDynamicLibrary(countReaderLib); +const txId = await client.transactions.execute({ + account: countReaderAccount.id(), + script, + foreignAccounts: [{ id: counterContractId }], +}); ``` ## Summary diff --git a/docs/src/web-client/mint_consume_create_tutorial.md b/docs/src/web-client/mint_consume_create_tutorial.md index 81c03c7..8070b46 100644 --- a/docs/src/web-client/mint_consume_create_tutorial.md +++ b/docs/src/web-client/mint_consume_create_tutorial.md @@ -52,35 +52,31 @@ console.log('Mint tx:', mintResult.transactionId); // Wait for the mint transaction to be committed await waitForCommit(mintResult.transactionId);`}, typescript: { code:`// 4. Mint tokens from the faucet to Alice -await client.syncState(); +await client.sync(); console.log("Minting tokens to Alice..."); -const mintTxRequest = client.newMintTransactionRequest( -.alice.id(), // Target account (who receives the tokens) -.faucet.id(), // Faucet account (who mints the tokens) -.NoteType.Public, // Note visibility (public = onchain) -.BigInt(1000), // Amount to mint (in base units) -); - -await client.submitNewTransaction(faucet.id(), mintTxRequest); +const mintTxId = await client.transactions.mint({ +.account: faucet.id(), // Faucet account (who mints the tokens) +.to: alice.id(), // Target account (who receives the tokens) +.amount: BigInt(1000), // Amount to mint (in base units) +.type: 'public', // Note visibility (public = onchain) +}); // Wait for the transaction to be processed -console.log("Waiting 10 seconds for transaction confirmation..."); -await new Promise((resolve) => setTimeout(resolve, 10000)); -await client.syncState();` }, +console.log("Waiting for transaction confirmation..."); +await client.transactions.waitFor(mintTxId.toHex()); +await client.sync();` }, }} reactFilename="lib/react/createMintConsume.tsx" tsFilename="lib/createMintConsume.ts" /> ### What's happening here? -1. **newMintTransactionRequest**: Creates a request to mint tokens to Alice. Note that this is only possible to submit transactions on the faucets' behalf if the user controls the faucet (i.e. its keys are stored in the client). -2. **newTransaction**: Locally executes and proves the transaction. -3. **submitTransaction**: Sends the transaction to the network. -4. Wait 10 seconds for the transaction to be included in a block. +1. **client.transactions.mint()**: Creates, proves, and submits a mint transaction to Alice. Note that this is only possible to submit transactions on the faucets' behalf if the user controls the faucet (i.e. its keys are stored in the client). +2. **client.transactions.waitFor()**: Polls until the transaction is committed on-chain. ## Step 2: Find consumable notes After minting, Alice has a note waiting for her but the tokens aren't in her account yet. -To identify notes that are ready to consume, the Miden WebClient provides the `getConsumableNotes` function: +To identify notes that are ready to consume, the MidenClient provides the `client.notes.listAvailable()` method: n.inputNoteRecord().id().toString()); console.log('Consumable notes:', noteIds);` }, typescript: { code: `// 5. Find notes available for consumption -const mintedNotes = await client.getConsumableNotes(alice.id()); +const mintedNotes = await client.notes.listAvailable({ account: alice.id() }); console.log(\`Found \${mintedNotes.length} note(s) to consume\`); -const mintedNoteList = mintedNotes.map((n) => n.inputNoteRecord().toNote()); console.log( .'Minted notes:', -.mintedNoteList.map((note) => note.id().toString()), +.mintedNotes.map((n) => n.inputNoteRecord().id().toString()), );` }, }} reactFilename="lib/react/createMintConsume.tsx" tsFilename="lib/createMintConsume.ts" /> @@ -109,11 +104,12 @@ await consume({ accountId: aliceId, noteIds }); console.log('Notes consumed.');` }, typescript: { code: `// 6. Consume the notes to add tokens to Alice's balance console.log('Consuming minted notes...'); -const consumeTxRequest = client.newConsumeTransactionRequest(mintedNoteList); - -await client.submitNewTransaction(alice.id(), consumeTxRequest); +await client.transactions.consume({ +.account: alice.id(), +.notes: mintedNotes.map((n) => n.inputNoteRecord().id().toString()), +}); -await client.syncState(); +await client.sync(); console.log('Notes consumed.');` }, }} reactFilename="lib/react/createMintConsume.tsx" tsFilename="lib/createMintConsume.ts" /> @@ -138,20 +134,16 @@ await send({ }); console.log('Tokens sent successfully!');` }, typescript: { code: `// 7. Send tokens from Alice to Bob -const bobAccountId = Address.fromBech32( -.'mtst1apve54rq8ux0jqqqqrkh5y0r0y8cwza6_qruqqypuyph', -).accountId(); +const bobAddress = 'mtst1apve54rq8ux0jqqqqrkh5y0r0y8cwza6_qruqqypuyph'; console.log("Sending tokens to Bob's account..."); -const sendTxRequest = client.newSendTransactionRequest( -.alice.id(), // Sender account ID -.bobAccountId, // Recipient account ID -.faucet.id(), // Asset ID (faucet that created the tokens) -.NoteType.Public, // Note visibility -.BigInt(100), // Amount to send -); - -await client.submitNewTransaction(alice.id(), sendTxRequest); +await client.transactions.send({ +.account: alice.id(), // Sender account ID +.to: bobAddress, // Recipient (bech32 address) +.token: faucet.id(), // Asset ID (faucet that created the tokens) +.amount: BigInt(100), // Amount to send +.type: 'public', // Note visibility +}); console.log('Tokens sent successfully!');` }, }} reactFilename="lib/react/createMintConsume.tsx" tsFilename="lib/createMintConsume.ts" /> @@ -261,90 +253,78 @@ export async function createMintConsume(): Promise { .} .// dynamic import → only in the browser, so WASM is loaded client‑side -.const { WebClient, AccountStorageMode, AuthScheme, NoteType, Address } = -..await import('@miden-sdk/miden-sdk'); +.const { MidenClient } = await import('@miden-sdk/miden-sdk'); -.const nodeEndpoint = 'https://rpc.testnet.miden.io'; -.const client = await WebClient.createClient(nodeEndpoint); +.const client = await MidenClient.create({ +..rpcUrl: 'https://rpc.testnet.miden.io', +.}); .// 1. Sync with the latest blockchain state -.const state = await client.syncState(); +.const state = await client.sync(); .console.log('Latest block number:', state.blockNum()); .// 2. Create Alice's account .console.log('Creating account for Alice…'); -.const aliceSeed = new Uint8Array(32); -.crypto.getRandomValues(aliceSeed); -.const alice = await client.newWallet( -..AccountStorageMode.public(), -..true, -..AuthScheme.AuthRpoFalcon512, -..aliceSeed, -.); +.const alice = await client.accounts.create({ +..type: 'MutableWallet', +..storage: 'public', +.}); .console.log('Alice ID:', alice.id().toString()); .// 3. Deploy a fungible faucet .console.log('Creating faucet…'); -.const faucet = await client.newFaucet( -..AccountStorageMode.public(), -..false, -..'MID', -..8, -..BigInt(1_000_000), -..AuthScheme.AuthRpoFalcon512, -.); +.const faucet = await client.accounts.create({ +..type: 'FungibleFaucet', +..symbol: 'MID', +..decimals: 8, +..maxSupply: BigInt(1_000_000), +..storage: 'public', +.}); .console.log('Faucet ID:', faucet.id().toString()); -.await client.syncState(); +.await client.sync(); .// 4. Mint tokens to Alice -.await client.syncState(); .console.log('Minting tokens to Alice...'); -.const mintTxRequest = client.newMintTransactionRequest( -..alice.id(), -..faucet.id(), -..NoteType.Public, -..BigInt(1000), -.); - -.await client.submitNewTransaction(faucet.id(), mintTxRequest); +.const mintTxId = await client.transactions.mint({ +..account: faucet.id(), +..to: alice.id(), +..amount: BigInt(1000), +..type: 'public', +.}); -.console.log('Waiting 10 seconds for transaction confirmation...'); -.await new Promise((resolve) => setTimeout(resolve, 10000)); -.await client.syncState(); +.console.log('Waiting for transaction confirmation...'); +.await client.transactions.waitFor(mintTxId.toHex()); +.await client.sync(); .// 5. Fetch minted notes -.const mintedNotes = await client.getConsumableNotes(alice.id()); -.const mintedNoteList = mintedNotes.map((n) => n.inputNoteRecord().toNote()); +.const mintedNotes = await client.notes.listAvailable({ account: alice.id() }); .console.log( ..'Minted notes:', -..mintedNoteList.map((note) => note.id().toString()), +..mintedNotes.map((n) => n.inputNoteRecord().id().toString()), .); .// 6. Consume minted notes .console.log('Consuming minted notes...'); -.const consumeTxRequest = client.newConsumeTransactionRequest(mintedNoteList); +.await client.transactions.consume({ +..account: alice.id(), +..notes: mintedNotes.map((n) => n.inputNoteRecord().id().toString()), +.}); -.await client.submitNewTransaction(alice.id(), consumeTxRequest); - -.await client.syncState(); +.await client.sync(); .console.log('Notes consumed.'); .// 7. Send tokens to Bob -.const bobAccountId = Address.fromBech32( -..'mtst1apve54rq8ux0jqqqqrkh5y0r0y8cwza6_qruqqypuyph', -.).accountId(); +.const bobAddress = 'mtst1apve54rq8ux0jqqqqrkh5y0r0y8cwza6_qruqqypuyph'; .console.log("Sending tokens to Bob's account..."); -.const sendTxRequest = client.newSendTransactionRequest( -..alice.id(), -..bobAccountId, -..faucet.id(), -..NoteType.Public, -..BigInt(100), -.); - -.await client.submitNewTransaction(alice.id(), sendTxRequest); +.await client.transactions.send({ +..account: alice.id(), +..to: bobAddress, +..token: faucet.id(), +..amount: BigInt(100), +..type: 'public', +.}); .console.log('Tokens sent successfully!'); }` }, }} reactFilename="lib/react/createMintConsume.tsx" tsFilename="lib/createMintConsume.ts" /> diff --git a/docs/src/web-client/unauthenticated_note_how_to.md b/docs/src/web-client/unauthenticated_note_how_to.md index c574355..e311854 100644 --- a/docs/src/web-client/unauthenticated_note_how_to.md +++ b/docs/src/web-client/unauthenticated_note_how_to.md @@ -261,12 +261,10 @@ export async function unauthenticatedNoteTransfer(): Promise { .if (typeof window === 'undefined') return console.warn('Run in browser'); .const { -..WebClient, -..AccountStorageMode, -..AuthScheme, -..NoteType, +..MidenClient, ..TransactionProver, ..Note, +..NoteType, ..NoteAssets, ..OutputNoteArray, ..FungibleAsset, @@ -277,85 +275,64 @@ export async function unauthenticatedNoteTransfer(): Promise { ..OutputNote, .} = await import('@miden-sdk/miden-sdk'); -.const client = await WebClient.createClient('https://rpc.testnet.miden.io'); +.const client = await MidenClient.create({ +..rpcUrl: 'https://rpc.testnet.miden.io', +.}); .const prover = TransactionProver.newLocalProver(); -.console.log('Latest block:', (await client.syncState()).blockNum()); +.console.log('Latest block:', (await client.sync()).blockNum()); .// ── Creating new account ────────────────────────────────────────────────────── .console.log('Creating accounts'); .console.log('Creating account for Alice…'); -.const alice = await client.newWallet( -..AccountStorageMode.public(), -..true, -..AuthScheme.AuthRpoFalcon512, -.); +.const alice = await client.accounts.create({ +..type: 'MutableWallet', +..storage: 'public', +.}); .console.log('Alice account ID:', alice.id().toString()); .const wallets = []; .for (let i = 0; i < 5; i++) { -..const wallet = await client.newWallet( -...AccountStorageMode.public(), -...true, -...AuthScheme.AuthRpoFalcon512, -..); +..const wallet = await client.accounts.create({ +...type: 'MutableWallet', +...storage: 'public', +..}); ..wallets.push(wallet); ..console.log('wallet ', i.toString(), wallet.id().toString()); .} .// ── Creating new faucet ────────────────────────────────────────────────────── -.const faucet = await client.newFaucet( -..AccountStorageMode.public(), -..false, -..'MID', -..8, -..BigInt(1_000_000), -..AuthScheme.AuthRpoFalcon512, -.); +.const faucet = await client.accounts.create({ +..type: 'FungibleFaucet', +..symbol: 'MID', +..decimals: 8, +..maxSupply: BigInt(1_000_000), +..storage: 'public', +.}); .console.log('Faucet ID:', faucet.id().toString()); .// ── mint 10 000 MID to Alice ────────────────────────────────────────────────────── -.{ -..const txResult = await client.executeTransaction( -...faucet.id(), -...client.newMintTransactionRequest( -....alice.id(), -....faucet.id(), -....NoteType.Public, -....BigInt(10_000), -...), -..); -..const proven = await client.proveTransaction(txResult, prover); -..const submissionHeight = await client.submitProvenTransaction( -...proven, -...txResult, -..); -..await client.applyTransaction(txResult, submissionHeight); -.} +.const mintTxId = await client.transactions.mint({ +..account: faucet.id(), +..to: alice.id(), +..amount: BigInt(10_000), +..type: 'public', +..prover, +.}); .console.log('Waiting for settlement'); -.await new Promise((r) => setTimeout(r, 7_000)); -.await client.syncState(); +.await client.transactions.waitFor(mintTxId.toHex()); +.await client.sync(); .// ── Consume the freshly minted note ────────────────────────────────────────────── -.const noteList = (await client.getConsumableNotes(alice.id())).map((rec) => -..rec.inputNoteRecord().toNote(), -.); - -.{ -..const txResult = await client.executeTransaction( -...alice.id(), -...client.newConsumeTransactionRequest(noteList), -..); -..const proven = await client.proveTransaction(txResult, prover); -..const submissionHeight = await client.submitProvenTransaction( -...proven, -...txResult, -..); -..await client.applyTransaction(txResult, submissionHeight); -..await client.syncState(); -.} +.const noteList = await client.notes.listAvailable({ account: alice.id() }); +.await client.transactions.consume({ +..account: alice.id(), +..notes: noteList.map((n) => n.inputNoteRecord().id().toString()), +..prover, +.}); +.await client.sync(); .// ── Create unauthenticated note transfer chain ───────────────────────────────────────────── .// Alice → wallet 1 → wallet 2 → wallet 3 → wallet 4 @@ -384,16 +361,7 @@ export async function unauthenticatedNoteTransfer(): Promise { ..{ ...const builder = new TransactionRequestBuilder(); ...const request = builder.withOwnOutputNotes(new OutputNoteArray([outputP2ID])).build(); -...const txResult = await client.executeTransaction( -....sender.id(), -....request, -...); -...const proven = await client.proveTransaction(txResult, prover); -...const submissionHeight = await client.submitProvenTransaction( -....proven, -....txResult, -...); -...await client.applyTransaction(txResult, submissionHeight); +...await client.transactions.submit(sender.id(), request, { prover }); ..} ..console.log('Consuming P2ID note...'); @@ -404,28 +372,14 @@ export async function unauthenticatedNoteTransfer(): Promise { ..const consumeRequest = consumeBuilder.withInputNotes(new NoteAndArgsArray([noteIdAndArgs])).build(); ..{ -...const txResult = await client.executeTransaction( +...const txId = await client.transactions.submit( ....receiver.id(), ....consumeRequest, +....{ prover }, ...); -...const proven = await client.proveTransaction(txResult, prover); -...const submissionHeight = await client.submitProvenTransaction( -....proven, -....txResult, -...); -...const txExecutionResult = await client.applyTransaction( -....txResult, -....submissionHeight, -...); - -...const txId = txExecutionResult -....executedTransaction() -....id() -....toHex() -....toString(); ...console.log( -....\`Consumed Note Tx on MidenScan: https://testnet.midenscan.com/tx/\${txId}\`, +....\`Consumed Note Tx on MidenScan: https://testnet.midenscan.com/tx/\${txId.toHex()}\`, ...); ..} From 16e458186adbae7ef36c2092371fb768922733f0 Mon Sep 17 00:00:00 2001 From: Wiktor Starczewski Date: Thu, 26 Feb 2026 01:07:28 +0100 Subject: [PATCH 05/14] fix(docs): format markdown files with prettier --- docs/src/web-client/counter_contract_tutorial.md | 15 ++++++++++----- .../foreign_procedure_invocation_tutorial.md | 15 ++++++++++----- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/docs/src/web-client/counter_contract_tutorial.md b/docs/src/web-client/counter_contract_tutorial.md index e3b98f7..47d4fd3 100644 --- a/docs/src/web-client/counter_contract_tutorial.md +++ b/docs/src/web-client/counter_contract_tutorial.md @@ -116,9 +116,8 @@ export async function incrementCounterContract(): Promise { } // dynamic import → only in the browser, so WASM is loaded client‑side - const { Address, AuthSecretKey, StorageSlot, MidenClient } = await import( - '@miden-sdk/miden-sdk' - ); + const { Address, AuthSecretKey, StorageSlot, MidenClient } = + await import('@miden-sdk/miden-sdk'); const nodeEndpoint = 'https://rpc.testnet.miden.io'; const client = await MidenClient.create({ rpcUrl: nodeEndpoint }); @@ -205,7 +204,10 @@ export async function incrementCounterContract(): Promise { const script = await client.compile.txScript({ code: txScriptCode, libraries: [ - { namespace: 'external_contract::counter_contract', code: counterContractCode }, + { + namespace: 'external_contract::counter_contract', + code: counterContractCode, + }, ], }); @@ -348,7 +350,10 @@ Use `client.compile.txScript()` to compile a transaction script. Pass any needed const script = await client.compile.txScript({ code: txScriptCode, libraries: [ - { namespace: 'external_contract::counter_contract', code: counterContractCode }, + { + namespace: 'external_contract::counter_contract', + code: counterContractCode, + }, ], }); ``` diff --git a/docs/src/web-client/foreign_procedure_invocation_tutorial.md b/docs/src/web-client/foreign_procedure_invocation_tutorial.md index 8631d9d..0e9b951 100644 --- a/docs/src/web-client/foreign_procedure_invocation_tutorial.md +++ b/docs/src/web-client/foreign_procedure_invocation_tutorial.md @@ -131,9 +131,8 @@ export async function foreignProcedureInvocation(): Promise { } // dynamic import → only in the browser, so WASM is loaded client‑side - const { Address, AuthSecretKey, StorageSlot, MidenClient } = await import( - '@miden-sdk/miden-sdk' - ); + const { Address, AuthSecretKey, StorageSlot, MidenClient } = + await import('@miden-sdk/miden-sdk'); const nodeEndpoint = 'https://rpc.testnet.miden.io'; const client = await MidenClient.create({ rpcUrl: nodeEndpoint }); @@ -299,7 +298,10 @@ export async function foreignProcedureInvocation(): Promise { const script = await client.compile.txScript({ code: fpiScriptCode, libraries: [ - { namespace: 'external_contract::count_reader_contract', code: countReaderCode }, + { + namespace: 'external_contract::count_reader_contract', + code: countReaderCode, + }, ], }); @@ -484,7 +486,10 @@ Use `client.compile.txScript()` and pass the count reader library inline. The li const script = await client.compile.txScript({ code: fpiScriptCode, libraries: [ - { namespace: 'external_contract::count_reader_contract', code: countReaderCode }, + { + namespace: 'external_contract::count_reader_contract', + code: countReaderCode, + }, ], }); ``` From cf7877cb1cc2b0848e5ea408011febdc1618401f Mon Sep 17 00:00:00 2001 From: Wiktor Starczewski Date: Thu, 26 Feb 2026 01:16:47 +0100 Subject: [PATCH 06/14] refactor(tutorials): replace AccountType string literals with enum references --- docs/src/web-client/counter_contract_tutorial.md | 8 ++++---- docs/src/web-client/create_deploy_tutorial.md | 12 ++++++------ .../web-client/creating_multiple_notes_tutorial.md | 10 ++++++---- .../foreign_procedure_invocation_tutorial.md | 4 ++-- docs/src/web-client/mint_consume_create_tutorial.md | 6 +++--- docs/src/web-client/unauthenticated_note_how_to.md | 7 ++++--- web-client/lib/foreignProcedureInvocation.ts | 9 ++++----- web-client/lib/incrementCounterContract.ts | 7 +++---- 8 files changed, 32 insertions(+), 31 deletions(-) diff --git a/docs/src/web-client/counter_contract_tutorial.md b/docs/src/web-client/counter_contract_tutorial.md index 47d4fd3..c537dfa 100644 --- a/docs/src/web-client/counter_contract_tutorial.md +++ b/docs/src/web-client/counter_contract_tutorial.md @@ -116,7 +116,7 @@ export async function incrementCounterContract(): Promise { } // dynamic import → only in the browser, so WASM is loaded client‑side - const { Address, AuthSecretKey, StorageSlot, MidenClient } = + const { AccountType, Address, AuthSecretKey, StorageSlot, MidenClient } = await import('@miden-sdk/miden-sdk'); const nodeEndpoint = 'https://rpc.testnet.miden.io'; @@ -184,7 +184,7 @@ export async function incrementCounterContract(): Promise { // Create the counter contract account const account = await client.accounts.create({ - type: 'ImmutableContract', + type: AccountType.ImmutableContract, storage: 'public', seed: walletSeed, auth, @@ -328,13 +328,13 @@ const counterAccountComponent = await client.compile.component({ ### Creating the contract account -Use `client.accounts.create()` with `type: 'ImmutableContract'` to build and register the contract. You must supply a `seed` (for deterministic ID derivation) and a raw `AuthSecretKey` — the client stores the key automatically: +Use `client.accounts.create()` with `type: AccountType.ImmutableContract` to build and register the contract. You must supply a `seed` (for deterministic ID derivation) and a raw `AuthSecretKey` — the client stores the key automatically: ```ts const auth = AuthSecretKey.rpoFalconWithRNG(walletSeed); const account = await client.accounts.create({ - type: 'ImmutableContract', + type: AccountType.ImmutableContract, storage: 'public', seed: walletSeed, auth, diff --git a/docs/src/web-client/create_deploy_tutorial.md b/docs/src/web-client/create_deploy_tutorial.md index a887f58..2e0fb88 100644 --- a/docs/src/web-client/create_deploy_tutorial.md +++ b/docs/src/web-client/create_deploy_tutorial.md @@ -123,7 +123,7 @@ export async function createMintConsume(): Promise { .} .// dynamic import → only in the browser, so WASM is loaded client‑side -.const { MidenClient } = +.const { MidenClient, AccountType } = ..await import('@miden-sdk/miden-sdk'); .// Connect to Miden testnet RPC endpoint @@ -233,7 +233,7 @@ export async function createMintConsume(): Promise { .// 2. Create Alice's account .console.log('Creating account for Alice…'); .const alice = await client.accounts.create({ -..type: 'MutableWallet', // Mutable: account code can be upgraded later +..type: AccountType.MutableWallet, // Mutable: account code can be upgraded later ..storage: 'public', // Public: account state is visible on-chain .}); .console.log('Alice ID:', alice.id().toString()); @@ -262,7 +262,7 @@ console.log('Setup complete.');`}, // A faucet is an account that can mint new tokens console.log('Creating faucet…'); const faucetAccount = await client.accounts.create({ -.type: 'FungibleFaucet', // Fungible faucet: can mint divisible tokens +.type: AccountType.FungibleFaucet, // Fungible faucet: can mint divisible tokens .symbol: 'MID', // Token symbol (like ETH, BTC, etc.) .decimals: 8, // Decimals (8 means 1 MID = 100,000,000 base units) .maxSupply: BigInt(1_000_000), // Max supply: total tokens that can ever be minted @@ -347,7 +347,7 @@ export async function createMintConsume(): Promise { .} .// dynamic import → only in the browser, so WASM is loaded client‑side -.const { MidenClient } = +.const { MidenClient, AccountType } = ..await import('@miden-sdk/miden-sdk'); .const client = await MidenClient.create({ @@ -361,7 +361,7 @@ export async function createMintConsume(): Promise { .// 2. Create Alice's account .console.log('Creating account for Alice…'); .const alice = await client.accounts.create({ -..type: 'MutableWallet', +..type: AccountType.MutableWallet, ..storage: 'public', .}); .console.log('Alice ID:', alice.id().toString()); @@ -369,7 +369,7 @@ export async function createMintConsume(): Promise { .// 3. Deploy a fungible faucet .console.log('Creating faucet…'); .const faucet = await client.accounts.create({ -..type: 'FungibleFaucet', +..type: AccountType.FungibleFaucet, ..symbol: 'MID', ..decimals: 8, ..maxSupply: BigInt(1_000_000), diff --git a/docs/src/web-client/creating_multiple_notes_tutorial.md b/docs/src/web-client/creating_multiple_notes_tutorial.md index cfe71e4..af8f3cf 100644 --- a/docs/src/web-client/creating_multiple_notes_tutorial.md +++ b/docs/src/web-client/creating_multiple_notes_tutorial.md @@ -180,6 +180,7 @@ export default function MultiSendWithDelegatedProver() { .const { ..MidenClient, +..AccountType, ..createP2IDNote, ..OutputNoteArray, ..TransactionRequestBuilder, @@ -232,14 +233,14 @@ await consume({ accountId: aliceId, noteIds });`}, typescript: { code:`// ── Creating new account ────────────────────────────────────────────────────── console.log('Creating account for Alice…'); const alice = await client.accounts.create({ -.type: 'MutableWallet', +.type: AccountType.MutableWallet, .storage: 'public', }); console.log('Alice account ID:', alice.id().toString()); // ── Creating new faucet ────────────────────────────────────────────────────── const faucet = await client.accounts.create({ -.type: 'FungibleFaucet', +.type: AccountType.FungibleFaucet, .symbol: 'MID', .decimals: 8, .maxSupply: BigInt(1_000_000), @@ -404,6 +405,7 @@ export async function multiSendWithDelegatedProver(): Promise { .const { ..MidenClient, +..AccountType, ..createP2IDNote, ..OutputNoteArray, ..TransactionRequestBuilder, @@ -418,14 +420,14 @@ export async function multiSendWithDelegatedProver(): Promise { .// ── Creating new account ────────────────────────────────────────────────────── .console.log('Creating account for Alice…'); .const alice = await client.accounts.create({ -..type: 'MutableWallet', +..type: AccountType.MutableWallet, ..storage: 'public', .}); .console.log('Alice account ID:', alice.id().toString()); .// ── Creating new faucet ────────────────────────────────────────────────────── .const faucet = await client.accounts.create({ -..type: 'FungibleFaucet', +..type: AccountType.FungibleFaucet, ..symbol: 'MID', ..decimals: 8, ..maxSupply: BigInt(1_000_000), diff --git a/docs/src/web-client/foreign_procedure_invocation_tutorial.md b/docs/src/web-client/foreign_procedure_invocation_tutorial.md index 0e9b951..3d63bc4 100644 --- a/docs/src/web-client/foreign_procedure_invocation_tutorial.md +++ b/docs/src/web-client/foreign_procedure_invocation_tutorial.md @@ -131,7 +131,7 @@ export async function foreignProcedureInvocation(): Promise { } // dynamic import → only in the browser, so WASM is loaded client‑side - const { Address, AuthSecretKey, StorageSlot, MidenClient } = + const { AccountType, Address, AuthSecretKey, StorageSlot, MidenClient } = await import('@miden-sdk/miden-sdk'); const nodeEndpoint = 'https://rpc.testnet.miden.io'; @@ -189,7 +189,7 @@ export async function foreignProcedureInvocation(): Promise { // Create the count reader contract account console.log('Creating count reader contract account...'); const countReaderAccount = await client.accounts.create({ - type: 'ImmutableContract', + type: AccountType.ImmutableContract, storage: 'public', seed: walletSeed, auth, diff --git a/docs/src/web-client/mint_consume_create_tutorial.md b/docs/src/web-client/mint_consume_create_tutorial.md index 8070b46..bb491ed 100644 --- a/docs/src/web-client/mint_consume_create_tutorial.md +++ b/docs/src/web-client/mint_consume_create_tutorial.md @@ -253,7 +253,7 @@ export async function createMintConsume(): Promise { .} .// dynamic import → only in the browser, so WASM is loaded client‑side -.const { MidenClient } = await import('@miden-sdk/miden-sdk'); +.const { MidenClient, AccountType } = await import('@miden-sdk/miden-sdk'); .const client = await MidenClient.create({ ..rpcUrl: 'https://rpc.testnet.miden.io', @@ -266,7 +266,7 @@ export async function createMintConsume(): Promise { .// 2. Create Alice's account .console.log('Creating account for Alice…'); .const alice = await client.accounts.create({ -..type: 'MutableWallet', +..type: AccountType.MutableWallet, ..storage: 'public', .}); .console.log('Alice ID:', alice.id().toString()); @@ -274,7 +274,7 @@ export async function createMintConsume(): Promise { .// 3. Deploy a fungible faucet .console.log('Creating faucet…'); .const faucet = await client.accounts.create({ -..type: 'FungibleFaucet', +..type: AccountType.FungibleFaucet, ..symbol: 'MID', ..decimals: 8, ..maxSupply: BigInt(1_000_000), diff --git a/docs/src/web-client/unauthenticated_note_how_to.md b/docs/src/web-client/unauthenticated_note_how_to.md index e311854..a07da92 100644 --- a/docs/src/web-client/unauthenticated_note_how_to.md +++ b/docs/src/web-client/unauthenticated_note_how_to.md @@ -262,6 +262,7 @@ export async function unauthenticatedNoteTransfer(): Promise { .const { ..MidenClient, +..AccountType, ..TransactionProver, ..Note, ..NoteType, @@ -287,7 +288,7 @@ export async function unauthenticatedNoteTransfer(): Promise { .console.log('Creating account for Alice…'); .const alice = await client.accounts.create({ -..type: 'MutableWallet', +..type: AccountType.MutableWallet, ..storage: 'public', .}); .console.log('Alice account ID:', alice.id().toString()); @@ -295,7 +296,7 @@ export async function unauthenticatedNoteTransfer(): Promise { .const wallets = []; .for (let i = 0; i < 5; i++) { ..const wallet = await client.accounts.create({ -...type: 'MutableWallet', +...type: AccountType.MutableWallet, ...storage: 'public', ..}); ..wallets.push(wallet); @@ -304,7 +305,7 @@ export async function unauthenticatedNoteTransfer(): Promise { .// ── Creating new faucet ────────────────────────────────────────────────────── .const faucet = await client.accounts.create({ -..type: 'FungibleFaucet', +..type: AccountType.FungibleFaucet, ..symbol: 'MID', ..decimals: 8, ..maxSupply: BigInt(1_000_000), diff --git a/web-client/lib/foreignProcedureInvocation.ts b/web-client/lib/foreignProcedureInvocation.ts index badb633..652c154 100644 --- a/web-client/lib/foreignProcedureInvocation.ts +++ b/web-client/lib/foreignProcedureInvocation.ts @@ -5,9 +5,8 @@ export async function foreignProcedureInvocation(): Promise { return; } - const { AuthSecretKey, StorageSlot, MidenClient } = await import( - '@miden-sdk/miden-sdk' - ); + const { AccountType, AuthSecretKey, StorageSlot, MidenClient } = + await import('@miden-sdk/miden-sdk'); const nodeEndpoint = 'http://localhost:57291'; const client = await MidenClient.create({ rpcUrl: nodeEndpoint }); @@ -94,7 +93,7 @@ export async function foreignProcedureInvocation(): Promise { const counterAuth = AuthSecretKey.rpoFalconWithRNG(counterSeed); const counterAccount = await client.accounts.create({ - type: 'ImmutableContract', + type: AccountType.ImmutableContract, storage: 'public', seed: counterSeed, auth: counterAuth, @@ -137,7 +136,7 @@ export async function foreignProcedureInvocation(): Promise { const readerAuth = AuthSecretKey.rpoFalconWithRNG(readerSeed); const countReaderAccount = await client.accounts.create({ - type: 'ImmutableContract', + type: AccountType.ImmutableContract, storage: 'public', seed: readerSeed, auth: readerAuth, diff --git a/web-client/lib/incrementCounterContract.ts b/web-client/lib/incrementCounterContract.ts index b3796e0..97bc55f 100644 --- a/web-client/lib/incrementCounterContract.ts +++ b/web-client/lib/incrementCounterContract.ts @@ -5,9 +5,8 @@ export async function incrementCounterContract(): Promise { return; } - const { AuthSecretKey, StorageSlot, MidenClient } = await import( - '@miden-sdk/miden-sdk' - ); + const { AccountType, AuthSecretKey, StorageSlot, MidenClient } = + await import('@miden-sdk/miden-sdk'); const nodeEndpoint = 'http://localhost:57291'; const client = await MidenClient.create({ rpcUrl: nodeEndpoint }); @@ -60,7 +59,7 @@ export async function incrementCounterContract(): Promise { const auth = AuthSecretKey.rpoFalconWithRNG(walletSeed); const account = await client.accounts.create({ - type: 'ImmutableContract', + type: AccountType.ImmutableContract, storage: 'public', seed: walletSeed, auth, From 8439a2ac4061498c4c87ca699d2bacfa46795868 Mon Sep 17 00:00:00 2001 From: Wiktor Starczewski Date: Thu, 26 Feb 2026 01:32:11 +0100 Subject: [PATCH 07/14] refactor(tutorials): replace NoteVisibility and StorageMode string literals with enum references --- .../web-client/counter_contract_tutorial.md | 14 ++++++--- docs/src/web-client/create_deploy_tutorial.md | 22 +++++++------- .../creating_multiple_notes_tutorial.md | 30 +++++++++++-------- .../foreign_procedure_invocation_tutorial.md | 12 ++++++-- .../mint_consume_create_tutorial.md | 19 ++++++------ docs/src/web-client/react_wallet_tutorial.md | 10 +++++-- .../web-client/unauthenticated_note_how_to.md | 19 +++++++----- web-client/lib/foreignProcedureInvocation.ts | 6 ++-- web-client/lib/incrementCounterContract.ts | 4 +-- web-client/lib/react/createMintConsume.tsx | 9 +++--- .../react/multiSendWithDelegatedProver.tsx | 9 +++--- .../lib/react/unauthenticatedNoteTransfer.tsx | 11 +++---- 12 files changed, 99 insertions(+), 66 deletions(-) diff --git a/docs/src/web-client/counter_contract_tutorial.md b/docs/src/web-client/counter_contract_tutorial.md index c537dfa..0c1a1c0 100644 --- a/docs/src/web-client/counter_contract_tutorial.md +++ b/docs/src/web-client/counter_contract_tutorial.md @@ -116,8 +116,14 @@ export async function incrementCounterContract(): Promise { } // dynamic import → only in the browser, so WASM is loaded client‑side - const { AccountType, Address, AuthSecretKey, StorageSlot, MidenClient } = - await import('@miden-sdk/miden-sdk'); + const { + AccountType, + Address, + AuthSecretKey, + StorageMode, + StorageSlot, + MidenClient, + } = await import('@miden-sdk/miden-sdk'); const nodeEndpoint = 'https://rpc.testnet.miden.io'; const client = await MidenClient.create({ rpcUrl: nodeEndpoint }); @@ -185,7 +191,7 @@ export async function incrementCounterContract(): Promise { // Create the counter contract account const account = await client.accounts.create({ type: AccountType.ImmutableContract, - storage: 'public', + storage: StorageMode.Public, seed: walletSeed, auth, components: [counterAccountComponent], @@ -335,7 +341,7 @@ const auth = AuthSecretKey.rpoFalconWithRNG(walletSeed); const account = await client.accounts.create({ type: AccountType.ImmutableContract, - storage: 'public', + storage: StorageMode.Public, seed: walletSeed, auth, components: [counterAccountComponent], diff --git a/docs/src/web-client/create_deploy_tutorial.md b/docs/src/web-client/create_deploy_tutorial.md index 2e0fb88..4594437 100644 --- a/docs/src/web-client/create_deploy_tutorial.md +++ b/docs/src/web-client/create_deploy_tutorial.md @@ -88,6 +88,7 @@ react: { code: `// lib/react/createMintConsume.tsx 'use client'; import { MidenProvider, useMiden, useCreateWallet, useCreateFaucet } from '@miden-sdk/react'; +import { StorageMode } from '@miden-sdk/miden-sdk'; function CreateMintConsumeInner() { .const { isReady } = useMiden(); @@ -123,7 +124,7 @@ export async function createMintConsume(): Promise { .} .// dynamic import → only in the browser, so WASM is loaded client‑side -.const { MidenClient, AccountType } = +.const { MidenClient, AccountType, StorageMode } = ..await import('@miden-sdk/miden-sdk'); .// Connect to Miden testnet RPC endpoint @@ -210,7 +211,7 @@ Back in your library file, extend the function: react: { code: `const run = async () => { .// 1. Create Alice's wallet (public, mutable) .console.log('Creating account for Alice…'); -.const alice = await createWallet({ storageMode: 'public' }); +.const alice = await createWallet({ storageMode: StorageMode.Public }); .console.log('Alice ID:', alice.id().toString()); };` }, typescript: { code: `// lib/createMintConsume.ts @@ -234,7 +235,7 @@ export async function createMintConsume(): Promise { .console.log('Creating account for Alice…'); .const alice = await client.accounts.create({ ..type: AccountType.MutableWallet, // Mutable: account code can be upgraded later -..storage: 'public', // Public: account state is visible on-chain +..storage: StorageMode.Public, // Public: account state is visible on-chain .}); .console.log('Alice ID:', alice.id().toString()); }` }, @@ -253,7 +254,7 @@ const faucet = await createFaucet({ .tokenSymbol: 'MID', // Token symbol (like ETH, BTC, etc.) .decimals: 8, // Decimals (8 means 1 MID = 100,000,000 base units) .maxSupply: BigInt(1_000_000), // Max supply: total tokens that can ever be minted -.storageMode: 'public', // Public: faucet operations are transparent +.storageMode: StorageMode.Public, // Public: faucet operations are transparent }); console.log('Faucet account ID:', faucet.id().toString()); @@ -266,7 +267,7 @@ const faucetAccount = await client.accounts.create({ .symbol: 'MID', // Token symbol (like ETH, BTC, etc.) .decimals: 8, // Decimals (8 means 1 MID = 100,000,000 base units) .maxSupply: BigInt(1_000_000), // Max supply: total tokens that can ever be minted -.storage: 'public', // Public: faucet operations are transparent +.storage: StorageMode.Public, // Public: faucet operations are transparent }); console.log('Faucet account ID:', faucetAccount.id().toString()); @@ -298,6 +299,7 @@ Your final `lib/react/createMintConsume.tsx` (React) or `lib/createMintConsume.t react: { code: `'use client'; import { MidenProvider, useMiden, useCreateWallet, useCreateFaucet } from '@miden-sdk/react'; +import { StorageMode } from '@miden-sdk/miden-sdk'; function CreateMintConsumeInner() { .const { isReady } = useMiden(); @@ -307,7 +309,7 @@ function CreateMintConsumeInner() { .const run = async () => { ..// 1. Create Alice's wallet (public, mutable) ..console.log('Creating account for Alice…'); -..const alice = await createWallet({ storageMode: 'public' }); +..const alice = await createWallet({ storageMode: StorageMode.Public }); ..console.log('Alice ID:', alice.id().toString()); ..// 2. Deploy a fungible faucet @@ -316,7 +318,7 @@ function CreateMintConsumeInner() { ...tokenSymbol: 'MID', ...decimals: 8, ...maxSupply: BigInt(1_000_000), -...storageMode: 'public', +...storageMode: StorageMode.Public, ..}); ..console.log('Faucet ID:', faucet.id().toString()); @@ -347,7 +349,7 @@ export async function createMintConsume(): Promise { .} .// dynamic import → only in the browser, so WASM is loaded client‑side -.const { MidenClient, AccountType } = +.const { MidenClient, AccountType, StorageMode } = ..await import('@miden-sdk/miden-sdk'); .const client = await MidenClient.create({ @@ -362,7 +364,7 @@ export async function createMintConsume(): Promise { .console.log('Creating account for Alice…'); .const alice = await client.accounts.create({ ..type: AccountType.MutableWallet, -..storage: 'public', +..storage: StorageMode.Public, .}); .console.log('Alice ID:', alice.id().toString()); @@ -373,7 +375,7 @@ export async function createMintConsume(): Promise { ..symbol: 'MID', ..decimals: 8, ..maxSupply: BigInt(1_000_000), -..storage: 'public', +..storage: StorageMode.Public, .}); .console.log('Faucet ID:', faucet.id().toString()); diff --git a/docs/src/web-client/creating_multiple_notes_tutorial.md b/docs/src/web-client/creating_multiple_notes_tutorial.md index af8f3cf..f92acd4 100644 --- a/docs/src/web-client/creating_multiple_notes_tutorial.md +++ b/docs/src/web-client/creating_multiple_notes_tutorial.md @@ -143,6 +143,7 @@ mkdir -p lib react: { code: `'use client'; import { MidenProvider, useMiden, useCreateWallet, useCreateFaucet, useMint, useConsume, useMultiSend, useWaitForCommit, useWaitForNotes } from '@miden-sdk/react'; +import { NoteVisibility, StorageMode } from '@miden-sdk/miden-sdk'; function MultiSendInner() { .const { isReady } = useMiden(); @@ -181,6 +182,8 @@ export default function MultiSendWithDelegatedProver() { .const { ..MidenClient, ..AccountType, +..NoteVisibility, +..StorageMode, ..createP2IDNote, ..OutputNoteArray, ..TransactionRequestBuilder, @@ -201,7 +204,7 @@ Add the code snippet below to the function. This code creates a wallet and fauce { ..// 1. Create Alice's wallet ..console.log('Creating account for Alice…'); -..const alice = await createWallet({ storageMode: 'public' }); +..const alice = await createWallet({ storageMode: StorageMode.Public }); ..const aliceId = alice.id().toString(); ..console.log('Alice account ID:', aliceId); @@ -341,7 +345,7 @@ function MultiSendInner() { ...tokenSymbol: 'MID', ...decimals: 8, ...maxSupply: BigInt(1_000_000), -...storageMode: 'public', +...storageMode: StorageMode.Public, ..}); ..const faucetId = faucet.id().toString(); ..console.log('Faucet ID:', faucetId); @@ -351,7 +355,7 @@ function MultiSendInner() { ...faucetId, ...targetAccountId: aliceId, ...amount: BigInt(10_000), -...noteType: 'public', +...noteType: NoteVisibility.Public, ..}); ..console.log('Waiting for settlement…'); @@ -371,7 +375,7 @@ function MultiSendInner() { ....{ to: 'mtst1apjg2ul76wrkxyr5qlcnczaskypa4ljn', amount: BigInt(100) }, ....{ to: 'mtst1arpee6y9cm8t7ypn33pc8fzj6gkzz7kd', amount: BigInt(100) }, ...], -...noteType: 'public', +...noteType: NoteVisibility.Public, ..}); ..console.log('All notes created ✅'); @@ -406,6 +410,8 @@ export async function multiSendWithDelegatedProver(): Promise { .const { ..MidenClient, ..AccountType, +..NoteVisibility, +..StorageMode, ..createP2IDNote, ..OutputNoteArray, ..TransactionRequestBuilder, @@ -421,7 +427,7 @@ export async function multiSendWithDelegatedProver(): Promise { .console.log('Creating account for Alice…'); .const alice = await client.accounts.create({ ..type: AccountType.MutableWallet, -..storage: 'public', +..storage: StorageMode.Public, .}); .console.log('Alice account ID:', alice.id().toString()); @@ -431,7 +437,7 @@ export async function multiSendWithDelegatedProver(): Promise { ..symbol: 'MID', ..decimals: 8, ..maxSupply: BigInt(1_000_000), -..storage: 'public', +..storage: StorageMode.Public, .}); .console.log('Faucet ID:', faucet.id().toString()); diff --git a/docs/src/web-client/foreign_procedure_invocation_tutorial.md b/docs/src/web-client/foreign_procedure_invocation_tutorial.md index 3d63bc4..ed82799 100644 --- a/docs/src/web-client/foreign_procedure_invocation_tutorial.md +++ b/docs/src/web-client/foreign_procedure_invocation_tutorial.md @@ -131,8 +131,14 @@ export async function foreignProcedureInvocation(): Promise { } // dynamic import → only in the browser, so WASM is loaded client‑side - const { AccountType, Address, AuthSecretKey, StorageSlot, MidenClient } = - await import('@miden-sdk/miden-sdk'); + const { + AccountType, + Address, + AuthSecretKey, + StorageMode, + StorageSlot, + MidenClient, + } = await import('@miden-sdk/miden-sdk'); const nodeEndpoint = 'https://rpc.testnet.miden.io'; const client = await MidenClient.create({ rpcUrl: nodeEndpoint }); @@ -190,7 +196,7 @@ export async function foreignProcedureInvocation(): Promise { console.log('Creating count reader contract account...'); const countReaderAccount = await client.accounts.create({ type: AccountType.ImmutableContract, - storage: 'public', + storage: StorageMode.Public, seed: walletSeed, auth, components: [countReaderComponent], diff --git a/docs/src/web-client/mint_consume_create_tutorial.md b/docs/src/web-client/mint_consume_create_tutorial.md index bb491ed..ae76f5c 100644 --- a/docs/src/web-client/mint_consume_create_tutorial.md +++ b/docs/src/web-client/mint_consume_create_tutorial.md @@ -45,7 +45,7 @@ const mintResult = await mint({ .faucetId, // Faucet account (who mints the tokens) .targetAccountId: aliceId, // Target account (who receives the tokens) .amount: BigInt(1000), // Amount to mint (in base units) -.noteType: 'public', // Note visibility (public = onchain) +.noteType: NoteVisibility.Public, // Note visibility (public = onchain) }); console.log('Mint tx:', mintResult.transactionId); @@ -130,7 +130,7 @@ await send({ .to: bobAddress, .assetId: faucetId, .amount: BigInt(100), -.noteType: 'public', +.noteType: NoteVisibility.Public, }); console.log('Tokens sent successfully!');` }, typescript: { code: `// 7. Send tokens from Alice to Bob @@ -164,6 +164,7 @@ Here's the complete `lib/react/createMintConsume.tsx` (React) or `lib/createMint react: { code: `'use client'; import { MidenProvider, useMiden, useCreateWallet, useCreateFaucet, useMint, useConsume, useSend, useWaitForCommit, useWaitForNotes } from '@miden-sdk/react'; +import { NoteVisibility, StorageMode } from '@miden-sdk/miden-sdk'; function CreateMintConsumeInner() { .const { isReady } = useMiden(); @@ -178,7 +179,7 @@ function CreateMintConsumeInner() { .const run = async () => { ..// 1. Create Alice's wallet (public, mutable) ..console.log('Creating account for Alice…'); -..const alice = await createWallet({ storageMode: 'public' }); +..const alice = await createWallet({ storageMode: StorageMode.Public }); ..const aliceId = alice.id().toString(); ..console.log('Alice ID:', aliceId); @@ -188,7 +189,7 @@ function CreateMintConsumeInner() { ...tokenSymbol: 'MID', ...decimals: 8, ...maxSupply: BigInt(1_000_000), -...storageMode: 'public', +...storageMode: StorageMode.Public, ..}); ..const faucetId = faucet.id().toString(); ..console.log('Faucet ID:', faucetId); @@ -199,7 +200,7 @@ function CreateMintConsumeInner() { ...faucetId, ...targetAccountId: aliceId, ...amount: BigInt(1000), -...noteType: 'public', +...noteType: NoteVisibility.Public, ..}); ..console.log('Mint tx:', mintResult.transactionId); @@ -224,7 +225,7 @@ function CreateMintConsumeInner() { ...to: bobAddress, ...assetId: faucetId, ...amount: BigInt(100), -...noteType: 'public', +...noteType: NoteVisibility.Public, ..}); ..console.log('Tokens sent successfully!'); .}; @@ -253,7 +254,7 @@ export async function createMintConsume(): Promise { .} .// dynamic import → only in the browser, so WASM is loaded client‑side -.const { MidenClient, AccountType } = await import('@miden-sdk/miden-sdk'); +.const { MidenClient, AccountType, NoteVisibility, StorageMode } = await import('@miden-sdk/miden-sdk'); .const client = await MidenClient.create({ ..rpcUrl: 'https://rpc.testnet.miden.io', @@ -267,7 +268,7 @@ export async function createMintConsume(): Promise { .console.log('Creating account for Alice…'); .const alice = await client.accounts.create({ ..type: AccountType.MutableWallet, -..storage: 'public', +..storage: StorageMode.Public, .}); .console.log('Alice ID:', alice.id().toString()); @@ -278,7 +279,7 @@ export async function createMintConsume(): Promise { ..symbol: 'MID', ..decimals: 8, ..maxSupply: BigInt(1_000_000), -..storage: 'public', +..storage: StorageMode.Public, .}); .console.log('Faucet ID:', faucet.id().toString()); diff --git a/docs/src/web-client/react_wallet_tutorial.md b/docs/src/web-client/react_wallet_tutorial.md index 24bfc0b..7fc2a08 100644 --- a/docs/src/web-client/react_wallet_tutorial.md +++ b/docs/src/web-client/react_wallet_tutorial.md @@ -324,6 +324,7 @@ The `useSend()` hook provides a function to send tokens to other accounts. ```tsx import { useState, type ChangeEvent } from 'react'; import { useSend, parseAssetAmount } from '@miden-sdk/react'; +import { NoteVisibility } from '@miden-sdk/miden-sdk'; function SendForm({ accountId, @@ -336,7 +337,9 @@ function SendForm({ const [to, setTo] = useState(''); const [assetId, setAssetId] = useState(assets[0]?.assetId ?? ''); const [amount, setAmount] = useState(''); - const [noteType, setNoteType] = useState<'private' | 'public'>('private'); + const [noteType, setNoteType] = useState( + NoteVisibility.Private, + ); const selectedAsset = assets.find((asset) => asset.assetId === assetId); const selectedDecimals = selectedAsset?.decimals; @@ -462,6 +465,7 @@ import { useConsume, useSend, } from '@miden-sdk/react'; +import { NoteVisibility } from '@miden-sdk/miden-sdk'; const Panel = ({ title, children }: { title: string; children: ReactNode }) => (
@@ -507,7 +511,9 @@ function Wallet({ accountId }: { accountId: string }) { const [to, setTo] = useState(''); const [assetId, setAssetId] = useState(''); const [amount, setAmount] = useState(''); - const [noteType, setNoteType] = useState<'private' | 'public'>('private'); + const [noteType, setNoteType] = useState( + NoteVisibility.Private, + ); const defaultAssetId = assets[0]?.assetId; const selectedAsset = assets.find((asset) => asset.assetId === assetId); const selectedDecimals = selectedAsset?.decimals; diff --git a/docs/src/web-client/unauthenticated_note_how_to.md b/docs/src/web-client/unauthenticated_note_how_to.md index a07da92..4df81c3 100644 --- a/docs/src/web-client/unauthenticated_note_how_to.md +++ b/docs/src/web-client/unauthenticated_note_how_to.md @@ -163,6 +163,7 @@ Copy and paste the following code into `lib/react/unauthenticatedNoteTransfer.ts react: { code: `'use client'; import { MidenProvider, useMiden, useCreateWallet, useCreateFaucet, useMint, useConsume, useInternalTransfer, useWaitForCommit, useWaitForNotes } from '@miden-sdk/react'; +import { NoteVisibility, StorageMode } from '@miden-sdk/miden-sdk'; function UnauthenticatedNoteTransferInner() { .const { isReady } = useMiden(); @@ -177,13 +178,13 @@ function UnauthenticatedNoteTransferInner() { .const run = async () => { ..// 1. Create Alice and 5 wallets for the transfer chain ..console.log('Creating accounts…'); -..const alice = await createWallet({ storageMode: 'public' }); +..const alice = await createWallet({ storageMode: StorageMode.Public }); ..const aliceId = alice.id().toString(); ..console.log('Alice account ID:', aliceId); ..const walletIds: string[] = []; ..for (let i = 0; i < 5; i++) { -...const wallet = await createWallet({ storageMode: 'public' }); +...const wallet = await createWallet({ storageMode: StorageMode.Public }); ...walletIds.push(wallet.id().toString()); ...console.log(\`Wallet \${i}:\`, walletIds[i]); ..} @@ -193,7 +194,7 @@ function UnauthenticatedNoteTransferInner() { ...tokenSymbol: 'MID', ...decimals: 8, ...maxSupply: BigInt(1_000_000), -...storageMode: 'public', +...storageMode: StorageMode.Public, ..}); ..const faucetId = faucet.id().toString(); ..console.log('Faucet ID:', faucetId); @@ -203,7 +204,7 @@ function UnauthenticatedNoteTransferInner() { ...faucetId, ...targetAccountId: aliceId, ...amount: BigInt(10_000), -...noteType: 'public', +...noteType: NoteVisibility.Public, ..}); ..console.log('Waiting for settlement…'); @@ -222,7 +223,7 @@ function UnauthenticatedNoteTransferInner() { ...recipients: walletIds, ...assetId: faucetId, ...amount: BigInt(50), -...noteType: 'public', +...noteType: NoteVisibility.Public, ..}); ..results.forEach((r, i) => { @@ -263,6 +264,8 @@ export async function unauthenticatedNoteTransfer(): Promise { .const { ..MidenClient, ..AccountType, +..NoteVisibility, +..StorageMode, ..TransactionProver, ..Note, ..NoteType, @@ -289,7 +292,7 @@ export async function unauthenticatedNoteTransfer(): Promise { .console.log('Creating account for Alice…'); .const alice = await client.accounts.create({ ..type: AccountType.MutableWallet, -..storage: 'public', +..storage: StorageMode.Public, .}); .console.log('Alice account ID:', alice.id().toString()); @@ -297,7 +300,7 @@ export async function unauthenticatedNoteTransfer(): Promise { .for (let i = 0; i < 5; i++) { ..const wallet = await client.accounts.create({ ...type: AccountType.MutableWallet, -...storage: 'public', +...storage: StorageMode.Public, ..}); ..wallets.push(wallet); ..console.log('wallet ', i.toString(), wallet.id().toString()); @@ -309,7 +312,7 @@ export async function unauthenticatedNoteTransfer(): Promise { ..symbol: 'MID', ..decimals: 8, ..maxSupply: BigInt(1_000_000), -..storage: 'public', +..storage: StorageMode.Public, .}); .console.log('Faucet ID:', faucet.id().toString()); diff --git a/web-client/lib/foreignProcedureInvocation.ts b/web-client/lib/foreignProcedureInvocation.ts index 652c154..0f3f340 100644 --- a/web-client/lib/foreignProcedureInvocation.ts +++ b/web-client/lib/foreignProcedureInvocation.ts @@ -5,7 +5,7 @@ export async function foreignProcedureInvocation(): Promise { return; } - const { AccountType, AuthSecretKey, StorageSlot, MidenClient } = + const { AccountType, AuthSecretKey, StorageMode, StorageSlot, MidenClient } = await import('@miden-sdk/miden-sdk'); const nodeEndpoint = 'http://localhost:57291'; @@ -94,7 +94,7 @@ export async function foreignProcedureInvocation(): Promise { const counterAccount = await client.accounts.create({ type: AccountType.ImmutableContract, - storage: 'public', + storage: StorageMode.Public, seed: counterSeed, auth: counterAuth, components: [counterComponent], @@ -137,7 +137,7 @@ export async function foreignProcedureInvocation(): Promise { const countReaderAccount = await client.accounts.create({ type: AccountType.ImmutableContract, - storage: 'public', + storage: StorageMode.Public, seed: readerSeed, auth: readerAuth, components: [countReaderComponent], diff --git a/web-client/lib/incrementCounterContract.ts b/web-client/lib/incrementCounterContract.ts index 97bc55f..de90e75 100644 --- a/web-client/lib/incrementCounterContract.ts +++ b/web-client/lib/incrementCounterContract.ts @@ -5,7 +5,7 @@ export async function incrementCounterContract(): Promise { return; } - const { AccountType, AuthSecretKey, StorageSlot, MidenClient } = + const { AccountType, AuthSecretKey, StorageMode, StorageSlot, MidenClient } = await import('@miden-sdk/miden-sdk'); const nodeEndpoint = 'http://localhost:57291'; @@ -60,7 +60,7 @@ export async function incrementCounterContract(): Promise { const account = await client.accounts.create({ type: AccountType.ImmutableContract, - storage: 'public', + storage: StorageMode.Public, seed: walletSeed, auth, components: [counterAccountComponent], diff --git a/web-client/lib/react/createMintConsume.tsx b/web-client/lib/react/createMintConsume.tsx index 2977512..a2ddb53 100644 --- a/web-client/lib/react/createMintConsume.tsx +++ b/web-client/lib/react/createMintConsume.tsx @@ -5,6 +5,7 @@ 'use client'; import { MidenProvider, useMiden, useCreateWallet, useCreateFaucet, useMint, useConsume, useSend, useWaitForCommit, useWaitForNotes } from '@miden-sdk/react'; +import { NoteVisibility, StorageMode } from '@miden-sdk/miden-sdk'; function CreateMintConsumeInner() { const { isReady } = useMiden(); @@ -19,7 +20,7 @@ function CreateMintConsumeInner() { const run = async () => { // 1. Create Alice's wallet (public, mutable) console.log('Creating account for Alice…'); - const alice = await createWallet({ storageMode: 'public' }); + const alice = await createWallet({ storageMode: StorageMode.Public }); const aliceId = alice.id().toString(); console.log('Alice ID:', aliceId); @@ -29,7 +30,7 @@ function CreateMintConsumeInner() { tokenSymbol: 'MID', decimals: 8, maxSupply: BigInt(1_000_000), - storageMode: 'public', + storageMode: StorageMode.Public, }); const faucetId = faucet.id().toString(); console.log('Faucet ID:', faucetId); @@ -40,7 +41,7 @@ function CreateMintConsumeInner() { faucetId, targetAccountId: aliceId, amount: BigInt(1000), - noteType: 'public', + noteType: NoteVisibility.Public, }); console.log('Mint tx:', mintResult.transactionId); @@ -65,7 +66,7 @@ function CreateMintConsumeInner() { to: bobAddress, assetId: faucetId, amount: BigInt(100), - noteType: 'public', + noteType: NoteVisibility.Public, }); console.log('Tokens sent successfully!'); }; diff --git a/web-client/lib/react/multiSendWithDelegatedProver.tsx b/web-client/lib/react/multiSendWithDelegatedProver.tsx index 4226acb..e20a589 100644 --- a/web-client/lib/react/multiSendWithDelegatedProver.tsx +++ b/web-client/lib/react/multiSendWithDelegatedProver.tsx @@ -5,6 +5,7 @@ 'use client'; import { MidenProvider, useMiden, useCreateWallet, useCreateFaucet, useMint, useConsume, useMultiSend, useWaitForCommit, useWaitForNotes } from '@miden-sdk/react'; +import { NoteVisibility, StorageMode } from '@miden-sdk/miden-sdk'; function MultiSendInner() { const { isReady } = useMiden(); @@ -19,7 +20,7 @@ function MultiSendInner() { const run = async () => { // 1. Create Alice's wallet console.log('Creating account for Alice…'); - const alice = await createWallet({ storageMode: 'public' }); + const alice = await createWallet({ storageMode: StorageMode.Public }); const aliceId = alice.id().toString(); console.log('Alice account ID:', aliceId); @@ -28,7 +29,7 @@ function MultiSendInner() { tokenSymbol: 'MID', decimals: 8, maxSupply: BigInt(1_000_000), - storageMode: 'public', + storageMode: StorageMode.Public, }); const faucetId = faucet.id().toString(); console.log('Faucet ID:', faucetId); @@ -38,7 +39,7 @@ function MultiSendInner() { faucetId, targetAccountId: aliceId, amount: BigInt(10_000), - noteType: 'public', + noteType: NoteVisibility.Public, }); console.log('Waiting for settlement…'); @@ -58,7 +59,7 @@ function MultiSendInner() { { to: 'mtst1apjg2ul76wrkxyr5qlcnczaskypa4ljn', amount: BigInt(100) }, { to: 'mtst1arpee6y9cm8t7ypn33pc8fzj6gkzz7kd', amount: BigInt(100) }, ], - noteType: 'public', + noteType: NoteVisibility.Public, }); console.log('All notes created ✅'); diff --git a/web-client/lib/react/unauthenticatedNoteTransfer.tsx b/web-client/lib/react/unauthenticatedNoteTransfer.tsx index e3c28db..ec806cc 100644 --- a/web-client/lib/react/unauthenticatedNoteTransfer.tsx +++ b/web-client/lib/react/unauthenticatedNoteTransfer.tsx @@ -5,6 +5,7 @@ 'use client'; import { MidenProvider, useMiden, useCreateWallet, useCreateFaucet, useMint, useConsume, useInternalTransfer, useWaitForCommit, useWaitForNotes } from '@miden-sdk/react'; +import { NoteVisibility, StorageMode } from '@miden-sdk/miden-sdk'; function UnauthenticatedNoteTransferInner() { const { isReady } = useMiden(); @@ -19,13 +20,13 @@ function UnauthenticatedNoteTransferInner() { const run = async () => { // 1. Create Alice and 5 wallets for the transfer chain console.log('Creating accounts…'); - const alice = await createWallet({ storageMode: 'public' }); + const alice = await createWallet({ storageMode: StorageMode.Public }); const aliceId = alice.id().toString(); console.log('Alice account ID:', aliceId); const walletIds: string[] = []; for (let i = 0; i < 5; i++) { - const wallet = await createWallet({ storageMode: 'public' }); + const wallet = await createWallet({ storageMode: StorageMode.Public }); walletIds.push(wallet.id().toString()); console.log(`Wallet ${i}:`, walletIds[i]); } @@ -35,7 +36,7 @@ function UnauthenticatedNoteTransferInner() { tokenSymbol: 'MID', decimals: 8, maxSupply: BigInt(1_000_000), - storageMode: 'public', + storageMode: StorageMode.Public, }); const faucetId = faucet.id().toString(); console.log('Faucet ID:', faucetId); @@ -45,7 +46,7 @@ function UnauthenticatedNoteTransferInner() { faucetId, targetAccountId: aliceId, amount: BigInt(10_000), - noteType: 'public', + noteType: NoteVisibility.Public, }); console.log('Waiting for settlement…'); @@ -64,7 +65,7 @@ function UnauthenticatedNoteTransferInner() { recipients: walletIds, assetId: faucetId, amount: BigInt(50), - noteType: 'public', + noteType: NoteVisibility.Public, }); results.forEach((r, i) => { From 51e0af6ade0d808dcba9c8e6a301cf108dc855d6 Mon Sep 17 00:00:00 2001 From: Wiktor Starczewski Date: Thu, 26 Feb 2026 01:48:29 +0100 Subject: [PATCH 08/14] refactor(tutorials): remove forced .toHex()/.toString() conversions in API calls --- .../creating_multiple_notes_tutorial.md | 10 +++++----- .../web-client/mint_consume_create_tutorial.md | 16 ++++++++-------- .../web-client/unauthenticated_note_how_to.md | 6 +++--- web-client/lib/react/createMintConsume.tsx | 4 ++-- .../lib/react/multiSendWithDelegatedProver.tsx | 2 +- .../lib/react/unauthenticatedNoteTransfer.tsx | 2 +- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/docs/src/web-client/creating_multiple_notes_tutorial.md b/docs/src/web-client/creating_multiple_notes_tutorial.md index f92acd4..3d02f46 100644 --- a/docs/src/web-client/creating_multiple_notes_tutorial.md +++ b/docs/src/web-client/creating_multiple_notes_tutorial.md @@ -231,7 +231,7 @@ await waitForCommit(mintResult.transactionId); // 4. Consume the freshly minted notes const notes = await waitForConsumableNotes({ accountId: aliceId }); -const noteIds = notes.map((n) => n.inputNoteRecord().id().toString()); +const noteIds = notes.map((n) => n.inputNoteRecord().id()); await consume({ accountId: aliceId, noteIds });`}, typescript: { code:`// ── Creating new account ────────────────────────────────────────────────────── console.log('Creating account for Alice…'); @@ -260,14 +260,14 @@ const mintTxId = await client.transactions.mint({ }); console.log('waiting for settlement'); -await client.transactions.waitFor(mintTxId.toHex()); +await client.transactions.waitFor(mintTxId); await client.sync(); // ── consume the freshly minted notes ────────────────────────────────────────────── const noteList = await client.notes.listAvailable({ account: alice.id() }); await client.transactions.consume({ .account: alice.id(), -.notes: noteList.map((n) => n.inputNoteRecord().id().toString()), +.notes: noteList.map((n) => n.inputNoteRecord()), });` }, }} reactFilename="lib/react/multiSendWithDelegatedProver.tsx" tsFilename="lib/multiSendWithDelegatedProver.ts" /> @@ -450,14 +450,14 @@ export async function multiSendWithDelegatedProver(): Promise { .}); .console.log('waiting for settlement'); -.await client.transactions.waitFor(mintTxId.toHex()); +.await client.transactions.waitFor(mintTxId); .await client.sync(); .// ── consume the freshly minted notes ────────────────────────────────────────────── .const noteList = await client.notes.listAvailable({ account: alice.id() }); .await client.transactions.consume({ ..account: alice.id(), -..notes: noteList.map((n) => n.inputNoteRecord().id().toString()), +..notes: noteList.map((n) => n.inputNoteRecord()), .}); .// ── build 3 P2ID notes (100 MID each) ───────────────────────────────────────────── diff --git a/docs/src/web-client/mint_consume_create_tutorial.md b/docs/src/web-client/mint_consume_create_tutorial.md index ae76f5c..fcad17c 100644 --- a/docs/src/web-client/mint_consume_create_tutorial.md +++ b/docs/src/web-client/mint_consume_create_tutorial.md @@ -64,7 +64,7 @@ const mintTxId = await client.transactions.mint({ // Wait for the transaction to be processed console.log("Waiting for transaction confirmation..."); -await client.transactions.waitFor(mintTxId.toHex()); +await client.transactions.waitFor(mintTxId); await client.sync();` }, }} reactFilename="lib/react/createMintConsume.tsx" tsFilename="lib/createMintConsume.ts" /> @@ -81,8 +81,8 @@ To identify notes that are ready to consume, the MidenClient provides the `clien n.inputNoteRecord().id().toString()); -console.log('Consumable notes:', noteIds);` }, +const noteIds = notes.map((n) => n.inputNoteRecord().id()); +console.log('Consumable notes:', noteIds.length);` }, typescript: { code: `// 5. Find notes available for consumption const mintedNotes = await client.notes.listAvailable({ account: alice.id() }); console.log(\`Found \${mintedNotes.length} note(s) to consume\`); @@ -106,7 +106,7 @@ typescript: { code: `// 6. Consume the notes to add tokens to Alice's balance console.log('Consuming minted notes...'); await client.transactions.consume({ .account: alice.id(), -.notes: mintedNotes.map((n) => n.inputNoteRecord().id().toString()), +.notes: mintedNotes.map((n) => n.inputNoteRecord()), }); await client.sync(); @@ -209,8 +209,8 @@ function CreateMintConsumeInner() { ..// 5. Wait for consumable notes to appear ..const notes = await waitForConsumableNotes({ accountId: aliceId }); -..const noteIds = notes.map((n) => n.inputNoteRecord().id().toString()); -..console.log('Consumable notes:', noteIds); +..const noteIds = notes.map((n) => n.inputNoteRecord().id()); +..console.log('Consumable notes:', noteIds.length); ..// 6. Consume minted notes ..console.log('Consuming minted notes...'); @@ -296,7 +296,7 @@ export async function createMintConsume(): Promise { .}); .console.log('Waiting for transaction confirmation...'); -.await client.transactions.waitFor(mintTxId.toHex()); +.await client.transactions.waitFor(mintTxId); .await client.sync(); .// 5. Fetch minted notes @@ -310,7 +310,7 @@ export async function createMintConsume(): Promise { .console.log('Consuming minted notes...'); .await client.transactions.consume({ ..account: alice.id(), -..notes: mintedNotes.map((n) => n.inputNoteRecord().id().toString()), +..notes: mintedNotes.map((n) => n.inputNoteRecord()), .}); .await client.sync(); diff --git a/docs/src/web-client/unauthenticated_note_how_to.md b/docs/src/web-client/unauthenticated_note_how_to.md index 4df81c3..4ebc1ec 100644 --- a/docs/src/web-client/unauthenticated_note_how_to.md +++ b/docs/src/web-client/unauthenticated_note_how_to.md @@ -212,7 +212,7 @@ function UnauthenticatedNoteTransferInner() { ..// 4. Consume the freshly minted notes ..const notes = await waitForConsumableNotes({ accountId: aliceId }); -..const noteIds = notes.map((n) => n.inputNoteRecord().id().toString()); +..const noteIds = notes.map((n) => n.inputNoteRecord().id()); ..await consume({ accountId: aliceId, noteIds }); ..// 5. Create the unauthenticated note transfer chain: @@ -326,14 +326,14 @@ export async function unauthenticatedNoteTransfer(): Promise { .}); .console.log('Waiting for settlement'); -.await client.transactions.waitFor(mintTxId.toHex()); +.await client.transactions.waitFor(mintTxId); .await client.sync(); .// ── Consume the freshly minted note ────────────────────────────────────────────── .const noteList = await client.notes.listAvailable({ account: alice.id() }); .await client.transactions.consume({ ..account: alice.id(), -..notes: noteList.map((n) => n.inputNoteRecord().id().toString()), +..notes: noteList.map((n) => n.inputNoteRecord()), ..prover, .}); .await client.sync(); diff --git a/web-client/lib/react/createMintConsume.tsx b/web-client/lib/react/createMintConsume.tsx index a2ddb53..7e612d8 100644 --- a/web-client/lib/react/createMintConsume.tsx +++ b/web-client/lib/react/createMintConsume.tsx @@ -50,8 +50,8 @@ function CreateMintConsumeInner() { // 5. Wait for consumable notes to appear const notes = await waitForConsumableNotes({ accountId: aliceId }); - const noteIds = notes.map((n) => n.inputNoteRecord().id().toString()); - console.log('Consumable notes:', noteIds); + const noteIds = notes.map((n) => n.inputNoteRecord().id()); + console.log('Consumable notes:', noteIds.length); // 6. Consume minted notes console.log('Consuming minted notes...'); diff --git a/web-client/lib/react/multiSendWithDelegatedProver.tsx b/web-client/lib/react/multiSendWithDelegatedProver.tsx index e20a589..9387879 100644 --- a/web-client/lib/react/multiSendWithDelegatedProver.tsx +++ b/web-client/lib/react/multiSendWithDelegatedProver.tsx @@ -47,7 +47,7 @@ function MultiSendInner() { // 4. Consume the freshly minted notes const notes = await waitForConsumableNotes({ accountId: aliceId }); - const noteIds = notes.map((n) => n.inputNoteRecord().id().toString()); + const noteIds = notes.map((n) => n.inputNoteRecord().id()); await consume({ accountId: aliceId, noteIds }); // 5. Send 100 MID to three recipients in a single transaction diff --git a/web-client/lib/react/unauthenticatedNoteTransfer.tsx b/web-client/lib/react/unauthenticatedNoteTransfer.tsx index ec806cc..32e1480 100644 --- a/web-client/lib/react/unauthenticatedNoteTransfer.tsx +++ b/web-client/lib/react/unauthenticatedNoteTransfer.tsx @@ -54,7 +54,7 @@ function UnauthenticatedNoteTransferInner() { // 4. Consume the freshly minted notes const notes = await waitForConsumableNotes({ accountId: aliceId }); - const noteIds = notes.map((n) => n.inputNoteRecord().id().toString()); + const noteIds = notes.map((n) => n.inputNoteRecord().id()); await consume({ accountId: aliceId, noteIds }); // 5. Create the unauthenticated note transfer chain: From 75cf85998fea10bae1fb1eeac57fe2a08793ec02 Mon Sep 17 00:00:00 2001 From: Wiktor Starczewski Date: Thu, 26 Feb 2026 02:10:46 +0100 Subject: [PATCH 09/14] refactor(tutorials): migrate web-client/lib TypeScript files to MidenClient API - Replace WebClient with MidenClient.create() - Replace syncState() with sync() - Replace newWallet/newFaucet with client.accounts.create() - Replace manual tx request builders with client.transactions.mint/consume/send/submit() - Replace getConsumableNotes() with client.notes.listAvailable() - Pass account objects directly instead of .id() to transaction methods - Use NoteVisibility enum instead of 'public' string literals - Update React files to pass account objects instead of string IDs --- web-client/lib/createMintConsume.ts | 102 ++++++-------- web-client/lib/mintTestnetToAddress.ts | 63 ++++----- .../lib/multiSendWithDelegatedProver.ts | 101 ++++++------- web-client/lib/react/createMintConsume.tsx | 18 ++- .../react/multiSendWithDelegatedProver.tsx | 18 ++- .../lib/react/unauthenticatedNoteTransfer.tsx | 28 ++-- web-client/lib/unauthenticatedNoteTransfer.ts | 133 ++++++------------ 7 files changed, 183 insertions(+), 280 deletions(-) diff --git a/web-client/lib/createMintConsume.ts b/web-client/lib/createMintConsume.ts index a7612fd..1f2b1bf 100644 --- a/web-client/lib/createMintConsume.ts +++ b/web-client/lib/createMintConsume.ts @@ -6,96 +6,76 @@ export async function createMintConsume(): Promise { } // dynamic import → only in the browser, so WASM is loaded client‑side - const { - WebClient, - AccountStorageMode, - AuthScheme, - NoteType, - Address, - } = await import('@miden-sdk/miden-sdk'); + const { MidenClient, AccountType, NoteVisibility, StorageMode } = await import('@miden-sdk/miden-sdk'); - const nodeEndpoint = 'https://rpc.testnet.miden.io'; - const client = await WebClient.createClient(nodeEndpoint); + const client = await MidenClient.create({ + rpcUrl: 'https://rpc.testnet.miden.io', + }); // 1. Sync with the latest blockchain state - const state = await client.syncState(); + const state = await client.sync(); console.log('Latest block number:', state.blockNum()); // 2. Create Alice's account console.log('Creating account for Alice…'); - const aliceSeed = new Uint8Array(32); - crypto.getRandomValues(aliceSeed); - const alice = await client.newWallet( - AccountStorageMode.public(), - true, - AuthScheme.AuthRpoFalcon512, - aliceSeed, - ); + const alice = await client.accounts.create({ + type: AccountType.MutableWallet, + storage: StorageMode.Public, + }); console.log('Alice ID:', alice.id().toString()); // 3. Deploy a fungible faucet console.log('Creating faucet…'); - const faucet = await client.newFaucet( - AccountStorageMode.public(), - false, - 'MID', - 8, - BigInt(1_000_000), - AuthScheme.AuthRpoFalcon512, - ); + const faucet = await client.accounts.create({ + type: AccountType.FungibleFaucet, + symbol: 'MID', + decimals: 8, + maxSupply: BigInt(1_000_000), + storage: StorageMode.Public, + }); console.log('Faucet ID:', faucet.id().toString()); - await client.syncState(); + await client.sync(); // 4. Mint tokens to Alice - await client.syncState(); - console.log('Minting tokens to Alice...'); - const mintTxRequest = client.newMintTransactionRequest( - alice.id(), - faucet.id(), - NoteType.Public, - BigInt(1000), - ); - - await client.submitNewTransaction(faucet.id(), mintTxRequest); + const mintTxId = await client.transactions.mint({ + account: faucet, + to: alice, + amount: BigInt(1000), + type: NoteVisibility.Public, + }); - console.log('Waiting 10 seconds for transaction confirmation...'); - await new Promise((resolve) => setTimeout(resolve, 10000)); - await client.syncState(); + console.log('Waiting for transaction confirmation...'); + await client.transactions.waitFor(mintTxId); + await client.sync(); // 5. Fetch minted notes - const mintedNotes = await client.getConsumableNotes(alice.id()); - const mintedNoteList = mintedNotes.map((n) => - n.inputNoteRecord().toNote(), - ); + const mintedNotes = await client.notes.listAvailable({ account: alice }); console.log( 'Minted notes:', - mintedNoteList.map((note) => note.id().toString()), + mintedNotes.map((n) => n.inputNoteRecord().id().toString()), ); // 6. Consume minted notes console.log('Consuming minted notes...'); - const consumeTxRequest = client.newConsumeTransactionRequest(mintedNoteList); - - await client.submitNewTransaction(alice.id(), consumeTxRequest); + await client.transactions.consume({ + account: alice, + notes: mintedNotes.map((n) => n.inputNoteRecord()), + }); - await client.syncState(); + await client.sync(); console.log('Notes consumed.'); // 7. Send tokens to Bob - const bobAccountId = Address.fromBech32( - 'mtst1apve54rq8ux0jqqqqrkh5y0r0y8cwza6_qruqqypuyph', - ).accountId(); + const bobAddress = 'mtst1apve54rq8ux0jqqqqrkh5y0r0y8cwza6_qruqqypuyph'; console.log("Sending tokens to Bob's account..."); - const sendTxRequest = client.newSendTransactionRequest( - alice.id(), - bobAccountId, - faucet.id(), - NoteType.Public, - BigInt(100), - ); - - await client.submitNewTransaction(alice.id(), sendTxRequest); + await client.transactions.send({ + account: alice, + to: bobAddress, + token: faucet, + amount: BigInt(100), + type: NoteVisibility.Public, + }); console.log('Tokens sent successfully!'); } diff --git a/web-client/lib/mintTestnetToAddress.ts b/web-client/lib/mintTestnetToAddress.ts index 6ed1823..7ab4c2f 100644 --- a/web-client/lib/mintTestnetToAddress.ts +++ b/web-client/lib/mintTestnetToAddress.ts @@ -8,31 +8,32 @@ export async function mintTestnetToAddress(): Promise { } const { - WebClient, - AccountStorageMode, - AuthScheme, + MidenClient, + AccountType, + NoteVisibility, + StorageMode, Address, - NoteType, TransactionProver, } = await import('@miden-sdk/miden-sdk'); - const client = await WebClient.createClient('https://rpc.testnet.miden.io'); + const client = await MidenClient.create({ + rpcUrl: 'https://rpc.testnet.miden.io', + }); const prover = TransactionProver.newLocalProver(); - console.log('Latest block:', (await client.syncState()).blockNum()); + console.log('Latest block:', (await client.sync()).blockNum()); // ── Create a faucet ──────────────────────────────────────────────────────── console.log('Creating faucet...'); - const faucet = await client.newFaucet( - AccountStorageMode.public(), - false, - 'MID', - 8, - BigInt(1_000_000), - AuthScheme.AuthRpoFalcon512, - ); + const faucet = await client.accounts.create({ + type: AccountType.FungibleFaucet, + symbol: 'MID', + decimals: 8, + maxSupply: BigInt(1_000_000), + storage: StorageMode.Public, + }); console.log('Faucet ID:', faucet.id().toString()); - await client.syncState(); + await client.sync(); // ── Mint to recipient ─────────────────────────────────────────────────────── const recipientAddress = @@ -41,30 +42,18 @@ export async function mintTestnetToAddress(): Promise { console.log('Recipient account ID:', recipientAccountId.toString()); console.log('Minting 100 MIDEN tokens...'); - const txResult = await client.executeTransaction( - faucet.id(), - client.newMintTransactionRequest( - recipientAccountId, - faucet.id(), - NoteType.Public, - BigInt(100), - ), - ); - const proven = await client.proveTransaction(txResult, prover); - const submissionHeight = await client.submitProvenTransaction( - proven, - txResult, - ); - const txExecutionResult = await client.applyTransaction( - txResult, - submissionHeight, - ); + const mintTxId = await client.transactions.mint({ + account: faucet, + to: recipientAccountId, + amount: BigInt(100), + type: NoteVisibility.Public, + prover, + }); console.log('Waiting for settlement...'); - await new Promise((resolve) => setTimeout(resolve, 7_000)); - await client.syncState(); + await client.transactions.waitFor(mintTxId); + await client.sync(); - const txId = txExecutionResult.executedTransaction().id().toHex().toString(); - console.log('Mint tx id:', txId); + console.log('Mint tx id:', mintTxId.toHex()); console.log('Mint complete.'); } diff --git a/web-client/lib/multiSendWithDelegatedProver.ts b/web-client/lib/multiSendWithDelegatedProver.ts index 08a2bad..5b9196e 100644 --- a/web-client/lib/multiSendWithDelegatedProver.ts +++ b/web-client/lib/multiSendWithDelegatedProver.ts @@ -9,68 +9,57 @@ export async function multiSendWithDelegatedProver(): Promise { if (typeof window === 'undefined') return console.warn('Run in browser'); const { - WebClient, - AccountStorageMode, - AuthScheme, - Address, - NoteType, - Note, - NoteAssets, + MidenClient, + AccountType, + NoteVisibility, + StorageMode, + createP2IDNote, OutputNoteArray, - FungibleAsset, - NoteAttachment, TransactionRequestBuilder, - OutputNote, } = await import('@miden-sdk/miden-sdk'); - const client = await WebClient.createClient('https://rpc.testnet.miden.io'); + const client = await MidenClient.create({ + rpcUrl: 'https://rpc.testnet.miden.io', + }); - console.log('Latest block:', (await client.syncState()).blockNum()); + console.log('Latest block:', (await client.sync()).blockNum()); // ── Creating new account ────────────────────────────────────────────────────── console.log('Creating account for Alice…'); - const alice = await client.newWallet( - AccountStorageMode.public(), - true, - AuthScheme.AuthRpoFalcon512, - ); + const alice = await client.accounts.create({ + type: AccountType.MutableWallet, + storage: StorageMode.Public, + }); console.log('Alice account ID:', alice.id().toString()); // ── Creating new faucet ────────────────────────────────────────────────────── - const faucet = await client.newFaucet( - AccountStorageMode.public(), - false, - 'MID', - 8, - BigInt(1_000_000), - AuthScheme.AuthRpoFalcon512, - ); + const faucet = await client.accounts.create({ + type: AccountType.FungibleFaucet, + symbol: 'MID', + decimals: 8, + maxSupply: BigInt(1_000_000), + storage: StorageMode.Public, + }); console.log('Faucet ID:', faucet.id().toString()); // ── mint 10 000 MID to Alice ────────────────────────────────────────────────────── - await client.submitNewTransaction( - faucet.id(), - client.newMintTransactionRequest( - alice.id(), - faucet.id(), - NoteType.Public, - BigInt(10_000), - ), - ); + const mintTxId = await client.transactions.mint({ + account: faucet, + to: alice, + amount: BigInt(10_000), + type: NoteVisibility.Public, + }); console.log('waiting for settlement'); - await new Promise((r) => setTimeout(r, 7_000)); - await client.syncState(); + await client.transactions.waitFor(mintTxId); + await client.sync(); // ── consume the freshly minted notes ────────────────────────────────────────────── - const noteList = (await client.getConsumableNotes(alice.id())).map((rec) => - rec.inputNoteRecord().toNote(), - ); - - await client.submitNewTransaction( - alice.id(), - client.newConsumeTransactionRequest(noteList), - ); + const noteList = await client.notes.listAvailable({ account: alice }); + await client.transactions.consume({ + account: alice, + notes: noteList.map((n) => n.inputNoteRecord()), + }); // ── build 3 P2ID notes (100 MID each) ───────────────────────────────────────────── const recipientAddresses = [ @@ -79,25 +68,19 @@ export async function multiSendWithDelegatedProver(): Promise { 'mtst1arpee6y9cm8t7ypn33pc8fzj6gkzz7kd', ]; - const assets = new NoteAssets([new FungibleAsset(faucet.id(), BigInt(100))]); - - const p2idNotes = recipientAddresses.map((addr) => { - const receiverAccountId = Address.fromBech32(addr).accountId(); - const note = Note.createP2IDNote( - alice.id(), - receiverAccountId, - assets, - NoteType.Public, - new NoteAttachment(), - ); - - return OutputNote.full(note); - }); + const p2idNotes = recipientAddresses.map((addr) => + createP2IDNote({ + from: alice, + to: addr, + assets: { token: faucet, amount: BigInt(100) }, + type: NoteVisibility.Public, + }), + ); // ── create all P2ID notes ─────────────────────────────────────────────────────────────── const builder = new TransactionRequestBuilder(); const txRequest = builder.withOwnOutputNotes(new OutputNoteArray(p2idNotes)).build(); - await client.submitNewTransaction(alice.id(), txRequest); + await client.transactions.submit(alice, txRequest); console.log('All notes created ✅'); } diff --git a/web-client/lib/react/createMintConsume.tsx b/web-client/lib/react/createMintConsume.tsx index 7e612d8..3c27946 100644 --- a/web-client/lib/react/createMintConsume.tsx +++ b/web-client/lib/react/createMintConsume.tsx @@ -21,8 +21,7 @@ function CreateMintConsumeInner() { // 1. Create Alice's wallet (public, mutable) console.log('Creating account for Alice…'); const alice = await createWallet({ storageMode: StorageMode.Public }); - const aliceId = alice.id().toString(); - console.log('Alice ID:', aliceId); + console.log('Alice ID:', alice.id().toString()); // 2. Deploy a fungible faucet console.log('Creating faucet…'); @@ -32,14 +31,13 @@ function CreateMintConsumeInner() { maxSupply: BigInt(1_000_000), storageMode: StorageMode.Public, }); - const faucetId = faucet.id().toString(); - console.log('Faucet ID:', faucetId); + console.log('Faucet ID:', faucet.id().toString()); // 3. Mint 1000 tokens to Alice console.log('Minting tokens to Alice...'); const mintResult = await mint({ - faucetId, - targetAccountId: aliceId, + faucetId: faucet, + targetAccountId: alice, amount: BigInt(1000), noteType: NoteVisibility.Public, }); @@ -49,22 +47,22 @@ function CreateMintConsumeInner() { await waitForCommit(mintResult.transactionId); // 5. Wait for consumable notes to appear - const notes = await waitForConsumableNotes({ accountId: aliceId }); + const notes = await waitForConsumableNotes({ accountId: alice }); const noteIds = notes.map((n) => n.inputNoteRecord().id()); console.log('Consumable notes:', noteIds.length); // 6. Consume minted notes console.log('Consuming minted notes...'); - await consume({ accountId: aliceId, noteIds }); + await consume({ accountId: alice, noteIds }); console.log('Notes consumed.'); // 7. Send 100 tokens to Bob const bobAddress = 'mtst1apve54rq8ux0jqqqqrkh5y0r0y8cwza6_qruqqypuyph'; console.log("Sending tokens to Bob's account..."); await send({ - from: aliceId, + from: alice, to: bobAddress, - assetId: faucetId, + assetId: faucet, amount: BigInt(100), noteType: NoteVisibility.Public, }); diff --git a/web-client/lib/react/multiSendWithDelegatedProver.tsx b/web-client/lib/react/multiSendWithDelegatedProver.tsx index 9387879..f6c1667 100644 --- a/web-client/lib/react/multiSendWithDelegatedProver.tsx +++ b/web-client/lib/react/multiSendWithDelegatedProver.tsx @@ -21,8 +21,7 @@ function MultiSendInner() { // 1. Create Alice's wallet console.log('Creating account for Alice…'); const alice = await createWallet({ storageMode: StorageMode.Public }); - const aliceId = alice.id().toString(); - console.log('Alice account ID:', aliceId); + console.log('Alice account ID:', alice.id().toString()); // 2. Deploy a fungible faucet const faucet = await createFaucet({ @@ -31,13 +30,12 @@ function MultiSendInner() { maxSupply: BigInt(1_000_000), storageMode: StorageMode.Public, }); - const faucetId = faucet.id().toString(); - console.log('Faucet ID:', faucetId); + console.log('Faucet ID:', faucet.id().toString()); // 3. Mint 10,000 MID to Alice const mintResult = await mint({ - faucetId, - targetAccountId: aliceId, + faucetId: faucet, + targetAccountId: alice, amount: BigInt(10_000), noteType: NoteVisibility.Public, }); @@ -46,14 +44,14 @@ function MultiSendInner() { await waitForCommit(mintResult.transactionId); // 4. Consume the freshly minted notes - const notes = await waitForConsumableNotes({ accountId: aliceId }); + const notes = await waitForConsumableNotes({ accountId: alice }); const noteIds = notes.map((n) => n.inputNoteRecord().id()); - await consume({ accountId: aliceId, noteIds }); + await consume({ accountId: alice, noteIds }); // 5. Send 100 MID to three recipients in a single transaction await sendMany({ - from: aliceId, - assetId: faucetId, + from: alice, + assetId: faucet, recipients: [ { to: 'mtst1aqezqc90x7dkzypr9m5fmlpp85w6cl04', amount: BigInt(100) }, { to: 'mtst1apjg2ul76wrkxyr5qlcnczaskypa4ljn', amount: BigInt(100) }, diff --git a/web-client/lib/react/unauthenticatedNoteTransfer.tsx b/web-client/lib/react/unauthenticatedNoteTransfer.tsx index 32e1480..e9e3704 100644 --- a/web-client/lib/react/unauthenticatedNoteTransfer.tsx +++ b/web-client/lib/react/unauthenticatedNoteTransfer.tsx @@ -4,7 +4,7 @@ // lib/unauthenticatedNoteTransfer.ts is used for Playwright tests instead. 'use client'; -import { MidenProvider, useMiden, useCreateWallet, useCreateFaucet, useMint, useConsume, useInternalTransfer, useWaitForCommit, useWaitForNotes } from '@miden-sdk/react'; +import { MidenProvider, useMiden, useCreateWallet, useCreateFaucet, useMint, useConsume, useInternalTransfer, useWaitForCommit, useWaitForNotes, type Account } from '@miden-sdk/react'; import { NoteVisibility, StorageMode } from '@miden-sdk/miden-sdk'; function UnauthenticatedNoteTransferInner() { @@ -21,14 +21,13 @@ function UnauthenticatedNoteTransferInner() { // 1. Create Alice and 5 wallets for the transfer chain console.log('Creating accounts…'); const alice = await createWallet({ storageMode: StorageMode.Public }); - const aliceId = alice.id().toString(); - console.log('Alice account ID:', aliceId); + console.log('Alice account ID:', alice.id().toString()); - const walletIds: string[] = []; + const wallets: Account[] = []; for (let i = 0; i < 5; i++) { const wallet = await createWallet({ storageMode: StorageMode.Public }); - walletIds.push(wallet.id().toString()); - console.log(`Wallet ${i}:`, walletIds[i]); + wallets.push(wallet); + console.log(`Wallet ${i}:`, wallet.id().toString()); } // 2. Deploy a fungible faucet @@ -38,13 +37,12 @@ function UnauthenticatedNoteTransferInner() { maxSupply: BigInt(1_000_000), storageMode: StorageMode.Public, }); - const faucetId = faucet.id().toString(); - console.log('Faucet ID:', faucetId); + console.log('Faucet ID:', faucet.id().toString()); // 3. Mint 10,000 MID to Alice const mintResult = await mint({ - faucetId, - targetAccountId: aliceId, + faucetId: faucet, + targetAccountId: alice, amount: BigInt(10_000), noteType: NoteVisibility.Public, }); @@ -53,17 +51,17 @@ function UnauthenticatedNoteTransferInner() { await waitForCommit(mintResult.transactionId); // 4. Consume the freshly minted notes - const notes = await waitForConsumableNotes({ accountId: aliceId }); + const notes = await waitForConsumableNotes({ accountId: alice }); const noteIds = notes.map((n) => n.inputNoteRecord().id()); - await consume({ accountId: aliceId, noteIds }); + await consume({ accountId: alice, noteIds }); // 5. Create the unauthenticated note transfer chain: // Alice → Wallet 0 → Wallet 1 → Wallet 2 → Wallet 3 → Wallet 4 console.log('Starting unauthenticated transfer chain…'); const results = await transferChain({ - from: aliceId, - recipients: walletIds, - assetId: faucetId, + from: alice, + recipients: wallets, + assetId: faucet, amount: BigInt(50), noteType: NoteVisibility.Public, }); diff --git a/web-client/lib/unauthenticatedNoteTransfer.ts b/web-client/lib/unauthenticatedNoteTransfer.ts index fb7fdc9..f8da183 100644 --- a/web-client/lib/unauthenticatedNoteTransfer.ts +++ b/web-client/lib/unauthenticatedNoteTransfer.ts @@ -9,12 +9,13 @@ export async function unauthenticatedNoteTransfer(): Promise { if (typeof window === 'undefined') return console.warn('Run in browser'); const { - WebClient, - AccountStorageMode, - AuthScheme, - NoteType, + MidenClient, + AccountType, + NoteVisibility, + StorageMode, TransactionProver, Note, + NoteType, NoteAssets, OutputNoteArray, FungibleAsset, @@ -25,85 +26,64 @@ export async function unauthenticatedNoteTransfer(): Promise { OutputNote, } = await import('@miden-sdk/miden-sdk'); - const client = await WebClient.createClient('https://rpc.testnet.miden.io'); + const client = await MidenClient.create({ + rpcUrl: 'https://rpc.testnet.miden.io', + }); const prover = TransactionProver.newLocalProver(); - console.log('Latest block:', (await client.syncState()).blockNum()); + console.log('Latest block:', (await client.sync()).blockNum()); // ── Creating new account ────────────────────────────────────────────────────── console.log('Creating accounts'); console.log('Creating account for Alice…'); - const alice = await client.newWallet( - AccountStorageMode.public(), - true, - AuthScheme.AuthRpoFalcon512, - ); + const alice = await client.accounts.create({ + type: AccountType.MutableWallet, + storage: StorageMode.Public, + }); console.log('Alice account ID:', alice.id().toString()); const wallets = []; for (let i = 0; i < 5; i++) { - const wallet = await client.newWallet( - AccountStorageMode.public(), - true, - AuthScheme.AuthRpoFalcon512, - ); + const wallet = await client.accounts.create({ + type: AccountType.MutableWallet, + storage: StorageMode.Public, + }); wallets.push(wallet); console.log('wallet ', i.toString(), wallet.id().toString()); } // ── Creating new faucet ────────────────────────────────────────────────────── - const faucet = await client.newFaucet( - AccountStorageMode.public(), - false, - 'MID', - 8, - BigInt(1_000_000), - AuthScheme.AuthRpoFalcon512, - ); + const faucet = await client.accounts.create({ + type: AccountType.FungibleFaucet, + symbol: 'MID', + decimals: 8, + maxSupply: BigInt(1_000_000), + storage: StorageMode.Public, + }); console.log('Faucet ID:', faucet.id().toString()); // ── mint 10 000 MID to Alice ────────────────────────────────────────────────────── - { - const txResult = await client.executeTransaction( - faucet.id(), - client.newMintTransactionRequest( - alice.id(), - faucet.id(), - NoteType.Public, - BigInt(10_000), - ), - ); - const proven = await client.proveTransaction(txResult, prover); - const submissionHeight = await client.submitProvenTransaction( - proven, - txResult, - ); - await client.applyTransaction(txResult, submissionHeight); - } + const mintTxId = await client.transactions.mint({ + account: faucet, + to: alice, + amount: BigInt(10_000), + type: NoteVisibility.Public, + prover, + }); console.log('Waiting for settlement'); - await new Promise((r) => setTimeout(r, 7_000)); - await client.syncState(); + await client.transactions.waitFor(mintTxId); + await client.sync(); // ── Consume the freshly minted note ────────────────────────────────────────────── - const noteList = (await client.getConsumableNotes(alice.id())).map((rec) => - rec.inputNoteRecord().toNote(), - ); - - { - const txResult = await client.executeTransaction( - alice.id(), - client.newConsumeTransactionRequest(noteList), - ); - const proven = await client.proveTransaction(txResult, prover); - const submissionHeight = await client.submitProvenTransaction( - proven, - txResult, - ); - await client.applyTransaction(txResult, submissionHeight); - await client.syncState(); - } + const noteList = await client.notes.listAvailable({ account: alice }); + await client.transactions.consume({ + account: alice, + notes: noteList.map((n) => n.inputNoteRecord()), + prover, + }); + await client.sync(); // ── Create unauthenticated note transfer chain ───────────────────────────────────────────── // Alice → wallet 1 → wallet 2 → wallet 3 → wallet 4 @@ -132,16 +112,7 @@ export async function unauthenticatedNoteTransfer(): Promise { { const builder = new TransactionRequestBuilder(); const request = builder.withOwnOutputNotes(new OutputNoteArray([outputP2ID])).build(); - const txResult = await client.executeTransaction( - sender.id(), - request, - ); - const proven = await client.proveTransaction(txResult, prover); - const submissionHeight = await client.submitProvenTransaction( - proven, - txResult, - ); - await client.applyTransaction(txResult, submissionHeight); + await client.transactions.submit(sender, request, { prover }); } console.log('Consuming P2ID note...'); @@ -152,28 +123,14 @@ export async function unauthenticatedNoteTransfer(): Promise { const consumeRequest = consumeBuilder.withInputNotes(new NoteAndArgsArray([noteIdAndArgs])).build(); { - const txResult = await client.executeTransaction( - receiver.id(), + const txId = await client.transactions.submit( + receiver, consumeRequest, + { prover }, ); - const proven = await client.proveTransaction(txResult, prover); - const submissionHeight = await client.submitProvenTransaction( - proven, - txResult, - ); - const txExecutionResult = await client.applyTransaction( - txResult, - submissionHeight, - ); - - const txId = txExecutionResult - .executedTransaction() - .id() - .toHex() - .toString(); console.log( - `Consumed Note Tx on MidenScan: https://testnet.midenscan.com/tx/${txId}`, + `Consumed Note Tx on MidenScan: https://testnet.midenscan.com/tx/${txId.toHex()}`, ); } } From 7b8bcdac549b0e93cde8dd87b68f8475c166624a Mon Sep 17 00:00:00 2001 From: Wiktor Starczewski Date: Thu, 26 Feb 2026 02:14:37 +0100 Subject: [PATCH 10/14] refactor(docs): pass account objects and NoteVisibility enum in TypeScript code snippets --- .../creating_multiple_notes_tutorial.md | 36 +++++++++---------- .../mint_consume_create_tutorial.md | 32 ++++++++--------- .../web-client/unauthenticated_note_how_to.md | 10 +++--- 3 files changed, 39 insertions(+), 39 deletions(-) diff --git a/docs/src/web-client/creating_multiple_notes_tutorial.md b/docs/src/web-client/creating_multiple_notes_tutorial.md index 3d02f46..b9e2e77 100644 --- a/docs/src/web-client/creating_multiple_notes_tutorial.md +++ b/docs/src/web-client/creating_multiple_notes_tutorial.md @@ -253,10 +253,10 @@ console.log('Faucet ID:', faucet.id().toString()); // ── mint 10 000 MID to Alice ────────────────────────────────────────────────────── const mintTxId = await client.transactions.mint({ -.account: faucet.id(), -.to: alice.id(), +.account: faucet, +.to: alice, .amount: BigInt(10_000), -.type: 'public', +.type: NoteVisibility.Public, }); console.log('waiting for settlement'); @@ -264,9 +264,9 @@ await client.transactions.waitFor(mintTxId); await client.sync(); // ── consume the freshly minted notes ────────────────────────────────────────────── -const noteList = await client.notes.listAvailable({ account: alice.id() }); +const noteList = await client.notes.listAvailable({ account: alice }); await client.transactions.consume({ -.account: alice.id(), +.account: alice, .notes: noteList.map((n) => n.inputNoteRecord()), });` }, }} reactFilename="lib/react/multiSendWithDelegatedProver.tsx" tsFilename="lib/multiSendWithDelegatedProver.ts" /> @@ -298,17 +298,17 @@ const recipientAddresses = [ const p2idNotes = recipientAddresses.map((addr) => .createP2IDNote({ -..from: alice.id(), +..from: alice, ..to: addr, -..assets: { token: faucet.id(), amount: BigInt(100) }, -..type: 'public', +..assets: { token: faucet, amount: BigInt(100) }, +..type: NoteVisibility.Public, .}), ); // ── create all P2ID notes ─────────────────────────────────────────────────────────────── const builder = new TransactionRequestBuilder(); const txRequest = builder.withOwnOutputNotes(new OutputNoteArray(p2idNotes)).build(); -await client.transactions.submit(alice.id(), txRequest); +await client.transactions.submit(alice, txRequest); console.log('All notes created ✅');` }, }} reactFilename="lib/react/multiSendWithDelegatedProver.tsx" tsFilename="lib/multiSendWithDelegatedProver.ts" /> @@ -443,10 +443,10 @@ export async function multiSendWithDelegatedProver(): Promise { .// ── mint 10 000 MID to Alice ────────────────────────────────────────────────────── .const mintTxId = await client.transactions.mint({ -..account: faucet.id(), -..to: alice.id(), +..account: faucet, +..to: alice, ..amount: BigInt(10_000), -..type: 'public', +..type: NoteVisibility.Public, .}); .console.log('waiting for settlement'); @@ -454,9 +454,9 @@ export async function multiSendWithDelegatedProver(): Promise { .await client.sync(); .// ── consume the freshly minted notes ────────────────────────────────────────────── -.const noteList = await client.notes.listAvailable({ account: alice.id() }); +.const noteList = await client.notes.listAvailable({ account: alice }); .await client.transactions.consume({ -..account: alice.id(), +..account: alice, ..notes: noteList.map((n) => n.inputNoteRecord()), .}); @@ -469,17 +469,17 @@ export async function multiSendWithDelegatedProver(): Promise { .const p2idNotes = recipientAddresses.map((addr) => ..createP2IDNote({ -...from: alice.id(), +...from: alice, ...to: addr, -...assets: { token: faucet.id(), amount: BigInt(100) }, -...type: 'public', +...assets: { token: faucet, amount: BigInt(100) }, +...type: NoteVisibility.Public, ..}), .); .// ── create all P2ID notes ─────────────────────────────────────────────────────────────── .const builder = new TransactionRequestBuilder(); .const txRequest = builder.withOwnOutputNotes(new OutputNoteArray(p2idNotes)).build(); -.await client.transactions.submit(alice.id(), txRequest); +.await client.transactions.submit(alice, txRequest); .console.log('All notes created ✅'); }` }, diff --git a/docs/src/web-client/mint_consume_create_tutorial.md b/docs/src/web-client/mint_consume_create_tutorial.md index fcad17c..7204035 100644 --- a/docs/src/web-client/mint_consume_create_tutorial.md +++ b/docs/src/web-client/mint_consume_create_tutorial.md @@ -56,10 +56,10 @@ await client.sync(); console.log("Minting tokens to Alice..."); const mintTxId = await client.transactions.mint({ -.account: faucet.id(), // Faucet account (who mints the tokens) -.to: alice.id(), // Target account (who receives the tokens) +.account: faucet, // Faucet account (who mints the tokens) +.to: alice, // Target account (who receives the tokens) .amount: BigInt(1000), // Amount to mint (in base units) -.type: 'public', // Note visibility (public = onchain) +.type: NoteVisibility.Public, // Note visibility (public = onchain) }); // Wait for the transaction to be processed @@ -84,7 +84,7 @@ const notes = await waitForConsumableNotes({ accountId: aliceId }); const noteIds = notes.map((n) => n.inputNoteRecord().id()); console.log('Consumable notes:', noteIds.length);` }, typescript: { code: `// 5. Find notes available for consumption -const mintedNotes = await client.notes.listAvailable({ account: alice.id() }); +const mintedNotes = await client.notes.listAvailable({ account: alice }); console.log(\`Found \${mintedNotes.length} note(s) to consume\`); console.log( @@ -105,7 +105,7 @@ console.log('Notes consumed.');` }, typescript: { code: `// 6. Consume the notes to add tokens to Alice's balance console.log('Consuming minted notes...'); await client.transactions.consume({ -.account: alice.id(), +.account: alice, .notes: mintedNotes.map((n) => n.inputNoteRecord()), }); @@ -138,11 +138,11 @@ const bobAddress = 'mtst1apve54rq8ux0jqqqqrkh5y0r0y8cwza6_qruqqypuyph'; console.log("Sending tokens to Bob's account..."); await client.transactions.send({ -.account: alice.id(), // Sender account ID +.account: alice, // Sender account ID .to: bobAddress, // Recipient (bech32 address) -.token: faucet.id(), // Asset ID (faucet that created the tokens) +.token: faucet, // Asset ID (faucet that created the tokens) .amount: BigInt(100), // Amount to send -.type: 'public', // Note visibility +.type: NoteVisibility.Public, // Note visibility }); console.log('Tokens sent successfully!');` }, @@ -289,10 +289,10 @@ export async function createMintConsume(): Promise { .console.log('Minting tokens to Alice...'); .const mintTxId = await client.transactions.mint({ -..account: faucet.id(), -..to: alice.id(), +..account: faucet, +..to: alice, ..amount: BigInt(1000), -..type: 'public', +..type: NoteVisibility.Public, .}); .console.log('Waiting for transaction confirmation...'); @@ -300,7 +300,7 @@ export async function createMintConsume(): Promise { .await client.sync(); .// 5. Fetch minted notes -.const mintedNotes = await client.notes.listAvailable({ account: alice.id() }); +.const mintedNotes = await client.notes.listAvailable({ account: alice }); .console.log( ..'Minted notes:', ..mintedNotes.map((n) => n.inputNoteRecord().id().toString()), @@ -309,7 +309,7 @@ export async function createMintConsume(): Promise { .// 6. Consume minted notes .console.log('Consuming minted notes...'); .await client.transactions.consume({ -..account: alice.id(), +..account: alice, ..notes: mintedNotes.map((n) => n.inputNoteRecord()), .}); @@ -320,11 +320,11 @@ export async function createMintConsume(): Promise { .const bobAddress = 'mtst1apve54rq8ux0jqqqqrkh5y0r0y8cwza6_qruqqypuyph'; .console.log("Sending tokens to Bob's account..."); .await client.transactions.send({ -..account: alice.id(), +..account: alice, ..to: bobAddress, -..token: faucet.id(), +..token: faucet, ..amount: BigInt(100), -..type: 'public', +..type: NoteVisibility.Public, .}); .console.log('Tokens sent successfully!'); }` }, diff --git a/docs/src/web-client/unauthenticated_note_how_to.md b/docs/src/web-client/unauthenticated_note_how_to.md index 4ebc1ec..7071ddf 100644 --- a/docs/src/web-client/unauthenticated_note_how_to.md +++ b/docs/src/web-client/unauthenticated_note_how_to.md @@ -318,10 +318,10 @@ export async function unauthenticatedNoteTransfer(): Promise { .// ── mint 10 000 MID to Alice ────────────────────────────────────────────────────── .const mintTxId = await client.transactions.mint({ -..account: faucet.id(), -..to: alice.id(), +..account: faucet, +..to: alice, ..amount: BigInt(10_000), -..type: 'public', +..type: NoteVisibility.Public, ..prover, .}); @@ -330,9 +330,9 @@ export async function unauthenticatedNoteTransfer(): Promise { .await client.sync(); .// ── Consume the freshly minted note ────────────────────────────────────────────── -.const noteList = await client.notes.listAvailable({ account: alice.id() }); +.const noteList = await client.notes.listAvailable({ account: alice }); .await client.transactions.consume({ -..account: alice.id(), +..account: alice, ..notes: noteList.map((n) => n.inputNoteRecord()), ..prover, .}); From 77ac31debaa50b9151d10f7010f37868a700e1be Mon Sep 17 00:00:00 2001 From: Wiktor Starczewski Date: Thu, 26 Feb 2026 02:46:42 +0100 Subject: [PATCH 11/14] fix(web-client): use localhost node and pass account objects directly to SDK --- web-client/lib/createMintConsume.ts | 2 +- web-client/lib/foreignProcedureInvocation.ts | 8 ++++---- web-client/lib/incrementCounterContract.ts | 4 ++-- web-client/lib/mintTestnetToAddress.ts | 2 +- web-client/lib/multiSendWithDelegatedProver.ts | 2 +- web-client/lib/unauthenticatedNoteTransfer.ts | 2 +- web-client/playwright.config.ts | 3 +++ 7 files changed, 13 insertions(+), 10 deletions(-) diff --git a/web-client/lib/createMintConsume.ts b/web-client/lib/createMintConsume.ts index 1f2b1bf..86b0b95 100644 --- a/web-client/lib/createMintConsume.ts +++ b/web-client/lib/createMintConsume.ts @@ -9,7 +9,7 @@ export async function createMintConsume(): Promise { const { MidenClient, AccountType, NoteVisibility, StorageMode } = await import('@miden-sdk/miden-sdk'); const client = await MidenClient.create({ - rpcUrl: 'https://rpc.testnet.miden.io', + rpcUrl: 'http://localhost:57291', }); // 1. Sync with the latest blockchain state diff --git a/web-client/lib/foreignProcedureInvocation.ts b/web-client/lib/foreignProcedureInvocation.ts index 0f3f340..47ded5b 100644 --- a/web-client/lib/foreignProcedureInvocation.ts +++ b/web-client/lib/foreignProcedureInvocation.ts @@ -114,7 +114,7 @@ export async function foreignProcedureInvocation(): Promise { // Wait for the deploy transaction to be committed to a block // before using it as a foreign account in FPI await client.transactions.execute({ - account: counterAccount.id(), + account: counterAccount, script: deployScript, waitForConfirmation: true, }); @@ -184,15 +184,15 @@ export async function foreignProcedureInvocation(): Promise { }); await client.transactions.execute({ - account: countReaderAccount.id(), + account: countReaderAccount, script, - foreignAccounts: [{ id: counterAccount.id() }], + foreignAccounts: [counterAccount], }); await client.sync(); const updatedCountReaderContract = await client.accounts.get( - countReaderAccount.id(), + countReaderAccount, ); const countReaderStorage = updatedCountReaderContract ?.storage() diff --git a/web-client/lib/incrementCounterContract.ts b/web-client/lib/incrementCounterContract.ts index de90e75..8c36252 100644 --- a/web-client/lib/incrementCounterContract.ts +++ b/web-client/lib/incrementCounterContract.ts @@ -81,7 +81,7 @@ export async function incrementCounterContract(): Promise { }); await client.transactions.execute({ - account: account.id(), + account, script, }); @@ -89,7 +89,7 @@ export async function incrementCounterContract(): Promise { console.log('Counter contract ID:', account.id().toString()); - const counter = await client.accounts.get(account.id()); + const counter = await client.accounts.get(account); const count = counter?.storage().getItem(counterSlotName); const counterValue = Number( BigInt('0x' + count!.toHex().slice(-16).match(/../g)!.reverse().join('')), diff --git a/web-client/lib/mintTestnetToAddress.ts b/web-client/lib/mintTestnetToAddress.ts index 7ab4c2f..9b560e0 100644 --- a/web-client/lib/mintTestnetToAddress.ts +++ b/web-client/lib/mintTestnetToAddress.ts @@ -17,7 +17,7 @@ export async function mintTestnetToAddress(): Promise { } = await import('@miden-sdk/miden-sdk'); const client = await MidenClient.create({ - rpcUrl: 'https://rpc.testnet.miden.io', + rpcUrl: 'http://localhost:57291', }); const prover = TransactionProver.newLocalProver(); diff --git a/web-client/lib/multiSendWithDelegatedProver.ts b/web-client/lib/multiSendWithDelegatedProver.ts index 5b9196e..a6912ac 100644 --- a/web-client/lib/multiSendWithDelegatedProver.ts +++ b/web-client/lib/multiSendWithDelegatedProver.ts @@ -19,7 +19,7 @@ export async function multiSendWithDelegatedProver(): Promise { } = await import('@miden-sdk/miden-sdk'); const client = await MidenClient.create({ - rpcUrl: 'https://rpc.testnet.miden.io', + rpcUrl: 'http://localhost:57291', }); console.log('Latest block:', (await client.sync()).blockNum()); diff --git a/web-client/lib/unauthenticatedNoteTransfer.ts b/web-client/lib/unauthenticatedNoteTransfer.ts index f8da183..a0816f4 100644 --- a/web-client/lib/unauthenticatedNoteTransfer.ts +++ b/web-client/lib/unauthenticatedNoteTransfer.ts @@ -27,7 +27,7 @@ export async function unauthenticatedNoteTransfer(): Promise { } = await import('@miden-sdk/miden-sdk'); const client = await MidenClient.create({ - rpcUrl: 'https://rpc.testnet.miden.io', + rpcUrl: 'http://localhost:57291', }); const prover = TransactionProver.newLocalProver(); diff --git a/web-client/playwright.config.ts b/web-client/playwright.config.ts index ad95c84..0d5850a 100644 --- a/web-client/playwright.config.ts +++ b/web-client/playwright.config.ts @@ -12,6 +12,9 @@ export default defineConfig({ use: { baseURL: "http://localhost:3000", headless: true, + launchOptions: { + args: ["--disable-web-security"], + }, }, webServer: { command: "yarn dev", From b5a29d1caa40411fa79d39a80d55425864db345a Mon Sep 17 00:00:00 2001 From: Wiktor Starczewski Date: Thu, 26 Feb 2026 14:20:02 +0100 Subject: [PATCH 12/14] refactor(tutorials): use send({ authenticated: false }) + consume() for unauthenticated notes Replace the manual TransactionRequestBuilder loop with the new send() API: - unauthenticatedNoteTransfer.ts: replace 10-line builder pattern with send({ authenticated: false }) + consume({ notes: [note] }) - unauthenticatedNoteTransfer.tsx: replace useInternalTransfer/transferChain with explicit useSend + useConsume loop - unauthenticated_note_how_to.md: update both TypeScript and React code snippets --- .../web-client/unauthenticated_note_how_to.md | 119 +++++++----------- .../lib/react/unauthenticatedNoteTransfer.tsx | 30 +++-- web-client/lib/unauthenticatedNoteTransfer.ts | 62 +++------ 3 files changed, 80 insertions(+), 131 deletions(-) diff --git a/docs/src/web-client/unauthenticated_note_how_to.md b/docs/src/web-client/unauthenticated_note_how_to.md index 7071ddf..37f87b6 100644 --- a/docs/src/web-client/unauthenticated_note_how_to.md +++ b/docs/src/web-client/unauthenticated_note_how_to.md @@ -162,7 +162,7 @@ Copy and paste the following code into `lib/react/unauthenticatedNoteTransfer.ts n.inputNoteRecord().id()); -..await consume({ accountId: aliceId, noteIds }); +..await consume({ accountId: alice, noteIds }); ..// 5. Create the unauthenticated note transfer chain: ..// Alice → Wallet 0 → Wallet 1 → Wallet 2 → Wallet 3 → Wallet 4 ..console.log('Starting unauthenticated transfer chain…'); -..const results = await transferChain({ -...from: aliceId, -...recipients: walletIds, -...assetId: faucetId, -...amount: BigInt(50), -...noteType: NoteVisibility.Public, -..}); - -..results.forEach((r, i) => { +..let currentSender = alice; +..for (let i = 0; i < wallets.length; i++) { +...const wallet = wallets[i]; +...const { note } = await send({ +....from: currentSender, +....to: wallet, +....assetId: faucet, +....amount: BigInt(50), +....noteType: NoteVisibility.Public, +....authenticated: false, +...}); +...const result = await consume({ accountId: wallet, noteIds: [note] }); ...console.log( -....\`Transfer \${i + 1}: https://testnet.midenscan.com/tx/\${r.consumeTransactionId}\`, +....\`Transfer \${i + 1}: https://testnet.midenscan.com/tx/\${result.transactionId}\`, ...); -..}); +...currentSender = wallet; +..} ..console.log('Asset transfer chain completed ✅'); .}; @@ -267,16 +269,6 @@ export async function unauthenticatedNoteTransfer(): Promise { ..NoteVisibility, ..StorageMode, ..TransactionProver, -..Note, -..NoteType, -..NoteAssets, -..OutputNoteArray, -..FungibleAsset, -..NoteAndArgsArray, -..NoteAndArgs, -..NoteAttachment, -..TransactionRequestBuilder, -..OutputNote, .} = await import('@miden-sdk/miden-sdk'); .const client = await MidenClient.create({ @@ -286,9 +278,7 @@ export async function unauthenticatedNoteTransfer(): Promise { .console.log('Latest block:', (await client.sync()).blockNum()); -.// ── Creating new account ────────────────────────────────────────────────────── -.console.log('Creating accounts'); - +.// ── Creating accounts ────────────────────────────────────────────────────── .console.log('Creating account for Alice…'); .const alice = await client.accounts.create({ ..type: AccountType.MutableWallet, @@ -316,7 +306,7 @@ export async function unauthenticatedNoteTransfer(): Promise { .}); .console.log('Faucet ID:', faucet.id().toString()); -.// ── mint 10 000 MID to Alice ────────────────────────────────────────────────────── +.// ── Mint 10,000 MID to Alice ────────────────────────────────────────────────────── .const mintTxId = await client.transactions.mint({ ..account: faucet, ..to: alice, @@ -343,50 +333,31 @@ export async function unauthenticatedNoteTransfer(): Promise { .for (let i = 0; i < wallets.length; i++) { ..console.log(\`\\nUnauthenticated tx \${i + 1}\`); -..// Determine sender and receiver for this iteration ..const sender = i === 0 ? alice : wallets[i - 1]; ..const receiver = wallets[i]; ..console.log('Sender:', sender.id().toString()); ..console.log('Receiver:', receiver.id().toString()); -..const assets = new NoteAssets([new FungibleAsset(faucet.id(), BigInt(50))]); -..const p2idNote = Note.createP2IDNote( -...sender.id(), -...receiver.id(), -...assets, -...NoteType.Public, -...new NoteAttachment(), -..); - -..const outputP2ID = OutputNote.full(p2idNote); - -..console.log('Creating P2ID note...'); -..{ -...const builder = new TransactionRequestBuilder(); -...const request = builder.withOwnOutputNotes(new OutputNoteArray([outputP2ID])).build(); -...await client.transactions.submit(sender.id(), request, { prover }); -..} - -..console.log('Consuming P2ID note...'); - -..const noteIdAndArgs = new NoteAndArgs(p2idNote, null); - -..const consumeBuilder = new TransactionRequestBuilder(); -..const consumeRequest = consumeBuilder.withInputNotes(new NoteAndArgsArray([noteIdAndArgs])).build(); - -..{ -...const txId = await client.transactions.submit( -....receiver.id(), -....consumeRequest, -....{ prover }, -...); +..const { note } = await client.transactions.send({ +...account: sender, +...to: receiver, +...token: faucet, +...amount: BigInt(50), +...type: NoteVisibility.Public, +...authenticated: false, +...prover, +..}); -...console.log( -....\`Consumed Note Tx on MidenScan: https://testnet.midenscan.com/tx/\${txId.toHex()}\`, -...); -..} +..const consumeTxId = await client.transactions.consume({ +...account: receiver, +...notes: [note], +...prover, +..}); +..console.log( +...\`Consumed Note Tx on MidenScan: https://testnet.midenscan.com/tx/\${consumeTxId.toHex()}\`, +..); .} .console.log('Asset transfer chain completed ✅'); diff --git a/web-client/lib/react/unauthenticatedNoteTransfer.tsx b/web-client/lib/react/unauthenticatedNoteTransfer.tsx index e9e3704..ada2b87 100644 --- a/web-client/lib/react/unauthenticatedNoteTransfer.tsx +++ b/web-client/lib/react/unauthenticatedNoteTransfer.tsx @@ -4,7 +4,7 @@ // lib/unauthenticatedNoteTransfer.ts is used for Playwright tests instead. 'use client'; -import { MidenProvider, useMiden, useCreateWallet, useCreateFaucet, useMint, useConsume, useInternalTransfer, useWaitForCommit, useWaitForNotes, type Account } from '@miden-sdk/react'; +import { MidenProvider, useMiden, useCreateWallet, useCreateFaucet, useMint, useConsume, useSend, useWaitForCommit, useWaitForNotes, type Account } from '@miden-sdk/react'; import { NoteVisibility, StorageMode } from '@miden-sdk/miden-sdk'; function UnauthenticatedNoteTransferInner() { @@ -13,7 +13,7 @@ function UnauthenticatedNoteTransferInner() { const { createFaucet } = useCreateFaucet(); const { mint } = useMint(); const { consume } = useConsume(); - const { transferChain } = useInternalTransfer(); + const { send } = useSend(); const { waitForCommit } = useWaitForCommit(); const { waitForConsumableNotes } = useWaitForNotes(); @@ -58,19 +58,25 @@ function UnauthenticatedNoteTransferInner() { // 5. Create the unauthenticated note transfer chain: // Alice → Wallet 0 → Wallet 1 → Wallet 2 → Wallet 3 → Wallet 4 console.log('Starting unauthenticated transfer chain…'); - const results = await transferChain({ - from: alice, - recipients: wallets, - assetId: faucet, - amount: BigInt(50), - noteType: NoteVisibility.Public, - }); + let currentSender: Account = alice; + for (let i = 0; i < wallets.length; i++) { + const wallet = wallets[i]; + const { note } = await send({ + from: currentSender, + to: wallet, + assetId: faucet, + amount: BigInt(50), + noteType: NoteVisibility.Public, + authenticated: false, + }); - results.forEach((r, i) => { + const result = await consume({ accountId: wallet, noteIds: [note!] }); console.log( - `Transfer ${i + 1}: https://testnet.midenscan.com/tx/${r.consumeTransactionId}`, + `Transfer ${i + 1}: https://testnet.midenscan.com/tx/${result.transactionId}`, ); - }); + + currentSender = wallet; + } console.log('Asset transfer chain completed ✅'); }; diff --git a/web-client/lib/unauthenticatedNoteTransfer.ts b/web-client/lib/unauthenticatedNoteTransfer.ts index a0816f4..36c200d 100644 --- a/web-client/lib/unauthenticatedNoteTransfer.ts +++ b/web-client/lib/unauthenticatedNoteTransfer.ts @@ -14,16 +14,6 @@ export async function unauthenticatedNoteTransfer(): Promise { NoteVisibility, StorageMode, TransactionProver, - Note, - NoteType, - NoteAssets, - OutputNoteArray, - FungibleAsset, - NoteAndArgsArray, - NoteAndArgs, - NoteAttachment, - TransactionRequestBuilder, - OutputNote, } = await import('@miden-sdk/miden-sdk'); const client = await MidenClient.create({ @@ -90,49 +80,31 @@ export async function unauthenticatedNoteTransfer(): Promise { for (let i = 0; i < wallets.length; i++) { console.log(`\nUnauthenticated tx ${i + 1}`); - // Determine sender and receiver for this iteration const sender = i === 0 ? alice : wallets[i - 1]; const receiver = wallets[i]; console.log('Sender:', sender.id().toString()); console.log('Receiver:', receiver.id().toString()); - const assets = new NoteAssets([new FungibleAsset(faucet.id(), BigInt(50))]); - const p2idNote = Note.createP2IDNote( - sender.id(), - receiver.id(), - assets, - NoteType.Public, - new NoteAttachment(), - ); - - const outputP2ID = OutputNote.full(p2idNote); - - console.log('Creating P2ID note...'); - { - const builder = new TransactionRequestBuilder(); - const request = builder.withOwnOutputNotes(new OutputNoteArray([outputP2ID])).build(); - await client.transactions.submit(sender, request, { prover }); - } - - console.log('Consuming P2ID note...'); - - const noteIdAndArgs = new NoteAndArgs(p2idNote, null); - - const consumeBuilder = new TransactionRequestBuilder(); - const consumeRequest = consumeBuilder.withInputNotes(new NoteAndArgsArray([noteIdAndArgs])).build(); + const { note } = await client.transactions.send({ + account: sender, + to: receiver, + token: faucet, + amount: BigInt(50), + type: NoteVisibility.Public, + authenticated: false, + prover, + }); - { - const txId = await client.transactions.submit( - receiver, - consumeRequest, - { prover }, - ); + const consumeTxId = await client.transactions.consume({ + account: receiver, + notes: [note], + prover, + }); - console.log( - `Consumed Note Tx on MidenScan: https://testnet.midenscan.com/tx/${txId.toHex()}`, - ); - } + console.log( + `Consumed Note Tx on MidenScan: https://testnet.midenscan.com/tx/${consumeTxId.toHex()}`, + ); } console.log('Asset transfer chain completed ✅'); From 967a7eaa25dd08b7648e1326be93584a060db3d0 Mon Sep 17 00:00:00 2001 From: Wiktor Starczewski Date: Thu, 26 Feb 2026 14:45:14 +0100 Subject: [PATCH 13/14] refactor(tutorials): use proverUrl shorthand at client creation Replace per-call TransactionProver.newLocalProver() with proverUrl: 'local' in MidenClient.create(). Removes the TransactionProver import from tutorial files. --- docs/src/web-client/unauthenticated_note_how_to.md | 7 +------ web-client/lib/mintTestnetToAddress.ts | 4 +--- web-client/lib/unauthenticatedNoteTransfer.ts | 7 +------ 3 files changed, 3 insertions(+), 15 deletions(-) diff --git a/docs/src/web-client/unauthenticated_note_how_to.md b/docs/src/web-client/unauthenticated_note_how_to.md index 37f87b6..087fc9b 100644 --- a/docs/src/web-client/unauthenticated_note_how_to.md +++ b/docs/src/web-client/unauthenticated_note_how_to.md @@ -268,13 +268,12 @@ export async function unauthenticatedNoteTransfer(): Promise { ..AccountType, ..NoteVisibility, ..StorageMode, -..TransactionProver, .} = await import('@miden-sdk/miden-sdk'); .const client = await MidenClient.create({ ..rpcUrl: 'https://rpc.testnet.miden.io', +..proverUrl: 'local', .}); -.const prover = TransactionProver.newLocalProver(); .console.log('Latest block:', (await client.sync()).blockNum()); @@ -312,7 +311,6 @@ export async function unauthenticatedNoteTransfer(): Promise { ..to: alice, ..amount: BigInt(10_000), ..type: NoteVisibility.Public, -..prover, .}); .console.log('Waiting for settlement'); @@ -324,7 +322,6 @@ export async function unauthenticatedNoteTransfer(): Promise { .await client.transactions.consume({ ..account: alice, ..notes: noteList.map((n) => n.inputNoteRecord()), -..prover, .}); .await client.sync(); @@ -346,13 +343,11 @@ export async function unauthenticatedNoteTransfer(): Promise { ...amount: BigInt(50), ...type: NoteVisibility.Public, ...authenticated: false, -...prover, ..}); ..const consumeTxId = await client.transactions.consume({ ...account: receiver, ...notes: [note], -...prover, ..}); ..console.log( diff --git a/web-client/lib/mintTestnetToAddress.ts b/web-client/lib/mintTestnetToAddress.ts index 9b560e0..020554b 100644 --- a/web-client/lib/mintTestnetToAddress.ts +++ b/web-client/lib/mintTestnetToAddress.ts @@ -13,13 +13,12 @@ export async function mintTestnetToAddress(): Promise { NoteVisibility, StorageMode, Address, - TransactionProver, } = await import('@miden-sdk/miden-sdk'); const client = await MidenClient.create({ rpcUrl: 'http://localhost:57291', + proverUrl: 'local', }); - const prover = TransactionProver.newLocalProver(); console.log('Latest block:', (await client.sync()).blockNum()); @@ -47,7 +46,6 @@ export async function mintTestnetToAddress(): Promise { to: recipientAccountId, amount: BigInt(100), type: NoteVisibility.Public, - prover, }); console.log('Waiting for settlement...'); diff --git a/web-client/lib/unauthenticatedNoteTransfer.ts b/web-client/lib/unauthenticatedNoteTransfer.ts index 36c200d..c3b5e32 100644 --- a/web-client/lib/unauthenticatedNoteTransfer.ts +++ b/web-client/lib/unauthenticatedNoteTransfer.ts @@ -13,13 +13,12 @@ export async function unauthenticatedNoteTransfer(): Promise { AccountType, NoteVisibility, StorageMode, - TransactionProver, } = await import('@miden-sdk/miden-sdk'); const client = await MidenClient.create({ rpcUrl: 'http://localhost:57291', + proverUrl: 'local', }); - const prover = TransactionProver.newLocalProver(); console.log('Latest block:', (await client.sync()).blockNum()); @@ -59,7 +58,6 @@ export async function unauthenticatedNoteTransfer(): Promise { to: alice, amount: BigInt(10_000), type: NoteVisibility.Public, - prover, }); console.log('Waiting for settlement'); @@ -71,7 +69,6 @@ export async function unauthenticatedNoteTransfer(): Promise { await client.transactions.consume({ account: alice, notes: noteList.map((n) => n.inputNoteRecord()), - prover, }); await client.sync(); @@ -93,13 +90,11 @@ export async function unauthenticatedNoteTransfer(): Promise { amount: BigInt(50), type: NoteVisibility.Public, authenticated: false, - prover, }); const consumeTxId = await client.transactions.consume({ account: receiver, notes: [note], - prover, }); console.log( From 678e9748b53f80c9ed2fd3695a021d55f6e88229 Mon Sep 17 00:00:00 2001 From: Wiktor Starczewski Date: Thu, 26 Feb 2026 14:52:02 +0100 Subject: [PATCH 14/14] refactor(tutorials): use rpcUrl shorthand 'local' in TS client tutorials --- docs/src/web-client/unauthenticated_note_how_to.md | 2 +- web-client/lib/mintTestnetToAddress.ts | 2 +- web-client/lib/unauthenticatedNoteTransfer.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/src/web-client/unauthenticated_note_how_to.md b/docs/src/web-client/unauthenticated_note_how_to.md index 087fc9b..bb0f7bf 100644 --- a/docs/src/web-client/unauthenticated_note_how_to.md +++ b/docs/src/web-client/unauthenticated_note_how_to.md @@ -271,7 +271,7 @@ export async function unauthenticatedNoteTransfer(): Promise { .} = await import('@miden-sdk/miden-sdk'); .const client = await MidenClient.create({ -..rpcUrl: 'https://rpc.testnet.miden.io', +..rpcUrl: 'local', ..proverUrl: 'local', .}); diff --git a/web-client/lib/mintTestnetToAddress.ts b/web-client/lib/mintTestnetToAddress.ts index 020554b..90ddaf1 100644 --- a/web-client/lib/mintTestnetToAddress.ts +++ b/web-client/lib/mintTestnetToAddress.ts @@ -16,7 +16,7 @@ export async function mintTestnetToAddress(): Promise { } = await import('@miden-sdk/miden-sdk'); const client = await MidenClient.create({ - rpcUrl: 'http://localhost:57291', + rpcUrl: 'local', proverUrl: 'local', }); diff --git a/web-client/lib/unauthenticatedNoteTransfer.ts b/web-client/lib/unauthenticatedNoteTransfer.ts index c3b5e32..fc05b41 100644 --- a/web-client/lib/unauthenticatedNoteTransfer.ts +++ b/web-client/lib/unauthenticatedNoteTransfer.ts @@ -16,7 +16,7 @@ export async function unauthenticatedNoteTransfer(): Promise { } = await import('@miden-sdk/miden-sdk'); const client = await MidenClient.create({ - rpcUrl: 'http://localhost:57291', + rpcUrl: 'local', proverUrl: 'local', });