Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
211 changes: 20 additions & 191 deletions docs/src/web-client/creating_multiple_notes_tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,75 +106,16 @@ export default function Home() {
}
```

## Step 3 — Initalize the WebClient & Define the Note Script 
## Step 3 — Initalize the WebClient

Create the file `lib/multiSendWithDelegatedProver.ts` and add the following code. This snippet defines the P2ID note script, implements the function `multiSendWithDelegatedProver`, and initializes the WebClient along with the delegated prover endpoint.
Create the file `lib/multiSendWithDelegatedProver.ts` and add the following code. This snippet implements the function `multiSendWithDelegatedProver`, and initializes the WebClient along with the delegated prover endpoint.

```
mkdir -p lib
touch lib/multiSendWithDelegatedProver.ts
```

```ts
/**
* P2ID (Pay to ID) Note Script for Miden Network
* Enables creating notes that can be received by specific account IDs
*/
const P2ID_NOTE_SCRIPT = `
use.miden::account
use.miden::account_id
use.miden::note

# ERRORS
# =================================================================================================

const.ERR_P2ID_WRONG_NUMBER_OF_INPUTS="P2ID note expects exactly 2 note inputs"

const.ERR_P2ID_TARGET_ACCT_MISMATCH="P2ID's target account address and transaction address do not match"

#! Pay-to-ID script: adds all assets from the note to the account, assuming ID of the account
#! matches target account ID specified by the note inputs.
#!
#! Requires that the account exposes:
#! - miden::contracts::wallets::basic::receive_asset procedure.
#!
#! Inputs: []
#! Outputs: []
#!
#! Note inputs are assumed to be as follows:
#! - target_account_id is the ID of the account for which the note is intended.
#!
#! Panics if:
#! - Account does not expose miden::contracts::wallets::basic::receive_asset procedure.
#! - Account ID of executing account is not equal to the Account ID specified via note inputs.
#! - The same non-fungible asset already exists in the account.
#! - Adding a fungible asset would result in amount overflow, i.e., the total amount would be
#! greater than 2^63.
begin
# store the note inputs to memory starting at address 0
padw push.0 exec.note::get_inputs
# => [num_inputs, inputs_ptr, EMPTY_WORD]

# make sure the number of inputs is 2
eq.2 assert.err=ERR_P2ID_WRONG_NUMBER_OF_INPUTS
# => [inputs_ptr, EMPTY_WORD]

# read the target account ID from the note inputs
mem_loadw drop drop
# => [target_account_id_prefix, target_account_id_suffix]

exec.account::get_id
# => [account_id_prefix, account_id_suffix, target_account_id_prefix, target_account_id_suffix, ...]

# ensure account_id = target_account_id, fails otherwise
exec.account_id::is_equal assert.err=ERR_P2ID_TARGET_ACCT_MISMATCH
# => []

exec.note::add_note_assets_to_account
# => []
end
`;

