<!doctype html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>WASM Example</title> </head> <body> <label for="accountFileInput" class="custom-file-upload"> Choose Account File </label> <input type="file" id="accountFileInput" style="display: none" /> <label for="noteFileInput" class="custom-file-upload"> Choose Note File </label> <input type="file" id="noteFileInput" style="display: none" /> <script type="module" src="./dist/index.js"></script> <script type="module"> // Example of using the exported WebClient in the browser import { AdviceMap, AccountStorageMode, AuthSecretKey, Felt, FeltArray, FungibleAsset, InputNoteState, Note, NoteAssets, NoteExecutionHint, NoteExecutionMode, NoteFilter, NoteId, NoteIdAndArgs, NoteIdAndArgsArray, NoteInputs, NoteMetadata, NoteRecipient, NoteTag, NoteType, OutputNote, OutputNotesArray, Rpo256, TransactionRequest, TransactionRequestBuilder, TransactionScriptInputPair, TransactionScriptInputPairArray, WebClient, } from "./dist/index.js"; document .getElementById("accountFileInput") .addEventListener("change", function (event) { const file = event.target.files[0]; if (file) { const reader = new FileReader(); reader.onload = async function (e) { let webClient = await createMidenWebClient(); const arrayBuffer = e.target.result; const byteArray = new Uint8Array(arrayBuffer); await testImportAccount(webClient, byteArray); }; reader.readAsArrayBuffer(file); } }); document .getElementById("noteFileInput") .addEventListener("change", async function (event) { const file = event.target.files[0]; if (file) { const reader = new FileReader(); reader.onload = async function (e) { let webClient = await createMidenWebClient(); const arrayBuffer = e.target.result; const byteArray = new Uint8Array(arrayBuffer); await importInputNote(webClient, byteArray, true); }; reader.readAsArrayBuffer(file); } }); function setupNoteFileInputListener(webClient) { document .getElementById("noteFileInput") .addEventListener("change", async function (event) { const file = event.target.files[0]; if (file) { try { const byteArray = await readFileAsByteArray(file); console.log(byteArray); // Output the byte array to check the content let result = await importInputNote(webClient, byteArray); console.log(result); // Log the result of the import process } catch (error) { console.error("Error handling file:", error); } } }); } async function readFileAsByteArray(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = () => { const arrayBuffer = reader.result; const byteArray = new Uint8Array(arrayBuffer); console.log("Byte array length:", byteArray.length); // Check the length resolve(byteArray); }; reader.onerror = () => { console.error("File read error:", reader.error); reject(reader.error); }; reader.readAsArrayBuffer(file); }); } async function createMidenWebClient(dbName = "MidenClientDB", initSeed) { try { let rpc_url = "http://localhost:57291"; let envoy_proxy_url = "http://localhost:8080"; const webClient = new WebClient(); await webClient.create_client(rpc_url, null, initSeed); return webClient; } catch (error) { console.error("Failed to create client with web store:", error); } } async function testStoreAndRpc(webClient) { try { await webClient.test_store_and_rpc(); } catch (error) { console.error("Failed to create client with web store:", error); } } // Account Functions /////////////////////////////////////////////////////////////////// async function createNewWallet(webClient, storageMode, mutable) { try { let result = await webClient.new_wallet(storageMode, mutable); console.log(`Created new wallet account with id ${result}`); return result; } catch (error) { console.error("Failed to call create account:", error); } } async function createNewFaucet( webClient, storageMode, nonFungible, tokenSymbol, decimals, maxSupply ) { try { let result = await webClient.new_faucet( storageMode, nonFungible, tokenSymbol, decimals, maxSupply ); console.log(`Created new faucet with id ${result}`); return result; } catch (error) { console.error("Failed to call create account:", error); } } async function importAccount(webClient, accountAsBytes) { try { let result = await webClient.import_account(accountAsBytes); console.log(result); return result; } catch (error) { console.error("Failed to call import account:", error); } } async function getAccounts(webClient) { try { let accounts = await webClient.get_accounts(); let accountIds = accounts.map((account) => account.id); console.log(accountIds); return accountIds; } catch (error) { console.error("Failed to call get accounts:", error); } } async function getAccount(webClient, accountId) { try { let result = await webClient.get_account(accountId); console.log(result); return result; } catch (error) { console.error("Failed to call get account:", error); } } // Transaction Functions /////////////////////////////////////////////////////////////////// async function createNewMintTransaction( webClient, targetAccountId, faucetId, noteType, amount ) { try { let result = await webClient.new_mint_transaction( targetAccountId, faucetId, noteType, amount ); console.log( `Created new mint transaction with id ${result.transaction_id}` ); console.log(`Output notes created: ${result.created_note_ids}`); return result; } catch (error) { console.error("Failed to call create new mint transaction:", error); } } async function createNewConsumeTransaction( webClient, accountId, listOfNotes ) { try { let result = await webClient.new_consume_transaction( accountId, listOfNotes ); console.log( `Created new consume transaction with id ${result.transaction_id}` ); console.log(`Output notes created: ${result.created_note_ids}`); return result; } catch (error) { console.error( "Failed to call create new consume transaction:", error ); } } async function createNewSendTransaction( webClient, senderAccountId, targetAccountId, facuetId, noteType, amount, recallHeight ) { try { let result = await webClient.new_send_transaction( senderAccountId, targetAccountId, facuetId, noteType, amount, recallHeight ); console.log( `Created new send transaction with id ${result.transaction_id}` ); console.log(`Output notes created: ${result.created_note_ids}`); return result; } catch (error) { console.error("Failed to call create new send transaction:", error); } } async function createNewSwapTransaction( webClient, senderAccountId, offeredAssetFaucetId, offeredAssetAmount, requestedAssetFaucetId, requestedAssetAmount, noteType ) { try { let result = await webClient.new_swap_transaction( senderAccountId, offeredAssetFaucetId, offeredAssetAmount, requestedAssetFaucetId, requestedAssetAmount, noteType ); console.log( `Created new swap transaction with id ${result.transaction_id}` ); console.log( `Output notes created: ${result.expected_output_note_ids}` ); console.log( `Expected Partial Notes: ${result.expected_partial_note_ids}` ); console.log(`Payback Note Tag: ${result.payback_note_tag}`); return result; } catch (error) { console.error("Failed to call create new swap transaction:", error); } } async function getTransactions(webClient) { try { let result = await webClient.get_transactions(); console.log(result); return result; } catch (error) { console.error("Failed to call get transactions:", error); } } // Note Functions /////////////////////////////////////////////////////////////////// async function getInputNotes(webClient, status = "All") { try { let result = await webClient.get_input_notes(status); console.log(result); return result; } catch (error) { console.error("Failed to call get input notes:", error); } } async function getInputNote(webClient, noteId) { try { let result = await webClient.get_input_note(noteId); console.log(result); return result; } catch (error) { console.error("Failed to call get input note:", error); } } async function getOutputNotes(webClient, status = "All") { try { let result = await webClient.get_output_notes(status); console.log(result); return result; } catch (error) { console.error("Failed to call get output notes:", error); } } async function getOutputNote(webClient, noteId) { try { let result = await webClient.get_output_note(noteId); console.log(result); return result; } catch (error) { console.error("Failed to call get input note:", error); } } async function importInputNote(webClient, noteAsBytes, verify) { try { await webClient.import_note(noteAsBytes, verify); } catch (error) { console.error("Failed to call import input note:", error); } } async function exportNote(webClient, noteId) { try { let result = await webClient.export_note(noteId, "Partial"); let byteArray = new Uint8Array(result); console.log(byteArray); return byteArray; } catch (error) { console.error("Failed to call export input note:", error); } } // Sync Functions /////////////////////////////////////////////////////////////////// async function syncState(webClient) { try { let result = await webClient.sync_state(); console.log("Synced state to block ", result); } catch (error) { console.error("Failed to call sync state:", error); } } async function addTag(webClient, noteTag) { try { let result = await webClient.add_tag(noteTag); console.log(result); } catch (error) { console.error("Failed to call add note tag:", error); } } // Tests /////////////////////////////////////////////////////////////////// // Done async function testCreateNewWallet() { const initSeed = new Uint8Array([ 223, 198, 73, 130, 93, 79, 220, 107, 25, 181, 91, 235, 101, 105, 136, 172, 151, 161, 174, 73, 142, 81, 238, 192, 227, 93, 54, 113, 136, 223, 75, 174, ]); console.log("testCreateNewWallet started"); const webClient = await createMidenWebClient("MidenClientDB", initSeed); const wallet = await webClient.new_wallet( AccountStorageMode.public(), true ); console.log("Wallet id: "); console.log(wallet.id().to_string()); console.log("testCreateNewWallet finished"); } // Done async function testCreateNewFaucet() { console.log("testCreateNewFaucet started"); let webClient = await createMidenWebClient(); await createNewFaucet( webClient, "Private", false, "DEN", "10", "1000000" ); console.log("testCreateNewFaucet finished"); } // Done async function testImportAccount(webClient, accountAsBytes) { console.log("testImportAccount started"); await importAccount(webClient, accountAsBytes); console.log("testImportAccount finished"); } // Done async function testGetAccounts(shouldCreateAccounts = true) { console.log("testGetAccounts started"); let webClient = await createMidenWebClient(); if (shouldCreateAccounts) { await createNewWallet(webClient, "Private", true); } await getAccounts(webClient); console.log("testGetAccounts finished"); } // Done async function testGetAccount() { console.log("testGetAccount started"); let webClient = await createMidenWebClient(); let accountId = await createNewWallet(webClient, "Private", true); await getAccount(webClient, accountId.to_string()); console.log("testGetAccount finished"); } // Done async function testNewMintTransaction() { console.log("testNewMintTransaction started"); let webClient = await createMidenWebClient(); let targetAccount = await createNewWallet( webClient, AccountStorageMode.private(), true ); let faucet = await createNewFaucet( webClient, AccountStorageMode.private(), false, "DAG", 8, BigInt(10000000) ); console.log("syncing state..."); await syncState(webClient); console.log("state synced"); await new Promise((r) => setTimeout(r, 20000)); await webClient.fetch_and_cache_account_auth_by_pub_key(faucet.id()); console.log("fetched"); let result = await createNewMintTransaction( webClient, targetAccount.id(), faucet.id(), NoteType.private(), BigInt(1000) ); await new Promise((r) => setTimeout(r, 20000)); await syncState(webClient); console.log("testNewMintTransaction finished"); } // Done async function testNewConsumeTransaction() { console.log("testNewConsumeTransaction started"); let webClient = await createMidenWebClient(); let targetAccount = await createNewWallet( webClient, AccountStorageMode.private(), true ); let faucet = await createNewFaucet( webClient, AccountStorageMode.private(), false, "DEN", 10, BigInt(1000000) ); await new Promise((r) => setTimeout(r, 20000)); await syncState(webClient); await webClient.fetch_and_cache_account_auth_by_pub_key(faucet.id()); let mintTransactionResult = await createNewMintTransaction( webClient, targetAccount.id(), faucet.id(), NoteType.private(), BigInt(1000) ); let created_notes = mintTransactionResult.created_notes().notes(); let created_note_ids = created_notes.map((note) => note.id().to_string() ); console.log("waiting on minted notes to get eaten by the rpc..."); await new Promise((r) => setTimeout(r, 20000)); await syncState(webClient); await webClient.fetch_and_cache_account_auth_by_pub_key( targetAccount.id() ); let consumeTransactionResult = await createNewConsumeTransaction( webClient, targetAccount.id(), created_note_ids ); await new Promise((r) => setTimeout(r, 20000)); await syncState(webClient); console.log("testNewConsumeTransaction finished"); } // Done async function testNewSendTransaction() { console.log("testNewSendTransaction started"); let webClient = await createMidenWebClient(); let senderAccountId = await createNewWallet(webClient, "Private", true); let targetAccountId = await createNewWallet(webClient, "Private", true); let faucetId = await createNewFaucet( webClient, "Private", false, "DEN", "10", "1000000" ); await syncState(webClient); await new Promise((r) => setTimeout(r, 20000)); await webClient.fetch_and_cache_account_auth_by_pub_key( faucetId.to_string() ); let mintTransactionResult = await createNewMintTransaction( webClient, senderAccountId.to_string(), faucetId.to_string(), "Private", "1000" ); await new Promise((r) => setTimeout(r, 20000)); await syncState(webClient); await webClient.fetch_and_cache_account_auth_by_pub_key( senderAccountId.to_string() ); let consumeTransactionResult = await createNewConsumeTransaction( webClient, senderAccountId.to_string(), mintTransactionResult.created_note_ids ); await new Promise((r) => setTimeout(r, 20000)); await syncState(webClient); await webClient.fetch_and_cache_account_auth_by_pub_key( senderAccountId.to_string() ); let sendTransactionResult = await createNewSendTransaction( webClient, senderAccountId.to_string(), targetAccountId.to_string(), faucetId.to_string(), "Private", "500", null ); await new Promise((r) => setTimeout(r, 20000)); await syncState(webClient); await webClient.fetch_and_cache_account_auth_by_pub_key( targetAccountId.to_string() ); let consumeSendTransactionResult = await createNewConsumeTransaction( webClient, targetAccountId.to_string(), sendTransactionResult.created_note_ids ); await new Promise((r) => setTimeout(r, 20000)); await syncState(webClient); console.log("testNewSendTransaction finished"); } // Done async function testNewSendTransactionWithRecallHeight() { console.log("testNewSendTransactionWithRecallHeight started"); let webClient = await createMidenWebClient(); let senderAccountId = await createNewWallet(webClient, "Private", true); let targetAccountId = await createNewWallet(webClient, "Private", true); let faucetId = await createNewFaucet( webClient, "Private", false, "DEN", "10", "1000000" ); await syncState(webClient); await new Promise((r) => setTimeout(r, 20000)); await webClient.fetch_and_cache_account_auth_by_pub_key( faucetId.to_string() ); let mintTransactionResult = await createNewMintTransaction( webClient, senderAccountId.to_string(), faucetId.to_string(), "Private", "1000" ); await new Promise((r) => setTimeout(r, 20000)); await syncState(webClient); await webClient.fetch_and_cache_account_auth_by_pub_key( senderAccountId.to_string() ); let consumeTransactionResult = await createNewConsumeTransaction( webClient, senderAccountId.to_string(), mintTransactionResult.created_note_ids ); await new Promise((r) => setTimeout(r, 20000)); await syncState(webClient); await webClient.fetch_and_cache_account_auth_by_pub_key( senderAccountId.to_string() ); let sendTransactionResult = await createNewSendTransaction( webClient, senderAccountId.to_string(), targetAccountId.to_string(), faucetId.to_string(), "Private", "500", "0" ); await new Promise((r) => setTimeout(r, 20000)); await syncState(webClient); await webClient.fetch_and_cache_account_auth_by_pub_key( senderAccountId.to_string() ); let consumeSendTransactionResult = await createNewConsumeTransaction( webClient, senderAccountId.to_string(), sendTransactionResult.created_note_ids ); await new Promise((r) => setTimeout(r, 20000)); await syncState(webClient); console.log("testNewSendTransactionWithRecallHeight finished"); } // Done async function testNewSwapTransaction() { console.log("testNewSwapTransaction started"); let webClient = await createMidenWebClient(); let walletAAccountId = await createNewWallet( webClient, "Private", true ); let walletBAccountId = await createNewWallet( webClient, "Private", true ); let offeredAssetFaucetId = await createNewFaucet( webClient, "Private", false, "DEN", "10", "1000000" ); let requestedAssetFaucetId = await createNewFaucet( webClient, "Private", false, "GAR", "10", "1000000" ); await syncState(webClient); await new Promise((r) => setTimeout(r, 20000)); await webClient.fetch_and_cache_account_auth_by_pub_key( offeredAssetFaucetId.to_string() ); let walletAMintTransactionResult = await createNewMintTransaction( webClient, walletAAccountId.to_string(), offeredAssetFaucetId.to_string(), "Public", "1000" ); await new Promise((r) => setTimeout(r, 20000)); await syncState(webClient); await webClient.fetch_and_cache_account_auth_by_pub_key( requestedAssetFaucetId.to_string() ); let walletBMintTransactionResult = await createNewMintTransaction( webClient, walletBAccountId.to_string(), requestedAssetFaucetId.to_string(), "Public", "1000" ); await new Promise((r) => setTimeout(r, 20000)); await syncState(webClient); await webClient.fetch_and_cache_account_auth_by_pub_key( walletAAccountId.to_string() ); let walletAConsumeTransactionResult = await createNewConsumeTransaction( webClient, walletAAccountId.to_string(), walletAMintTransactionResult.created_note_ids ); await new Promise((r) => setTimeout(r, 20000)); await syncState(webClient); await webClient.fetch_and_cache_account_auth_by_pub_key( walletBAccountId.to_string() ); let walletBConsumeTransactionResult = await createNewConsumeTransaction( webClient, walletBAccountId.to_string(), walletBMintTransactionResult.created_note_ids ); await new Promise((r) => setTimeout(r, 20000)); await syncState(webClient); await webClient.fetch_and_cache_account_auth_by_pub_key( walletAAccountId.to_string() ); let swapTransactionResult = await createNewSwapTransaction( webClient, walletAAccountId.to_string(), offeredAssetFaucetId.to_string(), "100", requestedAssetFaucetId.to_string(), "900", "Public" ); await new Promise((r) => setTimeout(r, 20000)); await syncState(webClient); await addTag(webClient, swapTransactionResult.payback_note_tag); await new Promise((r) => setTimeout(r, 20000)); await syncState(webClient); await webClient.fetch_and_cache_account_auth_by_pub_key( walletBAccountId.to_string() ); let walletBConsumeSwapTransactionResult = await createNewConsumeTransaction( webClient, walletBAccountId.to_string(), swapTransactionResult.expected_output_note_ids // TODO CHANGE ME ); await new Promise((r) => setTimeout(r, 20000)); await syncState(webClient); await webClient.fetch_and_cache_account_auth_by_pub_key( walletAAccountId.to_string() ); let walletAConsumeSwapTransactionResult = await createNewConsumeTransaction( webClient, walletAAccountId.to_string(), swapTransactionResult.expected_partial_note_ids // TODO CHANGE ME ); await new Promise((r) => setTimeout(r, 20000)); await syncState(webClient); console.log("testNewSwapTransaction finished"); } // Done async function testGetTransactions() { console.log("testGetTransactions started"); let webClient = await createMidenWebClient(); let walletAccount = await createNewWallet(webClient, "Private", true); let faucetAccount = await createNewFaucet( webClient, "Private", false, "DEN", "10", "1000000" ); await syncState(webClient); await new Promise((r) => setTimeout(r, 20000)); await webClient.fetch_and_cache_account_auth_by_pub_key( faucetAccount.to_string() ); let mintTransactionResult = await createNewMintTransaction( webClient, walletAccount.to_string(), faucetAccount.to_string(), "Private", "1000" ); await new Promise((r) => setTimeout(r, 20000)); await syncState(webClient); await webClient.fetch_and_cache_account_auth_by_pub_key( walletAccount.to_string() ); let consumeTransactionResult = await createNewConsumeTransaction( webClient, walletAccount.to_string(), mintTransactionResult.created_note_ids ); await new Promise((r) => setTimeout(r, 20000)); await syncState(webClient); await getTransactions(webClient); console.log("testGetTransactions finished"); } // Done async function testGetInputNotes() { console.log("testGetInputNotes started"); let webClient = await createMidenWebClient(); let targetAccountId = await createNewWallet(webClient, "Private", true); let faucetId = await createNewFaucet( webClient, "Private", false, "DEN", "10", "1000000" ); await syncState(webClient); await new Promise((r) => setTimeout(r, 20000)); await webClient.fetch_and_cache_account_auth_by_pub_key( faucetId.to_string() ); let mintTransactionResult = await createNewMintTransaction( webClient, targetAccountId.to_string(), faucetId.to_string(), "Private", "1000" ); await new Promise((r) => setTimeout(r, 20000)); await syncState(webClient); await webClient.fetch_and_cache_account_auth_by_pub_key( targetAccountId.to_string() ); let consumeTransactionResult = await createNewConsumeTransaction( webClient, targetAccountId.to_string(), mintTransactionResult.created_note_ids ); await new Promise((r) => setTimeout(r, 20000)); await syncState(webClient); await getInputNotes(webClient); console.log("testGetInputNotes finished"); } // Done async function testGetInputNote() { console.log("testGetInputNote started"); let webClient = await createMidenWebClient(); let targetAccountId = await createNewWallet(webClient, "Private", true); let faucetId = await createNewFaucet( webClient, "Private", false, "DEN", "10", "1000000" ); await syncState(webClient); await new Promise((r) => setTimeout(r, 20000)); await webClient.fetch_and_cache_account_auth_by_pub_key( faucetId.to_string() ); let mintTransactionResult = await createNewMintTransaction( webClient, targetAccountId.to_string(), faucetId.to_string(), "Private", "1000" ); await new Promise((r) => setTimeout(r, 20000)); await syncState(webClient); await webClient.fetch_and_cache_account_auth_by_pub_key( targetAccountId.to_string() ); let consumeTransactionResult = await createNewConsumeTransaction( webClient, targetAccountId.to_string(), mintTransactionResult.created_note_ids ); await new Promise((r) => setTimeout(r, 20000)); await syncState(webClient); await getInputNote( webClient, mintTransactionResult.created_note_ids[0] ); console.log("testGetInputNote finished"); } // Done async function testGetNote() { console.log("testGetNote started"); let webClient = await createMidenWebClient(); // Create accounts and sync let regularAccountTemplate = createBasicMutableAccountTemplate("Local"); let fungibleFaucetAccountTemplate = createFungibleFaucetAccountTemplate( "DEN", "10", "1000000", "Local" ); let regularAccountId = await createNewAccount( webClient, regularAccountTemplate ); let faucetId = await createNewAccount( webClient, fungibleFaucetAccountTemplate ); await syncState(webClient); await new Promise((r) => setTimeout(r, 10000)); // Create mint transaction and sync let transactionTemplate = createMintTransactionTemplate( regularAccountId, faucetId, "1000", "Private" ); let createTransactionResult = await createTransaction( webClient, transactionTemplate ); await new Promise((r) => setTimeout(r, 10000)); await syncState(webClient); await getInputNote( webClient, createTransactionResult.created_note_ids[0] ); console.log("testGetNote finished"); } // Done async function testGetOutputNotes() { console.log("testGetOutputNotes started"); let webClient = await createMidenWebClient(); let targetAccountId = await createNewWallet(webClient, "Private", true); let faucetId = await createNewFaucet( webClient, "Private", false, "DEN", "10", "1000000" ); await syncState(webClient); await new Promise((r) => setTimeout(r, 20000)); await webClient.fetch_and_cache_account_auth_by_pub_key( faucetId.to_string() ); let mintTransactionResult = await createNewMintTransaction( webClient, targetAccountId.to_string(), faucetId.to_string(), "Private", "1000" ); await new Promise((r) => setTimeout(r, 20000)); await syncState(webClient); await webClient.fetch_and_cache_account_auth_by_pub_key( targetAccountId.to_string() ); let consumeTransactionResult = await createNewConsumeTransaction( webClient, targetAccountId.to_string(), mintTransactionResult.created_note_ids ); await new Promise((r) => setTimeout(r, 20000)); await syncState(webClient); await getOutputNotes(webClient); console.log("testGetOutputNotes finished"); } // Done async function testGetOutputNote() { console.log("testGetOutputNote started"); let webClient = await createMidenWebClient(); let targetAccountId = await createNewWallet(webClient, "Private", true); let faucetId = await createNewFaucet( webClient, "Private", false, "DEN", "10", "1000000" ); await syncState(webClient); await new Promise((r) => setTimeout(r, 20000)); await webClient.fetch_and_cache_account_auth_by_pub_key( faucetId.to_string() ); let mintTransactionResult = await createNewMintTransaction( webClient, targetAccountId.to_string(), faucetId.to_string(), "Private", "1000" ); await new Promise((r) => setTimeout(r, 20000)); await syncState(webClient); await webClient.fetch_and_cache_account_auth_by_pub_key( targetAccountId.to_string() ); let consumeTransactionResult = await createNewConsumeTransaction( webClient, targetAccountId.to_string(), mintTransactionResult.created_note_ids ); await new Promise((r) => setTimeout(r, 20000)); await syncState(webClient); await getOutputNote( webClient, mintTransactionResult.created_note_ids[0] ); console.log("testGetOutputNote finished"); } // Done async function testExportNote() { console.log("testExportNote started"); let webClient = await createMidenWebClient(); // let senderAccountId = await createNewWallet(webClient, "Private", true); let faucetId = await createNewFaucet( webClient, "Private", false, "DEN", "10", "1000000" ); await syncState(webClient); await new Promise((r) => setTimeout(r, 20000)); await webClient.fetch_and_cache_account_auth_by_pub_key(faucetId); let mintTransactionResult = await createNewMintTransaction( webClient, "0x9186b96f559e852f", // Insert target account id here faucetId, "Private", "1000" ); await new Promise((r) => setTimeout(r, 20000)); await syncState(webClient); let result = await exportNote( webClient, mintTransactionResult.created_note_ids[0] ); const blob = new Blob([result], { type: "application/octet-stream" }); // Create a URL for the Blob const url = URL.createObjectURL(blob); // Create a temporary anchor element const a = document.createElement("a"); a.href = url; a.download = "exportNoteTest.mno"; // Specify the file name // Append the anchor to the document document.body.appendChild(a); // Programmatically click the anchor to trigger the download a.click(); // Remove the anchor from the document document.body.removeChild(a); // Revoke the object URL to free up resources URL.revokeObjectURL(url); console.log("testExportNote finished"); } // Done async function testImportInputNote() { console.log("testImportInputNote started"); let webClient = await createMidenWebClient(); let walletAccount = await createNewWallet(webClient, "Private", true); function setupNoteFileInputListener(webClient, targetAccountId) { document .getElementById("noteFileInput") .addEventListener("change", async function (event) { const file = event.target.files[0]; if (file) { const reader = new FileReader(); reader.onload = async function (e) { const arrayBuffer = e.target.result; const byteArray = new Uint8Array(arrayBuffer); console.log(byteArray); // Now you can work with the bytes let result = await importInputNote( webClient, byteArray, false ); console.log(result); // Log the result of the import process await webClient.fetch_and_cache_account_auth_by_pub_key( targetAccountId ); let consumeTransactionResult = await createNewConsumeTransaction( webClient, "0x98f63aaa54c58c14", // targetAccountId, [result] ); await new Promise((r) => setTimeout(r, 20000)); await syncState(webClient); console.log("testImportInputNote finished"); }; reader.readAsArrayBuffer(file); } }); } setupNoteFileInputListener(webClient, walletAccount); } // This test is modeled after this test in the Miden codebase: // https://github.com/0xPolygonMiden/miden-client/blob/2f8707faeded3725a1d732310f616e3e2170a50d/tests/integration/custom_transactions_tests.rs#L54 async function testCustomTransaction() { console.log("testCustomTransaction started"); // Creating Wallet and Faucet let webClient = await createMidenWebClient(); let walletId = await createNewWallet(webClient, "Private", false); let faucetId = await createNewFaucet( webClient, "Private", false, "DEN", "10", "1000000" ); await syncState(webClient); // Creating Custom Note which needs the following: // - Note Assets // - Note Metadata // - Note Recipient // Creating NOTE_ARGS let felt1 = new Felt(BigInt(9)); let felt2 = new Felt(BigInt(12)); let felt3 = new Felt(BigInt(18)); let felt4 = new Felt(BigInt(3)); let felt5 = new Felt(BigInt(3)); let felt6 = new Felt(BigInt(18)); let felt7 = new Felt(BigInt(12)); let felt8 = new Felt(BigInt(9)); let noteArgs = [felt1, felt2, felt3, felt4, felt5, felt6, felt7, felt8]; let feltArray = new FeltArray(); noteArgs.forEach((felt) => feltArray.append(felt)); let noteAssets = new NoteAssets([ new FungibleAsset(faucetId, BigInt(10)), ]); let noteMetadata = new NoteMetadata( faucetId, NoteType.private(), NoteTag.from_account_id(walletId, NoteExecutionMode.new_local()), NoteExecutionHint.none(), null ); let expectedNoteArgs = noteArgs.map((felt) => felt.as_int()); let memAddress = "1000"; let memAddress2 = "1004"; let expectedNoteArg1 = expectedNoteArgs.slice(0, 4).join("."); let expectedNoteArg2 = expectedNoteArgs.slice(4, 8).join("."); let note_script = ` # Custom P2ID note script # # This note script asserts that the note args are exactly the same as passed # (currently defined as {expected_note_arg_1} and {expected_note_arg_2}). # Since the args are too big to fit in a single note arg, we provide them via advice inputs and # address them via their commitment (noted as NOTE_ARG) # This note script is based off of the P2ID note script because notes currently need to have # assets, otherwise it could have been boiled down to the assert. use.miden::account use.miden::note use.miden::contracts::wallets::basic->wallet use.std::mem proc.add_note_assets_to_account push.0 exec.note::get_assets # => [num_of_assets, 0 = ptr, ...] # compute the pointer at which we should stop iterating mul.4 dup.1 add # => [end_ptr, ptr, ...] # pad the stack and move the pointer to the top padw movup.5 # => [ptr, 0, 0, 0, 0, end_ptr, ...] # compute the loop latch dup dup.6 neq # => [latch, ptr, 0, 0, 0, 0, end_ptr, ...] while.true # => [ptr, 0, 0, 0, 0, end_ptr, ...] # save the pointer so that we can use it later dup movdn.5 # => [ptr, 0, 0, 0, 0, ptr, end_ptr, ...] # load the asset mem_loadw # => [ASSET, ptr, end_ptr, ...] # pad the stack before call padw swapw padw padw swapdw # => [ASSET, pad(12), ptr, end_ptr, ...] # add asset to the account call.wallet::receive_asset # => [pad(16), ptr, end_ptr, ...] # clean the stack after call dropw dropw dropw # => [0, 0, 0, 0, ptr, end_ptr, ...] # increment the pointer and compare it to the end_ptr movup.4 add.4 dup dup.6 neq # => [latch, ptr+4, ASSET, end_ptr, ...] end # clear the stack drop dropw drop end begin # push data from the advice map into the advice stack adv.push_mapval # => [NOTE_ARG] # memory address where to write the data push.${memAddress} # => [target_mem_addr, NOTE_ARG_COMMITMENT] # number of words push.2 # => [number_of_words, target_mem_addr, NOTE_ARG_COMMITMENT] exec.mem::pipe_preimage_to_memory # => [target_mem_addr'] dropw # => [] # read first word push.${memAddress} # => [data_mem_address] mem_loadw # => [NOTE_ARG_1] push.${expectedNoteArg1} assert_eqw.err=101 # => [] # read second word push.${memAddress2} # => [data_mem_address_2] mem_loadw # => [NOTE_ARG_2] push.${expectedNoteArg2} assert_eqw.err=102 # => [] # store the note inputs to memory starting at address 0 push.0 exec.note::get_inputs # => [num_inputs, inputs_ptr] # make sure the number of inputs is 1 eq.2 assert.err=103 # => [inputs_ptr] # read the target account id from the note inputs mem_load # => [target_account_id_prefix] exec.account::get_id swap drop # => [account_id_prefix, target_account_id_prefix, ...] # ensure account_id = target_account_id, fails otherwise assert_eq.err=104 # => [...] exec.add_note_assets_to_account # => [...] end `; let compiledNoteScript = await webClient.compile_note_script(note_script); let noteInputs = new NoteInputs(new FeltArray([walletId.to_felt()])); let noteRecipient = new NoteRecipient(compiledNoteScript, noteInputs); let note = new Note(noteAssets, noteMetadata, noteRecipient); // Creating First Custom Transaction Request to Mint the Custom Note let transaction_request = new TransactionRequestBuilder() .with_own_output_notes(new OutputNotesArray([OutputNote.full(note)])) .build(); // Execute and Submit Transaction await webClient.fetch_and_cache_account_auth_by_pub_key( faucetId.to_string() ); let transaction_result = await webClient.new_transaction( faucetId, transaction_request ); await webClient.submit_transaction(transaction_result); await new Promise((r) => setTimeout(r, 10000)); await webClient.sync_state(); // Just like in the miden test, you can modify this script to get the execution to fail // by modifying the assert let tx_script = ` use.miden::contracts::auth::basic->auth_tx use.miden::kernels::tx::prologue use.miden::kernels::tx::memory begin push.0 push.0 # => [0, 0] assert_eq call.auth_tx::auth_tx_rpo_falcon512 end `; // Creating Second Custom Transaction Request to Consume Custom Note // with Invalid/Valid Transaction Script let account_auth = await webClient.get_account_auth(walletId); let public_key = account_auth.get_rpo_falcon_512_public_key_as_word(); let secret_key = account_auth.get_rpo_falcon_512_secret_key_as_felts(); let transcription_script_input_pair_array = new TransactionScriptInputPairArray([ new TransactionScriptInputPair(public_key, secret_key), ]); let transaction_script = await webClient.compile_tx_script( tx_script, transcription_script_input_pair_array ); let note_id = note.id(); let note_args_commitment = Rpo256.hash_elements(feltArray); // gets consumed by NoteIdAndArgs let note_id_and_args = new NoteIdAndArgs( note_id, note_args_commitment.to_word() ); let note_id_and_args_array = new NoteIdAndArgsArray([note_id_and_args]); let advice_map = new AdviceMap(); let note_args_commitment_2 = Rpo256.hash_elements(feltArray); advice_map.insert(note_args_commitment_2, feltArray); let transaction_request_2 = new TransactionRequest() .with_authenticated_input_notes(note_id_and_args_array) .with_custom_script(transaction_script) .extend_advice_map(advice_map); // Execute and Submit Transaction await webClient.fetch_and_cache_account_auth_by_pub_key( walletId.to_string() ); let transaction_result_2 = await webClient.new_transaction( walletId, transaction_request_2 ); await webClient.submit_transaction(transaction_result_2); await new Promise((r) => setTimeout(r, 10000)); await webClient.sync_state(); console.log("testCustomTransaction finished"); } await testCreateNewWallet(); // await testCreateNewFaucet(); // await testGetAccounts(); // await testGetAccount(); // await testNewMintTransaction(); // await testNewConsumeTransaction(); // await testNewSendTransaction(); // await testNewSendTransactionWithRecallHeight(); // await testNewSwapTransaction(); // await testGetTransactions(); // await testGetInputNotes(); // await testGetInputNote(); // await testGetOutputNotes(); // await testGetOutputNote(); // await testExportNote(); // await testImportInputNote(); // await testCustomTransaction(); </script> </body> </html>