export async function multiSendWithDelegatedProver(): Promise<void> {
// Ensure this runs only in a browser context
if (typeof window === "undefined") return console.warn("Run in browser");
Expand Down Expand Up @@ -278,31 +219,16 @@ const recipientAddresses = [
"0x67dc56bd0cbe629000006f36d81029",
];

const script = client.compileNoteScript(P2ID_NOTE_SCRIPT);

const assets = new NoteAssets([new FungibleAsset(faucet.id(), BigInt(100))]);
const metadata = new NoteMetadata(
alice.id(),
NoteType.Public,
NoteTag.fromAccountId(alice.id(), NoteExecutionMode.newLocal()),
NoteExecutionHint.always(),
);

const p2idNotes = recipientAddresses.map((addr) => {
let serialNumber = Word.newFromFelts([
new Felt(BigInt(Math.floor(Math.random() * 0x1_0000_0000))),
new Felt(BigInt(Math.floor(Math.random() * 0x1_0000_0000))),
new Felt(BigInt(Math.floor(Math.random() * 0x1_0000_0000))),
new Felt(BigInt(Math.floor(Math.random() * 0x1_0000_0000))),
]);

const acct = AccountId.fromHex(addr);
const inputs = new NoteInputs(new FeltArray([acct.suffix(), acct.prefix()]));

let note = new Note(
const receiverAccountId = AccountId.fromHex(addr);
let note = Note.createP2IDNote(
alice.id(),
receiverAccountId,
assets,
metadata,
new NoteRecipient(serialNumber, script, inputs),
NoteType.Public,
new Felt(BigInt(0)),
);

return OutputNote.full(note);
Expand All @@ -328,64 +254,11 @@ Your `lib/multiSendWithDelegatedProver.ts` file sould now look like this:

```ts
/**
* P2ID (Pay to ID) Note Script for Miden Network
* Enables creating notes that can be received by specific account IDs
* Demonstrates multi-send functionality using a delegated prover on the Miden Network
* Creates multiple P2ID (Pay to ID) notes for different recipients
*
* @throws {Error} If the function cannot be executed in a browser environment
*/
const P2ID_NOTE_SCRIPT = `
use.miden::account
use.miden::account_id
use.miden::note

# ERRORS
# =================================================================================================

const.ERR_P2ID_WRONG_NUMBER_OF_INPUTS="P2ID note expects exactly 2 note inputs"

const.ERR_P2ID_TARGET_ACCT_MISMATCH="P2ID's target account address and transaction address do not match"

#! Pay-to-ID script: adds all assets from the note to the account, assuming ID of the account
#! matches target account ID specified by the note inputs.
#!
#! Requires that the account exposes:
#! - miden::contracts::wallets::basic::receive_asset procedure.
#!
#! Inputs: []
#! Outputs: []
#!
#! Note inputs are assumed to be as follows:
#! - target_account_id is the ID of the account for which the note is intended.
#!
#! Panics if:
#! - Account does not expose miden::contracts::wallets::basic::receive_asset procedure.
#! - Account ID of executing account is not equal to the Account ID specified via note inputs.
#! - The same non-fungible asset already exists in the account.
#! - Adding a fungible asset would result in amount overflow, i.e., the total amount would be
#! greater than 2^63.
begin
# store the note inputs to memory starting at address 0
padw push.0 exec.note::get_inputs
# => [num_inputs, inputs_ptr, EMPTY_WORD]

# make sure the number of inputs is 2
eq.2 assert.err=ERR_P2ID_WRONG_NUMBER_OF_INPUTS
# => [inputs_ptr, EMPTY_WORD]

# read the target account ID from the note inputs
mem_loadw drop drop
# => [target_account_id_prefix, target_account_id_suffix]

exec.account::get_id
# => [account_id_prefix, account_id_suffix, target_account_id_prefix, target_account_id_suffix, ...]

# ensure account_id = target_account_id, fails otherwise
exec.account_id::is_equal assert.err=ERR_P2ID_TARGET_ACCT_MISMATCH
# => []

exec.note::add_note_assets_to_account
# => []
end
`;

export async function multiSendWithDelegatedProver(): Promise<void> {
// Ensure this runs only in a browser context
if (typeof window === "undefined") return console.warn("Run in browser");
Expand Down Expand Up @@ -413,11 +286,9 @@ export async function multiSendWithDelegatedProver(): Promise<void> {
OutputNote,
} = await import("@demox-labs/miden-sdk");

const client = await WebClient.createClient(
"https://rpc.testnet.miden.io:443",
);
const client = await WebClient.createClient("https://rpc.testnet.miden.io");
const prover = TransactionProver.newRemoteProver(
"https://tx-prover.testnet.miden.io",
"https://tx-prover.devnet.miden.io",
);

console.log("Latest block:", (await client.syncState()).blockNum());
Expand Down Expand Up @@ -476,33 +347,16 @@ export async function multiSendWithDelegatedProver(): Promise<void> {
"0x67dc56bd0cbe629000006f36d81029",
];

const script = client.compileNoteScript(P2ID_NOTE_SCRIPT);

const assets = new NoteAssets([new FungibleAsset(faucet.id(), BigInt(100))]);
const metadata = new NoteMetadata(
alice.id(),
NoteType.Public,
NoteTag.fromAccountId(alice.id(), NoteExecutionMode.newLocal()),
NoteExecutionHint.always(),
);

const p2idNotes = recipientAddresses.map((addr) => {
let serialNumber = Word.newFromFelts([
new Felt(BigInt(Math.floor(Math.random() * 0x1_0000_0000))),
new Felt(BigInt(Math.floor(Math.random() * 0x1_0000_0000))),
new Felt(BigInt(Math.floor(Math.random() * 0x1_0000_0000))),
new Felt(BigInt(Math.floor(Math.random() * 0x1_0000_0000))),
]);

const acct = AccountId.fromHex(addr);
const inputs = new NoteInputs(
new FeltArray([acct.suffix(), acct.prefix()]),
);

let note = new Note(
const receiverAccountId = AccountId.fromHex(addr);
let note = Note.createP2IDNote(
alice.id(),
receiverAccountId,
assets,
metadata,
new NoteRecipient(serialNumber, script, inputs),
NoteType.Public,
new Felt(BigInt(0)),
);

return OutputNote.full(note);
Expand All @@ -522,28 +376,3 @@ export async function multiSendWithDelegatedProver(): Promise<void> {
console.log("All notes created ✅");
}
```

### Running the example

To run a full working example navigate to the `web-client` directory in the [miden-tutorials](https://github.com/0xMiden/miden-tutorials/) repository and run the web application example:

```bash
cd web-client
pnpm i
pnpm run start
```

### Resetting the `MidenClientDB`

The Miden webclient stores account and note data in the browser. To clear the account and node data in the browser, paste this code snippet into the browser console:

```javascript
(async () => {
const dbs = await indexedDB.databases(); // Get all database names
for (const db of dbs) {
await indexedDB.deleteDatabase(db.name);
console.log(`Deleted database: ${db.name}`);
}
console.log("All databases deleted.");
})();
```
88 changes: 6 additions & 82 deletions docs/src/web-client/unauthenticated_note_how_to.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,65 +138,6 @@ touch lib/unauthenticatedNoteTransfer.ts
Copy and paste the following code into the `lib/unauthenticatedNoteTransfer.ts` file:

```ts
/**
* P2ID (Pay to ID) Note Script for Miden Network
* Enables creating notes that can be received by specific account IDs
*/
const P2ID_NOTE_SCRIPT = `
use.miden::account
use.miden::account_id
use.miden::note

# ERRORS
# =================================================================================================

const.ERR_P2ID_WRONG_NUMBER_OF_INPUTS="P2ID note expects exactly 2 note inputs"

const.ERR_P2ID_TARGET_ACCT_MISMATCH="P2ID's target account address and transaction address do not match"

#! Pay-to-ID script: adds all assets from the note to the account, assuming ID of the account
#! matches target account ID specified by the note inputs.
#!
#! Requires that the account exposes:
#! - miden::contracts::wallets::basic::receive_asset procedure.
#!
#! Inputs: []
#! Outputs: []
#!
#! Note inputs are assumed to be as follows:
#! - target_account_id is the ID of the account for which the note is intended.
#!
#! Panics if:
#! - Account does not expose miden::contracts::wallets::basic::receive_asset procedure.
#! - Account ID of executing account is not equal to the Account ID specified via note inputs.
#! - The same non-fungible asset already exists in the account.
#! - Adding a fungible asset would result in amount overflow, i.e., the total amount would be
#! greater than 2^63.
begin
# store the note inputs to memory starting at address 0
padw push.0 exec.note::get_inputs
# => [num_inputs, inputs_ptr, EMPTY_WORD]

# make sure the number of inputs is 2
eq.2 assert.err=ERR_P2ID_WRONG_NUMBER_OF_INPUTS
# => [inputs_ptr, EMPTY_WORD]

# read the target account ID from the note inputs
mem_loadw drop drop
# => [target_account_id_prefix, target_account_id_suffix]

exec.account::get_id
# => [account_id_prefix, account_id_suffix, target_account_id_prefix, target_account_id_suffix, ...]

# ensure account_id = target_account_id, fails otherwise
exec.account_id::is_equal assert.err=ERR_P2ID_TARGET_ACCT_MISMATCH
# => []

exec.note::add_note_assets_to_account
# => []
end
`;

/**
* Demonstrates unauthenticated note transfer chain using a delegated prover on the Miden Network
* Creates a chain of P2ID (Pay to ID) notes: Alice → wallet 1 → wallet 2 → wallet 3 → wallet 4
Expand Down Expand Up @@ -295,8 +236,6 @@ export async function unauthenticatedNoteTransfer(): Promise<void> {
);
await client.syncState();

const script = client.compileNoteScript(P2ID_NOTE_SCRIPT);

// ── Create unauthenticated note transfer chain ─────────────────────────────────────────────
// Alice → wallet 1 → wallet 2 → wallet 3 → wallet 4
for (let i = 0; i < wallets.length; i++) {
Expand All @@ -310,29 +249,14 @@ export async function unauthenticatedNoteTransfer(): Promise<void> {
console.log("Receiver:", receiver.id().toString());

const assets = new NoteAssets([new FungibleAsset(faucet.id(), BigInt(50))]);
const metadata = new NoteMetadata(
sender.id(),
NoteType.Public,
NoteTag.fromAccountId(sender.id()),
NoteExecutionHint.always(),
);

let serialNumber = Word.newFromFelts([
new Felt(BigInt(Math.floor(Math.random() * 0x1_0000_0000))),
new Felt(BigInt(Math.floor(Math.random() * 0x1_0000_0000))),
new Felt(BigInt(Math.floor(Math.random() * 0x1_0000_0000))),
new Felt(BigInt(Math.floor(Math.random() * 0x1_0000_0000))),
]);

const receiverAcct = AccountId.fromHex(receiver.id().toString());
const inputs = new NoteInputs(
new FeltArray([receiverAcct.suffix(), receiverAcct.prefix()]),
);
const receiverAccountId = AccountId.fromHex(receiver.id().toString());

let p2idNote = new Note(
let p2idNote = Note.createP2IDNote(
sender.id(),
receiverAccountId,
assets,
metadata,
new NoteRecipient(serialNumber, script, inputs),
NoteType.Public,
new Felt(BigInt(0)),
);

let outputP2ID = OutputNote.full(p2idNote);
Expand Down
Loading