diff --git a/Cargo.lock b/Cargo.lock index 690a9abf22..daf2fdc4a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1517,6 +1517,7 @@ dependencies = [ "napi-derive", "num_cpus", "rand", + "signal-hook", ] [[package]] @@ -1586,7 +1587,7 @@ dependencies = [ [[package]] name = "jubjub" version = "0.9.0" -source = "git+https://github.com/iron-fish/jubjub.git?branch=blstrs#a1a0c2ed69eec4d5d5e87842e2a40849f7fa4633" +source = "git+https://github.com/iron-fish/jubjub.git?branch=blstrs#531157cfa7b81ade207e819ef50c563843b10e30" dependencies = [ "bitvec", "blst", @@ -2510,6 +2511,25 @@ dependencies = [ "digest 0.10.6", ] +[[package]] +name = "signal-hook" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + [[package]] name = "signature" version = "2.0.0" diff --git a/Cargo.toml b/Cargo.toml index 7ceea9ac2a..955ccc7d88 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,4 +15,4 @@ homepage = "https://ironfish.network/" repository = "https://github.com/iron-fish/ironfish" [profile.release] -debug = true \ No newline at end of file +debug = true diff --git a/config/eslint-config-ironfish/index.js b/config/eslint-config-ironfish/index.js index 978bcb75d7..d0747feae8 100644 --- a/config/eslint-config-ironfish/index.js +++ b/config/eslint-config-ironfish/index.js @@ -68,6 +68,7 @@ module.exports = { rules: { 'ironfish/no-vague-imports': 'error', 'ironfish/no-buffer-cmp': 'error', + 'ironfish/no-promise-race': 'error', // Catches expressions that aren't assigned '@typescript-eslint/no-unused-expressions': [ diff --git a/config/eslint-plugin-ironfish/index.js b/config/eslint-plugin-ironfish/index.js index 0ff7d24290..8b189ee5b5 100644 --- a/config/eslint-plugin-ironfish/index.js +++ b/config/eslint-plugin-ironfish/index.js @@ -42,4 +42,19 @@ module.exports.rules = { }; }, }, + "no-promise-race": { + create(context) { + return { + MemberExpression: function (node) { + if (node.object.name === 'Promise' && node.property.name === 'race') { + context.report({ + node, + message: + "Promise.race leaks memory. You can work around it by using PromiseUtils.split to pass resolve/reject to other Promises. See https://github.com/nodejs/node/issues/17469#issuecomment-685216777 for more details.", + }); + } + }, + }; + }, + }, }; diff --git a/ironfish-cli/Dockerfile b/ironfish-cli/Dockerfile index 7f49291dd0..a7e3336a02 100644 --- a/ironfish-cli/Dockerfile +++ b/ironfish-cli/Dockerfile @@ -1,4 +1,4 @@ -FROM node:20-bookworm as build +FROM node:20-bookworm AS build ENV PATH="/root/.cargo/bin:${PATH}" RUN \ diff --git a/ironfish-cli/STYLE_GUIDE.md b/ironfish-cli/STYLE_GUIDE.md index 39fa4d2801..80bbd93412 100644 --- a/ironfish-cli/STYLE_GUIDE.md +++ b/ironfish-cli/STYLE_GUIDE.md @@ -69,6 +69,20 @@ However, if prompting is required to complete a command, this means the user wil ## Output +When designing the output for a command, commands should output human readable output and not machine readable output. This means you should use components under the `ui` module such as `card`, `table`, or normal logs. It's fine if you only display a simplified version of the output. If the user needs the full data in machine readable format they can use the `--json` flag. + +You can categorize commands in a few ways, and you will design their output differently depending on the purpose of the command. You have output commands (status, chain:blocks:info, wallet:transactions), operation commands (stop, wallet:rename). + +### JSON Output + +We want to support JSON output in all data commands. This will allow developers to use our CLI for basic automating purposes avoiding the need to set up an HTTP client. + +If a command returns data it should have `static enableJsonFlag = true` and return an object with the JSON data in the command. The output JSON will automatically be colorized. See more here, https://oclif.io/docs/json/ + +It's OK to both return an object and use `log` even if JSON is not enabled. If you need custom logic and don't want to rely on returning the JSON, you can use `jsonEnabled()` and the `ui.json()` component to manually log colorized JSON. + +This is not necessary for operation commands that perform actions and quit such as `wallet:rename`. + ### Progress Many commands need to run long running operations. The CLI should not look like it's unresponsive. For example, `ironfish wallet:post` posts a transaction and optionally sends it to the network: diff --git a/ironfish-cli/bin/run b/ironfish-cli/bin/run index 485f409e80..3b9901180c 100755 --- a/ironfish-cli/bin/run +++ b/ironfish-cli/bin/run @@ -24,7 +24,4 @@ if (Number(process.versions.node.split('.')[0]) < MIN_NODE_VERSION) { process.exit(1) } -require('@oclif/core') - .run() - .then(require('@oclif/core/flush')) - .catch(require('@oclif/core/handle')) +require('@oclif/core').execute({ dir: __dirname }) diff --git a/ironfish-cli/package.json b/ironfish-cli/package.json index 2eb1b8e7eb..a33ae829c6 100644 --- a/ironfish-cli/package.json +++ b/ironfish-cli/package.json @@ -1,6 +1,6 @@ { "name": "ironfish", - "version": "2.4.1", + "version": "2.5.0", "description": "CLI for running and interacting with an Iron Fish node", "author": "Iron Fish (https://ironfish.network)", "main": "build/src/index.js", @@ -23,8 +23,9 @@ "node": ">=18" }, "devDependencies": { - "@oclif/test": "2.1.0", + "@oclif/test": "4.0.4", "@types/blessed": "0.1.17", + "@types/cli-progress": "3.11.6", "@types/inquirer": "8.2.5", "@types/node": "18.11.16", "@types/tar": "6.1.1", @@ -34,7 +35,7 @@ "eslint-plugin-deprecation": "2.0.0", "jest": "29.7.0", "jest-jasmine2": "29.7.0", - "oclif": "3.7.2", + "oclif": "4.14.0", "rimraf": "^3.0.2", "ts-jest": "29.1.1", "tsc-watch": "4.2.9", @@ -58,15 +59,17 @@ "oclif:version": "oclif readme && git add README.md" }, "dependencies": { - "@ironfish/rust-nodejs": "2.4.0", - "@ironfish/sdk": "2.4.1", - "@oclif/core": "3.27.0", - "@oclif/plugin-autocomplete": "1.3.10", - "@oclif/plugin-help": "5.1.12", - "@oclif/plugin-not-found": "2.3.1", - "@oclif/plugin-warn-if-update-available": "2.0.40", + "@ironfish/rust-nodejs": "2.5.0", + "@ironfish/sdk": "2.5.0", + "@ledgerhq/hw-transport-node-hid": "6.29.1", + "@oclif/core": "4.0.11", + "@oclif/plugin-autocomplete": "3.1.6", + "@oclif/plugin-help": "6.2.5", + "@oclif/plugin-not-found": "3.2.10", + "@oclif/plugin-warn-if-update-available": "3.1.8", "@types/keccak": "3.0.4", "@types/tar": "6.1.1", + "@zondax/ledger-ironfish": "0.1.2", "axios": "1.7.2", "bech32": "2.0.0", "blessed": "0.1.81", @@ -77,6 +80,8 @@ "inquirer": "8.2.5", "json-colorizer": "2.2.2", "keccak": "3.0.4", + "natural-orderby": "3.0.2", + "string-width": "4.2.3", "supports-hyperlinks": "2.2.0", "tar": "6.1.11", "uuid": "8.3.2" @@ -99,6 +104,12 @@ "topics": { "wallet:scanning": { "description": "Turn on or off scanning for accounts" + }, + "chain:blocks": { + "description": "commands to look at blocks" + }, + "chain:assets": { + "description": "commands to look at assets" } } }, diff --git a/ironfish-cli/scripts/build-docker.sh b/ironfish-cli/scripts/build-docker.sh index 803cf0f8c3..bc59dce58d 100755 --- a/ironfish-cli/scripts/build-docker.sh +++ b/ironfish-cli/scripts/build-docker.sh @@ -3,8 +3,14 @@ set -euo pipefail cd "$(dirname "$0")/../.." cat .gitignore - > .dockerignore < | void + abstract start(): Promise | void - async run(): Promise { + async run(): Promise { try { - await this.start() + return await this.start() } catch (error: unknown) { if (hasUserResponseError(error)) { this.log(error.codeMessage) @@ -103,16 +115,15 @@ export abstract class IronfishCommand extends Command { } else { throw error } + } finally { + this.client?.close() } this.exit(0) } async init(): Promise { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any - const commandClass = this.constructor as any - // eslint-disable-next-line @typescript-eslint/no-unsafe-argument - const { flags } = await this.parse(commandClass) + const { flags } = await this.parse(this.ctor) // Get the flags from the flag object which is unknown const dataDirFlag = getFlag(flags, DataDirFlagKey) @@ -220,6 +231,19 @@ export abstract class IronfishCommand extends Command { closeFromSignal(signal: NodeJS.Signals): Promise { throw new Error(`Not implemented closeFromSignal: ${signal}`) } + + // Override the built-in logJson method to implement our own colorizer that + // works with default terminal colors instead of requiring a theme to be + // configured. + logJson(json: unknown): void { + ux.stdout(ui.json(json)) + } + + async connectRpc(forceLocal = false, forceRemote = false): Promise { + const client = await this.sdk.connectRpc(forceLocal, forceRemote) + this.client = client + return client + } } function getFlag(flags: unknown, flag: FLAGS): unknown { diff --git a/ironfish-cli/src/commands/blocks/show.ts b/ironfish-cli/src/commands/blocks/show.ts deleted file mode 100644 index 88cb579391..0000000000 --- a/ironfish-cli/src/commands/blocks/show.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import { Args } from '@oclif/core' -import { IronfishCommand } from '../../command' -import { LocalFlags } from '../../flags' - -export default class ShowBlock extends IronfishCommand { - static description = 'Show the block header of a requested hash or sequence' - - static args = { - search: Args.string({ - required: true, - description: 'The hash or sequence of the block to look at', - }), - } - - static flags = { - ...LocalFlags, - } - - async start(): Promise { - const { args } = await this.parse(ShowBlock) - const { search } = args - - const client = await this.sdk.connectRpc() - const data = await client.chain.getBlock({ search }) - - this.log(JSON.stringify(data.content, undefined, ' ')) - } -} diff --git a/ironfish-cli/src/commands/browse.ts b/ironfish-cli/src/commands/browse.ts index 6270b6c54a..5faa6bcbad 100644 --- a/ironfish-cli/src/commands/browse.ts +++ b/ironfish-cli/src/commands/browse.ts @@ -4,15 +4,12 @@ import { Platform } from '@ironfish/sdk' import { Flags } from '@oclif/core' import { IronfishCommand } from '../command' -import { ConfigFlag, ConfigFlagKey, DataDirFlag, DataDirFlagKey } from '../flags' import { PlatformUtils } from '../utils' export class BrowseCommand extends IronfishCommand { static description = `Browse to your data directory` static flags = { - [ConfigFlagKey]: ConfigFlag, - [DataDirFlagKey]: DataDirFlag, cd: Flags.boolean({ default: false, description: 'print the directory where the data directory is', diff --git a/ironfish-cli/src/commands/chain/asset.ts b/ironfish-cli/src/commands/chain/asset.ts deleted file mode 100644 index 565f34f328..0000000000 --- a/ironfish-cli/src/commands/chain/asset.ts +++ /dev/null @@ -1,38 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import { BufferUtils } from '@ironfish/sdk' -import { Args } from '@oclif/core' -import { IronfishCommand } from '../../command' -import { RemoteFlags } from '../../flags' - -export default class Asset extends IronfishCommand { - static description = 'Get the asset info' - - static args = { - id: Args.string({ - required: true, - description: 'The identifier of the asset', - }), - } - - static flags = { - ...RemoteFlags, - } - - async start(): Promise { - const { args } = await this.parse(Asset) - const { id: assetId } = args - - const client = await this.sdk.connectRpc() - const data = await client.chain.getAsset({ id: assetId }) - - this.log(`Name: ${BufferUtils.toHuman(Buffer.from(data.content.name, 'hex'))}`) - this.log(`Metadata: ${BufferUtils.toHuman(Buffer.from(data.content.metadata, 'hex'))}`) - this.log(`Creator: ${data.content.creator}`) - this.log(`Owner: ${data.content.owner}`) - this.log(`Supply: ${data.content.supply ?? 'N/A'}`) - this.log(`Identifier: ${data.content.id}`) - this.log(`Transaction Created: ${data.content.createdTransactionHash}`) - } -} diff --git a/ironfish-cli/src/commands/chain/assets/info.ts b/ironfish-cli/src/commands/chain/assets/info.ts new file mode 100644 index 0000000000..354e9e40a7 --- /dev/null +++ b/ironfish-cli/src/commands/chain/assets/info.ts @@ -0,0 +1,47 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +import { BufferUtils } from '@ironfish/sdk' +import { Args } from '@oclif/core' +import { IronfishCommand } from '../../../command' +import { ColorFlag, ColorFlagKey, RemoteFlags } from '../../../flags' +import * as ui from '../../../ui' + +export default class AssetInfo extends IronfishCommand { + static description = 'show asset information' + static enableJsonFlag = true + + static args = { + id: Args.string({ + required: true, + description: 'The identifier of the asset', + }), + } + + static flags = { + ...RemoteFlags, + [ColorFlagKey]: ColorFlag, + } + + async start(): Promise { + const { args } = await this.parse(AssetInfo) + const { id: assetId } = args + + const client = await this.connectRpc() + const data = await client.chain.getAsset({ id: assetId }) + + this.log( + ui.card({ + Name: BufferUtils.toHuman(Buffer.from(data.content.name, 'hex')), + Metadata: BufferUtils.toHuman(Buffer.from(data.content.metadata, 'hex')), + Creator: data.content.creator, + Owner: data.content.owner, + Supply: data.content.supply ?? 'N/A', + Identifier: data.content.id, + 'Transaction Created': data.content.createdTransactionHash, + }), + ) + + return data.content + } +} diff --git a/ironfish-cli/src/commands/chain/benchmark.ts b/ironfish-cli/src/commands/chain/benchmark.ts index 7c0a15237f..46848f8ffc 100644 --- a/ironfish-cli/src/commands/chain/benchmark.ts +++ b/ironfish-cli/src/commands/chain/benchmark.ts @@ -7,8 +7,8 @@ import blessed from 'blessed' import fs from 'fs/promises' import path from 'path' import { IronfishCommand } from '../../command' -import { LocalFlags } from '../../flags' import { IronfishCliPKG } from '../../package' +import * as ui from '../../ui' export default class Benchmark extends IronfishCommand { static description = @@ -17,7 +17,6 @@ export default class Benchmark extends IronfishCommand { static hidden = true static flags = { - ...LocalFlags, targetdir: Flags.string({ char: 't', required: false, @@ -78,7 +77,7 @@ export default class Benchmark extends IronfishCommand { return this.error(`Chain must have at least ${blocks} blocks`) } - if (!tempNode.chain.head.hash.equals(startingHeader?.hash)) { + if (!tempNode.chain.head.hash.equals(startingHeader.hash)) { return this.error(`The two chains do not match at sequence ${startingSequence}`) } @@ -158,11 +157,12 @@ function renderStatus( totalNotes: number, sequence?: number, ): string { - return `\ -Current Block ${sequence ? sequence.toString() : '-'} -Blocks Processed ${totalBlocks.toString()} -Blocks/sec ${totalMs ? (totalBlocks / (totalMs / 1000)).toFixed(2) : 0} -Transactions/sec ${totalMs ? (totalTransactions / (totalMs / 1000)).toFixed(2) : 0} -Spends/sec ${totalMs ? (totalSpends / (totalMs / 1000)).toFixed(2) : 0} -Notes/sec ${totalMs ? (totalNotes / (totalMs / 1000)).toFixed(2) : 0}` + return ui.card({ + 'Current Block': sequence ? sequence.toString() : '-', + 'Blocks Processed': totalBlocks.toString(), + 'Blocks/sec': totalMs ? (totalBlocks / (totalMs / 1000)).toFixed(2) : 0, + 'Transactions/sec': totalMs ? (totalTransactions / (totalMs / 1000)).toFixed(2) : 0, + 'Spends/sec': totalMs ? (totalSpends / (totalMs / 1000)).toFixed(2) : 0, + 'Notes/sec': totalMs ? (totalNotes / (totalMs / 1000)).toFixed(2) : 0, + }) } diff --git a/ironfish-cli/src/commands/chain/blocks/info.ts b/ironfish-cli/src/commands/chain/blocks/info.ts new file mode 100644 index 0000000000..b3bdfecc7e --- /dev/null +++ b/ironfish-cli/src/commands/chain/blocks/info.ts @@ -0,0 +1,52 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +import { BufferUtils, CurrencyUtils, TimeUtils } from '@ironfish/sdk' +import { Args } from '@oclif/core' +import { IronfishCommand } from '../../../command' +import { ColorFlag, ColorFlagKey } from '../../../flags' +import * as ui from '../../../ui' + +export default class BlockInfo extends IronfishCommand { + static description = 'Show the block header of a requested hash or sequence' + static enableJsonFlag = true + + static args = { + search: Args.string({ + required: true, + description: 'The hash or sequence of the block to look at', + }), + } + + static flags = { + [ColorFlagKey]: ColorFlag, + } + + async start(): Promise { + const { args } = await this.parse(BlockInfo) + const { search } = args + + const client = await this.connectRpc() + const data = await client.chain.getBlock({ search }) + const blockData = data.content + + const miningReward = blockData.block.transactions[0] + + this.log( + ui.card({ + Hash: blockData.block.hash, + Confirmed: blockData.metadata.confirmed, + Fork: !blockData.metadata.main, + Sequence: blockData.block.sequence, + 'Previous Block Hash': blockData.block.previousBlockHash, + Difficulty: blockData.block.difficulty, + Timestamp: TimeUtils.renderString(blockData.block.timestamp), + Graffiti: BufferUtils.toHuman(Buffer.from(blockData.block.graffiti, 'hex')), + 'Mining Reward': CurrencyUtils.render((miningReward.fee * -1).toString(), true), + 'Transaction Count': blockData.block.transactions.length, + }), + ) + + return blockData + } +} diff --git a/ironfish-cli/src/commands/chain/broadcast.ts b/ironfish-cli/src/commands/chain/broadcast.ts index f862086893..9d2bb42032 100644 --- a/ironfish-cli/src/commands/chain/broadcast.ts +++ b/ironfish-cli/src/commands/chain/broadcast.ts @@ -6,7 +6,7 @@ import { IronfishCommand } from '../../command' import { RemoteFlags } from '../../flags' export class BroadcastCommand extends IronfishCommand { - static description = `Broadcast a transaction to the network` + static description = 'broadcast a transaction to the network' static flags = { ...RemoteFlags, @@ -24,7 +24,7 @@ export class BroadcastCommand extends IronfishCommand { const { transaction } = args ux.action.start(`Broadcasting transaction`) - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() const response = await client.chain.broadcastTransaction({ transaction }) if (response.content) { ux.action.stop(`Transaction broadcasted: ${response.content.hash}`) diff --git a/ironfish-cli/src/commands/chain/download.ts b/ironfish-cli/src/commands/chain/download.ts index fa1062e858..1ae08d936d 100644 --- a/ironfish-cli/src/commands/chain/download.ts +++ b/ironfish-cli/src/commands/chain/download.ts @@ -5,17 +5,13 @@ import { ErrorUtils, FileUtils, NodeUtils } from '@ironfish/sdk' import { Flags, ux } from '@oclif/core' import fsAsync from 'fs/promises' import { IronfishCommand } from '../../command' -import { LocalFlags } from '../../flags' import { DownloadedSnapshot, getDefaultManifestUrl, SnapshotDownloader } from '../../snapshot' import { confirmOrQuit, ProgressBar, ProgressBarPresets } from '../../ui' export default class Download extends IronfishCommand { - static hidden = false - - static description = `Download and import a chain snapshot` + static description = 'download the chain' static flags = { - ...LocalFlags, manifestUrl: Flags.string({ char: 'm', description: 'Manifest url to download snapshot from', diff --git a/ironfish-cli/src/commands/chain/export.ts b/ironfish-cli/src/commands/chain/export.ts index 4d4618d7ec..129d25aaed 100644 --- a/ironfish-cli/src/commands/chain/export.ts +++ b/ironfish-cli/src/commands/chain/export.ts @@ -9,7 +9,7 @@ import { RemoteFlags } from '../../flags' import { ProgressBar } from '../../ui' export default class Export extends IronfishCommand { - static description = 'Export part of the chain database to JSON' + static description = 'export the chain to a file' static flags = { ...RemoteFlags, @@ -41,7 +41,7 @@ export default class Export extends IronfishCommand { const exportPath = this.sdk.fileSystem.join(exportDir, 'data.json') - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() const stream = client.chain.exportChainStream({ start: args.start, diff --git a/ironfish-cli/src/commands/chain/forks.ts b/ironfish-cli/src/commands/chain/forks.ts index a682db74d1..1b1b0fa375 100644 --- a/ironfish-cli/src/commands/chain/forks.ts +++ b/ironfish-cli/src/commands/chain/forks.ts @@ -8,7 +8,7 @@ import { RemoteFlags } from '../../flags' import { GossipForkCounter } from '../../utils/gossipForkCounter' export default class ForksCommand extends IronfishCommand { - static description = 'Try to detect forks that are being mined' + static description = 'detect forks that are being mined' static flags = { ...RemoteFlags, diff --git a/ironfish-cli/src/commands/chain/genesisadd.ts b/ironfish-cli/src/commands/chain/genesisadd.ts index 8322822450..12767c0053 100644 --- a/ironfish-cli/src/commands/chain/genesisadd.ts +++ b/ironfish-cli/src/commands/chain/genesisadd.ts @@ -10,17 +10,15 @@ import { IJSON, isValidPublicAddress, } from '@ironfish/sdk' -import { Flags, ux } from '@oclif/core' +import { Flags } from '@oclif/core' import fs from 'fs/promises' import { IronfishCommand } from '../../command' -import { LocalFlags } from '../../flags' -import { confirmOrQuit } from '../../ui' +import { confirmOrQuit, table, TableColumns } from '../../ui' export default class GenesisAddCommand extends IronfishCommand { static hidden = true static flags = { - ...LocalFlags, account: Flags.string({ char: 'a', required: true, @@ -80,7 +78,7 @@ export default class GenesisAddCommand extends IronfishCommand { // Log genesis block info this.log(`Genesis block will be modified with the following values in a new transaction:`) this.log(`Allocations:`) - const columns: ux.Table.table.Columns = { + const columns: TableColumns = { identity: { header: 'ADDRESS', get: (row: GenesisBlockAllocation) => row.publicAddress, @@ -97,7 +95,7 @@ export default class GenesisAddCommand extends IronfishCommand { }, } - ux.table(allocations, columns, { + table(allocations, columns, { printLine: this.log.bind(this), }) diff --git a/ironfish-cli/src/commands/chain/genesisblock.ts b/ironfish-cli/src/commands/chain/genesisblock.ts index 994277535e..f350a2a36f 100644 --- a/ironfish-cli/src/commands/chain/genesisblock.ts +++ b/ironfish-cli/src/commands/chain/genesisblock.ts @@ -12,11 +12,10 @@ import { makeGenesisBlock, Target, } from '@ironfish/sdk' -import { Flags, ux } from '@oclif/core' +import { Flags } from '@oclif/core' import fs from 'fs/promises' import { IronfishCommand } from '../../command' -import { LocalFlags } from '../../flags' -import { confirmOrQuit } from '../../ui' +import { confirmOrQuit, table, TableColumns } from '../../ui' export default class GenesisBlockCommand extends IronfishCommand { static description = 'Create and serialize a genesis block' @@ -24,7 +23,6 @@ export default class GenesisBlockCommand extends IronfishCommand { static hidden = true static flags = { - ...LocalFlags, account: Flags.string({ char: 'a', required: false, @@ -135,7 +133,7 @@ export default class GenesisBlockCommand extends IronfishCommand { this.log(`Genesis block will be created with the following values:`) this.log(`\nDifficulty: ${target.toDifficulty()}\n`) this.log(`Allocations:`) - const columns: ux.Table.table.Columns = { + const columns: TableColumns = { identity: { header: 'ADDRESS', get: (row: GenesisBlockAllocation) => row.publicAddress, @@ -152,7 +150,7 @@ export default class GenesisBlockCommand extends IronfishCommand { }, } - ux.table(info.allocations, columns, { + table(info.allocations, columns, { printLine: this.log.bind(this), }) diff --git a/ironfish-cli/src/commands/chain/power.ts b/ironfish-cli/src/commands/chain/power.ts index 1c67ad0a54..632448e77d 100644 --- a/ironfish-cli/src/commands/chain/power.ts +++ b/ironfish-cli/src/commands/chain/power.ts @@ -4,13 +4,14 @@ import { FileUtils } from '@ironfish/sdk' import { Args, Flags } from '@oclif/core' import { IronfishCommand } from '../../command' -import { LocalFlags } from '../../flags' +import { ColorFlag, ColorFlagKey } from '../../flags' export default class Power extends IronfishCommand { - static description = "Show the network's hash power per second" + static description = "show the network's mining power" + static enableJsonFlag = true static flags = { - ...LocalFlags, + [ColorFlagKey]: ColorFlag, history: Flags.integer({ required: false, description: @@ -25,14 +26,13 @@ export default class Power extends IronfishCommand { }), } - async start(): Promise { + async start(): Promise { const { flags, args } = await this.parse(Power) - const { block } = args - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() const data = await client.chain.getNetworkHashPower({ - sequence: block, + sequence: args.block, blocks: flags.history, }) @@ -41,5 +41,7 @@ export default class Power extends IronfishCommand { this.log( `The network power for block ${data.content.sequence} was ${formattedHashesPerSecond} averaged over ${data.content.blocks} previous blocks.`, ) + + return data.content } } diff --git a/ironfish-cli/src/commands/chain/prune.ts b/ironfish-cli/src/commands/chain/prune.ts index d2bb61b5d4..19527e45d6 100644 --- a/ironfish-cli/src/commands/chain/prune.ts +++ b/ironfish-cli/src/commands/chain/prune.ts @@ -4,15 +4,11 @@ import { BlockchainUtils } from '@ironfish/sdk' import { Flags, ux } from '@oclif/core' import { IronfishCommand } from '../../command' -import { LocalFlags } from '../../flags' export default class Prune extends IronfishCommand { - static description = 'Remove old blocks from the chain' - - static hidden = false + static description = 'remove unused blocks from the chain' static flags = { - ...LocalFlags, dry: Flags.boolean({ default: false, description: 'Dry run prune first', diff --git a/ironfish-cli/src/commands/chain/readd-block.ts b/ironfish-cli/src/commands/chain/readd-block.ts deleted file mode 100644 index d8e0ce6293..0000000000 --- a/ironfish-cli/src/commands/chain/readd-block.ts +++ /dev/null @@ -1,47 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import { Args, ux } from '@oclif/core' -import { IronfishCommand } from '../../command' -import { LocalFlags } from '../../flags' - -export default class ReAddBlock extends IronfishCommand { - static description = - 'Remove and readd a block on the chain if it has no other blocks after it' - - static hidden = true - - static flags = { - ...LocalFlags, - } - - static args = { - hash: Args.string({ - required: true, - description: 'The hash of the block in hex format', - }), - } - - async start(): Promise { - const { args } = await this.parse(ReAddBlock) - const hash = Buffer.from(args.hash, 'hex') - - ux.action.start(`Opening node`) - const node = await this.sdk.node() - await node.openDB() - await node.chain.open() - ux.action.stop('done.') - - const block = await node.chain.getBlock(hash) - - if (!block) { - this.log(`No block found with hash ${hash.toString('hex')}`) - return this.exit(0) - } - - await node.chain.removeBlock(hash) - await node.chain.addBlock(block) - - this.log('Block has been reimported.') - } -} diff --git a/ironfish-cli/src/commands/chain/repair.ts b/ironfish-cli/src/commands/chain/repair.ts index 516112ddf6..29c5fe6f61 100644 --- a/ironfish-cli/src/commands/chain/repair.ts +++ b/ironfish-cli/src/commands/chain/repair.ts @@ -4,7 +4,6 @@ import { Assert, BlockHeader, FullNode, IDatabaseTransaction, TimeUtils } from '@ironfish/sdk' import { Flags, ux } from '@oclif/core' import { IronfishCommand } from '../../command' -import { LocalFlags } from '../../flags' import { confirmOrQuit, ProgressBar, ProgressBarPresets } from '../../ui' const TREE_BATCH = 1000 @@ -20,7 +19,6 @@ export default class RepairChain extends IronfishCommand { static hidden = true static flags = { - ...LocalFlags, confirm: Flags.boolean({ char: 'c', default: false, diff --git a/ironfish-cli/src/commands/chain/rewind.ts b/ironfish-cli/src/commands/chain/rewind.ts index 886bfa8bcf..68cbc557d0 100644 --- a/ironfish-cli/src/commands/chain/rewind.ts +++ b/ironfish-cli/src/commands/chain/rewind.ts @@ -1,72 +1,80 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import { Assert, Blockchain, FullNode, NodeUtils, Wallet } from '@ironfish/sdk' -import { Args, Command } from '@oclif/core' +import { Assert, Blockchain, BlockchainUtils, FullNode, NodeUtils, Wallet } from '@ironfish/sdk' +import { Args, Command, Flags } from '@oclif/core' import { IronfishCommand } from '../../command' -import { LocalFlags } from '../../flags' import { ProgressBar, ProgressBarPresets } from '../../ui' export default class Rewind extends IronfishCommand { - static description = - 'Rewind the chain database to the given sequence by deleting all blocks with greater sequences' + static description = 'rewind the blockchain to a block' + + static hidden = true static args = { - to: Args.string({ + to: Args.integer({ required: true, description: 'The block sequence to rewind to', }), - from: Args.string({ + from: Args.integer({ required: false, description: 'The sequence to start removing blocks from', }), } static flags = { - ...LocalFlags, + wallet: Flags.boolean({ + default: true, + allowNo: true, + description: 'should the wallet be rewinded', + }), } async start(): Promise { - const { args } = await this.parse(Rewind) + const { args, flags } = await this.parse(Rewind) const node = await this.sdk.node() await NodeUtils.waitForOpen(node) - await rewindChainTo(this, node, Number(args.to), Number(args.from)) + await rewindChainTo(this, node, flags.wallet, args.to, args.from) } } export const rewindChainTo = async ( command: Command, node: FullNode, + rewindWallet: boolean, to: number, from?: number, ): Promise => { const chain = node.chain const wallet = node.wallet - const sequence = to - - const fromSequence = from ? Math.max(from, chain.latest.sequence) : chain.latest.sequence + const { start, stop } = BlockchainUtils.getBlockRange(node.chain, { + start: to, + stop: from, + }) - const toDisconnect = fromSequence - sequence + const blockCount = stop - start - if (toDisconnect <= 0) { + if (blockCount <= 0) { command.log( - `Chain head currently at ${fromSequence}. Cannot rewind to ${sequence} because it is is greater than the latest sequence in the chain.`, + `Chain head currently at ${stop}. Cannot rewind to ${start} because it is is greater than the latest sequence in the chain.`, ) command.exit(1) } command.log( - `Chain currently has blocks up to ${fromSequence}. Rewinding ${toDisconnect} blocks to ${sequence}.`, + `Chain currently has blocks up to ${stop}. Rewinding ${blockCount} blocks to ${start}.`, ) - await disconnectBlocks(chain, toDisconnect) + await disconnectBlocks(chain, blockCount) - await rewindWalletHead(chain, wallet, sequence) + if (rewindWallet) { + await rewindWalletHead(chain, wallet) + } - await removeBlocks(chain, sequence, fromSequence) + await removeBlocks(chain, start, stop) } async function disconnectBlocks(chain: Blockchain, toDisconnect: number): Promise { @@ -91,34 +99,34 @@ async function disconnectBlocks(chain: Blockchain, toDisconnect: number): Promis bar.stop() } -async function rewindWalletHead( - chain: Blockchain, - wallet: Wallet, - sequence: number, -): Promise { - const latestHead = await wallet.getLatestHead() - - if (latestHead) { - const walletHead = await chain.getHeader(latestHead.hash) +async function rewindWalletHead(chain: Blockchain, wallet: Wallet): Promise { + const walletHead = await wallet.getLatestHead() - if (walletHead && walletHead.sequence > sequence) { - const bar = new ProgressBar('Rewinding wallet', { preset: ProgressBarPresets.withSpeed }) + if (!walletHead) { + return + } - const toRewind = walletHead.sequence - sequence - let rewound = 0 + if (walletHead.sequence > chain.head.sequence) { + const total = walletHead.sequence - chain.head.sequence - bar.start(toRewind, 0) + const bar = new ProgressBar('Rewinding wallet', { preset: ProgressBarPresets.withSpeed }) + bar.start(total, 0) - const scan = await wallet.scan({ wait: false }) + const scan = await wallet.scan({ wait: false }) - if (scan) { - scan.onTransaction.on((_) => { - bar.update(++rewound) - }) - } + if (scan) { + scan.onTransaction.on((sequence, _, action) => { + if (action === 'connect') { + bar.update(total - Math.abs(sequence - chain.head.sequence)) + } else { + bar.update(total - Math.abs(sequence - 1 - chain.head.sequence)) + } + }) - bar.stop() + await scan.wait() } + + bar.stop() } } diff --git a/ironfish-cli/src/commands/chain/show.ts b/ironfish-cli/src/commands/chain/show.ts deleted file mode 100644 index a91ab9ccf4..0000000000 --- a/ironfish-cli/src/commands/chain/show.ts +++ /dev/null @@ -1,38 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import { Args } from '@oclif/core' -import { IronfishCommand } from '../../command' -import { LocalFlags } from '../../flags' - -export default class Show extends IronfishCommand { - static description = 'Show the heaviest chain' - - static flags = { - ...LocalFlags, - } - - static args = { - start: Args.integer({ - default: -50, - required: false, - description: 'The sequence to start at (inclusive, genesis block is 1)', - }), - stop: Args.integer({ - required: false, - description: 'The sequence to end at (inclusive)', - }), - } - - async start(): Promise { - const { args } = await this.parse(Show) - const { start, stop } = args - - this.log(`Getting the chain blocks...`) - await this.sdk.client.connect() - - const data = await this.sdk.client.chain.showChain({ start, stop }) - - data.content.content.forEach((content) => this.log(content)) - } -} diff --git a/ironfish-cli/src/commands/chain/status.ts b/ironfish-cli/src/commands/chain/status.ts new file mode 100644 index 0000000000..b856b1f565 --- /dev/null +++ b/ironfish-cli/src/commands/chain/status.ts @@ -0,0 +1,50 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +import { FileUtils, renderNetworkName } from '@ironfish/sdk' +import { IronfishCommand } from '../../command' +import { ColorFlag, ColorFlagKey } from '../../flags' +import * as ui from '../../ui' + +export default class ChainStatus extends IronfishCommand { + static description = 'show chain information' + static enableJsonFlag = true + + static flags = { + [ColorFlagKey]: ColorFlag, + } + + async start(): Promise { + const client = await this.connectRpc() + + const [status, difficulty, power] = await Promise.all([ + client.node.getStatus(), + client.chain.getDifficulty(), + client.chain.getNetworkHashPower(), + ]) + + this.log( + ui.card({ + Network: renderNetworkName(status.content.node.networkId), + Blocks: status.content.blockchain.head.sequence, + Hash: status.content.blockchain.head.hash, + Time: new Date(status.content.blockchain.headTimestamp).toLocaleString(), + Synced: status.content.blockchain.synced, + Difficulty: difficulty.content.difficulty, + Size: FileUtils.formatFileSize(status.content.blockchain.dbSizeBytes), + Work: status.content.blockchain.dbSizeBytes, + Power: FileUtils.formatHashRate(power.content.hashesPerSecond), + }), + ) + + return { + blockchain: status.content.blockchain, + difficulty: difficulty.content, + power: power.content, + node: { + network: renderNetworkName(status.content.node.networkId), + networkId: status.content.node.networkId, + }, + } + } +} diff --git a/ironfish-cli/src/commands/chain/transactions/info.ts b/ironfish-cli/src/commands/chain/transactions/info.ts new file mode 100644 index 0000000000..6dfecd004b --- /dev/null +++ b/ironfish-cli/src/commands/chain/transactions/info.ts @@ -0,0 +1,54 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +import { CurrencyUtils, FileUtils } from '@ironfish/sdk' +import { Args } from '@oclif/core' +import { IronfishCommand } from '../../../command' +import { ColorFlag, ColorFlagKey, RemoteFlags } from '../../../flags' +import * as ui from '../../../ui' + +export class TransactionInfo extends IronfishCommand { + static description = 'show transaction information' + static enableJsonFlag = true + + static flags = { + ...RemoteFlags, + [ColorFlagKey]: ColorFlag, + } + + static args = { + hash: Args.string({ + required: true, + description: 'Hash of the transaction', + }), + } + + async start(): Promise { + const { args } = await this.parse(TransactionInfo) + + const client = await this.connectRpc() + + const response = await client.chain.getTransaction({ + transactionHash: args.hash, + }) + + const transaction = response.content + + this.log( + ui.card({ + 'Block hash': transaction.blockHash, + 'Transaction hash': transaction.hash, + Fee: CurrencyUtils.render(transaction.fee.toString(), true), + 'Expiration sequence': transaction.expiration, + 'Transaction size': FileUtils.formatMemorySize(transaction.size), + 'Notes output': transaction.notes.length, + 'Notes spent': transaction.spends.length, + 'Mint count': transaction.mints.length, + 'Burn count': transaction.burns.length, + }), + ) + + return transaction + } +} diff --git a/ironfish-cli/src/commands/config/edit.ts b/ironfish-cli/src/commands/config/edit.ts index 48cb99002c..480cc7249e 100644 --- a/ironfish-cli/src/commands/config/edit.ts +++ b/ironfish-cli/src/commands/config/edit.ts @@ -8,7 +8,6 @@ import os from 'os' import path from 'path' import { promisify } from 'util' import { IronfishCommand } from '../../command' -import { ConfigFlag, ConfigFlagKey, DataDirFlag, DataDirFlagKey } from '../../flags' import { launchEditor } from '../../utils' const mkdtempAsync = promisify(mkdtemp) @@ -21,8 +20,6 @@ export class EditCommand extends IronfishCommand { Set the editor in either EDITOR environment variable, or set 'editor' in your ironfish config` static flags = { - [ConfigFlagKey]: ConfigFlag, - [DataDirFlagKey]: DataDirFlag, remote: Flags.boolean({ default: false, description: 'Connect to the node when editing the config', @@ -39,7 +36,7 @@ export class EditCommand extends IronfishCommand { this.exit(code || undefined) } - const client = await this.sdk.connectRpc(!flags.remote) + const client = await this.connectRpc(!flags.remote) const response = await client.config.getConfig({ user: true }) const output = JSON.stringify(response.content, undefined, ' ') diff --git a/ironfish-cli/src/commands/config/get.ts b/ironfish-cli/src/commands/config/get.ts index 9d2c16dd5a..0f5a91c1a3 100644 --- a/ironfish-cli/src/commands/config/get.ts +++ b/ironfish-cli/src/commands/config/get.ts @@ -3,12 +3,13 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import { ConfigOptions } from '@ironfish/sdk' import { Args, Flags } from '@oclif/core' -import jsonColorizer from 'json-colorizer' import { IronfishCommand } from '../../command' -import { RemoteFlags } from '../../flags' +import { ColorFlag, ColorFlagKey, RemoteFlags } from '../../flags' +import * as ui from '../../ui' export class GetCommand extends IronfishCommand { static description = `Print out one config value` + static enableJsonFlag = true static args = { name: Args.string({ @@ -19,6 +20,7 @@ export class GetCommand extends IronfishCommand { static flags = { ...RemoteFlags, + [ColorFlagKey]: ColorFlag, user: Flags.boolean({ description: 'Only show config from the users datadir and not overrides', }), @@ -26,23 +28,13 @@ export class GetCommand extends IronfishCommand { default: false, description: 'Dont connect to the node when displaying the config', }), - color: Flags.boolean({ - default: true, - allowNo: true, - description: 'Should colorize the output', - }), - json: Flags.boolean({ - default: false, - allowNo: true, - description: 'Output the config value as json', - }), } - async start(): Promise { + async start(): Promise { const { args, flags } = await this.parse(GetCommand) const { name } = args - const client = await this.sdk.connectRpc(flags.local) + const client = await this.connectRpc(flags.local) const response = await client.config.getConfig({ user: flags.user, @@ -54,19 +46,10 @@ export class GetCommand extends IronfishCommand { this.exit(0) } - let output = '' + const config = { [key]: response.content[key] } - if (flags.json) { - output = JSON.stringify(response.content[key], undefined, ' ') - - if (flags.color) { - output = jsonColorizer(output) - } - } else { - output = String(response.content[key]) - } + this.log(ui.card(config)) - this.log(output) - this.exit(0) + return config } } diff --git a/ironfish-cli/src/commands/config/index.ts b/ironfish-cli/src/commands/config/index.ts index c7beba2598..5f4a18142e 100644 --- a/ironfish-cli/src/commands/config/index.ts +++ b/ironfish-cli/src/commands/config/index.ts @@ -2,13 +2,14 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import { Flags } from '@oclif/core' -import jsonColorizer from 'json-colorizer' import { IronfishCommand } from '../../command' import { ColorFlag, ColorFlagKey } from '../../flags' import { RemoteFlags } from '../../flags' +import * as ui from '../../ui' export class ShowCommand extends IronfishCommand { static description = `Print out the entire config` + static enableJsonFlag = true static flags = { ...RemoteFlags, @@ -22,16 +23,15 @@ export class ShowCommand extends IronfishCommand { }), } - async start(): Promise { + async start(): Promise { const { flags } = await this.parse(ShowCommand) - const client = await this.sdk.connectRpc(flags.local) + const client = await this.connectRpc(flags.local) const response = await client.config.getConfig({ user: flags.user }) + const config = response.content - let output = JSON.stringify(response.content, undefined, ' ') - if (flags.color) { - output = jsonColorizer(output) - } - this.log(output) + this.log(ui.card(config)) + + return config } } diff --git a/ironfish-cli/src/commands/config/set.ts b/ironfish-cli/src/commands/config/set.ts index 906b0dacca..5cd83a7e31 100644 --- a/ironfish-cli/src/commands/config/set.ts +++ b/ironfish-cli/src/commands/config/set.ts @@ -35,7 +35,7 @@ export class SetCommand extends IronfishCommand { const { args, flags } = await this.parse(SetCommand) const { name, value } = args - const client = await this.sdk.connectRpc(flags.local) + const client = await this.connectRpc(flags.local) await client.config.setConfig({ name, value }) this.exit(0) diff --git a/ironfish-cli/src/commands/config/unset.ts b/ironfish-cli/src/commands/config/unset.ts index d28a549682..3dc81ecd12 100644 --- a/ironfish-cli/src/commands/config/unset.ts +++ b/ironfish-cli/src/commands/config/unset.ts @@ -29,7 +29,7 @@ export class UnsetCommand extends IronfishCommand { const { args, flags } = await this.parse(UnsetCommand) const { name } = args - const client = await this.sdk.connectRpc(flags.local) + const client = await this.connectRpc(flags.local) await client.config.unsetConfig({ name }) this.exit(0) diff --git a/ironfish-cli/src/commands/debug.ts b/ironfish-cli/src/commands/debug.ts index b9b8827ea7..d0d4feeffa 100644 --- a/ironfish-cli/src/commands/debug.ts +++ b/ironfish-cli/src/commands/debug.ts @@ -13,7 +13,6 @@ import { execSync } from 'child_process' import os from 'os' import { getHeapStatistics } from 'v8' import { IronfishCommand } from '../command' -import { LocalFlags } from '../flags' const SPACE_BUFFER = 8 @@ -21,10 +20,6 @@ export default class Debug extends IronfishCommand { static description = 'Show debug information to help locate issues' static hidden = true - static flags = { - ...LocalFlags, - } - async start(): Promise { const node = await this.sdk.node({ autoSeed: false }) diff --git a/ironfish-cli/src/commands/faucet.ts b/ironfish-cli/src/commands/faucet.ts index 0653eba999..286c9cd3d0 100644 --- a/ironfish-cli/src/commands/faucet.ts +++ b/ironfish-cli/src/commands/faucet.ts @@ -7,6 +7,7 @@ import { Flags, ux } from '@oclif/core' import { IronfishCommand } from '../command' import { RemoteFlags } from '../flags' import { ONE_FISH_IMAGE, TWO_FISH_IMAGE } from '../images' +import { inputPrompt } from '../ui' const FAUCET_DISABLED = false @@ -33,7 +34,7 @@ export class FaucetCommand extends IronfishCommand { this.exit(1) } - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() const networkInfoResponse = await client.chain.getNetworkInfo() if (networkInfoResponse.content === null || networkInfoResponse.content.networkId !== 0) { @@ -47,9 +48,7 @@ export class FaucetCommand extends IronfishCommand { if (!email) { email = - (await ux.prompt('Enter your email to stay updated with Iron Fish', { - required: false, - })) || undefined + (await inputPrompt('Enter your email to stay updated with Iron Fish')) || undefined } // Create an account if one is not set @@ -59,9 +58,7 @@ export class FaucetCommand extends IronfishCommand { if (!accountName) { this.log(`You don't have a default account set up yet. Let's create one first!`) accountName = - (await ux.prompt('Please enter the name of your new Iron Fish account', { - required: false, - })) || 'default' + (await inputPrompt('Please enter the name of your new Iron Fish account')) || 'default' await client.wallet.createAccount({ name: accountName, default: true }) } @@ -89,17 +86,17 @@ export class FaucetCommand extends IronfishCommand { this.log( ` - ${TWO_FISH_IMAGE} + ${TWO_FISH_IMAGE} -Congratulations! The Iron Fish Faucet just added your request to the queue! + Congratulations! The Iron Fish Faucet just added your request to the queue! -It will be processed within the next hour and $IRON will be sent directly to your account. + It will be processed within the next hour and $IRON will be sent directly to your account. -Check your balance by running: - - ironfish wallet:balance + Check your balance by running: + - ironfish wallet:balance -Learn how to send a transaction by running: - - ironfish wallet:send --help`, + Learn how to send a transaction by running: + - ironfish wallet:send --help`, ) } } diff --git a/ironfish-cli/src/commands/fees.ts b/ironfish-cli/src/commands/fees.ts index bebd774d7b..fa3b5f073b 100644 --- a/ironfish-cli/src/commands/fees.ts +++ b/ironfish-cli/src/commands/fees.ts @@ -26,7 +26,7 @@ export class FeeCommand extends IronfishCommand { async start(): Promise { const { flags } = await this.parse(FeeCommand) - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() if (flags.explain) { await this.explainFeeRates(client) diff --git a/ironfish-cli/src/commands/mempool/status.ts b/ironfish-cli/src/commands/mempool/status.ts index 10aaf19087..14bb320e1d 100644 --- a/ironfish-cli/src/commands/mempool/status.ts +++ b/ironfish-cli/src/commands/mempool/status.ts @@ -7,6 +7,7 @@ import { Flags } from '@oclif/core' import blessed from 'blessed' import { IronfishCommand } from '../../command' import { RemoteFlags } from '../../flags' +import * as ui from '../../ui' export default class Status extends IronfishCommand { static description = 'Show the status of the Mempool' @@ -24,7 +25,7 @@ export default class Status extends IronfishCommand { const { flags } = await this.parse(Status) if (!flags.follow) { - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() const response = await client.mempool.getMempoolStatus() this.log(renderStatus(response.content)) this.exit(0) @@ -63,10 +64,11 @@ function renderStatus(content: GetMempoolStatusResponse): string { const maxStorage = FileUtils.formatMemorySize(content.maxSizeBytes) const saturationPercentage = ((content.sizeBytes / content.maxSizeBytes) * 100).toFixed(2) - return `\ -Tx Count ${content.size} -Memory ${storage} / ${maxStorage} (${saturationPercentage}%) -Eviction Cache ${content.recentlyEvictedCache.size} / ${content.recentlyEvictedCache.maxSize} -Evictions ${content.evictions} -Head Sequence ${content.headSequence}` + return ui.card({ + 'Tx Count': content.size, + Memory: `${storage} / ${maxStorage} (${saturationPercentage}%)`, + 'Eviction Cache': `${content.recentlyEvictedCache.size} / ${content.recentlyEvictedCache.maxSize}`, + Evictions: content.evictions, + 'Head Sequence': content.headSequence, + }) } diff --git a/ironfish-cli/src/commands/mempool/transactions.ts b/ironfish-cli/src/commands/mempool/transactions.ts index cc882e79d5..a2d82b5829 100644 --- a/ironfish-cli/src/commands/mempool/transactions.ts +++ b/ironfish-cli/src/commands/mempool/transactions.ts @@ -2,11 +2,10 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import { getFeeRate, GetMempoolTransactionResponse, MinMax, Transaction } from '@ironfish/sdk' -import { Flags, ux } from '@oclif/core' -import { InferredFlags } from '@oclif/core/lib/interfaces' +import { Flags, Interfaces } from '@oclif/core' import { IronfishCommand } from '../../command' import { RemoteFlags } from '../../flags' -import { TableFlags } from '../../utils/table' +import { table, TableColumns, TableFlags } from '../../ui' const { sort: _, ...tableFlags } = TableFlags @@ -152,9 +151,9 @@ type TransactionRow = { function renderTable( response: GetMempoolTransactionResponse[], - flags: InferredFlags, + flags: Interfaces.InferredFlags, ): string { - const columns: ux.Table.table.Columns = { + const columns: TableColumns = { position: { header: 'POSITION', minWidth: 4, @@ -210,7 +209,7 @@ function renderTable( let result = '' const limit = flags.csv ? 0 : flags.show - ux.table(getRows(response, limit), columns, { + table(getRows(response, limit), columns, { printLine: (line) => (result += `${String(line)}\n`), ...flags, }) diff --git a/ironfish-cli/src/commands/migrations/index.ts b/ironfish-cli/src/commands/migrations/index.ts index 0845878cf4..8a5b047451 100644 --- a/ironfish-cli/src/commands/migrations/index.ts +++ b/ironfish-cli/src/commands/migrations/index.ts @@ -2,16 +2,10 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import { IronfishCommand } from '../../command' -import { ConfigFlag, ConfigFlagKey, DataDirFlag, DataDirFlagKey } from '../../flags' export class StatusCommand extends IronfishCommand { static description = `List all the migration statuses` - static flags = { - [ConfigFlagKey]: ConfigFlag, - [DataDirFlagKey]: DataDirFlag, - } - async start(): Promise { await this.parse(StatusCommand) diff --git a/ironfish-cli/src/commands/migrations/revert.ts b/ironfish-cli/src/commands/migrations/revert.ts index dd0168197d..ba4e1a17f6 100644 --- a/ironfish-cli/src/commands/migrations/revert.ts +++ b/ironfish-cli/src/commands/migrations/revert.ts @@ -2,18 +2,12 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import { IronfishCommand } from '../../command' -import { ConfigFlag, ConfigFlagKey, DataDirFlag, DataDirFlagKey } from '../../flags' export class RevertCommand extends IronfishCommand { static description = `Revert the last run migration` static hidden = true - static flags = { - [ConfigFlagKey]: ConfigFlag, - [DataDirFlagKey]: DataDirFlag, - } - async start(): Promise { await this.parse(RevertCommand) diff --git a/ironfish-cli/src/commands/migrations/start.ts b/ironfish-cli/src/commands/migrations/start.ts index 2ac49734ba..099fc38835 100644 --- a/ironfish-cli/src/commands/migrations/start.ts +++ b/ironfish-cli/src/commands/migrations/start.ts @@ -3,15 +3,11 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import { Flags } from '@oclif/core' import { IronfishCommand } from '../../command' -import { ConfigFlag, ConfigFlagKey, DataDirFlag, DataDirFlagKey, LocalFlags } from '../../flags' export class StartCommand extends IronfishCommand { static description = `Run migrations` static flags = { - ...LocalFlags, - [ConfigFlagKey]: ConfigFlag, - [DataDirFlagKey]: DataDirFlag, dry: Flags.boolean({ default: false, description: 'Dry run migrations first', diff --git a/ironfish-cli/src/commands/miners/pools/status.ts b/ironfish-cli/src/commands/miners/pools/status.ts index ec24238bf5..0d9070a183 100644 --- a/ironfish-cli/src/commands/miners/pools/status.ts +++ b/ironfish-cli/src/commands/miners/pools/status.ts @@ -16,6 +16,7 @@ import { Flags } from '@oclif/core' import blessed from 'blessed' import dns from 'dns' import { IronfishCommand } from '../../../command' +import * as ui from '../../../ui' export class PoolStatus extends IronfishCommand { static description = `Show the status of a mining pool` @@ -105,23 +106,26 @@ export class PoolStatus extends IronfishCommand { } renderStatus(status: MiningStatusMessage): string { - let result = '' - result += `Status of mining pool '${status.name}':\n` - result += `Miners: ${status.miners}\n` - result += `Hashrate: ${FileUtils.formatHashRate(status.hashRate)}\n` - result += `Shares pending payout: ${status.sharesPending}\n` - result += `Clients: ${status.clients}\n` - result += `Bans: ${status.bans}\n` + let data: Record = { + 'Status of mining pool': status.name, + Miners: status.miners, + Hashrate: FileUtils.formatHashRate(status.hashRate), + 'Shares pending payout': status.sharesPending, + Clients: status.clients, + Bans: status.bans, + } if (status.addressStatus) { - result += `\nMining status for address '${status.addressStatus.publicAddress}':\n` - result += `Number of miners: ${status.addressStatus.miners}\n` - result += `Connected miners: ${status.addressStatus.connectedMiners.join(', ')}\n` - result += `Hashrate: ${FileUtils.formatHashRate( - status.addressStatus.hashRate, - )}\n` - result += `Shares pending payout: ${status.addressStatus.sharesPending}` + data = { + ...data, + 'Mining status for address': status.addressStatus.publicAddress, + 'Number of miners': status.addressStatus.miners, + 'Connected miners': status.addressStatus.connectedMiners.join(', '), + Hashrate: FileUtils.formatHashRate(status.addressStatus.hashRate), + 'Shares pending payout': status.addressStatus.sharesPending, + } } - return result + + return ui.card(data) } } diff --git a/ironfish-cli/src/commands/miners/start.ts b/ironfish-cli/src/commands/miners/start.ts index 2ec9fc4f1e..29ad236df5 100644 --- a/ironfish-cli/src/commands/miners/start.ts +++ b/ironfish-cli/src/commands/miners/start.ts @@ -81,7 +81,7 @@ export class Miner extends IronfishCommand { let publicAddress = flags.address if (publicAddress == null) { - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() const publicKeyResponse = await client.wallet.getAccountPublicKey() publicAddress = publicKeyResponse.content.publicKey diff --git a/ironfish-cli/src/commands/peers/banned.ts b/ironfish-cli/src/commands/peers/banned.ts index a9678ca643..28540c6af1 100644 --- a/ironfish-cli/src/commands/peers/banned.ts +++ b/ironfish-cli/src/commands/peers/banned.ts @@ -2,11 +2,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import { BannedPeerResponse, GetBannedPeersResponse, PromiseUtils } from '@ironfish/sdk' -import { Flags, ux } from '@oclif/core' +import { Flags } from '@oclif/core' import blessed from 'blessed' import { IronfishCommand } from '../../command' import { RemoteFlags } from '../../flags' -import { TableFlags } from '../../utils/table' +import { table, TableColumns, TableFlags } from '../../ui' const { sort, ...tableFlags } = TableFlags @@ -19,7 +19,7 @@ export class BannedCommand extends IronfishCommand { sort: { ...sort, exclusive: ['follow'], - }, + } as typeof sort, follow: Flags.boolean({ char: 'f', default: false, @@ -67,7 +67,7 @@ export class BannedCommand extends IronfishCommand { } function renderTable(content: GetBannedPeersResponse): string { - const columns: ux.Table.table.Columns = { + const columns: TableColumns = { identity: { minWidth: 45, header: 'IDENTITY', @@ -86,7 +86,7 @@ function renderTable(content: GetBannedPeersResponse): string { let result = '' - ux.table(content.peers, columns, { + table(content.peers, columns, { printLine: (line) => (result += `${String(line)}\n`), }) diff --git a/ironfish-cli/src/commands/peers/index.ts b/ironfish-cli/src/commands/peers/index.ts index ab192ddfb2..3a46771f56 100644 --- a/ironfish-cli/src/commands/peers/index.ts +++ b/ironfish-cli/src/commands/peers/index.ts @@ -2,12 +2,12 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import { GetPeersResponse, PromiseUtils } from '@ironfish/sdk' -import { Flags, ux } from '@oclif/core' -import { InferredFlags } from '@oclif/core/lib/interfaces' +import { Flags } from '@oclif/core' +import { Interfaces } from '@oclif/core' import blessed from 'blessed' import { IronfishCommand } from '../../command' import { RemoteFlags } from '../../flags' -import { TableFlags } from '../../utils/table' +import { table, TableColumns, TableFlags } from '../../ui' type GetPeerResponsePeer = GetPeersResponse['peers'][0] @@ -94,9 +94,9 @@ export class ListCommand extends IronfishCommand { function renderTable( content: GetPeersResponse, - flags: InferredFlags, + flags: Interfaces.InferredFlags, ): string { - let columns: ux.Table.table.Columns = { + let columns: TableColumns = { identity: { header: 'IDENTITY', get: (row: GetPeerResponsePeer) => { @@ -224,7 +224,7 @@ function renderTable( let result = '' - ux.table(peers, columns, { + table(peers, columns, { printLine: (line) => (result += `${String(line)}\n`), ...flags, }) diff --git a/ironfish-cli/src/commands/repl.ts b/ironfish-cli/src/commands/repl.ts index da92431e34..7a7d96c2e3 100644 --- a/ironfish-cli/src/commands/repl.ts +++ b/ironfish-cli/src/commands/repl.ts @@ -8,22 +8,11 @@ import fs from 'fs/promises' import repl from 'node:repl' import path from 'path' import { IronfishCommand } from '../command' -import { - ConfigFlag, - ConfigFlagKey, - DataDirFlag, - DataDirFlagKey, - VerboseFlag, - VerboseFlagKey, -} from '../flags' export default class Repl extends IronfishCommand { static description = 'An interactive terminal to the node' static flags = { - [VerboseFlagKey]: VerboseFlag, - [ConfigFlagKey]: ConfigFlag, - [DataDirFlagKey]: DataDirFlag, opendb: Flags.boolean({ description: 'open the databases', allowNo: true, @@ -48,7 +37,7 @@ export default class Repl extends IronfishCommand { this.log('\n Get a block at a sequence') this.log(` > await chain.getHeaderAtSequence(1)`) this.log('\n List all account names') - this.log(` > wallet.listAccounts().map((a) => a.name)`) + this.log(` > wallet.accounts.map((a) => a.name)`) this.log(`\n Get the balance of an account`) this.log(` > const account = await wallet.getAccountByName('default')`) this.log(` > await wallet.getBalances(account)`) diff --git a/ironfish-cli/src/commands/reset.ts b/ironfish-cli/src/commands/reset.ts index 34b441ff8e..ddd87f37a2 100644 --- a/ironfish-cli/src/commands/reset.ts +++ b/ironfish-cli/src/commands/reset.ts @@ -5,23 +5,12 @@ import { FullNode, PEER_STORE_FILE_NAME } from '@ironfish/sdk' import { Flags, ux } from '@oclif/core' import fsAsync from 'fs/promises' import { IronfishCommand } from '../command' -import { - ConfigFlag, - ConfigFlagKey, - DataDirFlag, - DataDirFlagKey, - VerboseFlag, - VerboseFlagKey, -} from '../flags' import { confirmOrQuit } from '../ui' export default class Reset extends IronfishCommand { static description = 'Reset the node to its initial state' static flags = { - [VerboseFlagKey]: VerboseFlag, - [ConfigFlagKey]: ConfigFlag, - [DataDirFlagKey]: DataDirFlag, networkId: Flags.integer({ char: 'i', default: undefined, diff --git a/ironfish-cli/src/commands/rpc/status.ts b/ironfish-cli/src/commands/rpc/status.ts index bd1bd874ca..cd4e3ffe2a 100644 --- a/ironfish-cli/src/commands/rpc/status.ts +++ b/ironfish-cli/src/commands/rpc/status.ts @@ -6,6 +6,7 @@ import { Flags } from '@oclif/core' import blessed from 'blessed' import { IronfishCommand } from '../../command' import { RemoteFlags } from '../../flags' +import * as ui from '../../ui' export default class Status extends IronfishCommand { static description = 'Show the status of the RPC layer' @@ -23,7 +24,7 @@ export default class Status extends IronfishCommand { const { flags } = await this.parse(Status) if (!flags.follow) { - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() const response = await client.rpc.getRpcStatus() this.log(renderStatus(response.content)) this.exit(0) @@ -62,16 +63,18 @@ function renderStatus(content: GetRpcStatusResponse): string { for (const adapter of content.adapters) { result += `\n\n[${adapter.name}]\n` - result += `Clients: ${adapter.clients}\n` - result += `Requests Pending: ${adapter.pending.length}\n` - result += `Routes Pending: ${adapter.pending.join(', ')}\n` - result += `Inbound Traffic: ${FileUtils.formatMemorySize(adapter.inbound)}/s\n` - result += `Outbound Traffic: ${FileUtils.formatMemorySize(adapter.outbound)}/s\n` - result += `Outbound Total: ${FileUtils.formatMemorySize(adapter.writtenBytes)}\n` - result += `Inbound Total: ${FileUtils.formatMemorySize(adapter.readBytes)}\n` - result += `RW Backlog: ${FileUtils.formatMemorySize( - adapter.readableBytes, - )} / ${FileUtils.formatMemorySize(adapter.writableBytes)}` + result += ui.card({ + Clients: adapter.clients, + 'Requests Pending': adapter.pending.length, + 'Routes Pending': adapter.pending.join(', '), + 'Inbound Traffic': FileUtils.formatMemorySize(adapter.inbound), + 'Outbound Traffic': FileUtils.formatMemorySize(adapter.outbound), + 'Outbound Total': FileUtils.formatMemorySize(adapter.writtenBytes), + 'Inbound Total': FileUtils.formatMemorySize(adapter.readBytes), + 'RW Backlog': `${FileUtils.formatMemorySize( + adapter.readableBytes, + )} / ${FileUtils.formatMemorySize(adapter.writableBytes)}`, + }) } return result diff --git a/ironfish-cli/src/commands/rpc/token.ts b/ironfish-cli/src/commands/rpc/token.ts index 34a3feeeda..5ca6dbf314 100644 --- a/ironfish-cli/src/commands/rpc/token.ts +++ b/ironfish-cli/src/commands/rpc/token.ts @@ -3,13 +3,11 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import { Flags } from '@oclif/core' import { IronfishCommand } from '../../command' -import { LocalFlags } from '../../flags' export default class Token extends IronfishCommand { static description = 'Get or set the RPC auth token' static flags = { - ...LocalFlags, token: Flags.string({ required: false, description: 'Set the RPC auth token to ', diff --git a/ironfish-cli/src/commands/start.ts b/ironfish-cli/src/commands/start.ts index b64ebd175a..09231246f8 100644 --- a/ironfish-cli/src/commands/start.ts +++ b/ironfish-cli/src/commands/start.ts @@ -7,10 +7,6 @@ import inspector from 'node:inspector' import { v4 as uuid } from 'uuid' import { IronfishCommand, SIGNALS } from '../command' import { - ConfigFlag, - ConfigFlagKey, - DataDirFlag, - DataDirFlagKey, RpcAuthFlag, RpcAuthFlagKey, RpcHttpHostFlag, @@ -29,8 +25,6 @@ import { RpcUseIpcFlagKey, RpcUseTcpFlag, RpcUseTcpFlagKey, - VerboseFlag, - VerboseFlagKey, } from '../flags' import { ONE_FISH_IMAGE } from '../images' @@ -41,12 +35,9 @@ export default class Start extends IronfishCommand { static description = 'Start the node' static flags = { - [VerboseFlagKey]: VerboseFlag, - [ConfigFlagKey]: ConfigFlag, - [DataDirFlagKey]: DataDirFlag, - [RpcUseIpcFlagKey]: { ...RpcUseIpcFlag, allowNo: true }, - [RpcUseTcpFlagKey]: { ...RpcUseTcpFlag, allowNo: true }, - [RpcUseHttpFlagKey]: { ...RpcUseHttpFlag, allowNo: true }, + [RpcUseIpcFlagKey]: { ...RpcUseIpcFlag, allowNo: true } as typeof RpcUseIpcFlag, + [RpcUseTcpFlagKey]: { ...RpcUseTcpFlag, allowNo: true } as typeof RpcUseTcpFlag, + [RpcUseHttpFlagKey]: { ...RpcUseHttpFlag, allowNo: true } as typeof RpcUseHttpFlag, [RpcTcpTlsFlagKey]: RpcTcpTlsFlag, [RpcAuthFlagKey]: RpcAuthFlag, [RpcTcpHostFlagKey]: RpcTcpHostFlag, diff --git a/ironfish-cli/src/commands/status.ts b/ironfish-cli/src/commands/status.ts index ab5cb01bfd..14e9013457 100644 --- a/ironfish-cli/src/commands/status.ts +++ b/ironfish-cli/src/commands/status.ts @@ -13,6 +13,7 @@ import { Flags } from '@oclif/core' import blessed from 'blessed' import { IronfishCommand } from '../command' import { RemoteFlags } from '../flags' +import * as ui from '../ui' export default class Status extends IronfishCommand { static description = 'Show the status of the node' @@ -34,7 +35,7 @@ export default class Status extends IronfishCommand { const { flags } = await this.parse(Status) if (!flags.follow) { - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() const response = await client.node.getStatus() this.log(renderStatus(response.content, flags.all)) this.exit(0) @@ -214,22 +215,22 @@ function renderStatus(content: GetNodeStatusResponse, debugOutput: boolean): str ? [cores, current, rollingAvg].join(', ') : [cores, current].join(', ') - return `\ -Version ${content.node.version} @ ${content.node.git} -Node ${nodeStatus} -Node Name ${content.node.nodeName} -Peer ID ${content.peerNetwork.publicIdentity} -Block Graffiti ${blockGraffiti} -Network ${network} -Memory ${memoryStatus} -CPU ${cpuStatus} -P2P Network ${peerNetworkStatus} -Mining ${miningDirectorStatus} -Mem Pool ${memPoolStatus} -Syncer ${blockSyncerStatus} -Blockchain ${blockchainStatus} -Accounts ${accountStatus} -Telemetry ${telemetryStatus} -Workers ${workersStatus} -` + return ui.card({ + Version: `${content.node.version} @ ${content.node.git}`, + Node: nodeStatus, + 'Node Name': content.node.nodeName, + 'Peed ID': content.peerNetwork.publicIdentity, + 'Block Graffiti': blockGraffiti, + Network: network, + Memory: memoryStatus, + CPU: cpuStatus, + 'P2P Network': peerNetworkStatus, + Mining: miningDirectorStatus, + 'Mem Pool': memPoolStatus, + Syncer: blockSyncerStatus, + Blockchain: blockchainStatus, + Accounts: accountStatus, + Telemetry: telemetryStatus, + Workers: workersStatus, + }) } diff --git a/ironfish-cli/src/commands/swim.ts b/ironfish-cli/src/commands/swim.ts index 7b9d75f720..ef81c71ac0 100644 --- a/ironfish-cli/src/commands/swim.ts +++ b/ironfish-cli/src/commands/swim.ts @@ -1,7 +1,7 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import { ux } from '@oclif/core' +import { PromiseUtils } from '@ironfish/sdk' import { IronfishCommand } from '../command' import { ONE_FISH_IMAGE, TWO_FISH_IMAGE } from '../images' @@ -40,7 +40,7 @@ export default class SwimCommand extends IronfishCommand { console.clear() this.renderPixels(pixels) this.log('The hex fish are coming...') - await ux.wait(32) + await PromiseUtils.sleep(32) } // eslint-disable-next-line no-console diff --git a/ironfish-cli/src/commands/wallet/accounts.ts b/ironfish-cli/src/commands/wallet/accounts.ts index 1439c2c626..9b14f58d28 100644 --- a/ironfish-cli/src/commands/wallet/accounts.ts +++ b/ironfish-cli/src/commands/wallet/accounts.ts @@ -19,7 +19,7 @@ export class AccountsCommand extends IronfishCommand { async start(): Promise { const { flags } = await this.parse(AccountsCommand) - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() const response = await client.wallet.getAccounts({ displayName: flags.displayName }) diff --git a/ironfish-cli/src/commands/wallet/address.ts b/ironfish-cli/src/commands/wallet/address.ts index 0d2e0f8e14..e555c689e5 100644 --- a/ironfish-cli/src/commands/wallet/address.ts +++ b/ironfish-cli/src/commands/wallet/address.ts @@ -25,7 +25,7 @@ export class AddressCommand extends IronfishCommand { const { args } = await this.parse(AddressCommand) const { account } = args - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() const response = await client.wallet.getAccountPublicKey({ account: account, diff --git a/ironfish-cli/src/commands/wallet/assets.ts b/ironfish-cli/src/commands/wallet/assets.ts index b53f691c6d..b21fcfb779 100644 --- a/ironfish-cli/src/commands/wallet/assets.ts +++ b/ironfish-cli/src/commands/wallet/assets.ts @@ -9,11 +9,12 @@ import { PUBLIC_ADDRESS_LENGTH, } from '@ironfish/rust-nodejs' import { BufferUtils } from '@ironfish/sdk' -import { Args, Flags, ux } from '@oclif/core' +import { Args, Flags } from '@oclif/core' import { IronfishCommand } from '../../command' import { RemoteFlags } from '../../flags' +import { table, TableFlags } from '../../ui' import { renderAssetWithVerificationStatus } from '../../utils' -import { TableCols, TableFlags } from '../../utils/table' +import { TableCols } from '../../utils/table' const MAX_ASSET_METADATA_COLUMN_WIDTH = ASSET_METADATA_LENGTH + 1 const MIN_ASSET_METADATA_COLUMN_WIDTH = ASSET_METADATA_LENGTH / 2 + 1 @@ -45,7 +46,7 @@ export class AssetsCommand extends IronfishCommand { // TODO: remove account arg const account = flags.account ? flags.account : args.account - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() const response = client.wallet.getAssets({ account, }) @@ -59,7 +60,7 @@ export class AssetsCommand extends IronfishCommand { let showHeader = !flags['no-header'] for await (const asset of response.contentStream()) { - ux.table( + table( [asset], { name: TableCols.fixedWidth({ @@ -77,6 +78,7 @@ export class AssetsCommand extends IronfishCommand { id: { header: 'ID', minWidth: ASSET_ID_LENGTH + 1, + get: (row) => row.id, }, metadata: TableCols.fixedWidth({ header: 'Metadata', @@ -85,6 +87,7 @@ export class AssetsCommand extends IronfishCommand { }), createdTransactionHash: { header: 'Created Transaction Hash', + get: (row) => row.createdTransactionHash, }, supply: { header: 'Supply', diff --git a/ironfish-cli/src/commands/wallet/balance.ts b/ironfish-cli/src/commands/wallet/balance.ts index be4f21b4b2..4e74cf5800 100644 --- a/ironfish-cli/src/commands/wallet/balance.ts +++ b/ironfish-cli/src/commands/wallet/balance.ts @@ -5,6 +5,7 @@ import { CurrencyUtils, GetBalanceResponse, isNativeIdentifier, RpcAsset } from import { Args, Flags } from '@oclif/core' import { IronfishCommand } from '../../command' import { RemoteFlags } from '../../flags' +import * as ui from '../../ui' import { renderAssetWithVerificationStatus } from '../../utils' export class BalanceCommand extends IronfishCommand { @@ -50,7 +51,7 @@ export class BalanceCommand extends IronfishCommand { // TODO: remove account arg const account = flags.account ? flags.account : args.account - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() const response = await client.wallet.getAccountBalance({ account, @@ -86,18 +87,26 @@ export class BalanceCommand extends IronfishCommand { const renderedUnconfirmed = renderValue(response.content.unconfirmed, asset, assetName) const renderedPending = renderValue(response.content.pending, asset, assetName) if (flags.all) { - this.log(`Account: ${response.content.account}`) - this.log(`Head Hash: ${response.content.blockHash || 'NULL'}`) - this.log(`Head Sequence: ${response.content.sequence || 'NULL'}`) - this.log(`Available: ${renderedAvailable}`) - this.log(`Confirmed: ${renderedConfirmed}`) - this.log(`Unconfirmed: ${renderedUnconfirmed}`) - this.log(`Pending: ${renderedPending}`) + this.log( + ui.card({ + Account: response.content.account, + 'Head Hash': response.content.blockHash || 'NULL', + 'Head Sequence': response.content.sequence || 'NULL', + Available: renderedAvailable, + Confirmed: renderedConfirmed, + Unconfirmed: renderedUnconfirmed, + Pending: renderedPending, + }), + ) return } - this.log(`Account: ${response.content.account}`) - this.log(`Available Balance: ${renderedAvailable}`) + this.log( + ui.card({ + Account: response.content.account, + 'Available Balance': renderedAvailable, + }), + ) } explainBalance(response: GetBalanceResponse, asset: RpcAsset, assetName: string): void { diff --git a/ironfish-cli/src/commands/wallet/balances.ts b/ironfish-cli/src/commands/wallet/balances.ts index a8f59762c6..ca96906f1f 100644 --- a/ironfish-cli/src/commands/wallet/balances.ts +++ b/ironfish-cli/src/commands/wallet/balances.ts @@ -2,11 +2,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import { BufferUtils, CurrencyUtils, GetBalancesResponse, RpcAsset } from '@ironfish/sdk' -import { Args, Flags, ux } from '@oclif/core' +import { Args, Flags } from '@oclif/core' import { IronfishCommand } from '../../command' import { RemoteFlags } from '../../flags' +import { table, TableColumns, TableFlags } from '../../ui' import { compareAssets, renderAssetWithVerificationStatus } from '../../utils' -import { TableFlags } from '../../utils/table' type AssetBalancePairs = { asset: RpcAsset; balance: GetBalancesResponse['balances'][number] } @@ -39,7 +39,7 @@ export class BalancesCommand extends IronfishCommand { async start(): Promise { const { flags, args } = await this.parse(BalancesCommand) - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() // TODO: remove account arg const account = flags.account ? flags.account : args.account @@ -64,7 +64,7 @@ export class BalancesCommand extends IronfishCommand { }) } - let columns: ux.Table.table.Columns = { + let columns: TableColumns = { assetName: { header: 'Asset Name', get: ({ asset }) => @@ -129,6 +129,6 @@ export class BalancesCommand extends IronfishCommand { ), ) - ux.table(assetBalancePairs, columns, { ...flags }) + table(assetBalancePairs, columns, { ...flags }) } } diff --git a/ironfish-cli/src/commands/wallet/burn.ts b/ironfish-cli/src/commands/wallet/burn.ts index d61a3fd368..5827df6420 100644 --- a/ironfish-cli/src/commands/wallet/burn.ts +++ b/ironfish-cli/src/commands/wallet/burn.ts @@ -13,7 +13,7 @@ import { import { Flags, ux } from '@oclif/core' import { IronfishCommand } from '../../command' import { IronFlag, RemoteFlags, ValueFlag } from '../../flags' -import { confirmOrQuit } from '../../ui' +import * as ui from '../../ui' import { selectAsset } from '../../utils/asset' import { promptCurrency } from '../../utils/currency' import { promptExpiration } from '../../utils/expiration' @@ -72,6 +72,12 @@ export class Burn extends IronfishCommand { description: 'Return raw transaction. Use it to create a transaction but not post to the network', }), + unsignedTransaction: Flags.boolean({ + default: false, + description: + 'Return a serialized UnsignedTransaction. Use it to create a transaction and build proofs but not post to the network', + exclusive: ['rawTransaction'], + }), expiration: Flags.integer({ char: 'e', description: @@ -89,7 +95,7 @@ export class Burn extends IronfishCommand { async start(): Promise { const { flags } = await this.parse(Burn) - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() if (!flags.offline) { const status = await client.wallet.getNodeStatus() @@ -173,7 +179,7 @@ export class Burn extends IronfishCommand { } let expiration = flags.expiration - if (flags.rawTransaction && expiration === undefined) { + if ((flags.rawTransaction || flags.unsignedTransaction) && expiration === undefined) { expiration = await promptExpiration({ logger: this.logger, client: client }) } @@ -219,6 +225,16 @@ export class Burn extends IronfishCommand { this.exit(0) } + if (flags.unsignedTransaction) { + const response = await client.wallet.buildTransaction({ + account, + rawTransaction: RawTransactionSerde.serialize(raw).toString('hex'), + }) + this.log('Unsigned Transaction') + this.log(response.content.unsignedTransaction) + this.exit(0) + } + await this.confirm(assetData, amount, raw.fee, account, flags.confirm) ux.action.start('Sending the transaction') @@ -252,10 +268,14 @@ export class Burn extends IronfishCommand { ) this.log(`Burned asset ${assetName} from ${account}`) - this.log(`Asset Identifier: ${assetId}`) - this.log(`Amount: ${renderedAmount}`) - this.log(`Hash: ${transaction.hash().toString('hex')}`) - this.log(`Fee: ${CurrencyUtils.render(transaction.fee(), true)}`) + this.log( + ui.card({ + 'Asset Identifier': assetId, + Amount: renderedAmount, + Hash: transaction.hash().toString('hex'), + Fee: CurrencyUtils.render(transaction.fee(), true), + }), + ) const networkId = (await client.chain.getNetworkInfo()).content.networkId const transactionUrl = getExplorer(networkId)?.getTransactionUrl( @@ -288,7 +308,7 @@ export class Burn extends IronfishCommand { const renderedAmount = CurrencyUtils.render(amount, true, asset.id, asset.verification) const renderedFee = CurrencyUtils.render(fee, true) - await confirmOrQuit( + await ui.confirmOrQuit( `You are about to burn ${renderedAmount} plus a transaction fee of ${renderedFee} with the account ${account}\nDo you confirm?`, confirm, ) diff --git a/ironfish-cli/src/commands/wallet/chainport/send.ts b/ironfish-cli/src/commands/wallet/chainport/send.ts index ffdfd61265..b613651778 100644 --- a/ironfish-cli/src/commands/wallet/chainport/send.ts +++ b/ironfish-cli/src/commands/wallet/chainport/send.ts @@ -17,7 +17,7 @@ import { Flags, ux } from '@oclif/core' import inquirer from 'inquirer' import { IronfishCommand } from '../../../command' import { HexFlag, IronFlag, RemoteFlags, ValueFlag } from '../../../flags' -import { confirmOrQuit } from '../../../ui' +import { confirmOrQuit, inputPrompt } from '../../../ui' import { selectAsset } from '../../../utils' import { ChainportBridgeTransaction, @@ -77,12 +77,16 @@ export class BridgeCommand extends IronfishCommand { description: 'The block sequence after which the transaction will be removed from the mempool. Set to 0 for no expiration.', }), + offline: Flags.boolean({ + default: false, + description: 'Allow offline transaction creation', + }), } async start(): Promise { const { flags } = await this.parse(BridgeCommand) - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() const networkId = (await client.chain.getNetworkInfo()).content.networkId @@ -173,9 +177,7 @@ export class BridgeCommand extends IronfishCommand { } if (!to) { - to = await ux.prompt('Enter the public address of the recipient', { - required: true, - }) + to = await inputPrompt('Enter the public address of the recipient', true) } if (!isEthereumAddress(to)) { diff --git a/ironfish-cli/src/commands/wallet/create.ts b/ironfish-cli/src/commands/wallet/create.ts index 01ebb8e5ed..fcb9758c6c 100644 --- a/ironfish-cli/src/commands/wallet/create.ts +++ b/ironfish-cli/src/commands/wallet/create.ts @@ -2,9 +2,10 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import { Args, ux } from '@oclif/core' +import { Args } from '@oclif/core' import { IronfishCommand } from '../../command' import { RemoteFlags } from '../../flags' +import { inputPrompt } from '../../ui' export class CreateCommand extends IronfishCommand { static description = `Create a new account for sending and receiving coins` @@ -25,12 +26,10 @@ export class CreateCommand extends IronfishCommand { let name = args.account if (!name) { - name = await ux.prompt('Enter the name of the account', { - required: true, - }) + name = await inputPrompt('Enter the name of the account', true) } - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() this.log(`Creating account ${name}`) const result = await client.wallet.createAccount({ name }) diff --git a/ironfish-cli/src/commands/wallet/delete.ts b/ironfish-cli/src/commands/wallet/delete.ts index 4f55289658..7aa7569a54 100644 --- a/ironfish-cli/src/commands/wallet/delete.ts +++ b/ironfish-cli/src/commands/wallet/delete.ts @@ -5,6 +5,7 @@ import { Args, Flags, ux } from '@oclif/core' import { IronfishCommand } from '../../command' import { RemoteFlags } from '../../flags' +import { inputPrompt } from '../../ui' export class DeleteCommand extends IronfishCommand { static description = `Permanently delete an account` @@ -32,14 +33,14 @@ export class DeleteCommand extends IronfishCommand { const { confirm, wait } = flags const { account } = args - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() ux.action.start(`Deleting account '${account}'`) const response = await client.wallet.removeAccount({ account, confirm, wait }) ux.action.stop() if (response.content.needsConfirm) { - const value = await ux.prompt(`Are you sure? Type ${account} to confirm`) + const value = await inputPrompt(`Are you sure? Type ${account} to confirm`) if (value !== account) { this.log(`Aborting: ${value} did not match ${account}`) diff --git a/ironfish-cli/src/commands/wallet/export.ts b/ironfish-cli/src/commands/wallet/export.ts index b48e363fd7..835e9cbacf 100644 --- a/ironfish-cli/src/commands/wallet/export.ts +++ b/ironfish-cli/src/commands/wallet/export.ts @@ -4,7 +4,6 @@ import { AccountFormat, ErrorUtils, LanguageUtils } from '@ironfish/sdk' import { Args, Flags } from '@oclif/core' import fs from 'fs' -import jsonColorizer from 'json-colorizer' import path from 'path' import { IronfishCommand } from '../../command' import { ColorFlag, ColorFlagKey, EnumLanguageKeyFlag, RemoteFlags } from '../../flags' @@ -12,6 +11,7 @@ import { confirmOrQuit } from '../../ui' export class ExportCommand extends IronfishCommand { static description = `Export an account` + static enableJsonFlag = true static flags = { ...RemoteFlags, @@ -29,10 +29,6 @@ export class ExportCommand extends IronfishCommand { required: false, choices: LanguageUtils.LANGUAGE_KEYS, }), - json: Flags.boolean({ - default: false, - description: 'Output the account as JSON, rather than the default bech32', - }), path: Flags.string({ description: 'The path to export the account to', required: false, @@ -50,9 +46,9 @@ export class ExportCommand extends IronfishCommand { }), } - async start(): Promise { + async start(): Promise { const { flags, args } = await this.parse(ExportCommand) - const { color, local, path: exportPath, viewonly: viewOnly } = flags + const { local, path: exportPath, viewonly: viewOnly } = flags const { account } = args if (flags.language) { @@ -65,7 +61,7 @@ export class ExportCommand extends IronfishCommand { ? AccountFormat.JSON : AccountFormat.Base64Json - const client = await this.sdk.connectRpc(local) + const client = await this.connectRpc(local) const response = await client.wallet.exportAccount({ account, viewOnly, @@ -73,10 +69,7 @@ export class ExportCommand extends IronfishCommand { language: flags.language, }) - let output = response.content.account - if (color && flags.json && !exportPath) { - output = jsonColorizer(output) - } + const output = response.content.account if (exportPath) { let resolved = this.sdk.fileSystem.resolve(exportPath) @@ -110,5 +103,9 @@ export class ExportCommand extends IronfishCommand { } this.log(output) + + if (flags.json) { + return output + } } } diff --git a/ironfish-cli/src/commands/wallet/import.ts b/ironfish-cli/src/commands/wallet/import.ts index 7866558fd4..535e5eaa11 100644 --- a/ironfish-cli/src/commands/wallet/import.ts +++ b/ironfish-cli/src/commands/wallet/import.ts @@ -1,11 +1,18 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import { RPC_ERROR_CODES, RpcRequestError } from '@ironfish/sdk' +import { + AccountFormat, + encodeAccountImport, + RPC_ERROR_CODES, + RpcRequestError, +} from '@ironfish/sdk' import { Args, Flags, ux } from '@oclif/core' import { IronfishCommand } from '../../command' import { RemoteFlags } from '../../flags' +import { inputPrompt } from '../../ui' import { importFile, importPipe, longPrompt } from '../../utils/input' +import { Ledger } from '../../utils/ledger' export class ImportCommand extends IronfishCommand { static description = `Import an account` @@ -26,6 +33,11 @@ export class ImportCommand extends IronfishCommand { createdAt: Flags.integer({ description: 'Block sequence to begin scanning from for the imported account', }), + ledger: Flags.boolean({ + description: 'import a view-only account from a ledger device', + default: false, + exclusive: ['path'], + }), } static args = { @@ -39,18 +51,27 @@ export class ImportCommand extends IronfishCommand { const { flags, args } = await this.parse(ImportCommand) const { blob } = args - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() let account: string - if (blob && blob.length !== 0 && flags.path && flags.path.length !== 0) { + if ( + blob && + blob.length !== 0 && + ((flags.path && flags.path.length !== 0) || flags.ledger) + ) { this.error( - `Your command includes an unexpected argument. Please pass either --path or the output of wallet:export.`, + `Your command includes an unexpected argument. Please pass only 1 of the following: + 1. the output of wallet:export OR + 2. --path to import an account from a file OR + 3. --ledger to import an account from a ledger device`, ) } if (blob) { account = blob + } else if (flags.ledger) { + account = await this.importLedger() } else if (flags.path) { account = await importFile(this.sdk.fileSystem, flags.path) } else if (process.stdin.isTTY) { @@ -72,9 +93,7 @@ export class ImportCommand extends IronfishCommand { this.log() this.log(`Found existing account with name '${flags.name}'`) - const name = await ux.prompt('Enter a different name for the account', { - required: true, - }) + const name = await inputPrompt('Enter a different name for the account', true) if (name === flags.name) { this.error(`Entered the same name: '${name}'`) } @@ -105,9 +124,7 @@ export class ImportCommand extends IronfishCommand { this.log(e.codeMessage) } - const name = await ux.prompt(message, { - required: true, - }) + const name = await inputPrompt(message, true) if (name === flags.name) { this.error(`Entered the same name: '${name}'`) } @@ -129,4 +146,19 @@ export class ImportCommand extends IronfishCommand { this.log(`Run "ironfish wallet:use ${name}" to set the account as default`) } } + + async importLedger(): Promise { + try { + const ledger = new Ledger(this.logger) + await ledger.connect() + const account = await ledger.importAccount() + return encodeAccountImport(account, AccountFormat.Base64Json) + } catch (e) { + if (e instanceof Error) { + this.error(e.message) + } else { + this.error('Unknown error while importing account from ledger device.') + } + } + } } diff --git a/ironfish-cli/src/commands/wallet/mint.ts b/ironfish-cli/src/commands/wallet/mint.ts index a97139eb89..0557493128 100644 --- a/ironfish-cli/src/commands/wallet/mint.ts +++ b/ironfish-cli/src/commands/wallet/mint.ts @@ -17,7 +17,7 @@ import { import { Flags, ux } from '@oclif/core' import { IronfishCommand } from '../../command' import { IronFlag, RemoteFlags, ValueFlag } from '../../flags' -import { confirmOrQuit, confirmPrompt } from '../../ui' +import * as ui from '../../ui' import { selectAsset } from '../../utils/asset' import { promptCurrency } from '../../utils/currency' import { promptExpiration } from '../../utils/expiration' @@ -106,11 +106,17 @@ export class Mint extends IronfishCommand { description: 'The public address of the account to transfer ownership of this asset to.', required: false, }), + unsignedTransaction: Flags.boolean({ + default: false, + description: + 'Return a serialized UnsignedTransaction. Use it to create a transaction and build proofs but not post to the network', + exclusive: ['rawTransaction'], + }), } async start(): Promise { const { flags } = await this.parse(Mint) - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() if (!flags.offline) { const status = await client.wallet.getNodeStatus() @@ -147,21 +153,16 @@ export class Mint extends IronfishCommand { // name is provided let isMintingNewAsset = Boolean(name || metadata) if (!assetId && !metadata && !name) { - isMintingNewAsset = await confirmPrompt('Do you want to create a new asset?') + isMintingNewAsset = await ui.confirmPrompt('Do you want to create a new asset?') } if (isMintingNewAsset) { if (!name) { - name = await ux.prompt('Enter the name for the new asset', { - required: true, - }) + name = await ui.inputPrompt('Enter the name for the new asset', true) } if (!metadata) { - metadata = await ux.prompt('Enter metadata for the new asset', { - default: '', - required: false, - }) + metadata = await ui.inputPrompt('Enter metadata for the new asset') } const newAsset = new Asset(accountPublicKey, name, metadata) @@ -234,7 +235,7 @@ export class Mint extends IronfishCommand { } let expiration = flags.expiration - if (flags.rawTransaction && expiration === undefined) { + if ((flags.rawTransaction || flags.unsignedTransaction) && expiration === undefined) { expiration = await promptExpiration({ logger: this.logger, client: client }) } @@ -284,6 +285,16 @@ export class Mint extends IronfishCommand { this.exit(0) } + if (flags.unsignedTransaction) { + const response = await client.wallet.buildTransaction({ + account, + rawTransaction: RawTransactionSerde.serialize(raw).toString('hex'), + }) + this.log('Unsigned Transaction') + this.log(response.content.unsignedTransaction) + this.exit(0) + } + await this.confirm( account, amount, @@ -328,10 +339,14 @@ export class Mint extends IronfishCommand { ) const renderedFee = CurrencyUtils.render(transaction.fee(), true) this.log(`Minted asset ${BufferUtils.toHuman(minted.asset.name())} from ${account}`) - this.log(`Asset Identifier: ${minted.asset.id().toString('hex')}`) - this.log(`Value: ${renderedValue}`) - this.log(`Fee: ${renderedFee}`) - this.log(`Hash: ${transaction.hash().toString('hex')}`) + this.log( + ui.card({ + 'Asset Identifier': minted.asset.id().toString('hex'), + Value: renderedValue, + Fee: renderedFee, + Hash: transaction.hash().toString('hex'), + }), + ) const networkId = (await client.chain.getNetworkInfo()).content.networkId const transactionUrl = getExplorer(networkId)?.getTransactionUrl( @@ -390,6 +405,6 @@ export class Mint extends IronfishCommand { confirmMessage.push('Do you confirm?') - await confirmOrQuit(confirmMessage.join('\n'), confirm) + await ui.confirmOrQuit(confirmMessage.join('\n'), confirm) } } diff --git a/ironfish-cli/src/commands/wallet/multisig/account/participants.ts b/ironfish-cli/src/commands/wallet/multisig/account/participants.ts index 80e11ef213..eca3361fc9 100644 --- a/ironfish-cli/src/commands/wallet/multisig/account/participants.ts +++ b/ironfish-cli/src/commands/wallet/multisig/account/participants.ts @@ -19,7 +19,7 @@ export class MultisigAccountParticipants extends IronfishCommand { async start(): Promise { const { flags } = await this.parse(MultisigAccountParticipants) - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() const response = await client.wallet.multisig.getAccountIdentities({ account: flags.account, diff --git a/ironfish-cli/src/commands/wallet/multisig/commitment/aggregate.ts b/ironfish-cli/src/commands/wallet/multisig/commitment/aggregate.ts index 5c70c2952b..f09021af7c 100644 --- a/ironfish-cli/src/commands/wallet/multisig/commitment/aggregate.ts +++ b/ironfish-cli/src/commands/wallet/multisig/commitment/aggregate.ts @@ -55,7 +55,7 @@ export class CreateSigningPackage extends IronfishCommand { } commitments = commitments.map((s) => s.trim()) - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() const signingPackageResponse = await client.wallet.multisig.createSigningPackage({ account: flags.account, diff --git a/ironfish-cli/src/commands/wallet/multisig/commitment/create.ts b/ironfish-cli/src/commands/wallet/multisig/commitment/create.ts index f307a15c4f..fff272cd81 100644 --- a/ironfish-cli/src/commands/wallet/multisig/commitment/create.ts +++ b/ironfish-cli/src/commands/wallet/multisig/commitment/create.ts @@ -69,7 +69,7 @@ export class CreateSigningCommitmentCommand extends IronfishCommand { }) } - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() const unsignedTransaction = new UnsignedTransaction( Buffer.from(unsignedTransactionInput, 'hex'), ) diff --git a/ironfish-cli/src/commands/wallet/multisig/dealer/create.ts b/ironfish-cli/src/commands/wallet/multisig/dealer/create.ts index ed4135d20f..1a41a274ca 100644 --- a/ironfish-cli/src/commands/wallet/multisig/dealer/create.ts +++ b/ironfish-cli/src/commands/wallet/multisig/dealer/create.ts @@ -6,6 +6,7 @@ import { AccountImport } from '@ironfish/sdk/src/wallet/exporter' import { Flags, ux } from '@oclif/core' import { IronfishCommand } from '../../../../command' import { RemoteFlags } from '../../../../flags' +import { inputPrompt } from '../../../../ui' import { longPrompt } from '../../../../utils/input' export class MultisigCreateDealer extends IronfishCommand { @@ -54,16 +55,14 @@ export class MultisigCreateDealer extends IronfishCommand { let minSigners = flags.minSigners if (!minSigners) { - const input = await ux.prompt('Enter the number of minimum signers', { - required: true, - }) + const input = await inputPrompt('Enter the number of minimum signers', true) minSigners = parseInt(input) if (isNaN(minSigners) || minSigners < 2) { this.error('Minimum number of signers must be at least 2') } } - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() const name = await this.getCoordinatorName(client, flags.name?.trim()) @@ -131,7 +130,7 @@ export class MultisigCreateDealer extends IronfishCommand { let name = inputName do { - name = name ?? (await ux.prompt('Enter a name for the coordinator', { required: true })) + name = name ?? (await inputPrompt('Enter a name for the coordinator', true)) if (accountNames.has(name)) { this.log(`Account with name ${name} already exists`) diff --git a/ironfish-cli/src/commands/wallet/multisig/dkg/round1.ts b/ironfish-cli/src/commands/wallet/multisig/dkg/round1.ts index fd92ba98b9..d03f4a06f8 100644 --- a/ironfish-cli/src/commands/wallet/multisig/dkg/round1.ts +++ b/ironfish-cli/src/commands/wallet/multisig/dkg/round1.ts @@ -1,9 +1,10 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import { Flags, ux } from '@oclif/core' +import { Flags } from '@oclif/core' import { IronfishCommand } from '../../../../command' import { RemoteFlags } from '../../../../flags' +import { inputPrompt } from '../../../../ui' import { longPrompt } from '../../../../utils/input' import { selectSecret } from '../../../../utils/multisig' @@ -32,7 +33,7 @@ export class DkgRound1Command extends IronfishCommand { async start(): Promise { const { flags } = await this.parse(DkgRound1Command) - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() let participantName = flags.participantName if (!participantName) { @@ -57,9 +58,7 @@ export class DkgRound1Command extends IronfishCommand { let minSigners = flags.minSigners if (!minSigners) { - const input = await ux.prompt('Enter the number of minimum signers', { - required: true, - }) + const input = await inputPrompt('Enter the number of minimum signers', true) minSigners = parseInt(input) if (isNaN(minSigners) || minSigners < 2) { this.error('Minimum number of signers must be at least 2') diff --git a/ironfish-cli/src/commands/wallet/multisig/dkg/round2.ts b/ironfish-cli/src/commands/wallet/multisig/dkg/round2.ts index 318003df48..ebc0f409c6 100644 --- a/ironfish-cli/src/commands/wallet/multisig/dkg/round2.ts +++ b/ironfish-cli/src/commands/wallet/multisig/dkg/round2.ts @@ -1,9 +1,10 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import { Flags, ux } from '@oclif/core' +import { Flags } from '@oclif/core' import { IronfishCommand } from '../../../../command' import { RemoteFlags } from '../../../../flags' +import { inputPrompt } from '../../../../ui' import { longPrompt } from '../../../../utils/input' import { selectSecret } from '../../../../utils/multisig' @@ -32,7 +33,7 @@ export class DkgRound2Command extends IronfishCommand { async start(): Promise { const { flags } = await this.parse(DkgRound2Command) - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() let participantName = flags.participantName if (!participantName) { @@ -41,9 +42,9 @@ export class DkgRound2Command extends IronfishCommand { let round1SecretPackage = flags.round1SecretPackage if (!round1SecretPackage) { - round1SecretPackage = await ux.prompt( + round1SecretPackage = await inputPrompt( `Enter the round 1 secret package for participant ${participantName}`, - { required: true }, + true, ) } diff --git a/ironfish-cli/src/commands/wallet/multisig/dkg/round3.ts b/ironfish-cli/src/commands/wallet/multisig/dkg/round3.ts index 29f1ef8d45..7cb163bcd3 100644 --- a/ironfish-cli/src/commands/wallet/multisig/dkg/round3.ts +++ b/ironfish-cli/src/commands/wallet/multisig/dkg/round3.ts @@ -1,9 +1,10 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import { Flags, ux } from '@oclif/core' +import { Flags } from '@oclif/core' import { IronfishCommand } from '../../../../command' import { RemoteFlags } from '../../../../flags' +import { inputPrompt } from '../../../../ui' import { longPrompt } from '../../../../utils/input' import { selectSecret } from '../../../../utils/multisig' @@ -42,7 +43,7 @@ export class DkgRound3Command extends IronfishCommand { async start(): Promise { const { flags } = await this.parse(DkgRound3Command) - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() let participantName = flags.participantName if (!participantName) { @@ -51,11 +52,9 @@ export class DkgRound3Command extends IronfishCommand { let round2SecretPackage = flags.round2SecretPackage if (!round2SecretPackage) { - round2SecretPackage = await ux.prompt( - `Enter the encrypted secret package for participant ${participantName}`, - { - required: true, - }, + round2SecretPackage = await inputPrompt( + `Enter the round 2 encrypted secret package for participant ${participantName}`, + true, ) } diff --git a/ironfish-cli/src/commands/wallet/multisig/participant/create.ts b/ironfish-cli/src/commands/wallet/multisig/participant/create.ts index f07828b885..5357cfcfc9 100644 --- a/ironfish-cli/src/commands/wallet/multisig/participant/create.ts +++ b/ironfish-cli/src/commands/wallet/multisig/participant/create.ts @@ -2,9 +2,10 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import { RPC_ERROR_CODES, RpcRequestError } from '@ironfish/sdk' -import { Flags, ux } from '@oclif/core' +import { Flags } from '@oclif/core' import { IronfishCommand } from '../../../../command' import { RemoteFlags } from '../../../../flags' +import { inputPrompt } from '../../../../ui' export class MultisigIdentityCreate extends IronfishCommand { static description = `Create a multisig participant identity` @@ -21,12 +22,10 @@ export class MultisigIdentityCreate extends IronfishCommand { const { flags } = await this.parse(MultisigIdentityCreate) let name = flags.name if (!name) { - name = await ux.prompt('Enter a name for the identity', { - required: true, - }) + name = await inputPrompt('Enter a name for the identity', true) } - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() let response while (!response) { try { @@ -38,9 +37,7 @@ export class MultisigIdentityCreate extends IronfishCommand { ) { this.log() this.log(e.codeMessage) - name = await ux.prompt('Enter a new name for the identity', { - required: true, - }) + name = await inputPrompt('Enter a new name for the identity', true) } else { throw e } diff --git a/ironfish-cli/src/commands/wallet/multisig/participant/index.ts b/ironfish-cli/src/commands/wallet/multisig/participant/index.ts index 7fa6698989..58241fcf41 100644 --- a/ironfish-cli/src/commands/wallet/multisig/participant/index.ts +++ b/ironfish-cli/src/commands/wallet/multisig/participant/index.ts @@ -20,7 +20,7 @@ export class MultisigIdentity extends IronfishCommand { async start(): Promise { const { flags } = await this.parse(MultisigIdentity) - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() if (flags.name) { const response = await client.wallet.multisig.getIdentity({ name: flags.name }) diff --git a/ironfish-cli/src/commands/wallet/multisig/participants/index.ts b/ironfish-cli/src/commands/wallet/multisig/participants/index.ts index 7c8e7c5bf8..806e499a28 100644 --- a/ironfish-cli/src/commands/wallet/multisig/participants/index.ts +++ b/ironfish-cli/src/commands/wallet/multisig/participants/index.ts @@ -1,9 +1,9 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import { ux } from '@oclif/core' import { IronfishCommand } from '../../../../command' import { RemoteFlags } from '../../../../flags' +import { table } from '../../../../ui' export class MultisigParticipants extends IronfishCommand { static description = 'List out all the participant names and identities' @@ -13,7 +13,7 @@ export class MultisigParticipants extends IronfishCommand { } async start(): Promise { - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() const response = await client.wallet.multisig.getIdentities() const participants = [] @@ -27,7 +27,7 @@ export class MultisigParticipants extends IronfishCommand { // sort identities by name participants.sort((a, b) => a.name.localeCompare(b.name)) - ux.table( + table( participants, { name: { diff --git a/ironfish-cli/src/commands/wallet/multisig/signature/aggregate.ts b/ironfish-cli/src/commands/wallet/multisig/signature/aggregate.ts index 53791127d3..7d22da5913 100644 --- a/ironfish-cli/src/commands/wallet/multisig/signature/aggregate.ts +++ b/ironfish-cli/src/commands/wallet/multisig/signature/aggregate.ts @@ -64,7 +64,7 @@ export class MultisigSign extends IronfishCommand { ux.action.start('Signing the multisig transaction') - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() const response = await client.wallet.multisig.aggregateSignatureShares({ account: flags.account, diff --git a/ironfish-cli/src/commands/wallet/multisig/signature/create.ts b/ironfish-cli/src/commands/wallet/multisig/signature/create.ts index 5d06bced33..39812cec25 100644 --- a/ironfish-cli/src/commands/wallet/multisig/signature/create.ts +++ b/ironfish-cli/src/commands/wallet/multisig/signature/create.ts @@ -46,7 +46,7 @@ export class CreateSignatureShareCommand extends IronfishCommand { signingPackageString = await longPrompt('Enter the signing package') } - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() const signingPackage = new multisig.SigningPackage(Buffer.from(signingPackageString, 'hex')) const unsignedTransaction = new UnsignedTransaction( diff --git a/ironfish-cli/src/commands/wallet/notes/combine.ts b/ironfish-cli/src/commands/wallet/notes/combine.ts index 4649d15256..c48a31dd61 100644 --- a/ironfish-cli/src/commands/wallet/notes/combine.ts +++ b/ironfish-cli/src/commands/wallet/notes/combine.ts @@ -12,11 +12,11 @@ import { TimeUtils, Transaction, } from '@ironfish/sdk' -import { Flags, ux } from '@oclif/core' +import { Flags } from '@oclif/core' import inquirer from 'inquirer' import { IronfishCommand } from '../../../command' import { HexFlag, IronFlag, RemoteFlags } from '../../../flags' -import { confirmOrQuit } from '../../../ui' +import { confirmOrQuit, inputPrompt, table } from '../../../ui' import { getAssetsByIDs, selectAsset } from '../../../utils' import { getExplorer } from '../../../utils/explorer' import { selectFee } from '../../../utils/fees' @@ -132,9 +132,7 @@ export class CombineNotesCommand extends IronfishCommand { // eslint-disable-next-line no-constant-condition while (true) { - const result = await ux.prompt('Enter the number of notes', { - required: true, - }) + const result = await inputPrompt('Enter the number of notes', true) const notesToCombine = parseInt(result) @@ -220,7 +218,7 @@ export class CombineNotesCommand extends IronfishCommand { async start(): Promise { const { flags } = await this.parse(CombineNotesCommand) - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() let to = flags.to let from = flags.account @@ -288,8 +286,7 @@ export class CombineNotesCommand extends IronfishCommand { const totalAmount = notes.reduce((acc, note) => acc + BigInt(note.value), 0n) - const memo = - flags.memo ?? (await ux.prompt('Enter the memo (or leave blank)', { required: false })) + const memo = flags.memo ?? (await inputPrompt('Enter the memo (or leave blank)')) const expiration = await this.calculateExpiration(client, spendPostTime, numberOfNotes) @@ -452,7 +449,7 @@ export class CombineNotesCommand extends IronfishCommand { if (resultingNotes) { this.log('') - ux.table( + table( resultingNotes, { hash: { diff --git a/ironfish-cli/src/commands/wallet/notes/index.ts b/ironfish-cli/src/commands/wallet/notes/index.ts index e0da85a6a4..a00d62efce 100644 --- a/ironfish-cli/src/commands/wallet/notes/index.ts +++ b/ironfish-cli/src/commands/wallet/notes/index.ts @@ -2,10 +2,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import { CurrencyUtils, RpcAsset } from '@ironfish/sdk' -import { Args, Flags, ux } from '@oclif/core' +import { Args, Flags } from '@oclif/core' import { IronfishCommand } from '../../../command' import { RemoteFlags } from '../../../flags' -import { TableCols, TableFlags } from '../../../utils/table' +import { table, TableFlags } from '../../../ui' +import { TableCols } from '../../../utils/table' const { sort: _, ...tableFlags } = TableFlags export class NotesCommand extends IronfishCommand { @@ -34,7 +35,7 @@ export class NotesCommand extends IronfishCommand { const assetLookup: Map = new Map() - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() const response = client.wallet.getAccountNotesStream({ account }) @@ -48,19 +49,22 @@ export class NotesCommand extends IronfishCommand { ) } - ux.table( + table( [note], { memo: { header: 'Memo', // Maximum memo length is 32 bytes minWidth: 33, + get: (row) => row.memo, }, sender: { header: 'Sender', + get: (row) => row.sender, }, transactionHash: { header: 'From Transaction', + get: (row) => row.transactionHash, }, isSpent: { header: 'Spent', @@ -86,6 +90,7 @@ export class NotesCommand extends IronfishCommand { }, noteHash: { header: 'Note Hash', + get: (row) => row.noteHash, }, nullifier: { header: 'Nullifier', diff --git a/ironfish-cli/src/commands/wallet/post.ts b/ironfish-cli/src/commands/wallet/post.ts index 0d31888ba3..8ff40c6322 100644 --- a/ironfish-cli/src/commands/wallet/post.ts +++ b/ironfish-cli/src/commands/wallet/post.ts @@ -57,7 +57,7 @@ export class PostCommand extends IronfishCommand { const serialized = Buffer.from(transaction, 'hex') const raw = RawTransactionSerde.deserialize(serialized) - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() const senderAddress = raw.sender() if (!senderAddress) { diff --git a/ironfish-cli/src/commands/wallet/prune.ts b/ironfish-cli/src/commands/wallet/prune.ts index de9c19ac88..9347b935a1 100644 --- a/ironfish-cli/src/commands/wallet/prune.ts +++ b/ironfish-cli/src/commands/wallet/prune.ts @@ -4,15 +4,11 @@ import { NodeUtils, TransactionStatus } from '@ironfish/sdk' import { Flags, ux } from '@oclif/core' import { IronfishCommand } from '../../command' -import { LocalFlags } from '../../flags' export default class PruneCommand extends IronfishCommand { static description = 'Removes expired transactions from the wallet' - static hidden = false - static flags = { - ...LocalFlags, dryrun: Flags.boolean({ default: false, description: 'Dry run prune first', @@ -54,7 +50,7 @@ export default class PruneCommand extends IronfishCommand { accounts = [account] } else { - accounts = node.wallet.listAccounts() + accounts = node.wallet.accounts } if (flags.expire) { diff --git a/ironfish-cli/src/commands/wallet/rename.ts b/ironfish-cli/src/commands/wallet/rename.ts index 18da1aa716..224913fe3c 100644 --- a/ironfish-cli/src/commands/wallet/rename.ts +++ b/ironfish-cli/src/commands/wallet/rename.ts @@ -27,7 +27,7 @@ export class RenameCommand extends IronfishCommand { const { args } = await this.parse(RenameCommand) const { account, newName } = args - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() await client.wallet.renameAccount({ account, newName }) this.log(`Account ${account} renamed to ${newName}`) } diff --git a/ironfish-cli/src/commands/wallet/rescan.ts b/ironfish-cli/src/commands/wallet/rescan.ts index 06fea5f00f..3761dbb22c 100644 --- a/ironfish-cli/src/commands/wallet/rescan.ts +++ b/ironfish-cli/src/commands/wallet/rescan.ts @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +import { setLogLevelFromConfig } from '@ironfish/sdk' import { Flags, ux } from '@oclif/core' import { IronfishCommand } from '../../command' import { RemoteFlags } from '../../flags' @@ -33,12 +34,18 @@ export class RescanCommand extends IronfishCommand { this.error('You cannot pass both --local and --no-follow') } - const client = await this.sdk.connectRpc(local) + const client = await this.connectRpc(local) ux.action.start('Asking node to start scanning', undefined, { stdout: true, }) + // Suppress log messages from the wallet scanner, to prevent those messages + // from interfering with the progress bar. This problem can occur only if + // not connected to a remote node (i.e. we're running with the in-memory + // rpc). + setLogLevelFromConfig('wallet:error') + const response = client.wallet.rescan({ follow }) const progress = new ProgressBar('Scanning blocks', { diff --git a/ironfish-cli/src/commands/wallet/reset.ts b/ironfish-cli/src/commands/wallet/reset.ts index b4af982e39..b7e57e3e7c 100644 --- a/ironfish-cli/src/commands/wallet/reset.ts +++ b/ironfish-cli/src/commands/wallet/reset.ts @@ -45,7 +45,7 @@ export class ResetCommand extends IronfishCommand { flags.confirm, ) - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() await client.wallet.resetAccount({ account, diff --git a/ironfish-cli/src/commands/wallet/scanning/off.ts b/ironfish-cli/src/commands/wallet/scanning/off.ts index 22fa58966c..7dc843fd31 100644 --- a/ironfish-cli/src/commands/wallet/scanning/off.ts +++ b/ironfish-cli/src/commands/wallet/scanning/off.ts @@ -23,7 +23,7 @@ export class ScanningOffCommand extends IronfishCommand { const { args } = await this.parse(ScanningOffCommand) const { account } = args - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() await client.wallet.setScanning({ account: account, diff --git a/ironfish-cli/src/commands/wallet/scanning/on.ts b/ironfish-cli/src/commands/wallet/scanning/on.ts index f4e5053236..58339bdd66 100644 --- a/ironfish-cli/src/commands/wallet/scanning/on.ts +++ b/ironfish-cli/src/commands/wallet/scanning/on.ts @@ -23,7 +23,7 @@ export class ScanningOnCommand extends IronfishCommand { const { args } = await this.parse(ScanningOnCommand) const { account } = args - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() await client.wallet.setScanning({ account: account, diff --git a/ironfish-cli/src/commands/wallet/send.ts b/ironfish-cli/src/commands/wallet/send.ts index 6ca3aa60af..fb442012be 100644 --- a/ironfish-cli/src/commands/wallet/send.ts +++ b/ironfish-cli/src/commands/wallet/send.ts @@ -8,18 +8,20 @@ import { isValidPublicAddress, RawTransaction, RawTransactionSerde, + RpcClient, TimeUtils, Transaction, } from '@ironfish/sdk' -import { Flags, ux } from '@oclif/core' +import { Flags } from '@oclif/core' import { IronfishCommand } from '../../command' import { HexFlag, IronFlag, RemoteFlags, ValueFlag } from '../../flags' -import { confirmOrQuit } from '../../ui' +import * as ui from '../../ui' import { selectAsset } from '../../utils/asset' import { promptCurrency } from '../../utils/currency' import { promptExpiration } from '../../utils/expiration' import { getExplorer } from '../../utils/explorer' import { selectFee } from '../../utils/fees' +import { Ledger } from '../../utils/ledger' import { getSpendPostTimeInMs, updateSpendPostTimeInMs } from '../../utils/spendPostTime' import { displayTransactionSummary, @@ -96,7 +98,6 @@ export class Send extends IronfishCommand { 'Return raw transaction. Use it to create a transaction but not post to the network', }), unsignedTransaction: Flags.boolean({ - hidden: true, default: false, description: 'Return a serialized UnsignedTransaction. Use it to create a transaction and build proofs but not post to the network', @@ -111,6 +112,10 @@ export class Send extends IronfishCommand { description: 'The note hashes to include in the transaction', multiple: true, }), + ledger: Flags.boolean({ + default: false, + description: 'Send a transaction using a Ledger device', + }), } async start(): Promise { @@ -119,7 +124,7 @@ export class Send extends IronfishCommand { let to = flags.to let from = flags.account - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() if (!flags.offline) { const status = await client.wallet.getNodeStatus() @@ -200,13 +205,10 @@ export class Send extends IronfishCommand { } if (!to) { - to = await ux.prompt('Enter the public address of the recipient', { - required: true, - }) + to = await ui.inputPrompt('Enter the public address of the recipient', true) } - const memo = - flags.memo ?? (await ux.prompt('Enter the memo (or leave blank)', { required: false })) + const memo = flags.memo ?? (await ui.inputPrompt('Enter the memo (or leave blank)')) if (!isValidPublicAddress(to)) { this.log(`A valid public address is required`) @@ -255,6 +257,8 @@ export class Send extends IronfishCommand { raw = RawTransactionSerde.deserialize(bytes) } + displayTransactionSummary(raw, assetData, amount, from, to, memo) + if (flags.rawTransaction) { this.log('Raw Transaction') this.log(RawTransactionSerde.serialize(raw).toString('hex')) @@ -272,7 +276,10 @@ export class Send extends IronfishCommand { this.exit(0) } - displayTransactionSummary(raw, assetData, amount, from, to, memo) + if (flags.ledger) { + await this.sendTransactionWithLedger(client, raw, from, flags.watch, flags.confirm) + this.exit(0) + } const spendPostTime = getSpendPostTimeInMs(this.sdk) @@ -286,7 +293,7 @@ export class Send extends IronfishCommand { ) } - await confirmOrQuit('', flags.confirm) + await ui.confirmOrQuit('', flags.confirm) transactionTimer.start() @@ -334,9 +341,13 @@ export class Send extends IronfishCommand { ) const renderedFee = CurrencyUtils.render(transaction.fee(), true) this.log(`Sent ${renderedAmount} to ${to} from ${from}`) - this.log(`Hash: ${transaction.hash().toString('hex')}`) - this.log(`Fee: ${renderedFee}`) - this.log(`Memo: ${memo}`) + this.log( + ui.card({ + Hash: transaction.hash().toString('hex'), + Fee: renderedFee, + Memo: memo, + }), + ) const networkId = (await client.chain.getNetworkInfo()).content.networkId const transactionUrl = getExplorer(networkId)?.getTransactionUrl( @@ -358,4 +369,83 @@ export class Send extends IronfishCommand { }) } } + + private async sendTransactionWithLedger( + client: RpcClient, + raw: RawTransaction, + from: string | undefined, + watch: boolean, + confirm: boolean, + ): Promise { + const ledger = new Ledger(this.logger) + try { + await ledger.connect() + } catch (e) { + if (e instanceof Error) { + this.error(e.message) + } else { + throw e + } + } + + const publicKey = (await client.wallet.getAccountPublicKey({ account: from })).content + .publicKey + + const ledgerPublicKey = await ledger.getPublicAddress() + + if (publicKey !== ledgerPublicKey) { + this.error( + `The public key on the ledger device does not match the public key of the account '${from}'`, + ) + } + + const buildTransactionResponse = await client.wallet.buildTransaction({ + account: from, + rawTransaction: RawTransactionSerde.serialize(raw).toString('hex'), + }) + + const unsignedTransaction = buildTransactionResponse.content.unsignedTransaction + + const signature = (await ledger.sign(unsignedTransaction)).toString('hex') + + this.log(`\nSignature: ${signature}`) + + const addSignatureResponse = await client.wallet.addSignature({ + unsignedTransaction, + signature, + }) + + const signedTransaction = addSignatureResponse.content.transaction + const bytes = Buffer.from(signedTransaction, 'hex') + + const transaction = new Transaction(bytes) + + this.log(`\nSigned Transaction: ${signedTransaction}`) + this.log(`\nHash: ${transaction.hash().toString('hex')}`) + this.log(`Fee: ${CurrencyUtils.render(transaction.fee(), true)}`) + + await ui.confirmOrQuit('', confirm) + + const addTransactionResponse = await client.wallet.addTransaction({ + transaction: signedTransaction, + broadcast: true, + }) + + if (addTransactionResponse.content.accepted === false) { + this.error( + `Transaction '${transaction.hash().toString('hex')}' was not accepted into the mempool`, + ) + } + + if (watch) { + this.log('') + + await watchTransaction({ + client, + logger: this.logger, + account: from, + hash: transaction.hash().toString('hex'), + }) + } + } } diff --git a/ironfish-cli/src/commands/wallet/sign.ts b/ironfish-cli/src/commands/wallet/sign.ts new file mode 100644 index 0000000000..5c80ca0935 --- /dev/null +++ b/ironfish-cli/src/commands/wallet/sign.ts @@ -0,0 +1,133 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +import { CurrencyUtils, RpcClient, Transaction } from '@ironfish/sdk' +import { Flags } from '@oclif/core' +import { IronfishCommand } from '../../command' +import { RemoteFlags } from '../../flags' +import { longPrompt } from '../../utils/input' +import { Ledger } from '../../utils/ledger' +import { renderTransactionDetails, watchTransaction } from '../../utils/transaction' + +export class SignTransaction extends IronfishCommand { + static description = `Sign an unsigned transaction` + static flags = { + ...RemoteFlags, + unsignedTransaction: Flags.string({ + char: 'u', + description: 'Unsigned transaction to sign.', + }), + ledger: Flags.boolean({ + description: 'Sign with a ledger device', + default: false, + }), + broadcast: Flags.boolean({ + default: false, + description: 'Broadcast the transaction to the network after signing', + }), + watch: Flags.boolean({ + default: false, + description: 'Wait for the transaction to be confirmed', + dependsOn: ['broadcast'], + }), + } + + async start(): Promise { + const { flags } = await this.parse(SignTransaction) + const client = await this.connectRpc() + + if (!flags.broadcast && flags.watch) { + this.error('Cannot use --watch without --broadcast') + } + + let unsignedTransaction = flags.unsignedTransaction + if (!unsignedTransaction) { + unsignedTransaction = await longPrompt('Enter the unsigned transaction', { + required: true, + }) + } + + let signedTransaction: string + let account: string + + if (flags.ledger) { + const response = await this.signWithLedger(client, unsignedTransaction) + signedTransaction = response.transaction + account = response.account + } else { + const response = await this.signWithAccount(client, unsignedTransaction) + signedTransaction = response.transaction + account = response.account + } + + const response = await client.wallet.addTransaction({ + transaction: signedTransaction, + broadcast: flags.broadcast, + }) + + const bytes = Buffer.from(signedTransaction, 'hex') + const transaction = new Transaction(bytes) + + this.log(`\nSigned Transaction: ${signedTransaction}`) + this.log(`\nHash: ${transaction.hash().toString('hex')}`) + this.log(`Fee: ${CurrencyUtils.render(transaction.fee(), true)}`) + + await renderTransactionDetails(client, transaction, account, this.logger) + + if (flags.broadcast && response.content.accepted === false) { + this.error( + `Transaction '${transaction.hash().toString('hex')}' was not accepted into the mempool`, + ) + } + + if (flags.watch) { + this.log('') + + await watchTransaction({ + client, + logger: this.logger, + account: account, + hash: transaction.hash().toString('hex'), + }) + } + } + + private async signWithAccount(client: RpcClient, unsignedTransaction: string) { + const response = await client.wallet.signTransaction({ + unsignedTransaction: unsignedTransaction, + }) + + return { + transaction: response.content.transaction, + account: response.content.account, + } + } + + private async signWithLedger(client: RpcClient, unsignedTransaction: string) { + const ledger = new Ledger(this.logger) + try { + await ledger.connect() + } catch (e) { + if (e instanceof Error) { + this.error(e.message) + } else { + throw e + } + } + + const signature = (await ledger.sign(unsignedTransaction)).toString('hex') + + this.log(`\nSignature: ${signature}`) + + const addSignatureResponse = await client.wallet.addSignature({ + unsignedTransaction, + signature, + }) + + return { + transaction: addSignatureResponse.content.transaction, + account: addSignatureResponse.content.account, + } + } +} diff --git a/ironfish-cli/src/commands/wallet/status.ts b/ironfish-cli/src/commands/wallet/status.ts index 9aa2a49b6d..ad53d7d637 100644 --- a/ironfish-cli/src/commands/wallet/status.ts +++ b/ironfish-cli/src/commands/wallet/status.ts @@ -1,11 +1,10 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import { ux } from '@oclif/core' import chalk from 'chalk' import { IronfishCommand } from '../../command' import { RemoteFlags } from '../../flags' -import { TableFlags } from '../../utils/table' +import { table, TableFlags } from '../../ui' export class StatusCommand extends IronfishCommand { static description = `Get status of all accounts` @@ -18,21 +17,24 @@ export class StatusCommand extends IronfishCommand { async start(): Promise { const { flags } = await this.parse(StatusCommand) - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() const response = await client.wallet.getAccountsStatus() - ux.table( + table( response.content.accounts, { name: { + get: (row) => row.name, header: 'Account Name', minWidth: 11, }, id: { + get: (row) => row.id, header: 'Account ID', }, viewOnly: { + get: (row) => row.viewOnly, header: 'View Only', }, headHash: { diff --git a/ironfish-cli/src/commands/wallet/transaction/import.ts b/ironfish-cli/src/commands/wallet/transaction/import.ts index 0baef7c2d5..e9b1232c93 100644 --- a/ironfish-cli/src/commands/wallet/transaction/import.ts +++ b/ironfish-cli/src/commands/wallet/transaction/import.ts @@ -9,7 +9,7 @@ import { importFile, importPipe, longPrompt } from '../../../utils/input' export class TransactionImportCommand extends IronfishCommand { static description = `Import a transaction into your wallet` - static aliases = ['wallet:transaction:add'] + static hiddenAliases = ['wallet:transaction:add'] static flags = { ...RemoteFlags, @@ -57,7 +57,7 @@ export class TransactionImportCommand extends IronfishCommand { } ux.action.start(`Importing transaction`) - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() const response = await client.wallet.addTransaction({ transaction, broadcast: flags.broadcast, diff --git a/ironfish-cli/src/commands/wallet/transaction/index.ts b/ironfish-cli/src/commands/wallet/transaction/index.ts index 9804bb67cc..a55b5c6ef4 100644 --- a/ironfish-cli/src/commands/wallet/transaction/index.ts +++ b/ironfish-cli/src/commands/wallet/transaction/index.ts @@ -12,6 +12,7 @@ import { import { Args, Flags, ux } from '@oclif/core' import { IronfishCommand } from '../../../command' import { RemoteFlags } from '../../../flags' +import * as ui from '../../../ui' import { displayChainportTransactionSummary, extractChainportDataFromTransaction, @@ -48,7 +49,7 @@ export class TransactionCommand extends IronfishCommand { // TODO: remove account arg const account = flags.account ? flags.account : args.account - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() const networkId = (await client.chain.getNetworkInfo()).content.networkId const response = await client.wallet.getAccountTransaction({ @@ -70,24 +71,27 @@ export class TransactionCommand extends IronfishCommand { const renderedFee = CurrencyUtils.render(transaction.fee, true) const explorerUrl = getExplorer(networkId)?.getTransactionUrl(hash) - this.log(`Transaction: ${hash}`) + const data: Record = { + Transaction: hash, + } if (explorerUrl) { - this.log(`Explorer: ${explorerUrl}`) + data['Explorer'] = explorerUrl } - this.log(`Account: ${response.content.account}`) - this.log(`Status: ${transaction.status}`) - this.log(`Type: ${transaction.type}`) - this.log(`Timestamp: ${TimeUtils.renderString(transaction.timestamp)}`) - this.log(`Fee: ${renderedFee}`) + data['Account'] = response.content.account + data['Status'] = transaction.status + data['Type'] = transaction.type + data['Timestamp'] = TimeUtils.renderString(transaction.timestamp) + data['Fee'] = renderedFee if (transaction.blockHash && transaction.blockSequence) { - this.log(`Block Hash: ${transaction.blockHash}`) - this.log(`Block Sequence: ${transaction.blockSequence}`) + data['Block Hash'] = transaction.blockHash + data['Block Sequence'] = transaction.blockSequence } - this.log(`Notes Count: ${transaction.notes.length}`) - this.log(`Spends Count: ${transaction.spends.length}`) - this.log(`Mints Count: ${transaction.mints.length}`) - this.log(`Burns Count: ${transaction.burns.length}`) - this.log(`Sender: ${transaction.notes[0].sender}`) + data['Notes Count'] = transaction.notes.length + data['Spends Count'] = transaction.spends.length + data['Mints Count'] = transaction.mints.length + data['Burns Count'] = transaction.burns.length + data['Sender'] = transaction.notes[0].sender + this.log(ui.card(data)) const chainportTxnDetails = extractChainportDataFromTransaction(networkId, transaction) @@ -126,7 +130,7 @@ export class TransactionCommand extends IronfishCommand { }) } - ux.table(noteAssetPairs, { + ui.table(noteAssetPairs, { amount: { header: 'Amount', get: ({ asset, note }) => @@ -157,7 +161,7 @@ export class TransactionCommand extends IronfishCommand { if (transaction.spends.length > 0) { this.log(`\n---Spends---\n`) - ux.table(transaction.spends, { + ui.table(transaction.spends, { size: { header: 'Size', get: (spend) => spend.size, @@ -183,9 +187,10 @@ export class TransactionCommand extends IronfishCommand { ) this.log(`\n---Asset Balance Deltas---\n`) - ux.table(assetBalanceDeltas, { + ui.table(assetBalanceDeltas, { assetId: { header: 'Asset ID', + get: (assetBalanceDelta) => assetBalanceDelta.assetId, }, delta: { header: 'Balance Change', diff --git a/ironfish-cli/src/commands/wallet/transaction/view.ts b/ironfish-cli/src/commands/wallet/transaction/view.ts index 7f13d96f05..6ac2e81332 100644 --- a/ironfish-cli/src/commands/wallet/transaction/view.ts +++ b/ironfish-cli/src/commands/wallet/transaction/view.ts @@ -39,7 +39,7 @@ export class TransactionViewCommand extends IronfishCommand { async start(): Promise { const { flags } = await this.parse(TransactionViewCommand) - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() const account = flags.account ?? (await this.selectAccount(client)) diff --git a/ironfish-cli/src/commands/wallet/transaction/watch.ts b/ironfish-cli/src/commands/wallet/transaction/watch.ts index f8d82600dc..46b80853d2 100644 --- a/ironfish-cli/src/commands/wallet/transaction/watch.ts +++ b/ironfish-cli/src/commands/wallet/transaction/watch.ts @@ -38,7 +38,7 @@ export class WatchTxCommand extends IronfishCommand { // TODO: remove account arg const account = flags.account ? flags.account : args.account - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() await watchTransaction({ client, diff --git a/ironfish-cli/src/commands/wallet/transactions.ts b/ironfish-cli/src/commands/wallet/transactions.ts index a1513e1ce9..49cff44e0d 100644 --- a/ironfish-cli/src/commands/wallet/transactions.ts +++ b/ironfish-cli/src/commands/wallet/transactions.ts @@ -10,12 +10,13 @@ import { RpcAsset, TransactionType, } from '@ironfish/sdk' -import { Args, Flags, ux } from '@oclif/core' +import { Args, Flags } from '@oclif/core' import { IronfishCommand } from '../../command' import { RemoteFlags } from '../../flags' +import { table, TableColumns, TableFlags } from '../../ui' import { getAssetsByIDs } from '../../utils' import { extractChainportDataFromTransaction } from '../../utils/chainport' -import { Format, TableCols, TableFlags } from '../../utils/table' +import { Format, TableCols } from '../../utils/table' const { sort: _, ...tableFlags } = TableFlags export class TransactionsCommand extends IronfishCommand { @@ -68,11 +69,9 @@ export class TransactionsCommand extends IronfishCommand { ? Format.csv : flags.output === 'json' ? Format.json - : flags.output === 'yaml' - ? Format.yaml : Format.cli - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() const networkId = (await client.chain.getNetworkInfo()).content.networkId @@ -120,7 +119,7 @@ export class TransactionsCommand extends IronfishCommand { transactionRows = this.getTransactionRows(assetLookup, transaction, format) } - ux.table(transactionRows, columns, { + table(transactionRows, columns, { printLine: this.log.bind(this), ...flags, 'no-header': !showHeader, @@ -260,48 +259,57 @@ export class TransactionsCommand extends IronfishCommand { extended: boolean, notes: boolean, format: Format, - ): ux.Table.table.Columns> { - let columns: ux.Table.table.Columns> = { + ): TableColumns> { + let columns: TableColumns> = { timestamp: TableCols.timestamp({ streaming: true, }), status: { header: 'Status', minWidth: 12, + get: (row) => row.status ?? '', }, type: { header: 'Type', minWidth: notes ? 18 : 8, + get: (row) => row.type ?? '', }, hash: { header: 'Hash', minWidth: 32, + get: (row) => row.hash ?? '', }, notesCount: { header: 'Notes', minWidth: 5, extended: true, + get: (row) => row.notesCount ?? '', }, spendsCount: { header: 'Spends', minWidth: 5, extended: true, + get: (row) => row.spendsCount ?? '', }, mintsCount: { header: 'Mints', minWidth: 5, extended: true, + get: (row) => row.mintsCount ?? '', }, burnsCount: { header: 'Burns', minWidth: 5, extended: true, + get: (row) => row.burnsCount ?? '', }, expiration: { header: 'Expiration', + get: (row) => row.expiration ?? '', }, submittedSequence: { header: 'Submitted Sequence', + get: (row) => row.submittedSequence ?? '', }, feePaid: { header: 'Fee Paid ($IRON)', @@ -327,12 +335,15 @@ export class TransactionsCommand extends IronfishCommand { ...columns, sender: { header: 'Sender Address', + get: (row) => row.sender ?? '', }, recipient: { header: 'Recipient Address', + get: (row) => row.recipient ?? '', }, memo: { header: 'Memo', + get: (row) => row.memo ?? '', }, } } @@ -342,6 +353,7 @@ export class TransactionsCommand extends IronfishCommand { group: { header: '', minWidth: 3, + get: (row) => row.group ?? '', }, ...columns, } @@ -385,4 +397,5 @@ type TransactionRow = { submittedSequence: number sender: string recipient: string + memo?: string } diff --git a/ironfish-cli/src/commands/wallet/use.ts b/ironfish-cli/src/commands/wallet/use.ts index ffda39750a..165f8d6c60 100644 --- a/ironfish-cli/src/commands/wallet/use.ts +++ b/ironfish-cli/src/commands/wallet/use.ts @@ -23,7 +23,7 @@ export class UseCommand extends IronfishCommand { const { args } = await this.parse(UseCommand) const { account } = args - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() await client.wallet.useAccount({ account }) this.log(`The default account is now: ${account}`) } diff --git a/ironfish-cli/src/commands/wallet/which.ts b/ironfish-cli/src/commands/wallet/which.ts index 404386120c..3317328aec 100644 --- a/ironfish-cli/src/commands/wallet/which.ts +++ b/ironfish-cli/src/commands/wallet/which.ts @@ -23,7 +23,7 @@ export class WhichCommand extends IronfishCommand { async start(): Promise { const { flags } = await this.parse(WhichCommand) - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() const { content: { diff --git a/ironfish-cli/src/commands/workers/status.ts b/ironfish-cli/src/commands/workers/status.ts index 58ac797133..69446c663a 100644 --- a/ironfish-cli/src/commands/workers/status.ts +++ b/ironfish-cli/src/commands/workers/status.ts @@ -23,7 +23,7 @@ export default class Status extends IronfishCommand { const { flags } = await this.parse(Status) if (!flags.follow) { - const client = await this.sdk.connectRpc() + const client = await this.connectRpc() const response = await client.worker.getWorkersStatus() this.log(renderStatus(response.content)) this.exit(0) diff --git a/ironfish-cli/src/flags.ts b/ironfish-cli/src/flags.ts index b4920b456c..f8ee624c88 100644 --- a/ironfish-cli/src/flags.ts +++ b/ironfish-cli/src/flags.ts @@ -34,6 +34,7 @@ export const VerboseFlag = Flags.boolean({ char: 'v', default: false, description: 'Set logging level to verbose', + helpGroup: 'GLOBAL', }) export const ColorFlag = Flags.boolean({ @@ -45,6 +46,7 @@ export const ColorFlag = Flags.boolean({ export const ConfigFlag = Flags.string({ default: DEFAULT_CONFIG_NAME, description: 'The name of the config file to use', + helpGroup: 'GLOBAL', }) export const DataDirFlag = Flags.string({ @@ -52,6 +54,7 @@ export const DataDirFlag = Flags.string({ default: DEFAULT_DATA_DIR, description: 'The path to the data dir', env: 'IRONFISH_DATA_DIR', + helpGroup: 'GLOBAL', }) export const RpcUseIpcFlag = Flags.boolean({ @@ -96,24 +99,11 @@ export const RpcUseHttpFlag = Flags.boolean({ allowNo: true, }) -/** - * These flags should usually be used on any command that starts a node, - * or uses a database to execute the command - */ -export const LocalFlags = { - [VerboseFlagKey]: VerboseFlag, - [ConfigFlagKey]: ConfigFlag, - [DataDirFlagKey]: DataDirFlag, -} - /** * These flags should usually be used on any command that uses an * RPC client to connect to a node to run the command */ export const RemoteFlags = { - [VerboseFlagKey]: VerboseFlag, - [ConfigFlagKey]: ConfigFlag, - [DataDirFlagKey]: DataDirFlag, [RpcUseTcpFlagKey]: RpcUseTcpFlag, [RpcUseIpcFlagKey]: RpcUseIpcFlag, [RpcTcpHostFlagKey]: RpcTcpHostFlag, diff --git a/ironfish-cli/src/testHarness.ts b/ironfish-cli/src/testHarness.ts new file mode 100644 index 0000000000..f89eb8062d --- /dev/null +++ b/ironfish-cli/src/testHarness.ts @@ -0,0 +1,25 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +import type { Jest } from '@jest/environment' +import type { JestExpect } from '@jest/expect' +import type { Global } from '@jest/types' + +declare global { + const { + it, + test, + fit, + xit, + xtest, + describe, + xdescribe, + fdescribe, + beforeAll, + beforeEach, + afterEach, + afterAll, + }: Global.GlobalAdditions + const expect: JestExpect + const jest: Jest +} diff --git a/ironfish-cli/src/ui/card.ts b/ironfish-cli/src/ui/card.ts new file mode 100644 index 0000000000..528f3c0bfc --- /dev/null +++ b/ironfish-cli/src/ui/card.ts @@ -0,0 +1,18 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +export function card(items: Record, extraPadding: number = 2): string { + const keys = Object.keys(items) + const longestKey = keys.reduce((p, c) => Math.max(p, c.length), 0) + + const result = [] + + for (const key of keys) { + const keyPadded = (key + ':').padEnd(longestKey + 1 + extraPadding) + const value = String(items[key]) + result.push(`${keyPadded} ${value}`) + } + + return result.join('\n') +} diff --git a/ironfish-cli/src/ui/index.ts b/ironfish-cli/src/ui/index.ts new file mode 100644 index 0000000000..1b524bebe7 --- /dev/null +++ b/ironfish-cli/src/ui/index.ts @@ -0,0 +1,9 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +export * from './card' +export * from './json' +export * from './progressBar' +export * from './prompt' +export * from './table' diff --git a/ironfish-cli/src/ui/json.ts b/ironfish-cli/src/ui/json.ts new file mode 100644 index 0000000000..70b0838e28 --- /dev/null +++ b/ironfish-cli/src/ui/json.ts @@ -0,0 +1,16 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +import jsonColorizer from 'json-colorizer' + +export function json(data: unknown): string { + let output = data + + // Only try to stringify JSON output if it is not already a string + if (typeof data !== 'string') { + output = JSON.stringify(data, undefined, ' ') + } + + return jsonColorizer(output) +} diff --git a/ironfish-cli/src/ui.ts b/ironfish-cli/src/ui/progressBar.ts similarity index 71% rename from ironfish-cli/src/ui.ts rename to ironfish-cli/src/ui/progressBar.ts index cfb5ee226e..b7c0b15e2b 100644 --- a/ironfish-cli/src/ui.ts +++ b/ironfish-cli/src/ui/progressBar.ts @@ -3,28 +3,26 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import { Assert, Meter, TimeUtils } from '@ironfish/sdk' -import { ux } from '@oclif/core' import * as cliProgress from 'cli-progress' -import inquirer from 'inquirer' -const progressBarCompleteChar = '\u2588' -const progressBarIncompleteChar = '\u2591' +const PROGRESS_BAR_COMPLETE_CHAR = '\u2588' +const PROGRESS_BAR_INCOMPLETE_CHAR = '\u2591' export const ProgressBarPresets = { basic: { - barCompleteChar: progressBarCompleteChar, - barIncompleteChar: progressBarIncompleteChar, + barCompleteChar: PROGRESS_BAR_COMPLETE_CHAR, + barIncompleteChar: PROGRESS_BAR_INCOMPLETE_CHAR, format: '{title}: [{bar}] {percentage}% | ETA: {estimate}', }, default: { - barCompleteChar: progressBarCompleteChar, - barIncompleteChar: progressBarIncompleteChar, + barCompleteChar: PROGRESS_BAR_COMPLETE_CHAR, + barIncompleteChar: PROGRESS_BAR_INCOMPLETE_CHAR, format: '{title}: [{bar}] {percentage}% | {formattedValue} / {formattedTotal} | ETA: {estimate}', }, withSpeed: { - barCompleteChar: progressBarCompleteChar, - barIncompleteChar: progressBarIncompleteChar, + barCompleteChar: PROGRESS_BAR_COMPLETE_CHAR, + barIncompleteChar: PROGRESS_BAR_INCOMPLETE_CHAR, format: '{title}: [{bar}] {percentage}% | {formattedValue} / {formattedTotal} | {speed} / sec | ETA: {estimate}', }, @@ -111,28 +109,3 @@ export class ProgressBar { this.bar.setTotal(total) } } - -export async function confirmPrompt(message: string): Promise { - const result: { prompt: boolean } = await inquirer.prompt({ - type: 'confirm', - // Add a new-line for readability, manually. If the prefix is set to a new-line, it seems to - // add a space before the message, which is unwanted. - message: `\n${message}`, - name: 'prompt', - prefix: '', - }) - return result.prompt -} - -export async function confirmOrQuit(message?: string, confirm?: boolean): Promise { - if (confirm) { - return - } - - const confirmed = await confirmPrompt(message || 'Do you confirm?') - - if (!confirmed) { - ux.log('Operation aborted.') - ux.exit(0) - } -} diff --git a/ironfish-cli/src/ui/prompt.ts b/ironfish-cli/src/ui/prompt.ts new file mode 100644 index 0000000000..d0b201497e --- /dev/null +++ b/ironfish-cli/src/ui/prompt.ts @@ -0,0 +1,54 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +import { ux } from '@oclif/core' +import inquirer from 'inquirer' + +async function _inputPrompt(message: string): Promise { + const result: { prompt: string } = await inquirer.prompt({ + type: 'input', + name: 'prompt', + message: `${message}:`, + }) + return result.prompt.trim() +} + +export async function inputPrompt(message: string, required: boolean = false): Promise { + let userInput: string = '' + + if (required) { + while (!userInput) { + userInput = await _inputPrompt(message) + } + } else { + userInput = await _inputPrompt(message) + } + + return userInput +} + +export async function confirmPrompt(message: string): Promise { + const result: { prompt: boolean } = await inquirer.prompt({ + type: 'confirm', + // Add a new-line for readability, manually. If the prefix is set to a new-line, it seems to + // add a space before the message, which is unwanted. + message: `\n${message}`, + name: 'prompt', + prefix: '', + }) + return result.prompt +} + +export async function confirmOrQuit(message?: string, confirm?: boolean): Promise { + if (confirm) { + return + } + + const confirmed = await confirmPrompt(message || 'Do you confirm?') + + if (!confirmed) { + ux.stdout('Operation aborted.') + ux.exit(0) + } +} diff --git a/ironfish-cli/src/ui/table.ts b/ironfish-cli/src/ui/table.ts new file mode 100644 index 0000000000..c105dd4dc4 --- /dev/null +++ b/ironfish-cli/src/ui/table.ts @@ -0,0 +1,251 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +import { Assert } from '@ironfish/sdk' +import { Flags, ux } from '@oclif/core' +import chalk from 'chalk' +import { orderBy } from 'natural-orderby' +import stringWidth from 'string-width' + +const WIDE_DASH = '─' + +export interface TableColumn> { + // The return type of this function can be extended, it's really just to avoid + // being `unknown`. Anything that has a `.toString()` function can be added + // here with no extra changes. + get(this: void, row: T): string | number | bigint | boolean + header: string + extended?: boolean + minWidth?: number +} + +export type TableColumns> = { [key: string]: TableColumn } + +export interface TableOptions { + [key: string]: unknown + extended?: boolean + 'no-header'?: boolean + output?: string + printLine?(this: void, s: unknown): unknown + sort?: string +} + +export const TableFlags = { + csv: Flags.boolean({ + description: 'output is csv format [alias: --output=csv]', + }), + extended: Flags.boolean({ + description: 'show extra columns', + }), + 'no-header': Flags.boolean({ + description: 'hide table header from output', + exclusive: ['csv'], + }), + output: Flags.string({ + description: 'output in a more machine friendly format', + exclusive: ['csv'], + options: ['csv', 'json'], + }), + sort: Flags.string({ + description: "property to sort by (prepend '-' for descending)", + }), +} + +export function table>( + data: T[], + columns: TableColumns, + options: TableOptions = {}, +): void { + new Table(data, columns, options).render() +} + +class Table> { + data: T[] + columns: (TableColumn & { extended: boolean; key: string; width?: number })[] + options: TableOptions & { extended: boolean; printLine(s: unknown): unknown } + + constructor(data: T[], columns: TableColumns, options: TableOptions) { + this.data = data + this.columns = Object.entries(columns).map(([key, column]) => { + const extended = column.extended || false + return { + ...column, + extended, + key, + } + }) + this.options = { + extended: options.extended || false, + 'no-header': options['no-header'], + output: options.csv ? 'csv' : options.output, + printLine: options.printLine ?? ux.stdout.bind(ux), + sort: options.sort, + } + } + + render() { + // Generate the rendered text to be displayed + let rows: Record[] = [] + for (const data of this.data) { + const row: Record = {} + for (const column of this.columns) { + // Only show columns marked as extended if the table is set to show + // extended columns + if (!this.options.extended && column.extended === true) { + continue + } + row[column.key] = column.get(data).toString() + } + rows.push(row) + } + + // Sort the rows given the column to sort by + if (this.options.sort) { + let sortOrder: 'asc' | 'desc' + let header: string + if (this.options.sort[0] === '-') { + sortOrder = 'desc' + header = this.options.sort.slice(1) + } else { + sortOrder = 'asc' + header = this.options.sort + } + + const column = this.columns.find((c) => c.header.toLowerCase() === header.toLowerCase()) + Assert.isNotUndefined(column, `No column found with name '${header}'`) + + rows = orderBy(rows, column.key, sortOrder) + } + + switch (this.options.output) { + case 'csv': { + this.renderCsv(rows) + break + } + + case 'json': { + this.renderJson(rows) + break + } + + default: { + this.renderTerminal(rows) + } + } + } + + renderCsv(rows: Record[]) { + const columnHeaders = [] + for (const column of this.columns) { + // Only show columns marked as extended if the table is set to show + // extended columns + if (!this.options.extended && column.extended === true) { + continue + } + columnHeaders.push(sanitizeCsvValue(column.header)) + } + this.options.printLine(columnHeaders.join(',')) + + for (const row of rows) { + const rowValues = [] + for (const value of Object.values(row)) { + rowValues.push(sanitizeCsvValue(value)) + } + this.options.printLine(rowValues.join(',')) + } + } + + renderJson(rows: Record[]) { + this.options.printLine(JSON.stringify(rows, null, 2)) + } + + renderTerminal(rows: Record[]) { + // Find column lengths + for (const column of this.columns) { + column.width = maxColumnLength(column, rows) + } + + if (!this.options['no-header']) { + // Print headers + const columnHeaders = [] + for (const column of this.columns) { + // Only show columns marked as extended if the table is set to show + // extended columns + if (!this.options.extended && column.extended === true) { + continue + } + Assert.isNotUndefined(column.width) + const spacerLength = column.width - stringWidth(column.header) + columnHeaders.push(`${column.header}${' '.repeat(spacerLength)}`) + } + this.options.printLine(chalk.bold(` ${columnHeaders.join(' ')}`)) + + // Print header underline + const columnUnderlines = [] + for (const column of this.columns) { + // Only show columns marked as extended if the table is set to show + // extended columns + if (!this.options.extended && column.extended === true) { + continue + } + Assert.isNotUndefined(column.width) + columnUnderlines.push(WIDE_DASH.repeat(column.width)) + } + this.options.printLine(chalk.bold(` ${columnUnderlines.join(' ')}`)) + } + + // Print rows + for (const row of rows) { + const rowValues = [] + for (const [key, value] of Object.entries(row)) { + const column = this.columns.find((c) => c.key === key) + Assert.isNotUndefined(column) + Assert.isNotUndefined(column.width) + const spacerLength = column.width - stringWidth(value) + rowValues.push(`${value}${' '.repeat(spacerLength)}`) + } + this.options.printLine(` ${rowValues.join(' ')}`) + } + } +} + +function maxColumnLength>( + column: { key: string; header: string; minWidth?: number }, + data: T[], +): number { + let maxLength = stringWidth(column.header) + + for (const row of data) { + const length = stringWidth(row[column.key]) + if (length > maxLength) { + maxLength = length + } + } + + if (column.minWidth != null && column.minWidth > maxLength) { + return column.minWidth + } + + return maxLength +} + +function sanitizeCsvValue(value: string): string { + const newValue = value + + // Double-quotes must be escaped with another double-quote + newValue.replace('"', '""') + + // If the value contains any of these special characters, it needs to be + // wrapped in double-quotes + if ( + newValue.includes('"') || + newValue.includes('\r') || + newValue.includes('\n') || + newValue.includes(',') + ) { + return `"${newValue}"` + } + + return newValue +} diff --git a/ironfish-cli/src/utils/chainport/utils.test.ts b/ironfish-cli/src/utils/chainport/utils.test.ts index 53582df2e6..74ef594fef 100644 --- a/ironfish-cli/src/utils/chainport/utils.test.ts +++ b/ironfish-cli/src/utils/chainport/utils.test.ts @@ -1,6 +1,7 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +import type { Mock } from 'jest-mock' import { RpcWalletNote, RpcWalletTransaction, TransactionType } from '@ironfish/sdk' import { getConfig } from './config' import { ChainportMemoMetadata } from './metadata' @@ -16,7 +17,7 @@ describe('isChainportTransaction', () => { } beforeEach(() => { - ;(getConfig as jest.Mock).mockReturnValue(mockConfig) + ;(getConfig as Mock).mockReturnValue(mockConfig) }) it('should return false for non-SEND/RECEIVE transactions', () => { @@ -42,7 +43,7 @@ describe('isChainportTransaction', () => { }) it('should return true for valid incoming chainport transaction', () => { - ;(ChainportMemoMetadata.decode as jest.Mock).mockReturnValue([1, 'address']) + ;(ChainportMemoMetadata.decode as Mock).mockReturnValue([1, 'address']) const transaction = { type: TransactionType.RECEIVE, @@ -92,7 +93,7 @@ describe('isChainportTransaction', () => { }) it('should return true for valid outgoing chainport transaction', () => { - ;(ChainportMemoMetadata.decode as jest.Mock).mockReturnValue([1, 'address']) + ;(ChainportMemoMetadata.decode as Mock).mockReturnValue([1, 'address']) const transaction = { type: TransactionType.SEND, notes: [ diff --git a/ironfish-cli/src/utils/currency.ts b/ironfish-cli/src/utils/currency.ts index da1720128f..67740de52a 100644 --- a/ironfish-cli/src/utils/currency.ts +++ b/ironfish-cli/src/utils/currency.ts @@ -4,7 +4,7 @@ import { Asset } from '@ironfish/rust-nodejs' import { Assert, CurrencyUtils, Logger, RpcAssetVerification, RpcClient } from '@ironfish/sdk' -import { ux } from '@oclif/core' +import { inputPrompt } from '../ui' /** * This prompts the user to enter an amount of currency in the major @@ -57,9 +57,7 @@ export async function promptCurrency(options: { // eslint-disable-next-line no-constant-condition while (true) { - const input = await ux.prompt(text, { - required: options.required, - }) + const input = await inputPrompt(text, options.required) if (!input) { return null diff --git a/ironfish-cli/src/utils/expiration.ts b/ironfish-cli/src/utils/expiration.ts index 4ce9720297..1755d58c4f 100644 --- a/ironfish-cli/src/utils/expiration.ts +++ b/ironfish-cli/src/utils/expiration.ts @@ -3,7 +3,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import { Logger, RpcClient } from '@ironfish/sdk' -import { ux } from '@oclif/core' +import { inputPrompt } from '../ui' export async function promptExpiration(options: { client: RpcClient @@ -17,7 +17,7 @@ export async function promptExpiration(options: { const prompt = `Enter an expiration block sequence for the transaction. You can also enter 0 for no expiration, or leave blank to use the default. The current chain head is ${headSequence}` - const input = await ux.prompt(prompt, { required: false }) + const input = await inputPrompt(prompt) if (!input) { return } diff --git a/ironfish-cli/src/utils/ledger.ts b/ironfish-cli/src/utils/ledger.ts new file mode 100644 index 0000000000..fe472383ec --- /dev/null +++ b/ironfish-cli/src/utils/ledger.ts @@ -0,0 +1,162 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +import { createRootLogger, Logger } from '@ironfish/sdk' +import { AccountImport } from '@ironfish/sdk/src/wallet/exporter' +import TransportNodeHid from '@ledgerhq/hw-transport-node-hid' +import IronfishApp, { + IronfishKeys, + ResponseAddress, + ResponseProofGenKey, + ResponseSign, + ResponseViewKey, +} from '@zondax/ledger-ironfish' + +export class Ledger { + app: IronfishApp | undefined + logger: Logger + PATH = "m/44'/1338'/0" + + constructor(logger?: Logger) { + this.app = undefined + this.logger = logger ? logger : createRootLogger() + } + + connect = async () => { + const transport = await TransportNodeHid.create(3000, 3000) + + if (transport.deviceModel) { + this.logger.debug(`${transport.deviceModel.productName} found.`) + } + + const app = new IronfishApp(transport) + + const appInfo = await app.appInfo() + this.logger.debug(appInfo.appName ?? 'no app name') + + if (appInfo.appName !== 'Ironfish') { + this.logger.debug(appInfo.appName ?? 'no app name') + this.logger.debug(appInfo.returnCode.toString(16)) + this.logger.debug(appInfo.errorMessage.toString()) + + // references: + // https://github.com/LedgerHQ/ledger-live/blob/173bb3c84cc855f83ab8dc49362bc381afecc31e/libs/ledgerjs/packages/errors/src/index.ts#L263 + // https://github.com/Zondax/ledger-ironfish/blob/bf43a4b8d403d15138699ee3bb1a3d6dfdb428bc/docs/APDUSPEC.md?plain=1#L25 + if (appInfo.returnCode === 0x5515) { + throw new Error('Please unlock your Ledger device.') + } + + throw new Error('Please open the Iron Fish app on your ledger device.') + } + + if (appInfo.appVersion) { + this.logger.debug(`Ironfish App Version: ${appInfo.appVersion}`) + } + + this.app = app + + return { app, PATH: this.PATH } + } + + getPublicAddress = async () => { + if (!this.app) { + throw new Error('Connect to Ledger first') + } + + const response: ResponseAddress = await this.app.retrieveKeys( + this.PATH, + IronfishKeys.PublicAddress, + false, + ) + + if (!response.publicAddress) { + this.logger.debug(`No public address returned.`) + this.logger.debug(response.returnCode.toString()) + throw new Error(response.errorMessage) + } + + return response.publicAddress.toString('hex') + } + + importAccount = async () => { + if (!this.app) { + throw new Error('Connect to Ledger first') + } + + const responseAddress: ResponseAddress = await this.app.retrieveKeys( + this.PATH, + IronfishKeys.PublicAddress, + false, + ) + + if (!responseAddress.publicAddress) { + this.logger.debug(`No public address returned.`) + this.logger.debug(responseAddress.returnCode.toString()) + throw new Error(responseAddress.errorMessage) + } + + this.logger.log('Please confirm the request on your ledger device.') + + const responseViewKey: ResponseViewKey = await this.app.retrieveKeys( + this.PATH, + IronfishKeys.ViewKey, + true, + ) + + if (!responseViewKey.viewKey || !responseViewKey.ovk || !responseViewKey.ivk) { + this.logger.debug(`No view key returned.`) + this.logger.debug(responseViewKey.returnCode.toString()) + throw new Error(responseViewKey.errorMessage) + } + + const responsePGK: ResponseProofGenKey = await this.app.retrieveKeys( + this.PATH, + IronfishKeys.ProofGenerationKey, + false, + ) + + if (!responsePGK.ak || !responsePGK.nsk) { + this.logger.debug(`No proof authorizing key returned.`) + throw new Error(responsePGK.errorMessage) + } + + const accountImport: AccountImport = { + version: 4, // ACCOUNT_SCHEMA_VERSION as of 2024-05 + name: 'ledger', + viewKey: responseViewKey.viewKey.toString('hex'), + incomingViewKey: responseViewKey.ivk.toString('hex'), + outgoingViewKey: responseViewKey.ovk.toString('hex'), + publicAddress: responseAddress.publicAddress.toString('hex'), + proofAuthorizingKey: responsePGK.nsk.toString('hex'), + spendingKey: null, + createdAt: null, + } + + return accountImport + } + + sign = async (message: string): Promise => { + if (!this.app) { + throw new Error('Connect to Ledger first') + } + + this.logger.log('Please confirm the request on your ledger device.') + + const buffer = Buffer.from(message, 'hex') + + // max size of a transaction is 16kb + if (buffer.length > 16 * 1024) { + throw new Error('Transaction size is too large, must be less than 16kb.') + } + + const response: ResponseSign = await this.app.sign(this.PATH, buffer) + + if (!response.signature) { + this.logger.debug(`No signatures returned.`) + this.logger.debug(response.returnCode.toString()) + throw new Error(response.errorMessage) + } + + return response.signature + } +} diff --git a/ironfish-cli/src/utils/table.ts b/ironfish-cli/src/utils/table.ts index a569bd5e94..60220eb957 100644 --- a/ironfish-cli/src/utils/table.ts +++ b/ironfish-cli/src/utils/table.ts @@ -4,8 +4,7 @@ import { ASSET_NAME_LENGTH } from '@ironfish/rust-nodejs' import { Assert, BufferUtils, TimeUtils } from '@ironfish/sdk' -import { Flags, ux } from '@oclif/core' -import { table } from '@oclif/core/lib/cli-ux/styled/table' +import { TableColumn } from '../ui' /** * Estimated max length of the longest TimeUtils.renderTime() @@ -28,7 +27,7 @@ const timestamp = >(options?: { field?: string get?: (row: Record) => string minWidth?: number -}): Partial> => { +}): TableColumn => { const header = options?.header ?? 'Timestamp' const field = options?.field ?? 'timestamp' @@ -63,12 +62,15 @@ const timestamp = >(options?: { const asset = >(options?: { extended?: boolean format?: Format -}): Partial>> => { +}): Partial>> => { if (options?.extended || options?.format !== Format.cli) { return { assetId: { header: 'Asset ID', - get: (row) => row['assetId'], + get: (row) => { + Assert.isString(row.assetId) + return row.assetId + }, minWidth: MAX_ASSET_NAME_COLUMN_WIDTH, extended: options?.extended ?? false, }, @@ -107,9 +109,9 @@ const asset = >(options?: { const fixedWidth = >(options: { width: number get: (row: T) => string - header?: string + header: string extended?: boolean -}): Partial> => { +}): TableColumn => { return { ...options, get: (row) => truncateCol(options.get(row), options.width), @@ -129,24 +131,6 @@ export enum Format { cli = 'cli', csv = 'csv', json = 'json', - yaml = 'yaml', } export const TableCols = { timestamp, asset, fixedWidth } - -const { 'no-truncate': _, ...tableFlags } = ux.table.flags() - -export const TableFlags = { - ...tableFlags, - truncate: Flags.boolean({ - description: 'truncate output to fit screen', - default: false, - allowNo: true, - }), - 'no-truncate': Flags.boolean({ - hidden: true, - default(context) { - return Promise.resolve(!context.flags['truncate']) - }, - }), -} diff --git a/ironfish-rust-nodejs/Cargo.toml b/ironfish-rust-nodejs/Cargo.toml index f69fa5ab97..0850f2b6c0 100644 --- a/ironfish-rust-nodejs/Cargo.toml +++ b/ironfish-rust-nodejs/Cargo.toml @@ -23,7 +23,8 @@ workspace = true [lib] crate-type = ["cdylib"] -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +stats = ["ironfish/note-encryption-stats", "jubjub/stats", "dep:signal-hook"] [dependencies] base64 = "0.13.0" @@ -32,9 +33,10 @@ ironfish = { path = "../ironfish-rust" } ironfish-frost = { git = "https://github.com/iron-fish/ironfish-frost.git", branch = "main" } napi = { version = "2.13.2", features = ["napi6"] } napi-derive = "2.13.0" -jubjub = { git = "https://github.com/iron-fish/jubjub.git", branch = "blstrs" } +jubjub = { git = "https://github.com/iron-fish/jubjub.git", branch = "blstrs", features = ["multiply-many"] } rand = "0.8.5" num_cpus = "1.16.0" +signal-hook = { version = "0.3.17", optional = true, default-features = false, features = ["iterator"] } [build-dependencies] napi-build = "2.0.1" diff --git a/ironfish-rust-nodejs/index.d.ts b/ironfish-rust-nodejs/index.d.ts index 6d17ac5e50..cb4be65e4f 100644 --- a/ironfish-rust-nodejs/index.d.ts +++ b/ironfish-rust-nodejs/index.d.ts @@ -86,6 +86,7 @@ export function isValidPublicAddress(hexAddress: string): boolean * sandboxed environment. */ export function getCpuCount(): CpuCount +export function generateRandomizedPublicKey(viewKeyString: string, publicKeyRandomnessString: string): string export class FishHashContext { constructor(full: boolean) prebuildDataset(threads: number): void @@ -113,11 +114,11 @@ export class Asset { static nativeId(): Buffer id(): Buffer serialize(): Buffer - static deserialize(jsBytes: Buffer): NativeAsset + static deserialize(jsBytes: Buffer, skipValidation?: boolean | undefined | null): NativeAsset } export type NativeNoteEncrypted = NoteEncrypted export class NoteEncrypted { - constructor(jsBytes: Buffer) + constructor(jsBytes: Buffer, skipValidation?: boolean | undefined | null) serialize(): Buffer equals(other: NoteEncrypted): boolean /** @@ -131,9 +132,10 @@ export class NoteEncrypted { */ static combineHash(depth: number, jsLeft: Buffer, jsRight: Buffer): Buffer /** Returns undefined if the note was unable to be decrypted with the given key. */ - decryptNoteForOwner(incomingHexKey: string): Buffer | null + decryptNoteForOwner(incomingViewKey: Buffer): Buffer | null + decryptNoteForOwners(incomingViewKeys: Array): Array /** Returns undefined if the note was unable to be decrypted with the given key. */ - decryptNoteForSpender(outgoingHexKey: string): Buffer | null + decryptNoteForSpender(outgoingViewKey: Buffer): Buffer | null } export type NativeNote = Note export class Note { @@ -226,10 +228,12 @@ export type NativeUnsignedTransaction = UnsignedTransaction export class UnsignedTransaction { constructor(jsBytes: Buffer) serialize(): Buffer + randomizedPublicKey(): string publicKeyRandomness(): string hash(): Buffer signingPackage(nativeIdentiferCommitments: Array): string sign(spenderHexKey: string): Buffer + addSignature(signature: Buffer): Buffer } export class FoundBlockResult { randomness: string diff --git a/ironfish-rust-nodejs/index.js b/ironfish-rust-nodejs/index.js index 46ae24dd0c..6ca64090b1 100644 --- a/ironfish-rust-nodejs/index.js +++ b/ironfish-rust-nodejs/index.js @@ -252,7 +252,7 @@ if (!nativeBinding) { throw new Error(`Failed to load native binding`) } -const { FishHashContext, KEY_LENGTH, NONCE_LENGTH, BoxKeyPair, randomBytes, boxMessage, unboxMessage, RollingFilter, initSignalHandler, triggerSegfault, ASSET_ID_LENGTH, ASSET_METADATA_LENGTH, ASSET_NAME_LENGTH, ASSET_LENGTH, Asset, NOTE_ENCRYPTION_KEY_LENGTH, MAC_LENGTH, ENCRYPTED_NOTE_PLAINTEXT_LENGTH, ENCRYPTED_NOTE_LENGTH, NoteEncrypted, PUBLIC_ADDRESS_LENGTH, RANDOMNESS_LENGTH, MEMO_LENGTH, AMOUNT_VALUE_LENGTH, DECRYPTED_NOTE_LENGTH, Note, PROOF_LENGTH, TRANSACTION_SIGNATURE_LENGTH, TRANSACTION_PUBLIC_KEY_RANDOMNESS_LENGTH, TRANSACTION_EXPIRATION_LENGTH, TRANSACTION_FEE_LENGTH, LATEST_TRANSACTION_VERSION, TransactionPosted, Transaction, verifyTransactions, UnsignedTransaction, LanguageCode, generateKey, spendingKeyToWords, wordsToSpendingKey, generatePublicAddressFromIncomingViewKey, generateKeyFromPrivateKey, initializeSapling, FoundBlockResult, ThreadPoolHandler, isValidPublicAddress, CpuCount, getCpuCount, multisig } = nativeBinding +const { FishHashContext, KEY_LENGTH, NONCE_LENGTH, BoxKeyPair, randomBytes, boxMessage, unboxMessage, RollingFilter, initSignalHandler, triggerSegfault, ASSET_ID_LENGTH, ASSET_METADATA_LENGTH, ASSET_NAME_LENGTH, ASSET_LENGTH, Asset, NOTE_ENCRYPTION_KEY_LENGTH, MAC_LENGTH, ENCRYPTED_NOTE_PLAINTEXT_LENGTH, ENCRYPTED_NOTE_LENGTH, NoteEncrypted, PUBLIC_ADDRESS_LENGTH, RANDOMNESS_LENGTH, MEMO_LENGTH, AMOUNT_VALUE_LENGTH, DECRYPTED_NOTE_LENGTH, Note, PROOF_LENGTH, TRANSACTION_SIGNATURE_LENGTH, TRANSACTION_PUBLIC_KEY_RANDOMNESS_LENGTH, TRANSACTION_EXPIRATION_LENGTH, TRANSACTION_FEE_LENGTH, LATEST_TRANSACTION_VERSION, TransactionPosted, Transaction, verifyTransactions, UnsignedTransaction, LanguageCode, generateKey, spendingKeyToWords, wordsToSpendingKey, generatePublicAddressFromIncomingViewKey, generateKeyFromPrivateKey, initializeSapling, FoundBlockResult, ThreadPoolHandler, isValidPublicAddress, CpuCount, getCpuCount, generateRandomizedPublicKey, multisig } = nativeBinding module.exports.FishHashContext = FishHashContext module.exports.KEY_LENGTH = KEY_LENGTH @@ -302,4 +302,5 @@ module.exports.ThreadPoolHandler = ThreadPoolHandler module.exports.isValidPublicAddress = isValidPublicAddress module.exports.CpuCount = CpuCount module.exports.getCpuCount = getCpuCount +module.exports.generateRandomizedPublicKey = generateRandomizedPublicKey module.exports.multisig = multisig diff --git a/ironfish-rust-nodejs/npm/darwin-arm64/package.json b/ironfish-rust-nodejs/npm/darwin-arm64/package.json index 8fd800a807..b7c2e79307 100644 --- a/ironfish-rust-nodejs/npm/darwin-arm64/package.json +++ b/ironfish-rust-nodejs/npm/darwin-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@ironfish/rust-nodejs-darwin-arm64", - "version": "2.4.0", + "version": "2.5.0", "os": [ "darwin" ], diff --git a/ironfish-rust-nodejs/npm/darwin-x64/package.json b/ironfish-rust-nodejs/npm/darwin-x64/package.json index 6fb392ab79..37a498d4c4 100644 --- a/ironfish-rust-nodejs/npm/darwin-x64/package.json +++ b/ironfish-rust-nodejs/npm/darwin-x64/package.json @@ -1,6 +1,6 @@ { "name": "@ironfish/rust-nodejs-darwin-x64", - "version": "2.4.0", + "version": "2.5.0", "os": [ "darwin" ], diff --git a/ironfish-rust-nodejs/npm/linux-arm64-gnu/package.json b/ironfish-rust-nodejs/npm/linux-arm64-gnu/package.json index bbea495fea..e137fa5f06 100644 --- a/ironfish-rust-nodejs/npm/linux-arm64-gnu/package.json +++ b/ironfish-rust-nodejs/npm/linux-arm64-gnu/package.json @@ -1,6 +1,6 @@ { "name": "@ironfish/rust-nodejs-linux-arm64-gnu", - "version": "2.4.0", + "version": "2.5.0", "os": [ "linux" ], diff --git a/ironfish-rust-nodejs/npm/linux-arm64-musl/package.json b/ironfish-rust-nodejs/npm/linux-arm64-musl/package.json index 30cb9421ba..49287e2e3c 100644 --- a/ironfish-rust-nodejs/npm/linux-arm64-musl/package.json +++ b/ironfish-rust-nodejs/npm/linux-arm64-musl/package.json @@ -1,6 +1,6 @@ { "name": "@ironfish/rust-nodejs-linux-arm64-musl", - "version": "2.4.0", + "version": "2.5.0", "os": [ "linux" ], diff --git a/ironfish-rust-nodejs/npm/linux-x64-gnu/package.json b/ironfish-rust-nodejs/npm/linux-x64-gnu/package.json index b8f1f64a39..33b833b861 100644 --- a/ironfish-rust-nodejs/npm/linux-x64-gnu/package.json +++ b/ironfish-rust-nodejs/npm/linux-x64-gnu/package.json @@ -1,6 +1,6 @@ { "name": "@ironfish/rust-nodejs-linux-x64-gnu", - "version": "2.4.0", + "version": "2.5.0", "os": [ "linux" ], diff --git a/ironfish-rust-nodejs/npm/linux-x64-musl/package.json b/ironfish-rust-nodejs/npm/linux-x64-musl/package.json index 66133c58b3..07598dd27a 100644 --- a/ironfish-rust-nodejs/npm/linux-x64-musl/package.json +++ b/ironfish-rust-nodejs/npm/linux-x64-musl/package.json @@ -1,6 +1,6 @@ { "name": "@ironfish/rust-nodejs-linux-x64-musl", - "version": "2.4.0", + "version": "2.5.0", "os": [ "linux" ], diff --git a/ironfish-rust-nodejs/npm/win32-x64-msvc/package.json b/ironfish-rust-nodejs/npm/win32-x64-msvc/package.json index 425746cd12..a5a8b11320 100644 --- a/ironfish-rust-nodejs/npm/win32-x64-msvc/package.json +++ b/ironfish-rust-nodejs/npm/win32-x64-msvc/package.json @@ -1,6 +1,6 @@ { "name": "@ironfish/rust-nodejs-win32-x64-msvc", - "version": "2.4.0", + "version": "2.5.0", "os": [ "win32" ], diff --git a/ironfish-rust-nodejs/package.json b/ironfish-rust-nodejs/package.json index 7a4ca058ba..49a8e9ddce 100644 --- a/ironfish-rust-nodejs/package.json +++ b/ironfish-rust-nodejs/package.json @@ -1,6 +1,6 @@ { "name": "@ironfish/rust-nodejs", - "version": "2.4.0", + "version": "2.5.0", "description": "Node.js bindings for Rust code required by the Iron Fish SDK", "main": "index.js", "types": "index.d.ts", @@ -14,6 +14,7 @@ "artifacts": "napi artifacts", "build": "yarn clean && napi build --platform --release", "build:debug": "napi build --platform", + "build:stats": "yarn clean && napi build --platform --release --features=stats", "prepublishOnly": "napi prepublish --skip-gh-release", "test:slow": "jest --testPathIgnorePatterns --testMatch \"**/*.test.slow.ts\"", "clean": "rimraf target" @@ -34,7 +35,6 @@ }, "devDependencies": { "@napi-rs/cli": "2.16.1", - "@types/jest": "29.5.8", "jest": "29.7.0", "rimraf": "3.0.2", "ts-jest": "29.1.1", diff --git a/ironfish-rust-nodejs/src/lib.rs b/ironfish-rust-nodejs/src/lib.rs index 46694fa68b..e21182f4f1 100644 --- a/ironfish-rust-nodejs/src/lib.rs +++ b/ironfish-rust-nodejs/src/lib.rs @@ -5,12 +5,15 @@ use std::fmt::Display; use std::num::NonZeroUsize; +use ironfish::keys::generate_randomized_public_key; use ironfish::keys::Language; use ironfish::serializing::bytes_to_hex; +use ironfish::serializing::fr::FrSerializable; use ironfish::IncomingViewKey; use ironfish::PublicAddress; use ironfish::SaplingKey; +use ironfish::ViewKey; use napi::bindgen_prelude::*; use napi_derive::napi; @@ -24,6 +27,9 @@ pub mod rolling_filter; pub mod signal_catcher; pub mod structs; +#[cfg(feature = "stats")] +pub mod stats; + fn to_napi_err(err: impl Display) -> napi::Error { Error::from_reason(err.to_string()) } @@ -252,3 +258,19 @@ pub fn get_cpu_count() -> CpuCount { physical_count: num_cpus::get_physical() as u32, } } + +#[napi(js_name = "generateRandomizedPublicKey")] +pub fn randomize_pk( + view_key_string: String, + public_key_randomness_string: String, +) -> Result { + let view_key = ViewKey::from_hex(&view_key_string).map_err(to_napi_err)?; + + let public_key_randomness = + jubjub::Fr::from_hex(&public_key_randomness_string).map_err(to_napi_err)?; + + let public_key = + generate_randomized_public_key(view_key, public_key_randomness).map_err(to_napi_err)?; + + Ok(bytes_to_hex(&public_key)) +} diff --git a/ironfish-rust-nodejs/src/stats.rs b/ironfish-rust-nodejs/src/stats.rs new file mode 100644 index 0000000000..3b52f5b567 --- /dev/null +++ b/ironfish-rust-nodejs/src/stats.rs @@ -0,0 +1,92 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +#![cfg(feature = "stats")] + +use napi::JsObject; +use napi_derive::module_exports; +use signal_hook::{consts::signal::SIGUSR1, iterator::Signals}; +use std::fmt::Write as FmtWrite; +use std::io::{self, Write as IoWrite}; +use std::sync::Once; +use std::thread; + +fn print_stats(colors: bool) { + let ecpm_stats = jubjub::stats(); + let note_stats = ironfish::merkle_note::stats::get(); + + // Write the stats in a buffer first, then write the buffer to stderr. The goal of the buffer + // is to attempt to write the stats in a single syscall, so that the stats output will not be + // interleaved with the rest of the output from the main process. This may not always work + // (depending on the buffering performed by stderr), but it is better than calling `print!` + // directly. + let mut s = String::new(); + + write!( + &mut s, + "\n\ + {highlight}Elliptic Curve Point Multiplication Stats:\n\ + • affine muls: {affine_muls}\n\ + • extended muls: {extended_muls}\n\ + • extended vector muls: {extended_mul_many_calls} calls / {extended_mul_many_operands} points\n\ + Note Encryption Stats:\n\ + • total: {note_construct}\n\ + Note Decryption Stats:\n\ + • for owner: {note_dec_for_owner} ({note_dec_for_owner_ok} [{note_dec_for_owner_ok_percent:.2}%] successful)\n\ + • for spender: {note_dec_for_spender} ({note_dec_for_spender_ok} [{note_dec_for_spender_ok_percent:.2}%] successful){reset}\n\ + \n", + highlight = if colors { "\x1b[1;31m" } else { "" }, + reset = if colors { "\x1b[0m" } else { "" }, + affine_muls = ecpm_stats.affine_muls, + extended_muls = ecpm_stats.extended_muls, + extended_mul_many_calls = ecpm_stats.extended_mul_many_calls, + extended_mul_many_operands = ecpm_stats.extended_mul_many_operands, + note_construct = note_stats.construct, + note_dec_for_owner = note_stats.decrypt_note_for_owner.total, + note_dec_for_owner_ok = note_stats.decrypt_note_for_owner.successful, + note_dec_for_owner_ok_percent = + note_stats.decrypt_note_for_owner.successful as f64 / + note_stats.decrypt_note_for_owner.total as f64 * 100., + note_dec_for_spender = note_stats.decrypt_note_for_spender.total, + note_dec_for_spender_ok = note_stats.decrypt_note_for_spender.successful, + note_dec_for_spender_ok_percent = + note_stats.decrypt_note_for_spender.successful as f64 / + note_stats.decrypt_note_for_spender.total as f64 * 100., + ).expect("failed to write stats to buffer"); + + let mut stderr = io::stderr().lock(); + stderr + .write_all(s.as_bytes()) + .and_then(|()| stderr.flush()) + .expect("failed to write stats to stderr"); +} + +/// Prints statistics whenever SIGUSR1 is sent to this process. +fn print_stats_on_signal() { + let mut signals = Signals::new([SIGUSR1]).expect("failed to set up signal handler"); + for _ in signals.forever() { + print_stats(true); + } +} + +pub fn setup_signal_handler() { + thread::spawn(print_stats_on_signal); +} + +/// Sets up the stats signal handler when the N-API module is imported. +/// +/// Technically, the `module_exports` macro is supposed to be used on code that sets up the +/// JavaScript exports. Here we are abusing the functionality a little bit by performing other side +/// actions. However, given that all the code contained in this module is for development only and +/// will never be released to the public, we consider this use acceptable. +#[module_exports] +fn init(_exports: JsObject) -> napi::Result<()> { + // Due to how Node worker threads work, this N-API module will be imported multiple times (once + // for the main thread, then once for each worker thread spawned). We use `Once` here to avoid + // setting up multiple signal handlers, which would result in duplicate stats messages being + // emitted after receiving a signal. + static START: Once = Once::new(); + START.call_once(setup_signal_handler); + Ok(()) +} diff --git a/ironfish-rust-nodejs/src/structs/asset.rs b/ironfish-rust-nodejs/src/structs/asset.rs index 8e371dcc3e..1052f41c30 100644 --- a/ironfish-rust-nodejs/src/structs/asset.rs +++ b/ironfish-rust-nodejs/src/structs/asset.rs @@ -91,9 +91,15 @@ impl NativeAsset { } #[napi(factory)] - pub fn deserialize(js_bytes: JsBuffer) -> Result { + pub fn deserialize(js_bytes: JsBuffer, skip_validation: Option) -> Result { let bytes = js_bytes.into_value()?; - let asset = Asset::read(bytes.as_ref()).map_err(to_napi_err)?; + let skip_validation = skip_validation.unwrap_or(false); + let asset = if !skip_validation { + Asset::read(bytes.as_ref()) + } else { + Asset::read_unchecked(bytes.as_ref()) + } + .map_err(to_napi_err)?; Ok(NativeAsset { asset }) } diff --git a/ironfish-rust-nodejs/src/structs/note_encrypted.rs b/ironfish-rust-nodejs/src/structs/note_encrypted.rs index bace22c6df..cd0597bf3e 100644 --- a/ironfish-rust-nodejs/src/structs/note_encrypted.rs +++ b/ironfish-rust-nodejs/src/structs/note_encrypted.rs @@ -2,20 +2,20 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +use crate::to_napi_err; +use ironfish::merkle_note::NOTE_ENCRYPTION_KEY_SIZE; +use ironfish::note::ENCRYPTED_NOTE_SIZE; +use ironfish::note::PLAINTEXT_NOTE_SIZE; +use ironfish::serializing::aead::MAC_SIZE; use ironfish::IncomingViewKey; +use ironfish::MerkleNote; use ironfish::MerkleNoteHash; +use ironfish::Note; use ironfish::OutgoingViewKey; use napi::bindgen_prelude::*; use napi::JsBuffer; use napi_derive::napi; -use ironfish::merkle_note::NOTE_ENCRYPTION_KEY_SIZE; -use ironfish::note::ENCRYPTED_NOTE_SIZE; -use ironfish::serializing::aead::MAC_SIZE; -use ironfish::MerkleNote; - -use crate::to_napi_err; - #[napi] pub const NOTE_ENCRYPTION_KEY_LENGTH: u32 = NOTE_ENCRYPTION_KEY_SIZE as u32; @@ -29,6 +29,33 @@ pub const ENCRYPTED_NOTE_PLAINTEXT_LENGTH: u32 = ENCRYPTED_NOTE_SIZE as u32 + MA pub const ENCRYPTED_NOTE_LENGTH: u32 = NOTE_ENCRYPTION_KEY_LENGTH + ENCRYPTED_NOTE_PLAINTEXT_LENGTH + 96; +#[inline] +fn try_map(items: I, f: F) -> std::result::Result, E> +where + I: IntoIterator, + I::IntoIter: ExactSizeIterator, + F: Fn(T) -> std::result::Result, +{ + let items = items.into_iter(); + let mut result = Vec::with_capacity(items.len()); + for item in items { + result.push(f(item)?); + } + Ok(result) +} + +#[inline] +fn decrypted_note_to_buffer(note: std::result::Result) -> Result> { + match note { + Ok(note) => { + let mut buf = [0u8; PLAINTEXT_NOTE_SIZE]; + note.write(&mut buf[..]).map_err(to_napi_err)?; + Ok(Some(Buffer::from(&buf[..]))) + } + Err(_) => Ok(None), + } +} + #[napi(js_name = "NoteEncrypted")] pub struct NativeNoteEncrypted { pub(crate) note: MerkleNote, @@ -37,9 +64,16 @@ pub struct NativeNoteEncrypted { #[napi] impl NativeNoteEncrypted { #[napi(constructor)] - pub fn new(js_bytes: JsBuffer) -> Result { + pub fn new(js_bytes: JsBuffer, skip_validation: Option) -> Result { let bytes = js_bytes.into_value()?; - let note = MerkleNote::read(bytes.as_ref()).map_err(to_napi_err)?; + let skip_validation = skip_validation.unwrap_or(false); + + let note = if !skip_validation { + MerkleNote::read(bytes.as_ref()) + } else { + MerkleNote::read_unchecked(bytes.as_ref()) + } + .map_err(to_napi_err)?; Ok(NativeNoteEncrypted { note }) } @@ -100,34 +134,31 @@ impl NativeNoteEncrypted { /// Returns undefined if the note was unable to be decrypted with the given key. #[napi] - pub fn decrypt_note_for_owner(&self, incoming_hex_key: String) -> Result> { + pub fn decrypt_note_for_owner(&self, incoming_view_key: JsBuffer) -> Result> { let incoming_view_key = - IncomingViewKey::from_hex(&incoming_hex_key).map_err(to_napi_err)?; - - Ok(match self.note.decrypt_note_for_owner(&incoming_view_key) { - Ok(note) => { - let mut vec = vec![]; - note.write(&mut vec).map_err(to_napi_err)?; - Some(Buffer::from(vec)) - } - Err(_) => None, - }) + IncomingViewKey::read(&*incoming_view_key.into_value()?).map_err(to_napi_err)?; + let decrypted_note = self.note.decrypt_note_for_owner(&incoming_view_key); + decrypted_note_to_buffer(decrypted_note).map_err(to_napi_err) + } + + #[napi] + pub fn decrypt_note_for_owners( + &self, + incoming_view_keys: Vec, + ) -> Result>> { + let incoming_view_keys = try_map(incoming_view_keys, |incoming_view_key| { + IncomingViewKey::read(&*incoming_view_key.into_value()?).map_err(to_napi_err) + })?; + let decrypted_notes = self.note.decrypt_note_for_owners(&incoming_view_keys); + try_map(decrypted_notes, decrypted_note_to_buffer).map_err(to_napi_err) } /// Returns undefined if the note was unable to be decrypted with the given key. #[napi] - pub fn decrypt_note_for_spender(&self, outgoing_hex_key: String) -> Result> { + pub fn decrypt_note_for_spender(&self, outgoing_view_key: JsBuffer) -> Result> { let outgoing_view_key = - OutgoingViewKey::from_hex(&outgoing_hex_key).map_err(to_napi_err)?; - Ok( - match self.note.decrypt_note_for_spender(&outgoing_view_key) { - Ok(note) => { - let mut vec = vec![]; - note.write(&mut vec).map_err(to_napi_err)?; - Some(Buffer::from(vec)) - } - Err(_) => None, - }, - ) + OutgoingViewKey::read(&*outgoing_view_key.into_value()?).map_err(to_napi_err)?; + let decrypted_note = self.note.decrypt_note_for_spender(&outgoing_view_key); + decrypted_note_to_buffer(decrypted_note).map_err(to_napi_err) } } diff --git a/ironfish-rust-nodejs/src/structs/transaction.rs b/ironfish-rust-nodejs/src/structs/transaction.rs index 0f381aad1a..14219c6c75 100644 --- a/ironfish-rust-nodejs/src/structs/transaction.rs +++ b/ironfish-rust-nodejs/src/structs/transaction.rs @@ -405,6 +405,12 @@ impl NativeUnsignedTransaction { Ok(Buffer::from(vec)) } + #[napi] + pub fn randomized_public_key(&self) -> String { + let bytes = self.transaction.randomized_public_key_bytes(); + bytes_to_hex(&bytes) + } + #[napi] pub fn public_key_randomness(&self) -> String { let bytes = self.transaction.public_key_randomness().to_bytes(); @@ -460,6 +466,25 @@ impl NativeUnsignedTransaction { Ok(Buffer::from(vec)) } + + #[napi] + pub fn add_signature(&mut self, signature: JsBuffer) -> Result { + let bytes = signature.into_value()?; + + let mut signature_bytes = [0u8; 64]; + + signature_bytes.copy_from_slice(bytes.as_ref()); + + let signed_transaction = self + .transaction + .add_signature(signature_bytes) + .map_err(to_napi_err)?; + + let mut vec: Vec = vec![]; + signed_transaction.write(&mut vec).map_err(to_napi_err)?; + + Ok(Buffer::from(vec)) + } } #[napi(namespace = "multisig")] diff --git a/ironfish-rust-nodejs/tests/demo.test.slow.ts b/ironfish-rust-nodejs/tests/demo.test.slow.ts index 3115b6b1ee..3be016edf7 100644 --- a/ironfish-rust-nodejs/tests/demo.test.slow.ts +++ b/ironfish-rust-nodejs/tests/demo.test.slow.ts @@ -76,11 +76,11 @@ describe('Demonstrate the Sapling API', () => { expect(encryptedNote.hash().byteLength).toBe(32) expect(encryptedNote.equals(encryptedNote)).toBe(true) - const decryptedNoteBuffer = encryptedNote.decryptNoteForOwner(key.incomingViewKey) + const decryptedNoteBuffer = encryptedNote.decryptNoteForOwner(Buffer.from(key.incomingViewKey, 'hex')) expect(decryptedNoteBuffer).toBeInstanceOf(Buffer) expect(decryptedNoteBuffer!.byteLength).toBe(DECRYPTED_NOTE_LENGTH) - const decryptedSpenderNote = encryptedNote.decryptNoteForSpender(key.outgoingViewKey) + const decryptedSpenderNote = encryptedNote.decryptNoteForSpender(Buffer.from(key.outgoingViewKey, 'hex')) expect(decryptedSpenderNote).toBe(null) const decryptedNote = Note.deserialize(decryptedNoteBuffer!) @@ -104,7 +104,7 @@ describe('Demonstrate the Sapling API', () => { const transaction = new Transaction(LATEST_TRANSACTION_VERSION) transaction.setExpiration(10) const encryptedNote = new NoteEncrypted(postedMinersFeeTransaction.getNote(0)) - const decryptedNote = Note.deserialize(encryptedNote.decryptNoteForOwner(key.incomingViewKey)!) + const decryptedNote = Note.deserialize(encryptedNote.decryptNoteForOwner(Buffer.from(key.incomingViewKey, 'hex'))!) const newNote = new Note(recipientKey.publicAddress, 15n, Buffer.from('receive'), Asset.nativeId(), minersFeeNote.owner()) let currentHash = encryptedNote.hash() diff --git a/ironfish-rust-nodejs/tests/testHarness.ts b/ironfish-rust-nodejs/tests/testHarness.ts new file mode 100644 index 0000000000..f89eb8062d --- /dev/null +++ b/ironfish-rust-nodejs/tests/testHarness.ts @@ -0,0 +1,25 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +import type { Jest } from '@jest/environment' +import type { JestExpect } from '@jest/expect' +import type { Global } from '@jest/types' + +declare global { + const { + it, + test, + fit, + xit, + xtest, + describe, + xdescribe, + fdescribe, + beforeAll, + beforeEach, + afterEach, + afterAll, + }: Global.GlobalAdditions + const expect: JestExpect + const jest: Jest +} diff --git a/ironfish-rust/Cargo.toml b/ironfish-rust/Cargo.toml index 593487bf41..1f5f52f9d1 100644 --- a/ironfish-rust/Cargo.toml +++ b/ironfish-rust/Cargo.toml @@ -26,6 +26,7 @@ workspace = true [features] benchmark = [] download-params = ["dep:reqwest"] +note-encryption-stats = [] [lib] name = "ironfish" @@ -45,7 +46,7 @@ group = "0.12.0" ironfish-frost = { git = "https://github.com/iron-fish/ironfish-frost.git", branch = "main" } fish_hash = "0.3.0" ironfish_zkp = { version = "0.2.0", path = "../ironfish-zkp" } -jubjub = { git = "https://github.com/iron-fish/jubjub.git", branch = "blstrs" } +jubjub = { git = "https://github.com/iron-fish/jubjub.git", branch = "blstrs", features = ["multiply-many"] } lazy_static = "1.4.0" libc = "0.2.126" # sub-dependency that needs a pinned version until a new release of cpufeatures: https://github.com/RustCrypto/utils/pull/789 rand = "0.8.5" diff --git a/ironfish-rust/src/assets/asset.rs b/ironfish-rust/src/assets/asset.rs index 3b1d02ca83..f1d4605435 100644 --- a/ironfish-rust/src/assets/asset.rs +++ b/ironfish-rust/src/assets/asset.rs @@ -134,6 +134,20 @@ impl Asset { Asset::new_with_nonce(creator, name, metadata, nonce) } + pub fn read_unchecked(mut reader: R) -> Result { + let creator = PublicAddress::read_unchecked(&mut reader)?; + + let mut name = [0; NAME_LENGTH]; + reader.read_exact(&mut name[..])?; + + let mut metadata = [0; METADATA_LENGTH]; + reader.read_exact(&mut metadata[..])?; + + let nonce = reader.read_u8()?; + + Asset::new_with_nonce(creator, name, metadata, nonce) + } + /// Stow the bytes of this struct in the given writer. pub fn write(&self, mut writer: W) -> Result<(), IronfishError> { self.creator.write(&mut writer)?; diff --git a/ironfish-rust/src/keys/mod.rs b/ironfish-rust/src/keys/mod.rs index f6b8ce9b65..9e4313cda6 100644 --- a/ironfish-rust/src/keys/mod.rs +++ b/ironfish-rust/src/keys/mod.rs @@ -24,6 +24,8 @@ mod public_address; pub use public_address::*; mod view_keys; pub use view_keys::*; +mod util; +pub use util::*; pub mod proof_generation_key; pub use proof_generation_key::*; diff --git a/ironfish-rust/src/keys/public_address.rs b/ironfish-rust/src/keys/public_address.rs index d7af609462..4b9ea5f887 100644 --- a/ironfish-rust/src/keys/public_address.rs +++ b/ironfish-rust/src/keys/public_address.rs @@ -23,17 +23,18 @@ pub struct PublicAddress(pub(crate) SubgroupPoint); impl PublicAddress { /// Initialize a public address from its 32 byte representation. - pub fn new( - public_address_bytes: &[u8; PUBLIC_ADDRESS_SIZE], - ) -> Result { - assert!(public_address_bytes.len() == 32); - let public_address_non_prime = SubgroupPoint::from_bytes(public_address_bytes); - - if public_address_non_prime.is_some().into() { - Ok(PublicAddress(public_address_non_prime.unwrap())) - } else { - Err(IronfishError::new(IronfishErrorKind::InvalidPaymentAddress)) - } + pub fn new(bytes: &[u8; PUBLIC_ADDRESS_SIZE]) -> Result { + Option::from(SubgroupPoint::from_bytes(bytes)) + .map(PublicAddress) + .ok_or_else(|| IronfishError::new(IronfishErrorKind::InvalidPaymentAddress)) + } + + /// Initialize a public address from its 32 byte representation, without performing expensive + /// checks on the validity of the address. + pub fn new_unchecked(bytes: &[u8; PUBLIC_ADDRESS_SIZE]) -> Result { + Option::from(SubgroupPoint::from_bytes_unchecked(bytes)) + .map(PublicAddress) + .ok_or_else(|| IronfishError::new(IronfishErrorKind::InvalidPaymentAddress)) } /// Load a public address from a Read implementation (e.g: socket, file) @@ -43,6 +44,12 @@ impl PublicAddress { Self::new(&address_bytes) } + pub fn read_unchecked(reader: &mut R) -> Result { + let mut address_bytes = [0; PUBLIC_ADDRESS_SIZE]; + reader.read_exact(&mut address_bytes)?; + Self::new_unchecked(&address_bytes) + } + /// Initialize a public address from a sapling key. Typically constructed from /// SaplingKey::public_address() pub fn from_key(sapling_key: &SaplingKey) -> PublicAddress { diff --git a/ironfish-rust/src/keys/util.rs b/ironfish-rust/src/keys/util.rs new file mode 100644 index 0000000000..369b518e8a --- /dev/null +++ b/ironfish-rust/src/keys/util.rs @@ -0,0 +1,19 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use group::GroupEncoding; +use ironfish_zkp::{constants::SPENDING_KEY_GENERATOR, redjubjub}; +use jubjub::Fr; + +use crate::{errors::IronfishError, ViewKey}; + +pub fn generate_randomized_public_key( + view_key: ViewKey, + public_key_randomness: Fr, +) -> Result<[u8; 32], IronfishError> { + let randomized_public_key = redjubjub::PublicKey(view_key.authorizing_key.into()) + .randomize(public_key_randomness, *SPENDING_KEY_GENERATOR); + + Ok(randomized_public_key.0.to_bytes()) +} diff --git a/ironfish-rust/src/keys/view_keys.rs b/ironfish-rust/src/keys/view_keys.rs index f26bcdfc3f..68b9f26e3e 100644 --- a/ironfish-rust/src/keys/view_keys.rs +++ b/ironfish-rust/src/keys/view_keys.rs @@ -37,7 +37,7 @@ pub struct IncomingViewKey { impl IncomingViewKey { /// load view key from a Read implementation - pub fn read(reader: &mut R) -> Result { + pub fn read(reader: R) -> Result { let view_key = read_scalar(reader)?; Ok(IncomingViewKey { view_key }) } @@ -85,6 +85,21 @@ impl IncomingViewKey { pub(crate) fn shared_secret(&self, ephemeral_public_key: &SubgroupPoint) -> [u8; 32] { shared_secret(&self.view_key, ephemeral_public_key, ephemeral_public_key) } + + pub(crate) fn shared_secrets( + slice: &[Self], + ephemeral_public_key: &SubgroupPoint, + ) -> Vec<[u8; 32]> { + let raw_view_keys = slice + .iter() + .map(move |ivk| ivk.view_key.to_bytes()) + .collect::>(); + shared_secrets( + &raw_view_keys[..], + ephemeral_public_key, + ephemeral_public_key, + ) + } } /// Contains two keys that are required (along with outgoing view key) @@ -159,6 +174,13 @@ pub struct OutgoingViewKey { } impl OutgoingViewKey { + /// load view key from a Read implementation + pub fn read(mut reader: R) -> Result { + let mut view_key = [0u8; 32]; + reader.read_exact(&mut view_key)?; + Ok(OutgoingViewKey { view_key }) + } + /// Load a key from a string of hexadecimal digits pub fn from_hex(value: &str) -> Result { match hex_to_bytes(value) { @@ -217,12 +239,36 @@ impl OutgoingViewKey { /// key (Bob's public key) to get the final shared secret /// /// The resulting key can be used in any symmetric cipher +#[must_use] pub(crate) fn shared_secret( secret_key: &jubjub::Fr, other_public_key: &SubgroupPoint, reference_public_key: &SubgroupPoint, ) -> [u8; 32] { let shared_secret = (other_public_key * secret_key).to_bytes(); + hash_shared_secret(&shared_secret, reference_public_key) +} + +/// Equivalent to calling `shared_secret()` multiple times on the same +/// `other_public_key`/`reference_public_key`, but more efficient. +#[must_use] +pub(crate) fn shared_secrets( + secret_keys: &[[u8; 32]], + other_public_key: &SubgroupPoint, + reference_public_key: &SubgroupPoint, +) -> Vec<[u8; 32]> { + let shared_secrets = other_public_key.as_extended().multiply_many(secret_keys); + shared_secrets + .into_iter() + .map(move |shared_secret| { + hash_shared_secret(&shared_secret.to_bytes(), reference_public_key) + }) + .collect() +} + +#[inline] +#[must_use] +fn hash_shared_secret(shared_secret: &[u8; 32], reference_public_key: &SubgroupPoint) -> [u8; 32] { let reference_bytes = reference_public_key.to_bytes(); let mut hasher = Blake2b::new() @@ -230,10 +276,11 @@ pub(crate) fn shared_secret( .personal(DIFFIE_HELLMAN_PERSONALIZATION) .to_state(); - hasher.update(&shared_secret); + hasher.update(&shared_secret[..]); hasher.update(&reference_bytes); + let mut hash_result = [0; 32]; - hash_result[..].clone_from_slice(hasher.finalize().as_ref()); + hash_result[..].copy_from_slice(hasher.finalize().as_ref()); hash_result } diff --git a/ironfish-rust/src/merkle_note.rs b/ironfish-rust/src/merkle_note.rs index 7607f75b92..be1d763d60 100644 --- a/ironfish-rust/src/merkle_note.rs +++ b/ironfish-rust/src/merkle_note.rs @@ -2,7 +2,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use crate::{errors::IronfishError, keys::EphemeralKeyPair, serializing::read_point}; +use crate::{ + errors::IronfishError, + keys::EphemeralKeyPair, + serializing::{read_point, read_point_unchecked}, +}; /// Implement a merkle note to store all the values that need to go into a merkle tree. /// A tree containing these values can serve as a snapshot of the entire chain. @@ -39,7 +43,7 @@ pub const NOTE_ENCRYPTION_MINER_KEYS: &[u8; NOTE_ENCRYPTION_KEY_SIZE] = b"Iron Fish note encryption miner key000000000000000000000000000000000000000000000"; const SHARED_KEY_PERSONALIZATION: &[u8; 16] = b"Iron Fish Keyenc"; -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct MerkleNote { /// Randomized value commitment. Sometimes referred to as /// `cv` in the literature. It's calculated by multiplying a value by a @@ -128,6 +132,9 @@ impl MerkleNote { diffie_hellman_keys: &EphemeralKeyPair, note_encryption_keys: [u8; NOTE_ENCRYPTION_KEY_SIZE], ) -> MerkleNote { + #[cfg(feature = "note-encryption-stats")] + stats::inc_construct(); + let secret_key = diffie_hellman_keys.secret(); let public_key = diffie_hellman_keys.public(); @@ -142,7 +149,7 @@ impl MerkleNote { } } - /// Load a MerkleNote from the given stream + /// Load a MerkleNote from the given reader. pub fn read(mut reader: R) -> Result { let value_commitment = read_point(&mut reader)?; let note_commitment = read_scalar(&mut reader)?; @@ -162,6 +169,30 @@ impl MerkleNote { }) } + /// Load a MerkleNote from the given reader, skipping some expensive validity checks on the + /// input. + /// + /// This method is faster than [`read()`], but it requires trusted or pre-validated input. + /// Passing invalid input may result in erroneous calculations or security risks. + pub fn read_unchecked(mut reader: R) -> Result { + let value_commitment = read_point_unchecked(&mut reader)?; + let note_commitment = read_scalar(&mut reader)?; + let ephemeral_public_key = read_point_unchecked(&mut reader)?; + + let mut encrypted_note = [0; ENCRYPTED_NOTE_SIZE + aead::MAC_SIZE]; + reader.read_exact(&mut encrypted_note[..])?; + let mut note_encryption_keys = [0; NOTE_ENCRYPTION_KEY_SIZE]; + reader.read_exact(&mut note_encryption_keys[..])?; + + Ok(MerkleNote { + value_commitment, + note_commitment, + ephemeral_public_key, + encrypted_note, + note_encryption_keys, + }) + } + pub fn write(&self, writer: &mut W) -> Result<(), IronfishError> { writer.write_all(&self.value_commitment.to_bytes())?; writer.write_all(&self.note_commitment.to_bytes_le())?; @@ -180,17 +211,56 @@ impl MerkleNote { &self, owner_view_key: &IncomingViewKey, ) -> Result { + #[cfg(feature = "note-encryption-stats")] + stats::inc_decrypt_note_for_owner(1); + let shared_secret = owner_view_key.shared_secret(&self.ephemeral_public_key); let note = Note::from_owner_encrypted(owner_view_key, &shared_secret, &self.encrypted_note)?; note.verify_commitment(self.note_commitment)?; + + #[cfg(feature = "note-encryption-stats")] + stats::inc_decrypt_note_for_owner_ok(1); Ok(note) } + pub fn decrypt_note_for_owners( + &self, + owner_view_keys: &[IncomingViewKey], + ) -> Vec> { + #[cfg(feature = "note-encryption-stats")] + stats::inc_decrypt_note_for_owner(owner_view_keys.len()); + + let shared_secrets = + IncomingViewKey::shared_secrets(owner_view_keys, &self.ephemeral_public_key); + + let result = owner_view_keys + .iter() + .zip(shared_secrets.iter()) + .map(move |(owner_view_key, shared_secret)| { + let note = Note::from_owner_encrypted( + owner_view_key, + shared_secret, + &self.encrypted_note, + )?; + note.verify_commitment(self.note_commitment)?; + Ok(note) + }) + .collect::>>(); + + #[cfg(feature = "note-encryption-stats")] + stats::inc_decrypt_note_for_owner_ok(result.iter().filter(move |res| res.is_ok()).count()); + + result + } + pub fn decrypt_note_for_spender( &self, spender_key: &OutgoingViewKey, ) -> Result { + #[cfg(feature = "note-encryption-stats")] + stats::inc_decrypt_note_for_spender(); + let encryption_key = calculate_key_for_encryption_keys( spender_key, &self.value_commitment, @@ -206,6 +276,9 @@ impl MerkleNote { let note = Note::from_spender_encrypted(public_address.0, &shared_key, &self.encrypted_note)?; note.verify_commitment(self.note_commitment)?; + + #[cfg(feature = "note-encryption-stats")] + stats::inc_decrypt_note_for_spender_ok(); Ok(note) } } @@ -269,6 +342,82 @@ fn calculate_key_for_encryption_keys( .expect("has has incorrect length") } +#[cfg(feature = "note-encryption-stats")] +pub mod stats { + use std::sync::atomic::AtomicUsize; + use std::sync::atomic::Ordering::Relaxed; + + static CONSTRUCT_CALLS: AtomicUsize = AtomicUsize::new(0); + + static DECRYPT_FOR_OWNER_CALLS: AtomicUsize = AtomicUsize::new(0); + static DECRYPT_FOR_OWNER_OK_CALLS: AtomicUsize = AtomicUsize::new(0); + + static DECRYPT_FOR_SPENDER_CALLS: AtomicUsize = AtomicUsize::new(0); + static DECRYPT_FOR_SPENDER_OK_CALLS: AtomicUsize = AtomicUsize::new(0); + + /// Statistics on the operations performed by the [`ironfish::merkle_note`] module. + #[derive(Copy, Clone, PartialEq, Eq, Debug)] + pub struct Stats { + /// Number of [`MerkleNote::construct()`] calls made so far. + pub construct: usize, + /// Number of [`MerkleNote::decrypt_note_for_owner()`] calls made so far. + pub decrypt_note_for_owner: CallResultStats, + /// Number of [`MerkleNote::decrypt_note_for_spender()`] calls made so far. + pub decrypt_note_for_spender: CallResultStats, + } + + /// Statistics for a function that returns a `Result`. + #[derive(Copy, Clone, PartialEq, Eq, Debug)] + pub struct CallResultStats { + /// Number of calls to a function performed so far. This includes both successful (`Ok`) + /// and unsuccessful (`Err`) calls. + pub total: usize, + /// Number of calls to a function performed so far that returned a successful (`Ok`) + /// result. + pub successful: usize, + } + + #[inline(always)] + pub(super) fn inc_construct() { + CONSTRUCT_CALLS.fetch_add(1, Relaxed); + } + + #[inline(always)] + pub(super) fn inc_decrypt_note_for_owner(count: usize) { + DECRYPT_FOR_OWNER_CALLS.fetch_add(count, Relaxed); + } + + #[inline(always)] + pub(super) fn inc_decrypt_note_for_owner_ok(count: usize) { + DECRYPT_FOR_OWNER_OK_CALLS.fetch_add(count, Relaxed); + } + + #[inline(always)] + pub(super) fn inc_decrypt_note_for_spender() { + DECRYPT_FOR_SPENDER_CALLS.fetch_add(1, Relaxed); + } + + #[inline(always)] + pub(super) fn inc_decrypt_note_for_spender_ok() { + DECRYPT_FOR_SPENDER_OK_CALLS.fetch_add(1, Relaxed); + } + + #[must_use] + pub fn get() -> Stats { + Stats { + construct: CONSTRUCT_CALLS.load(Relaxed), + decrypt_note_for_owner: CallResultStats { + total: DECRYPT_FOR_OWNER_CALLS.load(Relaxed), + successful: DECRYPT_FOR_OWNER_OK_CALLS.load(Relaxed), + }, + decrypt_note_for_spender: CallResultStats { + total: DECRYPT_FOR_SPENDER_CALLS.load(Relaxed), + successful: DECRYPT_FOR_SPENDER_OK_CALLS.load(Relaxed), + }, + } + } +} + #[cfg(test)] mod test { use super::MerkleNote; @@ -441,4 +590,41 @@ mod test { .decrypt_note_for_spender(spender_key.outgoing_view_key()) .is_err()); } + + #[test] + fn test_serialization_roundtrip() { + let spender_key = SaplingKey::generate_key(); + let note = Note::new( + spender_key.public_address(), + 42, + "", + NATIVE_ASSET, + spender_key.public_address(), + ); + let diffie_hellman_keys = EphemeralKeyPair::new(); + + let value_commitment = ValueCommitment::new(note.value, note.asset_generator()); + + let merkle_note = MerkleNote::new( + spender_key.outgoing_view_key(), + ¬e, + &value_commitment, + &diffie_hellman_keys, + ); + + let mut serialization = Vec::new(); + + merkle_note + .write(&mut serialization) + .expect("serialization failed"); + + assert_eq!( + MerkleNote::read(&serialization[..]).expect("deserialization failed"), + merkle_note + ); + assert_eq!( + MerkleNote::read_unchecked(&serialization[..]).expect("deserialization failed"), + merkle_note + ); + } } diff --git a/ironfish-rust/src/note.rs b/ironfish-rust/src/note.rs index 912398a690..3a87c09ce4 100644 --- a/ironfish-rust/src/note.rs +++ b/ironfish-rust/src/note.rs @@ -35,6 +35,12 @@ pub const ENCRYPTED_NOTE_SIZE: usize = // + 32 memo // + 32 sender address // = 136 +pub const PLAINTEXT_NOTE_SIZE: usize = PUBLIC_ADDRESS_SIZE + + ASSET_ID_LENGTH + + AMOUNT_VALUE_SIZE + + SCALAR_SIZE + + MEMO_SIZE + + PUBLIC_ADDRESS_SIZE; pub const SCALAR_SIZE: usize = 32; pub const MEMO_SIZE: usize = 32; pub const AMOUNT_VALUE_SIZE: usize = 8; @@ -105,7 +111,7 @@ pub struct Note { pub(crate) sender: PublicAddress, } -impl<'a> Note { +impl Note { /// Construct a new Note. pub fn new( owner: PublicAddress, @@ -158,7 +164,7 @@ impl<'a> Note { /// This should generally never be used to serialize to disk or the network. /// It is primarily added as a device for transmitting the note across /// thread boundaries. - pub fn write(&self, mut writer: &mut W) -> Result<(), IronfishError> { + pub fn write(&self, mut writer: W) -> Result<(), IronfishError> { self.owner.write(&mut writer)?; self.asset_id.write(&mut writer)?; writer.write_u64::(self.value)?; @@ -179,7 +185,7 @@ impl<'a> Note { /// This function allows the owner to decrypt the note using the derived /// shared secret and their own view key. pub fn from_owner_encrypted( - owner_view_key: &'a IncomingViewKey, + owner_view_key: &IncomingViewKey, shared_secret: &[u8; 32], encrypted_bytes: &[u8; ENCRYPTED_NOTE_SIZE + aead::MAC_SIZE], ) -> Result { @@ -349,10 +355,9 @@ impl<'a> Note { ) -> Result<(jubjub::Fr, AssetIdentifier, u64, Memo, PublicAddress), IronfishError> { let plaintext_bytes: [u8; ENCRYPTED_NOTE_SIZE] = aead::decrypt(shared_secret, encrypted_bytes)?; + let mut reader = &plaintext_bytes[..]; - let mut reader = plaintext_bytes[..].as_ref(); - - let randomness: jubjub::Fr = read_scalar(&mut reader)?; + let randomness = read_scalar(&mut reader)?; let value = reader.read_u64::()?; let mut memo = Memo::default(); diff --git a/ironfish-rust/src/serializing/mod.rs b/ironfish-rust/src/serializing/mod.rs index 1555eaf690..17c671c1e7 100644 --- a/ironfish-rust/src/serializing/mod.rs +++ b/ironfish-rust/src/serializing/mod.rs @@ -34,6 +34,16 @@ pub(crate) fn read_point(mut reader: R) -> Result .ok_or_else(|| IronfishError::new(IronfishErrorKind::InvalidData)) } +pub(crate) fn read_point_unchecked( + mut reader: R, +) -> Result { + let mut point_repr = G::Repr::default(); + reader.read_exact(point_repr.as_mut())?; + + Option::from(G::from_bytes_unchecked(&point_repr)) + .ok_or_else(|| IronfishError::new(IronfishErrorKind::InvalidData)) +} + /// Output the bytes as a hexadecimal String pub fn bytes_to_hex(bytes: &[u8]) -> String { let mut hex: Vec = vec![0; bytes.len() * 2]; diff --git a/ironfish-rust/src/transaction/tests.rs b/ironfish-rust/src/transaction/tests.rs index 5e24aef5a1..fa3e05ae9a 100644 --- a/ironfish-rust/src/transaction/tests.rs +++ b/ironfish-rust/src/transaction/tests.rs @@ -6,7 +6,9 @@ use std::collections::{BTreeMap, HashMap}; #[cfg(test)] use super::internal_batch_verify_transactions; -use super::{ProposedTransaction, Transaction}; + +use super::{ProposedTransaction, Transaction, TRANSACTION_PUBLIC_KEY_SIZE}; + use crate::test_util::create_multisig_identities; use crate::transaction::tests::split_spender_key::split_spender_key; use crate::{ @@ -23,8 +25,8 @@ use crate::{ TRANSACTION_EXPIRATION_SIZE, TRANSACTION_FEE_SIZE, TRANSACTION_SIGNATURE_SIZE, }, }; - use ff::Field; +use group::GroupEncoding; use ironfish_frost::{ frost::{round2, round2::SignatureShare, Identifier, Randomizer}, nonces::deterministic_signing_nonces, @@ -837,3 +839,79 @@ fn test_aggregate_signature_shares() { // verify transaction verify_transaction(&signed_transaction).expect("should be able to verify transaction"); } + +#[test] +fn test_add_signature_by_building_transaction() { + let spender_key = SaplingKey::generate_key(); + + // create notes + + let in_note = Note::new( + spender_key.public_address(), + 42, + "", + NATIVE_ASSET, + spender_key.public_address(), + ); + + let out_note = Note::new( + spender_key.public_address(), + 40, + "", + NATIVE_ASSET, + spender_key.public_address(), + ); + + let mut transaction = ProposedTransaction::new(TransactionVersion::latest()); + + transaction + .add_spend(in_note.clone(), &make_fake_witness(&in_note.clone())) + .unwrap(); + + transaction.add_output(out_note).unwrap(); + + let public_address: crate::PublicAddress = spender_key.public_address(); + + let intended_fee = 1; + + let mut unsigned_transaction = transaction + .build( + spender_key.proof_authorizing_key, + spender_key.view_key().clone(), + spender_key.outgoing_view_key().clone(), + intended_fee, + Some(public_address), + ) + .expect("should be able to build unsigned transaction"); + + let private_key = redjubjub::PrivateKey(spender_key.spend_authorizing_key); + let randomized_private_key = private_key.randomize(unsigned_transaction.public_key_randomness); + let transaction_hash_bytes = unsigned_transaction.transaction_signature_hash().unwrap(); + + let transaction_randomized_public_key = + redjubjub::PublicKey(spender_key.view_key.authorizing_key.into()).randomize( + unsigned_transaction.public_key_randomness, + *SPENDING_KEY_GENERATOR, + ); + + let mut data_to_be_signed = [0; 64]; + data_to_be_signed[..TRANSACTION_PUBLIC_KEY_SIZE] + .copy_from_slice(&transaction_randomized_public_key.0.to_bytes()); + data_to_be_signed[32..].copy_from_slice(&transaction_hash_bytes[..]); + + let signature = randomized_private_key.sign( + &data_to_be_signed, + &mut thread_rng(), + *SPENDING_KEY_GENERATOR, + ); + + let mut signature_bytes: [u8; 64] = [0; 64]; + + signature.write(signature_bytes.as_mut()).unwrap(); + + let signed = unsigned_transaction + .add_signature(signature_bytes) + .expect("should be able to sign transaction"); + + verify_transaction(&signed).expect("should be able to verify transaction"); +} diff --git a/ironfish-rust/src/transaction/unsigned.rs b/ironfish-rust/src/transaction/unsigned.rs index e89d45f2b4..2ff8fd90e2 100644 --- a/ironfish-rust/src/transaction/unsigned.rs +++ b/ironfish-rust/src/transaction/unsigned.rs @@ -227,15 +227,21 @@ impl UnsignedTransaction { IronfishError::new_with_source(IronfishErrorKind::FailedSignatureVerification, e) })?; - let signature = { Signature::read(&mut authorizing_group_signature.serialize().as_ref())? }; + let serialized_signature = authorizing_group_signature.serialize(); + + let transaction = self.add_signature(serialized_signature)?; + + Ok(transaction) + } + + pub fn add_signature(&mut self, signature: [u8; 64]) -> Result { + let signature = Signature::read(&signature[..])?; - // Sign spends now that we have the data needed to be signed let mut spend_descriptions = Vec::with_capacity(self.spends.len()); for spend in self.spends.drain(0..) { spend_descriptions.push(spend.add_signature(signature)); } - // Sign mints now that we have the data needed to be signed let mut mint_descriptions = Vec::with_capacity(self.mints.len()); for mint in self.mints.drain(0..) { mint_descriptions.push(mint.add_signature(signature)); @@ -315,6 +321,10 @@ impl UnsignedTransaction { self.public_key_randomness } + pub fn randomized_public_key_bytes(&self) -> [u8; 32] { + self.randomized_public_key.0.to_bytes() + } + pub fn outputs(&self) -> &Vec { &self.outputs } diff --git a/ironfish/README.md b/ironfish/README.md index b620f3e67b..53026074bf 100644 --- a/ironfish/README.md +++ b/ironfish/README.md @@ -55,5 +55,5 @@ const node = sdk.node() node.start() // List all accounts from the wallet -console.log(await node.wallet.listAccounts()) +console.log(node.wallet.accounts) ``` diff --git a/ironfish/package.json b/ironfish/package.json index ac067139f2..813a98b780 100644 --- a/ironfish/package.json +++ b/ironfish/package.json @@ -1,6 +1,6 @@ { "name": "@ironfish/sdk", - "version": "2.4.1", + "version": "2.5.0", "description": "SDK for running and interacting with an Iron Fish node", "author": "Iron Fish (https://ironfish.network)", "main": "build/src/index.js", @@ -22,7 +22,7 @@ "dependencies": { "@ethersproject/bignumber": "5.7.0", "@fast-csv/format": "4.3.5", - "@ironfish/rust-nodejs": "2.4.0", + "@ironfish/rust-nodejs": "2.5.0", "@napi-rs/blake-hash": "1.3.3", "axios": "1.7.2", "bech32": "2.0.0", @@ -41,6 +41,7 @@ "leveldown": "6.1.1", "levelup": "4.4.0", "lodash": "4.17.21", + "nock": "13.5.4", "node-datachannel": "0.8.0", "node-forge": "1.3.1", "parse-json": "5.2.0", @@ -71,7 +72,6 @@ "@types/buffer-json": "2.0.0", "@types/colors": "1.2.1", "@types/imurmurhash": "0.1.1", - "@types/jest": "29.5.8", "@types/leveldown": "4.0.2", "@types/levelup": "4.3.0", "@types/lodash": "4.14.170", diff --git a/ironfish/src/__fixtures__/chainProcessor.test.ts.fixture b/ironfish/src/__fixtures__/chainProcessor.test.ts.fixture index 40b3968114..c870be92ff 100644 --- a/ironfish/src/__fixtures__/chainProcessor.test.ts.fixture +++ b/ironfish/src/__fixtures__/chainProcessor.test.ts.fixture @@ -238,5 +238,87 @@ } ] } + ], + "ChainProcessor limits blocks processed with maxQueueSize": [ + { + "header": { + "sequence": 2, + "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", + "noteCommitment": { + "type": "Buffer", + "data": "base64:9EZ7vYfAuHAUuprnDU5VAVe9dxWtuZpD+inRrqQTrhw=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:8T95/ZdJe2TfXl2p79vhgZ/fDaoyso4zy6/dleJ1RaU=" + }, + "target": "9282972777491357380673661573939192202192629606981189395159182914949423", + "randomness": "0", + "timestamp": 1719290394961, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 4, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAA/0pQVkKqklXaDXMzjwmClRCoxt1PDoOdCIu9GfN/J9uyFwCLx48dsvjyrVdfykTQQi37Q3PEeYDz5Ztx3ishxXWnBPrnAsLeDHQWR8hw1cGujkVLIfNARZBCRCFLpD1Ta6zDxVU5Dax7dgorcL6KBUNcS8KfOk05GgQ91Wxhz5oQAtbCpbeoA6IlUlT7Jb2zYjbJIvSpfFLxd2GQEwEmfJHpQQ4LhrJfvfeutKFtP2WACNZlQ9YjuYGxjJk4uKTX2VmX+RTICZGDQj8t73jm9li0Zjrm4t+/SVgKhXANMr3gLA9PPlNjafqExtvH/VabPyb7G7G7CyCEa9qJQsCrtC+oJn6jSMQzDZ16vizio5v+ZMr4n5YlJn7Rc8ZgIR9RLGqHv9KIa8t+WDVlrsij/hYvI93l9EnEU5bmVvYY93AdxtKu5hIvL17EJlVvyaYPCPudVAXi9HdWOoAaob+uMs5KSGFx7HrnyceQo/sNpgfhvzhm4tMN9xk/kr4wa5JioILsCMQODPVQ5vHHyRSOPft3+e2lvP4wXoaW7Js4k8OcIrDR+jaLzgizllOw18cjg/wn0Fub8e+bNT+j9YjrHH7ZhLx91MA+utfFxx1AiqKhxrxgxrdAfklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwJYpWultwIyXPG98GGM/qMZHsG4otZYHF2IQvcqNVdCQhHFekvVrPNbE8n9/AHsLX4k3gDSNsSUxH2hAYRFlpBA==" + } + ] + }, + { + "header": { + "sequence": 3, + "previousBlockHash": "152059029BF9A7BD3FE699F609CF8F01616F801DD33137F7D9DDE47D26C4EEB7", + "noteCommitment": { + "type": "Buffer", + "data": "base64:hE/okdJVaojx51iv+VKf7b8Y1ikMcPWpapwytQ0x/QA=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:iZKfZUm5q84TbDyrOWyXhVK7j4qtTlYLQRxTrQB/uI0=" + }, + "target": "9255858786337818395603165512831024101510453493377417362192396248796027", + "randomness": "0", + "timestamp": 1719290395283, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 5, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAi5H+T86c4kJHlqb9KkEFjGm+WMMYQeP2EhRN3vW/O7OKKwxL1+mwZ1DtpSVs1rho5XOzh0HGRLqVE2GDz548eljHOnpnGbd+7K7gB+xrUBOsK+AtmjkaCWtOgetIus+3ZTfZDAOCIrIaBsB1LU+27gw7Hgb5irlMdUgjH6ATxO4SAruKlIORsIXNAptMbJycLIdrhLW0fwn+ivtCEHu7Tgg1GxemCbO/kLnUjAJwCQ2PW9EzBefl9q4UKg+ZdqfYTGY5pSiIJIN5BtkdXZJXmBUs2IPxFdZt14KtNrwQYm3YW+grSGEgG8mOJ+Goro+5kau1AGzK/tM/44+xp4e5SCeDe4FyGOz8N2i+hPxw/8qByNmKz0dub+wbXTVmil0BmnN0I2LOFX6LqfXH/S1zpKumHYkPsslsZv/E9Sm+MbE95V2erwmy9XW6VAdMW+20zi9V9Oj7ufgPE28xegmOQljOSmVb+qkTTWLOaor1ickSjGKwbMqB+rRx16vhKVBwipiJ2csfCbqYfdvK31+mhmgy7S8Xti03DrmKtMjMns5hRopgy0O76FevFmPJOgLV6qJ1ZmY3eNjhrqgItDnTYwYkO3NbezqXHHVDKjXgAwo2n2gbMojgUElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw4kkz3LRo7ckLiJruENNs5TdwWmk3l1Rg1fT+MWU6j0Hvl58fDt604px/q2hBQV054q6A26cUjNJGJ288qHXeAA==" + } + ] + } + ], + "ChainProcessor should remain stable if hash is head": [ + { + "header": { + "sequence": 2, + "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", + "noteCommitment": { + "type": "Buffer", + "data": "base64:DHVQe7C8CrO0PQZrmqpIxHOyLQ/s/kqcMd/SzDSE4ks=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:BsNJJNbVpE4ABdLMBD0o/FQ9JT/kOctfk16EtQLu878=" + }, + "target": "9282972777491357380673661573939192202192629606981189395159182914949423", + "randomness": "0", + "timestamp": 1719347456625, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 4, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAdsfrXOYvO2c+rICPEMxgSLNBscHmG1y5ml5fPjnjS6CYLq3OUb2AYi/gYXO0s6RIK1iIRIZvjC0ckGS93XmCmZqGhWPIPd664zIe3oO272iz/wTnBdq0yBvDuV9nSTBSk7LLVSsEZgj+M7p1H/HuHHZY6lGJNANRUKXNuyBGBOIFVHeJABxe8HvrGdxviove8KY++mSrMzJTN4OIFv1XUbAJSUUWRMMBFKaZxy0papGpCp8LQ7wur7mQO1/5M+W93RFpwqZn87LnVSPOqG3ns5y7zl2jsQJDNJ1bTbjqm5TFEA7ZLZQUj6qsTMHZpLb0mblNEX/wo5jPPKzSxCAtQrUMjAk8AgSYChpr+lyU1t+Siq0dZ/eRB158YsPHtWJNgSFu/bVZXT5woVjzHdZO8f1z3DpPK1OkMq5OiKqC8INKpWWTo09Mkse2XTwWSRP5uZuh9/2+yTQySYEfRqcP0j3sFxo2M3bmAXArWlFP7EdITysrEMzkLPiVwAD5edM3/hkw4lsws4f2VeVe9WUCIVSRjztOB1s5jE5+6CI+/y1v04/2c5lLlYTBzsSYF/dHYOSpIHHGGpE8tuOZoJMMlbmYGNFmRy/KCxCjfuzgDwwMXKAtW9K5R0lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw9U2y863G+KW6lppD3d7rHCmm60FWDhKO99ASS8BSsHHgA0Wgp16gyaLFfs/r3DhRCCuvb1keyzpTDAiMShraDQ==" + } + ] + } ] } \ No newline at end of file diff --git a/ironfish/src/assets/assetsVerifier.test.ts b/ironfish/src/assets/assetsVerifier.test.ts index e6bdcf273a..83b182d16a 100644 --- a/ironfish/src/assets/assetsVerifier.test.ts +++ b/ironfish/src/assets/assetsVerifier.test.ts @@ -1,6 +1,7 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +import type { SpyInstance } from 'jest-mock' import nock from 'nock' import { VerifiedAssetsCacheStore } from '../fileStores/verifiedAssets' import { NodeFileProvider } from '../fileSystems' @@ -35,7 +36,7 @@ const assetData3 = { describe('AssetsVerifier', () => { jest.useFakeTimers() - const waitForRefreshToFinish = async (refreshSpy: jest.SpyInstance) => { + const waitForRefreshToFinish = async (refreshSpy: SpyInstance) => { for (const result of refreshSpy.mock.results) { await result.value } diff --git a/ironfish/src/blockchain/database/transactions.ts b/ironfish/src/blockchain/database/transactions.ts index be891b94c6..3f489e2e2b 100644 --- a/ironfish/src/blockchain/database/transactions.ts +++ b/ironfish/src/blockchain/database/transactions.ts @@ -27,7 +27,7 @@ export class TransactionsValueEncoding implements IDatabaseEncoding { head: chain.genesis.hash, }) - const onEvent: jest.Mock = jest.fn() + const onEvent: Mock<(header: BlockHeader, event: 'add' | 'remove') => void> = jest.fn() processor.onAdd.on((block) => onEvent(block, 'add')) processor.onRemove.on((block) => onEvent(block, 'remove')) @@ -82,7 +83,7 @@ describe('ChainProcessor', () => { head: chain.genesis.hash, }) - const onEvent: jest.Mock = jest.fn() + const onEvent: Mock<(header: BlockHeader, event: 'add' | 'remove') => void> = jest.fn() processor.onAdd.on((block) => onEvent(block, 'add')) processor.onRemove.on((block) => onEvent(block, 'remove')) @@ -138,4 +139,77 @@ describe('ChainProcessor', () => { expect(result.hashChanged).toEqual(false) expect(processor.hash).toEqual(chain.genesis.hash) }) + + it('limits blocks processed with maxQueueSize', async () => { + const { chain } = nodeTest + + const block1 = await useMinerBlockFixture(chain) + await expect(chain).toAddBlock(block1) + const block2 = await useMinerBlockFixture(chain) + await expect(chain).toAddBlock(block2) + + expect(chain.head.hash).toEqual(block2.header.hash) + + const onEvent: Mock<(header: BlockHeader, event: 'add' | 'remove') => void> = jest.fn() + + const processor = new ChainProcessor({ chain, head: null }) + processor.onAdd.on((block) => onEvent(block, 'add')) + processor.onRemove.on((block) => onEvent(block, 'remove')) + + processor.hash = chain.genesis.hash + processor.maxQueueSize = 1 + await processor.update() + expect(onEvent).toHaveBeenCalledTimes(1) + expect(onEvent).toHaveBeenNthCalledWith(1, block1.header, 'add') + + onEvent.mockReset() + + processor.hash = chain.genesis.hash + processor.maxQueueSize = null + await processor.update() + expect(onEvent).toHaveBeenCalledTimes(2) + expect(onEvent).toHaveBeenNthCalledWith(1, block1.header, 'add') + expect(onEvent).toHaveBeenNthCalledWith(2, block2.header, 'add') + }) + + it('should remain stable if hash is head', async () => { + const { chain } = nodeTest + + const block = await useMinerBlockFixture(chain) + await expect(chain).toAddBlock(block) + expect(chain.head.hash).toEqual(block.header.hash) + + const onEvent: Mock<(header: BlockHeader, event: 'add' | 'remove') => void> = jest.fn() + + const processor = new ChainProcessor({ chain, head: chain.genesis.hash }) + processor.onAdd.on((block) => onEvent(block, 'add')) + processor.onRemove.on((block) => onEvent(block, 'remove')) + + let result = await processor.update() + expect(result.hashChanged).toBe(true) + expect(processor.hash).toEqualBuffer(block.header.hash) + expect(onEvent).toHaveBeenCalledTimes(1) + expect(onEvent).toHaveBeenNthCalledWith(1, block.header, 'add') + + onEvent.mockReset() + + result = await processor.update() + expect(result.hashChanged).toBe(false) + expect(processor.hash).toEqualBuffer(block.header.hash) + expect(onEvent).toHaveBeenCalledTimes(0) + }) + + it('should not crash if head not found', async () => { + const MISSING_HEAD = Buffer.alloc(32, 'helloworld') + const processor = new ChainProcessor({ chain: nodeTest.chain, head: MISSING_HEAD }) + + const onEvent: Mock<(header: BlockHeader, event: 'add' | 'remove') => void> = jest.fn() + processor.onAdd.on((block) => onEvent(block, 'add')) + processor.onRemove.on((block) => onEvent(block, 'remove')) + + const result = await processor.update() + expect(result.hashChanged).toBe(false) + expect(processor.hash).toEqualBuffer(MISSING_HEAD) + expect(onEvent).toHaveBeenCalledTimes(0) + }) }) diff --git a/ironfish/src/chainProcessor.ts b/ironfish/src/chainProcessor.ts index c5888c18ea..13a1ff4fcf 100644 --- a/ironfish/src/chainProcessor.ts +++ b/ironfish/src/chainProcessor.ts @@ -3,7 +3,6 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import type { Blockchain } from './blockchain' import type { BlockHeader } from './primitives' -import { Assert } from './assert' import { Event } from './event' import { createRootLogger, Logger } from './logger' @@ -35,11 +34,18 @@ export class ChainProcessor { logger: Logger onAdd = new Event<[block: BlockHeader]>() onRemove = new Event<[block: BlockHeader]>() - - constructor(options: { logger?: Logger; chain: Blockchain; head: Buffer | null }) { + maxQueueSize: number | null + + constructor(options: { + logger?: Logger + chain: Blockchain + head: Buffer | null + maxQueueSize?: number | null + }) { this.chain = options.chain this.logger = (options.logger ?? createRootLogger()).withTag('chainprocessor') this.hash = options.head + this.maxQueueSize = options.maxQueueSize ?? null } private async add(header: BlockHeader): Promise { @@ -51,8 +57,6 @@ export class ChainProcessor { } async update({ signal }: { signal?: AbortSignal } = {}): Promise<{ hashChanged: boolean }> { - const oldHash = this.hash - if (!this.hash) { await this.add(this.chain.genesis) this.hash = this.chain.genesis.hash @@ -68,10 +72,13 @@ export class ChainProcessor { const head = await this.chain.getHeader(this.hash) - Assert.isNotNull( - head, - `Chain processor head not found in chain: ${this.hash.toString('hex')}`, - ) + let blockCount = 0 + let hashChanged = false + + if (!head) { + this.logger.warn('ChainProcessor could not find head in blockchain.') + return { hashChanged } + } const fork = await this.chain.findFork(head, chainHead) @@ -82,7 +89,7 @@ export class ChainProcessor { for await (const remove of iterBackwards) { if (signal?.aborted) { - return { hashChanged: !oldHash || !this.hash.equals(oldHash) } + return { hashChanged } } if (remove.hash.equals(fork.hash)) { @@ -92,13 +99,19 @@ export class ChainProcessor { await this.remove(remove) this.hash = remove.previousBlockHash this.sequence = remove.sequence - 1 + hashChanged = true + blockCount++ + + if (this.maxQueueSize && blockCount >= this.maxQueueSize) { + return { hashChanged } + } } const iterForwards = this.chain.iterateTo(fork, chainHead, undefined, false) for await (const add of iterForwards) { if (signal?.aborted) { - return { hashChanged: !oldHash || !this.hash.equals(oldHash) } + return { hashChanged } } if (add.hash.equals(fork.hash)) { @@ -108,8 +121,14 @@ export class ChainProcessor { await this.add(add) this.hash = add.hash this.sequence = add.sequence + hashChanged = true + blockCount++ + + if (this.maxQueueSize && blockCount >= this.maxQueueSize) { + return { hashChanged } + } } - return { hashChanged: !oldHash || !this.hash.equals(oldHash) } + return { hashChanged } } } diff --git a/ironfish/src/event.test.ts b/ironfish/src/event.test.ts index 6b11f1341b..97abdd7869 100644 --- a/ironfish/src/event.test.ts +++ b/ironfish/src/event.test.ts @@ -44,7 +44,7 @@ describe('Event', () => { it('should remove once', () => { const event = new Event<[]>() - const mock = jest.fn() + const mock = jest.fn<() => void>() event.once(mock) diff --git a/ironfish/src/fileStores/config.ts b/ironfish/src/fileStores/config.ts index 85bfb9a246..7110bd0ebd 100644 --- a/ironfish/src/fileStores/config.ts +++ b/ironfish/src/fileStores/config.ts @@ -304,6 +304,14 @@ export type ConfigOptions = { */ walletSyncingMaxQueueSize: number + /** + * The max number of blocks that may be processed in parallel when syncing. + * By default, this number is automatically calculated from the number of + * workers available (see `nodeWorkers` and `nodeWorkersMax`). You may set + * this number to limit the memory usage during syncing. + */ + walletSyncingMaxConcurrency: number + /** * Whether or not to build the full fish hash context at node startup. Setting this * to `true` will slightly increase node performance but use ~4.5GB more RAM. The majority of @@ -390,6 +398,7 @@ export const ConfigOptionsSchema: yup.ObjectSchema> = yup incomingWebSocketWhitelist: yup.array(yup.string().trim().defined()), walletGossipTransactionsMaxQueueSize: yup.number(), walletSyncingMaxQueueSize: yup.number(), + walletSyncingMaxConcurrency: yup.number().integer(), fishHashFullContext: yup.boolean(), }) .defined() @@ -499,6 +508,7 @@ export class Config< incomingWebSocketWhitelist: [], walletGossipTransactionsMaxQueueSize: 1000, walletSyncingMaxQueueSize: 100, + walletSyncingMaxConcurrency: -1, fishHashFullContext: false, } } diff --git a/ironfish/src/genesis/genesis.test.slow.ts b/ironfish/src/genesis/genesis.test.slow.ts index 7868b63df8..0dee91aaf6 100644 --- a/ironfish/src/genesis/genesis.test.slow.ts +++ b/ironfish/src/genesis/genesis.test.slow.ts @@ -1,6 +1,7 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +import type { SpiedFunction } from 'jest-mock' import { Asset, generateKey } from '@ironfish/rust-nodejs' import { BlockSerde, SerializedBlock } from '../primitives/block' import { Target } from '../primitives/target' @@ -13,8 +14,8 @@ import { GenesisBlockInfo, makeGenesisBlock } from './makeGenesisBlock' describe('Read genesis block', () => { const nodeTest = createNodeTest() - let targetMeetsSpy: jest.SpyInstance - let targetSpy: jest.SpyInstance + let targetMeetsSpy: SpiedFunction + let targetSpy: SpiedFunction beforeAll(() => { targetMeetsSpy = jest.spyOn(Target, 'meets').mockImplementation(() => true) @@ -41,8 +42,8 @@ describe('Read genesis block', () => { describe('Create genesis block', () => { const nodeTest = createNodeTest(false, { autoSeed: false }) - let targetMeetsSpy: jest.SpyInstance - let targetSpy: jest.SpyInstance + let targetMeetsSpy: SpiedFunction + let targetSpy: SpiedFunction beforeAll(() => { targetMeetsSpy = jest.spyOn(Target, 'meets').mockImplementation(() => true) @@ -151,8 +152,8 @@ describe('Create genesis block', () => { describe('addGenesisTransaction', () => { const nodeTest = createNodeTest(false, { autoSeed: false }) - let targetMeetsSpy: jest.SpyInstance - let targetSpy: jest.SpyInstance + let targetMeetsSpy: SpiedFunction + let targetSpy: SpiedFunction beforeAll(() => { targetMeetsSpy = jest.spyOn(Target, 'meets').mockImplementation(() => true) diff --git a/ironfish/src/memPool/memPool.test.ts b/ironfish/src/memPool/memPool.test.ts index d1ecac23b6..fdb468372c 100644 --- a/ironfish/src/memPool/memPool.test.ts +++ b/ironfish/src/memPool/memPool.test.ts @@ -277,7 +277,9 @@ describe('MemPool', () => { describe('with an expired sequence', () => { const nodeTest = createNodeTest() - afterEach(() => jest.restoreAllMocks()) + afterEach(() => { + jest.restoreAllMocks() + }) it('returns false', async () => { const { node } = nodeTest @@ -596,10 +598,10 @@ describe('MemPool', () => { await chain.removeBlock(block.header.hash) expect(memPool.get(transaction.hash())).toBeDefined() - expect([...memPool.orderedTransactions()]).toContainEqual(transaction) + expect(memPool.orderedTransactions()).toContainEqual(transaction) expect(memPool.exists(minersFee.hash())).toBe(false) - expect([...memPool.orderedTransactions()]).not.toContainEqual(minersFee) + expect(memPool.orderedTransactions()).not.toContainEqual(minersFee) }) it('does not add back in transactions with overlapping nullifiers if fee is smaller', async () => { diff --git a/ironfish/src/network/blockFetcher.test.ts b/ironfish/src/network/blockFetcher.test.ts index 8231b412c5..3854951bff 100644 --- a/ironfish/src/network/blockFetcher.test.ts +++ b/ironfish/src/network/blockFetcher.test.ts @@ -71,7 +71,7 @@ describe('BlockFetcher', () => { expect(sentPeers).toHaveLength(1) expect(sentPeers[0].sendSpy).toHaveBeenCalledWith( - new GetCompactBlockRequest(hash, expect.any(Number)), + new GetCompactBlockRequest(hash, expect.any(Number) as unknown as number), ) await peerNetwork.stop() @@ -177,7 +177,11 @@ describe('BlockFetcher', () => { expect(peers[0].sendSpy.mock.calls).toHaveLength(1) const request = peers[0].sendSpy.mock.calls[0][0] expect(request).toEqual( - new GetBlockTransactionsRequest(block.header.hash, [1, 0, 1, 0], expect.any(Number)), + new GetBlockTransactionsRequest( + block.header.hash, + [1, 0, 1, 0], + expect.any(Number) as unknown as number, + ), ) expect(await chain.hasBlock(block.header.hash)).toBe(false) diff --git a/ironfish/src/network/peerNetwork.test.ts b/ironfish/src/network/peerNetwork.test.ts index 10d93bbcda..8d91865ccc 100644 --- a/ironfish/src/network/peerNetwork.test.ts +++ b/ironfish/src/network/peerNetwork.test.ts @@ -111,7 +111,7 @@ describe('PeerNetwork', () => { expect(peerNetwork.isReady).toBe(false) - const readyChanged = jest.fn() + const readyChanged = jest.fn<(ready: boolean) => void>() peerNetwork.onIsReadyChanged.on(readyChanged) peerNetwork.start() @@ -893,7 +893,8 @@ describe('PeerNetwork', () => { // Don't sync incoming transactions to wallet since its done async and will // attempt to update the wallet after the test has finished peerNetwork.onTransactionGossipReceived.clear() - const onTransactionGossipReceivedSpy = jest.fn() + const onTransactionGossipReceivedSpy = + jest.fn<(transaction: Transaction, valid: boolean) => void>() peerNetwork.onTransactionGossipReceived.on(onTransactionGossipReceivedSpy) await peerNetwork.peerManager.onMessage.emitAsync( @@ -1161,7 +1162,8 @@ describe('PeerNetwork', () => { // Don't sync incoming transactions to wallet since its done async and will // attempt to update the wallet after the test has finished peerNetwork.onTransactionGossipReceived.clear() - const onTransactionGossipReceivedSpy = jest.fn() + const onTransactionGossipReceivedSpy = + jest.fn<(transaction: Transaction, valid: boolean) => void>() peerNetwork.onTransactionGossipReceived.on(onTransactionGossipReceivedSpy) await peerNetwork.peerManager.onMessage.emitAsync( diff --git a/ironfish/src/network/peers/connections/connection.test.ts b/ironfish/src/network/peers/connections/connection.test.ts index ee0cb72c85..6ffa6d9663 100644 --- a/ironfish/src/network/peers/connections/connection.test.ts +++ b/ironfish/src/network/peers/connections/connection.test.ts @@ -71,7 +71,9 @@ describe('Connection', () => { features: defaultFeatures(), }) - const _sendSpy = jest.spyOn(connection, '_send').mockImplementationOnce(jest.fn()) + const _sendSpy = jest + .spyOn(connection, '_send') + .mockImplementationOnce(jest.fn<(data: Buffer) => boolean>()) expect(connection.send(message)).toBe(false) expect(_sendSpy).not.toHaveBeenCalled() diff --git a/ironfish/src/network/peers/peer.test.ts b/ironfish/src/network/peers/peer.test.ts index ebcc9caa4a..67b4b38be8 100644 --- a/ironfish/src/network/peers/peer.test.ts +++ b/ironfish/src/network/peers/peer.test.ts @@ -358,7 +358,7 @@ describe('punish', () => { connections: { webSocket: connection }, }) - const onBannedHandler = jest.fn() + const onBannedHandler = jest.fn<(reason: string) => void>() peer.onBanned.on(onBannedHandler) peer.punish(BAN_SCORE.MAX, 'TESTING') diff --git a/ironfish/src/network/peers/peerManager.test.ts b/ironfish/src/network/peers/peerManager.test.ts index 69ad2a5203..7e8ab92f87 100644 --- a/ironfish/src/network/peers/peerManager.test.ts +++ b/ironfish/src/network/peers/peerManager.test.ts @@ -9,6 +9,7 @@ import { Assert } from '../../assert' import { canInitiateWebRTC, privateIdentityToIdentity } from '../identity' import { DisconnectingMessage, DisconnectingReason } from '../messages/disconnecting' import { IdentifyMessage } from '../messages/identify' +import { NetworkMessage } from '../messages/networkMessage' import { PeerListMessage } from '../messages/peerList' import { PeerListRequestMessage } from '../messages/peerListRequest' import { SignalMessage } from '../messages/signal' @@ -30,12 +31,13 @@ import { NetworkMessageType } from '../types' import { formatWebSocketAddress } from '../utils' import { VERSION_PROTOCOL, VERSION_PROTOCOL_MIN } from '../version' import { + Connection, ConnectionDirection, ConnectionType, WebRtcConnection, WebSocketConnection, } from './connections' -import { BAN_SCORE } from './peer' +import { BAN_SCORE, Peer } from './peer' import { defaultFeatures } from './peerFeatures' import { PeerManager } from './peerManager' @@ -495,7 +497,7 @@ describe('PeerManager', () => { // Create the peer to broker the connection through const { peer: brokeringPeer } = getConnectedPeer(peers) - const brokerPeerSendMock = jest.fn() + const brokerPeerSendMock = jest.fn<(message: NetworkMessage) => Connection | null>() brokeringPeer.send = brokerPeerSendMock // Create the peer to connect to WebRTC through @@ -733,7 +735,7 @@ describe('PeerManager', () => { it('Emits onConnectedPeersChanged when a peer enters CONNECTED or DISCONNECTED', () => { const pm = new PeerManager(mockLocalPeer(), mockPeerStore()) - const onConnectedPeersChangedMock = jest.fn() + const onConnectedPeersChangedMock = jest.fn<() => void>() pm.onConnectedPeersChanged.on(onConnectedPeersChangedMock) const { peer: connecting } = getConnectingPeer(pm) @@ -1118,7 +1120,8 @@ describe('PeerManager', () => { mockLocalPeer({ identity: webRtcLocalIdentity() }), mockPeerStore(), ) - const initWebRtcConnectionMock = jest.fn() + const initWebRtcConnectionMock = + jest.fn<(peer: Peer, initiator: boolean) => WebRtcConnection>() pm['initWebRtcConnection'] = initWebRtcConnectionMock const { peer, connection } = getConnectedPeer(pm, webRtcCannotInitiateIdentity()) @@ -1142,7 +1145,8 @@ describe('PeerManager', () => { mockLocalPeer({ identity: webRtcLocalIdentity() }), mockPeerStore(), ) - const initWebRtcConnectionMock = jest.fn() + const initWebRtcConnectionMock = + jest.fn<(peer: Peer, initiator: boolean) => WebRtcConnection>() pm['initWebRtcConnection'] = initWebRtcConnectionMock const { peer, connection } = getConnectedPeer(pm, webRtcCanInitiateIdentity()) @@ -1184,7 +1188,7 @@ describe('PeerManager', () => { peer1.onMessage.emit(message, peer1Connection) const reply = new DisconnectingMessage({ - disconnectUntil: expect.any(Number), + disconnectUntil: expect.any(Number) as unknown as number, reason: DisconnectingReason.Congested, sourceIdentity: pm.localPeer.publicIdentity, destinationIdentity: webRtcCanInitiateIdentity(), @@ -1286,7 +1290,7 @@ describe('PeerManager', () => { peer1.onMessage.emit(message, peer1Connection) const reply = new DisconnectingMessage({ - disconnectUntil: expect.any(Number), + disconnectUntil: expect.any(Number) as unknown as number, reason: DisconnectingReason.Congested, sourceIdentity: pm.localPeer.publicIdentity, destinationIdentity: webRtcCannotInitiateIdentity(), diff --git a/ironfish/src/network/testUtilities/helpers.ts b/ironfish/src/network/testUtilities/helpers.ts index 5aad6a6622..06bfc7d9f1 100644 --- a/ironfish/src/network/testUtilities/helpers.ts +++ b/ironfish/src/network/testUtilities/helpers.ts @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +import type { SpiedFunction } from 'jest-mock' import { Assert } from '../../assert' import { Identity, isIdentity } from '../identity' import { GetBlockHeadersResponse } from '../messages/getBlockHeaders' @@ -91,7 +92,7 @@ export const getConnectedPeersWithSpies = ( count: number, ): { peer: Peer - sendSpy: jest.SpyInstance + sendSpy: SpiedFunction<(message: NetworkMessage) => Connection | null> }[] => { return [...Array(count)].map((_) => { const { peer } = getConnectedPeer(peerManager) diff --git a/ironfish/src/network/transactionFetcher.test.ts b/ironfish/src/network/transactionFetcher.test.ts index 86d906eea5..6e3d96ce48 100644 --- a/ironfish/src/network/transactionFetcher.test.ts +++ b/ironfish/src/network/transactionFetcher.test.ts @@ -51,7 +51,7 @@ describe('TransactionFetcher', () => { expect(sentPeers).toHaveLength(1) expect(sentPeers[0].sendSpy).toHaveBeenCalledWith( - new PooledTransactionsRequest([hash], expect.any(Number)), + new PooledTransactionsRequest([hash], expect.any(Number) as unknown as number), ) await peerNetwork.stop() diff --git a/ironfish/src/networks/network.ts b/ironfish/src/networks/network.ts index f805dd5ce2..79fd7ce904 100644 --- a/ironfish/src/networks/network.ts +++ b/ironfish/src/networks/network.ts @@ -1,11 +1,10 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import { Assert } from '../assert' import { Consensus } from '../consensus' import { SerializedBlock } from '../primitives/block' import { MathUtils } from '../utils' -import { defaultNetworkName, isDefaultNetworkId, NetworkDefinition } from './networkDefinition' +import { isDefaultNetworkId, NetworkDefinition, renderNetworkName } from './networkDefinition' export class Network { readonly default: boolean @@ -23,14 +22,7 @@ export class Network { this.consensus = new Consensus({ ...definition.consensus }) this.genesis = definition.genesis this.bootstrapNodes = definition.bootstrapNodes - - if (this.default) { - const defaultName = defaultNetworkName(definition.id) - Assert.isNotUndefined(defaultName) - this.name = defaultName - } else { - this.name = `Custom Network ${definition.id}` - } + this.name = renderNetworkName(definition.id) } /** diff --git a/ironfish/src/networks/networkDefinition.ts b/ironfish/src/networks/networkDefinition.ts index 09a42fb333..30c6785e29 100644 --- a/ironfish/src/networks/networkDefinition.ts +++ b/ironfish/src/networks/networkDefinition.ts @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import * as yup from 'yup' +import { Assert } from '../assert' import { ActivationSequence, Checkpoint, ConsensusParameters } from '../consensus' import { Config, InternalStore } from '../fileStores' import { FileSystem } from '../fileSystems' @@ -83,6 +84,16 @@ export function defaultNetworkName(networkId: number): string | undefined { } } +export function renderNetworkName(networkId: number): string { + if (isDefaultNetworkId(networkId)) { + const defaultName = defaultNetworkName(networkId) + Assert.isNotUndefined(defaultName) + return defaultName + } else { + return `Custom Network ${networkId}` + } +} + export async function getNetworkDefinition( config: Config, internal: InternalStore, diff --git a/ironfish/src/node.ts b/ironfish/src/node.ts index afa33e502a..bdd70abd05 100644 --- a/ironfish/src/node.ts +++ b/ironfish/src/node.ts @@ -327,6 +327,7 @@ export class FullNode { networkId: network.id, nodeClient: memoryClient, logger, + chain, }) const node = new FullNode({ diff --git a/ironfish/src/primitives/noteEncrypted.ts b/ironfish/src/primitives/noteEncrypted.ts index 1ff5fd4492..9dcd3744db 100644 --- a/ironfish/src/primitives/noteEncrypted.ts +++ b/ironfish/src/primitives/noteEncrypted.ts @@ -15,6 +15,14 @@ export type NoteEncryptedHash = Buffer export type SerializedNoteEncryptedHash = Buffer export type SerializedNoteEncrypted = Buffer +const ensureBuffer = (value: Buffer | string): Buffer => { + if (typeof value === 'string') { + return Buffer.from(value, 'hex') + } else { + return value + } +} + export class NoteEncrypted { private readonly noteEncryptedSerialized: Buffer @@ -22,9 +30,16 @@ export class NoteEncrypted { private noteEncrypted: NativeNoteEncrypted | null = null private referenceCount = 0 - - constructor(noteEncryptedSerialized: Buffer) { + /** + * Used to record whether the note has already been previously validated, and + * thus does not need to be checked anymore after parsing. Used to speed up + * construction of `NativeNoteEncrypted` in `takeReference`. + */ + private skipValidation: boolean + + constructor(noteEncryptedSerialized: Buffer, options?: { skipValidation?: boolean }) { this.noteEncryptedSerialized = noteEncryptedSerialized + this.skipValidation = options?.skipValidation ?? false const reader = bufio.read(noteEncryptedSerialized, true) @@ -57,7 +72,11 @@ export class NoteEncrypted { takeReference(): NativeNoteEncrypted { this.referenceCount++ if (this.noteEncrypted === null) { - this.noteEncrypted = new NativeNoteEncrypted(this.noteEncryptedSerialized) + this.noteEncrypted = new NativeNoteEncrypted( + this.noteEncryptedSerialized, + this.skipValidation, + ) + this.skipValidation = true } return this.noteEncrypted } @@ -70,16 +89,28 @@ export class NoteEncrypted { } } - decryptNoteForOwner(ownerHexKey: string): Note | undefined { - const note = this.takeReference().decryptNoteForOwner(ownerHexKey) + decryptNoteForOwner(incomingViewKey: Buffer | string): Note | undefined { + const note = this.takeReference().decryptNoteForOwner(ensureBuffer(incomingViewKey)) this.returnReference() if (note) { return new Note(note) } } - decryptNoteForSpender(spenderHexKey: string): Note | undefined { - const note = this.takeReference().decryptNoteForSpender(spenderHexKey) + decryptNoteForOwners(incomingViewKeys: Array): Array { + if (incomingViewKeys.length === 0) { + return [] + } else if (incomingViewKeys.length === 1) { + return [this.decryptNoteForOwner(incomingViewKeys[0])] + } + + const notes = this.takeReference().decryptNoteForOwners(incomingViewKeys) + this.returnReference() + return notes.map((note) => (note ? new Note(note) : undefined)) + } + + decryptNoteForSpender(outgoingViewKey: Buffer | string): Note | undefined { + const note = this.takeReference().decryptNoteForSpender(ensureBuffer(outgoingViewKey)) this.returnReference() if (note) { return new Note(note) diff --git a/ironfish/src/primitives/transaction.ts b/ironfish/src/primitives/transaction.ts index 4f3c135796..b41c0e7573 100644 --- a/ironfish/src/primitives/transaction.ts +++ b/ironfish/src/primitives/transaction.ts @@ -62,7 +62,7 @@ export class Transaction { private transactionPosted: TransactionPosted | null = null private referenceCount = 0 - constructor(transactionPostedSerialized: Buffer) { + constructor(transactionPostedSerialized: Buffer, options?: { skipValidation?: boolean }) { this.transactionPostedSerialized = transactionPostedSerialized const reader = bufio.read(this.transactionPostedSerialized, true) @@ -109,14 +109,14 @@ export class Transaction { reader.seek(PROOF_LENGTH) // output note - return new NoteEncrypted(reader.readBytes(ENCRYPTED_NOTE_LENGTH, true)) + return new NoteEncrypted(reader.readBytes(ENCRYPTED_NOTE_LENGTH, true), options) }) this.mints = Array.from({ length: _mintsLength }, () => { // proof reader.seek(PROOF_LENGTH) - const asset = Asset.deserialize(reader.readBytes(ASSET_LENGTH)) + const asset = Asset.deserialize(reader.readBytes(ASSET_LENGTH), options?.skipValidation) const value = reader.readBigU64() let owner = null diff --git a/ironfish/src/rpc/clients/client.ts b/ironfish/src/rpc/clients/client.ts index 84bb664d48..f8b70ac435 100644 --- a/ironfish/src/rpc/clients/client.ts +++ b/ironfish/src/rpc/clients/client.ts @@ -7,6 +7,8 @@ import type { AcceptTransactionResponse, AddPeerRequest, AddPeerResponse, + AddSignatureRequest, + AddSignatureResponse, AddTransactionRequest, AddTransactionResponse, AggregateSignatureSharesRequest, @@ -159,8 +161,8 @@ import type { SetConfigResponse, SetScanningRequest, SetScanningResponse, - ShowChainRequest, - ShowChainResponse, + SignTransactionRequest, + SignTransactionResponse, StopNodeResponse, SubmitBlockRequest, SubmitBlockResponse, @@ -174,6 +176,8 @@ import type { import { ApiNamespace } from '../routes/namespaces' export abstract class RpcClient { + abstract close(): void + abstract request( route: string, data?: unknown, @@ -555,6 +559,15 @@ export abstract class RpcClient { ).waitForEnd() }, + addSignature: ( + params: AddSignatureRequest, + ): Promise> => { + return this.request( + `${ApiNamespace.wallet}/addSignature`, + params, + ).waitForEnd() + }, + createTransaction: ( params: CreateTransactionRequest, ): Promise> => { @@ -564,6 +577,15 @@ export abstract class RpcClient { ).waitForEnd() }, + signTransaction: ( + params: SignTransactionRequest, + ): Promise> => { + return this.request( + `${ApiNamespace.wallet}/signTransaction`, + params, + ).waitForEnd() + }, + estimateFeeRates: ( params?: EstimateFeeRatesRequest, ): Promise> => { @@ -887,7 +909,7 @@ export abstract class RpcClient { }, getNetworkHashPower: ( - params: GetNetworkHashPowerRequest, + params: GetNetworkHashPowerRequest = undefined, ): Promise> => { return this.request( `${ApiNamespace.chain}/getNetworkHashPower`, @@ -895,15 +917,6 @@ export abstract class RpcClient { ).waitForEnd() }, - showChain: ( - params: ShowChainRequest = undefined, - ): Promise> => { - return this.request( - `${ApiNamespace.chain}/showChain`, - params, - ).waitForEnd() - }, - getTransactionStream: ( params: GetTransactionStreamRequest, ): RpcResponse => { @@ -915,11 +928,11 @@ export abstract class RpcClient { getTransaction: ( params: GetTransactionRequest, - ): RpcResponse => { - return this.request( + ): Promise> => { + return this.request( `${ApiNamespace.chain}/getTransaction`, params, - ) + ).waitForEnd() }, getConsensusParameters: ( diff --git a/ironfish/src/rpc/clients/memoryClient.ts b/ironfish/src/rpc/clients/memoryClient.ts index 436f3c4fe4..69998ce565 100644 --- a/ironfish/src/rpc/clients/memoryClient.ts +++ b/ironfish/src/rpc/clients/memoryClient.ts @@ -29,4 +29,6 @@ export class RpcMemoryClient extends RpcClient { return RpcMemoryAdapter.requestStream(this.router, route, data) } + + close(): void {} } diff --git a/ironfish/src/rpc/routes/chain/__fixtures__/serializers.test.ts.fixture b/ironfish/src/rpc/routes/chain/__fixtures__/serializers.test.ts.fixture new file mode 100644 index 0000000000..25d15107b4 --- /dev/null +++ b/ironfish/src/rpc/routes/chain/__fixtures__/serializers.test.ts.fixture @@ -0,0 +1,36 @@ +{ + "Rpc Chain Serializers should optionally return serialized": [ + { + "value": { + "version": 4, + "id": "92879eb0-acc6-432f-be27-4086746a8f81", + "name": "test", + "spendingKey": "13ae2b816c006b1ca439bb3f1f34ad5c560418ab9b7127e6b35ac15586e6a7dc", + "viewKey": "3a2fded7a277601345c41ceee3582457beac30e2fc698c0a780e0151c4485decd57749d0e52cc41c0804ff5e97901b551e5f642216b2fe7e75af95e51c0a4ee0", + "incomingViewKey": "d18c6bbd9fcd1fa9902e3981a0cbbe80f0b12eb6bf53860041bb334e38766606", + "outgoingViewKey": "d585ac8112192346000cba3a17cdf1e931cefd669d18c969ebfdda5620d8047a", + "publicAddress": "9a56d5900d757ac4837f2fc800c7426a43d6e1d69c829c11f3c17af52e870757", + "createdAt": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + }, + "scanningEnabled": true, + "proofAuthorizingKey": "438afe1b8a45c98ccc426857103a5c1c20a3cd0d13292fb40f790ed5f956a90b" + }, + "head": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + } + }, + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAszlMYP6jllK6GdKJuvklyEInkCA5L3y9zzcwbVpFhpiDRbRF0zL/rSRpqORJjsL3Aj02X8BFcx8a8aB7I1ri2/Nw5DofvDmQirYEQtli/cGLH71rd22qcT3WTsjL+G6Lsjgoif3L2nmuwkNo+dCEOBUmbUC50s8TXmBdxvc9D/wTzC5l8SFrle869DI0Lk9eTMzyGZnPxr9fDUG8Io0RaIdIFE+e9JCY85yiRR4PT5ukitq4bW2LPqCOyi0tdxGPtO0b2/iUxxYgXYJy5zklqIoHNUm09bTy91+n7Ey61WjzMy27WZ3PUqpG0oupHPvGYMBoR/OljUGwhg3p4o9yCve3+EkzQHNwNkExgq9AIQQ+XvWkp62iRR0nqtxwWtZeeJ752sZ2P7f5/LZic+LxmQMrARFWP59e9iyx4O0eNs49QHMUs9vxSG28U6CDd0kDvlWv6hfx++asQTuONFLNOGLKqOjmcKv/ZJAOxyTWMqz//OSVTj3rkz0uuwVYs4R2Qa69FRmaoadlAe5KTpTBiL83yY1rDaAKfjyC4hGLm5EzfE29qz1Z2aeHXZXsAMBVL+HoAEN9uLl25jqOCVq3JWWRCnhgfGV/G8YjEfu873eiZTy43HHdwklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwL4g+FyQGz8rRXCWSBRk+7I2l9plAKoyFyA573OzGWMVTno00WAQlRaBDu9wkH/fqF/WhxRSIUkFdcP78NOp+DA==" + } + ] +} \ No newline at end of file diff --git a/ironfish/src/rpc/routes/chain/getBlock.ts b/ironfish/src/rpc/routes/chain/getBlock.ts index 375144903a..2eb759d842 100644 --- a/ironfish/src/rpc/routes/chain/getBlock.ts +++ b/ironfish/src/rpc/routes/chain/getBlock.ts @@ -10,9 +10,8 @@ import { GENESIS_BLOCK_SEQUENCE } from '../../../primitives/block' import { RpcNotFoundError, RpcValidationError } from '../../adapters' import { ApiNamespace } from '../namespaces' import { routes } from '../router' -import { serializeRpcBlockHeader } from './serializers' +import { serializeRpcBlockHeader, serializeRpcTransaction } from './serializers' import { RpcBlock, RpcBlockSchema } from './types' -import { serializeRpcTransaction } from './utils' export type GetBlockRequest = { search?: string diff --git a/ironfish/src/rpc/routes/chain/getBlocks.ts b/ironfish/src/rpc/routes/chain/getBlocks.ts index d6deca8ccb..40ead1e4da 100644 --- a/ironfish/src/rpc/routes/chain/getBlocks.ts +++ b/ironfish/src/rpc/routes/chain/getBlocks.ts @@ -8,8 +8,8 @@ import { BlockchainUtils } from '../../../utils/blockchain' import { RpcNotFoundError, RpcValidationError } from '../../adapters' import { ApiNamespace } from '../namespaces' import { routes } from '../router' +import { serializeRpcBlock } from './serializers' import { RpcBlock, RpcBlockSchema } from './types' -import { serializeRpcBlock } from './utils' export type GetBlocksRequest = { /** diff --git a/ironfish/src/rpc/routes/chain/getNetworkHashPower.test.ts b/ironfish/src/rpc/routes/chain/getNetworkHashPower.test.ts index 9192441121..698d66456d 100644 --- a/ironfish/src/rpc/routes/chain/getNetworkHashPower.test.ts +++ b/ironfish/src/rpc/routes/chain/getNetworkHashPower.test.ts @@ -26,7 +26,8 @@ describe('Route chain/getNetworkHashPower', () => { await Promise.all([expect(routeTest.node.chain).toAddBlock(block)]) await Promise.all([routeTest.node.wallet.scan()]) } - const response = await routeTest.client.chain.getNetworkHashPower({}) + const response = await routeTest.client.chain.getNetworkHashPower() + expect(response.content).toEqual( expect.objectContaining({ hashesPerSecond: expect.any(Number), diff --git a/ironfish/src/rpc/routes/chain/getNetworkHashPower.ts b/ironfish/src/rpc/routes/chain/getNetworkHashPower.ts index dd3f5c2416..6744bbc6ba 100644 --- a/ironfish/src/rpc/routes/chain/getNetworkHashPower.ts +++ b/ironfish/src/rpc/routes/chain/getNetworkHashPower.ts @@ -9,10 +9,12 @@ import { RpcValidationError } from '../../adapters' import { ApiNamespace } from '../namespaces' import { routes } from '../router' -export type GetNetworkHashPowerRequest = { - blocks?: number | null // number of blocks to look back - sequence?: number | null // the sequence of the latest block from when to estimate the network speed -} +export type GetNetworkHashPowerRequest = + | { + blocks?: number | null // number of blocks to look back + sequence?: number | null // the sequence of the latest block from when to estimate the network speed + } + | undefined export type GetNetworkHashPowerResponse = { hashesPerSecond: number @@ -26,7 +28,7 @@ export const GetNetworkHashPowerRequestSchema: yup.ObjectSchema = yup diff --git a/ironfish/src/rpc/routes/chain/getTransaction.ts b/ironfish/src/rpc/routes/chain/getTransaction.ts index 3719ba01a5..f288f2bfdf 100644 --- a/ironfish/src/rpc/routes/chain/getTransaction.ts +++ b/ironfish/src/rpc/routes/chain/getTransaction.ts @@ -3,13 +3,12 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import * as yup from 'yup' import { Assert } from '../../../assert' -import { getTransactionSize } from '../../../network/utils/serializers' import { FullNode } from '../../../node' import { BlockHashSerdeInstance } from '../../../serde' -import { CurrencyUtils } from '../../../utils' import { RpcNotFoundError, RpcValidationError } from '../../adapters' import { ApiNamespace } from '../namespaces' import { routes } from '../router' +import { serializeRpcTransaction } from './serializers' import { RpcTransaction, RpcTransactionSchema } from './types' export type GetTransactionRequest = { transactionHash: string; blockHash?: string } @@ -82,57 +81,25 @@ routes.register( const transactions = await context.chain.getBlockTransactions(blockHeader) - const foundTransaction = transactions.find(({ transaction }) => + const chainTransaction = transactions.find(({ transaction }) => transaction.hash().equals(transactionHashBuffer), ) - if (!foundTransaction) { + if (!chainTransaction) { throw new RpcNotFoundError( `Transaction not found on block ${blockHashBuffer.toString('hex')}`, ) } - const { transaction, initialNoteIndex } = foundTransaction - - const rawTransaction: GetTransactionResponse = { - fee: Number(transaction.fee()), - expiration: transaction.expiration(), - hash: transaction.hash().toString('hex'), - size: getTransactionSize(transaction), - noteSize: initialNoteIndex + transaction.notes.length, - notesCount: transaction.notes.length, - spendsCount: transaction.spends.length, - signature: transaction.transactionSignature().toString('hex'), - notesEncrypted: transaction.notes.map((note) => note.serialize().toString('hex')), - notes: transaction.notes.map((note) => ({ - commitment: note.hash().toString('hex'), - hash: note.hash().toString('hex'), - serialized: note.serialize().toString('hex'), - })), - mints: transaction.mints.map((mint) => ({ - assetId: mint.asset.id().toString('hex'), - id: mint.asset.id().toString('hex'), - assetName: mint.asset.name().toString('hex'), - value: CurrencyUtils.encode(mint.value), - name: mint.asset.name().toString('hex'), - metadata: mint.asset.metadata().toString('hex'), - creator: mint.asset.creator().toString('hex'), - transferOwnershipTo: mint.transferOwnershipTo?.toString('hex'), - })), - burns: transaction.burns.map((burn) => ({ - assetId: burn.assetId.toString('hex'), - id: burn.assetId.toString('hex'), - assetName: '', - value: CurrencyUtils.encode(burn.value), - })), - spends: transaction.spends.map((spend) => ({ - nullifier: spend.nullifier.toString('hex'), - commitment: spend.commitment.toString('hex'), - size: spend.size, - })), + request.end({ + ...serializeRpcTransaction(chainTransaction.transaction, true), blockHash: blockHashBuffer.toString('hex'), - } - - request.end(rawTransaction) + noteSize: chainTransaction.initialNoteIndex + chainTransaction.transaction.notes.length, + notesCount: chainTransaction.transaction.notes.length, + spendsCount: chainTransaction.transaction.spends.length, + notesEncrypted: chainTransaction.transaction.notes.map((note) => + note.serialize().toString('hex'), + ), + }) }, ) diff --git a/ironfish/src/rpc/routes/chain/index.ts b/ironfish/src/rpc/routes/chain/index.ts index 003667fd9f..08b7744cf1 100644 --- a/ironfish/src/rpc/routes/chain/index.ts +++ b/ironfish/src/rpc/routes/chain/index.ts @@ -14,7 +14,6 @@ export * from './getDifficulty' export * from './getNetworkHashPower' export * from './getTransaction' export * from './getTransactionStream' -export * from './showChain' export * from './getConsensusParameters' export * from './getAsset' export * from './getNetworkInfo' diff --git a/ironfish/src/rpc/routes/chain/serializers.test.ts b/ironfish/src/rpc/routes/chain/serializers.test.ts new file mode 100644 index 0000000000..27a445b9ba --- /dev/null +++ b/ironfish/src/rpc/routes/chain/serializers.test.ts @@ -0,0 +1,26 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +import { useMinersTxFixture } from '../../../testUtilities/fixtures' +import { createNodeTest } from '../../../testUtilities/nodeTest' +import { serializeRpcTransaction } from './serializers' + +describe('Rpc Chain Serializers', () => { + const nodeTest = createNodeTest() + + it('should optionally return serialized', async () => { + const transaction = await useMinersTxFixture(nodeTest.node) + + // Should include serialized formats + let serialized = serializeRpcTransaction(transaction, true) + expect(serialized.serialized).toBe(transaction.serialize().toString('hex')) + expect(serialized.notes[0].serialized).toBe( + transaction.notes[0].serialize().toString('hex'), + ) + + // Now should not include them + serialized = serializeRpcTransaction(transaction, false) + expect(serialized.serialized).not.toBeDefined() + expect(serialized.notes[0].serialized).not.toBeDefined() + }) +}) diff --git a/ironfish/src/rpc/routes/chain/serializers.ts b/ironfish/src/rpc/routes/chain/serializers.ts index 17f0d950a1..8da71e4d3b 100644 --- a/ironfish/src/rpc/routes/chain/serializers.ts +++ b/ironfish/src/rpc/routes/chain/serializers.ts @@ -4,8 +4,9 @@ import { getBlockSize, getTransactionSize } from '../../../network/utils/serializers' import { Block, BlockHeader, Target, Transaction } from '../../../primitives' +import { NoteEncrypted } from '../../../primitives/noteEncrypted' import { BufferUtils } from '../../../utils' -import { RpcBlock, RpcBlockHeader, RpcTransaction } from './types' +import { RpcBlock, RpcBlockHeader, RpcEncryptedNote, RpcTransaction } from './types' export function serializeRpcBlockHeader(header: BlockHeader): RpcBlockHeader { return { @@ -57,6 +58,17 @@ export const serializeRpcBlock = (block: Block, serialized?: boolean): RpcBlock } } +export const serializeRpcEncryptedNote = ( + note: NoteEncrypted, + serialized?: boolean, +): RpcEncryptedNote => { + return { + commitment: note.hash().toString('hex'), + hash: note.hash().toString('hex'), + ...(serialized ? { serialized: note.serialize().toString('hex') } : undefined), + } +} + export const serializeRpcTransaction = ( tx: Transaction, serialized?: boolean, @@ -66,11 +78,9 @@ export const serializeRpcTransaction = ( size: getTransactionSize(tx), fee: Number(tx.fee()), expiration: tx.expiration(), - notes: tx.notes.map((note) => ({ - commitment: note.hash().toString('hex'), - hash: note.hash().toString('hex'), - serialized: note.serialize().toString('hex'), - })), + notes: tx.notes.map((note) => { + return serializeRpcEncryptedNote(note, serialized) + }), spends: tx.spends.map((spend) => ({ nullifier: spend.nullifier.toString('hex'), commitment: spend.commitment.toString('hex'), diff --git a/ironfish/src/rpc/routes/chain/showChain.ts b/ironfish/src/rpc/routes/chain/showChain.ts deleted file mode 100644 index 25c4e5dfb5..0000000000 --- a/ironfish/src/rpc/routes/chain/showChain.ts +++ /dev/null @@ -1,51 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -import * as yup from 'yup' -import { Assert } from '../../../assert' -import { FullNode } from '../../../node' -import { ApiNamespace } from '../namespaces' -import { routes } from '../router' -import { renderChain } from './utils' - -export type ShowChainRequest = - | { - start?: number | null - stop?: number | null - } - | undefined - -export type ShowChainResponse = { - content: string[] -} - -export const ShowChainRequestSchema: yup.ObjectSchema = yup - .object({ - start: yup.number().nullable().optional(), - stop: yup.number().nullable().optional(), - }) - .optional() - -export const ShowChainResponseSchema: yup.ObjectSchema = yup - .object({ - content: yup.array(yup.string().defined()).defined(), - }) - .defined() - -/** - * Render the chain as ani ASCII graph of the block chain - */ -routes.register( - `${ApiNamespace.chain}/showChain`, - ShowChainRequestSchema, - async (request, context): Promise => { - Assert.isInstanceOf(context, FullNode) - - const content = await renderChain(context.chain, request.data?.start, request.data?.stop, { - indent: ' ', - work: false, - }) - - request.end({ content }) - }, -) diff --git a/ironfish/src/rpc/routes/chain/types.ts b/ironfish/src/rpc/routes/chain/types.ts index 4cc9847fea..9ca7ee0f4e 100644 --- a/ironfish/src/rpc/routes/chain/types.ts +++ b/ironfish/src/rpc/routes/chain/types.ts @@ -21,7 +21,7 @@ export const RpcSpendSchema: yup.ObjectSchema = yup export type RpcEncryptedNote = { hash: string - serialized: string + serialized?: string /** * @deprecated Please use hash instead */ @@ -32,7 +32,7 @@ export const RpcEncryptedNoteSchema: yup.ObjectSchema = yup .object({ commitment: yup.string().defined(), hash: yup.string().defined(), - serialized: yup.string().defined(), + serialized: yup.string().optional(), }) .defined() diff --git a/ironfish/src/rpc/routes/chain/utils.ts b/ironfish/src/rpc/routes/chain/utils.ts index 0d14f9abfe..77a5be4b7c 100644 --- a/ironfish/src/rpc/routes/chain/utils.ts +++ b/ironfish/src/rpc/routes/chain/utils.ts @@ -6,13 +6,8 @@ import { Assert } from '../../../assert' import { Blockchain } from '../../../blockchain' import { VerificationResult } from '../../../consensus/verifier' import { createRootLogger, Logger } from '../../../logger' -import { getBlockSize, getTransactionSize } from '../../../network/utils/serializers' -import { Block, Transaction } from '../../../primitives' import { BlockHeader } from '../../../primitives/blockheader' -import { BlockchainUtils, BufferUtils, HashUtils } from '../../../utils' -import { serializeRpcBlockHeader } from './serializers' -import { RpcBlock } from './types' -import { RpcTransaction } from './types' +import { BlockchainUtils, HashUtils } from '../../../utils' const DEFAULT_OPTIONS = { seq: true, @@ -166,58 +161,3 @@ export async function renderGraph( } } } - -export const serializeRpcBlock = (block: Block, serialized?: boolean): RpcBlock => { - const blockHeaderResponse = serializeRpcBlockHeader(block.header) - - const transactions: RpcTransaction[] = [] - for (const tx of block.transactions) { - transactions.push(serializeRpcTransaction(tx, serialized)) - } - - return { - ...blockHeaderResponse, - size: getBlockSize(block), - transactions, - } -} - -export const serializeRpcTransaction = ( - tx: Transaction, - serialized?: boolean, -): RpcTransaction => { - return { - hash: tx.hash().toString('hex'), - size: getTransactionSize(tx), - fee: Number(tx.fee()), - expiration: tx.expiration(), - notes: tx.notes.map((note) => ({ - commitment: note.hash().toString('hex'), - hash: note.hash().toString('hex'), - serialized: note.serialize().toString('hex'), - })), - spends: tx.spends.map((spend) => ({ - nullifier: spend.nullifier.toString('hex'), - commitment: spend.commitment.toString('hex'), - size: spend.size, - })), - mints: tx.mints.map((mint) => ({ - id: mint.asset.id().toString('hex'), - metadata: BufferUtils.toHuman(mint.asset.metadata()), - name: BufferUtils.toHuman(mint.asset.name()), - creator: mint.asset.creator().toString('hex'), - value: mint.value.toString(), - transferOwnershipTo: mint.transferOwnershipTo?.toString('hex'), - assetId: mint.asset.id().toString('hex'), - assetName: mint.asset.name().toString('hex'), - })), - burns: tx.burns.map((burn) => ({ - id: burn.assetId.toString('hex'), - value: burn.value.toString(), - assetId: burn.assetId.toString('hex'), - assetName: '', - })), - signature: tx.transactionSignature().toString('hex'), - ...(serialized ? { serialized: tx.serialize().toString('hex') } : {}), - } -} diff --git a/ironfish/src/rpc/routes/faucet/getFunds.test.ts b/ironfish/src/rpc/routes/faucet/getFunds.test.ts index df055379ca..8eab7589a0 100644 --- a/ironfish/src/rpc/routes/faucet/getFunds.test.ts +++ b/ironfish/src/rpc/routes/faucet/getFunds.test.ts @@ -25,7 +25,9 @@ describe('Route faucet.getFunds', () => { it('returns a 200 status code', async () => { routeTest.node.config.set('getFundsApi', 'foo.com') - axios.post = jest.fn().mockImplementationOnce(() => Promise.resolve({ data: { id: 5 } })) + axios.post = jest + .fn() + .mockResolvedValueOnce({ data: { id: 5 } }) as typeof axios.post const response = await routeTest.client .request('faucet/getFunds', { @@ -46,7 +48,7 @@ describe('Route faucet.getFunds', () => { describe('when too many faucet requests have been made', () => { it('throws an error', async () => { - axios.post = jest.fn().mockImplementationOnce(() => { + axios.post = jest.fn().mockImplementationOnce(() => { throw { response: { data: { @@ -55,7 +57,7 @@ describe('Route faucet.getFunds', () => { }, }, } - }) + }) as typeof axios.post await expect( routeTest.client.faucet.getFunds({ account: accountName, email }), ).rejects.toThrow(RpcRequestError) @@ -65,7 +67,9 @@ describe('Route faucet.getFunds', () => { describe('when the API request fails', () => { it('throws an error', async () => { const apiResponse = new Error('API failure') as AxiosError - axios.post = jest.fn().mockRejectedValueOnce(apiResponse) + axios.post = jest + .fn() + .mockRejectedValueOnce(apiResponse) as typeof axios.post await expect( routeTest.client.faucet.getFunds({ account: accountName, email }), ).rejects.toThrow('API failure') diff --git a/ironfish/src/rpc/routes/node/stopNode.test.ts b/ironfish/src/rpc/routes/node/stopNode.test.ts index c583f84a88..00107f4d49 100644 --- a/ironfish/src/rpc/routes/node/stopNode.test.ts +++ b/ironfish/src/rpc/routes/node/stopNode.test.ts @@ -7,7 +7,7 @@ describe('Route node.getStatus', () => { const routeTest = createRouteTest() it('should get status', async () => { - routeTest.node.shutdown = jest.fn() + routeTest.node.shutdown = jest.fn<() => Promise>() const response = await routeTest.client.node.stopNode() expect(response.status).toBe(200) diff --git a/ironfish/src/rpc/routes/wallet/__fixtures__/addSignature.test.ts.fixture b/ironfish/src/rpc/routes/wallet/__fixtures__/addSignature.test.ts.fixture new file mode 100644 index 0000000000..47c40f17fa --- /dev/null +++ b/ironfish/src/rpc/routes/wallet/__fixtures__/addSignature.test.ts.fixture @@ -0,0 +1,32 @@ +{ + "Route wallet/addSignature should return error if signature is not a valid hex": [ + { + "value": { + "version": 4, + "id": "0e9f1f07-ee9d-4746-a4e8-131d89d71345", + "name": "addSignatureAccount2", + "spendingKey": "21557df84c37fa55363c77ffe99a6d01a1c1938f06b805b34a2d2f3442016d3c", + "viewKey": "4d8f669c3667195906dcc4e636983d653e6042267fffb3b7ed1a00e8aeacf7011382ac8e43e6f446f3751dca9640eb7d684b88c181feec8f1399863b0e389c95", + "incomingViewKey": "9f13a57239aba9daade572166257ae494807e6436a9eaaf5bf312855e225d906", + "outgoingViewKey": "5c156963119e3fbdccd84d08622eae4dbbc36ada56e30682188a338fe9be0ed6", + "publicAddress": "608569ba934ef7bb6c6bc99e653b7ab18eb17bf02602c8fc489c3286d1065f2c", + "createdAt": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + }, + "scanningEnabled": true, + "proofAuthorizingKey": "0b3bcdc835ee3709c9a30cad80c36d0d4f5d5712349d6bbfd34da9ed405bbc02" + }, + "head": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + } + } + ] +} \ No newline at end of file diff --git a/ironfish/src/rpc/routes/wallet/addSignature.test.ts b/ironfish/src/rpc/routes/wallet/addSignature.test.ts new file mode 100644 index 0000000000..9d57c1ca49 --- /dev/null +++ b/ironfish/src/rpc/routes/wallet/addSignature.test.ts @@ -0,0 +1,36 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +import { RawTransactionSerde } from '../../../primitives' +import { useAccountFixture } from '../../../testUtilities' +import { createRawTransaction } from '../../../testUtilities/helpers/transaction' +import { createRouteTest } from '../../../testUtilities/routeTest' + +describe('Route wallet/addSignature', () => { + const routeTest = createRouteTest(true) + + it('should return error if signature is not a valid hex', async () => { + const account = await useAccountFixture(routeTest.node.wallet, 'addSignatureAccount') + const rawTransaction = await createRawTransaction({ + wallet: routeTest.node.wallet, + from: account, + }) + + const response = await routeTest.client.wallet.buildTransaction({ + rawTransaction: RawTransactionSerde.serialize(rawTransaction).toString('hex'), + account: account.name, + }) + + expect(response.status).toBe(200) + expect(response.content.unsignedTransaction).toBeDefined() + + const invalidSignature = 'invalid' + + await expect( + routeTest.client.wallet.addSignature({ + unsignedTransaction: response.content.unsignedTransaction, + signature: invalidSignature, + }), + ).rejects.toThrow('Invalid signature length') + }) +}) diff --git a/ironfish/src/rpc/routes/wallet/addSignature.ts b/ironfish/src/rpc/routes/wallet/addSignature.ts new file mode 100644 index 0000000000..a21383923b --- /dev/null +++ b/ironfish/src/rpc/routes/wallet/addSignature.ts @@ -0,0 +1,70 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +import { generateRandomizedPublicKey, UnsignedTransaction } from '@ironfish/rust-nodejs' +import * as yup from 'yup' +import { Account } from '../../../wallet' +import { ApiNamespace } from '../namespaces' +import { routes } from '../router' +import { AssertHasRpcContext } from '../rpcContext' + +export type AddSignatureRequest = { + unsignedTransaction: string + signature: string +} + +export type AddSignatureResponse = { + transaction: string + account: string +} + +export const AddSignatureRequestSchema: yup.ObjectSchema = yup + .object({ + unsignedTransaction: yup.string().defined(), + signature: yup.string().defined(), + }) + .defined() + +export const AddSignatureResponseSchema: yup.ObjectSchema = yup + .object({ + transaction: yup.string().defined(), + account: yup.string().defined(), + }) + .defined() + +routes.register( + `${ApiNamespace.wallet}/addSignature`, + AddSignatureRequestSchema, + (request, node): void => { + AssertHasRpcContext(request, node, 'wallet') + const unsignedTransaction = new UnsignedTransaction( + Buffer.from(request.data.unsignedTransaction, 'hex'), + ) + + const buffer = Buffer.from(request.data.signature, 'hex') + + if (buffer.length !== 64) { + throw new Error('Invalid signature length') + } + + const publicKeyRandomness = unsignedTransaction.publicKeyRandomness() + const randomizedPublicKey = unsignedTransaction.randomizedPublicKey() + + const account = node.wallet.findAccount( + (account: Account) => + generateRandomizedPublicKey(account.viewKey, publicKeyRandomness) === + randomizedPublicKey, + ) + + if (!account) { + throw new Error('Wallet does not contain sender account for this transaction.') + } + + const serialized = unsignedTransaction.addSignature(buffer) + + request.end({ + transaction: serialized.toString('hex'), + account: account.name, + }) + }, +) diff --git a/ironfish/src/rpc/routes/wallet/addTransaction.ts b/ironfish/src/rpc/routes/wallet/addTransaction.ts index 7c9a3301c6..e1083af83f 100644 --- a/ironfish/src/rpc/routes/wallet/addTransaction.ts +++ b/ironfish/src/rpc/routes/wallet/addTransaction.ts @@ -53,7 +53,7 @@ routes.register( await context.wallet.addPendingTransaction(transaction) - const accounts = await AsyncUtils.filter(context.wallet.listAccounts(), (account) => + const accounts = await AsyncUtils.filter(context.wallet.accounts, (account) => account.hasTransaction(transaction.hash()), ) diff --git a/ironfish/src/rpc/routes/wallet/getAccounts.ts b/ironfish/src/rpc/routes/wallet/getAccounts.ts index 234ea3e3ed..608beb46f9 100644 --- a/ironfish/src/rpc/routes/wallet/getAccounts.ts +++ b/ironfish/src/rpc/routes/wallet/getAccounts.ts @@ -38,7 +38,7 @@ routes.register( accounts = [defaultAccount] } } else { - accounts = node.wallet.listAccounts() + accounts = node.wallet.accounts } const names = accounts.map((a) => (request.data?.displayName ? a.displayName : a.name)) diff --git a/ironfish/src/rpc/routes/wallet/getAccountsStatus.ts b/ironfish/src/rpc/routes/wallet/getAccountsStatus.ts index b53bcfcbea..d91a976566 100644 --- a/ironfish/src/rpc/routes/wallet/getAccountsStatus.ts +++ b/ironfish/src/rpc/routes/wallet/getAccountsStatus.ts @@ -32,9 +32,7 @@ routes.register serializeRpcAccountStatus(node.wallet, account)), + node.wallet.accounts.map((account) => serializeRpcAccountStatus(node.wallet, account)), ) request.end({ accounts }) diff --git a/ironfish/src/rpc/routes/wallet/index.ts b/ironfish/src/rpc/routes/wallet/index.ts index 446008ccb1..775f5ebbe5 100644 --- a/ironfish/src/rpc/routes/wallet/index.ts +++ b/ironfish/src/rpc/routes/wallet/index.ts @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -export * from './setAccountHead' +export * from './addSignature' export * from './addTransaction' export * from './buildTransaction' export * from './burnAsset' @@ -12,10 +12,10 @@ export * from './createTransaction' export * from './estimateFeeRates' export * from './exportAccount' export * from './getAccountNotesStream' -export * from './getAccounts' export * from './getAccountStatus' export * from './getAccountTransaction' export * from './getAccountTransactions' +export * from './getAccounts' export * from './getAccountsStatus' export * from './getAsset' export * from './getAssets' @@ -38,7 +38,9 @@ export * from './renameAccount' export * from './rescan' export * from './resetAccount' export * from './sendTransaction' +export * from './setAccountHead' export * from './setScanning' +export * from './signTransaction' export * from './types' export * from './use' export * from './useAccount' diff --git a/ironfish/src/rpc/routes/wallet/postTransaction.ts b/ironfish/src/rpc/routes/wallet/postTransaction.ts index f763a86c28..326b41792b 100644 --- a/ironfish/src/rpc/routes/wallet/postTransaction.ts +++ b/ironfish/src/rpc/routes/wallet/postTransaction.ts @@ -3,6 +3,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import * as yup from 'yup' import { RawTransactionSerde } from '../../../primitives/rawTransaction' +import { Account } from '../../../wallet' import { RpcValidationError } from '../../adapters' import { ApiNamespace } from '../namespaces' import { routes } from '../router' @@ -55,7 +56,9 @@ routes.register( throw new RpcValidationError('Unable to determine sender account for raw transaction') } - const account = context.wallet.getAccountByPublicAddress(sender) + const account = context.wallet.findAccount( + (account: Account) => account.publicAddress === sender && account.isSpendingAccount(), + ) if (account === null) { throw new RpcValidationError( diff --git a/ironfish/src/rpc/routes/wallet/signTransaction.ts b/ironfish/src/rpc/routes/wallet/signTransaction.ts new file mode 100644 index 0000000000..24b5a3ce58 --- /dev/null +++ b/ironfish/src/rpc/routes/wallet/signTransaction.ts @@ -0,0 +1,66 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +import { generateRandomizedPublicKey, UnsignedTransaction } from '@ironfish/rust-nodejs' +import * as yup from 'yup' +import { Account } from '../../../wallet' +import { ApiNamespace } from '../namespaces' +import { routes } from '../router' +import { AssertHasRpcContext } from '../rpcContext' + +export type SignTransactionRequest = { + unsignedTransaction: string +} + +export type SignTransactionResponse = { + transaction: string + account: string +} + +export const SignTransactionRequestSchema: yup.ObjectSchema = yup + .object({ + unsignedTransaction: yup.string().defined(), + }) + .defined() + +export const SignTransactionResponseSchema: yup.ObjectSchema = yup + .object({ + transaction: yup.string().defined(), + account: yup.string().defined(), + }) + .defined() + +routes.register( + `${ApiNamespace.wallet}/signTransaction`, + SignTransactionRequestSchema, + (request, context): void => { + AssertHasRpcContext(request, context, 'wallet') + const unsignedTransaction = new UnsignedTransaction( + Buffer.from(request.data.unsignedTransaction, 'hex'), + ) + + const publicKeyRandomness = unsignedTransaction.publicKeyRandomness() + const randomizedPublicKey = unsignedTransaction.randomizedPublicKey() + + const account = context.wallet.findAccount( + (account: Account) => + generateRandomizedPublicKey(account.viewKey, publicKeyRandomness) === + randomizedPublicKey, + ) + + if (!account) { + throw new Error('Wallet does not contain sender account for this transaction.') + } + + if (!account.spendingKey) { + throw new Error('Account does not have a spending key') + } + + const serialized = unsignedTransaction.sign(account.spendingKey) + + request.end({ + transaction: serialized.toString('hex'), + account: account.name, + }) + }, +) diff --git a/ironfish/src/rpc/routes/wallet/utils.ts b/ironfish/src/rpc/routes/wallet/utils.ts index 55b76fdf9a..4e7b343d83 100644 --- a/ironfish/src/rpc/routes/wallet/utils.ts +++ b/ironfish/src/rpc/routes/wallet/utils.ts @@ -41,9 +41,9 @@ export async function getTransactionNotes( const accountKeys = [ { accountId: account.id, - incomingViewKey: account.incomingViewKey, - outgoingViewKey: account.outgoingViewKey, - viewKey: account.viewKey, + incomingViewKey: Buffer.from(account.incomingViewKey, 'hex'), + outgoingViewKey: Buffer.from(account.outgoingViewKey, 'hex'), + viewKey: Buffer.from(account.viewKey, 'hex'), }, ] @@ -80,7 +80,7 @@ export async function getTransactionNotes( Assert.isNotUndefined(decryptedSends) for (const note of decryptedSends) { - if (note === null) { + if (note === undefined) { continue } diff --git a/ironfish/src/sdk.test.ts b/ironfish/src/sdk.test.ts index f8d5900d7b..a12f52b19c 100644 --- a/ironfish/src/sdk.test.ts +++ b/ironfish/src/sdk.test.ts @@ -285,7 +285,7 @@ describe('IronfishSdk', () => { expect(connect).toHaveBeenCalledTimes(1) expect(client).toBeInstanceOf(RpcIpcClient) - expect(client).toMatchObject(sdk.client) + expect(client).toEqual(sdk.client) }) }) @@ -303,7 +303,7 @@ describe('IronfishSdk', () => { expect(connect).toHaveBeenCalledTimes(1) expect(client).toBeInstanceOf(RpcTcpClient) - expect(client).toMatchObject(sdk.client) + expect(client).toEqual(sdk.client) }) }) }) diff --git a/ironfish/src/storage/database.test.ts b/ironfish/src/storage/database.test.ts index 4da8396fbf..0935bf7e98 100644 --- a/ironfish/src/storage/database.test.ts +++ b/ironfish/src/storage/database.test.ts @@ -167,9 +167,9 @@ describe('Database', () => { const clearRange = StorageUtils.getPrefixKeyRange(Buffer.from('2')) - expect(await testStore.getAllKeys()).toMatchObject(['1', '2a', '2b', '3']) + expect(await testStore.getAllKeys()).toEqual(['1', '2a', '2b', '3']) await testStore.clear(undefined, clearRange) - expect(await testStore.getAllKeys()).toMatchObject(['1', '3']) + expect(await testStore.getAllKeys()).toEqual(['1', '3']) }) it('should clear store in a transaction', async () => { @@ -205,9 +205,9 @@ describe('Database', () => { const clearRange = StorageUtils.getPrefixKeyRange(Buffer.from('2')) - await expect(testStore.getAllKeys(tx)).resolves.toMatchObject(['1', '2a', '2b', '3']) + await expect(testStore.getAllKeys(tx)).resolves.toEqual(['1', '2a', '2b', '3']) await testStore.clear(tx, clearRange) - await expect(testStore.getAllKeys(tx)).resolves.toMatchObject(['1', '3']) + await expect(testStore.getAllKeys(tx)).resolves.toEqual(['1', '3']) }) }) @@ -617,8 +617,8 @@ describe('Database', () => { await db.metaStore.put('c', 1002) await db.metaStore.put('d', 1003) - await expect(db.metaStore.getAllKeys()).resolves.toMatchObject(['a', 'b', 'c', 'd']) - await expect(db.metaStore.getAllValues()).resolves.toMatchObject([1000, 1001, 1002, 1003]) + await expect(db.metaStore.getAllKeys()).resolves.toEqual(['a', 'b', 'c', 'd']) + await expect(db.metaStore.getAllValues()).resolves.toEqual([1000, 1001, 1002, 1003]) }) it('should get all keys and values in a range', async () => { @@ -635,14 +635,14 @@ describe('Database', () => { gte: Buffer.from('b'), lt: Buffer.from('d'), }), - ).resolves.toMatchObject([1001, 1002]) + ).resolves.toEqual([1001, 1002]) await expect( db.metaStore.getAllKeys(undefined, { gte: Buffer.from('b'), lt: Buffer.from('d'), }), - ).resolves.toMatchObject(['b', 'c']) + ).resolves.toEqual(['b', 'c']) }) it('should encode and decode keys', async () => { @@ -759,27 +759,27 @@ describe('Database', () => { await db.transaction(async (tx) => { await expect( db.metaStore.getAllKeys(tx, undefined, { ordered: true }), - ).resolves.toMatchObject(['a', 'b', 'd', 'e']) + ).resolves.toEqual(['a', 'b', 'd', 'e']) await expect( db.metaStore.getAllValues(tx, undefined, { ordered: true }), - ).resolves.toMatchObject([1001, 1003, 1002, 1000]) + ).resolves.toEqual([1001, 1003, 1002, 1000]) await db.metaStore.put('a', 1004, tx) await db.metaStore.put('c', 999, tx) await expect( db.metaStore.getAllKeys(tx, undefined, { ordered: true }), - ).resolves.toMatchObject(['a', 'b', 'c', 'd', 'e']) + ).resolves.toEqual(['a', 'b', 'c', 'd', 'e']) await expect( db.metaStore.getAllValues(tx, undefined, { ordered: true }), - ).resolves.toMatchObject([1004, 1003, 999, 1002, 1000]) + ).resolves.toEqual([1004, 1003, 999, 1002, 1000]) await expect( db.metaStore.getAllKeys(tx, undefined, { ordered: true, reverse: true }), - ).resolves.toMatchObject(['e', 'd', 'c', 'b', 'a']) + ).resolves.toEqual(['e', 'd', 'c', 'b', 'a']) await expect( db.metaStore.getAllValues(tx, undefined, { ordered: true, reverse: true }), - ).resolves.toMatchObject([1000, 1002, 999, 1003, 1004]) + ).resolves.toEqual([1000, 1002, 999, 1003, 1004]) }) }) }) diff --git a/ironfish/src/storage/database/encoding.test.ts b/ironfish/src/storage/database/encoding.test.ts index d1df25a8d9..bf208c074c 100644 --- a/ironfish/src/storage/database/encoding.test.ts +++ b/ironfish/src/storage/database/encoding.test.ts @@ -109,38 +109,38 @@ describe('Encoding', () => { await expect(prefixStore.get(['b', 'b'])).resolves.toBe('b') // Iteration operations - await expect(prefixStore.getAllValues()).resolves.toMatchObject(['a', 'b']) - await expect(prefixStore.getAllKeys()).resolves.toMatchObject([ + await expect(prefixStore.getAllValues()).resolves.toEqual(['a', 'b']) + await expect(prefixStore.getAllKeys()).resolves.toEqual([ ['a', 'a'], ['b', 'b'], ]) - await expect(prefixStore.getAllValues(undefined, keyRangeA)).resolves.toMatchObject(['a']) - await expect(prefixStore.getAllValues(undefined, keyRangeB)).resolves.toMatchObject(['b']) + await expect(prefixStore.getAllValues(undefined, keyRangeA)).resolves.toEqual(['a']) + await expect(prefixStore.getAllValues(undefined, keyRangeB)).resolves.toEqual(['b']) await prefixStore.clear(undefined, keyRangeA) await expect(prefixStore.get(['a', 'a'])).resolves.toBe(undefined) await expect(prefixStore.get(['b', 'b'])).resolves.toBe('b') - await expect(prefixStore.getAllValues(undefined, keyRangeA)).resolves.toMatchObject([]) - await expect(prefixStore.getAllValues(undefined, keyRangeB)).resolves.toMatchObject(['b']) + await expect(prefixStore.getAllValues(undefined, keyRangeA)).resolves.toEqual([]) + await expect(prefixStore.getAllValues(undefined, keyRangeB)).resolves.toEqual(['b']) await prefixStore.clear(undefined, keyRangeB) // Now try transactions await db.transaction(async (tx) => { await prefixStore.put(['a', 'a'], 'a', tx) - await expect(prefixStore.getAllValues(tx, keyRangeA)).resolves.toMatchObject(['a']) + await expect(prefixStore.getAllValues(tx, keyRangeA)).resolves.toEqual(['a']) await prefixStore.clear(tx, keyRangeA) - await expect(prefixStore.getAllValues(tx, keyRangeA)).resolves.toMatchObject([]) + await expect(prefixStore.getAllValues(tx, keyRangeA)).resolves.toEqual([]) await prefixStore.put(['b', 'b'], 'b', tx) - await expect(prefixStore.getAllValues(tx, keyRangeB)).resolves.toMatchObject(['b']) + await expect(prefixStore.getAllValues(tx, keyRangeB)).resolves.toEqual(['b']) await prefixStore.clear(tx, keyRangeB) - await expect(prefixStore.getAllValues(tx, keyRangeB)).resolves.toMatchObject([]) + await expect(prefixStore.getAllValues(tx, keyRangeB)).resolves.toEqual([]) }) - await expect(prefixStore.getAllValues(undefined, keyRangeA)).resolves.toMatchObject([]) - await expect(prefixStore.getAllValues(undefined, keyRangeB)).resolves.toMatchObject([]) + await expect(prefixStore.getAllValues(undefined, keyRangeA)).resolves.toEqual([]) + await expect(prefixStore.getAllValues(undefined, keyRangeB)).resolves.toEqual([]) }) it('should error with incorrect prefix size', async () => { diff --git a/ironfish/src/syncer.test.ts b/ironfish/src/syncer.test.ts index 4b0f2a82d4..9733840833 100644 --- a/ironfish/src/syncer.test.ts +++ b/ironfish/src/syncer.test.ts @@ -113,7 +113,7 @@ describe('Syncer', () => { const syncFromSpy = jest.spyOn(syncer, 'syncFrom') const [promise, , reject] = PromiseUtils.split() - syncFromSpy.mockResolvedValue(promise) + syncFromSpy.mockReturnValue(promise) syncer['startSync'](peer) expect(syncer.stopping).not.toBe(null) @@ -143,7 +143,7 @@ describe('Syncer', () => { const syncFromSpy = jest.spyOn(syncer, 'syncFrom') const [promise, resolve] = PromiseUtils.split() - syncFromSpy.mockResolvedValue(promise) + syncFromSpy.mockReturnValue(promise) syncer['startSync'](peer) expect(syncer.stopping).not.toBe(null) @@ -264,7 +264,7 @@ describe('Syncer', () => { const syncFromSpy = jest.spyOn(syncer, 'syncFrom') const [promise, resolve] = PromiseUtils.split() - syncFromSpy.mockResolvedValue(promise) + syncFromSpy.mockReturnValue(promise) syncer['startSync'](peer) // Set the nextMeasureTime to be less than now, which is the trigger to diff --git a/ironfish/src/telemetry/telemetry.test.ts b/ironfish/src/telemetry/telemetry.test.ts index 6e42e4cdac..38c19bfd5f 100644 --- a/ironfish/src/telemetry/telemetry.test.ts +++ b/ironfish/src/telemetry/telemetry.test.ts @@ -86,7 +86,9 @@ describe('Telemetry', () => { const points = telemetry['points'] expect(points).toHaveLength(currentPointsLength + 1) - expect(points[points.length - 1]).toMatchObject(mockMetric) + expect(points[points.length - 1]).toMatchObject( + mockMetric as unknown as Record, + ) }) }) diff --git a/ironfish/src/testHarness.ts b/ironfish/src/testHarness.ts new file mode 100644 index 0000000000..f89eb8062d --- /dev/null +++ b/ironfish/src/testHarness.ts @@ -0,0 +1,25 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +import type { Jest } from '@jest/environment' +import type { JestExpect } from '@jest/expect' +import type { Global } from '@jest/types' + +declare global { + const { + it, + test, + fit, + xit, + xtest, + describe, + xdescribe, + fdescribe, + beforeAll, + beforeEach, + afterEach, + afterAll, + }: Global.GlobalAdditions + const expect: JestExpect + const jest: Jest +} diff --git a/ironfish/src/testUtilities/matchers/blockchain.ts b/ironfish/src/testUtilities/matchers/blockchain.ts index 51df5c1209..08c770cc39 100644 --- a/ironfish/src/testUtilities/matchers/blockchain.ts +++ b/ironfish/src/testUtilities/matchers/blockchain.ts @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +import type { AsyncExpectationResult, SyncExpectationResult } from 'expect' import { diff } from 'jest-diff' import { Blockchain } from '../../blockchain' import { Block } from '../../primitives/block' @@ -12,7 +13,7 @@ import { makeError, makeResult } from './utils' function toEqualHash( self: BlockHash | null | undefined, other: BlockHash | null | undefined, -): jest.CustomMatcherResult { +): SyncExpectationResult { let error: string | null = null if (!self || !other) { @@ -26,7 +27,7 @@ function toEqualHash( return makeError(error, `Expected two serde elements to match, but they didn't`) } -function toEqualNullifier(self: Nullifier, other: Nullifier): jest.CustomMatcherResult { +function toEqualNullifier(self: Nullifier, other: Nullifier): SyncExpectationResult { let error: string | null = null if (!self || !other) { @@ -40,7 +41,7 @@ function toEqualNullifier(self: Nullifier, other: Nullifier): jest.CustomMatcher return makeError(error, `Expected two serde elements to match, but they didn't`) } -async function toAddBlock(self: Blockchain, other: Block): Promise { +async function toAddBlock(self: Blockchain, other: Block): AsyncExpectationResult { const result = await self.addBlock(other) if (!result.isAdded) { @@ -50,10 +51,7 @@ async function toAddBlock(self: Blockchain, other: Block): Promise { +async function toAddDoubleSpendBlock(self: Blockchain, other: Block): AsyncExpectationResult { // Mock data stores to allow creation of a double spend chain const transactionHashMock = jest .spyOn(self, 'transactionHashHasBlock') @@ -83,13 +81,12 @@ expect.extend({ toAddDoubleSpendBlock: toAddDoubleSpendBlock, }) -declare global { - namespace jest { - interface Matchers { - toEqualNullifier(other: Nullifier): R - toEqualHash(other: BlockHash | null | undefined): R - toAddBlock(block: Block): Promise - toAddDoubleSpendBlock(block: Block): Promise - } +declare module 'expect' { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + interface Matchers, T = unknown> { + toEqualNullifier(other: Nullifier): R + toEqualHash(other: BlockHash | null | undefined): R + toAddBlock(block: Block): Promise + toAddDoubleSpendBlock(block: Block): Promise } } diff --git a/ironfish/src/testUtilities/matchers/buffer.ts b/ironfish/src/testUtilities/matchers/buffer.ts index 7e9caa4664..f5f20adee8 100644 --- a/ironfish/src/testUtilities/matchers/buffer.ts +++ b/ironfish/src/testUtilities/matchers/buffer.ts @@ -2,13 +2,14 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +import type { SyncExpectationResult } from 'expect' import { diff } from 'jest-diff' import { makeResult } from './utils' function toEqualBuffer( self: Buffer | null | undefined, other: Buffer | null | undefined, -): jest.CustomMatcherResult { +): SyncExpectationResult { const pass = self === other || (!self && !other) || (self && other && self.equals(other)) if (!pass) { @@ -28,10 +29,9 @@ function toEqualBuffer( expect.extend({ toEqualBuffer: toEqualBuffer }) -declare global { - namespace jest { - interface Matchers { - toEqualBuffer(other: Buffer | null | undefined): R - } +declare module 'expect' { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + interface Matchers, T = unknown> { + toEqualBuffer(other: Buffer | null | undefined): R } } diff --git a/ironfish/src/testUtilities/matchers/index.ts b/ironfish/src/testUtilities/matchers/index.ts index f9b69a0db0..f39e133312 100644 --- a/ironfish/src/testUtilities/matchers/index.ts +++ b/ironfish/src/testUtilities/matchers/index.ts @@ -3,6 +3,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import './blockchain' +import './transaction' import './buffer' import './merkletree' import './string' diff --git a/ironfish/src/testUtilities/matchers/merkletree.ts b/ironfish/src/testUtilities/matchers/merkletree.ts index 373f141928..674856b4e3 100644 --- a/ironfish/src/testUtilities/matchers/merkletree.ts +++ b/ironfish/src/testUtilities/matchers/merkletree.ts @@ -2,19 +2,19 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +import type { AsyncExpectationResult, SyncExpectationResult } from 'expect' import { diff } from 'jest-diff' import { MerkleTree, Witness, WitnessSide } from '../../merkletree' import { NodeValue } from '../../merkletree/schema' import { makeError } from './utils' -declare global { - namespace jest { - interface Matchers { - toHaveLeaves(characters: string, parents: number[]): Promise - toHaveNodes(nodeSpecs: [number, WitnessSide, number, string][]): Promise - toMatchTree(other: MerkleTree): Promise - toMatchWitness(treeSize: number, rootHash: string, authPath: [WitnessSide, string][]): R - } +declare module 'expect' { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + interface Matchers, T = unknown> { + toHaveLeaves(characters: string, parents: number[]): Promise + toHaveNodes(nodeSpecs: [number, WitnessSide, number, string][]): Promise + toMatchTree(other: MerkleTree): Promise + toMatchWitness(treeSize: number, rootHash: string, authPath: [WitnessSide, string][]): R } } @@ -23,7 +23,7 @@ expect.extend({ tree: MerkleTree, characters: string, parents: number[], - ): Promise { + ): AsyncExpectationResult { let error: string | null = null const treeSize = await tree.size() @@ -54,7 +54,7 @@ expect.extend({ async toHaveNodes( tree: MerkleTree, nodeSpecs: [number, WitnessSide, number, string][], - ): Promise { + ): AsyncExpectationResult { let error: string | null = null const treeNodes = await tree.nodes.getAllValues() @@ -105,7 +105,7 @@ expect.extend({ async toMatchTree( tree: MerkleTree, other: MerkleTree, - ): Promise { + ): AsyncExpectationResult { let error: string | null = null const treeLeafCount = await tree.getCount('Leaves') const treeNodeCount = await tree.getCount('Nodes') @@ -152,7 +152,7 @@ expect.extend({ treeSize: number, rootHash: string, authenticationPath: [WitnessSide, string][], - ): jest.CustomMatcherResult { + ): SyncExpectationResult { let error: string | null = null if (witness === undefined) { diff --git a/ironfish/src/testUtilities/matchers/string.ts b/ironfish/src/testUtilities/matchers/string.ts index 67ad51654e..06954ba470 100644 --- a/ironfish/src/testUtilities/matchers/string.ts +++ b/ironfish/src/testUtilities/matchers/string.ts @@ -2,9 +2,10 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +import type { SyncExpectationResult } from 'expect' import { makeResult } from './utils' -function toBeBase64(self: string | null | undefined): jest.CustomMatcherResult { +function toBeBase64(self: string | null | undefined): SyncExpectationResult { const pass = !!self && self === Buffer.from(self, 'base64').toString('base64') if (!pass) { @@ -16,10 +17,9 @@ function toBeBase64(self: string | null | undefined): jest.CustomMatcherResult { expect.extend({ toBeBase64 }) -declare global { - namespace jest { - interface Matchers { - toBeBase64(): R - } +declare module 'expect' { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + interface Matchers, T = unknown> { + toBeBase64(): R } } diff --git a/ironfish/src/testUtilities/matchers/transaction.ts b/ironfish/src/testUtilities/matchers/transaction.ts new file mode 100644 index 0000000000..3af7297ba0 --- /dev/null +++ b/ironfish/src/testUtilities/matchers/transaction.ts @@ -0,0 +1,19 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +import { Transaction } from '../../primitives/transaction' + +function areTransactionsEqual(a: unknown, b: unknown): boolean | undefined { + const isATransaction = a instanceof Transaction + const isBTransaction = b instanceof Transaction + + if (isATransaction && isBTransaction) { + return a.equals(b) + } else if (!isATransaction && !isBTransaction) { + return undefined + } else { + return false + } +} + +expect.addEqualityTesters([areTransactionsEqual]) diff --git a/ironfish/src/testUtilities/mocks.ts b/ironfish/src/testUtilities/mocks.ts index a39ea31c6d..9f37deb686 100644 --- a/ironfish/src/testUtilities/mocks.ts +++ b/ironfish/src/testUtilities/mocks.ts @@ -30,7 +30,7 @@ export function mockWallet(): any { export function mockVerifier(): any { return { - verifyNewTransaction: jest.fn().mockResolvedValue({}), + verifyNewTransaction: jest.fn<(...args: any[]) => Promise>().mockResolvedValue({}), } } @@ -107,6 +107,6 @@ export function mockWorkerPool(): any { export function mockConfig(values: Record): any { return { - get: jest.fn((x) => values[x]), + get: jest.fn((x: string) => values[x]), } } diff --git a/ironfish/src/testUtilities/utils.test.ts b/ironfish/src/testUtilities/utils.test.ts deleted file mode 100644 index 75438d67b5..0000000000 --- a/ironfish/src/testUtilities/utils.test.ts +++ /dev/null @@ -1,53 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ - -import { mockImplementationShuffle } from './utils' - -describe('Mocks', () => { - it('should shuffle mock', async () => { - const mock = jest.fn() - - const results: number[] = [] - - mockImplementationShuffle<[number], void>(mock, (value: number) => { - results.push(value) - return Promise.resolve() - }) - - const promises = [] - for (let i = 0; i < 10; ++i) { - promises.push(mock(i)) - } - await Promise.all(promises) - - expect(results).toHaveLength(10) - }) - - it('should allow cancelation', () => { - jest.useFakeTimers() - - const mock = jest.fn() - const results: number[] = [] - - function mockImplementation(value: number) { - results.push(value) - return Promise.resolve(value) - } - - // it should have the result from the shuffled result - mockImplementationShuffle(mock, mockImplementation, 1) - mock(0) - jest.runAllTimers() - expect(results).toHaveLength(1) - - results.length = 0 - - // when we call cancel it should not have the result - const cancelShuffle = mockImplementationShuffle(mock, mockImplementation, 1) - mock(0) - cancelShuffle() - jest.runAllTimers() - expect(results).toHaveLength(0) - }) -}) diff --git a/ironfish/src/testUtilities/utils.ts b/ironfish/src/testUtilities/utils.ts index dc8f961bff..9deb2e1c84 100644 --- a/ironfish/src/testUtilities/utils.ts +++ b/ironfish/src/testUtilities/utils.ts @@ -66,67 +66,3 @@ export async function splitNotes( Assert.isNotNull(account.spendingKey) return transaction.post(account.spendingKey) } - -/** - * Asserts the type of a given function as a Jest mock. - */ -export function typeMock( - func: (...args: [...T]) => R, -): jest.Mock { - return func as jest.Mock -} - -/** - * Used to shuffle the responses from an asynchronous API call using a debounce strategy. - * @param mock The mock to intercept calls for and shuffle - * @param mocked The mock function to replace mock with - * @param time The maximum amount of debounce time to allow before returning shuffled results - */ -export function mockImplementationShuffle( - mock: jest.Mock, TArgs>, - mocked: (...args: TArgs) => Promise, - time = 10, -): () => void { - type PromiseResolve = (result: Promise) => void - const buffer: [TArgs, PromiseResolve][] = [] - let lastTimeout: number | null = null - let lastSend: number | null = null - - mock.mockImplementation((...args: TArgs): Promise => { - const promise = new Promise>((resolve) => { - if (lastTimeout) { - clearTimeout(lastTimeout) - } - - buffer.push([args, resolve]) - - function send() { - lastSend = Date.now() - - const shuffled = buffer.slice().sort(() => Math.random() - 0.5) - buffer.length = 0 - - for (const [args, resolve] of shuffled) { - resolve(mocked(...args)) - } - } - - // Force a send if the maximum amount of time has elapsed - if (lastSend !== null && Date.now() - lastSend > time) { - send() - return - } - - // Start the debounce timer - lastTimeout = setTimeout(send, time) as unknown as number - }) - - return promise.then((r) => r) - }) - - return () => { - if (lastTimeout) { - clearTimeout(lastTimeout) - } - } -} diff --git a/ironfish/src/utils/array.test.ts b/ironfish/src/utils/array.test.ts new file mode 100644 index 0000000000..032a4c3c58 --- /dev/null +++ b/ironfish/src/utils/array.test.ts @@ -0,0 +1,50 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +import { Assert } from '../assert' +import { ArrayUtils } from './array' + +describe('ArrayUtils', () => { + it('shuffles array', () => { + const items: number[] = [] + for (let i = 0; i <= 10000; ++i) { + items.push(i) + } + + const shuffled = ArrayUtils.shuffle(items) + expect(shuffled).not.toEqual(items) + expect(shuffled.sort((a, b) => a - b)).toEqual(items) + }) + + it('sample a random item', () => { + // single element + expect(ArrayUtils.sample([2])).toBe(2) + + // empty array + expect(ArrayUtils.sample([])).toBeNull() + + // test randomness + const samples = [0, 1, 2] + const found = new Set(samples) + + for (let i = 0; i < 10000; ++i) { + const sample = ArrayUtils.sample(samples) + Assert.isNotNull(sample) + found.delete(sample) + } + + expect(found.size).toBe(0) + }) + + it('removes an item in places', () => { + const items = [0, 1, 2] + + let removed = ArrayUtils.remove(items, 1) + expect(removed).toBe(true) + expect(items).toEqual([0, 2]) + + removed = ArrayUtils.remove(items, 100) + expect(removed).toBe(false) + expect(items).toEqual([0, 2]) + }) +}) diff --git a/ironfish/src/utils/asyncQueue.test.ts b/ironfish/src/utils/asyncQueue.test.ts new file mode 100644 index 0000000000..582a7a03d1 --- /dev/null +++ b/ironfish/src/utils/asyncQueue.test.ts @@ -0,0 +1,144 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +import { AsyncQueue } from './asyncQueue' +import { PromiseUtils } from './promise' + +describe('AsyncQueue', () => { + it('yields items in the same order as they were added', async () => { + const queue = new AsyncQueue(32) + + await queue.push('a') + await queue.push('b') + await queue.push('c') + + await expect(queue.pop()).resolves.toBe('a') + await expect(queue.pop()).resolves.toBe('b') + await expect(queue.pop()).resolves.toBe('c') + }) + + it('reports correct length after push and pop', async () => { + const queue = new AsyncQueue(32) + expect(queue.size).toBe(0) + + for (let size = 1; size <= 20; size++) { + await queue.push('a') + expect(queue.size).toBe(size) + } + + for (let size = 19; size >= 0; size--) { + await queue.pop() + expect(queue.size).toBe(size) + } + }) + + it('randomized test', async () => { + const sequence = [] + for (let i = 0; i < 10000; i++) { + sequence.push(i) + } + + const queue = new AsyncQueue(128) + const pushedItems = new Array() + const poppedItems = new Array() + + let i = 0 + while (poppedItems.length < sequence.length) { + const action: 'push' | 'pop' = + // if the queue is empty, the only possible action is 'push' + pushedItems.length === poppedItems.length + ? 'push' + : // if the queue is full, the only action is 'pop' + pushedItems.length - poppedItems.length >= 128 + ? 'pop' + : // in all other cases, flip a coin + Math.random() > 0.5 + ? 'push' + : 'pop' + if (action === 'push') { + const item = sequence[i++] + await queue.push(item) + pushedItems.push(item) + } else if (action === 'pop') { + const item = await queue.pop() + poppedItems.push(item) + } + } + + expect(pushedItems).toEqual(sequence) + expect(poppedItems).toEqual(sequence) + }) + + describe('push', () => { + it('blocks when the queue is full', async () => { + const queue = new AsyncQueue(2) + await queue.push('a') + await queue.push('b') + + // Queue is full; pushing a new element now should cause the returned + // promise not to be resolved + const pushPromise = queue.push('c').then(() => 'pushPromise') + const otherPromise = new Promise((resolve) => setTimeout(resolve, 100)).then( + () => 'otherPromise', + ) + + const [promise, res, rej] = PromiseUtils.split() + pushPromise.then(res, rej) + otherPromise.then(res, rej) + + const resolved = await promise + expect(resolved).toBe('otherPromise') + + // After popping an element, the promise returned by push should resolve + await queue.pop() + await pushPromise + }) + }) + + describe('pop', () => { + it('blocks when the queue is empty', async () => { + const queue = new AsyncQueue(2) + + // Queue is empty; popping an element now should cause the returned + // promise not to be resolved + const popPromise = queue.pop().then(() => 'popPromise') + const otherPromise = new Promise((resolve) => setTimeout(resolve, 100)).then( + () => 'otherPromise', + ) + + const [promise, res, rej] = PromiseUtils.split() + popPromise.then(res, rej) + otherPromise.then(res, rej) + + const resolved = await promise + expect(resolved).toBe('otherPromise') + + // After pushing a new element, the promise returned by pop should + // resolve + await queue.push('a') + await popPromise + }) + }) + + describe('iterator', () => { + it('does not yield any item when empty', () => { + const queue = new AsyncQueue(5) + + expect(Array.from(queue)).toEqual([]) + }) + + it('yields items without consuming them', async () => { + const queue = new AsyncQueue(5) + + await queue.push('a') + await queue.push('b') + await queue.push('c') + + expect(Array.from(queue)).toEqual(['a', 'b', 'c']) + + await expect(queue.pop()).resolves.toBe('a') + await expect(queue.pop()).resolves.toBe('b') + await expect(queue.pop()).resolves.toBe('c') + }) + }) +}) diff --git a/ironfish/src/utils/asyncQueue.ts b/ironfish/src/utils/asyncQueue.ts new file mode 100644 index 0000000000..45dec47232 --- /dev/null +++ b/ironfish/src/utils/asyncQueue.ts @@ -0,0 +1,151 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +const EMPTY = Symbol('EMPTY') + +function assertValidMaxSize(maxSize: number) { + if (!Number.isInteger(maxSize)) { + throw new Error('maxSize must be an integer') + } + if (maxSize <= 0) { + throw new Error('maxSize must be greater than 0') + } +} + +function assertNotEmpty(x: T | typeof EMPTY): asserts x is T { + if (x === EMPTY) { + throw new Error('Expected item not to be empty') + } +} + +/** + * A fixed-size, async queue, implemented on top of a circular buffer. + */ +export class AsyncQueue { + /** + * The circular buffer that backs the queue. + */ + private readonly items: Array + /** + * The position of the first element in `items`. Calling `pop()` returns `items[start]` + * (if non-empty). + */ + private start: number = 0 + /** + * The number of elements currently sitting in the queue. This can never exceed + * `items.length`. + */ + private len: number = 0 + + private onReadyToPush: Promise + private onReadyToPop: Promise + + private triggerReadyToPush: (() => void) | null = null + private triggerReadyToPop: (() => void) | null = null + + constructor(maxSize: number) { + assertValidMaxSize(maxSize) + + this.items = Array(maxSize).fill(EMPTY) as Array + + this.onReadyToPush = Promise.resolve() + this.onReadyToPop = new Promise((resolve) => { + this.triggerReadyToPop = resolve + }) + } + + get size(): number { + return this.len + } + + get maxSize(): number { + return this.items.length + } + + isEmpty(): boolean { + return this.len === 0 + } + + isFull(): boolean { + return this.len === this.items.length + } + + /** + * Adds a new element to the end of the queue. If the queue is full, waits until at + * least one element is popped. + */ + async push(item: Item): Promise { + while (this.isFull()) { + await this.onReadyToPush + } + + // TODO: should we consider allowing only powers of 2 as maxSize, so that we can use a + // bit shift instead of a modulo operation? + const index = (this.start + this.len) % this.items.length + this.items[index] = item + this.len += 1 + + if (this.triggerReadyToPop && !this.isEmpty()) { + this.triggerReadyToPop() + this.triggerReadyToPop = null + } + if (this.isFull()) { + this.onReadyToPush = new Promise((resolve) => { + this.triggerReadyToPush = resolve + }) + } + } + + /** + * Removes one element from the start of the queue. If the queue is empty, waits until + * at least one element is pushed. + */ + async pop(): Promise { + while (this.isEmpty()) { + await this.onReadyToPop + } + + const item = this.items[this.start] + this.items[this.start] = EMPTY + this.start = (this.start + 1) % this.items.length + this.len -= 1 + + if (this.triggerReadyToPush && !this.isFull()) { + this.triggerReadyToPush() + this.triggerReadyToPush = null + } + if (this.isEmpty()) { + this.onReadyToPop = new Promise((resolve) => { + this.triggerReadyToPop = resolve + }) + } + + assertNotEmpty(item) + return item + } + + *[Symbol.iterator](): Generator { + for (let i = 0; i < this.len; i++) { + const j = (this.start + i) % this.items.length + const item = this.items[j] + if (item === EMPTY) { + break + } + yield item + } + } + + clear() { + this.len = 0 + this.items.fill(EMPTY) + + if (this.triggerReadyToPush) { + this.triggerReadyToPush() + this.triggerReadyToPush = null + } + this.onReadyToPop = new Promise((resolve) => { + this.triggerReadyToPop = resolve + }) + } +} diff --git a/ironfish/src/utils/bloomFilter.test.ts b/ironfish/src/utils/bloomFilter.test.ts new file mode 100644 index 0000000000..c7c7067b0d --- /dev/null +++ b/ironfish/src/utils/bloomFilter.test.ts @@ -0,0 +1,53 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +import { randomBytes } from 'crypto' +import { BloomFilter } from './bloomFilter' + +describe('BloomFilter', () => { + describe('maybeHas', () => { + it('always returns false when empty', () => { + const filter = new BloomFilter(256) + + for (let i = 0; i < 1000; i++) { + const item = randomBytes(32) + expect(filter.maybeHas(item)).toBe(false) + } + }) + + it('returns true for all items that were explicitly put', () => { + const filter = new BloomFilter(256) + + for (let i = 0; i < 1000; i++) { + const item = randomBytes(32) + filter.put(item) + expect(filter.maybeHas(item)).toBe(true) + } + }) + + it('returns true for items that were not explicitly but, but have the same prefix as previously put items', () => { + const filter = new BloomFilter(512) + + const samePrefix = [ + Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]), + Buffer.from([1, 2, 3, 4, 9, 10, 11, 12]), + Buffer.from([1, 2, 3, 4, 13, 14, 15, 16]), + ] + const differentPrefix = [ + Buffer.from([1, 1, 1, 1, 1, 1, 1, 1]), + Buffer.from([2, 2, 2, 2, 2, 2, 2, 2]), + Buffer.from([3, 3, 3, 3, 3, 3, 3, 3]), + ] + + filter.put(samePrefix[0]) + + for (const item of samePrefix) { + expect(filter.maybeHas(item)).toBe(true) + } + for (const item of differentPrefix) { + expect(filter.maybeHas(item)).toBe(false) + } + }) + }) +}) diff --git a/ironfish/src/utils/bloomFilter.ts b/ironfish/src/utils/bloomFilter.ts new file mode 100644 index 0000000000..aa7ee583dc --- /dev/null +++ b/ironfish/src/utils/bloomFilter.ts @@ -0,0 +1,77 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +function isPowerOf2(n: number): boolean { + // This checks that n is non-zero, and that n and n-1 have no bits in common + // (taken from https://stackoverflow.com/a/30924333) + return !!(n && !(n & (n - 1))) +} + +/** + * Simple implementation of a bloom filter. This is a set-like data structure + * that can be used to check whether certain items may or may not be present in + * the set. This is a probabilistic data structure that does not return false + * negatives, but may return false positives. + * + * Usually, bloom filters work by computing the hash of each item added to the + * set. This implementation differs in that it does not compute any hash for + * efficiency, and instead assumes that each item contains random data. Items + * that share the same prefix will result in collisions/false positives. + */ +export class BloomFilter { + private readonly bitMask: number + private readonly bitArray: Buffer + + constructor(bits: number) { + if (bits < 8) { + // Need to have at least 1 byte + throw new Error(`bits must be at least 8 (got ${bits})`) + } + if (bits >= 1 << 30) { + // `bits` cannot exceed 2**30 because `indexOf` relies on + // `Buffer.readUInt32LE` (also, the array would be larger than 128 MiB, + // which may not be desiderable). This is 30 and not 32 because `1 << 32 + // === 1` and `1 << 31 === -2147483648` + throw new Error(`bits cannot exceed 2**30 (got ${bits})`) + } + if (!isPowerOf2(bits)) { + // Having `bits` as a power of 2 means that `bytes` (calculated below) + // will be a power of 2, and this allows efficient items lookup without + // using any modulo operator + throw new Error(`bits must be a power of 2`) + } + const bytes = bits >> 3 + this.bitArray = Buffer.alloc(bytes) + this.bitMask = bits - 1 + } + + private indexOf(item: Buffer): [byte: number, bit: number] { + // One of the assumption for this BloomFilter is that the items contain + // random data, so that we can skip hashing it. With that assumption in + // mind, we take the first `bits` out of `item` and use that as the index + // in the array. + const index = item.readUInt32LE(0) & this.bitMask + const byte = index >> 3 + const bit = index & 0b111 + return [byte, bit] + } + + /** + * Adds the item to the set. + */ + put(item: Buffer) { + const [byte, bit] = this.indexOf(item) + this.bitArray[byte] |= 1 << bit + } + + /** + * Returns true if the item *may* have been previously added by a call to + * `put()`, false otherwise. This method may return false positives, but + * never returns false negatives. + */ + maybeHas(item: Buffer): boolean { + const [byte, bit] = this.indexOf(item) + return !!(this.bitArray[byte] & (1 << bit)) + } +} diff --git a/ironfish/src/utils/retry.test.ts b/ironfish/src/utils/retry.test.ts index 6d36ca0e91..f68388e81a 100644 --- a/ironfish/src/utils/retry.test.ts +++ b/ironfish/src/utils/retry.test.ts @@ -10,7 +10,7 @@ describe('Retry', () => { jest.useFakeTimers({ legacyFakeTimers: false }) it('immediately returns when there is no error', async () => { - const fn = jest.fn().mockResolvedValue(123) + const fn = jest.fn<() => Promise>().mockResolvedValue(123) const retry = new Retry({ delay: 1000, jitter: 0.2, @@ -23,7 +23,7 @@ describe('Retry', () => { describe('without maxRetries', () => { it('keeps retrying until the function succeeds', async () => { - const fn = jest.fn() + const fn = jest.fn<() => Promise>() const retry = new Retry({ delay: 1000, jitter: 0.2, @@ -53,7 +53,7 @@ describe('Retry', () => { describe('with maxRetries', () => { it('keeps retrying until the maximum number of retries is reached', async () => { const maxRetries = 0 //10 - const fn = jest.fn() + const fn = jest.fn<() => Promise>() const retry = new Retry({ delay: 1000, jitter: 0.2, diff --git a/ironfish/src/wallet/__fixtures__/wallet.test.slow.ts.fixture b/ironfish/src/wallet/__fixtures__/wallet.test.slow.ts.fixture index f1c2f574d4..d95983e5be 100644 --- a/ironfish/src/wallet/__fixtures__/wallet.test.slow.ts.fixture +++ b/ironfish/src/wallet/__fixtures__/wallet.test.slow.ts.fixture @@ -351,118 +351,6 @@ ] } ], - "Wallet Removes notes when rolling back a fork": [ - { - "value": { - "version": 4, - "id": "7c33400f-4467-4ca2-9fe8-753ec9b990e9", - "name": "testA", - "spendingKey": "8819793463a99aa9bb8054a9947d8963887af88c117d76f3afe8794857338031", - "viewKey": "9369194732ba2e85c96597feb003bcd1f5bbea96cf281f2b4ce602b592e75184aecd8034da8e4b86c006b1fb9fe3b0fca55757c3ad5f2a6221de50c5039b2441", - "incomingViewKey": "9cbf9085d17168e11796f7c7f6f8521293b5f21ca491a9eeb8212c6c0dc9d004", - "outgoingViewKey": "aa3070df98bff103850a048b079a4fb0fa084423585fd94655472710e50b3a4c", - "publicAddress": "4d1ffb1e38788f1d5ef3978d9680d08a4f402b40b43a7faabde3e3fbe544dc40", - "createdAt": null, - "scanningEnabled": true, - "proofAuthorizingKey": "b785af62a34f29e9080590f00a517fe3a73a66da2a39f5907731946f44ea2103" - }, - "head": null - }, - { - "value": { - "version": 4, - "id": "4729cfd4-1db0-4aca-94f8-45801c8edd58", - "name": "testB", - "spendingKey": "7dfa306dc31b259cfb933b09a4fe637a2afa459e35d5727c99bfe2ed42cfbbe7", - "viewKey": "ef97818417b95aca5234ba933b69ba76754ca35b897d15d977d20597aa0b70d808a6002dbef6140c092c212f1750df973cd2815041369abb8798f442822cce67", - "incomingViewKey": "dba7925a07a584b375b2d85182e68e595034ecb8839aacd6fbfb05b7bf9f1606", - "outgoingViewKey": "a5999a8e17629cbe4758bcd70edb21adf9e7ec675c092a0f4844b82ddc8aaf8f", - "publicAddress": "b244bd095c6c835d11f1f833af36984bf1589c2d842141077b609ce559d24f0b", - "createdAt": null, - "scanningEnabled": true, - "proofAuthorizingKey": "6325e463f2330133da4dd139d7c6e3c9b54001fce7f8cb42d3b9ac63af8bbd00" - }, - "head": null - }, - { - "header": { - "sequence": 2, - "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", - "noteCommitment": { - "type": "Buffer", - "data": "base64:eTeIzsrYB3NQ6RX5Sf5ubtb2ZK0xwSRoZscdD2xknGI=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:BYxTG09lEE7p6FfekOb2/seCpBW0+1qCTEW456REE0E=" - }, - "target": "115792089237316195423570985008687907853269984665640564039457584007913129639935", - "randomness": "0", - "timestamp": 1717545209094, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 4, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAXP/k0xped3BqaHPSSnDHj0dKjf/i0RAy5syReq74xma3c5VwfJrKlc9as6Np9Xw7b7uuEZnP3xcWXPGRUvup20+H+NnvsLMqJDo0iYTdH8y1URnQkJ+oSLvsJoK0LdFtyY16+HIC6Y18iM/kTecU6k3vZf8i6dcV4vQ2bhskft8Ipwv072ieMzxZgqXSfsPYRY42CqSDEwuDQBRtiZEm9drFyn1W4QaxdiorVLmv0gyMw1zA04U0DTJLNQEdzEDb1heJ0JQMBu1Mlg5LmW0CdqNB8NO/oXgvJUVN5i88LHXWxw9wmUb0lm5Usvv9RSk7m5rfqOOJcLaf+xT69h22UD1MpxrDU2L+zO8cmV5+PYl7q0fORpNX884sgzrPPnQwbqEIfAS6dSlocejA9WsGWc/4QyV9zH3QYeF8lh9SXgI2EA+D0pMH0TDuksLnV1e+cdnAXc4AajmYdSNQeUjYTWVruLbHSXdPp0TMGqev6lnPr2k9w65pXBH42ha9HTOtHwPUqjZWm7qKs7MrQy4y0ccSneBnUldJwByapdAUIdzFV50jkg05FXKxEOubQbQl36X1sTCDeuK1FOeYsqHhD7bsct+6Z3Woct50a5N5jUO2OfAqu8uJwUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwgqpdDC1NdQYtnnnL1ZAe1EEKRp9SgXpaa/p3zzRG6DoWeR6A9wDIPF2Vkfppuh74kb6m45DaxisEzHl4WyDBAg==" - } - ] - }, - { - "header": { - "sequence": 2, - "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", - "noteCommitment": { - "type": "Buffer", - "data": "base64:/WHpUNJk1ZUbIs9RmVwBANo73YJmHzse6c2WIjwCggM=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:jGpU0dGtO0Bv/Rs9czI9bhcsdkJ76iq/Geu1OBr97k4=" - }, - "target": "115792089237316195423570985008687907853269984665640564039457584007913129639935", - "randomness": "0", - "timestamp": 1717545210192, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 4, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAARGfwAf6MqHGgnUk0FzqI9e8HmtQMst5vC6Cq2itpQZ+l4DlJjn/FnTFHpvGkX4PpdLRamZExTYynMZhd5YIr3MZaKXRaergW1ZHwTfK6FoWxPDhbQa8Y2K5ZlR0t3X3lx/XYWBvKNKxKass6OmNV6Q5CHWhCmFiLXQUtHlOUIyoPzm5qTYVl6rYbfoJxR/fisyLLiek7Kisf8+nU0EHA5xZ3xLP8RKt3U/AbjgT3MrOnSShG4SHj66KUcGbhbQWWpT1KAeI6qChxJJEY/JiAxQu2HaNb8lT6UozXGZQ2TLU5reigPE3skC0lfqphfkpt39P+Is7kQwuKEcR2aOw4IVH+oiy4g/Ti13/sbG3q1673fplAOFjanoUKtwWpPdVHZM9DCJkHx8myWn3M1bIawpeshjJaEcafq8NwMkbEBDBYcnucWnoy9I675oSM9TCJNfbFZwNbmAXdBIMRI+D215CUpPcVWYne1DzX9QzvpdgFhkA+4q18jk1FnkM26zG+q85Y0sktDWqpc1wQ3u4qzwMDLM4XD8C9Hj9t4B37Z/fSHN25WgE+BiP6wuw1A9OEEqatunY+kdfSPxlHxSqFdNVFBzCdSD1mzU0tprl0B9TTskHH1Oqni0lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwOOQ+TS2zMKSq3CQeJ9eCEXhAbCJrgKWnyW76HEWZHLkGtJlGlhFcZBEFr6vag4vTnx0aADytG9cnCsrzMQyHAw==" - } - ] - }, - { - "header": { - "sequence": 3, - "previousBlockHash": "9F3001E47620F2F57BC58E64B3B7F543EB9BBEE131796BD8A9961AEF2B5CEA7F", - "noteCommitment": { - "type": "Buffer", - "data": "base64:JN9o1LxRZiNJVsVVw3g53baaD2a3XsH9OR5v1WrWqgg=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:HABCNl1jrXBk8rNSQy+5IJ7ZEBEy44XMAQshq9pqX2E=" - }, - "target": "115792089237316195423570985008687907853269984665640564039457584007913129639935", - "randomness": "0", - "timestamp": 1717545211266, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 5, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAC/xvrQ8NmY9V6PGSvqsqVsnw3u+FzuLk4Pls+LAWdlWHr/T4eJ+7Xm4dfqEjQR88kTGJlZZDhlCGB6J8bgo9HmIvW5imOBncG+nJjDMxEwyjeDQVe2xT4X0hxNbJ5eFXNKcGa80TZbC5e7hS/MrL0FYZoFZLWlHN9LrjairOBqAWIySKYRYwt9RwtMHEFc/TH9WiOTkdoV6ap7UwjMFEleYoAJr1Jxy2pwxxe8mrt9awf+sKF62vFrRdH6IlLX1mWB3kMjTbC1SOLAvfJxDWxoobVILziYJbeR/og/PyMSJx4nJ1Jo7tjXBY0KgsWKDyXkDHj0BFDoCcwzLZCkCDjOEtbVGJTcPddC1ADiDUk5Jd9UxbqTbRsRLGDrDZxqU5Q3VWFkBl8SScLO9CeSNT4EEzsaBjeejOGw1GTQ6nEIxcmR09O6RCDx3suZyCCXOINYrTv4cNuIzsdYnUbI1y+sWy5UuLc00HP66rYp3rVGeLQhBblxdOF5nURJHTfQfiFw7ubRsZg1sziSsrAEFFJvengDqP2+Wfvs1ckYJ/efHO6moKUIYaR2mGEuOUFicH/+XLiNDaNPUV/Wq99wfRDBYVT0xS7HKp0q+29Dbsb+QZ4qdLYwx7z0lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwRWufRkwB7yAOVut2pYODDLbUVTLWIDiPnRanuCx2IzE10cHMe+bJvGKaUZx9reho0OBn3O2irqD/LHXyw2D7BA==" - } - ] - } - ], "Wallet View only accounts can observe received and spent notes": [ { "value": { @@ -1352,5 +1240,117 @@ } ] } + ], + "Wallet Removes notes when rolling back a fork": [ + { + "value": { + "version": 4, + "id": "cd32d3ae-a3f0-41e5-952c-ba430eac0a9d", + "name": "testA", + "spendingKey": "d1404bbc1140886f7f7be312029e254ea93369d59ffdefa45b9c5e96833bbb8a", + "viewKey": "9c9b854e1290ad846e75c8f747abedfcce7d68e41547157fc257afdccc429fec46b5aab2c46089bdd09c7fff38d8ae0f0faa699f97732c72b626853a5923e422", + "incomingViewKey": "a00560ae0c138fd4c2ae75ac8cb7b1869b4e90a8a7fa58728970547b6f721505", + "outgoingViewKey": "08e5fb5edc5eb8416cf151dc02812bb577d2ff2c96a7bbdac4ad10006b720553", + "publicAddress": "64cf78e2c1d923ca24a38863cd0a42f5f4bb42f3849375ba493a68d92a38401d", + "createdAt": null, + "scanningEnabled": true, + "proofAuthorizingKey": "dd370d899192be20a26816e195f6fce8651a3d501532198837d9d754e3d11c00" + }, + "head": null + }, + { + "value": { + "version": 4, + "id": "3c2f7db4-883c-4081-8ebe-dc1ddc9d6963", + "name": "testB", + "spendingKey": "9f8d5c3b61940b21e32279b68615b04e98f57953836761bb80e96ec19a902686", + "viewKey": "3bb41a4af34b71f766b6c17c154ef23b1b53d5bf22b13d34670f73c32722ef7099e33d5c888d843e865f66d6ea2518b2470110382c60b502f1edb70365385c89", + "incomingViewKey": "ba7298cad95c6b055576d38d901d3c29b5e4ba907351a29764c146e936d17800", + "outgoingViewKey": "1da9a40b0a70b2de121ae5c216d9a53efc3c565f7140154d98f5806cc3f8b7bc", + "publicAddress": "f00a99aa4bfe52a5749e36972bed4448575964eea74682f2759c4c9c225dda0f", + "createdAt": null, + "scanningEnabled": true, + "proofAuthorizingKey": "96b16ddb9f813186aff04cf38cf71fb13d25bbdf8ed9b79caa891552048e4709" + }, + "head": null + }, + { + "header": { + "sequence": 2, + "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", + "noteCommitment": { + "type": "Buffer", + "data": "base64:qt+/GjSXOiZu6QmwE195NyB23lGgdtqg9kZWVOTtg2g=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:vX9z4YThMKURqgF8vNiEuESHN1wVSc0SepIvDXo/TaE=" + }, + "target": "115792089237316195423570985008687907853269984665640564039457584007913129639935", + "randomness": "0", + "timestamp": 1721686869438, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 4, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAArOIj6Wspm7vCIidTO9qd1gJBx+4OeOv961aNVztPOW2Kfv0kXVY/L53XzzaqhCvwsbChwT5W86t1f8vzAcizi5GhpZ2ipF8d8b96bc3kBhKi9NdjtpNGPmCeu3sTpiSybM1xFys+3LdqrBHfDc1iZE5pnBvNLHiwMrxgup/lJOILp3EYnlz6nVlE/eZrhxCKLBK2OwXzW78iQp/qjQcxUTFE4eNO9fL1f3GaO74VWteJAOjE8c2F2wqtPWkK/arJA7SSE+IgXoCstpIiRe3Yst3NO24PiaXh6oLCuLiWo2dmIzqV2idl7oAHF4Rs/YM1FnCdx2cI9c4Em+jsPVk4DOECB/M1tMHwjEwMxc1urLIDJFHonBW38MgH1Dp53tVyzLHpQVOaluWsb35WgCQb0AgwrdQ8WuiAay5fghvflVE+vcgvwY07R32z1cFsi7XjPvT1Kh2y4PP19j+59a22W6xQ+X0LmP06Y1YDl376FvTOi4K3/KQsPhzKeE/vP/cmC8YVEs45plMDmzBb59TFRnu2ivnad6wcGuvydzbrwUTWQ3CP89N9Vkv+O1p0W0abpqsXDkS7YqAUeWwlzQt9U3hJTsjtf3nzORrWfZug+PJw1GnF6u3B9klyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwV4BR4lfi4N/WjRCzYHINT7ZXN8hTXghOFY2gKCrBEcdULviK7GAfh2w9PYCaBDrQ7lV/OUQd6YmRtxS7x2n9CQ==" + } + ] + }, + { + "header": { + "sequence": 2, + "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", + "noteCommitment": { + "type": "Buffer", + "data": "base64:CpSqkYHSG127MKJzBUwaQ5R3TyDDyWqgoqru0i0yoQg=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:3IwtFPxx+aQVediOcvQFqhRFznoqXnqFwUriKIPLEQ0=" + }, + "target": "115792089237316195423570985008687907853269984665640564039457584007913129639935", + "randomness": "0", + "timestamp": 1721686870002, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 4, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAATBxQ0f5eSmAyq9GWCNaKVVjDJ2Wzo2gOY6BbsQoV5EaRTBIgVLLMG0XNxyFEdlXL+UNes0xfg1GpJzaDqK62Me+JDIgH5HCtjG6RT0ArFuGZlvDCK6CQYoZjFIpIJpNgmlBoRNgtzumF7P7rIc/GPKREIsL8HJrBDktJ1raBGToAmXuyJBWYk3Lumei8obOWqjzzS4nq5Wx78BYTZvQM85EXDFXru8mLk3wS/6KLxBuuXgFbMSdnnev6ifSaN0t14T51ihDKrYX3OKRp7LjvdD9cEmiKV1wNqG5KKFy0LkVdIzqYmnaFtNP3Lp1jzcR8KKZtRNJXTQ63yFPP1rDpKjQxA0n1YWEF9hIKJvcY1tHgZesWcY7FdwJsbC98fn9Z+1DJYq2LmppBb6+7JlgjNQhGNlcmsiZrgPbDD7iQYhUe+EWooR9OyLf1ujft2wGroIT4wO3M4p9cteMICS++INl2Y6zhsVnlNdwVghJLD0Kd0AQVkA6jxEB/beaSXOWdoOBWfhzPr+DC3A6JUeTfKTnjKvOrfTvf3WKfcJi83d0d07LymqWv2lZ+MmdaWrZ2k1xj9dSaLc/YFSYE+8gLwE8ZN5H2g5sbdVry4CpiIaQjX+nwCOScRklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwY20OS3MMRoRF0edV7MAYEiAI5WpkyFjofregIiLjmbMr0Q4VIHV8WrZjqSTiDrGBj3ygqruDvBIct8GPFLb1BA==" + } + ] + }, + { + "header": { + "sequence": 3, + "previousBlockHash": "AE8E39C81597A1C79984FC014137C09B70877A247B4390842A0884B495DD4258", + "noteCommitment": { + "type": "Buffer", + "data": "base64:PySdNCFehP11kb0hAHQG3yDASM2Ix95MGccF0yxnlkk=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:todu4D6yQZzV64lY1jA6qdA0t4CMmsQ0yrX8a0y13AM=" + }, + "target": "115792089237316195423570985008687907853269984665640564039457584007913129639935", + "randomness": "0", + "timestamp": 1721686870593, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 5, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAgjt4hfdcl/SHkDp2RESBhIWuTLaeXFVziFX6/6KCvKuF0mH+j4LlEQXGwyidBrOkqqYUapkpCMEGhLblIBZpq9HLd2JeOCcUyTvBgpuUc4ai+HNwuU6RQi6rjr9+ezH1lT1Jc5/AQoW2xjpgytpkTl+rjh5/l3JRl0K6UmjX3yIYOuuqVRDvZVXZ5PSEAvfnQgvaJ93N5FnM4YbxlimarF/f402E5jAQBKMn53Fv3OOK1MdU/AK5x7Hk6VHHa5DI1AM5Qi0kfPsfFw/rld66SLhX9jAhJtwnAizUIjnd0PK3oDFgo9aUOiaU3o4VXm6Xy7oERAaUukwyw876ApeQg0CdIEZM0YjzIzd18OlA/p/wkLnzSNA+YhmK6s6xcMJAiyY4ae231CH4K3GGc/eshZEcDU9Lb3MRpLYZB6fZwJMT4/Hv1SzkBQvoUvCNKNtDbN5HfSuBYY99oIXSZbEQ/DZ90IQ+8Ul6LK7HLZ626PhmtUZEn38Kss9DDWHKSnJIQ5kmX8IumJXDMfjOCIxkm0Y19JQX33i89xlSDebKVhH3zdhncFqaxPEJSSL7BLJIpQzN2pGEw+bLY6KA3Gzy2VPj1cK25D7uPNgXT/wR8h06ELjfClWItElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwKzXYdWoIVvs+eqBNNKdebAaImfAwueJBhVjohtuDDKwx+j4U/Mub0mIVhPQ+3En2wbFMLX/Z+vO4fqosUv0AAQ==" + } + ] + } ] } \ No newline at end of file diff --git a/ironfish/src/wallet/__fixtures__/wallet.test.ts.fixture b/ironfish/src/wallet/__fixtures__/wallet.test.ts.fixture index 0536fe4d89..53339cb8d4 100644 --- a/ironfish/src/wallet/__fixtures__/wallet.test.ts.fixture +++ b/ironfish/src/wallet/__fixtures__/wallet.test.ts.fixture @@ -4329,45 +4329,17 @@ "data": "base64:AQEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/5M1dwAAAAAAAAAAy3pc2+JAD/A6NPIf91xdfQOKHCPwRJUvnVM/HlHbMHGXLfvuZ6UWoYCmQLyttYvDz1YqcfEHFmDQ2Ag9R0xbUNcPHtTmSbnfFN/MfB3aWrexE/5tgi73cO5zwZbC3z2TiObav6rtvfnpo20tO9YyiSHuvtscWXu/QS1Vx9HxvDcPQldpH4/MG72Qbgnon9H3eYhlwERwmncUu7kJNuqEghy54cs+YEN3KuwMJOhlFcyInhQbGKbXwODN2nfYeYtoks/hE/PXrI30SScVifsGbhkF2zvdlhAp1xvRhXF8a5lpjF/HPIsIwAbXG1uk9OJsIkCVqCOCgWtchLEd3lVo03jonQzOjkdfLNraJxUVavJ/Z6jrz6wUDE3Lsfq5tbVTBAAAACSLreEcoFC5KqBtvB5xKHIti9ukKYEWL2XCBFIKZlMNspPwzvSk2F/86DM5iEy95xtjj7lbvTESBobNj4nK2yl/RwpwrmdRG46vDtDhZSmvHL7tYtuHfPdlYQBjX1XBA4cxv+RKuQAi8CIr6F1tA0bBu014pHPMEO8z7FcR2+GkvrYdHu+0/osVqUFP1ADbvoFSQGjz+yWC5UbdqBtLMSDs5BJ2DMJRw1bH6OO/PrA/Zjpmp7/goKG20XRI1eMBNwDbXnR+dFMCYKJDaglonp1wTTY1XMMBTtZUpTf8W7qNirvCSpk42Ye+dBVvlzzREKDxZGn/+ZQeArr1NMaEKZhdk8Xt5YF1Iq+AouEEG8iABRtWXUS9A4kthpRSysAxey8jQdNEYUCeqBe86jutnfx/O0aSLhNcBtKD9u+nFOuGeHvcGMs54SB79DWe+MW/RxjE3dvxS1qDINNf4Y6LbDfpSS31Iko2I7xXVR6KxNI59Ki5GDDlXO/YmNwKWceMNyMMlI5SyNy5fyuBzv9sxEXfuouDNsztUvbgGf4z3Ny7IcILbGG2/3U8zXS/lqUn5rbU9ev/chBkC2gS6pZqQLl2pdpuw5lVUkEnT/+osEvNZxNkAtah8Zhw0hwv22tqTv2jtQzp9fePG5gKQZGW+RJGKauYPaHdjH3IFen7WDNq/2aXUOHdMxeMMKFVyCMl4FtDl7fP0co9PxtyUH358Z9bXt0K+ENmOvH0MgBkIXvZz/f+EYzSTqnrIYT+wJ1Kp1BtL206RByfqHE0ts63KH6WjH6+B8B0Jf0cHfvMOmKyvvyM7IbHlFNKCHOchA5kd3Zmz19NujaFoWY+87LlvDykuCnkP7TcH7slZlymjBm2vvO6CxP6BOuazMARTZoNvzQ/jHWJigcD" } ], - "Wallet connectBlock should add transactions to the walletDb with blockHash and sequence set": [ - { - "value": { - "version": 4, - "id": "98f0d037-134b-496d-a85e-f90a7500162e", - "name": "a", - "spendingKey": "5976662788b5abe5463fea3d9b0d49bc66cb02787a76c8f1f48da6034c6b0755", - "viewKey": "a773dfc42b64c93c64f49db6923ea489c8c59c33b0cca1ccd991037363e5da54d4617e933c0468cdd701c88989701372fe97a41e8697bf561eec28475bf5f60a", - "incomingViewKey": "078133d8b9f9055417dd4b03653ee4b8f251e0fefc32149aa7425c9d3fe6ae06", - "outgoingViewKey": "815fe80a2f67cf8e8228acfe9c3d6bacce5dd4c9f5afb3162f9fc73d58e1f526", - "publicAddress": "92f7010e34896fd468dff5af5afcf15b2ec2c126cf324bd7d7f58c02994c0a0b", - "createdAt": { - "hash": { - "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" - }, - "sequence": 1 - }, - "scanningEnabled": true, - "proofAuthorizingKey": "4f062833d1893d42e79808851b14d82392a2053853f6747334ea4db38a5ec60d" - }, - "head": { - "hash": { - "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" - }, - "sequence": 1 - } - }, + "Wallet getAssetStatus should return the correct status for assets": [ { "value": { "version": 4, - "id": "d1ed30d5-7bd1-42b3-a2cd-d8d0646f31c9", - "name": "b", - "spendingKey": "60c168e2d9582bfd1a68e86cfcea846b6c7fb5be8fe85450cf3900a39532aa49", - "viewKey": "edcc327edbde105cd7b3c5ec014a9018ed879418c0220b0da681bb0fa78bc1010a6ed96bfe3523853608a906d2fd2ab4b4fd3bed9376a00e01c00787e7f4a7af", - "incomingViewKey": "f9a76c3c240dbe1053a9cabe640386259fc6f8a0a7e86bfddfcf14df8fb72a04", - "outgoingViewKey": "1000c09122ba07b31e1a053808e1ee52ab4fcf82b1f58677b14bbf6664d90612", - "publicAddress": "7f6229c26f5ae7ae1d2460f66a49e21a0043738f63ab9919e29ce8af0ee227ce", + "id": "9ce72f1e-3ece-49cb-b65d-74f015d8868f", + "name": "test", + "spendingKey": "7d1b498c8d3cc4f73e73e6fd478a9365b0d8531ff6164c02ea4a082fc4f62153", + "viewKey": "ec221089ff616478f18ac4407a18ddcb1df20258cd9a573c50e16a16b5e1e4ec78d86afb3a27ad9cc1e928c20f0ad5dd983a1ab1043962a4679cc95f0821102b", + "incomingViewKey": "a133eac24bf5a25cc97053c90946ce9463c4504cc0cd1ec5197c2e0ffab3da01", + "outgoingViewKey": "85720d0846bd0c593b496c79637b57e4b6a0f2ec525d157424918d23724d4bfa", + "publicAddress": "bfcc2c07f689708132f5bc4e04d9457770885b1835152dc8d5a78a11ebe32eae", "createdAt": { "hash": { "type": "Buffer", @@ -4376,7 +4348,7 @@ "sequence": 1 }, "scanningEnabled": true, - "proofAuthorizingKey": "815ee445b678ca104c39396e10d94589ab3244a3852003099fe553f88fa79c01" + "proofAuthorizingKey": "9da0cf11902fe7853a0efd7737c8d409f3f06ad031eceb3f0bf2d1759431b904" }, "head": { "hash": { @@ -4392,15 +4364,15 @@ "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", "noteCommitment": { "type": "Buffer", - "data": "base64:tKOY0dLABR77M6xoQzhdVHhV0mHHw19i2WaSx+XiAxU=" + "data": "base64:ljyAKZkpGtZzzVxsP+MLmB+LBKtd2d46th2i6C1y6yY=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:QrmgOXZtL3Oi3eI7bEPgD9dCzI20mna6NxPw6f7Dcf4=" + "data": "base64:nCDFbONWvWb7DMJ9Kn+enFcxmO9FXei5rvmcHC+1lzw=" }, "target": "9282972777491357380673661573939192202192629606981189395159182914949423", "randomness": "0", - "timestamp": 1717538675075, + "timestamp": 1717538810002, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", "noteSize": 4, "work": "0" @@ -4408,78 +4380,56 @@ "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAWS90h4QTrgg8wrRxgd/n+DwC4c2h1SrvjjTyV8W9PpmAVzt5CoHiZPXsHY/H/jJS6+xm+oP4KSshoiqJUQC/KGZACTa7PlEPWeSB97LIzQyuNFxWCVP+7wXwUA0fmizNXKj/slNYz+pFcg9RncilXi1htyTanKlHBPuoqKwyKBQF87i+yN9YBwLK8may0ETBN19Rsghcx32qQwEvhIvJWz/z+9OKX1Fw8It6DdNtPDyuHFSQthQHFKBm49dfVmW1jhrfyHPknsz4xHrCgoqcUgS76yxm58bJ2DKeJz7WysBOxBcEqYomsGuVvwpmove93CkdWd6BYzEzS+SjkByCyzdU2sZr2gwfAn+Qxq7PefzpzCzkC5i6+hyEymlfy78jIlO4cNrA3XkKkgrJCa6JAmrxjWmigT/fRJglVWDiJjyaqDxe8w/pOohs0UebXPQwkqo6gwJjzXbpsx8Ol+9V1c0KqigMKY84ybMM0/ovUygzgYFivqXg96NxO7uvqACg5cs6vwpiQnxZ1DvFMODqdPJ4p5uxqxZPvH7wGnglto2CeBj3eNl3NV5iaVSW88Sh8hnCwrprHlQesAesS1H1IkuHQR7pffrGiNwh9GSuzGc1xmOAf0umq0lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwaUm+Qeppu0oF8bLu2SPyFpZEZ8aI80YIUGjJMXyYKbpEm5d84nUItiITHfCLsauZHRUYJrvp7kPE7/5xD/x7DA==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAIO6f0wCjg44SxkFkq204mtRvRYfkZb9oiVMSqrTUa0KhJFzHrNkZmy6ZttvdzFoXhEgdjLVRTc8x2ye7DRcF9JtLSl8KlA1XxayVNFtFLsaM1u3yZVcSN1YtLI0+woB0Zdvkj6CIPVXruZOiMYn/egap0Z0br5EcRbCTVGTeST8BO+8r1mzD8DzMqoAQbYG4xHwg5NcO/a3svvTNELC4pj9KF55LHOhTUccRfsiVPZ2P1OLx4A40LjNN8B36r9XzkPDeqs2QpWDMmCDFvKRmwA8pR77wylHzBbCNDxhwdyYlRVmmGR2yOP5Z2sO8/phrXIgasxp6z5ebCAFA4OEVubwnQ28zb3D/kWSPgSIvNvo04NoguTK5np9cySOTDTBNv06RwKYNE9jq1834s9i9pUZgEv0HmyfZnsZYJm9VyTk2qrsWE+wRTMT0s0ckWpqFJ/RGhj5EufQ08Od/6YHXILVD7XUpX9SG3Pi4p/CgDWX+22wIXR20pcUunVZCcd5C0rH4q613VtFU1L3o5qs7sQLNmH+x/15mnrdpAmpB/j4OhyH/VpQsT4skZ7BRJEQXPAAvHaB/zphGSD93D20Wf92yRKd95QYWtaf1Z/y+R6AH0cUHmXm8KElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwfB0rqqpXN4dcLtAKd1ebu62PbRC8xb3GlGApQjCmqQalIKDnOOrbq+bktmrbJUYbpdiwnU2VI+h0SrlS72OMBg==" } ] }, { - "header": { - "sequence": 3, - "previousBlockHash": "8C7D69EC69350E99BA5134807E12DF7D509035CDFD43503A05FC9957663218FB", - "noteCommitment": { - "type": "Buffer", - "data": "base64:MfFAgIf3mNhgU5WuhibYCyeKdt6aYTW21hIDNub5/TA=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:e7Qh3UOumiT6B03yJGggqNQdEybG1VbQk6/IXU+g0kY=" - }, - "target": "9255858786337818395603165512831024101510453493377417362192396248796027", - "randomness": "0", - "timestamp": 1717538676699, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 5, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAVo+0WQyMVWVrfe98CdaUMQbSU58ekKeVpOwWOApWdIiJftxH3+Uz4XWhZe++7z0kyJDB+qVzUyprfDYd5hgq4BVbmgzUu5yhxS9x6MM3U6i5f3OiWKK0Xh/TfqK0KAhi/gkcnlafw2Oxs95MQzi/gwAjP7AwjdlHAwUmHR+DrDkGl7sRNcmH0U1aSKjIU/CCB10HAUfwDikMsPalDBfpx8RL439M49dLi5rCuXavzQqI2vrH+TwbXSUxoEhEw5BX/b4f1FoBAInvu31/lVPkD7ioyZgplC8k/UAPEA8acw0ErHekvWuUqyxVcOEp8t1NPNR5z+V5ux84xSe2hv8mvbW9mnIdgf97eeoJu8Ho2Xyr1udQvG0DYwEeJXOww6s6NCWMyqT6HIv8vyE68tADSKX9vKoIHr0rSeY7b9yfTsDTSBuhDA6Gw/jKmxsdNqjHX1q7wFxWYlRPeQs0QAzV4G55Fu9dSsX2ZYvr5cdZF+CaF1NVJIiT6rM45KPwwDurmUTedy8QxkzQ+0PABc6dqtMRvwzI1VPvPJInHijJVvb5oR2F2yb9K0jKvS6mupUT2DnmvlEjKJGMqOrSZ1ESxSzFdS0ZobMa+yCUrb14lZWknVDjiXTTxklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwEL/U1HhIULe4WugQkf+rt3766vBmuBndiy+Nr9Kn08benLWssKAVpF2pln8P7kikD1jfWfqyoK6TfeZGN/fEAw==" - } - ] + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAx1XG8nmZYHQ1lZDF28yrjNdwPtLmJXorkmHX9wpd2smEGUFH1c+R1x90Cx1/C++ZDaG0LZOzFoURhJxAgkQWtLaKuHgy4X/THyeEIRF2de+rikJf3pai7Sl1Rk5keZmyEGdca9g1R4j11EvorfIueXMu5tUkSxjXGQih7xj00BAEzGD//L2AFiegE3c7DNOXrcmry9GugoJLx0NtqS+rSFuQSJWJkifCzus9NzVT5DWDpPIC1IiQe5v6JhhNCAD3bawctCBU4KkpKbzeJTChU9EJ8Aexj6eRDpAlecHOsVGGCsJ0dz1bBRkJiQ9UnGQ2IaU1CRRecDT3y2tEEZh3DniqfyVpGJdU6HL5I793Vf4K9pDxdBYAzyBR5hkQ2qMrPC7D7dcJHAmBEEGkBPlB25ztk1sUmFJNHlIq/E3LJm3E61ASn2x8lz7VW0X+J1CrzBetBuTa8P1WyM34ygGinGtIbuixAvKTuBPD3D1WYHUL8AmCSLBd2MQVXQ4QXhkytGrV71vL0Y9TIQUUmsynj1zfwRDdhGwl0JEAQKEaydEm/MGpIgKMunwX17UIT1DcRHZs8QDL7V5ddIHkl+pamlvYOqTG/Uv2yY4gt7+/5P9cKsBew8hqBMnYroNLOiCPvcwZKFcQl7wbyc1xBSswaeLuNGt5TtT27T+9Dr/HzejTvH8KfCGfBD68uJnPQsK86SBZQilhh6ix2IGJIsMAh06kCZq+XQoBoFkdkqFZd+4RcgcjGpbRMA+YBC7PguW7foeHd0jEiouRNB9IcfndU8o3VUtdabdKkYsF5F0XvJ+V1+586fBd1gJ8P7HZaCfXlVbvyTh8vjC17V8G0LSxSdvnpKr7iOgvD4l2mFXwK2CnEwLRVNAVR0j2WiUUknP0PDm6N9u2sf3xctF4ldJ/EsaKRN6kDSpgooqKnc/d6JHoWKN5KJj/MI5L6FnZzO9BS9sesUewkJiNSpAYd3hvVuz4C2buMGj0v8wsB/aJcIEy9bxOBNlFd3CIWxg1FS3I1aeKEevjLq5hc3NldAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG1ldGFkYXRhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEKAAAAAAAAAHegEyym/Ucg/MHeuws1hyy+jM+zhif831l7UTldqpaTNPaIs2r0vnhH5D+wIM5HCifg0OlnTjV7G2mcuziyfgc9gwv2Dr2csHNTeZsubKTYJwSSmUTRfzwujsxrJaaUv1RZoQ1ta5XLLCMBXq33YxSofd7+rr6rAi8TArKGCNUK" }, { "header": { - "sequence": 4, - "previousBlockHash": "6848F80E8EF39DA1362D4CE54E888666B6C785AA6F390293BEC242B8D916C2CB", + "sequence": 3, + "previousBlockHash": "2000D5E8FFDBCD7F4A0B1ACCAC17F750C344FE3B9B927E088269693C14B28C0A", "noteCommitment": { "type": "Buffer", - "data": "base64:Rvq8x9E7Bj3wp8V9I+x+GMw7t90akR/qhUkCa4u1LyY=" + "data": "base64:8S62RRIAfpSANrCm3IxZu3YlcBtQJrQcAQJu1v5QdRs=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:EyITUATYp4ngn6mMIil6iSCEuvhBdVmZn1HplouA/qU=" + "data": "base64:+NGczX+1gjYFWQjmPo959KmEs7QAsV8p9sdVuJc1bOk=" }, - "target": "9233318228143625020618577701423519925017621426082203201059080050516648", + "target": "9255858786337818395603165512831024101510453493377417362192396248796027", "randomness": "0", - "timestamp": 1717538685227, + "timestamp": 1717538813921, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 8, + "noteSize": 6, "work": "0" }, "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/2vKiP////8AAAAA8FKDUmlqZcbfq+aA4V4hXtwi/Mw7Jnwj54EuUFcXk4SxpCGQbSE49dntwcqkRHKjwAl2rXEh2EQ3C6PbDZJU3tIliBwJ0ErNm68C5BHux6Wy5FM6BI9pMiYvbFFZx/t9AmwKOc6hLvX1aTHbntRWW4BKfPWTV5QcW8O9mZXD+tQGtMLq8oHNBHQDx2VlUzPR2OPA2ScQ8r6hpEpgs79i54faiPoSGgmRcExNUBJQxeOJoJzRPREEBYS1FA5VZ+fYs41cW6m/9qcxEkavxd5RwYHMh9pj4rOXGzqVjbJGJtgLRTOjv/yQpIMFRVKsv5NmFwVBEbJuXJ+wK0nVxLYAnTNQtK4nosXm775hZhy4FOYcRWcTswpFE1oIHnUaGeRCV2cYWfH3qoO17INMMQDuTzmo7J0mK1HqRPtV6ksWX8iY5ylbeoxjf+lNE6n3BTE1q2Q0VJwGprm1J3+N0qXOOWvP6S38bSvtsLGqQYbs4SeJDzuwWOshAXVfZBjzMTQkN+Z7Q24a/gameEWs7LdYi9FfGrTUSauXCoPO4eAqmEybC7XFrRBSlUMqN14KbBTZwx+hYYNyIsP/QG0JtxonVO/6J0cONGRgiAAqEGhGrODlXz09t1Mm2Elyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwGuZvcRvviO4INw0bFf9Zd8V7bLANBBmjSih/otrU8WnuId9HT3kcGA/jmhOqMnSqwTi6YoV/Pq7020hleE8+Bg==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAyRShcULppVi9LURNIeUTgqVKs5/2NBIGXDchmWTbDOGN3WiWZ3tk4yaP9BckHcup4FbSxtyVPNJa0jiHdFppxUAxRBk687ttGhAWVqkY3ZCZRbXybGPSW9EfrRL35y227I4qnga9M9DK/9m8mFkJ78f3B90P+ILAB/HZwfysPJEJFIEiX1O5pAAtcSE41CQj4NUzKyn0ReNwqSC/+sp2jXjdCMmcrFlNR68q+ppFbQiLS/7EEet+3SZO6OYLF1N5xzucRYwtFSWtCIQb0HlKSj8ObuJMX3B4oaiXlKaEXX3VRnyRdQRJwcWiGaPrbZJLjzUVt3fEE0Jq6AnJNjAjrp6/PW27kDsgDAyZD1Qh+xEFNhPf7pUmTb1Kgk1dD2YTfFx6dwb5NwGaBTIsQIKano473Y9q1fFWMLBBKSD4JtfuPRo+aN77/LyMuBkScG/Rs9eT//pEhf/xnPW1D+G45XG4CF7q6TjhZOkWJ7/IlXnnIskhl3f2eS47zvfRNZHrGW6ZVEuXDF+0hlbopNX/SFhZIU7n7UyViwQYnU/t9WLaDm2G8P4kDn/7ugpH6o9geblFd3P+YEkx1mZd44c99XsXpjyDL85QiOia0B0CylYQc4T5kNM3wUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwSFe9YgIoJjUXjpiKrnrwtdncEAuFWPoaUez72Nto6unZYHBkzsMqSP4/g4Coe29M2MlNEBASUzWnYD18meGKBA==" }, { "type": "Buffer", - "data": "base64:AQEAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAA/Zecsdz5QXXjPvoG4n9bM6ifxwdMbWAR4vXIX3nayNmWtr0nOoEfDZnZ5ZZ1chEWv4HUJ7H+oMYTIkm0Lthr4FrAfo6mloz+MPWKr0zzSqC3ySFPzF0hNsdp6tb2oo5YVjRAmuTgIBrBzsthqlkYM/7qcEecOOYhLvSzvHzNQhMAqClHVAoj39QbVHfZBWHyTUnanUxVFFMgeO20436j+RWBsvj7sE+3FEJ48q+gm/etUpa5zXG+KZ9VHtjD/GLzdb5k/Ojl3zX5mNj2NGVAuTGOOLPv1X2fplrypruaAyQ5jXKX+qbJEXlzC2fOnLVHg6hmNgJ2QRxMjcyswbr/TzHxQICH95jYYFOVroYm2AsninbemmE1ttYSAzbm+f0wBQAAAPFNUhwZrRkUfPtW6HLktSpJ7Le1oyzo3SCAWzXqITrwfNeEZ7i4oGvrhtWntpDOvGAeeNFJm8G/eygqF1lF9OCscbSzj/4xt8DzLarIIU6Ce37Nvja8rM0LWdFEZoeZAo4Ens+z4DW7sWjftqSzRYtvUTR4wl65r9UlsXZ46XxLis7ZXtTkMVHaJa8gHAs0U64vg/lWDS+kBTdw/M6SlWOvVJDBqIvknThEYD2BFGOSBjcaxqmoIAE7trJNaqibvwq+GwLNf2kq26LipGgj1BuTnyjVQESQlmiRKRXCkqm2pAjggmjScSXIKQcMrLmO4o3d8+/UkcYpGU2uFTOKOMwC0ukIjkAGEQhRK1fTbZJZWso1o4SIhIce88uZ0JzACtGhEZWKUmu01WrW/vTC8UJzxyRwW3lbAK1dZXC4YMLYKSHvPbC/lHrdnK/I/ZOSfO3VQAUBtJ0CZpsgbScXiRN0IngYLa4HoiWQ/efOmIK3p8gj1ZsYQlVEFR9xiQGG6UrODTaZh3gRHftJokTiObM1l8il2dkep5JgCk3R77h/hGPVi7FydkGGsMq7zfgVm5lu0PGPJEuY/Q7SkO8hPcox39lmpOGRK4dTLxosk1HqpRBybj8eIJtgpkggQZvZjMM0n1jRB60ssV3wVwoPkQoYTe/IAXG9q7q+moRFMhyRsxRWYtPobyNJKaTTWSjXUEA2jnr5i6rlyCMHsPehchTvtjyzLik1U8kW0PikxrNltXYbwVZ2VHNgNBkbVX+i1x0fX2j0wvlvWrg8WX2ZmxywPze7MQ2g1RZflj940d9onEtwJaDLCteTkK4PtS+s5HY1xTcbmNSmLvATmI/ZLa2F4zR7HLZbMPMAjruPkWaRiOZCF4/JDjmyJQFB21sY0FcVuSZfaTeC8jFlh9H201pheuLz8/4dwgpFT7xthQ70fhTB0QgHP7cDDJ2GJcrjCbQI2vvNdpL/d4DP9ToZIucSRDhRFHEmtSpFjUuRzExuRoGbmUZ6sce57omN2DQAyzHuAOL9gRsVGXvC/9BxIvyeVwe1al0z8c3/JM/jAP3yAv4c1PqfUYhRG5h5GwdmMD+I3AEzJs8t4K/sea4VzazqcLJrzqq+OfmE7QCb+XrVQi9eaSq0DPCytU5hqlzMbJxFdiVZrfka2VwnkvPFBpTYOfXwOEClLqs1qVReV+LfQK0KKwVTitfC+INA7jM7u05crvS6VYfSznIXDGZS/UjqhbBGuaVU5Yq6FQjQnz4g5hYg1XlhonFOHehZ99mPq/3WthP7Zp0gJHfVJztKqXdailAayhQuLPjtFzjVIklAA9mRGSjXGU0QG0KtNtqAHsCC254gNhLKnZXewHV8whs77Y8onC7TLWaqTKTogaIwqnIPqfCFk6WXnY1n5PGRcerzF+aeygElp4u/00Ad71i58iDPDsG1mfsJDtj3q9SyrlkqOxuPG4UEIc1Mi+FEALwSc7EPTNPHHioLLR0cCOJuqHiL2pirJ8/EXDbM9fz5SMfo7C6BUWla37QCa4l+VKzLlBJUDLKpqUQBuGMAOG2UOXt5K3K7rebyQwkZQJvtwj6AxCb8igGyPXgdr6sKCQ==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAx1XG8nmZYHQ1lZDF28yrjNdwPtLmJXorkmHX9wpd2smEGUFH1c+R1x90Cx1/C++ZDaG0LZOzFoURhJxAgkQWtLaKuHgy4X/THyeEIRF2de+rikJf3pai7Sl1Rk5keZmyEGdca9g1R4j11EvorfIueXMu5tUkSxjXGQih7xj00BAEzGD//L2AFiegE3c7DNOXrcmry9GugoJLx0NtqS+rSFuQSJWJkifCzus9NzVT5DWDpPIC1IiQe5v6JhhNCAD3bawctCBU4KkpKbzeJTChU9EJ8Aexj6eRDpAlecHOsVGGCsJ0dz1bBRkJiQ9UnGQ2IaU1CRRecDT3y2tEEZh3DniqfyVpGJdU6HL5I793Vf4K9pDxdBYAzyBR5hkQ2qMrPC7D7dcJHAmBEEGkBPlB25ztk1sUmFJNHlIq/E3LJm3E61ASn2x8lz7VW0X+J1CrzBetBuTa8P1WyM34ygGinGtIbuixAvKTuBPD3D1WYHUL8AmCSLBd2MQVXQ4QXhkytGrV71vL0Y9TIQUUmsynj1zfwRDdhGwl0JEAQKEaydEm/MGpIgKMunwX17UIT1DcRHZs8QDL7V5ddIHkl+pamlvYOqTG/Uv2yY4gt7+/5P9cKsBew8hqBMnYroNLOiCPvcwZKFcQl7wbyc1xBSswaeLuNGt5TtT27T+9Dr/HzejTvH8KfCGfBD68uJnPQsK86SBZQilhh6ix2IGJIsMAh06kCZq+XQoBoFkdkqFZd+4RcgcjGpbRMA+YBC7PguW7foeHd0jEiouRNB9IcfndU8o3VUtdabdKkYsF5F0XvJ+V1+586fBd1gJ8P7HZaCfXlVbvyTh8vjC17V8G0LSxSdvnpKr7iOgvD4l2mFXwK2CnEwLRVNAVR0j2WiUUknP0PDm6N9u2sf3xctF4ldJ/EsaKRN6kDSpgooqKnc/d6JHoWKN5KJj/MI5L6FnZzO9BS9sesUewkJiNSpAYd3hvVuz4C2buMGj0v8wsB/aJcIEy9bxOBNlFd3CIWxg1FS3I1aeKEevjLq5hc3NldAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG1ldGFkYXRhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEKAAAAAAAAAHegEyym/Ucg/MHeuws1hyy+jM+zhif831l7UTldqpaTNPaIs2r0vnhH5D+wIM5HCifg0OlnTjV7G2mcuziyfgc9gwv2Dr2csHNTeZsubKTYJwSSmUTRfzwujsxrJaaUv1RZoQ1ta5XLLCMBXq33YxSofd7+rr6rAi8TArKGCNUK" } ] } ], - "Wallet connectBlock should update the account head hash": [ + "Wallet resetAccount should create a new account with the same keys but different id": [ { "value": { "version": 4, - "id": "203693aa-71d8-4bde-bd3e-678f96086a70", + "id": "f53847de-227a-481b-a812-d7d3bc470f79", "name": "a", - "spendingKey": "5b1eff525bdc0d699700370b4c464428bdc20b2f8901f07e9dbe025eda98842d", - "viewKey": "523b241521730831004ee05525dc7d80d949398e042370c55efb282ba0a6fc94690a8b2ec4bda70bffb676ac1b3af78558727c749797bb10074866795422233a", - "incomingViewKey": "1d8b5c646e4dc78dd5b114c9d6b9985ac3b157f2b1f3b88d6dc3274285087206", - "outgoingViewKey": "c0c68212bfa326b18a81662901f02550f36cdc6f902d5fda40f059a5012ed429", - "publicAddress": "1d36110d2e6c8dd0f700b747596cf63d62f743d13b8d8924055d96911e9333d8", + "spendingKey": "8b98a67d7682196a381b5d60a2620f2c91e5b73a2b2e3f7fa820df66658799c4", + "viewKey": "20775b11a44869e536657449c5855cd0915b71a7113bf49c743606420414273852c0c2aa8c2750a118e1b8a6a2203df3b344438b7c2ed1485385ebbec84742cc", + "incomingViewKey": "6109c2999c98a2e918b72c61e86da7f0e0abe9149bdcc850bc27a1eb42f44407", + "outgoingViewKey": "1f5613cf9e3adca3828dbc5d240fb945f8737681782080eb49a4f7e5a97a144f", + "publicAddress": "9219c0cded1632973b6f30fe89a1ef5d2ee497a43a9e8b4f327ad5e2c74bdd09", "createdAt": { "hash": { "type": "Buffer", @@ -4488,7 +4438,7 @@ "sequence": 1 }, "scanningEnabled": true, - "proofAuthorizingKey": "63c9a8367bb057cdce77b16f994e828cdbaa5203c41cc2e904f2b12252639208" + "proofAuthorizingKey": "363be292208a39201f35e92ca187ce0c4cd09dff07b555edc2b1af6d38158705" }, "head": { "hash": { @@ -4497,17 +4447,19 @@ }, "sequence": 1 } - }, + } + ], + "Wallet resetAccount should set the reset account balance to 0": [ { "value": { "version": 4, - "id": "c182e51d-7e0c-4074-9498-d47d48d35f17", - "name": "b", - "spendingKey": "4c456f3b38c1731304e5d4df3d0ec6b0cc06261dc58f7873eff2d598038bbd11", - "viewKey": "3b027acd91b59518793f55287f1b2811abaf5b2b0cf45fd5750d2573d8609cf32c15fab25f110e798d3cdc0a8840b8abfb7e4385bc5f4b70e17499eff43f463a", - "incomingViewKey": "04ae8d2c315fa46c1280ad3d773e5b9af5651516439929fddaa7a652f07fbe07", - "outgoingViewKey": "c239e74af1eeee7d96916801a4941f2cb7fdd9339281ab9d1921f75523cf6268", - "publicAddress": "e04def37fc0cab193e44a31390d85c0090a2b89a0610bc16e017f520aecf926e", + "id": "6a9ff94a-d3f6-4fb9-89f4-0ba9f707c04a", + "name": "a", + "spendingKey": "937a478517b57e3edac6b5f362910c7333d95fcc58c6fa400dac30b05441e57d", + "viewKey": "b443df461a21c2f783a01d9735720aee1df503aedbfdaf8c7166f49b2f2e801b96e721162122300197db9d96e5399154b732711c15d06b76ae231d2fbaa989d8", + "incomingViewKey": "e19764232ec43709b83322ddb76d7a1cba8276194e97bdb6ccf0c457aa19d200", + "outgoingViewKey": "3dbc7a26ca52b85339ae4dfa94e90394a15e162081d537657b565c1a65554a57", + "publicAddress": "b4230d53076043fec8aa43688879cfa6a3286f6a5f3ac64719cf9fa33744d206", "createdAt": { "hash": { "type": "Buffer", @@ -4516,7 +4468,7 @@ "sequence": 1 }, "scanningEnabled": true, - "proofAuthorizingKey": "502fe91c0be9444219abc053a14247785e8eccf5794d8af5d91dd3ee7ac4bc0a" + "proofAuthorizingKey": "b623eb9b8d6578c459eea70e0e562faa59576cdaba377cb66bc6e49e2ad06b0b" }, "head": { "hash": { @@ -4525,101 +4477,19 @@ }, "sequence": 1 } - }, - { - "header": { - "sequence": 2, - "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", - "noteCommitment": { - "type": "Buffer", - "data": "base64:8ZWbGvok4PJT2Na5ti76UPQJxVICBSKArkfCrCz5VG4=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:ctdXcichGfVii7/ebZ4DB8mOr6WQ6szgnpV0msPeOag=" - }, - "target": "9282972777491357380673661573939192202192629606981189395159182914949423", - "randomness": "0", - "timestamp": 1717538689366, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 4, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAATQiUeasNPZ0R+nL18MSm1AQeYU6LCBnTQgQUjMbUXoiMjLW6uTSiNmZLMs+2YlY4YUdt2rjyjmnsZYDxfKy4ZDm+fx8oD7oWy0ptSJ0TjBmTE4noa2ggEkQPdcfBYBZST3j5tMQZN7qGQED/6wNGyLr5QnsOe3f2fSx1vjv2VgcG30Vb6ss6jROh2rRliFfdLler/1OBds31Ec/ceJ7dValxNOfLgSur6Gewky9NiayJ3CRZLeGAH9pXg/W3KPhL1vVE8Qgx7oYwsjGYTM2/PNftNPhSaJtd5BEgQT5/v9s1Hc5sl5ezbKRZijzdFE+X645t2Ed4wM7wgcl9jWxKtQk/fUmTELjol8Si79LCEtVDxgpel1SYuIix4ZLV+LwBeNnEn0b/2/V+U13A16JDnxrycaNSXeHwxk2t5BsOVpqAD343MpH2QlnJ6jOCUnycnuUmFggjCK9Mnc7HjAVX7u2UDaSz5iLyuSSeBLGrbjmJldeSUlnJUgGPFCRuDsad6cyCQQcvxrqQkNRGwkmgwpK02umxDDNMqFSOHCCi9T/NZxH86r2pLdECJ1zLikmSEo9sGG+uMhJQ1GiSl4h+cUrVPo21d9CgSZ9ZnHb6mSiGEW/LSrFc2klyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwlw4U1DmDT5USNY4ERWMIjyTF5P4+ggRbiAErPcr8gHLtDQTVMGjQi1AYNQHEizcXU3oKfZKAR7+g9RzevUkSAg==" - } - ] - }, - { - "header": { - "sequence": 3, - "previousBlockHash": "C0ECF2D4F0A085EA8A0ECC2C4E3787BDF860A49AB80C867F2E780CA41024998B", - "noteCommitment": { - "type": "Buffer", - "data": "base64:nVr9NPL3fyAsgr4Rcz1CMjGYm1134UIZcnCQeibt+0s=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:gZLBGDeTqRWU+lMcr0wmUPa8co0ta46GKmaTmRei1LA=" - }, - "target": "9255858786337818395603165512831024101510453493377417362192396248796027", - "randomness": "0", - "timestamp": 1717538691121, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 5, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAA8mrZ8TJAL5muTNSgi2cTHoeI/kzCXiKKb6bDkzSZmQqDQFgBZQyv0vPQVxJCl3lCzEXxJi4tNQJ9fV3WZM/WYHA5iMF4YguK4f7ZQOSlp4agu3Dj/ngJVx8FcBW+UrdGKe+IR+yJtah3XER3k33zFucVaGXavwB++fSi6jzwXCMQE14xzYW7Y7Wjq7eUw1eKqv2rE5NsXrTkUlsOpEhWDf7anq/W2sH5StYdxqor21m0DivzRapxmD+jMBvn1Js/Vr/j5gtFAVPTPxa0klPqqOZ9o5c0bMg06P+DrgzVzofjNaD/KzevGEP/j8ZVyAJu/F5oGpT0yiscWdWBZJf4nkvyP75qnYVYwkpBuhnr7f8fZ6bT/EDnDBir1eN+zi1REjDamn9iq6/FYHwjv3vCw5aLpE1YkcBokpBoFX6F+tWQd+lj0bqimdkPsmJAC6m17dzQ1bN+IdMPgq1BsnlylnXubX6M6PfsmXNTuAYop+P0g30m+5FElQX8YMCn3uLGX6d1DLyOADNL5BHIcFZervsNJ4XJTGj0gZx49GBEyQ3g4qAPtOtdtWHxTQgXyJAB0mm/OnevHnYkhSk8tPIYTHGKT0qVEO/nEyIc6q6ttNaFj7nEwaNj50lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwelwwhjLv951EXCpMcJpo0IGVP5H5puiSHrCnkVpqn1Kkw+1zhq1zStuxmfdypNHnCvErus+K9fHMAYGthRthBw==" - } - ] - }, - { - "header": { - "sequence": 4, - "previousBlockHash": "BB35CF6F245C5407CA73F847AC5487DF8C60F61348474D5D7F94683F2EEEDB8A", - "noteCommitment": { - "type": "Buffer", - "data": "base64:CHDdyjgaJ2slNneDkRbyaSqkBW5ijPjY9nHek+782D0=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:r57/zAhw8CpWeINyFnybI5UjARfD3hFhIHK8ZmIPGbg=" - }, - "target": "9233318228143625020618577701423519925017621426082203201059080050516648", - "randomness": "0", - "timestamp": 1717538702961, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 8, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/2vKiP////8AAAAAdbblmP6WgplGVE9oz0WKWiH+g+IU+YvLlW2Ir1dowlWxZssjBm6KcJnDVMMyXvaIQrMpgAujtEXahv9iSq4K9SP4T8ZuQZ7CsOq3HHos5z+5lsGUgQI8rhYLy0nGu4qhGXKxxnMqWUN5C0jrehx6uijRjrZ2yz+ykTEh2e27HhUGg6mOyukbi925EFl6n7jnI1Ihl67wViryHrT2zcWBMGyk3LWpkEuGvPkxj3kUzPqozMxkyGc8ggHl3CpW9YXi+voM+oD/J8n5L1VBW2bHErYTKAO1wuZhU5uza+7ZjNPpuo67vr073h0hnnwu8aFCD4LZWE7ZJpO+ukY2GreV5q1tNPFYIBPn2Uk8ZHy8/imeQxu/Y8fj/7qFHEzoFdATeOYJb1kGaMW/wpLJKgQ5pKvn7pQJPdd24WxJWdKwS8nWkFRu+/d/cxwyWwdzLZyevMP7tXDaNOmp4LdPoTP0FNIUevUa99v4BZOZRBFGngc3RW5BDnWVWMjlP1O4qOq/erpGxvj9B+OjbxepuosUPjNaCVMduRI7/tJulGuQdMdzpJzYmQK+my41TLcBRJQlNyuqMHw6QpLaTTU5ilTUCpEOSuKCxXh1CQxcYwwbnWuexo2kkvHWMklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw1jbbfpY0TGw2ogdTk22dVss6hp/8pSYPV01t7zB0tNInXKQBj/BSEdqe/6UfH70iD4+/zW7l395Zb+FEkl+wDA==" - }, - { - "type": "Buffer", - "data": "base64:AQEAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAPD6mDMtouJiBFtRKIl3sieS/Wdx0hti1mnO+LmJWJ5q1f16S9kOPjPTme6WfZ3GHV8OWrt3mpsx9FEslQJddvC5J9Y8vWc0EwcKreCqdQPeYknY609MAHspJywh9hcRxFbES8l1EN4lA5OxAxixR+lwkObwhXfeLp4+VenZoeLwLtqJx4HUp7ZsX/h4qKskmilDwZnXaAChFw0jXfba7vvO47dRxPcs9JxochaNi40+zLsx85qMF6pjh0tN2pmJgNCBto4Yf7j4SrP0djw0xvJyYIPviKd/icdlLlGeS+CCZi/Hjz+xna8KBMniN3ORaHxCjWXQTFxoPrJE4Ny0/AJ1a/TTy938gLIK+EXM9QjIxmJtdd+FCGXJwkHom7ftLBQAAAE5z1IQcbD8btIqPHbqMde2kQn2izI0ffpmBxQKYV5N3nZmV8yZRYCGs3GiM3qDRG/mbv2LF63aK4GT/EN3/M1dXkCmSssZpwMobsiujqML2R1eECIMgggI3os1e45cUDbknNtxY3nX+AXBRna1DLpxXxbGI2MXM8CaZKMUcrnTmlTM8nuywtUZlgjVG7/KiOpc/rmG4dZisxQeMakvXR9AdQfBSAU+LfJ9ZNV6/pnUzZJKUHV7C0bV0yUGn6JuBmRW/JhbTPZcD3m3sl/947CTNN3CQ+aZeyK8mGNJ9UbLLFwWzIV2NuME/5Rzs8/bCrbf5VKEHgcgkqgwtFqI05bLOIIuzec+iSIxQtY4Jm8TlL40HndGOFGnwxTk6A00rBq188D/1hiTc8zErDTAwXtxNjeG8rOuvIwwk1FlwBnCGOU7XjVZFTRx/QM/a8eNf+H6A+iOcOo1mRLXm1aHHGwjfSqFXR1ehs6MXqSu/hjGsUk/LF3CDpDgkZNO4xfIfc0M80A03M4BtvPMGzcZxe4jIYkRRcLk0hNSbhM+EQpm+MpFTjFICtLLAMohPZqXL4oqjOJ1QVaki8UejkhOMTqTztzqAK2VBfWI0Kium49axlipAdHm1+qEVxxHatDhriQRoAcPztq8gCrhetjY+/Td6AjZsGXdYkLWdIn05st/Es+XYBsMEj69R33XmPwarwpsIc9BJt3qUkzc3CJ3fODKgAVvCBiSenJw5smwNlVX/jqoQU5gxvXztmYGXaUS85Aa78m5yuSHocyitTxBDnqBsI7l4eGGLHXP9rrZ/3iScjdf1ZaogSUWmA4owB6cGkR4areyP1+cUbf55RuPbToE/9TLMCLS7EY/R1o6G+aCzOLQeYB5jaU2hbuyqH/7QOjxPGgLVU+JT2ddU9imRFoDkshoQL0mY/BPxpcnZt1XbNZbp1gm88FQYV2zQb2spsjhw+VLRK5bdO7AuMyRuKoTuIVKDavcvDWQsLY50J21pDqW0d5vCRjSzUawKHEFc4NaBGL7GInv41XUIYCpmBtTTzPfPD+r8QrNxQRF29PSnHNipmsjVJS32qaY2Z7zc57C+awUe6A6gwLMbAjtmhtyVfjAsIlArVxUnEDsDwdRBeOCzPwVrkJ3CfujFNBxhrvIkba/fuXtlYZHiVcV275f3Jyhr9mJisFy0A7of7TVCdCGJ0Ou5F8lDMG35Wf7DlGJmYKLFfY8IcQFUMHkTLWDMMjrrVq+QUf8bd78zINjiAw07AvkpHM00a38EmHK1/bbRiz8SEHdY/7no2yI/KC/+T+Ux+yMakkFulLtdfh6+uX9AwvtOaM/170YvobYlp2wo3D/U9Dw5Jz/fmgjfHO7TolzhWEx+Fs3RL9uBxT7+Fpo0PeFI754i2+39Oo8qitirtDoHtpXkDevVWi6VeZp9pohu/H+u19EuEvxadllLnIahkVSwNMAoPSl7H+bAZJCjGH1gnqI9B7Z0nx076cX17BPG/VnKwnRubKvv5F1bae7eBkk7uMeo7hIthg6AlYJZyLSbMT/8DO0U7HdgrBE5EGlwGn9zscLDNPZuORy/5X7D4N2xy928iMicOT8oCw==" - } - ] } ], - "Wallet connectBlock should update the account unconfirmed balance": [ + "Wallet resetAccount should set the reset account head to null": [ { "value": { "version": 4, - "id": "e6e07578-1ad4-466c-93f6-d4e2c086ca46", + "id": "4eec859d-9c89-4908-a23c-4cded4b294c2", "name": "a", - "spendingKey": "420843092f654880ea9945307acd50f4a5cc81dae58f0886f1f18ce25c1d8d32", - "viewKey": "41b69bf61143f22ef34c11b53eb201f7489e1ee838f2944685e45aff0f13044ec36043c8516e8ac93133f1d7d2e6c62886d5787f89bb366abbe265efa64423eb", - "incomingViewKey": "14afb756bd4dab75ea541ca2395a5a43cc7c2d28d2604c9e2db33dc8a6b54a05", - "outgoingViewKey": "2f8bf7b9a052db1c5fcb25b85ad93523fc865c9493a12889dafeec82e1c98ba5", - "publicAddress": "2db05c91321a5e96af2303c9c9164bfc0a2789ccce25bbeb4213cc986fa755b9", + "spendingKey": "361eaae46d35035ae781a36b9e340258fd5afc2c9d3ebb24a80bd62303578b87", + "viewKey": "42208315b537e8d625a3c2ae5b77185c6b2cee1552233c7edd1a367ddfb39a54ccbde3760a337020c7ed42a0e3c75911ce6a10eab5de52551a445170db68f507", + "incomingViewKey": "169016b8098a97c18599273861c150e2232c7ea5bc93189d0eb076405920e807", + "outgoingViewKey": "ea8bb7fb76575ec9e5c3f5ab3ed106882d99b9b7fcc9afc224e0ce595e3f52f2", + "publicAddress": "8336fb0657aa4cd82cfb5fb4b6723300af8d8cd64f86b14ece8b0230c6c807a4", "createdAt": { "hash": { "type": "Buffer", @@ -4628,7 +4498,7 @@ "sequence": 1 }, "scanningEnabled": true, - "proofAuthorizingKey": "ce1df7be9844e830b02a603d25146aeb1cd88d47b28065115d8701dfb9927406" + "proofAuthorizingKey": "42a275b3cb8c60e9b90cc9e4d8ae72487cd3af1eff1dd61ec1b2cda588ce460b" }, "head": { "hash": { @@ -4637,17 +4507,19 @@ }, "sequence": 1 } - }, + } + ], + "Wallet resetAccount should mark the account for deletion": [ { "value": { "version": 4, - "id": "ba507d1f-eaa1-43b5-a3d5-e3f0835b2163", - "name": "b", - "spendingKey": "ca3241bdf3377026987473ae97f74ea32fac0a76bd7afbe5aa099a1d5eee3737", - "viewKey": "4a3540f5145e4781a31d65cc17b2ff8a807a1d4b565b854d9bf88d17a5215f5898807830f904d96c28fe93ea9137dca15ac7a84101c0eebf8854103f934d1cf0", - "incomingViewKey": "e3fd9ad198d5d57eb446d439862b8e4b529c5e186999aaf5319b0c6043205302", - "outgoingViewKey": "fd5aefcb77a84360379cb42ca1575af92af0fef6f9d585e00671788f5ab7fb69", - "publicAddress": "1bc946448310c4b70c9a0ad476741a0b0afeaf02750bdb5ca324ceb3c743dce8", + "id": "1db0d7c0-5dc0-4af1-9349-6dfdd1eec19a", + "name": "a", + "spendingKey": "d380f4af79c40738657e0ee8007a4759f9486df02022273d48e2fa9cd6576563", + "viewKey": "7d408b8858c58099450f0ea14ad0e810064ff08a73078617753eb29d30b7854aea22a9f5ed8612759086087d7b78b3aa50913829f494820a533ce5f13ddc7291", + "incomingViewKey": "f16815402bf70f6e6ef3b167a3a940419db3d05f8b6eb56cff9d09373bef4900", + "outgoingViewKey": "92a38016572d0afc6a1c7bb92632134c761b4ef0dc82e6083b61c8ffd5a7c1cd", + "publicAddress": "2b617eadeb40c7e6679212318210dd34de44ae591cbb1245a80563bade2e9706", "createdAt": { "hash": { "type": "Buffer", @@ -4656,7 +4528,7 @@ "sequence": 1 }, "scanningEnabled": true, - "proofAuthorizingKey": "12baa42c0cac30b9bef37d863528b3d2f6005299c8f545bf7bc219f4b7792904" + "proofAuthorizingKey": "c35690ea9aedc88905087aee7b51edb296caa78169107d016a7c2e785676bc0b" }, "head": { "hash": { @@ -4665,75 +4537,19 @@ }, "sequence": 1 } - }, - { - "header": { - "sequence": 2, - "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", - "noteCommitment": { - "type": "Buffer", - "data": "base64:E2EZVHjeLvWcAa8IT7Ni2Ux80EXU834VWaIr3z532nM=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:JdGMfWzvdPdPqLzGnPg9qbyxaaRTn78az489TPlJ1Kc=" - }, - "target": "9282972777491357380673661573939192202192629606981189395159182914949423", - "randomness": "0", - "timestamp": 1717538708585, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 4, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAgSWTdzyDmJymRS92zJ6fgFZXXdCw35XCWCRH7lIZpQOi/86a8KBnJAuMLY459E7oJaWl0uBXAtbvdworkuYoqsYWdX1miS2mq/GdiKy4srWWb8E2TM7twOJ5bb1wGk5x5wr8Eu3NvI/SaWujCe9yHptG3CPgENEt2jNdfDJI/nUCi8Xa3VewEt58G66eRKPwxpmEhQGTfFOw7HhO9Uat+8Rp8ZPJtEkKZnQy5ABMPICUDiTYnn8I/XX6nUFYwguKfotH9L2k1E59oIod3+8hSj2lTMmu5mLi9L/U6tkLAJdmtVUuLYiGKJE/F/PS/50gRl/U72Bjn0D68pPWyX38zuzJ3FcjnWgbIdeMLgGp7m2aZH06hNBCjFWfI3D/IpIkPJsK98MQ94gzN0lUXkNy+c2o19MOZlWcTfg8GRRjN7DCEav+1Qgqn6LnyZMJ9KPFnOGEJs3fd6UllhUiWiAHAcSQnq8b0ndA52LelRK/2qpVJCKONCoiW9GS4KNReZD8S6bKMusBUSESKIn7Xbz60zzOFpCi/yJVqRsjZwG+QPjSiGy6lsFiofURqGFtWpDtz31uvkhB5zvs+DBwMqxED46GLuP7DrQgZK5y2pqDGNg7Mf4hLgkgpklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw2cQJDVa+FJ7fx5sNcgq4p9gC9CqEPIpmNnUmPaBLHZp2Ge+G4csJGsjeKEcKyBCTslLzmuLNXHlMi25iEb8HBA==" - } - ] - }, - { - "header": { - "sequence": 3, - "previousBlockHash": "42DBCBB13E03695E976497A2432B740A14864A5C55AEC55A756C2AF0D19ACFEB", - "noteCommitment": { - "type": "Buffer", - "data": "base64:HOIPwfKSv4AOyIExevqAx1L2fz/yxsgMfKpg8rjYpGo=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:6iEUo3N+XYPWM49f6kf6gljcIUjIkPmhjUsVWsBYbuw=" - }, - "target": "9260366780148527510972123832573278885902566341756516011968728852484845", - "randomness": "0", - "timestamp": 1717538719107, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 7, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/2vKiP////8AAAAACZUa6EoIZyCC8ZqizUMtc1BG88YzWcApg7Xrlj3+yQSBPyB34rE7MvJb8f6VfQw18feDEV9FG+5ZWcnmYD14uotAMdtUPi26Kzw6ZO23OQeKYW3sjRVagdVQquvPXgshh3rBWEj7IcrcjA1ZCVYaGtn0bJVuL00YhWIzN45VgHcLFYPwLnFdVI/ALyqXtQ/BfWU1cU2RXf9CAYYMZUL5f/qWk7HgpaMvdYv2RJjJK6W4rJ9f1LdBtcFOizPRgfMwgUTqp+W5Izq5cViYhSUNbHRd4Xgy8m9Awsnrtxe33yDCERXj1zlEnZmNBG6tQ/GwOhYlJiberemmvVzl2/uVaxRgr3CnaizVdPRleCIb7xrEmlkmWnSSGVEWZDBALgRVyoopZaZyrKZKLJrPXXuazLFVWeax96pvoU2fer7oQz1rYdTKDw7zfSPNnQGvVCuqbwYmz3lqHimBHnuJg32RGszxK3NusII1lsrINTaRPK8NTDm30Rw0ZtzjRT5gcUKE62DybkU5m3r9cKMoMF9vq2IpXUmJlqjn0tTUf5GFoqyFxmGyiHfHZrUvI42aLpWqZRzSMp4Gv1Pi9xj5KILu69Xh++gYYH5iK61dROhLX40jH+HBFnRqJElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwo7KcKsMXQ0jYoWFUAeEweCvg9iJEVCanTe5cMzboRzDR+meyxr2aJtHviqQz8NOO/LcNlrHPH0Xg9Bcc8hFQCQ==" - }, - { - "type": "Buffer", - "data": "base64:AQEAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAtAAY8ThmuhqcQpUf0TphkomKQMN0eVjzwtGyMu+mZLWSpVb+gyh2ydR8wSopy6sh0sKHPiKwJHhDB70UCebhPPnJN0yvHuBqVbcmiqRBZYKI32O0Ovjvhvy/YKEBwEUFPQCwz5gllRoS8BVkbXJ5VGNtziCbldMaLCCQ1y9GhesNGbpsFbgADzV5WODkNb8WHjUlI8hQrgo9W5vEXuoN9f+ODpR1upViALfNthtosZqw/WnWHOZ5Q3GON6Z83brEUVT6m77LXuf/qo2x1h6U9RTcQQemOc6m9EXVV2isKtPdpCBi+P9unntLAd0ssYNyENruCC4PaEVKBTQ9D7vk2hNhGVR43i71nAGvCE+zYtlMfNBF1PN+FVmiK98+d9pzBAAAAL0kFmFW7Cb+uCgPMgQx49tlUgAh8EpgyV1zCErS3MC5mbMHSfOtEYS7cZUHucyJdu6X6eBXM4/S+DHUipaw5LWzSZcrglSdOOxp6nx0wylmm2y416rBGMNj0eXDjDl+C5OeC5vDEEMozWFMNnjrMiuE5XCao8s/tqpXW4fjdsXdAabGhemDS/Oa5hTaQccy25R70MiVre76bb63shAvJfoY2t82tIWgigvyK6dDsAoNgFemsIHo1QlDfTS2VbY+lxKsJo2CEu+n8LT1BTV3shPRgG5u0wfYaXhdx7s38LYwiTk93UKKVAynpVa57xHubbDgoyirc2Y9Ofk9iaC8Otk7ZxUP0gtkrQ+HXY7JJrOwsbSxRPVSGk7yqPsiFJz2d1vaOAlKaMLa4Gy9ADgxZP8rUmDcuX/rDBThiow31vWNyAr/rKbknYx0GQsK55MQqb5mq/lsezaXfftElNrSvz0pbmLyYCIR08kq8ruMBOZrbQPPte/YclPgILGNnMbu5EacoOxSIZEJ6J7BjjdgEZVE4d2mNo82sSA48JG0+yVXjMaSTvrALvckR7t4cV8WoW4fqFkResflba6+ewuENd/+OipGEF3It/hROoWnM9j3mQYWO41/FHNu7SWdz4ZGiuMBgtykOXkUpPzy5bqmvGqaIl66TJkOg2y0jR72E1WhNCqZatuCIVBdgE+DajUGVKnCc5QPdLy4u3aGkJu68Wo5y4WJMxceqwnghLXAHW6qxTSjBPtgnZ1zmYSiCepNVDz+s/QD+QJR7ar4ZL0H2xppUIa5sYHSiQFalM8dcMP3OZAtPoixbjSlMqMzzT8eP2f/HH/PG9/C7HXdcZoWnZGRee4buHHyAXsZ6Z6PubfVoJ5HcuqsirSifZwvtyHx9S8X4OF+OCSLZXjg3p7jLm/prXSMqGMqWLVX1lhnTonx7xL76QmriFQUcJR83hTDgGS4YC5k78s3PW+19D0GpvhayRGyGzRkn9PteI9kGZxZFtO5Oj8cYsegjjEtHqrOY53nE6+zpW7n6hW1DxnJxmW3mbryePCYeFe052oRLU/kezlckEj+RASDcUGYQ7MWgIgitGWlNXZb1KKy7ybWlw28r6nrEoUerMo+fmwCelciMMFTtkGa5gRRIcDBKw1qLze8D0e0nWkyfvbmpY3tPjYdQjDvfCQGgx32FqeMiRjKJLGdFf2USh07LXH6bj5EOIsIXNpyZcp85qm98/WUqMW0Y4Iwrp/DlJreJRNnY+U9QBNNkUC61f1MDf5VzXaida9Z/Y2pcPSZQQjy7fhU1QZQNSaOtQXsNaJ5stO+47Cm0K55NYUW1/ApYz8Xplty5v/8SK9s5mYeFR+mZeBINqxKfy8Rf/L9MticP2HKH/Mj3n6pUH5FA+QYECkMsaChZPM39u8/wziWeJ+VL1lnEX6VQvHjXtra9R+uRDJod6L8OLsa83jI+ZOvaxZyQJPTAAKAeLh2hWGIG9SC0b6uwMB4pKJIdLUOXaBQaswpFnURV6EHxmcZqHMBXvGTQ7zrXDw8AAVFx4S7pcWEssEJBGl6iXtfvQykxIk6WSH5OlQDT2UeNQJ35FvGmhjNMSZUAw==" - } - ] } ], - "Wallet connectBlock should not connect blocks behind the account head": [ + "Wallet resetAccount should optionally set createdAt to null": [ { "value": { "version": 4, - "id": "549c0c4e-62db-48b9-bf31-17ffe7a8e31b", + "id": "7beffcb8-b04c-4563-a719-631d6e742547", "name": "a", - "spendingKey": "38392b27d4f07a540dc60359f1776dd0deff50f2b8fd2acef76e7a0330c7e5f2", - "viewKey": "e118d06bd3e2ef6c7a3eb2276e71bf920e048ac57f9b8278c116f0682a1075e90a52c2d2f3b022d12788c9c027525cc779c79bb0b593bc158d285767dc9b3128", - "incomingViewKey": "904fc0c2542b4054697441a9aa09651ca4d23f87e2b009ded9ce9c25f86e0602", - "outgoingViewKey": "ead9f6e370a250d3e6f6a8bd26aeec8832f31fb29bbfde24bf29154c3963bfe7", - "publicAddress": "3c91103dedc461acc29cf0f2c38ea8b68cae02594cd61f007418ba4ea91e0b4b", + "spendingKey": "d02703f5b2ce1d0e9fec295b9ebdc26abf840553564c7c6c82741f7f85be236f", + "viewKey": "8dfcd122af2b54d80db4593bb9c01c01a4b2dd0552907dd93c6bee790429905e18d941069116640a12c94d619f770d43b2267174b23ff5557d57c396aad28b9d", + "incomingViewKey": "f35802b507f06f6c9f0bbeb9875da6d290b147a0586c7cb83e341c120a005c04", + "outgoingViewKey": "0f418c817a72226b81e89cd2bc1166bb593d6469aadfb758301a5972a99f849e", + "publicAddress": "98648a14194cd07bc1fa21d34bdb15fd41d556250dcc10f35888f24191cab41c", "createdAt": { "hash": { "type": "Buffer", @@ -4742,7 +4558,7 @@ "sequence": 1 }, "scanningEnabled": true, - "proofAuthorizingKey": "d9abfb17706f10f70a61c41f88d4a3e931835f3c98912e20edfcddc0b567370e" + "proofAuthorizingKey": "6f473605fc3fab9a66ea0f715ad6aeb36d624045086bd6c442497af0d9771103" }, "head": { "hash": { @@ -4758,15 +4574,15 @@ "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", "noteCommitment": { "type": "Buffer", - "data": "base64:9kj6mLUHK/z49LhREuV654QfldZes68IGprirmjS3XE=" + "data": "base64:xxBl7uwenihtMyNth1+es8eijtbg0APwhjU5JCkEXmI=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:ewxaYXo1/0UE/FqcSt3F/t3vxfBtF/I0qsZjjw2yiag=" + "data": "base64:0AZsQZxjyOjkBfy5wcV0LvCB407iMYL/C86Rx7pxIgY=" }, "target": "9282972777491357380673661573939192202192629606981189395159182914949423", "randomness": "0", - "timestamp": 1717538722947, + "timestamp": 1717538924255, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", "noteSize": 4, "work": "0" @@ -4774,1042 +4590,50 @@ "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAityQygHbqt0VjDxEzaFyBVzuioP/pzHMKsNiBhmLYjyBS4p2xk9YpIcbcrPGcFMuUCpdBpq4YzcH4AkSRu0tEzBB8Dh78NnQS2Lk0ETaCaKmomParGghvWIKx/S0B7YIOP5z4exXCqEVty0fymVVpxJ4EBghJhUfKwmuaaJ/VMIYkjAye/mqpgkAKXHqVN1892zovFr/+akH4xkKcdKUPNG91oLTsoHil8TzSMxuRRu4sENH/wA3Y4Yo6o3fuVplXQBGIvC5QvxJBJXPxULMH+0uBxsVx5syITQNutdEjaReDQ3rdgpHH3TWsOGzvmBRLw3es4+dRoxGKNDiYLU7AD31T+iQP5JqiS6zRzShpstX/wzCCqdnT7FN4LjG8WctMOED+mPkCPeh1QQfjkGCA6z8Lr4bn0ihy4eIPAq4fCNwexW/WGwQS3GB/es4Ruo3Yl7lgZho4f7xtSQ/x6qFp9yhGxlTfWpGgJKX1qqmLMrJITVH4UWTqj1LkhHwYi1WFaeovH5K1ZiTwSrlnZQY9bhtc/1MoVMjaI4WXDCW3TW8pSx1q+KkfYzj9D+A2ccteQ3wJkaVGYvyD9y/i22QYwhLdhZ45NX8HM1ELq96n3vCz2tbAIX2PUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwWa5z+Y5ScqK439M9t6NQMoGwtl44CEdDcAgpq/v1xG7/IvyqH64i4aCd0oOj314uNDGBnh1i386kv+H1IVEdAQ==" - } - ] - }, - { - "header": { - "sequence": 3, - "previousBlockHash": "F061890B105D00F09F2D22D79916B8915E63660D4F8613DED1003E1626F3554C", - "noteCommitment": { - "type": "Buffer", - "data": "base64:we4LwRNXxKAUFs9XFZpYKZZ5lrVuY6Knfoa/mf2JYjk=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:A0rjOI1sM2RqCm7hRI/ig82QVItLkR124lCsen0kF/Q=" - }, - "target": "9255858786337818395603165512831024101510453493377417362192396248796027", - "randomness": "0", - "timestamp": 1717538725161, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 5, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAA1Qt/MhtPOUbbH1Dq5Nwe5NYf5mgOF9qahSi+qXgQbCaU6LsxbSB3o9/imSy10i1TSmTchg6ks5Rp9fNtrGMfGwa1P5RpUECCJfvdNP5/DPuI3eNktr8KbgJcATJbTHnxs02dunV9Ai/lCEJXIFjxGV8kecG3kfwRWQSGdwGf1X0QenJ6mU/cQAHE3HA/LJa9cdG/y8LwUuZU0PvKq3yLpjufC0DYkQTJJYsffwSDQ82u70eGfQ+Z3wy8UCHYP1/2rBg8wFvQ81KGwtKOM/09uf3cFF86wJ8ySW9R7ys/bicUeoQJBP/FOi7GOgtRJw6wwuv9C5qwsLPau8nOfQIVG32PhpPX/Idzgw8R32Enuj7rvukdT3/9nccHL/HYpb8G/iEp8ajRMkUluuRP30/GHjhMxuP8Rb7rt2fsY/GZTV7xb5Rx6+RQ1zFmkyeIq781DzfhujdO+xF6iqOk7QROcYPK2PnZdmcoEZ4r8TO4aEm1qcI4eRDH79OBP73/60cJJ7LkKw+hFdq+lkqIq0SQZ1bkSEtZpw4RclWfELY6vUg9xaciDa8xWbmMGLVTo5oVNLmv0YBz6RlxmEH98piaznqd6XCuexTl0EYVZ0r/zb4cOUuHuciRr0lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw0xRvTW9fTJlsGdjoJU/AfEzHYSusIArbgU1x2eFhDJ3HuGPuWQxfjtKfdzOJBTlEzoU+OeEiLwfWwjqNE1yRAg==" - } - ] - } - ], - "Wallet connectBlock should not connect blocks equal to the account head": [ - { - "value": { - "version": 4, - "id": "876ad5f8-678a-4b18-a7a4-bed4748da70a", - "name": "a", - "spendingKey": "2cf20f13a0e93c09e06e8edce5c61eac5b4750afc68810661dcef81bb513f030", - "viewKey": "6a7590f9e9ebfef17356dc80f13812be8590f42e619149e3a139aef0e19f7dd9915255079068983b47871df78020a0f2027790b5a959794fd37cac0b4aefe0a9", - "incomingViewKey": "2de5acbe99b326bae9267b2471d58ede40cec3138fe156599d599b1403d4a107", - "outgoingViewKey": "eb45a5a3b4a9cbb1cfe22c1efea45c29e55e1c83d925d3ca892d693b28681235", - "publicAddress": "580336448b2097ac9f598d4aa6e7300219c49bb861bf11c24a9278ae65934f46", - "createdAt": { - "hash": { - "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" - }, - "sequence": 1 - }, - "scanningEnabled": true, - "proofAuthorizingKey": "99c3f6bed5f5e73d8c291e95c70056f43dada58594cba4739e833e882301ca04" - }, - "head": { - "hash": { - "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" - }, - "sequence": 1 - } - }, - { - "header": { - "sequence": 2, - "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", - "noteCommitment": { - "type": "Buffer", - "data": "base64:PANqKX16ed46OhXoTdcTbh109NRTEL+0nkdSUSNcr2A=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:2tlanU+nqFhfh+6GDGPHfRQrducErz4W+vk/nOeYhbg=" - }, - "target": "9282972777491357380673661573939192202192629606981189395159182914949423", - "randomness": "0", - "timestamp": 1717538728400, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 4, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAvy5s0E6Tr8GHS9Mv3Su1NfDF4q5kJwm0Qr0BxrGU/mWN8UY7Ga1iEFfUCpkc34j1lhNrUqG0dQM57Uc1OkJAs4oK3sASDF9xWwFwaCCn8GqXqnZKRdKjCB/elDjYeRQP58TOvPB32nxH3SeWIO5/zaUWY5swnUoXhhVsiZ1hOO0K5Qiv+XIcvmt1sUMUHstmB/MaWCX/bphyphh8vkYQpq25liVFkq83a7CmFwhv/7KHEwO/fmxrE7MGp3huWnv4Ovwl/DncOZBKP24rovGWhv+SipmE8eneGy+LONh1wRf8PJwP4b6QIR33nkquWibbnIJgstjYAlk2dCmfXwUTYMfLKJrnsEfst9NvhS4jOse8sGCDjZotqLif0koQTNIblY9H5cEwZsJypurz2xTbBeFgn90E9zl835tF8Ky1RtnUAWMZrTmJG7FkQWnIOVesMmOASe2HfuUVrQa8AC5JQjFlQmmFsMm69wL9vlfKyh5eKBGVjzviBT/vHd+zod8HpkaDL4eW0pb7FxxG/ahom49ohhYTl9PojKw/q6pb00K68i6lX286HGcFwH4K3bYsJ4cPsu7FWBf3YGVxdkGhqpdhlKsDTDh3IUE9+IbEliEk/UiQKwDqSklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwutUnEeOJzCTl+ddY8OWJjeu7mUaGRv7ZQlOzZXX+x1yrHthBe360JdCB3w4e8sYzVc16+exatwibwxJ5bUKBBQ==" - } - ] - }, - { - "header": { - "sequence": 3, - "previousBlockHash": "38E4839FA33029B096650E9CEDBAEC98B5B488AEDBB8A4D809AAE96E9863BE54", - "noteCommitment": { - "type": "Buffer", - "data": "base64:t/xu3Ock79Ta12+GZid3cxt0ACVSLDWvXeF0PgbLrWU=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:u85uO2zQwGWgLkAunfsf3ZPYU6VoD9Rsu6K05NJWl6E=" - }, - "target": "9255858786337818395603165512831024101510453493377417362192396248796027", - "randomness": "0", - "timestamp": 1717538730986, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 5, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAxrX3vg1YM1H3yTQvlQT6ji/CdaNebbYYdDfVbug9ybaPChtHD8CQkHfo739PmAZsBDzoaf7Pv/i4SwG2tpE//aYd63qUqcLrlKZ1c/DhR+6k3J8U6zRdND01JrkK+M+dXQtn/1dkteNGDLP4LOkWNQptPbMgDScW4UhxPFb8PzwUpijs7ccxeuCiXvmauk7K0T5FKgCK3q0HQNhj4vzM7osVbzz/t9kMGTSCNdDkq1+1JIzal68440UnIa1DaC6nrBDwvsNOYsl7iVD7QFHzYK9RD9WMbZCkOueAalN72dTno7UJXmnkC9vgaU7HZFKJEUoJ75aWxpuhruwb2aHpa2qZ5wISF8vN7CJOkI27IfZ0FFJqoDAUt9xLPt4UH/RbqNJX0XrORlwYQQjF8Q3JJjxYG2aJlnuKS+dCeeHGhD+71zFQvjYkX+wnTZk8Lqu3oJXO6InzHB5BvYyOc3B3f3a1xtpA6SS+gwZdzI8JGHPBiMOkaNNzOBS46ljmWFdKUu24FYO4LTZC1r5/ArwpByOf+ZR2aarBg3bqhqBXdUHejb5wAaFunYyWDcMdvHe5/SYARnn2tcp+ED6cP1wc6zpf0iqMLQ0UsEdUwwxXw3czGM9kxhDUNUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwf4WhCcmuXWYQgLSaI6PED2JFVKnTwOsas7wTdJ24ed7dlXvuyi8JfDraJaGvgUftHODqBn97MyjIuphUh7GfDA==" - } - ] - } - ], - "Wallet connectBlock should not connect blocks more than one block ahead of the account head": [ - { - "value": { - "version": 4, - "id": "52f3f178-cd61-4fb6-bec4-152614086521", - "name": "a", - "spendingKey": "c55214d79107e45db306830b34d5d2bcff54786820a5983ac32d6650f907f49f", - "viewKey": "bc12bfbf43fbb6931755d06e7568f1e49b46b2ef45db44f47d463e1635879aa97564c0970b1f81018303ec2550bacddbd41f4bacbc18c04f9d76eb641811efb6", - "incomingViewKey": "6914a8b8060ebd61f489938c8f76f5205cf2c5f462599de32b9656a237457605", - "outgoingViewKey": "3ce0a0bddfe06268060f00fe2baa4a5ad48cacade1cf0baca6b0df0e1d456f37", - "publicAddress": "d7a73845f559cfe20c840c3e944a439b3c6d89bfe93aaab4f4f6062d69a033d2", - "createdAt": { - "hash": { - "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" - }, - "sequence": 1 - }, - "scanningEnabled": true, - "proofAuthorizingKey": "690371ad8dd629b94449613b54e6715962d573b21a7e39e772167e575dc6fb09" - }, - "head": { - "hash": { - "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" - }, - "sequence": 1 - } - }, - { - "header": { - "sequence": 2, - "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", - "noteCommitment": { - "type": "Buffer", - "data": "base64:axaDsNs2wjUhByGtFxDUW+v5qC3s9gFC5h7FR2TJz0s=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:25ZW6iiZBiJjHP9FBDaXBr8tBIrPAPxAGxPhNzaAjS4=" - }, - "target": "9282972777491357380673661573939192202192629606981189395159182914949423", - "randomness": "0", - "timestamp": 1717538733868, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 4, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAA7hY/V1iRONzfsyFwdBgejDxV9sePkuGCSkjpnB35oaqyYuahqgCazfU6XWV0Bqr4gGvpx9h81s0BbxEJlkRnaxkbKlcEFVnN9cZ0JXQvrTeUbPqT3Si2ug9zj1nx05J9WebDGK4bByqHH8zSlfCq9vM97PJxq59Y8C9a8UjM3bwX+URjOZBwCrtJXRTXEq8WPxKhK9SoMc4nX3bgJmPXUcetuiZtpTRUYR1zGJO/pSqQd9XFiiJMKdUgsUZZW7CFgjRBlwO9ek7cRFcErvwFAharpOg1J+Ty5lms2woPCO16BH9Zo6DLmn5n//fJcPJ41ol2PxtzI5XGh/Te5UJTK4HEh/+Rsiboqzg7a//cjV57yWERern6+/BaA3z+/hRDlsNcryair7Z444tfhWmhJ0ha0lKfR3o2iA3ivli+1lCDVevavXlAEZH34m/wvWGdovOBZJaneUeNFTJ86MjRSI6f6JyTlHuvhMUOcoFxhrAFgzywXuXw8zmux1tGlfv8qZxmAqe/vfC5G5BOvumzACXIl9Coepx1QyUHxt2+U63boaFUPYtrOmO86e8ia+muFlOsPXwNHvvYi2EFVfgXoOAFZrbMv1VKpgqxdc/uAvRQhhl3gLo4yUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw8t9NBU/LZZLTk0+ukiOf99gcMMwfxDuJLucKn4VfvcPCc5xmrtlUnAwACFflSpWPoQMQqCcnw+kplNwyriQUDA==" - } - ] - }, - { - "header": { - "sequence": 3, - "previousBlockHash": "8DA8A4399285E2876D74DC2DFF1649DEFDC0D47700229E473D0CD02308613D58", - "noteCommitment": { - "type": "Buffer", - "data": "base64:7ghr1z9O7JdSQ2GcoFgmk7//hVvET5sbM5VrhP6wATI=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:ImH2S0om5NQNg2+2whXnhJgHannGzW/3cNBQA3Tw0GY=" - }, - "target": "9255858786337818395603165512831024101510453493377417362192396248796027", - "randomness": "0", - "timestamp": 1717538735542, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 5, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAyHRH30y2J54NKCqZPpQ09/jnfDD589NExzehSdtNljq2eVCXDZISUrLOoowNfpqmIZQDWfeH1ECHE7htZ2kobY92l+TjtVZjZSAhu0I20/2CKQghklwUPP7t31s12QnGdaLnTX77arFjdCotgQJj5AvnLUiBvtDqyE07te66OR4Gd0AWeLLYAm80gu9YnD6uRUldDkW/SeWXSvwphhq8kqs4lnsJGwozluBg1kOsFNKOt43w812CaEkA9c2uoalwyqMKuFO/CzzWapQk6msw07DTXZVZw164e3km+jYn2o7ZSpRvi2Pp7wJX+6ElRmRqkXs8JswuqTiwOytkLDogSHAYnz1QkkdyC1cxo3GX2zK1oHEaBMvI/lxGiQIzLgpCuEDFmch8X+ni6FmKFU6LbSB70qZYIBkiCP0YDPHbmhkvTUMemgc5exC7MrJMUmKCWRBbYXgC+T59v1EY3MJJAQotn6ADKjZxLdUodmA/Pvj39cD1gpslGfZO/hSwWI7ObV1FlVxf8PAQBurJogTvwaVBVMgsqD8G4VyWMjlXZSIDAcnvkFSKzsJf6MB3iQ8j7J9Ea3SNIlziX5ZB+UNJICCoM6plvcwR1q013zXIWTYuDisbs7yZKklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwoCxJ8lTQSddh+aRtx8Y4MrqZSvGfGlxRFCNlYEGltlhLEGhdOr7RL3vBHTtEDxI3WVG/GxEMv+CBB0nlV+v9Bg==" - } - ] - }, - { - "header": { - "sequence": 4, - "previousBlockHash": "1AF26A4624BDB9B504FD50692CDAC15B70DF2B6D618C555BD418B485078FB0D3", - "noteCommitment": { - "type": "Buffer", - "data": "base64:7JnKBObZW9pCkqZBeU56zV2LkIaz2oCnZcW4aiXoOj0=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:ZL6WUrM44Uwp3dJuMsZh6YQXWrK8F9gQnPge0yAy+qE=" - }, - "target": "9228823284279306817296266184515742822248210830185427859262273659833347", - "randomness": "0", - "timestamp": 1717538737319, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 6, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAvAQGidZtCdZYMY4HRsXMevvLIrm2v638Zq4wO2dAHOGonRQA6LBOD2KdoFixWAUYCRqtkjpIp/IqkuuQvJaS23ZaiPV2F3sQqRKBrQtnfXWmm559+q7TjwACA78K0+b+UFkncqOkZb5KF6eZ34aXkFBRQMvhRPzuthPnRcT5JpURxA/uLxwQcNLfTJJpZ02n2A0voCXogCHEt2Z0yi1PX2rvSso+rvFUGB1wGn3yu4SwFFclz20Gcpxme5k2oGCJo8Zow25zA69N7p3vvOxh3pf8qMkCt1cMV8HFpvV6kiYSCRNN5rt03Saf/O+yUrjdXO+8hiIJ1uOCSI/7fYkY4FVuqFz8ByNvYrJ4iW9XGXWu8yU/x7OUJAxY9TlBMIhZdWQL1s3cvNWdg0RCP08c+xVLwEr8e3aS9kxkSzHV04DzdKiTzrAHlZbspNbmCB74Ds5UgGVacmmtwCoytaTc3v/0+WePimy+ZdpC1MGAbg79PhATyHQ3DZ/agawTrRaCuRISHOJGW3lCmIKjy7CY6a82JLVy0Qlqmub6YJgMtbMkSrP7+W6yo05OKn+AGetWQ6H2ByXJDLV7rAhX18IwPf3TzksD5BTPNzFkKfDwNaX60SadZ9qbYUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwkw+TgO7gc74gv7XXhB5vi1jJ8SDnTY/wL0j8h9oP7z3XC6+6if+ob4fCr6saUqSSBMaki26UzSlLZrkhIklUAg==" - } - ] - } - ], - "Wallet connectBlock should update balance hash and sequence for each block": [ - { - "value": { - "version": 4, - "id": "86d20122-a7aa-471d-bec7-095455465420", - "name": "a", - "spendingKey": "545fb9021b6cfadf2fd90b94c60b879e34981ecb13647b41bb831a559ba5a17d", - "viewKey": "184b832ca1f4c996130dbb9dc3b58219ef9fb02e19b8180886287fb165a39051b215287f945f58ff8118300fabccac109d2318c2cddccb0b2938677dce3e2e9c", - "incomingViewKey": "e9ecd4dd525a226e840dd9a524ee807709b1220068b1e502409fa32799ee9c04", - "outgoingViewKey": "31eb8cad991687c2132c3fc08be99c62296423e26d4afffcda306ca9fbe658ce", - "publicAddress": "dd644113f8e1fc1d324f34060696d8352e97a17edf0a3a78dd54e1d246f1a6e0", - "createdAt": { - "hash": { - "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" - }, - "sequence": 1 - }, - "scanningEnabled": true, - "proofAuthorizingKey": "a6ecfe0bcd13494281d7b3c00288ce5c6141d3948cc0c888bec52ac3d187c50c" - }, - "head": { - "hash": { - "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" - }, - "sequence": 1 - } - }, - { - "value": { - "version": 4, - "id": "2675479b-fba2-476c-8293-696a1076290d", - "name": "b", - "spendingKey": "357f8ed6d40908876618b6c9a88c21da09f8ee02da5b78bc30a49f0eb3041b16", - "viewKey": "0eb7686fe87898e2f3fe20e62e318e46d80d21e22e313ef83d0d760c7d8d4dd23774ddce0610f05d66584a7ac28bb8df1080c9f4a6eb47a75d7d2d8fd3e02841", - "incomingViewKey": "768e419a67825b80983a529df92f94e16db370f6a78965959c6c7cdef0471101", - "outgoingViewKey": "3835258a93bbc9f8273c4b67d74f47a3b70a6200b1be82f2ef61d97ab09a492f", - "publicAddress": "340d2b8c66eaefd69d9ed97d9e047903e9693f6223ac370da7f3ba3c87b7cfa9", - "createdAt": { - "hash": { - "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" - }, - "sequence": 1 - }, - "scanningEnabled": true, - "proofAuthorizingKey": "f942c2ba94cf975969ab70c6d62a2ef0bb097a75c09bba385ae2beed16fdee08" - }, - "head": { - "hash": { - "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" - }, - "sequence": 1 - } - }, - { - "header": { - "sequence": 2, - "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", - "noteCommitment": { - "type": "Buffer", - "data": "base64:0cTKMW7m5/wqFGYfjkZddvkDcuZpR+4iTi7G0v4Ogk0=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:HK9zcLEUrSzUEd+9ClvZUbo/Yd2PBb0ir18/7NUx6Fg=" - }, - "target": "9282972777491357380673661573939192202192629606981189395159182914949423", - "randomness": "0", - "timestamp": 1717538741136, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 4, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAADxmLDI56+zX4HxzL/zq0JsCDhvaW/2vXU9L/XpDXXjylyp/BSzy5keWndulO4sLs6ESN2e+fCHch7yZeNJbm8Y7y3o413m+M5CtZxstVbiqV6DBEqPBElk0UflMYOqIH9GPnk7kohtOJG+PFo/TKQG9AocBa3NmBEM5pItzuad0SofmETSmpXbck3eO6cI1VD7xP3pxEfVUPxMvouxcY16z9jQ2mRttVgN5+AtwBPCSM9BI+aOcMthwLDBrkQ/LFzQ9RSrE3+0sizjvpv2xhuHeyyzNktl0V2bMm/BXkEdPVsMvrIzzgNN/WibMzeh7ehkgpgxbiImz55NJ3JqCRlyqkcJ3bz4qZ6uSlKlD+3Hbrlt3Dwuee39JN1bUqWtw8cIjXEzmXFLftwvuS6mlTDEqxUBGuhiiHw6+9aB5wv/O6vbxb/10oXsOXZCzgpFkPRlzKG1MPcgZehOkaBhteQU9TATcvz0aPQCDXsxVxjb8JmsrdllvjE1JhRGPyQXAdetHmVxdnmBBe4oG5RY80G2wu3qY3q9lXX2joYreTG9MHmcW8n+0ZfrvQZyD/eoi3Z6qskROAnOT6O3OeBdxk5lDkIRMJ756JDNPW2/3vGOV1gYcz3j10qklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwvXrjqeHuZLgAvok01nDw5J5WtniafAoXKYkSeB97T+pRy9GdT+WuhWx3JxWSCz3J9XQhB7x5lcObKi1YZWZ6Bg==" - } - ] - }, - { - "header": { - "sequence": 3, - "previousBlockHash": "6BE851616D0334EBA8E769E8192773A6DF7C8551898346777328FFC18D57939F", - "noteCommitment": { - "type": "Buffer", - "data": "base64:u3Qbqt8zygeR+feBF4gGS8gXTR4Xkgqe78RTy+XMSyI=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:LRCNWMKthGRqlN2eVdXY6fLgJBlgkoxVdUGuItT/KkI=" - }, - "target": "9255858786337818395603165512831024101510453493377417362192396248796027", - "randomness": "0", - "timestamp": 1717538743079, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 5, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAATN9filqyLp5g9XIJpl3DxoP4ZGraolOjtp/cdFFVLuOkChjTArrCoZqNawle3yTcREJd8NSP7CNUDbwGSkv75RTaCghb+eyrtsGisUNvq5qO9+gC0xkxjUBwKw19rvNE8Flg+A8kxakNX/2z/hrV7WYUJVwG8w4qVKqHwQrFb8wOYd8jxYUIy5y17kspRFtXwj9l+SsOFnJ4JrwQRb090xvvnX1ZaqcmsznOpcyS5I+ZNyjcEDRYTrVWxn8ogjLZjBS389JR4QzuLZfskOfdvBEotsf0pAZ6tyvobgv2j4l/V7wqIoNNFpJJyOgDqZ7XfvC8f+ysnHIXKwdFNfRwIPhp68mWQs5AbQHCA0uQw7CwmNPLu9zuWS/k4IPmw0w6XU6JF/vd4vR/mW2mxiF9O7EYGPxozFVsVRYaA3FkfdjO9YUsEFtQX8cgXVt9YZI04W0GOijnIHAmKSTEhF6A0V0Ac5WY6Lu0+1Zi/rwe6VzC8Cll5JcMLiOn11Yp96+hW7qblCsudQTqFtCoksGjwM45qr/ocXGWgj3EULm4WtaGb29eCrIkLL8FCsJ2a5qX5xOEmMnCa1Xpl0toZHQolLn6Xtio3xqIPy4NEB8QOmZhc70mn/Y1rUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwiW/fMXUvHCO+tq9O6wnCS6d5tTUb4Qc6A9a+yRL0JNvW86uum2qpC0uumbMBBYXidl+cRNKaLHyacJzazFprCA==" - } - ] - } - ], - "Wallet connectBlock should update balance hash and sequence for each asset in each block": [ - { - "value": { - "version": 4, - "id": "91ff6e55-1ce3-45e6-986b-2a49f2fbc040", - "name": "a", - "spendingKey": "ef064203b33bed503b7ead158644ebbb9f4be9d997196823c4e12dbc28ee40d1", - "viewKey": "36c3f9ea6678efc017148e12ae4790dbea760d2a684ad4c564bafb36962469cd33cc899fc64b80e985bae058e09006fd38711fc31c3c988e109c10c5424e0536", - "incomingViewKey": "51b77328b548d6476845925043b2b68979db966a80045974ab1faff3eabc6b04", - "outgoingViewKey": "82631567836d529fed8d550459aeb2d0fd89b09a6b197da028b3e730edff61d1", - "publicAddress": "0c0e73741390118a4965ef6590ff7f76e88355b6c514619e6334733c19ca1bc3", - "createdAt": { - "hash": { - "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" - }, - "sequence": 1 - }, - "scanningEnabled": true, - "proofAuthorizingKey": "846fc1e615e263752c522a1847bc2300a7c83bffd013d792d8bdea4b6c354e02" - }, - "head": { - "hash": { - "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" - }, - "sequence": 1 - } - }, - { - "header": { - "sequence": 2, - "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", - "noteCommitment": { - "type": "Buffer", - "data": "base64:kqsHopOnj8uetmgQSSpqWl7NwU2AGGVQhwE+LT3bHC4=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:v30AX7dy356AAhKJ5ZNKRzrToMjb8jmWDZD4OoLulo4=" - }, - "target": "9282972777491357380673661573939192202192629606981189395159182914949423", - "randomness": "0", - "timestamp": 1717538749069, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 4, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAiocrxO+A0IiTliX0oV9UQcwHLKLYpdD7cJ0j2V8cdu+pnbIjDrqLdRgHN5NMOd1WLm8aG7Acv2IYX+WFCNuNC/vhnaRs5ogA5eOkkj4KRruPQtbiqoiBrwZhb28f27a+nCDCCSZBNVatKjnwYgfLLMj/HVnmGpMkIZv9a8o/BioA9cKQJjlRIq4RNreEetCSe1pCJJFlGGELr5HX7dEfopLhQU5x+afaOeq9A5etQd2EKShXQUlFmkk2+cLR40tIQQ2Op/yjRSIITmkWElVA/ce/x5i77DP6yp5k0e0lsEoHjE6ApI8dKS1A4L5+HFMNmfM6qOeSn2qSnSM9VoBGYijYDHxtNOKLJjkaCOYT8ttYwGN8wLQdm15w1C0MhWAEEi6INZq/8bUi65WvnLij6a/D62OEugmwLwXOC0EZ3cg/HIyl06L/ApuvYAzNnfCJ9Nwi1e8lf/mD2sx22X3N/QrzJ5Ff+pUTpUpb+uOnMhSLTZHq+pdWHTkRFt0sViHPCZVc+QOGfhbFhBX8HEntLEkrk0fn4Istg03/i6fwNnFRkXqmu1HBCzfplBdVCsmB8t4dZUiwW8wXSaIc9Syi3UoaMmQb1WMVfy50Ub8ci7usL3C8AJCszElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwShYcru/Bp+PpurbV4diRas83fjyjaiCN972Mm1BfxAzb6EDYy9T1Kv7qidI1hKYfqMHKJ5ga1/tyBOadOt77DA==" - } - ] - }, - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmnpeUzQ9D4Qb93JM92qkiCn9l3rluRUHW+juo0JZ2NeQ3UNTNjaHpGKVuB1l7fJuNkO1I6LAbAPXohfQqu9RonksgRP3hsqUoMsOTAiQtU6T+UHDrSfXpmB6puUasi0/assXd6nPOwXoUAca2hBsmEPOdZzVfl69Ln8qx9RZDWUMZLfumFNYZiKE3SDENAH44SzcdTFuBQ+aKG/xebUNvbevPfGMlZj+S9yPUx7ydvWgYr3BXIxG01i3X2XKdZpmZBPB03WvFfpe9giixiIRqdCM0qqmJHGCUXXvYlhMqklDkP1nC4wZE6oTznUiubQ1AJUt4tyHxWTOAOaZymJEotHcDarpMSsWhUAMQIHvtQPIL1O//8HwUc9uPjSDUvQxJuwQlvJ4Eu828VyV4QGieitDLs9QANVNxlatupM2SkQIThRGPfwKuTKS7MOFxRSypaLfJ5ZcrLVXao1topQTN4LTpiWLIsHKZVDzAVGUzlhYhBSf42/M+6B5m1xVD+rbjesbslzGYAqJDkkubuGq9B+fFM51VsZL3yuXCqH67IaQ20wcE9YpBWg3HDIQcXtprWKORJ2z863b0msW45yPfg+3i5mgM6GXxPiUkHX2FLF64Si03JE/f3iR4xJNl8dIL0RNl+6uOETHlxF5N+2cjqMjmuGaDlSABoK/MUKxb4rYr76ieK43LqirPB5+QP+QoEKaD71zcgH/+qe+JJq7oPb40Nxo8oKOrSN07fAFFKhE2m1XJNzyUwJEt+xrrokklCee55uymo2jsavy9ZBDVdZbeZ84PNUSsVdFLTGfXczCpVT8ZkFC16SmYjtMmtzcscwyOFp195G0/4AT2iu2K9/PPjvhNNG5ElzSUnfBL8Kv0CUuNfGaFgjM+JhBra5sCbdwVj43wip7rETwNpcxkO3gDNK5Lh7vuFKDi01uQmxJfZ2LAiKZpO3ZaT7JlgbuN4n36zQzheA4c/JYBHhYAeXoqWQOCMzhDA5zdBOQEYpJZe9lkP9/duiDVbbFFGGeYzRzPBnKG8NmYWtlYXNzZXQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG1ldGFkYXRhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMKAAAAAAAAAENTfUHSs0oLIBLGCs8WT8AV5UUGKbuGC1+GMHbOT7KSAwe1ogeoI0RhsIsT4xTKfW6OKGZs4bsBabdHtcVL6wnzvKeMQOTpIxXZpT2MsszJJDiie1hFKsN1cPvRCsxmRYJteu+w22+DLETWfxHAvWg1qjUslhpSnoNpd8Q3dfoE" - }, - { - "header": { - "sequence": 3, - "previousBlockHash": "08E60EA96751B6C263CB3EDE91557A5A522F4DAB0D6C5BAC27381076686A134D", - "noteCommitment": { - "type": "Buffer", - "data": "base64:WR4JLjZ2xt2Ol8DHhGLXMuMzfxucA8TqN93MDlofpF4=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:SjDmHRvql99ZZ4ZQwyetDTfIxxWEqNehAnuOHYJv4RY=" - }, - "target": "9255858786337818395603165512831024101510453493377417362192396248796027", - "randomness": "0", - "timestamp": 1717538753111, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 6, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAxN0S+vesKhTrnUKkw5yBuZtFaPwSQ79HlGuEcpcKBrq3Sx4FOedDWBV+xzWO4cOi/BePz9o50Jw7Xw9scSpxhIVPXAfan86ApZvfEe4sY9ul43jAvStK8/7YXWa5N9shmdPxUai0rns2IZW35C8jFzabCHBiQkYJTszXtxJl308L2s7m35qmjgYGyGKbUhxoFeC9kPDeL7hLgK9Kx0U801ALpnseFPCMUoYWqjmg8iiO1m+dSdDsteothPM88en15C/C/wPTTCjBcIoy6r8oXqKEC9R/b8bUL/0nLUf9ZFMqNMOCuw7TQTOg13IjwOf9hFWd7mSmT24wInNKlKm+7rHh/oDYlMsemdyfTwBa0hvdFM0GMEPDsMUe548SRUdVoIIhkvO3FJyXd1RScokm6CW8U6mGKnyZX4GWXrLAqNe/Gvw8kBQRi/v33a5IN8ygR9xv2XshNGMW1OBAcUQxBeSjP+LCXLlqOUIXSDY9ySxF92cz15Uwjru0OPzGMmbJrhASy3kiQXk42acrZ2A4Iid9tLYreOGbImSW7ZDzhCcZwCDarc5PYpSGB59RuhbYoENnPHqyGa1ICLoyu9W3yD2pEvNTpkeaHRLE7TOg1Rlt7XVj5u2RMElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwn0pwjy7MY850X+mWqQHdF8hfP/NJc9JZD5O3DYZMlTPyVIlxKM2Uk6FvARR55xSl0l4OlvEQFVRwRq1kd4zfBg==" - }, - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmnpeUzQ9D4Qb93JM92qkiCn9l3rluRUHW+juo0JZ2NeQ3UNTNjaHpGKVuB1l7fJuNkO1I6LAbAPXohfQqu9RonksgRP3hsqUoMsOTAiQtU6T+UHDrSfXpmB6puUasi0/assXd6nPOwXoUAca2hBsmEPOdZzVfl69Ln8qx9RZDWUMZLfumFNYZiKE3SDENAH44SzcdTFuBQ+aKG/xebUNvbevPfGMlZj+S9yPUx7ydvWgYr3BXIxG01i3X2XKdZpmZBPB03WvFfpe9giixiIRqdCM0qqmJHGCUXXvYlhMqklDkP1nC4wZE6oTznUiubQ1AJUt4tyHxWTOAOaZymJEotHcDarpMSsWhUAMQIHvtQPIL1O//8HwUc9uPjSDUvQxJuwQlvJ4Eu828VyV4QGieitDLs9QANVNxlatupM2SkQIThRGPfwKuTKS7MOFxRSypaLfJ5ZcrLVXao1topQTN4LTpiWLIsHKZVDzAVGUzlhYhBSf42/M+6B5m1xVD+rbjesbslzGYAqJDkkubuGq9B+fFM51VsZL3yuXCqH67IaQ20wcE9YpBWg3HDIQcXtprWKORJ2z863b0msW45yPfg+3i5mgM6GXxPiUkHX2FLF64Si03JE/f3iR4xJNl8dIL0RNl+6uOETHlxF5N+2cjqMjmuGaDlSABoK/MUKxb4rYr76ieK43LqirPB5+QP+QoEKaD71zcgH/+qe+JJq7oPb40Nxo8oKOrSN07fAFFKhE2m1XJNzyUwJEt+xrrokklCee55uymo2jsavy9ZBDVdZbeZ84PNUSsVdFLTGfXczCpVT8ZkFC16SmYjtMmtzcscwyOFp195G0/4AT2iu2K9/PPjvhNNG5ElzSUnfBL8Kv0CUuNfGaFgjM+JhBra5sCbdwVj43wip7rETwNpcxkO3gDNK5Lh7vuFKDi01uQmxJfZ2LAiKZpO3ZaT7JlgbuN4n36zQzheA4c/JYBHhYAeXoqWQOCMzhDA5zdBOQEYpJZe9lkP9/duiDVbbFFGGeYzRzPBnKG8NmYWtlYXNzZXQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG1ldGFkYXRhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMKAAAAAAAAAENTfUHSs0oLIBLGCs8WT8AV5UUGKbuGC1+GMHbOT7KSAwe1ogeoI0RhsIsT4xTKfW6OKGZs4bsBabdHtcVL6wnzvKeMQOTpIxXZpT2MsszJJDiie1hFKsN1cPvRCsxmRYJteu+w22+DLETWfxHAvWg1qjUslhpSnoNpd8Q3dfoE" - } - ] - }, - { - "header": { - "sequence": 4, - "previousBlockHash": "2B9E5B414C7E314AAE120E9F60A334F7056B18B2D4FEF4137F64D0A5AC5E252B", - "noteCommitment": { - "type": "Buffer", - "data": "base64:WsrCaDVLDY2un9xJ8QN49kaSqPBFU++DXpSooG9lnU8=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:XvzBdub5bJaan40A/CIfy59FeALOAwFbz76dRrlOMAw=" - }, - "target": "9228823284279306817296266184515742822248210830185427859262273659833347", - "randomness": "0", - "timestamp": 1717538754915, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 7, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAC2aq80g2qa6cp5aZ55Mqdjrj7mLP1F8VzVsJLmAODJWt5mz5Oit0CHDAtnG+xkEOrI9R6SbSE8s9oAeR07XimlMvjaQWUGllv6SfuzUQ2uSDbDZkFf+AqcIG71ku4Whp+lOmTqS0xlBoKCSSM5qnuEwuKFd5T+yXDkRKSuv6Ad8CgOM7s8tqm4skjb64EX/pLc6BbnaNUfkRUMQOWSEPxHFeT8MMtHnW5BBV4bYi9VyhkQTi80GWRS3547uI9iVnIKJBil0rEzKW/UpwsefxRtGUhkuuvilhM5hohdiWzu8OO3aSiXbkNRdJQa0Bf1w7jlXE2h3TAJa2tWLGVtWq1cseSezAAB1SHOnkWrDTC5nLWYJR6LSGw+b8KcOasMJswKMimw3KtTWwEQbgNLARZSAe6ZZEntbRfTq3Cuh/5BOvE+IixruzDz6zmAdTL130eQEDobiEi63NLiCcIkvrktYLUKsugJKxYQvtF4CjyVKoU06uitmBjwH3D8uS9WzVGATqEDfjBPDHuA/cE8be/Ue7xz6djoBBsGec9vHn2Q9yF5qXwmh4iDYdRrJlAbk4wlFjqt52D44irz3Xm+omEnb/8KZItcgIkDPYd+TFUVsIRz3/YTjrsklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwWbJzidWm4ZMmT3fo0cM8iGsjUl/GSUQFZSqFwv8Qo4JrEygtm8WPEaUnz1w83wikE2n9JGZedCZROQhUU5QxCw==" - } - ] - } - ], - "Wallet connectBlock should save assets from the chain the account does not own": [ - { - "value": { - "version": 4, - "id": "915b4fcc-0b83-4003-abc3-b3ac8d2b3eb6", - "name": "a", - "spendingKey": "8d8da90ec36069f7ec0c039f02d5b175b15cca476f4247a3e3cfeee4a9120cbe", - "viewKey": "a871dada21ed96d1afd20e52752e46aea17bceeb0a86cb52da60f91ff410670e93851c697cb989036d95086b01a4d2e3cd799929e3e0594c6bd0d65bc937c605", - "incomingViewKey": "1ba43b83564d50c2d89c0380d692cb0c9605d8dd28622c9b9dfac26efaa4fa02", - "outgoingViewKey": "61893a6f08648028a4bff39a7586a70082bab7dcabe6fb0597068dd1c2089af3", - "publicAddress": "9d042d3a4438807b1225f6e9883c6af634460304362b1e1d1d11a985b47f0823", - "createdAt": { - "hash": { - "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" - }, - "sequence": 1 - }, - "scanningEnabled": true, - "proofAuthorizingKey": "7b5f73a54f417ff870e556af7c73696488dc3c7515256ad261bcb7389d73520e" - }, - "head": { - "hash": { - "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" - }, - "sequence": 1 - } - }, - { - "value": { - "version": 4, - "id": "2bae3447-51c0-4701-9b4f-7fa8ea787216", - "name": "b", - "spendingKey": "cb8cf2b9ff149f3d4dc4ff7cb60493ea5c77c5fd095c169aa6dbea0a58a241bf", - "viewKey": "2fce17e766907f9b8baf3654be6578c0f8972156e4f3f0ecf22351df54f7fa9b009ba948524e55030ab53f269fa58ca21f5b673d8583a432e88e8556e01268da", - "incomingViewKey": "3cc5ae32de87f1f557533e5a7c6c92fea4822b30b314e0c4e7ea4fd4488ac802", - "outgoingViewKey": "2170357e32352fcc6eafd2fb4b0659dba71d142a6038b157925f1ebf66577582", - "publicAddress": "ce2bb4c55cbec067fc8ba9d94f780b3def2ba2cef6c0a612c8d88ca3741c4c85", - "createdAt": { - "hash": { - "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" - }, - "sequence": 1 - }, - "scanningEnabled": true, - "proofAuthorizingKey": "9c3e2cbf70b994d5b3dd251a21630a7e03be438afc52a076361c9c7563c1e508" - }, - "head": { - "hash": { - "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" - }, - "sequence": 1 - } - }, - { - "header": { - "sequence": 2, - "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", - "noteCommitment": { - "type": "Buffer", - "data": "base64:+FjNmRVawduRQiIigLK1xtwcf1a9CzZfmlf8Y/1Sa2E=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:G9DvNe65URf7a4GSV5NBWdgmRxK/6ROQDLJiErMD4yE=" - }, - "target": "9282972777491357380673661573939192202192629606981189395159182914949423", - "randomness": "0", - "timestamp": 1717538757782, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 4, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAABeV3VFs52DJ0tY4f1l8opWZ1VM8zlob1V2AJLaLzdRSES8ckskGQinDg0u+gLpy76K7FNTN1K669jCazuq6D4qXnpAUrahVNcpX/kw6ZUIC337uyFvN3YRaTRsAGTolWkvUlpH/xCBpDK/xCfYOkK21VyzYzmXir7hmHDzaHJZABr4Y5/F3GRt6OHP+N2Io24A2O9MXIftZujrzEtM8dK63ftB28M9J6tkHXILIDiweIu12uYwQwHZhq5xXdeW5+uf/vzYLlF7Cg4gllFD578Kgo8m0CcnzPxzKdRhvuAXFhbeo8hSPqA7Tn/tsUlGCVzF3b/Qs7H82SSPN6byjeuzpVZN7DE9mgXOHPCg/dyDWlph0mKTTglBzXwzGLohI7xNASUv1w/AR+q013pJii1bsN1mXoFrhz80Pg+MW4wK06CVIkThpjxgLP9jgswDBxW35XTroUWsxfeC7eiRuOkEF0N+OqGBO0DtL3cMyphUdjGOGIyPZgJ6XouwEExO1qfuThd49e2y7N3rn6k/89MfX9in7l3QdGhPM9XNhbL7kojUlEaTLtphdGr9NJ3l5Yi8m09YbOytJrHVIIt9MCoYbLMQWs2i4E4HKe/TtGFmkT3CZY23nYKUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAww1HQ2VV0XSjCszDQaDH12BdxxjbHz7AfRBt74JPXRes4UK1lVO1stYLA0P4RRIpfYhOjj/O6AB9IYQ6EsZZoBQ==" - } - ] - }, - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3cYsnSm2iYH1hnUiD7hsi+7qbQlyaJFE5X/2zSk5QqOIXnh0YsRzzfOFj6m8rZ5e6DXEjDb6UhzWSy53Gi5CFPjA5NIM8SSINFRMe99OzxeR3stc3bUXrzvarT6nMlUecLBjAMgIHGoWjqROXGLCepMQykWodbyWcY7U1dfXXfQXjfH7yBM9ggeho9fe5gHzmXlgfwnZVZxiM5lAYaljv+mM55tJdM7qzusY3JoU2QWPwwj1GEhdYpgT1IY92vp8yo5MP5fMxMY14fqI4zSoUlKclCcyrREiA2v9iJoLyvbM1RX84lb9XhbswJKwYPmepMYZlMs9vgvWJD/e1flmS71ktW3wXawnJKd+u/BivI4q7reCBhYI/wPpGOJRzI4gRIKT/H78BMjyqPKpoDMD1zvLOvoyKJ0jaTktbe76P+NJOA8MeB7PRXS4JPG2HdxqPbzF17GX5OaC+brazhjSlOq03OdRsPU7lIGGEPvkv6ODhCr1fNB1bqW3I1OT98u0Hcyii1apTA35n+54FND8FwIitKZqsKlWMNFlvQr28e68RG2+loAVpeDwdDKc4wSuZJ3tK5op1zxvlBny37Yv4DuwgkFoCBXlFMIa0BboBFripEx/mJ3hZV5/hLiVIgsg3dpkbLUIQXnmQPs2t9bD6he0Io9OuVTTprxKgz1GKh6e8PbtRZU0F69ooORb7X9PasXEitA1MbQV0vXm5kZdzShwh8+NixMcmc5I+gp4Hvj9hQlFkwnYpXrGyTVQNSfdKd/UxZHOK04Couo7G6iUKcUy480r/JifjTJbodotn9e+yTMarnt25i1K2xz4KXMnxxuJwpFTl2BD7Nt9/+quCx6144XsPkvnDpAkg/SBwtjBDa+0K/P8JyDU9nIZ3Ajh+tyEtI7Z8GtXdLl3M0cuyAifI5T3edDCkg12x/AwpGskL5W/gWoAKCvpKr1/uE5fCJpBNODuBVajrCApD6cEyByhELXbiRbenQQtOkQ4gHsSJfbpiDxq9jRGAwQ2Kx4dHRGphbR/CCNmYWtlYXNzZXQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG1ldGFkYXRhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEKAAAAAAAAAEJ97Ic0jZXLSfwvPOD1i3qjdFAtexdxqms30odGo/lCPzwYZqco9QuayCmfeUYitQBcmx/TGhzJjRoL+JxdDgAGsyBnEpxTaQHSaxaT5dSJ5OwadNp7m3mPHcqFyQGIp155DeXcil0EpssKY0sg3M78Rr+tgbINqkuERA3Nw30L" - }, - { - "header": { - "sequence": 3, - "previousBlockHash": "CC0B49C422C9E3044EF1A99DE6E31BADF542F6C7CF7582440C83487E33A24E25", - "noteCommitment": { - "type": "Buffer", - "data": "base64:45AjYssDI98rufnehnLNvEqTEDRyXVQuo/AgZ3YdIDA=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:muBBl+5id6qsKh2H35/dXNCY8LmlB56ioE1KHFJw6UM=" - }, - "target": "9260366780148527510972123832573278885902566341756516011968728852484845", - "randomness": "0", - "timestamp": 1717538763488, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 6, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAECBGMoUQuumHxBwbg6at0a4IWqJiFWHnLFQDKpC0OiSwVSczR1LhnKCJrHY4BS0qZvLP11LkWp2HrGr2TLal98idMdbrHsE8QMrnFLsjnXm57tOqktkpVZ7/zOsnqBi0xjsucFV3q9227+ynFBNU6XhS/ooh5zfBxPw61XEVQ3wHvJMbqRcTkkTzPEUPycpKYFTfwPmTUpLe83QhGOyHzCU2eb8GIQSmZj+ectegooaL1uyfmxEgm8B2i3a84n55AXn40S5UFdk/c5foAhYNus1GSAyWUIVSxJjK/HMSR8k5M1GaYTZwMyPj20TpKHXxOYjl0IJGHN1vKiKS64FXa43PihmoTA6q+5iAj4P/C3xWPcg/M7nQrsDCn/oFFHE0EHc+I5JMMVjf7mTqgdKWhNtv/EQm9u84KotEQ8Hdy4r7Bx5CtnwroSd85uExgoLF+BQ5vd0CBtRJyPJPy55LGs0OnFnadblffQ6UF6dyoFnJfiB8/eMMjIklqXHQJ9HOi9XHj5JXK+eGfd5GCg/bQBKNej/dop/ANHFPFphoVA4VqlgNyzjWEtR6vmyhP1q38ejAD822XegqoObHd5bf4cHyGMd6ZQvdko4gdUaTqc4GLoZv+ByNW0lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwf4yI/wEIEr0qB0smpSnB/pKPPCdgG04kcHbsCGqPBJerkXjeL6WXtqFZsXgYrzwGGHhg5jmcO0ZghgrStfC1Ag==" - }, - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3cYsnSm2iYH1hnUiD7hsi+7qbQlyaJFE5X/2zSk5QqOIXnh0YsRzzfOFj6m8rZ5e6DXEjDb6UhzWSy53Gi5CFPjA5NIM8SSINFRMe99OzxeR3stc3bUXrzvarT6nMlUecLBjAMgIHGoWjqROXGLCepMQykWodbyWcY7U1dfXXfQXjfH7yBM9ggeho9fe5gHzmXlgfwnZVZxiM5lAYaljv+mM55tJdM7qzusY3JoU2QWPwwj1GEhdYpgT1IY92vp8yo5MP5fMxMY14fqI4zSoUlKclCcyrREiA2v9iJoLyvbM1RX84lb9XhbswJKwYPmepMYZlMs9vgvWJD/e1flmS71ktW3wXawnJKd+u/BivI4q7reCBhYI/wPpGOJRzI4gRIKT/H78BMjyqPKpoDMD1zvLOvoyKJ0jaTktbe76P+NJOA8MeB7PRXS4JPG2HdxqPbzF17GX5OaC+brazhjSlOq03OdRsPU7lIGGEPvkv6ODhCr1fNB1bqW3I1OT98u0Hcyii1apTA35n+54FND8FwIitKZqsKlWMNFlvQr28e68RG2+loAVpeDwdDKc4wSuZJ3tK5op1zxvlBny37Yv4DuwgkFoCBXlFMIa0BboBFripEx/mJ3hZV5/hLiVIgsg3dpkbLUIQXnmQPs2t9bD6he0Io9OuVTTprxKgz1GKh6e8PbtRZU0F69ooORb7X9PasXEitA1MbQV0vXm5kZdzShwh8+NixMcmc5I+gp4Hvj9hQlFkwnYpXrGyTVQNSfdKd/UxZHOK04Couo7G6iUKcUy480r/JifjTJbodotn9e+yTMarnt25i1K2xz4KXMnxxuJwpFTl2BD7Nt9/+quCx6144XsPkvnDpAkg/SBwtjBDa+0K/P8JyDU9nIZ3Ajh+tyEtI7Z8GtXdLl3M0cuyAifI5T3edDCkg12x/AwpGskL5W/gWoAKCvpKr1/uE5fCJpBNODuBVajrCApD6cEyByhELXbiRbenQQtOkQ4gHsSJfbpiDxq9jRGAwQ2Kx4dHRGphbR/CCNmYWtlYXNzZXQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG1ldGFkYXRhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEKAAAAAAAAAEJ97Ic0jZXLSfwvPOD1i3qjdFAtexdxqms30odGo/lCPzwYZqco9QuayCmfeUYitQBcmx/TGhzJjRoL+JxdDgAGsyBnEpxTaQHSaxaT5dSJ5OwadNp7m3mPHcqFyQGIp155DeXcil0EpssKY0sg3M78Rr+tgbINqkuERA3Nw30L" - } - ] - }, - { - "type": "Buffer", - "data": "base64:AQEAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAedLOklrBrXa6G/YBss5RRGHYAagMULHeqHtvM5xKrcyKoPph5eUMx51wYSH6UVqR/LmnHb93wCq8sdGE/3jManN0c+QbWoqcUWkoQdEFePCqybcpaKPjIPZlpoFp+iF1XCvmpxuZmFPjjhm0SRY+542gF85cp/agktDzn/yYGxAK6UV++wbBD8L2e5HViAtp6PgKRyhIN6RIvnBetatKFSCU/jGF1kTPOq90P/FAjQyTmdIzINRtAVJo6H9dm70F505fz8S2xzVWAvUu96/DT0MvUgLqA3IGQibWhNoMTSVHrQoSoxa8RoeZnsi4gsdN760TelMZWF+RrtTFPCfdh+OQI2LLAyPfK7n53oZyzbxKkxA0cl1ULqPwIGd2HSAwBgAAAEg2kYlX/ZNXTP0u+iLXVPS+2O/wVJTnCi0ynjwzJBGnkAq1IiVp2iLlOPJCo49wYHN8nto33NsOw1p+wwzY85pf0cQAWblkYceajHoNH0r+XTs6UQFSpD0GYI8GyTaIC68i1AHqpJDrPDRcn8gEpdPjVsW6zZcHQHRYWuv7cr182T49zYI/VC5+0de+iAuHZ4O0Q7lJ8eoId7Wu45O1qhxSe8Q9PGZZi6X4AqXRAQNb645/gLCaWq0ctCLOA2DcnQDfuIUZJP+gDM5GP0AUKfxy5ixtcLQs47GRyhBh0LULNOxtE3u2YXBiJ48ec1E4oq8jpNnX0u9AuQYaiEjOpcc+mPb9XsWzZ+5azJj/esJIrdMhCuTRoaMEPBPmQolbx1H2nNrv2DGbjDJBSmJz8UhKopiiUxVNY1UXqtOMgkWkF+Wknb9bDjQDzIX01xMm4J4eepOWjC14b5X6zAUjvyKYtr4h5m8+yWKMyNRt6mkMYdMTbAkBxIpODgltGP8JLN062AneB5YSWCfhzMdFCccx1a9HGHs7t2F1SeV4pYWBfAi4d/9NghUg94AWuqQrInqSf/TBi4FhK8x2eFwt3JThDcnAjRe4SG0Ny5kwxh+gI22Chc7V6IJuIROUfUQooYW6ZX7JlvzaWrbXWg06MW00I771JrOCn7m2P3PgSnRgmWw3bivugFzpKul1WxQd+TD6pvM22fWZ2BW7Q9qR+B+u5UqEf7cka/xfBiGJKKcGxO+mpsXRsfCeOBKt/8b0VUcrlIxsW9rDu8RRSMxyySVu2Kl50I2HPIW6/IfhZTvJqtxX27K34FGKc1vZRnthIqsAz1Jb3CPRnAUob66rUG+a4A6DpzjbJEZytisee7T7GMJgS3pkbFW0PRngpwa1JlT2oTeVeIo4Ca55ETq5OfQOw+y0ot7qGImKI4piQpspEp326oAFDDUKMhmjoD0SHJBmElcxulL8eanyY55ETuQDbh2HLNZX8neX626gk+WDwmZdYHumJXmMhsktULqdPzdtxOySq9fNd9T3rk1TjOtt0xNNMcJcPXURob7Egfj7NUqyPbl4oENOvEvMMFxFEJiiF01seT9nfGdiGw/veypRxR9/Whhi2fWcr623r2OuesvZaE2hmuxn8taSK/Zap5+NFo0wUncQawtSDjs3NsEl/AjPZcpuebAv8ERg09AGKstVhzkv4dY54jh4CmvzINdRbW44nRKASLA3wPeUFdttULbYyx3Nd0AGQaI+SizXW5F6oC6+dlv5x3Z/0ebiIpM6sqB/xgj3ngpas4JMzBU4Sg21RxHEdTmkgpwSAuwWDpaKXHWz7k9WZf3kxpcWaeYM9EVE7/i++f4ovASpO7oJu0cW2cJLXv8TaLPF54O6LeYTpLCPdWMU39XFJvtfQq5S6jSwW0iop6aqU5KU8BSsHoC+xWp/fHyw6ZtE6i8O1MBgQPixd544qZgP2VkxMNkuG9gRHSNWmTi81+D6Mp+hEXd2zI+vMco6Suz/L/OOdg/VhuRw9HgQTs+K/uGaafP1n2LdxB/N1yM1a9hZHBEMKMbgFOkLGz3wRy6g6KIw7cOFgMr89Bk/22f3nYKLAw==" - }, - { - "header": { - "sequence": 4, - "previousBlockHash": "E76F7B810F96BC5B5285D71ED22892BB7C6F01E5105E7EED220B185CFE8DBD13", - "noteCommitment": { - "type": "Buffer", - "data": "base64:A11I7xz+8WUxjQjMmcQrBIFT9qdoltoulQ03aeIxzBA=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:N4Ld7N8M+ia5EWn5aE8HKCiYw6ZoKAFxgzgy/lEQ7wA=" - }, - "target": "9237815341750015092140817300043113376661752366206318446334046747329935", - "randomness": "0", - "timestamp": 1717538773587, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 9, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAA05iQ60xabSSeTHFqbr84VYSNtfkbOd8+2i6CES3R+qO03Rf5BQg61ZNqnjjlReA0rV2LTBLVtldjXjd6cUPvzu5m3qKYc9u6/i+lhv2hmluw57qhpGEHEYLH2vL/tI8xlodYWrAemdWMgfJZ1TB4KjLyUlZjjymYBROlv8jNh+EGSdBlTa7m0ZS260gPui9aeQhQV6bFluPSU/4cfHVHQjFUm02pkSSGG/DfMlHoQSyAIO26NYqegK1CtVfD+iItQgZnV+5bD7J/Lk/U/bdxwuX3g0St7hqD3SRYfy03nZ3xu7LZLkCROer+UOZUrVR+tyh4e0vGZurmTuG3twY98Qv7AwqUn58jBkx7MyvjLQHOmCdqoSA8g0eR+zA6ffpGuIVmAouqfgVP8ARz7HJsOp+VbjB9famOZ9Mdze1qqWkWDn/tTAX8S87gMCpnr43bQGZCMU91bqS7fT01vZjSGgbpnJM75h9Pl8ayDp5nfwLjV6VMeNqo3dcY2GK946Thd//iqA8dNo7x/xTJogmG8nyrhRbO0pEvAZcxopuaBMmEye44Le7yCZiAuC+ApSvc9mplNs782iQUaFdZ/Suv3zJcbd/9gvlK8UwYtzkFEZ4XNAX0uy/i+klyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwqFeeYcaswJOX2ikmZG8s58NffYbgk4a45kDbXB6A3HD/WfL0TZRrq1uzb9sccPS79+Gup+2W9g+aw/E00/j1Ag==" - }, - { - "type": "Buffer", - "data": "base64:AQEAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAedLOklrBrXa6G/YBss5RRGHYAagMULHeqHtvM5xKrcyKoPph5eUMx51wYSH6UVqR/LmnHb93wCq8sdGE/3jManN0c+QbWoqcUWkoQdEFePCqybcpaKPjIPZlpoFp+iF1XCvmpxuZmFPjjhm0SRY+542gF85cp/agktDzn/yYGxAK6UV++wbBD8L2e5HViAtp6PgKRyhIN6RIvnBetatKFSCU/jGF1kTPOq90P/FAjQyTmdIzINRtAVJo6H9dm70F505fz8S2xzVWAvUu96/DT0MvUgLqA3IGQibWhNoMTSVHrQoSoxa8RoeZnsi4gsdN760TelMZWF+RrtTFPCfdh+OQI2LLAyPfK7n53oZyzbxKkxA0cl1ULqPwIGd2HSAwBgAAAEg2kYlX/ZNXTP0u+iLXVPS+2O/wVJTnCi0ynjwzJBGnkAq1IiVp2iLlOPJCo49wYHN8nto33NsOw1p+wwzY85pf0cQAWblkYceajHoNH0r+XTs6UQFSpD0GYI8GyTaIC68i1AHqpJDrPDRcn8gEpdPjVsW6zZcHQHRYWuv7cr182T49zYI/VC5+0de+iAuHZ4O0Q7lJ8eoId7Wu45O1qhxSe8Q9PGZZi6X4AqXRAQNb645/gLCaWq0ctCLOA2DcnQDfuIUZJP+gDM5GP0AUKfxy5ixtcLQs47GRyhBh0LULNOxtE3u2YXBiJ48ec1E4oq8jpNnX0u9AuQYaiEjOpcc+mPb9XsWzZ+5azJj/esJIrdMhCuTRoaMEPBPmQolbx1H2nNrv2DGbjDJBSmJz8UhKopiiUxVNY1UXqtOMgkWkF+Wknb9bDjQDzIX01xMm4J4eepOWjC14b5X6zAUjvyKYtr4h5m8+yWKMyNRt6mkMYdMTbAkBxIpODgltGP8JLN062AneB5YSWCfhzMdFCccx1a9HGHs7t2F1SeV4pYWBfAi4d/9NghUg94AWuqQrInqSf/TBi4FhK8x2eFwt3JThDcnAjRe4SG0Ny5kwxh+gI22Chc7V6IJuIROUfUQooYW6ZX7JlvzaWrbXWg06MW00I771JrOCn7m2P3PgSnRgmWw3bivugFzpKul1WxQd+TD6pvM22fWZ2BW7Q9qR+B+u5UqEf7cka/xfBiGJKKcGxO+mpsXRsfCeOBKt/8b0VUcrlIxsW9rDu8RRSMxyySVu2Kl50I2HPIW6/IfhZTvJqtxX27K34FGKc1vZRnthIqsAz1Jb3CPRnAUob66rUG+a4A6DpzjbJEZytisee7T7GMJgS3pkbFW0PRngpwa1JlT2oTeVeIo4Ca55ETq5OfQOw+y0ot7qGImKI4piQpspEp326oAFDDUKMhmjoD0SHJBmElcxulL8eanyY55ETuQDbh2HLNZX8neX626gk+WDwmZdYHumJXmMhsktULqdPzdtxOySq9fNd9T3rk1TjOtt0xNNMcJcPXURob7Egfj7NUqyPbl4oENOvEvMMFxFEJiiF01seT9nfGdiGw/veypRxR9/Whhi2fWcr623r2OuesvZaE2hmuxn8taSK/Zap5+NFo0wUncQawtSDjs3NsEl/AjPZcpuebAv8ERg09AGKstVhzkv4dY54jh4CmvzINdRbW44nRKASLA3wPeUFdttULbYyx3Nd0AGQaI+SizXW5F6oC6+dlv5x3Z/0ebiIpM6sqB/xgj3ngpas4JMzBU4Sg21RxHEdTmkgpwSAuwWDpaKXHWz7k9WZf3kxpcWaeYM9EVE7/i++f4ovASpO7oJu0cW2cJLXv8TaLPF54O6LeYTpLCPdWMU39XFJvtfQq5S6jSwW0iop6aqU5KU8BSsHoC+xWp/fHyw6ZtE6i8O1MBgQPixd544qZgP2VkxMNkuG9gRHSNWmTi81+D6Mp+hEXd2zI+vMco6Suz/L/OOdg/VhuRw9HgQTs+K/uGaafP1n2LdxB/N1yM1a9hZHBEMKMbgFOkLGz3wRy6g6KIw7cOFgMr89Bk/22f3nYKLAw==" - } - ] - } - ], - "Wallet connectBlock should add transactions to accounts if the account spends, but does not receive notes": [ - { - "value": { - "version": 4, - "id": "4b46528d-35ae-49fb-b3ab-c7942ea92860", - "name": "a", - "spendingKey": "312b7d60ca3fa451e1c737373acf7ce5efe871e04f978d0082765bbdebd8817a", - "viewKey": "8ca1af5cc4ee5b015ecfbf8eb4bce558746ee8109bc8cbe73a5a62e9cfd56098fcb36934e25fb4b61d0b0300c0a31a9e08f47f3b57446e60f9a2f0289e24d8d8", - "incomingViewKey": "875532d7b4a7a26386ddf29eff49a72b6a25b268167b4858af04f10c30a9ac02", - "outgoingViewKey": "66408539769523de7eca2418517b62cb02be7c401f0a7501bd13640d080e9c3e", - "publicAddress": "460d857e7d44100aadb1635d84a2d792131ccf3b111a3142e3551ec4c2f2c239", - "createdAt": { - "hash": { - "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" - }, - "sequence": 1 - }, - "scanningEnabled": true, - "proofAuthorizingKey": "ffb1665a2739ebc9ace5a30b71c5b20c5957c6e25b937450b187028e80833107" - }, - "head": { - "hash": { - "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" - }, - "sequence": 1 - } - }, - { - "value": { - "version": 4, - "id": "f2ca9dc3-8791-4db3-b590-c1723c30292f", - "name": "b", - "spendingKey": "07cb3a95ad4fe711659a9e35412fd0ee823ed9143fa9657a240457142097597a", - "viewKey": "38ea4aad94993846593c6483eb17e99f5231732b1bc67eabdaa23c28c7dec6ce031d854afa303382b742cbab41f240b6ac03b473c4a6973d8c2332c938e7db13", - "incomingViewKey": "eadda34d84590dae853bbaf51d2c2f7e5b4d9e529d2a939d27d1ac32614f9501", - "outgoingViewKey": "4086253445b82ef43620ec4c013f76a684d7f60777b27e308dc9956369a79669", - "publicAddress": "3e2e7615c181f2afaa6423465e3b3a9ddf8d89020891cd5f1fa77627beac0d4f", - "createdAt": { - "hash": { - "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" - }, - "sequence": 1 - }, - "scanningEnabled": true, - "proofAuthorizingKey": "ef3245c0bc7b577ad96755d1401d21318f5c2325a6c9ec635e2860e3b8447c05" - }, - "head": { - "hash": { - "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" - }, - "sequence": 1 - } - }, - { - "header": { - "sequence": 2, - "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", - "noteCommitment": { - "type": "Buffer", - "data": "base64:2YEeOO7CW5anvMnCFj4+fP2zXO5y2uMz7uYPIbEqehE=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:nOkfpH8xRjxR0cYszKBVE+pynTfSn1/Im56lD3tmO+Y=" - }, - "target": "9282972777491357380673661573939192202192629606981189395159182914949423", - "randomness": "0", - "timestamp": 1717538776794, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 4, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAA6gc0ZMKzVuYVGSGcf6ZStXbFhEhQGBdxZ6dp2MGcpBiqXW+1GeVcLuzGE0XCPoATF97RUQS93leoPPXEZuA9QxSmGG5O16C5N+NvCytJUQmUGF+f1CP1GPJYPApvqU7ZeX0gN36tFc0XmFZueRhkfaox6WXfY/nLn9sGeEZX0xEE6sBXYqru2NNST1fc9gpZn6pHTmG/DPAOF2h2eMyiy4qWAF1ZxFdry259sTpg5biUJdDHdfC46rgLggtXOG/HKqfDTgGu4seax9isDhriSqw7Wiy+RolXEN4vlsoHWTI/88nbrvNWwTMmIFNTJlnDPcQX9XbkDGtWmms61IKoBicAa0evNtu8e0lmNjnFR2pyugcjkqVshZiLwxwwL2Q1onxO+SOfIeX2bAO9svJfdisHU+bsUKya1thsnb28l8jWpPB1y2ClwGJoFznubXVfygKkwqNqJwDPnTSXoT51S3K0iCnuz7/7vkAWBc1XoMY66TKSWkrc3Y5eroOZEoxcZYgZ70I4yP6tpxRdk5aNE1269BFvGaIEoX8Wdmilyl2xdcCEDsRGCkduBs/+ndcMOrBHmHCYve6h1dgZQkSA80autapfNFaLKJuXy93FAKIq/afXZhStj0lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw0nYJUIFk2FxsS5XGthmLUBbrOrEJATp70MNA9plgkBYka4DxZbDJkaqvGhhRsWlwePT751lKGeumD6oEDV3gAA==" - } - ] - }, - { - "header": { - "sequence": 3, - "previousBlockHash": "3D2FD56B9C13A353C03760F88498F76DE18F31F1906D694C5BD0350EABC70F49", - "noteCommitment": { - "type": "Buffer", - "data": "base64:2aPW4nN3mBkAjPUddXJioPN1Wzb7Ccl6GwO2JE4ECXI=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:XVIsnhJCqY4oxukCRb4wLhvgU3h/hp//zO8NKcwRxz0=" - }, - "target": "9260366780148527510972123832573278885902566341756516011968728852484845", - "randomness": "0", - "timestamp": 1717538785387, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 6, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdiUEf////8AAAAA06jmlLwr+QR1va25HZIgnlFKNygW0YKgd1/hsswEaL61qnTHDAhtcJ1dgkoHHzSstl5O+27l8B6JDhV6LGmFGtzvxFU5oX/yP8SQ5gpFtoeDx4fkS70VU4jOGpulhIC3dgNsajM+mygbMVL2rGxWODo/kS9UmaXXWjKcVlbartwWNuwgeSfPbK93szYgCsHjsopG2CPWDY7+8S1T/eiI9UiSOhmpVkJ4vz5giU9YP8OIPRbJYNBDyi42s1M4oE9yhBiYmwWB72Te13hbCKXNv9klCubAoOz0hEmpHpRdia3h8t2L2mV/Px5vq+BvRLjvBuDFPxh+tXPMhLLz/Vm+gYsTXHcakQOYQKEhS78DObBm52aWXIu6NchDoqGL59pNKDa4RLzZ3qjqZKD8u98Mf0uLP3PNHppWj6MJGUSQsEYZ81wE0x83Mw7pVBxzNYV6ZcKjSW5WMGlByPpvYMsk2GK0RK4R1/KZg5u9OQ9vsy/z6Yowkn1HLgIuWhtUEzR4N9RO8tgql6xupVhTlJwhQUcvAIwIebBev9vsz6vqAXK0Bg78pDINhPO/XTdyokiKJmqhzwblFBp+ggmCebBF/TSsd9DBnLCzO3/yk+tYpb27bq2MhnYyvUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw1eoG14RNMtO9fK/cPOw1Zb5kANYygfdFNkSauFMZ98we8JoGw9PLNdVzUz3QUO/fGgEazju9WEIxJwYQyVybBg==" - }, - { - "type": "Buffer", - "data": "base64:AQEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/5M1dwAAAAAAAAAASZxlWuOu0Ps2ueBKEUuioZBPdkwkIwYZGlO5Dr5jY+OqdkRfBzzWOTej3VCj8BzOcc1jFTMeqxDJXSCgKn99TLoXpnJ6ZT7p3KMfUhuROKmA4azQ3l/1UYuH0EBA26BTu5/dYFmmveCMTqZqtOEbsqyHWrkzTbtNka1RY7z02SsZKkHCwNtS2H/Ea6kDwPyr8MmxfC+mqAt0vsoimtZc2/UG8eg1syAalj9aSVgVzoWmItbb0YhZCxSD/6osnyEo1CxTcI2UkdJNIRDV0GHmFDqd3J19m8i4Lj9oWS2MuDD5bMZN2zbfTPdrWZ4QRBU9MMQLNh+lIZAeUkp67SvrBtmBHjjuwluWp7zJwhY+Pnz9s1zuctrjM+7mDyGxKnoRBAAAAAohLf87WCUBH3JIzCIUSSf5IaT1QDG7kc5btsFcpNvmSp3h+62jTwLcX3WNCD2bVdry+ihDricLedL9aPhgIrYnwEcdZb5ULlr4w0RoaE/1S/2/mw+TJJ7Mrsk8l+8JBKUkn2RRjYdnAboJDK2HYpnTfK5fM8UMf2bbyZPGHbhHRaamIPAVpE0M0aHcf0EXlY+idaV3imHGj3sDWLmshbJzX0Dom5IL5XikGwSYS9r1gxgcJ/k6r041Ga+N/TcrqQvKj1fBzL7HI9JgV14Qk8V6x3N66L4lPxK49PL7wuPs+8fbmQmRvOuInjStaIEIUZijacDPLrvqP6ASx4M5G2MnQxs5wTsxXkDZT9B7isULVHzPT9gEYR5YDt9bx5E5sM5aUnr0Mjnm+HpxwQZqE9zjjkOKhg8NAUryUjGExwyYS1+py9WO4Zq4V5oN4JNj6z6TNN4EBIcnKUGp5P+LtADR3bN1DccBFFpMiFbVwfSaAiLJKJ3hNd03BpxjUb924lJg7XegbLq65zNuDhkD4x/asRbMPtV0Nr/wjLAAWiN8zAegPsDs7xf9e5KmbQRc2OPmRfs2xrA5/ZmRKMr2JhG46McwRlaz+fU5sQaQX9AQhsSj6cvQ84y7YRcy9pmpOyB6TRsu5NOLCe8pJyjmsJ4Gt8ydQCHMMhQjw2lEUDzvvIXELR6DR4O/HKprTFSMDSq98yTciuTsxKQBklxyze+jDs6H/32aPOP6D19W200fW4Wug1uakVtA7RzOPu8dF57JfYKJI47ARiBwiN8kaBTrF0NVSrHkdwzUF2Dox6qOMRpVCiyDRXgF+OUueqqmr/9QTljtkiC544EkgfyECFb5sRb1/KVHuVHpXqm7pORxAHt/5XPDTq3UkhnlJV/ZP1VEdIahGZIE" - } - ] - } - ], - "Wallet connectBlock should set null account.createdAt for the first on-chain transaction of an account": [ - { - "value": { - "version": 4, - "id": "711ac2d6-ae9a-46f1-aed1-b233a9df1349", - "name": "accountA", - "spendingKey": "4856d9c63d3d032871626027578178e8c6d18ae520ee4663a70817c3d9c63fe6", - "viewKey": "f9b09b02a744aa8dee0af81493ff546adf008e3223150cef6adbe81e055b8010932e92de9c2a1f302b42af7c7b853eba1b0ac9132d99875752cbe57cf894a09d", - "incomingViewKey": "2d03b13b8c18c4e823cb9485667e5449bbf0e7bacb825d8dde531727eb0b2901", - "outgoingViewKey": "d91a8e7dbf4c56531ad3b17a7ab626718642c0718e69352af3ac8b06753677c0", - "publicAddress": "f05152558308b505f6f6354ebf63c7153e6d56d18f960c030fce913f60e13eda", - "createdAt": null, - "scanningEnabled": true, - "proofAuthorizingKey": "52d635f7fcecd1d8aa1f3ddee510c124dc9a0c19ce126b597275f2cddbbd4907" - }, - "head": null - }, - { - "header": { - "sequence": 2, - "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", - "noteCommitment": { - "type": "Buffer", - "data": "base64:gG+uD3IgsfpU1G5I031IQovkI6na2S19jtbdDIAsI2s=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:T6nBRFaAVNv6mZyGQIuwESeC/bmm6v9MjF175LUkMs8=" - }, - "target": "9282972777491357380673661573939192202192629606981189395159182914949423", - "randomness": "0", - "timestamp": 1717538789098, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 4, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAKBHy8tTB8r/FmK6POR7isIbm85v+JlhRIQXKYbshp6GNP5UkxuyHOfYZDcc0PnRypD5PJCdOVYvMfa2L0iAh7SMYv1T9o8JS3fMWwAQQ0WCYvijv/Bg6wnwTc3ochiQ5PIXcgLxQnmU2INXL89WL3FPq/Kr1FUJK681PgzVmIhQXllF/mExjHkZR02WngTqH3BftP60SBCeIYo1rF8ocAo/bf2Jy3H8+WWiJQ6Q1/MaLoqp1HarCOZ5ebPdn3LjGt1ZgZdKSaEMtaiv1l+GuAENWEc4CuDpqrR1LInPOwgSqiaGw/a4tJ90FmSupNPP3Dq7NkgiaV6bUz7HLU0YcVG/malnE1JAXZm3B2NXqhB3NhLJbshkTMNVcxXbswvhStxJCuy7ZKhmj5EfalZ4DCfu47/fBi/EbILCYDUF/TNS8SBq552Eg8p/1Aj42gmDWE4bHOTwsiIZ7iHhB8A0B671g3GFJ3KhSdk2uSfpo5sIkWFa65NiLP3E9jqoI9H+EEQiRAW89/8nXl48tZYQe9fLfMiQaBCti2HVfV5pMUDJmYGH3HcNSMtHQNJxLmAB9LMQ+p2TqZr0V3RzWxRC1dD9bywUfabZaL9BpTnXMrysj4gaGmUnO5klyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwmiAl46IHq/guQhxT4xJWKSPMchzCvBqUBuJ95nRoztO9zm3b8dnXUBnmXP6H1bAEINq6k4blgjbcXdQfC2jmBA==" - } - ] - } - ], - "Wallet connectBlock should not set account.createdAt if the account has no transaction on the block": [ - { - "value": { - "version": 4, - "id": "f31d3fe2-b35f-49a7-8980-798854cf03eb", - "name": "accountA", - "spendingKey": "c279cf6007ca2fe2aa23c1d7051f806a9e0c5604f53c1b08a93d80b53a4e8974", - "viewKey": "7024a8ee339885cd32ebfd6378adc24eb20ab78cde7e87082aeb6591dd594970a8bfb7ba00b08d9d522f5dd9732edb92b93639763dc8ffa344079da16617ad6f", - "incomingViewKey": "2bd65c96b3906e5932db3a42febcba25d61a6953b65f523b53bcab7592578c07", - "outgoingViewKey": "fff51feb2faee0709c0dfcd8f3698408a908fadb9deeb69506cfaad625cdcac1", - "publicAddress": "388b72219f70f6da325062e5ad99e262d8a45137fca94db4de01056c8373f1b4", - "createdAt": null, - "scanningEnabled": true, - "proofAuthorizingKey": "e8977c2a73a734b44c202dd48c69a21f0031759eb4000d0ca2e25a5b85901502" - }, - "head": null - }, - { - "value": { - "version": 4, - "id": "85b515b5-8832-40bf-847b-8e550a097fbb", - "name": "accountB", - "spendingKey": "79725fd3fe93c52c61bfd98ae74097f1e4e483d5d7167ddaac60b9c7a5cd491e", - "viewKey": "dce8194d874c649b1f0abe5984b9ba60db41c6f07d2d39c7659821c5a54747476bca1f562de10898cc97ae1197b021878052f2059f1bd3bbef5106d9ecf6aa3b", - "incomingViewKey": "73bd776aa46e91e95ce5a3b720009ef9cd9e6b163bd19c70d8f5da95e675dd07", - "outgoingViewKey": "b19c83b5eb11068fe711e31942427bba2e641a03159df57e314898859c48426f", - "publicAddress": "c63c58186cc4a3c0fd3e3292fe0da1a6cc35bc463b8895da398674dab92484dc", - "createdAt": null, - "scanningEnabled": true, - "proofAuthorizingKey": "1498ae1f5c5e081d2e41309832439d8d91e2055f56caa501bdf6cbac6fbae904" - }, - "head": null - }, - { - "header": { - "sequence": 2, - "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", - "noteCommitment": { - "type": "Buffer", - "data": "base64:acRHxw+cWP/ibepfjNXZc87XBzgJndGzJC2yprfOHWM=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:wVpWK8p9G1n8FePP7dQyvqf4ypNlp1q9etiV/WQco2Q=" - }, - "target": "9282972777491357380673661573939192202192629606981189395159182914949423", - "randomness": "0", - "timestamp": 1717538791945, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 4, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAXKdkkZWD1dm5lxaxZyEsqyEuQSgM01VH/LLz3GUZ6OuXvFVUStyE3XO1pOdoWE1vVU3ffduV03pQ1RvZ7DdlEoPgykadfjTyjCPE9NzPwROPNpxnG5ZROfmUTQsF03REpqno60QDwD6QSOBYeJQzeDbHGLZUqskHx2o/DhYXQRcJT4+5tOnNmZKHMzjOA0DGjp1z7HeL1hPSGv8Z8RTxH4pwE4Z053WnD13onZHufoyHVXT4zoBh0raTcRDEDoJ2JXoWvBzkCiq3qefIvWkNlHlJ/zxVvrwA/vEOnUWmDkiWSDtK1L64iGgHBaZOTK0pC3eqM6cMyRKriiJ2FVfeNBb8rOTA37uWvGnUBXP5YWrJ7p3NdcGdl7djHxSu3ooQ/07FtJTTY72T140KpBzDwOGplWx3Y9P+9E56YaC4/Kqt9Sne/KX67k12dnWybklD015yAz+3LqsifgagDl+wxJawQJw2us3STYHSHXvkWanRMwehkzknDf57pHHRmr+qgTY+6wMstxpJR31lkfCJunBjC7kCLZn6M8U6lBc1ew9+asJcpDo+RFQMs8/YKbfr0Gmo2LjAGPTF5xWnDdsL0glR0uT8TUUrHA8w4mwSDUAVdnazlEcSkklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAws2uAaFTsGEJtmdqVD++dkjMHns212MietZsizjoFcHJ7znoxEVUB1I64k4kGb8/O6MLCWU5nD2S2tHBCz4cuDg==" - } - ] - } - ], - "Wallet connectBlock should not set account.createdAt if it is not null": [ - { - "value": { - "version": 4, - "id": "dd451e67-cfd3-4ac5-a488-b27beeff4c9c", - "name": "accountA", - "spendingKey": "39811f488f54d6e92d3f7f341cc5b76f574a24197bdaeeee6a05de53ddcce83c", - "viewKey": "e4b08d1947feaa48eb780fea468d7c493aa3a5cfe02d7cbe3119b76aa62dc358273e68609510a534841bd424f7c20e2444104bf04e4fc3706c1259c3725fba4c", - "incomingViewKey": "90a8f8f98471821e9df1412e1d950a2e6a5ac1489e433e79236be37293cfa807", - "outgoingViewKey": "801e2c3ebcf7916e410adceaaa7ed4acf98fa6b8119ffe11f3d11cbf45ae91fc", - "publicAddress": "f58e0e6b8457208f382488f030a45fe5415973c80c6929a2393c06c115f9a94f", - "createdAt": null, - "scanningEnabled": true, - "proofAuthorizingKey": "58652f234e80b7019de218000e350eaf0c711ee5dd4c66d72f1d611ca25ed302" - }, - "head": null - }, - { - "header": { - "sequence": 2, - "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", - "noteCommitment": { - "type": "Buffer", - "data": "base64:elUGwi/sjfDIPJd0ErK88yK0AQSgPV4vYjDWsZFx+DA=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:Ddn3jbvQB5ORKUEEfn8s/xrMGYN7gpmqXNqVmOcwoxc=" - }, - "target": "9282972777491357380673661573939192202192629606981189395159182914949423", - "randomness": "0", - "timestamp": 1717538794458, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 4, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAA1NqHxiJj54BQE17UDEPqVMbiCcMQ0nGmWz9At5DWA9+1xNMsFOEsMnZ54bNvm2I6ppVkewODOurdu7HnwtI5nmWO6REWA3K+feX2bUnyLa2EIBrTpMnt2XOJ98A1u6zVEgnTY32iAZ0dHpC8PGOlLFx9pOR97x6Z7Z6AsATZIxcJeWwgfsvMsNBWqEvoPonu8R3NQWG23Fe2TbCigyn+QqQldKjLuKxWlVhg1NuyFICWDBsx/7K4KKItSyJz7cj3F7TxT/9yW1/eb+wJkY2JjD5pzDeVvRpKvA+uZCAPeUY2Rwz9F0ddrKkwGVImQdy7ZUOb8e74pIwvfrJcPn2Qk/6vMJEJdAXHdrIN0SANx69VBPyTFk85jibeo79uYzdbGcJhFlPYIGvmQ618NJfPKEv2E3bc2c1eAYsjbvl2mtjprKllsNaxwnd8outXYfPFum/neQ+LaSzNQupTWcG0s7pvIULijYPZNE+dr8sWOKQkDJ5TYSS2m4mDgDmP6ZTmwyI2Jf7IT0HWiGWjT5vSy7IXBtGxRb3bEayCHn5PlkLF0f6J1U3flI3fzmNvya1dlD07qJn4SMCSxt1VmoxxH49bO+20XQe1llZS3LLBK8vFRyF31xgzpklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwQqQfM5NUTAIrURgLbUaJ0oIwwnOHaDjnI/hUQRPoKdsjmBO7l9v8F5f1EhXUe9wt3K68vq7WBtRg6ETHKQUtCQ==" - } - ] - }, - { - "header": { - "sequence": 3, - "previousBlockHash": "04D49503415F9C55A0D0757A7E6207923076EC745B05AAC727AB61E1B9C8BD0C", - "noteCommitment": { - "type": "Buffer", - "data": "base64:rrdnmsHXUQh+6XNX9knJnyOOKXHcQi4/3cmG13KpKD0=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:lE+nXnuSQZ8baWE1GYfBUo33F9o54ptpAAejyKhRaXg=" - }, - "target": "9255858786337818395603165512831024101510453493377417362192396248796027", - "randomness": "0", - "timestamp": 1717538795622, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 5, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAAN5H5ABA6oSm2IhIhHvcCR/kFPX9CPyzmK5Af8zgnyuVNtfT/Q0yZUc6YU5+aGFpz1hlZp8oKlKHdnAw5MpYwG25ZYTYT5MoRwczDnPKm0SuAkn/pRbcdQhu3lD36LjvKF22IhZNAVjrZoygkgf0yHYIjoPZc7NFTe4z36tytSoPKfPqkfWmCgV/jRn3C98EDuW/8ZDHtUdfjucRk36aBPxynQ4SIoyQ9pGSE2GNa4WXY7hk4L+nuf1bsCpUzy5Mt/cff29rgW5giGjrxCfltnJl7KCSe1ujCxXyfbCHBsoaSWZSVYMFGiK73oP7ApJ5GqjRNLXkqlqtOPw0VX9xOE1dnAJoWw/K/eKWl4a10xW2LDZ6pOgnRbA/oCocyx49UQyFGW0V4o+9PYA/H08QhtDo6HWMl0sPZsT2T/dT/jSo7kHVLuSgOJm8sEtYxiZrM26/hHsAiiCUHadqvIm5yRzA7+7uKWkfj5+YIRoedOcRPUQieqwlt1ZtyLEmxPN79vX5QrAqDDHmOJrTF+0C2xolH21pS12fDMclRK5qUSW71q54PSUYXSHWQ9y0Q0M2fUTeLZoGOkKNLosh0sen9dE5o7GKkFeNYSmaSRde83LoRV5FJDx/mklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw21ZN8hjtH82tG4OEQAEWDVGcXfmUbmHhAqnYZ72n+RdIFAKR1FzOiiAjuygEWxfSCjvra2TJ9DAApeMOkO5NCA==" - } - ] - } - ], - "Wallet connectBlock should skip decryption for accounts with createdAt later than the block header": [ - { - "value": { - "version": 4, - "id": "b588dd36-a52f-43c8-ab8c-ed43a64b76d7", - "name": "a", - "spendingKey": "9058f54f590f4453d9044d8fd1dda16ef29608ec7c79c71ae754c452b5228b85", - "viewKey": "1dab86894e0b022cd1d2d547bc2c75524013006456bb0a9281c94dd38f866d4035c70a7bc98d4d2de2dd7e3d143e30790a0efdfa148c4bbe01515f441d08149b", - "incomingViewKey": "01ef479369c340c617803aaebe5749807fc5ba8f24a44f2f8efdff2f57e37203", - "outgoingViewKey": "2a16e7d2db5541a55d55bacd69f5a5077d3aca6d64482032a74405042dbe23c4", - "publicAddress": "002e67c1b367a11cfac003e4c6a22352676c6db67ee482a6cf425614a3903be5", - "createdAt": { - "hash": { - "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" - }, - "sequence": 1 - }, - "scanningEnabled": true, - "proofAuthorizingKey": "bce77800905da0e98d479dbd811ac2b941bc7fe0743093aab2d1c2d5548cfc09" - }, - "head": { - "hash": { - "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" - }, - "sequence": 1 - } - }, - { - "header": { - "sequence": 2, - "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", - "noteCommitment": { - "type": "Buffer", - "data": "base64:mNWDk2Q+ISdSRIMDHQ28QKill4FoO2jg1bPIFRNvtHE=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:KRr7EGRKjnQqKLwz7R3+n296Fz9F7B9+nY2OS6Ly6Ew=" - }, - "target": "9282972777491357380673661573939192202192629606981189395159182914949423", - "randomness": "0", - "timestamp": 1717538798786, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 4, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAowQEtMyAsMn+9DffGKM2ND2vf140nq3sLf6Xwdml0qup4saqCdK3HmsxhTlyEab4Ni7dYjth6MPPHyCN7tGxiWdvkdJ3Jnsb9tttqEancsuunx9wZRJbIQMkv5x7FXs54MG6Wiu4B0Dd+/lpw3oCC7VivZ/gLXJW8Yic6S3auxcEXFb0th1QIC320Ii/hGpSiT97UcgV4ypVilS6t/nSinKTYN5ZH8ynHsnFEY+45HikMnmu2OOC/E8TVWLOsI3bZI/fKkm7CWZ3wiMZtMGoXNbV5dywoLzWFah1q7xwusMRLA3k7/UiCk0xjdZJAcNZfa80OPyld5/qVep+tDkrmL92vFg/H7dupkTQbfcOB8Dz3gNOMwFgeuk/kQrG4MhNNuN1Qnrn/3Qi1TeemwBOkDTD0SQ5ZrOUvApZbBSImZ4Bovy4FiLQrJ3xsyQjaPqHOB1r+Ygi5UU2NBnVGU8S+w+BDa6AwKGy97fmNJ3Z+sfF+FczZc5C3s6KHUbNYxjWP5MasyiCokewZJ6diYGl6x5OAxxyD6MleaOfKjpYMyJgSM+HSmuqbGvsbBmVUK2fSIm5o+x6P9460RTd+vhPzQ+vwKrPHSug2gIl1acompD+BdJV7YQel0lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwqFSGvY54V4N9zdzKv4B7rsVbhoZ0Mg9I0bDGgSuHJ2EltUbGq+ZvBmaiwnLwBKAi7uRxNyGzMwV3xPNmXmmQAA==" - } - ] - }, - { - "header": { - "sequence": 3, - "previousBlockHash": "7688B6A5D7E665E658526F7ADAF4FB5BF7CDD2BBD99341DBB6A6849CA3CAAEB1", - "noteCommitment": { - "type": "Buffer", - "data": "base64:46ARjbh7IqMrWxqcO8wX4d9GcBVw/R8/yLVycfMxwh4=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:ypsgJsKXpigzL8WH4wapmG1AzuyUFKLp4qRqjQsKEVk=" - }, - "target": "9255858786337818395603165512831024101510453493377417362192396248796027", - "randomness": "0", - "timestamp": 1717538800950, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 5, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAol+BoW5SFHzxc92P1NR4/Ybi1ogYtXhHsUi7UvxvOLCxVomyK0zQqi0y9mye0uNu84tmRuB2ggmRiwlEQ87m3zVx/shoQ4pWaMOJUx6h38qx2iqDkDMW6L1bflvSpDIfzQi8h1y+/WLFm9n8hQTA114oKJT8G0By3mLWsX9catsUt/FxnHFNKhZNXym8M6fdN7IVadXUi8kBe+C7HsDOZtipfcGM7wu5ropsxs3mswC3GeQEgtdBHqIxFkRiqqhthdZeKJZN4+biXFQ4Mc+qykbNkaXqtVnFuACAQjpse7vN2PWQuKjMxzMgTOuQ8Hg3JrRm2k9+mJidofvHvqZ9YJu9wRu8vZIotnl+HuYEnkSMSKt4ZlrawRHCuu4uz7Bo2H11Pf4xrDX0YmWhLIT6OQyWj40ZRrbuIuJoPB1Kl+eg1zRJHOo7FHoBzxl7G0LYzs9hNBhzbAG26vLjD/Jhfxkfm1ZbhTYzhPY4q4vD6ZRrUrOhoqNSkK4Oub6vo2jnvJl9wJ4UnN3aQkBjkEAAVQcYTDOk6tsEVSXYHvImmay0MXiLKzAf2ThI9NmpOLm6FMhR7R+MtnDRZceWYq4VnGfygFu6PHdzQv5RLpVL09ZUpur1qEJ/5klyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwrZHUl4EkptmplQte1OhdaHPtUfOkDqLxm8ucjAZ0htLU8eGoNDv7LOhtJqurc+u1plSWFvBvu1aQnGWAKQ9WBg==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAU3NULCyyfGTLdHPRcjrQu6xvlLDHRFNKQjpVRtnVe0aFKPWfudzbpib8u+yazaCbxvmBHvvnU3Tf8vEF00ny33Lgs1Y6bIA54mCbacBeT12recZHGrkqG/KW3ddUYwMxWb4J8XEaJcpEjX6ZjHsJUTz6nAtRA2K339Q7GJSQpvYRrzBTxwpfsrmoerV3Amn1BJACOJDGfAqQSqfLcNY8gPDB612FWTDZfq/hBk64WeCKyLL53ZuzHjQlpwRhqpT4Bmj3h4W3RoSFE6dEA+16ns1bdWkdG6nPWWqYYpHRlJziwkq0n4TBICEn+yrxWCJkWhAXjm/EKCndP7v2N8Qr8SH7dmBmcYSGmuEwRmN18CJJjim0xJAh157fy/mSRCJnc/FBr9plEGUmcA72m0XCiDOXtuFmOsWHoIk1siOcWFBA31MMKzsst+IrnOxX245T/co+fWCTOfWCXXQrmxAdB+iAtPmzgmO8SAlA06DJmDmtBeUVHb2vsXIXZDJjsM/jnFwV5c2vD9VeN30jf2WGwdZlOsdZbXj/59kWhruEWdWZ3XthLQqRki0fLoYGwn43HQblYP9RvwipJWmR6a6nj6ryB5DiGJ0NKWZ0lSlMJ4mJ7lw6WGUuHElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwEbvDPp+RDW8PbuCORTKWYb3bJycg1pljPBwWGbYnqt1iumQhbXVkBooC4EvqlNL2gNOd/iaBJ4FStugrQKLkAw==" } ] }, { "value": { "version": 4, - "id": "99316e47-0acb-4513-bdff-26ea481ba956", + "id": "7d4d70b2-6ec7-4167-9151-f1438c7b091f", "name": "b", - "spendingKey": "23cfd3578bd734c519359510a4e314d6aee03779c8a4417027a1724bc2c12a75", - "viewKey": "e0045a5dfdec70240386b79b6c883175cb3e14993d9eb6a375fc4a88769028b9fce06cefd661d9be699283724f8b734313b2bad44e48432dac90fdfe251e05ee", - "incomingViewKey": "d93d88278fb58013b1ba30bfe8a00f4adc907274fe9f91c5a53e61acc4f5e003", - "outgoingViewKey": "4a6df989a0340102fef6a71b03df8cba0e0635bee1963791fb900b8dc705e383", - "publicAddress": "40140a86a5071c4985e1ed66c2b8a0682e9a60ff45cf51e464f8820db66dc701", - "createdAt": { - "hash": { - "type": "Buffer", - "data": "base64:zlABkHbPDQPcYhD7AzaIX5QOulfKN5eNG9QdRHEh3RU=" - }, - "sequence": 3 - }, - "scanningEnabled": true, - "proofAuthorizingKey": "22d94ff922e50cd7fe9ae0c514968f3e52badb3d1e835ab0975d66e80c398801" - }, - "head": { - "hash": { - "type": "Buffer", - "data": "base64:zlABkHbPDQPcYhD7AzaIX5QOulfKN5eNG9QdRHEh3RU=" - }, - "sequence": 3 - } - } - ], - "Wallet connectBlock should skip updating accounts with scanningEnabled set to false": [ - { - "value": { - "version": 4, - "id": "55b5d5c0-c65a-4793-abe3-60db528f677e", - "name": "a", - "spendingKey": "7dc498a9da3700f32cccb798f96367bd43d5d8da827f13142a97da632b47398f", - "viewKey": "47ae04369220115e2936d54e0c900c8779b96b0e287f8de747cb383e9d53f3bc1a688b4c672e5f59d09447d964c2d659a87b9db6b3648f8728a68b8f52fc85ea", - "incomingViewKey": "3f80e3b0bf87fc10a7823f349b97858efc9c9ad62c3d5e3afe76f2eced7de002", - "outgoingViewKey": "4da65b8bd524c0f9e5b6e98998ab575d8cb912202f42e9ea73e1f4c1e2ff955b", - "publicAddress": "17eec804ae83239ae38c8849008c0864f2b4bf1ff70b341e71e7a2b126d079b8", + "spendingKey": "dfeb5befd86eeec4a28484a98ae0945bef3d08d66820f23d641248d455dd8a6c", + "viewKey": "ea99d3ba32e2afdf7868ec05b672a611c7027fa1a0c2eaf0e46cc8eca047f14b8ed9d2b0980196608ff44f698b8b4f01f626a79bf764fc64d705d8d0293dd236", + "incomingViewKey": "3b7294d5f761708107d3de2fe1988055dd54c68e4718af20d7fe1acfd7532702", + "outgoingViewKey": "a9186f68b889911d78461e9b5576aae0b2d97547ba4fe809b36b53a53651ad70", + "publicAddress": "bccc050a0c7444743fb01d59230dde81003021d6cea4d8b239afe021102463e7", "createdAt": { "hash": { "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + "data": "base64:mZq6o8uyv4LYoSbNLuuK+fF4tYM65yBRkmI4JuPAnok=" }, - "sequence": 1 + "sequence": 2 }, "scanningEnabled": true, - "proofAuthorizingKey": "b0020a642ac5a40462d3d4cec61e1f2701d63385ec3980df5916e3fffee4940b" + "proofAuthorizingKey": "43394e75285fa9d2c1785fe2758c26820966f0e0d38803ce0b21d8cb406efd08" }, "head": { "hash": { "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + "data": "base64:mZq6o8uyv4LYoSbNLuuK+fF4tYM65yBRkmI4JuPAnok=" }, - "sequence": 1 + "sequence": 2 } - }, + } + ], + "Wallet resetAccount should optionally set scanningEnabled to true": [ { "value": { "version": 4, - "id": "68cbe0b7-4853-4798-b33e-718da60abcf4", - "name": "b", - "spendingKey": "c4f0d8703fb0adcba6556381d5ddbc90bcea828a07283f60829977296c141a93", - "viewKey": "707f8bc5c6e5982169e70c0f2c34c23f16d5b7d3423cfffc75d17b95850587b63d25ad7939e2ba0847207472de32edb348560aa86aeac2147be1474c7e51ba6d", - "incomingViewKey": "93050c8e56f3b603eb59f5f3185bfec01549efe873acfa463009954e3ad8aa04", - "outgoingViewKey": "8436e444dc23a2d8d5712f536a14ac56f0cc27e7aa691602d8c2e5fcf4ef4ff4", - "publicAddress": "a085e2b5c5beed24baf419e0d5d48d1c28acc6ff4aa941e6d75f509450fb888f", + "id": "c71a1138-638e-44fe-8058-6f61c4837c63", + "name": "a", + "spendingKey": "ecce415425e647d632f625effdb1717428b14a35a8c29bf1d8961b028be538a4", + "viewKey": "f9af8ad35f04c95bdd6b84694755bd5dc5cd92345f8262a33558632f491e145970f01a3d9e095287f2f3bc8f1a020799007eb914e439842918857737d89d8a6f", + "incomingViewKey": "368140c29ca137998fedb7e6e51f20411db9dd56a796764d9e361590ed23de07", + "outgoingViewKey": "acd19c3801777aa4fd97cf7819d08d3bece3d14b83245fe29b24acec1bb4fe96", + "publicAddress": "81ac0d338d2048bac791a3cfb92818638d183465c3fc20d24dccd73e0e442d8d", "createdAt": { "hash": { "type": "Buffer", @@ -5818,7 +4642,7 @@ "sequence": 1 }, "scanningEnabled": true, - "proofAuthorizingKey": "252642d09a7431a7e0dd31bbd9324588f794a7ed55154a9a8a563d2e34be8407" + "proofAuthorizingKey": "eebe1953bc0241b2e20885684b0c533e110ee701b2efd97afea2ef00c999360e" }, "head": { "hash": { @@ -5827,71 +4651,19 @@ }, "sequence": 1 } - }, - { - "header": { - "sequence": 2, - "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", - "noteCommitment": { - "type": "Buffer", - "data": "base64:T26lr8PMOBcM5kYMOUt5cU1rtNnix147uTQVXz6+ExE=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:3mxMJXiCGdQwkhDJU9bwv2i6KA/ssRtV+Ly+NzXBGbo=" - }, - "target": "9282972777491357380673661573939192202192629606981189395159182914949423", - "randomness": "0", - "timestamp": 1717538804397, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 4, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAADnV1BhIJXegnwrktCtTYJf+B0PuPJseZ0kiIlvjWjiq5nTnsx3G7M4yBsFjRG8j5vNRq6xkQAuVUnKOIEV6EQNmfzgN1FXk6vCf3spJHiFOmXmWbwJJ78y/JgQ9XjrIty+gjb7gBqWqssrRUIv2tvgniiWDA8O5BYHrGAvuJ0ZMVD3hlYSu6t42UDBcy/gwbu1bBU8bv9nm+2UpxkozCFB4ePUoRwFeHpeGuGzsdKQuAJXj9gdoHAXJHId8q/883O4vd6oBfxsMWQdZx2nLW4QUtTUqbLr1tCZxqDK5ExVLAaB9pAvD+9QJcmE6b4mSD2x4QW2XSFxCLtDdGAlyDZkdU3RADN18ibp2y7B5+r5ZaV4EDGBCV/llNPgvpPb1rRTtR2kVZf11WWAnH+s4O41GPDNn+jKDk0mxSmShc1JHpgmAF70WBHoUdVshH6c2iGk9IaLG56bnq1LQKofHOKYfWNnVSwVqzBga+viUzFLXx1f2ViMJmudYDCH69W0veHCZSX08JiKbefZsPAfTc9HDP2dSY21WfFV2fRJU/fLRzD9lkGUei6kElqEiwW1oUHPlwIqhY8IcIEhI8dajAoeFEmGIzIfrWoTTeEqxdNN3533sYhCRieUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwA6QUF5JVn8fPQYfsu5ypg3+9oorQF3XZi8Rbe1ULH8kWP/WV76w108cpEF4n6KGuWv8iyHlAtOo26MQMk9p9Aw==" - } - ] - }, - { - "header": { - "sequence": 3, - "previousBlockHash": "FAFF4201484462C6EBA2A87EEDFEF3EAD15674945B9BB92F6821A6A8D82433C7", - "noteCommitment": { - "type": "Buffer", - "data": "base64:XZqMUKJKccQbWWfMk/OvUyo/srN6DS9FmWUVb5KxazA=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:RB+cuH59qMEU3YUPTGgRWNMOds4BdrEw6Y1D9Byuc+A=" - }, - "target": "9255858786337818395603165512831024101510453493377417362192396248796027", - "randomness": "0", - "timestamp": 1717538806590, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 5, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAARc3xGXqhfWxUC895dmLdMkdi7JOTAosTuTkwHgxfQ9WU1jtHmkxEswUmgx1nKxGiMvl3vkuUFBhpL3lRriNDylUsNyoXbNCdDEPsbIgQacez0wkI7ZlE2ii6kjwU66xgpYCawon59mpaHkSDght/i1vdTn1hqgZiptFPXztNdHwMG/EMEmvOzGlQ4uEDFMLVy5ah+6o4Ts0OkEuOoEJY9nQT4TqgX0ExaM4IytIU0g2E2JzQTBMx6sLbMUIJX7bpoqbf40YqXGTXgEmb2zQw5B37loviIbV36360CD7Ld8QeJavNc6Knlf82MzoivMAhjLcF6gGkpyaKwjM0/oUmxR4Or5SRFOcOmiPJq4TLdQu74xh4LwuvtkhW5O/PArthSFwrrCqZ/uR48bewoQ5e3k/hzwiisubBWMKxzcITzJbG2D9IOelK8jupaQ0curYUpWxwIeyeqDk0fE9K5ZkhJ/BrqrcWBfCs6g9hKmG1fb3TpUvl46hD7cp1rLt/lbOMS+uS5TfwivGbzRHkMHqB+XhSlsHKSXqEEIEtc3avxSpI+Vcu8XEv2JXRAGD81MLzhM4uNn+6DFnbfA+D9Fef1cXB+bpOv1SHTKHG2ZOSlGwngXCuYwQkBklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwjbNX4ht0TYLHYdEzOT6GmqBDanqfUBNoG4EQb1G7rzPoDl/pK9lyqSjAjVbi1y8NSD9dGSWj37vO7P9FB5x0Cg==" - } - ] } ], - "Wallet getAssetStatus should return the correct status for assets": [ + "Wallet getTransactionType should return miner type for minersFee transactions": [ { "value": { "version": 4, - "id": "9ce72f1e-3ece-49cb-b65d-74f015d8868f", - "name": "test", - "spendingKey": "7d1b498c8d3cc4f73e73e6fd478a9365b0d8531ff6164c02ea4a082fc4f62153", - "viewKey": "ec221089ff616478f18ac4407a18ddcb1df20258cd9a573c50e16a16b5e1e4ec78d86afb3a27ad9cc1e928c20f0ad5dd983a1ab1043962a4679cc95f0821102b", - "incomingViewKey": "a133eac24bf5a25cc97053c90946ce9463c4504cc0cd1ec5197c2e0ffab3da01", - "outgoingViewKey": "85720d0846bd0c593b496c79637b57e4b6a0f2ec525d157424918d23724d4bfa", - "publicAddress": "bfcc2c07f689708132f5bc4e04d9457770885b1835152dc8d5a78a11ebe32eae", + "id": "c56fbe5c-2319-43c6-9c74-6957bd458e80", + "name": "a", + "spendingKey": "e64dd4e579c36542e7bb22de61769f11119a7449f2a28a48ce1461d8cfe4ea29", + "viewKey": "c9f799ff86541fec1f0d242c4f48056292ee077d739b5ac24a5a2d9636bc7d0f05522b614e5300c3bfcdb64f81d19390ece894886a632128503c66b644d4c452", + "incomingViewKey": "514c3812e86bf59e651f35cdf5797b41d1c3dafa1d9f3a6005781b18ac9ecb06", + "outgoingViewKey": "702f217dc84ba67dfa4bc09a3c8f6491514c9b5b1b05891ec4b9bc762ff9d4db", + "publicAddress": "60f29d4d089cbefe816d8892bc7a9e39b14541f4e8ab805819b3381ea3cd3d01", "createdAt": { "hash": { "type": "Buffer", @@ -5900,7 +4672,7 @@ "sequence": 1 }, "scanningEnabled": true, - "proofAuthorizingKey": "9da0cf11902fe7853a0efd7737c8d409f3f06ad031eceb3f0bf2d1759431b904" + "proofAuthorizingKey": "03aec8ded54e30e5422791974a8fc3ff5f0b9ec7ae7ff71b599962a024983508" }, "head": { "hash": { @@ -5916,15 +4688,15 @@ "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", "noteCommitment": { "type": "Buffer", - "data": "base64:ljyAKZkpGtZzzVxsP+MLmB+LBKtd2d46th2i6C1y6yY=" + "data": "base64:D+WvBzZCzglfbki2aW7CExBQTYwhthCDqqGeTJNA3AE=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:nCDFbONWvWb7DMJ9Kn+enFcxmO9FXei5rvmcHC+1lzw=" + "data": "base64:tZDwrof0mSVCzaFO/8KbpJjC4UzZlApxhdkikVYRcMc=" }, "target": "9282972777491357380673661573939192202192629606981189395159182914949423", "randomness": "0", - "timestamp": 1717538810002, + "timestamp": 1717538940787, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", "noteSize": 4, "work": "0" @@ -5932,56 +4704,22 @@ "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAIO6f0wCjg44SxkFkq204mtRvRYfkZb9oiVMSqrTUa0KhJFzHrNkZmy6ZttvdzFoXhEgdjLVRTc8x2ye7DRcF9JtLSl8KlA1XxayVNFtFLsaM1u3yZVcSN1YtLI0+woB0Zdvkj6CIPVXruZOiMYn/egap0Z0br5EcRbCTVGTeST8BO+8r1mzD8DzMqoAQbYG4xHwg5NcO/a3svvTNELC4pj9KF55LHOhTUccRfsiVPZ2P1OLx4A40LjNN8B36r9XzkPDeqs2QpWDMmCDFvKRmwA8pR77wylHzBbCNDxhwdyYlRVmmGR2yOP5Z2sO8/phrXIgasxp6z5ebCAFA4OEVubwnQ28zb3D/kWSPgSIvNvo04NoguTK5np9cySOTDTBNv06RwKYNE9jq1834s9i9pUZgEv0HmyfZnsZYJm9VyTk2qrsWE+wRTMT0s0ckWpqFJ/RGhj5EufQ08Od/6YHXILVD7XUpX9SG3Pi4p/CgDWX+22wIXR20pcUunVZCcd5C0rH4q613VtFU1L3o5qs7sQLNmH+x/15mnrdpAmpB/j4OhyH/VpQsT4skZ7BRJEQXPAAvHaB/zphGSD93D20Wf92yRKd95QYWtaf1Z/y+R6AH0cUHmXm8KElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwfB0rqqpXN4dcLtAKd1ebu62PbRC8xb3GlGApQjCmqQalIKDnOOrbq+bktmrbJUYbpdiwnU2VI+h0SrlS72OMBg==" - } - ] - }, - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAx1XG8nmZYHQ1lZDF28yrjNdwPtLmJXorkmHX9wpd2smEGUFH1c+R1x90Cx1/C++ZDaG0LZOzFoURhJxAgkQWtLaKuHgy4X/THyeEIRF2de+rikJf3pai7Sl1Rk5keZmyEGdca9g1R4j11EvorfIueXMu5tUkSxjXGQih7xj00BAEzGD//L2AFiegE3c7DNOXrcmry9GugoJLx0NtqS+rSFuQSJWJkifCzus9NzVT5DWDpPIC1IiQe5v6JhhNCAD3bawctCBU4KkpKbzeJTChU9EJ8Aexj6eRDpAlecHOsVGGCsJ0dz1bBRkJiQ9UnGQ2IaU1CRRecDT3y2tEEZh3DniqfyVpGJdU6HL5I793Vf4K9pDxdBYAzyBR5hkQ2qMrPC7D7dcJHAmBEEGkBPlB25ztk1sUmFJNHlIq/E3LJm3E61ASn2x8lz7VW0X+J1CrzBetBuTa8P1WyM34ygGinGtIbuixAvKTuBPD3D1WYHUL8AmCSLBd2MQVXQ4QXhkytGrV71vL0Y9TIQUUmsynj1zfwRDdhGwl0JEAQKEaydEm/MGpIgKMunwX17UIT1DcRHZs8QDL7V5ddIHkl+pamlvYOqTG/Uv2yY4gt7+/5P9cKsBew8hqBMnYroNLOiCPvcwZKFcQl7wbyc1xBSswaeLuNGt5TtT27T+9Dr/HzejTvH8KfCGfBD68uJnPQsK86SBZQilhh6ix2IGJIsMAh06kCZq+XQoBoFkdkqFZd+4RcgcjGpbRMA+YBC7PguW7foeHd0jEiouRNB9IcfndU8o3VUtdabdKkYsF5F0XvJ+V1+586fBd1gJ8P7HZaCfXlVbvyTh8vjC17V8G0LSxSdvnpKr7iOgvD4l2mFXwK2CnEwLRVNAVR0j2WiUUknP0PDm6N9u2sf3xctF4ldJ/EsaKRN6kDSpgooqKnc/d6JHoWKN5KJj/MI5L6FnZzO9BS9sesUewkJiNSpAYd3hvVuz4C2buMGj0v8wsB/aJcIEy9bxOBNlFd3CIWxg1FS3I1aeKEevjLq5hc3NldAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG1ldGFkYXRhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEKAAAAAAAAAHegEyym/Ucg/MHeuws1hyy+jM+zhif831l7UTldqpaTNPaIs2r0vnhH5D+wIM5HCifg0OlnTjV7G2mcuziyfgc9gwv2Dr2csHNTeZsubKTYJwSSmUTRfzwujsxrJaaUv1RZoQ1ta5XLLCMBXq33YxSofd7+rr6rAi8TArKGCNUK" - }, - { - "header": { - "sequence": 3, - "previousBlockHash": "2000D5E8FFDBCD7F4A0B1ACCAC17F750C344FE3B9B927E088269693C14B28C0A", - "noteCommitment": { - "type": "Buffer", - "data": "base64:8S62RRIAfpSANrCm3IxZu3YlcBtQJrQcAQJu1v5QdRs=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:+NGczX+1gjYFWQjmPo959KmEs7QAsV8p9sdVuJc1bOk=" - }, - "target": "9255858786337818395603165512831024101510453493377417362192396248796027", - "randomness": "0", - "timestamp": 1717538813921, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 6, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAyRShcULppVi9LURNIeUTgqVKs5/2NBIGXDchmWTbDOGN3WiWZ3tk4yaP9BckHcup4FbSxtyVPNJa0jiHdFppxUAxRBk687ttGhAWVqkY3ZCZRbXybGPSW9EfrRL35y227I4qnga9M9DK/9m8mFkJ78f3B90P+ILAB/HZwfysPJEJFIEiX1O5pAAtcSE41CQj4NUzKyn0ReNwqSC/+sp2jXjdCMmcrFlNR68q+ppFbQiLS/7EEet+3SZO6OYLF1N5xzucRYwtFSWtCIQb0HlKSj8ObuJMX3B4oaiXlKaEXX3VRnyRdQRJwcWiGaPrbZJLjzUVt3fEE0Jq6AnJNjAjrp6/PW27kDsgDAyZD1Qh+xEFNhPf7pUmTb1Kgk1dD2YTfFx6dwb5NwGaBTIsQIKano473Y9q1fFWMLBBKSD4JtfuPRo+aN77/LyMuBkScG/Rs9eT//pEhf/xnPW1D+G45XG4CF7q6TjhZOkWJ7/IlXnnIskhl3f2eS47zvfRNZHrGW6ZVEuXDF+0hlbopNX/SFhZIU7n7UyViwQYnU/t9WLaDm2G8P4kDn/7ugpH6o9geblFd3P+YEkx1mZd44c99XsXpjyDL85QiOia0B0CylYQc4T5kNM3wUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwSFe9YgIoJjUXjpiKrnrwtdncEAuFWPoaUez72Nto6unZYHBkzsMqSP4/g4Coe29M2MlNEBASUzWnYD18meGKBA==" - }, - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAx1XG8nmZYHQ1lZDF28yrjNdwPtLmJXorkmHX9wpd2smEGUFH1c+R1x90Cx1/C++ZDaG0LZOzFoURhJxAgkQWtLaKuHgy4X/THyeEIRF2de+rikJf3pai7Sl1Rk5keZmyEGdca9g1R4j11EvorfIueXMu5tUkSxjXGQih7xj00BAEzGD//L2AFiegE3c7DNOXrcmry9GugoJLx0NtqS+rSFuQSJWJkifCzus9NzVT5DWDpPIC1IiQe5v6JhhNCAD3bawctCBU4KkpKbzeJTChU9EJ8Aexj6eRDpAlecHOsVGGCsJ0dz1bBRkJiQ9UnGQ2IaU1CRRecDT3y2tEEZh3DniqfyVpGJdU6HL5I793Vf4K9pDxdBYAzyBR5hkQ2qMrPC7D7dcJHAmBEEGkBPlB25ztk1sUmFJNHlIq/E3LJm3E61ASn2x8lz7VW0X+J1CrzBetBuTa8P1WyM34ygGinGtIbuixAvKTuBPD3D1WYHUL8AmCSLBd2MQVXQ4QXhkytGrV71vL0Y9TIQUUmsynj1zfwRDdhGwl0JEAQKEaydEm/MGpIgKMunwX17UIT1DcRHZs8QDL7V5ddIHkl+pamlvYOqTG/Uv2yY4gt7+/5P9cKsBew8hqBMnYroNLOiCPvcwZKFcQl7wbyc1xBSswaeLuNGt5TtT27T+9Dr/HzejTvH8KfCGfBD68uJnPQsK86SBZQilhh6ix2IGJIsMAh06kCZq+XQoBoFkdkqFZd+4RcgcjGpbRMA+YBC7PguW7foeHd0jEiouRNB9IcfndU8o3VUtdabdKkYsF5F0XvJ+V1+586fBd1gJ8P7HZaCfXlVbvyTh8vjC17V8G0LSxSdvnpKr7iOgvD4l2mFXwK2CnEwLRVNAVR0j2WiUUknP0PDm6N9u2sf3xctF4ldJ/EsaKRN6kDSpgooqKnc/d6JHoWKN5KJj/MI5L6FnZzO9BS9sesUewkJiNSpAYd3hvVuz4C2buMGj0v8wsB/aJcIEy9bxOBNlFd3CIWxg1FS3I1aeKEevjLq5hc3NldAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG1ldGFkYXRhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEKAAAAAAAAAHegEyym/Ucg/MHeuws1hyy+jM+zhif831l7UTldqpaTNPaIs2r0vnhH5D+wIM5HCifg0OlnTjV7G2mcuziyfgc9gwv2Dr2csHNTeZsubKTYJwSSmUTRfzwujsxrJaaUv1RZoQ1ta5XLLCMBXq33YxSofd7+rr6rAi8TArKGCNUK" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAlzbVRjPC61/JquWjwWyxyuF8Aaxg9sW3d6vGFmVfHF2tIu4Fml71ATpmI0i6X92Fx9irMPI2CIh+UFgO2PmR6wsYv2gWaT6XQURcSGiO+NmB0zXFRDq4boO5uuSRfRwitcRjKhO+b3uqlLLOWzz61l1qjHH/Qpj+vio90vrOQgcCwMjDNE1P8fOhIQmPOhf46oixUERd/zPqEECvaVpml+4R2lYCwJJoYKvqqP1FL5+1ufTRdMr6YQ3g3KuJJSQBCepqWzFiTInca95LI5LUVfYsnkj7o5pQjG9FmeSDWCtTC2S2qInyEMFZDCGmbINwUoeROqz36qIvLPkdwnEs66gFaV6Ki85sVtxBNS53Z2gJN5SVLKqsoBhaEdY8EpkwjbgQmEs+lRsAIr2H/BnTpAr+JGTEQKTpyS9UK8jIOV2SHDAr54ogOLdQU/t6e8rFmvaMupO/zMktpLWXU5Wx/B9JFvKUTY/M3nmdhDmoFvzI1QGZklfTPzhvOqLVZmmZyOEZc8yL6ciwWG6g98V5Bw2l4dJvsziVSZskXhqLdHmmv9zqH0ER0I4PDYA2kOvbgRAZeoddLkWBGNbJgSWhOM8AqkaxanwG3NaCCkFLx2Y9pwjSz0YUiklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw+4Y2WOP5osklh8+xp33c4C6rsgG4d5R+Qkd4DAI/eICJfe4OsYSH7BQSSMt9KcOdZcT1/zgYQNkooCuo8LewAg==" } ] } ], - "Wallet disconnectBlock should update transactions in the walletDb with blockHash and sequence null": [ + "Wallet getTransactionType should return send type for outgoing transactions": [ { "value": { "version": 4, - "id": "4d36c81b-117a-422b-ac3b-a9313d02b5f3", + "id": "64e75cf9-efd5-44ee-90ae-35c791638917", "name": "a", - "spendingKey": "6a6e0c3cc54799d623f7d9727eaad86529db7c76b1b676d1a2059ce3dfe4b793", - "viewKey": "d7476ab6c2b44fc2a86f9f2e3229465a156e8ec0545eab7351b585b1e26b7568c5f5793362cff416f7c9ae66a5d96fdd44562e634fa150c96e177c45163fa04e", - "incomingViewKey": "559be50c376636b333867940c56e5adf3bf14102891c12e2df915bde0148ed03", - "outgoingViewKey": "fda80687cb6b89197a2f474bc395557aaa78e8ee775375a65fb46fb9c8d4db8a", - "publicAddress": "77f8f0f146065f36329224ae5b3e3f12cab487ca04d4f589754f97872dd08e2e", + "spendingKey": "846f74914a7f7fe27a35df50c4459a65af4b8d1317638b5c7d08ecff5a894e07", + "viewKey": "df507062f8bb6759ff5626cec5a59ac49a173906e94bef23ca185bdfaf3a691e918383a46293981fb85b4971a798c56cad7315f35b2aa11bef4116f449aca84b", + "incomingViewKey": "15b6ef66795b5a640221a5fe863b69542ca92aaade03e33d4c828b1aee050205", + "outgoingViewKey": "ee464e9cc173682b92fe04a12db52e03e8951d02d58049776c774c450cebec77", + "publicAddress": "fc1b87236e98d329028c59dcb55139dece067d9a8092fc02f92bb83d5afd6cbf", "createdAt": { "hash": { "type": "Buffer", @@ -5990,7 +4728,7 @@ "sequence": 1 }, "scanningEnabled": true, - "proofAuthorizingKey": "c12d8e4220df0aed7a6089a41f1b3f95198e22fb300fa9a81737065a9e235403" + "proofAuthorizingKey": "dd2c457f45e3131857b78dbf882f21d5f825f81362f7211860f565ce9ada9d05" }, "head": { "hash": { @@ -6003,13 +4741,13 @@ { "value": { "version": 4, - "id": "2922b6cf-3662-4059-bf2e-0176957f82fa", + "id": "a4e9c220-3d1c-4e4c-9d24-4424ee2d47bd", "name": "b", - "spendingKey": "03ef7aa84b14d78820cdfae07c7e46a5974b9b42f98d3ac1dd56d9cc77b625b3", - "viewKey": "5783005de68cf30674842c1348c4a770552bcd7f4ccdc95f90d45a35e9e9f61cdc5e03670f8ad85e438a9634b17ceacd8dbf8ba1bb062d6a2df943a556137114", - "incomingViewKey": "d4779702213d80c09cf32fcf339675fd42f7df41c5881aee93fb05a858c0db01", - "outgoingViewKey": "aab99e3522c644aa7a35fd99242b012530f7c92e5f7d09883345a3617711f332", - "publicAddress": "9b88b5a458a7f981f54b9ffdda6532677519dd0c71f71559207e4df60b5f2e6e", + "spendingKey": "9a915605737f1a94b9cc8db0d7fb3d7b4e6cd0c3ec25a2b92971d5d32677121a", + "viewKey": "944293a643ac12d0fd3f9528dab304777b10702243562f8532b890b4acd0a41fedb2e3045bf3385e577dc051807e559cb8ef243292101e473c07d0980edc6d72", + "incomingViewKey": "13de79e7e2ef97fea168a875f3f78d0b4e40bc17757c46d673475b992b6dce01", + "outgoingViewKey": "539ea34dcb6523714f018c29b17dc0450fe1735f0acc7980e74038a1ac7f88b7", + "publicAddress": "5ec695f11f12ae8e29f508edfef57acf4a2f1ec4a157c803c9d6365ce119143b", "createdAt": { "hash": { "type": "Buffer", @@ -6018,7 +4756,7 @@ "sequence": 1 }, "scanningEnabled": true, - "proofAuthorizingKey": "4b7a55b3ca8d174f7858f62bd1704173147c2506e7e0110a43972abfb712bf0b" + "proofAuthorizingKey": "640914444bada025c574a7553cbad78e573d6ec2fae65c1df5321db909d1e609" }, "head": { "hash": { @@ -6034,15 +4772,15 @@ "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", "noteCommitment": { "type": "Buffer", - "data": "base64:2ywBgNNP8H0qbOMxslC54Alzx1npm8LN9PZkbmzxVms=" + "data": "base64:kD/0V2KfYuAAuyhjJ1rEUdjuFosJ5ZOXBGS6fa+MCms=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:iqNdPEjFbXj/df67x61DdErXQIUhWxLcDcpAzEaQXJY=" + "data": "base64:qn/FQnlKaVfstPrKsqMgT74EPCnldIDowffOxo8imuU=" }, "target": "9282972777491357380673661573939192202192629606981189395159182914949423", "randomness": "0", - "timestamp": 1717538817506, + "timestamp": 1717538943989, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", "noteSize": 4, "work": "0" @@ -6050,25 +4788,25 @@ "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAn+SgA5elA2Yw2XHJkGWcINS3NN3LYbM5gv208m6zZpWJndQl6wyYJK9WMOnOT8jdtkrmmbtcKLt9y3wwNeuh76dKefWQTYno9U7jBcwQa8WIBCD/P10fJo7pEEqoZLiutXHm6zKqDraXAZtmSpKFie0zzkQGy6eZMY5DEoJKTlUZT3HB9lhJ+Zl4nUdvAo+0tUJpE8j/+R5cZ/5AEzTgJcCgzbopLy2eNU1jkgUeO+6A3J60mFjtEcdaZ6P+HhvddNQGbnkICUhVGUB6J+bC4nMFrV4UIBYPcwSa9oS9appixHG/NgELn6EiVnwcmmq9PHr7JL2tdiLpM6/sdbyQnFeEeRQ8Gh6LaF1Wkck68SVzcpWQUBhAQZUs0PXXErxVVCQwjjNwk5mP1wBg3rqIYvHTG2HB6Ta1fugrloURYxAwFz683WK3CZCoJNbiFWQFPxoGkaTCA7qxrpiSc9s/f77t+lrrW5R5oJhMnvbjH4O56qM7uE9+7k1ZJSEV0qxZLU/BETrU/O2gBUdqSxLty60HLCIc5LnqtJSvUuGTMSGZXCTWigdHtH9SkqDU6g1l+wocnc3YYfN0DAWXDwjBD3ULmszz+n6bfFzxUB+us+A7WQ+VwD/6qklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwuN4KaJjKLCHOFw/cn2rhAF9bJCqHXgLuedmrK0xz401fRpsaz1WjPx7g7CWPUX5XgOSGU1ShMd2B4o3cdj7MBw==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAARrRd4fMOdXv6ERlKatGHMjzlPZZxMB2JQS/Er5qjq8GorCef/Bk0Dc5HW7+t5L4U8e/YW7+hV43jtiD/wqQIa590jbWOqPPvYzrWGKZXBguXnxyq0EqhayGREmDIApDdFNxWm/Pn/RvXiIbQ71FLAo+y2Zphnk7RYanKTOM/ohcTx1bgVF9L54fk72WX+1LvY2JT1jr59Pd0PjyveSrpjICvv7bw4WVKbEgrrOCBrc+rt93jsA8lJ5a3L8R2ykHOfWw/hfGcn6wycv/oNT9oFggWBhntgE4CpLpREmVuP0DSlzUa8Vv54f/thmfBT+ZcX1BLbwZNvFdqdlm9meldKt4JIrXWxYwowFrwYdJV5icZza1/39PU8OXLvY48ItE9Q6xuYmIUGQiJ677uTcIELMgB0cYKPN3BsCz3k9/kwumdBHlQPXfnIFQkjCrXnKTxXiEcL52qAjgJaniiCBlC9idGL9bijOYSPweGUa++/R3mYZbtibA6IsZxqatBw4NAwruXDsS1iEoMrwq3lA0uIyovbo3x8LPVflanA2F8SQpjxnpl+PNm3z3qwAtmNH8EfY0S9EN81cvPI5tucJglsOcuf2W6OLxSu+8eKZW2uvCHb2pkSFIlMElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwQwjNX1alENo2d91FWMLxrni6nUGPSHwxCzMmSvVpHSVN2PVwQEkrHpL1m9y7WwWDaALzaxqHs7+TkIYf0IeHCg==" } ] }, { "header": { "sequence": 3, - "previousBlockHash": "87F7E2DA3BDD6138E780C429171F7D03D4866EA7CA666787C71F372D73C0779F", + "previousBlockHash": "40B02466CAF9ED8415965338E5CE0EAD1E7D27C275E6CAD55BD573A04B1B9034", "noteCommitment": { "type": "Buffer", - "data": "base64:4fux5iPMDcHRKhXYTfbyUtiI+Ny9akWMFl14jDuDJ2o=" + "data": "base64:wxUR8U5uQ5+diof3bZLH1O8Q7n5E+T69JYjYZ7aaczA=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:7Kmz5HPGmfr0IqxHToKMovYX7ViGL9wgOdwrE03CEbw=" + "data": "base64:uiQHkSFVPaWVvtcrOnglAc8idhVSfYoagSvqphapeC8=" }, "target": "9255858786337818395603165512831024101510453493377417362192396248796027", "randomness": "0", - "timestamp": 1717538819526, + "timestamp": 1717538945379, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", "noteSize": 5, "work": "0" @@ -6076,25 +4814,25 @@ "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAUc3/rmPJEkcUH6FoJ67mpmB+ho6FGEvAVVJuPdX0x1qkQmJAa4Maxdw5tgOEL1JyGpz0x156c3JBkgAC5/enoJ6/kl23433GDl3pmmuxpIGCKW2ve2/rb6DLdbxwPiV6+gFaYCX8W3DmAxYAhpIkbMCamT+StVD0Zm8WGg0n2N0Fn0OS3HTPa6gsae35IGo97X1RcegTeH5BRa4bQ5r/gdoiJAbL6JzFJ5UJVLEv4jGIMiMEayJZ1uuy8mBagJR7DofUrMu0j2lj3nnAt8T23dlXCJmHItNJPvgTVfInfri2FYE8xJjmf0VRKWBF6KdZ/QiLBwmS0zVMQCd+koNel4UsK3UCK1pFIPudJi/QXCEB7jW17mI6PRcpSlx/E3oR12JxX5idF3xLs1y6eVwQ+caSWrN95nVGZ6DCroidBu3fLNX74bWqD0o0Xb+v9/F1CFJTmBhXERInb4qB67xbupkrtzlEOqjuqN3bGHgq4AHRYO5R67Uj7Hq7YRcHZVOr7C80OS3q4FBwoyeDusfU0ZhYi6TjGLcOz93hmqV0OsrerKsK82vz/z+rExXKiAA6TAboPUd6BYv3xhATyAVXAxhhusOyE3LnKqNE8yF26hOwzw1XTnW9l0lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw9V6ltxaB0huwsyo12VcVbxswvvdoj7gsEmAmlvOLTZWto3nLzV2Vd0ufrnwaYf65hVAAZqcidYDOQS0naptpBg==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAo8hSIw/8R+iPBJtDF4t23PlICjM8tzIy5+Mhmu1cAzWovsye+5OC8dBlnCWItgwZPRSsJBkOHjfVxc7DhXuGft+T1UsaLtOXizE/tjKkJNeIfYhREDfyl1hkVLuUgjXbVo0c2hvwfdoXxSBErwRt2bQ+7rXXSxlh7oTW/I1xJL8N15qz0PBLg+QTjsPp2L2dZALD80agZlXOjnflmxYX2bzgcqVd6M9lsRbUdnsuSnKUOT1kxw0I1cigm5IipCFlaUwNJteT6fan3M/MBD4YEViYg3C4bFdB6RjW37/AMxFNUcz4QKCPjJEhUH94EcWo+WegWsBNykALQNuOOoiVybTDdLhRK+VQ7/yoXv+qZIddNQYZlhSTNwP7toBxzy4rBBXwp43PqEh4jhQvgstcGWYo540HFVLFYiQ7rrje31abqqtU2RrGVtsQrxZazxqXwnrJsd8FTnOs6ImbGDP5PdNDE/OoAh5ozhWM5WzjOuummjzj93sx4G99naHuF8Ey+VvFPexFY3aYLzni2fW5/uXibLJI4y5wtR2lvtMj7mLfz2Tjq0CUAbArYtwbyJdVLPO3cOiJDgOcnFBc5rJ6poU4vEMPDFW4XMihGL+SnMPW7VEJ/JwZMElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwYWRFBFNE4rl0YdYwffKKrmmNXZD9pTHOKfqya37ws1u6kD15uzqCrw+dxd++66U4o67ghgJujvNcYQHvUZkrBQ==" } ] }, { "header": { "sequence": 4, - "previousBlockHash": "64BC4CAA0864E98EB217AD9718387D5EA97B1631D1DE556AB219C70D2A9FA9CA", + "previousBlockHash": "9C5B62C46AE334039F95FA2D1283B13CCF490FDDE4AC28D78BFA62B7F90456A9", "noteCommitment": { "type": "Buffer", - "data": "base64:fEbtSjyxeX/k6mQSno4lRP8X0a7TxBi4ii1SJyQrBx0=" + "data": "base64:DL2vFwoSCgdRX3juXF6dXT9YxBSigN2wXN9V7ownxVk=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:Xm4OsaW1zo5hFTxslay3UKW7D9jgtEgN76jtg2Covyg=" + "data": "base64:1LvYS+S1Dn96TH3DwZo3mKvnZmFLPGErmtJL8Cp+dr8=" }, - "target": "9233318228143625020618577701423519925017621426082203201059080050516648", + "target": "9237817552710710459325694168790757901687427753068917234625768156097641", "randomness": "0", - "timestamp": 1717538828217, + "timestamp": 1717538960856, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", "noteSize": 8, "work": "0" @@ -6102,26 +4840,26 @@ "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/2vKiP////8AAAAA7/BGXjBaoQcXdcKt7BLmtO72HDn6vL3yrvfyo62QmNep440nAfH6zOxZ2f3sEbMvVH0zyBx3jLYxrjMudbcXiqi1M/Jf+EFHwNZ/d45YDGeNbClOqQRpAbd0FRAkTQtwMuk8WNI1DX38Yv6TzOYQoPROvNilfyesqxAHC1QPmyINd7wdXGOiqPX+Z6gBqLlmiywSvmSpsOZRmTN6YDkfO4EicLxhmITOWsOOsavp7faqENyNEX8yXxWCqfj4O45J8t53jaki6hmqaqT/utiYr1klY9Oafw0JIY78qgGVQZh45LK4deKtPd9SEutqP2HRh/uUF90bcpu/5z95XIpXtzPf5iKkoYrqKaQLfcOfuw3rdC2JGOtdoTWa4UvoS7tTFYe4lhSzh9gpwVVgYG4LoDywirWcwK/a0tHKKUeng9ooB3+Dtx+DV5rfMjjKzadzC8TJQ7gpCAgeVRj5B3deagCmdBoTBU5MebLI/5LzyJF8kADk25h/hlafHP98JMN8G22/mGltDrTqHmG0O0kP21coZlGt4qZ75S7cHSKclQg8jLQ+XO+ONhe86vxozEqg+XezEgNrNFm+cKyyhk6yGKtDMrWq6LPxsNI5TzMhW/44ycbym9yrsUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwh1LckMrSdyMKCQf4nrXWxGzTJhaoB2oCXGv8ckMUJ+DdUy1OuVHww5mbN9mErDs+oWj4R4FAeFVNs5ekXfsOAg==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/2vKiP////8AAAAA/LHvmXP0C7WunnQq4s5Sb0sSsAv7OM9rwNhnVxL3jqWopCzCiW8R7M/1UrcIYS1l20OqB/HXuMbW9FJiyM7290ZKA46AX3X6M7688rXQ55+ZiM2ODDygDexvMukbR3Ta0nLxUay/HDdkYkiDYZ0xKwhPKo1KZWjd/svnQ6w3gMEBBHZe/plDym+VJTAWJ84+/L3/cg9uClWIPob01zqm2GESETQzjeviPgtndP+9Gf+o2MAH+3ne0IyfPEqP5s1mVggJaNOwacMIEKMG4kY6GOkKAzQAT/ThnjG3zMMke46cxA91SjrRsyXCXuo2bjvJpoE45vypUdONEI6XRiNUJ30g70leY40A0KefYfWbBEV32qMtHFTxPRpxAV5BpI5lIBR1nOpgnKe2XZe/fsGquEQoi6vRDw1EIsqpV+RzqKUnz3PXr7SDBs+Np/ukf9bKV6iL8nn3/SuPAJqZMBX/6DigDo9h4elsBfnT50X+yDAti0FzJlGUXrnghwvtVomqgAFsUB1LRA7ooSOy1ZHUumA3ZtOkfYIUK3nNfEfo2dlrie4yxWFnjPdajSPGyE7pZiExygSIkRYkPFV/RbAT4wp5gUJAS7xwExEL6fjOkA7X8hIAh6xDiklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwFrKErzF+1B8ZY9ppvwcve/QJqV5qA1G0JvfTdbjTQdwBFbJ1b1G8nhrJ8Ypo+uOFL1fvIldpZwQnEDt1GNYyCw==" }, { "type": "Buffer", - "data": "base64:AQEAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAN1aMPhqNBjLikuXaTnrGJay+0RQWcuYK7vLqUlSq8YSNPYzN2q7SCaMZYA0o7TqT2CmMfKQ2h4NntZaKOyunnbwxSmWQsA+dRkPvGbOvl1Sw4HOa1ZbWSd8vEYepSc2uymGeUnTKRA6ixytamFERvJ8WhjxXIl2JWaMeaOU9qUYNUF5T1ma5v9oLLuHr/2bdyeHYOVwtw8DKJAPiXtlcs1Wn5/TrYrHBDkIzkW7/coOO5x70pOqXR8VzYxol7s7yfxl296esMiCn/lQ7F30mCljR0U68SIlTYghU7FgRWhICv8DvlDiPbPH0c/hdvp7c13DxxcThoz2BqpFfCKPqKOH7seYjzA3B0SoV2E328lLYiPjcvWpFjBZdeIw7gydqBQAAANXKct7eOCT9pozgY6hZ3h955onOuWs8teQw5kKgeZR9V4NmJZlYR5/Pp3uhCkDa/fMpWKwPddJv6AfCmjeZM5sJTxqAcnNrSpsTEEiKgh/OUy+ZWHcrjOAriivy7RKkCIWckvomu1lugL+KYyxGk65YhlnuxL3JpRbZMOuB98Bg35dJTxC/voIABDGvPbyrS7CyLiy/ofQ1yF5wvy+yc1kSBMVJyagnFK7KHILJYFTTfjJuZEOT5fMdZA9F74PRvRDEu3wXIzSs5OKhG/VK3+iLWuJVAD5czM/+kl4o0g4952mPUwydWRljCF17WkY6D5LrVowNQOS5hZ9ganagZO+kFWQlQ/fQI3tY4ENUA+O2lowSvDnH+JK6d2rqN34EIkLfOi4DWleUZ/1sgwDhx2ZKbZMjlbl5t5FYFIEV4MRSTr9WR1HVLQ28k3a3uH4JN/aapvCD+2itPxlEotV9xi7Io7Q1qG8x8FjHQ4NrkV9IjSnGkEoXYRRoO4mgPweShFYtPm07aF2SmkNX/SoqVSFNfTrQ8bWhxQixtHsNA/4hfxvCuiyWD110P0yOdn8+3Y8o+d/yIi58MX1NcU3Wsfrpla/nL0Uq7xVv81qt5+Hb9hY+L50QmuQPTLtPjGUKt0NRgiTtoNeQNdAgavriJoesNBk3Cl6EpqP7HeQIf9ZxY2gPYtJqWck+dkrqjg8xyRT8gTqLawsR6wJtd21lKF8gMaz0tByqwLIGPUEayzufec17RE6L3FK52YPbdAc/Yav2JSEFtHOv31G9um+v0sJDPJWR2XMNNVvCPl/oOWGT+a7YRe8iwBiqMklJtIcnxRThFTLCmzyzuOT1rno+0Wm5Vka4mbKebYT6y7Pn7IF+J5BfSIteIt+WHi8xQ+Y+/3hLYgmeCIifW6THPBj81/u4Dvg3Zo8Sna10bzOGJUvrhIwdjHrJH9AWCYubXgMr6ha50e5+3e5G6FJs+6Yb53ElZ6EQk2DCeU7t9AgQovhaNcpkJEEiJQGCtRaiftjtYbCJPu8/TZygIxMVoVDOlP9rv5rEsbm44hg5RI1OaBioHeK/9EfaBHuFkNK2Fx0OuvgaKL9b/LBbRVqdlkm1feJDFbO059Hil3orb+PU7TJQ0Fs37c10uRcWhpARRn0KKAsox8QP0acpbbUx/DvQl/iIFR8u+/De0TkZiDWg/EElwthJST6Cbwvclj4yQVjk3ddoGiWDtEHTmPUioyfVOfCcuvKVU6fEKpmxHcn1vlimrJAit1pIiVMkXNUZ0pjFOcv64hWSwL1PIfYyEWe/yJ9xeRODjMbPjeXYgjhiAe14Vcbf9g+C7/gBpu3RYRx5iYauB2VWqmtuHfewX/4K4QkzBdvGgZqz23r7q81Vj5RlPpQtQSfD0eaO4Dqm2f5whiER6OtfRXnlmGE31luYCWrpHJxQaWdfJYwnN2LzR24RDsH5yzLZ9X/Ui6hO2ZCqd0NfnH1LpOxHMJr9P/7iF3/M7PkOuDY4db69bFEqhQkkvOuMKGf2HATeMYHC5452kafY2yzsRSc6pYzes1lGoU/8/5Wm9r0qLOurj+hND446wcyKWicieAVV9Ps6GNchAQ==" + "data": "base64:AQEAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAb/X0X/HI7xUdgYl1jiGPiR4t7HdilFNJ1ImbNhdb+3GqmA0ZOezL4zI07AqSDpfDCVxGFUWVZtI71GNgXkYgffijxVP0HB5WCJY00I8pr/yILWkGTmsGx2ba+nCETyGQzTynYOHQDPSKCjP6WeVNQYBGH1NS31VmfQabfM/BBmESEMsMRGeMnMVkVEfpIJc+RC6pk2X9V7/8sR2He1f0eaVP3nrumv3RCZ06HlWv/qqk4jNc2bYxPuX1QbEcN1+cp2jpwjaZVj8Mz7bCq0vuFVmh4MPNgIFzBkXALZDfr+8r42ClnixuJnRnycBDTR+Rxk+30ixo2f8H75jO/yZKpsMVEfFObkOfnYqH922Sx9TvEO5+RPk+vSWI2Ge2mnMwBQAAAFxR7JF5Oo2tKN4jwUixToZndxikLOQEZNNxXB01L5mCAyNgCmShjCt/7QWttLAwWnyb+r04vzOlok1r2bQFKN6t87sPBvP28FFHv7i101RFKYReRYTof/CrTgpQPKqMCIbjqqtSMFYv/Ecp2P5bmN2Xir/5Y4rrJose9rF0VqDgvoa9zqn3Ei9lkAcyHTTUa6ak0XMP1ilQ6wdnR7XMU8M24DeuVY/hqzlNIiBoVciLwQXPNZy2hm+rRneLDNRYvhnmaBEuzloZ5uM0yQqK+Luo0N28+Q8bzHEpz3j8VAiFbDRgeZw/LL1L+mdgW0OxK45s8LmwjtsOAYLmwD8MIlPU3jR75tgMMs+UBhyft2OBW2hEYkt0+wm3TgS9z248nl10eHEuSCtU3TKhbLl5oyPOIZcHDgUTf/GtX/Df4Xo19Xs54U6ordx9+ScZk8wnCibCyUCbSb1YC2nYu3yDpXMqEGoGtcFJOefQl0gBMAm68YjAsB6yy/ibxv62sqYIJs/2LHc17sb2WKxTTkMZxppQrtCadW4FqnS+hujPOc+i9gABoKUyqZCs1IMumY7g3T9qPbq3tnY8QfgB382mP5PRJoLmrX4lPWXKUVTqrY1RsteaqnYCKF11mHY1rBRxpcdZJgqntDNreaapPwDts/U5DDir1JXObJXJOVDDOaUajllDNz8BXkikmV27kYa6i6vEywcwTRIXnx1b/Hk7xr2tV27dHIJV5zsZ3zrVlHfQEii7xxQIm1sN6+O97hiyqQtMIZWVeuLtlO2t7b24p0x5ADrKJ3JSvzcE3qNszUTf3k9+6fIAcKyoSp+Epd3KpmLa2t00adRUyYWMew0z3w2SFot8+TkgZiCBxjderq9bcwqiSnIGVeSL6zVh1AVgUX3zwdw1CbuRjTYwc9Q65Ftz9ew13CEUWqS+7PTW5tl26Gje0oN8BGgMrFstW2tF3p2yHOeik9YX/UY+4WI1tuk9E5fdHezUQbgZKnqt0Qw1lQiCxbMmLS+GBZwxgR1fLKo0B2o0zbWA9+kVBkBLHQMykP6hhqWMgFf+s05kAYslZlBaKNcYO5OG0zDnpunoTSTcCdtLVizIW3E074MnKvPuKMauuW9SBS39FTJ850PyFCeRz9ExEeModGNZFtFjyQDu+DhhfO8UNAKyyn00CfhH4YVprDWn3fCfz6bj1KOqjSnuWXS285pppECdE+nVE2V7LVDTexWYJyyjmVlRY0m0NLTNrjLRWxzT0loESC45zs/M66e8EdWM50zduL1aAeQreNpaWwBGg8rUwQuuWomwyAcVo2+GgTqRC3kFCtQSVaHB801WHcguech1wTaEN1hl9NjMCEOWYyqaJEwUoNlz+lhrlrTfb0QWCXz3d+X3Ci7R2xhyNv6Dv7+HIHKLASNOMkksbpyTUdkYaXeK2B+vs3shVhFX6WnM8+0jZq0ZT91XBybLPUfZR1LpwlYHaBLvJwvZGZ1TGlItQkJ4aHmcgtOQmp7G9p/vV0RQlTIlO96ioiSHoui8Qv3Qp7uSltg9Ip5GCu9WvlYzhdTeShCnlrWhrtrYO0eJCtGN1SG8o6v0UBK78mkVRlyedx9LBw==" } ] } ], - "Wallet disconnectBlock should update the account head hash to the previous block": [ + "Wallet getTransactionType should return send type for mint transactions": [ { "value": { "version": 4, - "id": "23a13952-9ca1-4fc7-8b8b-ca7d54528a7f", + "id": "1752aafb-063a-407e-9a89-fa6cf21251df", "name": "a", - "spendingKey": "43d0225b1300276945a95e014300ec96efbce8ad4350945138f974640dbeb8ae", - "viewKey": "a2e4d5ebcc416605a649cc105bbfbc1744674b87fe96ada78e0c25126ca7d3ec1c13945530ff3c86b9df7464db04f3c17036926053a127e94d0375de2c4ceb55", - "incomingViewKey": "85be2a194babc67ca480a7fad7fee31de1e22b1bf6a42c180b7957f804bb3b03", - "outgoingViewKey": "37dc14d6db97de98a5cb417b4878abee0da710aa9852b78509457db265a7bd9d", - "publicAddress": "a04b7f87ed8da22822fd6e12d8e4f1ff026e075d81170fa389619687fc09bba3", + "spendingKey": "3ddf6ef059038d3e00eb9c054356b73243d47b655afb53de6780406ed467b70b", + "viewKey": "93cb0e9ef0adc763018cc7cccdb287024460bd9de22778d649bc021f436275a5bb98700cc9e01b463d2eb1c6fc73468874076e37224ae57fff95d51dee4566c9", + "incomingViewKey": "e1d116d102f3832dee495bf0b8e22e9ac241e394c839f4a3cc6c17b70a1ec701", + "outgoingViewKey": "c481bc21735be6f39e11cdcafba614db85f4183153b8b539641ea0830fd3c11d", + "publicAddress": "f0fbe34510ec326ba09245a4d54837dad8b32031a2d9fcad7cc79e66f3effd17", "createdAt": { "hash": { "type": "Buffer", @@ -6130,7 +4868,7 @@ "sequence": 1 }, "scanningEnabled": true, - "proofAuthorizingKey": "82ad3b2281fed4dc1e6688d397fb8c821cd31958addf28d49bc8759fecaf4e00" + "proofAuthorizingKey": "ae8e40d882b798ec0ad76c8cd52bf7930efe746e038b86607520c2016388910c" }, "head": { "hash": { @@ -6140,16 +4878,78 @@ "sequence": 1 } }, + { + "header": { + "sequence": 2, + "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", + "noteCommitment": { + "type": "Buffer", + "data": "base64:onCdNmggF/2oGVp4f/p8oknj0nj8lc/SLDHFGX/YWUI=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:52ERR+LGjawjWBROzSmoSEo9uPzsNdDEI8sI9O63sJo=" + }, + "target": "9282972777491357380673661573939192202192629606981189395159182914949423", + "randomness": "0", + "timestamp": 1717538965971, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 4, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAArn5L3SkJFV6D2iI0M6BIYRDQBFYZmqWKrv4hi1j/W6SXq9VIai5CjFHYLIaXlJAEhNtquTP6IgL9896gqhnPqbdhbd6HycGg6y+OqPoNQwOE3VG/Mv4hPqMWnmzBsGZKnWyg2+IeIOvoKSewBuEMklUN5o0uFz0XRXFI0wxXuVkMSJDOn/Nv5yedmJBfu/IqEux6Brr+a4GnLZR6RprhtIxRnS0srk51wjCjdqN8peeQ+WiWTwgJa/MzU4l3v0OCN0rWHZl4b2Tt1dmb0RNpzW9UB+YFe1ATOl1OzosOKebiivMk0TUKtpOntjzGXqLA7gH4pdN1FepmKPily3yl5IegfpR7B+tQnjCzPXWOqSs5Wcjm5HcwceztZYly9yomBmTrGZ/peNaBim5F0ckO17BTQjQhS/8AZIo4SYmP8VuLirAmnRo1oy8hgGynYBzbTbJDPj3HEsT1xQRzB5+ed+28CWVuwfpA9tC9tpFpSWFe7HX4cvIQZBkojzPG/1Py+dODzRnQLv7VrshbnpcwAO2UPr2AHLG8Fwc7zIAZ24F6eNHN65aHb+dUhvHXjTP4iDlHg6yNXllku3FKEvc8kVQaB2LhPHW3lwKnNBYFQOlWMcIrwYuODUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwcjJfwd0I9efczfg20oav1ibON8LckBbQkoXToi18vhnsAyplf0g+wdX/SK2N5eEXIyK7pJ3qeVlt7H+vHCijBg==" + } + ] + }, + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+MdUUPjPr8bYZCJtC3J2W4iA938sRS3Qoe2BZJzBrgWKvokrOsO0O/hDpcz5SvYv1bSNzwldDXrJoRIzVMB+cYyX6fkN0Cx/oAZlukvFI/muwiPA75GDk8tHuYvEoDvTw7WRve/ltH+QC/NJpquGnsv3svnkZj7qar4pEEQbNpAZovB/TUJD7Unzoae4escwbKsFkdh67iuegyxt26gIe8IHn2kcvn3fS/bsQO55NcSXC7CauLu2F3gmjLbgq9KaOpbbwifsHGXM+zW/UWzL/V8HL9FAISt+4NxP9wxwvxa//SRdJ7MguUEr8JXVSQxK5Y1xL+gipkqwzwqOshkcNIGpoX4013FSoIAbcnzrBqHWfhGihtHLeDyC9co8Lgpo/kVYSvJnqgtopdigb+8VY254wEvt8QA3vByw115LBm1x5yRh3mAxFa1aSjedz0X58ErncHLAoXqOXZbsnxLACEtjkb6dulKxdvzl0MGQBZvwYDCnlrq7t5M1NJlnMNWbCm+zmPCTEq4lLPRKMj5yoO0p0i1vDZqSpoatJbFHE6xMFcuyGC0DGpNHRCoFlfh2TNXLkaZl2OKsob4EjsS+vqnT5yCnIGbe8PfBVWwN5zwePJrYYJspTfBUnQ08ui+eGoprZlSX6jYdY7h/lO7TXalWQ0iqeZGcNlwLwF/wlnSTnyuGOOuzAxuSfR+TbvyIunSmOlLl9+2rnJ6f7vRly0RpUJWc0UbMp5ReHEgT6FrQRkJy2nAEWEKipTKuJGYKzt8RxpaobwfYK2A+9kJYds/lbtE9twVmj64i/CQxWL+zkurINVrYaSMbMEckGH47cH8xEzMFdc0cb++2gIvRLrJd7nRuHbO+ELzsz48eW2lGZL5PTuLqZ5u0sxzI7HOs0Tscv/xS4t8BAd8djZffsitKJDqPKSTpmRwkpkCBtxymMrFqTXujAkrxQ4vWUK1jlES6PNB5dntroZqwWXBNALcXRL7lNOrP8PvjRRDsMmugkkWk1Ug32tizIDGi2fytfMeeZvPv/RdmYWtlYXNzZXQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG1ldGFkYXRhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAKVllL5fZK+LL8CsKp+KUlDcVZSF7SgJeIKXj6e+BAY+rWp+ecYfUBZLX7ZrP+JQXsA1JfRbjB9cPp1n6ltc+Ag+smvti84jb2uZThx+QUg3rENLxJc8EeuLnnMV6fA3pt4YSEZ1gBEbth0piU1z9vPdnpyi8jS5HrWwtBHLKngF" + }, + { + "header": { + "sequence": 3, + "previousBlockHash": "87E305098235CD4ED1E59AAB0E750C25DE65C2808B5142C0DBF463975747C6DF", + "noteCommitment": { + "type": "Buffer", + "data": "base64:xOp7eiljMucd2lTHf590CbEP6FhPcEsBkx8RuinEsxI=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:Nixjzd7o7fnd1LWmI1xLyZegfs7QSYMTwiLyggwrzgk=" + }, + "target": "9260366780148527510972123832573278885902566341756516011968728852484845", + "randomness": "0", + "timestamp": 1717538973214, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 6, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAKF84UDt0oViCmGUPnejc+ywBy30UoeOGW2bUrCMI34Cg9rR2FynPxlwGN+QgmBxjnEHIDdLHLIvswKI7uV9lA3kCQNrhje05X1q3cG1/zHWNXqOUYWwN0igYCCUH3eWBNR9pv2jTtH5JTGomyYvQEbqQkTezxQfYbxTCUXFZ39QWxxhwHrM7pg4krwcwucTl6DBpTnekawRDmg41eUZ4qIAI0vwjkzvIWiebFupRaICATpH1koxEMAwzbUKeNntYeWCNFqmeX656N73yeAMfq5uOYkv9Drf1PWRTG2t+bud0UbN2p4H7MYha9Ih4bPgAncyt+JpIuo/aiOsjzwE7kRw5eJE4Yz6IKVRG8UjyoMrpiqJPAOcMeWn6h7WjaPhRz6i6+dnYjaojCXuQj5xmzg2ppthvdABgqVYLJ2eeMsICvfLZ85b1hyYjcaLTbKiBzq3ccxEHQrBMNm2Tm2feN/898gKKGCqDD4NaRzVozuEm4U3Muyl5yJG3ErHYdPXYCS550Joxk3PQl6S7w94yAZKMMUXTBatCVcc5sK/7/LU1gmjBmkjp+8ZKdTnQR5In8HRh8HygMxNhPA0tKSO2kAYGG8EdvMsdzeZKndldn7pVbhLGwuPQ/klyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwqcoKO324naEHo7H3CsJYViRrjbMdiIaOSYTVU7gVuHC6DBbVm5CuAu1beM7a+33QhqICVQS6w4uRSaj+mJrNCQ==" + }, + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+MdUUPjPr8bYZCJtC3J2W4iA938sRS3Qoe2BZJzBrgWKvokrOsO0O/hDpcz5SvYv1bSNzwldDXrJoRIzVMB+cYyX6fkN0Cx/oAZlukvFI/muwiPA75GDk8tHuYvEoDvTw7WRve/ltH+QC/NJpquGnsv3svnkZj7qar4pEEQbNpAZovB/TUJD7Unzoae4escwbKsFkdh67iuegyxt26gIe8IHn2kcvn3fS/bsQO55NcSXC7CauLu2F3gmjLbgq9KaOpbbwifsHGXM+zW/UWzL/V8HL9FAISt+4NxP9wxwvxa//SRdJ7MguUEr8JXVSQxK5Y1xL+gipkqwzwqOshkcNIGpoX4013FSoIAbcnzrBqHWfhGihtHLeDyC9co8Lgpo/kVYSvJnqgtopdigb+8VY254wEvt8QA3vByw115LBm1x5yRh3mAxFa1aSjedz0X58ErncHLAoXqOXZbsnxLACEtjkb6dulKxdvzl0MGQBZvwYDCnlrq7t5M1NJlnMNWbCm+zmPCTEq4lLPRKMj5yoO0p0i1vDZqSpoatJbFHE6xMFcuyGC0DGpNHRCoFlfh2TNXLkaZl2OKsob4EjsS+vqnT5yCnIGbe8PfBVWwN5zwePJrYYJspTfBUnQ08ui+eGoprZlSX6jYdY7h/lO7TXalWQ0iqeZGcNlwLwF/wlnSTnyuGOOuzAxuSfR+TbvyIunSmOlLl9+2rnJ6f7vRly0RpUJWc0UbMp5ReHEgT6FrQRkJy2nAEWEKipTKuJGYKzt8RxpaobwfYK2A+9kJYds/lbtE9twVmj64i/CQxWL+zkurINVrYaSMbMEckGH47cH8xEzMFdc0cb++2gIvRLrJd7nRuHbO+ELzsz48eW2lGZL5PTuLqZ5u0sxzI7HOs0Tscv/xS4t8BAd8djZffsitKJDqPKSTpmRwkpkCBtxymMrFqTXujAkrxQ4vWUK1jlES6PNB5dntroZqwWXBNALcXRL7lNOrP8PvjRRDsMmugkkWk1Ug32tizIDGi2fytfMeeZvPv/RdmYWtlYXNzZXQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG1ldGFkYXRhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAKVllL5fZK+LL8CsKp+KUlDcVZSF7SgJeIKXj6e+BAY+rWp+ecYfUBZLX7ZrP+JQXsA1JfRbjB9cPp1n6ltc+Ag+smvti84jb2uZThx+QUg3rENLxJc8EeuLnnMV6fA3pt4YSEZ1gBEbth0piU1z9vPdnpyi8jS5HrWwtBHLKngF" + } + ] + } + ], + "Wallet getTransactionType should return send type for burn transactions": [ { "value": { "version": 4, - "id": "3db24702-4c00-45d7-8cf6-d3a39866dc8f", - "name": "b", - "spendingKey": "9fd21200e06e7eb043ab19cfb0baf610ce78a34cac2459a309bf83c235c6bb9f", - "viewKey": "af25a238a5b7571f4a04c68cbf0a3d2b439140bceb4089037e6002dfaa90e50b5c562f0c23f1293933808a008239d4804d7accb73bc9c949b0c3992b82307632", - "incomingViewKey": "24375314e92a44b3ffee23a1ede3db99417d78ed573557002190bcc6168a3604", - "outgoingViewKey": "0170cde824d36c7b73510632c2eceaead5abdcc3cfe0f3dea276c1fcd2784f4a", - "publicAddress": "4df7683042db7b5452447fec67f8705fb987eac27dbc7a90b3952631fc9eef14", + "id": "e70d60b0-ed2c-4ecd-8733-6868e06a1f07", + "name": "a", + "spendingKey": "1e0f64aa9f3399ff327fcee2f958d2878b22c330976591ce22260ed49b7a6ae2", + "viewKey": "f24aa2d07299bd40c42bde10abbac5d2eb8a610ed05e69cb09e058427deb3aad28024d98a0418fe395b0923a0063926ec3674da1b2d70a08d0d6c85a332c6265", + "incomingViewKey": "f9203e5893973e234d850b65573003ba04f89c231195d0598a4198c446d89102", + "outgoingViewKey": "641d47cd60fb9991e6c62561f53f3b557f04a285ae6924cc5914718e9fbbe138", + "publicAddress": "cec7be662b6bac78af667994b490f26857d18dca1e728488ffe7de0b01c4404e", "createdAt": { "hash": { "type": "Buffer", @@ -6158,7 +4958,7 @@ "sequence": 1 }, "scanningEnabled": true, - "proofAuthorizingKey": "6f056d911f82921ee5b80b302cfb83be49c6a6d9f14ef3f0bd514733161b9d06" + "proofAuthorizingKey": "23b064a3b8d0933b948996bf738832e9f7c65e859c7112dd9b3ab9309db3d507" }, "head": { "hash": { @@ -6174,15 +4974,15 @@ "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", "noteCommitment": { "type": "Buffer", - "data": "base64:XEQ3Bvjk6XhOZA3wHi2/0JYKEr5N4Q4zuCPfdqkoDGM=" + "data": "base64:aS7ASLGMZiv7hpmqlHeNB5FRMyV91rVJBc1tPoKm1C8=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:qJLnZKHMkfT5JWiHaS0n2oDYVnQQ8oWHiDAv8Kbp8JM=" + "data": "base64:AuB8iwuUK4wG0Mq67TGU6TTpY4xgsEAbVKgn0qS0tI4=" }, "target": "9282972777491357380673661573939192202192629606981189395159182914949423", "randomness": "0", - "timestamp": 1717538832024, + "timestamp": 1717538977678, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", "noteSize": 4, "work": "0" @@ -6190,51 +4990,63 @@ "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAHq/ooVgaEf52Ok/jN7FT4CBAAIoUWTyCp4GX7xpxAEWoLwVq85RgQ1GqhEmlBrZyP8WijWJCNdyRrveFKm9RnK3NkLjqGS7r8T3zvbVH6tqHGM0N1kd20pWEGX1fROAQqw+FPYnnSOPZUotHirCtHcEvwedqCErrhLaTs7LG9r8DUdqPhLpbem3nRaR6xG/F8xpNAvRLe65RL4iMR73saKVMsQcCLGlKC8KSGDFdzpGy3Hp7ZwDGyq/19koEvI/d+eOlp5jEiK7NEpD+IRrbuUTTLsgeaipz4kbZBDSk5kY1/nEFAyo4HQ82UOVt5G1nogvxHsePf+36qI3u4MPpRzs0loinoq4UcJJH8HOpxDIIhmxY/t3n/2Dkezkkyw08UlSx54/WGNoiDWmAySIdc/wNb9qbUXV43oj9yKhinCLaLXvXY+hfwk+lGSwViwqPYZkUY8O3BkYDJ+Y0vhbRWVbNRfVZghtuGDVwDynBwV10Uc3f2KBuZcVnf2Ctalnmz/fdCXVzxz3OzHH/RpLyfD/jyo9HDD/DK4/cdAuDcXfMXiUlmwaMQKyiQC3jXxCuecB9IJa06sS5hdMksBWR++KBY/f/Ht4IT0mmumuNX9m1xlH+t6CfBklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAweBrhDoyFhZhF9bbrEiyy+RQt3ft23/UUjRvKzv774N2HP4kI3CDV1p1c35pJMV2VNRmA6UFeacXu7uzbK7hFAQ==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAT4+USY6FnToSV7ZjcHzWvUT9p6fvxmTd0dFshKKHhaOwV6UxnRaFMxwRGAiRQmkQs/crpIVhpvceXbUV0C/YbCWZr2K+T0GRnnxGzHWROC+y3YMorg10M5SUK57UFTD9z0pZhMJzJTqx4Wt/JLwXgwbEzamfBEBSQNyYM4ZX+NoZh/7ySogA208M4saEhys9gwb6DRcPdIpXozNsnnGN7miACrdJcyi/oF9akZyooCaRsGJCV4GDZ00lnor4AESThyoGb2xHW4YjCNfqEbdANtuECOKFGMc5B2SHb4h3m1gmH0T2wBHj9ToomU27LHKtGLe5XdEU1ibsfrwgFin0P7R7AJRrXhcw2xmxgiy3p1DpsCJyzEMSM2ApROZmxyYEkSAEnZ4GUvasMfxQh06GBZRVgrwDcRzod8HAcaJaFNExqNMayN+hVYOz64arKT1yAMGyKsdrhUtFz5HFVv0EVxz/tjwZDulRKp3TPwKCVw/9Z8U8etc7CNnBNUM/AAfuLbeXCKyrAga7Wgc613aUtt2cm91yRg4zREMCETkzgYPVqS0K2iXmTqha/GRiOC2pCYlfetpSemH4eOE7ql1eA7XCulNxv2/rFeTznc1aElOagai+E7Eyzklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwmv67lpCUh67l1lWOSSZZrAwIbOxlwXQx2mUV/wjgZkqaS6b1DxMVg4lRdMz1336XflHtqPG5UhzuZdIy3XQRDg==" } ] }, + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE77QpulZtkpkkf24CYcBP2qUgX+qSRIB+djV1VVfhzejHnuJ4vnj4QJahrQ35gb1z+6a/BaGG3zTTlp7ZrOk1ieWdwIDTSZoBDMLtRkTi2q0QwhnZmIUJ+i9mqVLUh2MYvsqnmNs9ClsqeB/fYPnwP9ZP3w/KMCrx3juijlfWjQNcsLqn+SMA3Q5ApFY+k0ZIX4hyLHWbOI4VCOb3Jei8rlQgo77HmjLpFOnmcLLSYyp+RsVm8BzJ4/3I2GADRJL63S7AWdej9mHqCRgJSnLxqEZLdTwyqHpyqsmfxKBHOKBnOW9Qn4pUWDHWtSGi6fPEyvdwSBWTMxalBkwujTRaB7hArdVpXzGZwbLKvCaRqPSjpSTK8W8ggd7u6WVbsZb9JWOz3+ShA1lZh4xsPsv2P1uqulzIzNoQglCPj2wnDBzMG4FFgvaUr8pP/XPpeSKnSbS8PmvQpAcifZZK5l4YZaBOiucPgmywFCpIwqgjB4i8a8UYGjW+tA1LGVmVGnhy7e/muL/xlK6SEKDtgF068Fpey7+rCsXI1m4wIxVw4tT/Y7aWa8C+jhqxHGOObv1hp13/71EQE/oE2WOE4cqcVlzTP7vUl5aW2IMT1k4yRVqNy6mNG7YgTHpGB2YC1znaYP92M0BJkhnyJG85qrgClhZgC5GzlT8P0umRD9IbgIyIajGL1kxZrHHtIImqywLFuc9CgVTlmBkJbO9RtJtifYuqITaEJ4bj6e0M7/fX+N786SrzdkjWWLWqsGfRaoszUx5mSYl1h0UJFY4B8sNq6U84A5qBtgIjnZtF6sKLFPky9Vtc7iY0ZXLxdo8NQhf3kyUlKBuZoq4Mqg/0Xuj21EFw4Lug2X6EXBiIeJplV/HCe9fxfq59ypcyA0H60+pVtUYuQ/amJ1XdcpYC1a5AAUbdGPpY4d2s3i2nTQEOVEON/RapXwSY8exLECBRuHHelTtBwDlm7sjb8kIfHQHnWLqtqcnrwNOzse+ZitrrHivZnmUtJDyaFfRjcoecoSI/+feCwHEQE5mYWtlYXNzZXQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG1ldGFkYXRhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsKAAAAAAAAAILb/O4cVis/DloIJXLK6zg3y2uKNGph8FYoizUSjKzfb6nKQ7gufjpDqROnU3F6q/rbkGbK7VKWMESV44HVDAdEabfmg+yZgHyrPqcXoXgr8Zw2LAjTWNg3brj9Kuwk7eq1xsSQL2MI0eS4HTCls3v4D8X2HV2Flngb0/vlWWIC" + }, { "header": { "sequence": 3, - "previousBlockHash": "7F840778C2EE7BBCEE58345E540CCA24BA65274887151D50D7C51AE1BC1AD330", + "previousBlockHash": "216409CB9937C70C611CC4FA9BFA37518E3AA47236B7EBC514C71E78A39926F2", "noteCommitment": { "type": "Buffer", - "data": "base64:VLevhByK2cSaVFYaNWBo/yiiAz+38SIQFC4OTVQUvgg=" + "data": "base64:mK95bK5rOxJgUHgQ/d1RvV/JLGkdNqXvwt+wt41hjGM=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:weNpITr/hPtmw7dvQGSCoIp5dTXHrQ9rd01PbDsmNE0=" + "data": "base64:2CY+t+au4Gl01WHD7KhEkKoAYC+O+FVMLwXrwcu7xLk=" }, "target": "9255858786337818395603165512831024101510453493377417362192396248796027", "randomness": "0", - "timestamp": 1717538833953, + "timestamp": 1717538981685, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 5, + "noteSize": 6, "work": "0" }, "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAiBjSTrwG11TFrZKrBMkbozpK6BUV4ZV2a2L/D3xF9eiSTMp7Oydru8f4SdPcO3hT9r/zF73HAnFRouEIztu6QMJfHv5yBeKP+UQ9VlcxJcKPgKxjefh9oHxa4zf536/QIBwdYI13JxQdou0HRYTH4HwBdBjXeF3dOAO2Ah39JnoJnFxWUbpyyICeyHHoxREtoi6Q/RQgJ+qx+tXKkYvUX08cJYr8ymRMzKk0SoB4qZesp4PxHlhbDsYBtHraSFd2unPRQnNzh1x9a/C8tJPYE/J85OuZbDSJeTGzJlgRkPV+S/6N1SOZnb1kJdI7r2L03H9Jd3dd6p5EZY3jBvNpanyP8t50E/daoVkBWwzauTFq/N43PSMEAYYYtU72MTMwxHq4H2srfd45R0v36wKg0k25Xx77jsL/ZqGQb2Q5028+60FTnH3VdLQ6jn5iUqga2dxB6qB1jxJyXPsQLBI137TPB+hPrTBA4pUD2QQhRMbZZ05VbPEs9bT9vE3Ef+pCbxU5WXl4yavl7wPr0tH2bDskCrtA/YbDBWZqgIMolpXzgvw/QOc9xzhCToN7X+8eMQb9t9zk8Z3nD6C0OOIXxX++4mniCbJAzBml1hY/vedIuFx20s/COklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwz5bdLkzzcHD32CydUnSmIf07YTCqFmWgAdTrY4ywvL8uGIGp8qIg2pRYcChhep8AMh/dz7fvblEfwQ3arb8MCA==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAwIl34DAsfiNW+UPDnL2HSTpcTliMyVpHxLy8DYdIkdumwfJ25zQsU3N/1UaavA7hK7IhK8axVCZN/3kgNixHiHw9E1r1qiyRaegyOPP+RJO1R2IcLhaNqzQwsNsKoa4qq6j9qDzscfyuNO6D1EJ/ILY2kNEFjqWKwd+B2I0i3fkRBJVCweBA/ctV3KJh8E6qgysP5lNwaSvBO3jc8RE4/+JviszvLXTyQArXDUjzVu2I3wkguvUbnkbO9HY+MdKM0fRwTRUxjSbYSaoDWrJ88SychritYLhoLlXf1a19kt87HsCyUmYvHXIt2/76PY3O48X3JBmxlsXOUVmVGerwDkcEsYeFKwejca+GPz/6TtcbDy0kGwNdnNU/3EHotKpAL1UGFmBV8Zab71cXH/Pxtnwsx6swtrvuhsbK+B5JZCm7yrEeXnrgL1uX09nqYi2ktmWGJmAhE7pio837v0DKCW2u1V2pisUTAiHOxfngkQ3PFr+YCJs9Ah1jq8pO5nl2vHUQwzTXl2wQQ51z//nYaipev4kXNrbF62tNDi8eg8FVbgpEAk8Uu3wMSWLSA5/PyN/T7kkTPJSxDaFhKBZx0f/apTC++RK7W5ngLfNNcTGZ03XSHfyX9klyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwA96BvNjRm4Z61DvxXmKG+5jFYELBdvqecqwWOOZpCWBWIaHcE85CVEEgJSstW7xB2DRMqh78BRlmzLxpRxYwAw==" + }, + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE77QpulZtkpkkf24CYcBP2qUgX+qSRIB+djV1VVfhzejHnuJ4vnj4QJahrQ35gb1z+6a/BaGG3zTTlp7ZrOk1ieWdwIDTSZoBDMLtRkTi2q0QwhnZmIUJ+i9mqVLUh2MYvsqnmNs9ClsqeB/fYPnwP9ZP3w/KMCrx3juijlfWjQNcsLqn+SMA3Q5ApFY+k0ZIX4hyLHWbOI4VCOb3Jei8rlQgo77HmjLpFOnmcLLSYyp+RsVm8BzJ4/3I2GADRJL63S7AWdej9mHqCRgJSnLxqEZLdTwyqHpyqsmfxKBHOKBnOW9Qn4pUWDHWtSGi6fPEyvdwSBWTMxalBkwujTRaB7hArdVpXzGZwbLKvCaRqPSjpSTK8W8ggd7u6WVbsZb9JWOz3+ShA1lZh4xsPsv2P1uqulzIzNoQglCPj2wnDBzMG4FFgvaUr8pP/XPpeSKnSbS8PmvQpAcifZZK5l4YZaBOiucPgmywFCpIwqgjB4i8a8UYGjW+tA1LGVmVGnhy7e/muL/xlK6SEKDtgF068Fpey7+rCsXI1m4wIxVw4tT/Y7aWa8C+jhqxHGOObv1hp13/71EQE/oE2WOE4cqcVlzTP7vUl5aW2IMT1k4yRVqNy6mNG7YgTHpGB2YC1znaYP92M0BJkhnyJG85qrgClhZgC5GzlT8P0umRD9IbgIyIajGL1kxZrHHtIImqywLFuc9CgVTlmBkJbO9RtJtifYuqITaEJ4bj6e0M7/fX+N786SrzdkjWWLWqsGfRaoszUx5mSYl1h0UJFY4B8sNq6U84A5qBtgIjnZtF6sKLFPky9Vtc7iY0ZXLxdo8NQhf3kyUlKBuZoq4Mqg/0Xuj21EFw4Lug2X6EXBiIeJplV/HCe9fxfq59ypcyA0H60+pVtUYuQ/amJ1XdcpYC1a5AAUbdGPpY4d2s3i2nTQEOVEON/RapXwSY8exLECBRuHHelTtBwDlm7sjb8kIfHQHnWLqtqcnrwNOzse+ZitrrHivZnmUtJDyaFfRjcoecoSI/+feCwHEQE5mYWtlYXNzZXQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG1ldGFkYXRhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsKAAAAAAAAAILb/O4cVis/DloIJXLK6zg3y2uKNGph8FYoizUSjKzfb6nKQ7gufjpDqROnU3F6q/rbkGbK7VKWMESV44HVDAdEabfmg+yZgHyrPqcXoXgr8Zw2LAjTWNg3brj9Kuwk7eq1xsSQL2MI0eS4HTCls3v4D8X2HV2Flngb0/vlWWIC" } ] }, + { + "type": "Buffer", + "data": "base64:AQEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAE1J8HBgNQSQ/ZwFj7dtD2OFVEooj4VItPMQhtqRNNbKzUsO9C1ImuiFKLhUEzpWRbPF5IhgeD8VcvJnWWLyC/mmSNZM9dS1/9NmGo9Qb4KK5kqHj/Mb0DAe6GiM7ksVwIpnZn0aEDD07vohnfgpHRcSG5/xeD5G9fNHlO9346HsN64VZGXEJHvxEWdkpjPeBFvXGXtM9pbqB2diUQ1i1qP9W060lZ8joZGIA/PTU2y+GlCXP5WEh7fcoA6CYuebrQYF4/aEHt0spOiRa514jFHI54jbcpQxEbNFAECAPJLITLfpcmgk4Nnj1DqOEF8qQPQdYkkpzPsSv6vu/IhAlQpiveWyuazsSYFB4EP3dUb1fySxpHTal78LfsLeNYYxjBgAAAFAcQYJ3Bjq80IkYQGlRobMuZrHVChVRfKaZI8t4870WcA+2DPrv8jMttuiYGurEAP+Y5oTlQBoHuMzQTmmLOMzKjmps0sXGaTm1qyIss3xMqc2CC60VRcdEbk1vDsVvAaWwS+yns3B+uLn3GDgZ722Ak7R2pIXks4Lai2UCgmaaF74bkbbULeNB8ly6jDZl1ZToANqnpE9ExyZPlW1oJVaPNW/hZ+tZKI2TOKMWgcp+pLeIsscVA65ZFpl440aotBb30DXZr4u1RXEi1+o9X9GCb00T18SahJNy1rg6IUcc2W9Ng+cSUB5c8C8qAS1qKYdHUk7PMj7bQx1a7zqOYXuIvIvALh6LePls7Y1a/09v6iEEbCU0UJY5U7VquVMj+IhcfpvXN5iYcuqC50QPI/GwI5qN0R7cysC67bQEfKqmzf/YMYc8WUf8VBqX59oU9zduR9aevFzwdMNNNRFr+hQ8pbyJoBupGRQ1MYoLKHgsVyKJabsgvZvqDqk/3Wjuaz/IIuBWNVUMmXV/Cap+nM7vSXVynOxFKsZiupZJA/cYjW9LSx6tZP3mLoKCn9sJOakXu68vbOifl2BA22ksZO0vJXl9ZgEG9/uE+iI7mZn0aXNWiIkrwyUmWpFxY25Qeeo4tEkH6CJgDqMQ8QMfAcgW6n+//Ifzzo/TUezwoAjoUZYY7daOszTIhY6zKvDZ0O4weI3KryPDBbLwxd1Yzd04VnF/PPFTlMxg6hepb+CRfvQP5HnlKGKUQ8Uq5wLB5zvRp6vOmu2W2Jq/twaQlF8ZVOuzyfHC3oQpb5/Q9Jp8tBtlSPxp2Zy0STzNBJRcKFx87GU9Q2vbV/qrj77lqIoBxrjeDLGrSwIAAAAAAAAADQNXKeAIKXatYnxF4RvRddJ5EsDu4ittGEX3M350r81G1g686V86OMk1c5iiGqaVDRZ61tuvRWO750wKKFJxCQ==" + }, { "header": { "sequence": 4, - "previousBlockHash": "7A51C70423B28FAA99D236FDB07C41896C626A3B0AEDE5F8F77EF748B335744B", + "previousBlockHash": "28BA7F2C93974C90AA11A503B27C976B6EED085470CDF11A6E8242C77889C413", "noteCommitment": { "type": "Buffer", - "data": "base64:1VFep3fDG3jQM7IXUgSIc5yayWx+kTt+pWNuuFrQMWg=" + "data": "base64:i1hZd72Q/bi6aCdWOqGg4I1ixsl+M48AxPfbG/X5aGA=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:HtbB9rZdaTtVHX6qR9rSngAvUmd+ptTTlSNlrEciW1E=" + "data": "base64:FotkS0I+a4FhPq4s9AAPgzPktQ/bWyZezOo4EA+Nmsk=" }, "target": "9233318228143625020618577701423519925017621426082203201059080050516648", "randomness": "0", - "timestamp": 1717538843233, + "timestamp": 1717538987224, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", "noteSize": 8, "work": "0" @@ -6242,26 +5054,26 @@ "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/2vKiP////8AAAAAAH0GoT/7LrRguG0yKDNoy9ewEA4cl6FOB7BfWLne/Y+KPwu0Irz9uzUv49v8x87FJ+zAeEGJG5oP7xQynrTsACKlnYEfbgj5bJ4UWu1wE/2WqgRENm3eLMIzjgHaqtqavLzqUmHBTZvhtFLYAb8D/wqBdCSThiIRJKhQNbdX6gURCmWsjj6X9decFpaJgY3Yntcr3V7dWlYkwf5ZPZhJYOBvZOeq1ipMAPEXGO7DvQGPnO7StvBXHXNwv3yJp6Dq0k/W4bsF9H39jGKcYj2mHLjtdnI2ya5xOzhl5wHGlpFYjGovQceW5idwYxYkxesN1rmUFR8yNCyKzXcE4L7vWqUWOiTUjSMO31dx7vFGx41dImcUoLxjOH04z5N4CiNX6r+4sPmADN+fPBijO9G+DonljGDI+ZUkKM7D+uFSvj1LbfeWUHNjWY1Xl+bym4SH61AAhmnSlQrVG2yOSda06oqxhoblbixHTfplRfWTHBBiE7leiNR0LDpmKi8BDO2yp9yVSB63dwi1VtAujet2vb+4ei4rSu07tCr8aUQPguzmpUL5Q13YU74zJUvkPMRKVNfyFHEfjk6ygfaV8Y6lPkLAo1mqin5MUjW2g1dnX1AlC4ycEV6E+Ulyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwSU5gwUKD5ZDJfOoXXkRjRoaQRGUUt2a1nh5f5M6QXelciVGZ329dHr8qn18zI7i9AO8wFhj76fVFVE6IAxSXBA==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAALVdeHAARF6+/FPvLKt6au1F+pPgisG9zBFVL4JYvR1m45/gQDxhSDVUzWnoEG6JvR4btm2AmemzicsIL48qB00kn1K9y5Djtm07eB1DBrCOS+1dICZZGpd75VzCRjLczVUWR2mAjLoHo7iO4YKiov2+nw/k9RSjomzHISATKZUsSl+fwW/+6GnEiPXAzAgbsKItpXNUVwXW7qag3afvSr0M1nCHHBToAOqUdpxSDjkKwOLVoSVcgYigagqIcYUhtOHthUFEIlTYIf9GrPexHctQW64+ktX0/LhzotMbipFGSHXin8Mb01H1GFFn2z2d28qlUCrHpdhdGLJJyhdeg3Y2ZMYqsA9YlMtsM9sBlutEo9wRNtOuZuBgvQSgGy8RYBlox+/u82x9J76TfbOiYu5zaMdbhHPKyCV04KEusfMhVOWuZveLhhLTdwKBdibzSEhGz7NII7mSomBPuE/oF5UnMbaaT7ANHAgQPOKPszprz1JtT0YquQ+O+9KGzSQy0UAapPRt+fzQLsvBldcarcoBzW+ugFoCChcDA2KmLsOhdg9yhN2kFGOEAKmeBN9H1oc/X/YxFlRPIW9C+sb/adN6TOgU7ZY+PW+KYA521TaK1fCkf/ZmIWklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwVnmp2/WjL5jliFYsJ6hCSIiLkZ7VqivBFmkJO7lkHQa6Io3ccBDSdQidWSK+Y569Kf9LBH5MrTsMDAcA5UkkAA==" }, { "type": "Buffer", - "data": "base64:AQEAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAsVj1yV+P5iuV3DltoHMXbeBgTqhtWHYNHhsilaFhIqi1oP4hz5GGoYsQM9XWNq2BQ5lr5NxdmFRD+umqSuiyS2CFexBdNKl3ULWNR2jhD6ajEmB6GptEEh9XXRVfhb7Dpmxaukf8TNPAMQQljeemC7IqjXgttaXZH7kwQ7l4xkwLbTMhud2VYqfv3zl0ubJE3uoDGU7aWNu3Hj7kNqg63Q5Q1+4sD7XYYL0YHXdgGiuQhDvzlUYFPPpLLUa8tUe9CWD/QwJsVr5O4uSfYl8oDZp2qCkWZOYhWgnDO/HbQLJn6GAFouwyQLO3co7R3b+DDYAuK9uFFWQoMXJWkUF051S3r4QcitnEmlRWGjVgaP8oogM/t/EiEBQuDk1UFL4IBQAAAI4h66Vpc9z6JfEJUi32sYFCoi2sSXWv11Y4IQGmhvZMpGSO3tuzyNJlsPKB8e5Ct7dPSnelCeUmxeVD3vG7t9Bcx7TO5hP9nHof8Gsnl7wFEJLeRJjnv806K7NkCMe3CJdZ85lljwu3o7837OgZ3R2gOAcmfGEbRHqdBxJSuYUg71uXN1gq8FCoWGid7Bkl1pYKjBDzfO28nuCaPvQ9NTp/jTbf0mzrLQM3a0Ws0RwzLrUMmi8/JeiLneSjcNLHVRDFSXt2UssE0To+nH6hDU9HTJLhfPys+YVn7H6oo0QVD/1d9zJoGS1ozWnIsVqRDKvGtbLlqgK/zPu7qJi13Hh4VAWAfttaJlIZ0piST44SWorUNih2EGYJvQ8einQJ4A3HKsJeJLEOpI51G62ZhwpQQyDLBE/0crH2SKmLi0bbihabxnQi4sq3GpxANiMZgxumZaQ4400I178uZNejXT6P9fpAZ3ZwhTN8/P0GdBii4ygpLsQ3NqgDmhNWYJFn6aY6p4jEmCL5O51R630EIohL6kBQVr+JhyLiLUGspwydMa6gE2KKoGN9o8hx+8a75rLEOZbP2wgCilWhmxx7tg9g1v08stL+UPIYSUlOVAPn3Ln9A3Fy+oOVsirWqRFYdfNgnFyBLxF+Glkftjg14534UJv4RgrDbnhUuF6JEiYJTh22OD7vUtEh7indVRA41guq4G2N+1KVjSIEXzPL8ASZ4z+lD8QaZgxsDlgM1BEadtt7eKKsTSvTckiLKOIdXcHQBjoVwRmAyOcSDMPzZrq7nXDwbBygudgrFDr9TTf0gTlAFwbYJTiv1IVw0iJGEYunMnHI8RDc65zSiZ1b7tKluZHxTqaTF3sIgCoSsu+bqZu4OY+gwUimLUG6FubybEh/0Z7JSRKfYFGhm25/njTYjU/2ZefXlfG+V12lzt7lYjdmxIdAL1wVxFZ9Yg63chLO3pls9OHIYE56jL8OCzrZ/RCh/REW4e8f4CyfJCy+5ge05F4+6YKxMiUkCOCXXHjz/6CfkrtDDgMkwEhp9Zu9qR38HAKhBJCQ4bTdwQiRurrLQ9PAwc6BzLzASAZABxvebd6TtIEyWdRt18wy2hN3xk5Ek6OJDVsjO4Sywbl9yvvjLwaDxKvcSPAJvttMZtEKkOOH/MQFE/3zWFg/Xqw83Wi3uIHIT9LYxjig2N/ewyDWx7kpUOoJ/OUHogVdS8FWQJcdpPeVNJLgE3PMqpGecM52UFDHRK+SQhj1eaffxMzGoJfPJxkoSLyb18l4Kixdp3yrBbUexUeAvEPmWS7Vojtwzui3lxhsnDM32UggclhVfKxc+LSUF6pX3eut9skn0FkHvc68l6Auwpmh0ljoJCukuXs7VdsBCYJ6ltrTCiEgtIguxe34p6L5ih6XGpV3Lha5Uzs54cyr979mIVcJzYRNrmkdD8LwytZwzqplMh5fijS4FFflsfz+QXIg2jS7olebEzHTt+w4xaQA1SKdvAWdtOin2EHnyrjAAUXYOtSq6SEXErlLMORNt3yS1+k8jkNE0RBUYn8UFacASU2theizMQoBU5bM+ENEkbZ3ohdRKEMuIhSsH7ym1JprAg==" + "data": "base64:AQEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAE1J8HBgNQSQ/ZwFj7dtD2OFVEooj4VItPMQhtqRNNbKzUsO9C1ImuiFKLhUEzpWRbPF5IhgeD8VcvJnWWLyC/mmSNZM9dS1/9NmGo9Qb4KK5kqHj/Mb0DAe6GiM7ksVwIpnZn0aEDD07vohnfgpHRcSG5/xeD5G9fNHlO9346HsN64VZGXEJHvxEWdkpjPeBFvXGXtM9pbqB2diUQ1i1qP9W060lZ8joZGIA/PTU2y+GlCXP5WEh7fcoA6CYuebrQYF4/aEHt0spOiRa514jFHI54jbcpQxEbNFAECAPJLITLfpcmgk4Nnj1DqOEF8qQPQdYkkpzPsSv6vu/IhAlQpiveWyuazsSYFB4EP3dUb1fySxpHTal78LfsLeNYYxjBgAAAFAcQYJ3Bjq80IkYQGlRobMuZrHVChVRfKaZI8t4870WcA+2DPrv8jMttuiYGurEAP+Y5oTlQBoHuMzQTmmLOMzKjmps0sXGaTm1qyIss3xMqc2CC60VRcdEbk1vDsVvAaWwS+yns3B+uLn3GDgZ722Ak7R2pIXks4Lai2UCgmaaF74bkbbULeNB8ly6jDZl1ZToANqnpE9ExyZPlW1oJVaPNW/hZ+tZKI2TOKMWgcp+pLeIsscVA65ZFpl440aotBb30DXZr4u1RXEi1+o9X9GCb00T18SahJNy1rg6IUcc2W9Ng+cSUB5c8C8qAS1qKYdHUk7PMj7bQx1a7zqOYXuIvIvALh6LePls7Y1a/09v6iEEbCU0UJY5U7VquVMj+IhcfpvXN5iYcuqC50QPI/GwI5qN0R7cysC67bQEfKqmzf/YMYc8WUf8VBqX59oU9zduR9aevFzwdMNNNRFr+hQ8pbyJoBupGRQ1MYoLKHgsVyKJabsgvZvqDqk/3Wjuaz/IIuBWNVUMmXV/Cap+nM7vSXVynOxFKsZiupZJA/cYjW9LSx6tZP3mLoKCn9sJOakXu68vbOifl2BA22ksZO0vJXl9ZgEG9/uE+iI7mZn0aXNWiIkrwyUmWpFxY25Qeeo4tEkH6CJgDqMQ8QMfAcgW6n+//Ifzzo/TUezwoAjoUZYY7daOszTIhY6zKvDZ0O4weI3KryPDBbLwxd1Yzd04VnF/PPFTlMxg6hepb+CRfvQP5HnlKGKUQ8Uq5wLB5zvRp6vOmu2W2Jq/twaQlF8ZVOuzyfHC3oQpb5/Q9Jp8tBtlSPxp2Zy0STzNBJRcKFx87GU9Q2vbV/qrj77lqIoBxrjeDLGrSwIAAAAAAAAADQNXKeAIKXatYnxF4RvRddJ5EsDu4ittGEX3M350r81G1g686V86OMk1c5iiGqaVDRZ61tuvRWO750wKKFJxCQ==" } ] } ], - "Wallet disconnectBlock should update the account unconfirmed balance": [ + "Wallet getTransactionType should return receive type for incoming transactions": [ { "value": { "version": 4, - "id": "5c3b31ee-84ae-4e9f-8d32-3c758ca02176", + "id": "c4cb3024-e8b7-434d-8829-9335377d66eb", "name": "a", - "spendingKey": "14202ee215ed69b97c6c3317793af0558ece43bbb2ee3f0cb164df9d8eb16170", - "viewKey": "110d3c1105b91392ff60c0f2ec143ed75738346f6f3d6a939e6f5cfd0134f29258070c1c4a7f76ff3838956fa5541f9bd8e3f5127b6903fe25efb07359c9a4a4", - "incomingViewKey": "af17c73970552539f2392f4caff51cd13ca17b635e01e1957aef25a55650a506", - "outgoingViewKey": "e1844f59394714ab1dee5d294c06f4b05884c1cb4cd78e4a68d25ffa121421e0", - "publicAddress": "e76c858e25070012fcbf5126dfbd4318959d300f4e0bd9e659b0beb1bf771cde", + "spendingKey": "14693cb6c6e5ceedd843f678db9bc375ce44c7073f37c9eed6d3dea779ab8bf9", + "viewKey": "418a47bf9602431caa7790bcc6d72980af04ec20426d099a7e0f212bccbe9eacfe08b43fc99d13b7f87c7fcc34893d010ecf193e57a767716b2186f5d00cd5d5", + "incomingViewKey": "6d2e22e99680c3c63fe31d6398793f9b87454432b01ddb8482692eb597d66606", + "outgoingViewKey": "6c88876709c07716f48b19d8056980876a7cd803854f30c6c70091577a6ef8c1", + "publicAddress": "6ca52578ba0d94daee94af9fe5603043acd6efd1b1a9e8c54647f59b1cf18f99", "createdAt": { "hash": { "type": "Buffer", @@ -6270,7 +5082,7 @@ "sequence": 1 }, "scanningEnabled": true, - "proofAuthorizingKey": "311edf69e8789151f2348e5705591d1511a2964e218061c450d24c9fa7951f08" + "proofAuthorizingKey": "a8b6d0e280b9332339356cd93dc93653375ce5aa88d013394e07a8dddea9d409" }, "head": { "hash": { @@ -6283,13 +5095,13 @@ { "value": { "version": 4, - "id": "772a244d-93d0-402d-8c0d-556b3f67925d", + "id": "20efe043-89bc-48e0-8ee0-07b0fac2cb40", "name": "b", - "spendingKey": "bf5135531a77781c0c6740e1ee5f2c5c88aa96e4ccee9efc30199a8ab55664b0", - "viewKey": "fd1ff51a5fd1f024a47c8e214de1cdc8eecaf506bbfac1e923511077f3ee43899300d1e4ed347d4cff8b9ac1000734d99e828e34c20e277b6197738baa3d7d11", - "incomingViewKey": "c7f1775e88f82bc6fadfb27c3a443063aa22b9dd692f3a0ba8caa77fb2b78d02", - "outgoingViewKey": "7ac5c5eb4054140b70697ca4e896c329c5fb55ffd98e1c1b352692b6adc9710c", - "publicAddress": "7788a27f2d1b3376f6d36b386bacce08a33724fb0565d47c6a24a5d0472f945f", + "spendingKey": "202d96f2615513c2ede0c1bff0cb0e5cc2625d1579f9de24c324097913f161c0", + "viewKey": "643cc5658542c1ecce532fc5a94e099521978a3cc47b5ce1552ec0dbf8128ce3aa620a8fecad587f018946a95bfe2678912b7e5acd932cf9988d1689722e7a0e", + "incomingViewKey": "9dff42b9726e1ac5354bae32ce2462d85dd985488ca3fad3579675b65cf4ce04", + "outgoingViewKey": "1801e8be9cce2b842805bb8d05744ed4b9073d1f2047c2e718c09715892d336c", + "publicAddress": "3bd5dff2753a8a2b0761c27f468cea32effcca7fa479d66abd38a70a32062a64", "createdAt": { "hash": { "type": "Buffer", @@ -6298,7 +5110,7 @@ "sequence": 1 }, "scanningEnabled": true, - "proofAuthorizingKey": "e4407cadd714bbbda77c092f4b9409732dfcc15842945fb45b073d2793a8bb0c" + "proofAuthorizingKey": "f942a40b3b8b18debe70aae80f451b1fd280934cac610a51a82fe75264946503" }, "head": { "hash": { @@ -6314,15 +5126,15 @@ "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", "noteCommitment": { "type": "Buffer", - "data": "base64:UVEq2PuNfdEoC5os2mTh/pGh+//KtVzV9OmjNE4u9A4=" + "data": "base64:UuhrkF4SAaKe7XkXXUMxX/eU7R+6uIiJXh0LwCbpEVc=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:KMr6pfCHWpaCUHXO9ZY4pzLg/F+5HDmahXtMNExDzrs=" + "data": "base64:KCOjP37PoO4h14Z+sNC07HD8JS12DtSF95A3Yxq3E1w=" }, "target": "9282972777491357380673661573939192202192629606981189395159182914949423", "randomness": "0", - "timestamp": 1717538846941, + "timestamp": 1717538989717, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", "noteSize": 4, "work": "0" @@ -6330,52 +5142,78 @@ "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAMHocbEKX/hFqteL3S6G/e3KMJAHNNmRRKfZVlnk9mD6wRc7YCXfS9W8uBzJK+P8xTdoTXNp59/yMVGDgBEQ3/M+PWGueOStYeTcPNaqW7LqgG1JlwwtvX73WEGPb3xq+bJXPnSuALtvt/hLTBpmNUKnm1hkzgCrfk6lc92bJp0sV6t+GGzIwX5FEYIa/98a/YJGLV+rhn9nl9WYXMpvu8ARL9pAZ0h8xdmvCpIZ79amnJ6V5KVGpyvI+rgNvFzb5YEMqfb3Hqtlbf4woIFdQEDU9y4u1lI+Z0TqpJd4m0ai1/DgpKZZY9LO1Y7kKmxA8a9EreYVxg5yCQxSPq0/GoTPacLy/TdOEgropoPrj+LG1ABME5Ywm0OwHHi2V6BZTH82Y0izewLUgvi40d6k2xvv52dbz9jhKBY81GXg1OqnTQ08jE/wypHRosTQQEegdxVrGuOHLU0HAnLvIbCxnIRgnHViHklbqaTU0y8jkepAjTdKsM8IOzsIr7aC/zDhNoRKjwdLZO3rmHJZHDZ5rqKdIBvQvoUjjBvpgyFXKb2+z9DyLDGYLLAUIO7+hu1dI/On9b42CcSEtGHc6QgUWY8D1dBlO0mGqA9NZ7EiEnThuYlSW1pdJGElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwyV+jz+8x2nGaHlf/UyODXXLpoue7fUuDmziRqa01zxsa7s6iH48m6i6opt/8hRYHCLwAt2trGPejvN0liJPyBA==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAA1K21zyIuRHaG9i/n5UhbPUTahRf/4H4W+mzCiPTAqEiwbAkw8MrpIm3E8pHrRGmU2HNXJ+H+oQ49lV9NIKD2Qe6okGoHDqIaRFMrSB++FL+DfoPlUyq7G3O8cmRHYRkQt4Fnnwl6v/QDhmDAtR4FnHQYlJKnw3rwSzneEGwlUpQCT6Hbc/KJd/jp5aEhQfmkXCB+YoVB5P9vQ/8/PeXxaa9xSLFZM5riRUjEjVb6WUGxP5wJ52DZcKSd2EFmwcf3bjSmUFYqloenbkqzGN2orjOoEQzYlcMECr9K3fXXJp2o+kvWp/BR209jz872Zirvk6dBazZvMJ40LZL9IGpGEa0eDU/0aJOW2oOZD+P9Tw4W9vmhgslgWhrbkF1/d7AZj+Xh4USFX55U6njxIS0ctalLqlASWo3bRmut2K7aaj6EDE/PUozwwftYUqSJNJv4zGEfGBzkAbvmlyzCqgrt5xXzS2t5wkEfklaNOIeX2t2Q1f/qQagdlCBSQIdRVEsLmrK2OKFub2zcQBI/RPpMDZDz4bXvBfvaBtJ46bd0hkJwn79oB0+IxCw9K/tNc8ZKYrKCLsBbikw5ejvKhTanPzXGv75dd/jQoYC9XZaC1Gy2PLZ2VBtkmUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwBJSgfDD70PDdz4bvhExyqIAPyqo1n2ywSkzhWkWPV4L+DyiX06NGiIennDE2lDt3PLJ6vpbLNvCTuJp3+YEICg==" } ] }, { "header": { "sequence": 3, - "previousBlockHash": "47BE1B2BC6DC4E9124BB587396A9AB36A373166E8393DA3C22078A4EA29D86B2", + "previousBlockHash": "8F3C9A535641712B724F5EF936F8136F5BCDA81DB0CF3BAA5D619CC6290B7A9F", "noteCommitment": { "type": "Buffer", - "data": "base64:ircI02WWlTMdDjJj9Ca0t6e5NN7vTiBxmQmi3WRAIV0=" + "data": "base64:5XpURaP5TgcLXs7ttAKzKPPxuVeVdZsobHnDo2vLgzU=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:925HWtFRAfb3ctfSfvk9NYg9xQspfZWKVkx+W65mItE=" + "data": "base64:Adzrr8VU5KnMuAKnawAvcj2gZh/FhUp0FyXyK8lqUvE=" }, - "target": "9260366780148527510972123832573278885902566341756516011968728852484845", + "target": "9255858786337818395603165512831024101510453493377417362192396248796027", "randomness": "0", - "timestamp": 1717538855857, + "timestamp": 1717538990741, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 7, + "noteSize": 5, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAd60WzsCia5aaqjCnF6aJ1UydAjAz2I/pTIsZ3EVSOo2jU/SWIkYWD/J+4XSx/ExymiJXkc6Ej5Z7oT1vDcAHH66dbS3dX5QC+HxEwObJrGCEA/XjqgQ1Vdc/UnsZuEEw/ccoJWqL41gPubhQDDIXvyWICZCErjg9C40Mlpx/Q18Ksk1BMzVYJuVOSsWyVxwYgfR3EYCqFgrnwQ1Y1dqNKWphFJvpuvDfPH64lBpv9b2THjfG5A6t4FpGfiASD8tqcKJk9huNpi4QxkuEwnySxhl3xcNUablkBI7JCKTJNXVLS6PSwV6pOgZLg9QlnEW1qYYtpzTbBIImBjgBOipU1XmfzHF9UVbYz1IHyH8sihWIqHI7ncZlaSbl1amQ2x1GSqTrxZAZ+y0fSIYI9kZ6eSfnXE9yNexHeBOjCsPpQTs87GtS6byjl7AhclfkKHHx241Q/OFONj5I4E5qTlGH7F//93RI8G0nR341Fl2T7MnPaViGk+VW1068Zad3JYOyRvz0zSJa0RAu2yOmStFgVwP8SZOu8SDXtoqDrnVhWu9CbBl1j2U3i56Nm/YzzFivOT8gqRl/ZHItJDG4RbnyXQv+9JgwnRkhnEYq0569/hLbSYfCvuSMm0lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwfP+B7tcXM8iblSEyZ7NIjkA+i6DPBlebCklGY03N80IoLIVFmvSTs00ITfc4HYEjGcK8Rg+spqUoBs//SqfMBA==" + } + ] + }, + { + "header": { + "sequence": 4, + "previousBlockHash": "4030109C2193ABAD2C1196BACC0FAD459A5554B2466AB2EF45D0575AE893A08C", + "noteCommitment": { + "type": "Buffer", + "data": "base64:j5RhH+NP7THvS7URjv95YuJAxQmARx7NlsFgETIiA0E=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:3ufKD/Tu2NIj6DUMd2pAp0MHYtxGs/Wcttu0MSsshXQ=" + }, + "target": "9228823284279306817296266184515742822248210830185427859262273659833347", + "randomness": "0", + "timestamp": 1717538995575, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 8, "work": "0" }, "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/2vKiP////8AAAAAyUcbRn9SkBycLj8GjNnpdxJlegIdiiV5CiEBe0YQ/zOqMJiEGG4UvJ0Z/Zx817eRrxSXGi/AgCE0YJqBcmylwQYh9xe06QBCXY5SiEtnDzquMh3B4wkzgL6xJ+qHol5lsgmEJuv/Gj0oDdvm5Oe/AkoeGu+vJYVemvl3C2BCqpYWolxorcwum7RB+lfs3gGNlAGbytgmjh/HoM0aG988Lo3Bm3qvu50+Qg/7cBqgAZ+uAlbpCLwG7ZT2XB+GKQtI8F3KcmzovUeriiuqc1R2TfwmRmfGu4zJ4JiMJh83QQ7L3nMc5tBmZ3F1xGHAvV3Qpr3Y1no9pZ7ohrfg3dM7TtRs/olo7pJiCBOt7TdDGkBrXrte1/ojEuf5n09Q8QsMjGUmcKlyXHl64O9nc0a5VoJwjfRoVGeOPqs6pf2afGZMic74kYMuF5HI50TAwNwzYg3EMifD15/t/Lg/ychFI1hPLtHdHswV7nLG/4x61ia87dcFQGS0UO1ePKgYad+LtXlvX5hiDJlUA0DRnlUemkJCW0pyXtoQcYEgtD6bCU7xQ/S/4OnxuKZf0HFOYBiUWGR71+/vmC+l6Y8QYs1RDc2GhALw/juhwtDb0REBIwcdZEn7hM2E20lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwDVZm4rAZYBWbolDd4gzVsbi0PtZuxU/ccMWHr5ZkL2XIaJJ/mWZO1BLEUNpSwLyIzAekacg8TMNuQkAjGkwsAA==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/2vKiP////8AAAAAHJw1xcOYxGD9SzcMislG4w/p9rVrkr+aQg+SYuyZPRm1AGU5Y6frFpwXvNVKJxPRtGPMGBkHbJJfe4Fph8DLjAfxQ+4T6Smu2BwucDTn3/CAyy6aJt8zwRuWt7kjvL1qXco3PgVr1tW38pVDdDTMX4V1gNIhCZM/8xSjPly/UhURjqWieS2DuC/glh66pElUgoVH4GwqN++85C4h7Qtdepct+FgHYT9pAsUreVnvavCF2ba65DVhvhei2cnVYr1Smx3iUwemI3T/pjU1513Xh7lZPiwKgw+vpbMdwe5P1MOEyQDJrG3cUVgoJTP3d4bQ6V9q2zcbOmmM6Cmva/G7aBB2RlgEwT/4Dx5UKbnkEdZPILTpnXdEAjXm4r/HvSc9VqsYHulj0g7/KTR76fyx71aB4DmRX935gHtnmdx2NoVEE5vxwGRKmfwnIUfFmOroRXLFeAIgtMwIAuV4TPWiIVkM+xAm5q7nrhq2fJriMQjyDDFuyALoEvnqpyLyKY9VvTlkmEVS0pB3OSn/KK4HApF6uTyev6cPtwOho6zd/nl0kllfeAm2Qos4Tq5sp9tI1FBqDT8KJtThHQ06gHL8UTo0bnjqcmWL9nGmb/aI/gaJysn0Cox1dElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwhsNBOFeqO40AS+WoO72jhts1jCfAtN5qQVQ1Hf+MfbJW0wQ5B5Zz/TKrbnx3c2P5n8l9cXWaVATIjL/xePWEDQ==" }, { "type": "Buffer", - "data": "base64:AQEAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAcIbTSj5X5dwiPouHLXYI5QOajW2WwbB4tun+0Hz+Fr6oRpcakoIL6bEZQfx8AffMLLEqueiTk6r7dkUYnVs1LQ0z0Xy23g3WUx/5WJEPijGrdJ+avye65OZ1VWHuCPoQAOnn13YYhiaxLnWxjiW48YofBdDpkX/r5kvhT1EO6SQZJ9irTSn00O/nFq4CXxcnMRq/DhgItM9WCMIgiKP3VH+N6fnznBNtXVAZjyjfrKOvGE4qQrNdvv81Zsx9CTbR17OEa6+NAN25AJLzw/MiO00aufLiI74U/UyFOej6UcVjsPEeVxtN9GX0PbtpYCVG1mvF8QJjuiT8ufzsdjByJ1FRKtj7jX3RKAuaLNpk4f6Rofv/yrVc1fTpozROLvQOBAAAANpXX8ersxpuq1AKk7y0dOwLYjGJ2ZWT+s//0TfZkvGzW1tbnHYgRX/W+FCIjcOcG/7yJY4o1kJR09BMQ6bvD1CZN1MVKHtFAOHpcg9eP8lWDo5NmEz6SUKfHzAS9JieB6SZ/ieVeyT/dgP9FnG62ZuGFSeh5DJuT2cpk2d6y48fwMXJTRdsj4eNdHFtkGNT74U6InHGMAOU33NyXMVC8dRuOH3U4q1Pglr7EJRxJFqkoK3OdVOLb3Xia8eTTg7qORF9mIZpP1ZrsILlKcDl0lOkCymNLVyCSAbFDXM3JMOboEjr+x0HQ2L2APH5owfDn7dZpcYResuup2S5ZwDSXnjka0CzccXik5LQLMIENsjE4gyw/4qQNY/J0HOGzMb4NfFK2lkUWmahs2KCARVfYncdfoaaxiBDFb6AsmbrsA4AEXEhmUQFJOudAUvH525Ef+ymLd7A5sjTAQX+6GmqHCBan+bDjB04PRJwLzTgf4zILtKhYYJtLYWdl79pNCYCgIsvmnPoG//nZ5ueBd1LWODMb7nUdXgC40lQ+yxu/V6i1/OquA4OGJ0Ih+bltKK1qqB+4qPyLHUXwhKpoqQa1uVnomVxLdGA76RW2NRAJHaqfvhJHoRxmbYFd859/ikFXi+5dXQwEVQaeK8NbUFuVF3hKIAyhqYlvsV1ziBPqs+pj2RfDey3qIvmB4kFo+mLqi/cC0N586CkH64HiQo+vwkP1n6xSgc5FXLTk0Xta0Uw9oGSgvdqgx23bByfasjCm48oGwoVxkWH6uK+LcZUPeEqHKci3lQ7l65g9Mf2FpiS0FbcjIlt2Gyl3j6KK7yvgToJ6cM7zwz0QhJJho7Ua6XamJpS0sYMaRRcoM6IXKecVXDFjbhBzW6IRasvSmuG5quxculPDHm6S1cheGSZA3pNTz4gnT+F1yeW68vBPPzRUYkpMhLf8LkGrqxN8ctozcDJghuZefipRb2n8NDfrV+ez5npn9MH5asGJx3C9uHx3Iyv4qWSsL2GORZuTnSBmTNrHf7K3wyK3JusG1p4Eh8aqKYjqOyzkX2dwQJ4C41uwfCdwRsLXZbYKxpN9NX/SdpBsaiWUbQl1ocq1QYBT53rSc7Ngh2QkQWMMisdp8a3KIdxdPwKxJuhevcs4U4c4nXmtObcmJ8DKzSF7uASm3ytjYEiLp8KQvyxslRR4NqDokJcKLyCAB1rNzpGJeI6sASXZKWP2Wa8BVDGj5XcsTICrdAOTi02KRLWuUAIYdX1EQJ9k5hGkLSupIbM4iSO0cTpOEfeaHoH89NBUL2tqHcq3hfD7gNEBSYWjX471RFI1um6/EOeMWl5yyXHZgRQTzkAHjgrsHouSsmrtRwddNWYaI8/kFV6Z9W3fZ1zYKhs8ajcHA+GlqnFMF/jiErw1tl/5XJPDRBq0IZM4V3amDiC/BouZpwmQgFKzI0iGxl2qHIBjPFRrXDHaKCBURrH+876JQWdyWa2Qof2PNTa+5IhG1fW0fKW/7sszZUFSI36muDfed7nlnCCm9/EDI6oOVjXEmURVSoN/hOYp2Z+MuasGAFqDo/frtoh7sdelK+j/325JHVg7kGmb3g/FQ2bCA==" + "data": "base64:AQEAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAU9DQfBkBhR+iUr9GxTbNVob7ycwXFBHQbXwz4HSReCCX6487hT7JLOfPVdd7qyCeaGFRLssZkBw35LlN7TU7+3jbPMxOyvXwBmm2KBx6QR2xrREdBUXZZlqWgvshWUtDQ0Aj4C0Vwcj6H8nfb9oEVCsKPSLQeO9vhAC+n/hBIcAGS63PNrJOm/pABp0KGelVKEYSQ+AWz3ftbfqiQvVOXaqSt8OIxB9qaOBor3kQ6umTEc1Yxll6uqsTEVz1SKlNG20UMOdpQwjGzFi+e9ehrmSqUXun22UG1fIWg04emtgZAbF+NXSrmLZhkuTr6Bp6n65GmGLFYoy5YgUN4el4guV6VEWj+U4HC17O7bQCsyjz8blXlXWbKGx5w6Nry4M1BQAAAI/SmkkM5k4vLO5PR0Ph793f8pUZEC+ILXBXOTLdd6PhP5ky4/WcAgtGlHtrIh9QAuW1FFUgXyt7nkMu8QWkx7zDhcFjfczgrbRjPcjTDeRZKwLGdMgFw8geqHy1StLPCZcJJSKZJqrMga/H/S/Qw62bSrNJOI5SLQz3mtLQSbC0/A6tCuYSYDL4dAPyCd6sm6gNoi/vb9UOfmE6h6/Kvi6wayxUp/7wr5+M4Sfe5lpLW6OZCaJxD9eC7eSB6u1JVgzMFGHHuGihZ0hbx42jD4mFLwKGxtytWLnYH2qO8G2IkDVdx9eQQH/sX1SbCbHr3bU7mhf5zJQXuZAgChjOjRlpSIHWWVgrzuFt2WCGsGqTaszU/k9l2O0pXqdHm7cysZg1uA+Bo8lZ25lAnVMJEZorOi/VcbD//p9DxYXpKbGs9F1/9c8/hJkOcT4tIFaxZ9vWMEaN2Mh72PnwV5+Bg2s5HjgK1ztIDMOptjID/WDgjGmT3bhkRCpmsTJYQ3jdn8cPa0RjriTVoMzUMVWNYl15gz9Q+2CDtoy3+bT52psTQeLSpNo54JtxGNCW8ct9v0A/6mCf/9nYsJGIe86Xez9J+R6vAplqTx52lcqc6tH1VhVrzIEZELcslXEMJnjVISJjA/GHf89FTunxkopoPS0aBCGYlsfGAsv97340psZuF6j2xXJh29MLPj1DIQRoQWBY+b5oMd4nDemJuN+rYqp7oq1Q3MS2yug3nvVS0SDRHgBTK2AfRZRU0yXJUiyqJaunpBjtq/1TWVM/TRjsuKb0aJe6cFn14tnpunkyhx0YfSP2YkDr1WmQ3Pqhdd6lj4Iduk/Og+LAeo/AxaqFueKBED6ZRsUaNxPzehA5DZ/n6xs3AQv/3naEuSgmRhW2QF/L2eL245ePYLuLm30TdjdgFnA4DSeMbEjujtfq23iPEyt3m0rjTbsBJOr3FXzyaYbF7dnfjsIaoUu+Bar0A3OfXJBcX/3zBLUj6VNK+A0WX7ceBHWtjayVoJfyahmj/FYAFswYsa6PutSHgQ1mq+wD4vZIFqeMFelynXWWz/aGjOHZ0AHedkLfb6HrR7Nqd9HVO531fRDytf00wIecZcSPFvSLWDestcCMu0qxshKf2/t99OLMFWzwEtQyZNS+hUGf+1I5SgRMI7vY3E0SmA5jDXb/EfayXxoJgDxedfXXrqeO88zeFykcQoI0DV4Zts62pZ98rdLCzV2COQrPj6Eu9bLqTImHMWrAh1+tVmyotnz1fZEpe+8eWFznAL8C9l75eBKSl2aHTlrsUOvdbOlCawP4XQ0SK9jtaRzwSxE2ibBRvt1t9FGB36D+355NlXK8olT2DE9G5I6uC20KN1+StDZGlyn931FcziYp7R1Kc05wXGCFIGKlwb6kjyZ13IMY2mzP4LzWmycg2owURFgdXCL9+CUGO3NaBSJ9RzlFUunq7xLqNoHLz+PrNxTmKFFXlBVyGoD3hQ5/W7bfGi/C6U9pAHInIgjId+kZnuiS97ykO8+veG8387640rOLWl2QOZ7twQSfJt2ytvPi6gHPJ+5ENAxMzpnfakuThJZjoVtbfITANU4HRchbzlfYAw==" } ] } ], - "Wallet disconnectBlock should not disconnect blocks before the account head": [ + "Wallet shouldDecryptForAccount should return true for an account with null createdAt": [ { "value": { "version": 4, - "id": "06c2b10b-d498-470c-bc22-724c216023cf", - "name": "a", - "spendingKey": "fc8ddbcd9a14a83bb10605aa95d83327f72c3113f1e0c385c2142bfdf14ce5bc", - "viewKey": "fb1290c5fb54837d30953e67b8cc00facb268e284af9531716846f9ea0606b86f0b7241488e5aac31e9160371939c203410bc7fbd094fae09160bd0d911912ae", - "incomingViewKey": "8a7496e08240c340567d2689c03fda557d0fafef3af918b0cd23bb6d2f637004", - "outgoingViewKey": "4ee2db77355e1431706c7cce644bfcb43c102a7d4ebbfe5b5ea70685c17e3a5a", - "publicAddress": "cf135210deb44de9cff4bf804acbdb5ecb8afdebf15642b16b98c4283068d62b", + "id": "ab5b44be-38b3-4c52-8872-8f93b269b817", + "name": "test", + "spendingKey": "ba906d52efbd927f0be11d429358919ea1c87fbb7a4498f8e2ecd046a2793a71", + "viewKey": "fa278f55c53812b3bca2ddd7c0878050b6522f9f87288c3d03250fba9a5bf236fc5e71eac8694878b8c810d96d5c5721b9f1b3507a86eba039e893d09092e89e", + "incomingViewKey": "74d4b2b2c1cc39f4097b90c8b50a3bae0c85c04a3e588e922a18742b70b53304", + "outgoingViewKey": "7f7a01e7efdb53e7b4a12ca4664c0277429205c6b21e5532965f6add9967f36d", + "publicAddress": "74f189128d5f91e129af0bd86d986b948f21ab00561e7b47285000968b8df845", "createdAt": { "hash": { "type": "Buffer", @@ -6384,7 +5222,7 @@ "sequence": 1 }, "scanningEnabled": true, - "proofAuthorizingKey": "5116aad81f2c1c4cf7a0132eea2889d7541554b366731a448c9a656883718607" + "proofAuthorizingKey": "d4da17a97007808a389d636669d59efcae825d66cced3bb52c813e5dbf9b8e08" }, "head": { "hash": { @@ -6400,15 +5238,15 @@ "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", "noteCommitment": { "type": "Buffer", - "data": "base64:oIISnC5yyLhTdHruf/8Hp5Hxe87Gpu1+5b/zg6HbHCs=" + "data": "base64:Ye223RdSL5Fj+ilufxi5m1pJ2cQEP04YtZP40xumgT0=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:zspW61o33712G2RTjQUZMzo6yzNBI0RZdWfZOz1jsM8=" + "data": "base64:VuyFBIxcZoBgF75z/D7ExBC3xFJKkzk0ASQhfIm5fdo=" }, "target": "9282972777491357380673661573939192202192629606981189395159182914949423", "randomness": "0", - "timestamp": 1717538858455, + "timestamp": 1717538998177, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", "noteSize": 4, "work": "0" @@ -6416,48 +5254,22 @@ "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAR8+NW8/ifVihj/Yv9j6yald53BZyqmYv2igRjH9ljKi1o/U3BvFG1Iq8AuB3aVMHvyMp0MZ7qEEnON3bLbHKZgDiY+d/z5bkigCRNZnDjAezmDeaOcIOMHCRYUav4ppMzAcxr6HhE7zEiyDadJmgv0I3vkO4uaCbXNcHvFfY3hQRZkF+uOFkyqGjGwaNGu+KUyRvpc6fNmwAvPzZ/oQyCBR3zqihtGHmKUSgWojelVSuwDckcHDOdzorpeZ1o2Dk18xLQQyX+UB6g7+L8ivG1h7XoXzfH4rucoC1qXPzvOKdaqOyYjeqhSbsPjdjF9D59k+qyC3q9if6DNgO7dK+aubmU0r6cVaTnTgY5wi2zLUnPSCTRABQcRLi7PFv2sEWTcQeK4JfP2FooiLIUCb/KvzCjoxpxaNOFUAV8HBZkC2D0umxZ25FYMHlVT+eFB4q0iiPpIgDq+UlmzYdfO7XWLNM7eQJdHaeQBM77CHWJ85m9iwjedg/ZGIkch7dv8XqnbqnR9BwfXng2/FtWZvFFMusG8RGck9Ip8aEwIZDdfdszV1sXCugq0V86iK8vZrQXUs+Dbg0UHUitVkC+FZ1QorTp+pCun7lwE1ngQpoajc157Rcfnx9GElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw8WA2ieOlnP8TotfkvOs4SQ1gwScWSFnFjf9kqaDuvMTgKqJy4esCCZ2NezZ0r4P+sxeC4cNv2qmW5ZJ1UJjtCw==" - } - ] - }, - { - "header": { - "sequence": 3, - "previousBlockHash": "D5CB6968AF11661F9A7A785EDA2CD889F40F7111C3E8BCF954459BA888B9DBDF", - "noteCommitment": { - "type": "Buffer", - "data": "base64:TyeNFr8FNbUG0C2wCQe5jv+8jXWOmJVNSYIYkPiEmlk=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:QY2eAdcGiBIKWdRgqsEVtCVf2BWf7X//E2T080QyOuE=" - }, - "target": "9255858786337818395603165512831024101510453493377417362192396248796027", - "randomness": "0", - "timestamp": 1717538859907, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 5, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAATicJNlPBMAX96+ROTIYVSblPyu41TTNrolZycYj5bMuT3jVrwQ8X3JAFbQpoCd5yANzw3KejzYeeOb7De+SAi++JzIn8R4CJeN2U4OTPSS24pMv7EZM8E4Nzhsur9rYpV1Bw62SpBX+At7hR+Ywm9vvZr+VfnVzSkl/gphueVu8LrIK9U4OiK8YKZAzOLKBXrS16NnFQusF3A4O4s9VByv4oQUYk57nuYBctWCltcYyOwxROejWRPJRRCd4iEn4vPlhRFU2pJt0qs6JOL6seev+5w6NtuNzo/fCCu2KF3YS7OcXT1mqBwnRfE4rl7RZLYdemjR4vZXjtK0e+VJxm8tE1hT9WQpPrgnR0bTXX7VR+TmBal2ItKvpHfWgKdGReA4TYP4RgeXYvbsLlWOao9tn9jYjUMFvPPDSVTeWog5rcT4C0ZnJO5rrrr5XVB/MJNNBNxUiljLq/ouMdofpuUwTsvbNFNeB3spanQiolE0WPBpESEkjDZcAmyEi2h8Y9k6k0IzdiNO4JKUAPAfwH/UUlP9m6D7iju5UUpgT13KsVC1q/wEFrYBjOsXZVfN6ICc9mNv9LEdMhJt4QzaCk+4Nuzchtf07GuZW7ZMuRbDhfQtA6lPTd3klyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwYVlXXBZYDSff6CVvwOFkKAIMRuRTMW12CxDW0ZvMBoOlDKU7N0UAeUpqk/50o3qQlry0hDp7zR9ztF0BC2V5CA==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAtaBpU33iI5phDHMDr379VGMo9mtOeclLnyNPE/Gk5DWD5XURR1gDcbaRZ6brJn/o63t1yIvzMq+mFjGuFOksTn4Vc3VUMFbNJcRAI4x4iBm1EqQTd5sA8eaSeb9lz0bMpT/fXduflL5uKiSHJ5WIlZ5zeaG3DVvH5eirAN9kJ2USZ9YJUA9SsDK/wJPlqVm7BL0/ph0kJ/UXL6pQawgLiHy7w0lu+wWEtX39Fc4nnB6ZsY6VSb77x5Jg4CTrX2AK3unixfUmZFKutH5d3DkGYKLwfIoIMQmTx3sqlbHHeHhCzAJhoLhYP9V3FE7rwc/KOjMitlzx3tfWF/loGkfrz7nWbaS7hEC1n60pu6SWwxQa1ntzfbFCpDfghO1CCWkrB1UDDbAZruUIuCLu1gqGGD+NLZMLed1KvcYTlcoGH6BHKmP576imyeZbSQHLkUWBBQ4pIAa+gfejAcE5asKsUt5MMjVa/LZsbt32mW707oF/ZLJgPOmMoFufLww9EB220o52pYQG1bGshC4agxJik2t936biKrUn+cSFDx7ODmpo18U4DyfykcxwCLbrcYkMoHX8HmyiTzhc7NIh0P95WpvuyUwg/UasBxNbxb6mHgzjck1zZQ8MIUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwVBoeIcfVogURg03ma8kl1MPPqMaSumSYTJLxHHmyK+f4idC1ofgBJ5PJsOd8NFqNgWb4t4NFwv0xkcV9jdloBQ==" } ] } ], - "Wallet disconnectBlock should not disconnect blocks ahead of the account head": [ + "Wallet shouldDecryptForAccount should return true for an account with createdAt earlier than the header": [ { "value": { "version": 4, - "id": "d985e9f3-f52b-4032-b73f-2749d94ad877", - "name": "a", - "spendingKey": "341da00743442551cfd2e4fd4b68f3b2a301e29b888cb1db28dc0a67b266f86f", - "viewKey": "ec6f5f4687cd114f2c7f8ad0094e23ef9490abc9690787b820ab7a09dc6c54590a8e84c158347b4f731992e730499294869b077f44d936e47f9403faa6be5098", - "incomingViewKey": "f636c40ba00c10270a2e4f47e935ad31ee0a5ecb382dbc184408aa0ab1402400", - "outgoingViewKey": "6bf7751d5aa48ea23c6ff551afc76814e1ca5da64e6f50506505c115cacd6272", - "publicAddress": "3ad02fc5efcbb82261f4e1ee206e30125ec84b708ca463f94cd0a8f60422b563", + "id": "e4e8e6e1-2e12-4718-9113-80c11fee565f", + "name": "test", + "spendingKey": "8803cd390dc21e390155bcdb76703829be72bdd0d34883e9767b3e9a7ecaca3c", + "viewKey": "911c59f20fe23ea928efe890c6a3fafbc026008bc2efd219c61b76a2515049038b81f13675c60d7a7dcc024027dee03d3680e79c39a5067814f90fc9dfac5b41", + "incomingViewKey": "ee7d2844f24f69e6b7ac13b9016cdf6ebfd3281ce832bf9aae209485bfc02004", + "outgoingViewKey": "494d3e951b10776159af788756fc79169babd1c44674fd36abcfade121882735", + "publicAddress": "71fb7ef377bbe2d80361b858ab2d8cd2dc526bd5e1591f794e7d213f890d1644", "createdAt": { "hash": { "type": "Buffer", @@ -6466,7 +5278,7 @@ "sequence": 1 }, "scanningEnabled": true, - "proofAuthorizingKey": "f3291c52c0b33405b81cb6a60460c3678a169d5ff146e595794386980f77f308" + "proofAuthorizingKey": "b8510ed4d78dab26b05034300b9192410c0f91ebf109c60f9d3261835d5f960d" }, "head": { "hash": { @@ -6482,15 +5294,15 @@ "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", "noteCommitment": { "type": "Buffer", - "data": "base64:h3iHfNNoqk3ptWzTCvzNuUgKVkB5Ih+6h6qosgoCuWU=" + "data": "base64:CrdKzR6+2LH4Vt+MAuJNoo7NDeOEBXMeHt9dh/7/zhE=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:yNNo/jHUN0qcdfQ7tay/7TRILJjOnfBcPL6Am9fSrXA=" + "data": "base64:6anoi2aMrsOrpvlT148T0G5FALnPyYATB1ycah0mQx4=" }, "target": "9282972777491357380673661573939192202192629606981189395159182914949423", "randomness": "0", - "timestamp": 1717538862519, + "timestamp": 1717539000204, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", "noteSize": 4, "work": "0" @@ -6498,48 +5310,22 @@ "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAA+kBBR3w2770Gg7r/fUAdw93keYoVlRD+i3dd0fpEl9quMMUyYja2ZtZkSKh0yDmbwYb0g1tF1SZDkMSHZqyIUGZyzHgzRZmo7MsuAFSMxWGVxq3HzE7gqa83E6QLdXc3CwDHV9FqO3uCuqUlPEbnntJeDeA8m3+ikD2K+e32iDAUncE64viikd4bxDXAFeedJEVKMGvdzHaL5LoLAbQpqHTE+g6DfP+HMNE+/QAtgpCJyV56kPfxB6WJNi6RxsQo+CJKwlRO5K9KPwKvgH3nUfH0J/+eVrAkMr4ZOdyqICkAlfCHfsIJYrznWgNYc4vROcLATnwu31XwP2opVrHYsGyRpIm35gpc6ZC1oXri4pxRkIXYVdmzlD8J3buEFhsQ8U5nDBo6G9a6PN4qbZaCXAIMXP1ZlnariHDjC8m/xgTZ7k3xeveOS6WIRQCnOk0Hnc3aKIRAhHoRy9WhvLmcxOcsDWKz611NnKdYakPHtSAn5I+8GFOc7ORl251FuNXU7TdO8mmYs8dRb/P6niwf9hri/xfX7a80CHpvcHkaSEe8OIIqw18vsrEkk6aio03y4HHqhW9R2nsz+EMz76r3jCvm1wikvRrDVOn96dRiLbvyrx72bJFX+0lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwGs7nTOeoaOvIMJvM0DyeKLMeuJWVRIspaww4L73ZdwNfZ9Xu3XjdI93Yyn1yHWqGh23rPsoV5udQdjBUBJFPDg==" - } - ] - }, - { - "header": { - "sequence": 3, - "previousBlockHash": "E48E0FBA10278DAF09A70F9A42BB91111FD244BD9C1451BDEB6B84EC3284873C", - "noteCommitment": { - "type": "Buffer", - "data": "base64:85xP01XjV7CBMD+YPMiqLt5Ta1jsRI6avi4oScbg5Dw=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:bt4ip0u35BNrDx6veGbcrD5MBei91dNWMiZpQbge8go=" - }, - "target": "9255858786337818395603165512831024101510453493377417362192396248796027", - "randomness": "0", - "timestamp": 1717538864120, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 5, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAJm8DcH4rbB7Ll1Uod57AASBHE6oNjWuNK5imEIyNFGeho306OydbtbVn/yk3uhLlODCsxAticOKfipAUrH6ZIBMaHAE3hkSKwejHx+gOLI2vcoKZZu7r3wdQZEjRsJPtOdzlLFmkk+X05/BjXjmKUpBtLlmEKVDThqhe0wlmmlsNNf2qWxwQ+gaelJbS7E/7HaAQ107V3eZsEntJoLErgzYNsocwAvRNXloDTsJXf5KyxVMU6Z8pIF0TaTLvldZkjeDIwzVWAzhphPOOoGNjmL/QlgogcMn4fMxQFSHUII1+4ykj1DNBeroMvCva7eQdX93LspbrLbMXpqU63TPOWiFYPjH/2Igk6PzIuFMIZevnw8nMgGLKJTrUvPVAm3gOXIXHWXo2J/4m2mwyfhp9pT44e2IHIObjRlhLLsf9PtEo18iPIFg1ZsD44q699Gs+4nefmMlOm1XGUOOED7jmKweY8zbsWCkov3jAtbnbRNcL69eLHZ6Gws4f3ZXY4NvKmuoqBHz7G24JP3CopSgPamgUgIsyh4votvRRdl3ypIwE8qvNYvjPsbFVtA8yWU2FRq9iINZW28YKsM7N2xJR5GxBpgJYFC7sqrbSPJ6vWIQ0O7LwND4RBklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwYOzxfJdc6cI7qAXgjadd9STVhj4CUYgo4+deMLXXyZdfpcL7LSGzvxy0r9XdFJgBtFCYKTr7vrzATmpeh7K3Bw==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAXW00UnSpuO8qpo2Jyg3B/tpZdqG4VCXnE21y1dO3szKRW1IX+QU5tTiRscWoIIrLesCowNl+UW+H9Yh9c2f45nHsQ/UJMXrWQuHBc9B+SJ6luZht+E60UMdqZ4AiBwKyWpW8qcPo4W1huZaRjjgYcGA+0Hg0dPCOeEFKyc94wXoZz8eED57unrjvPC76XQJP8MX/15TOEHpxWEpvuprzT6W4lkHbFlDS59bzvWH/ENCnikKBV496LqMVOhiLvxPYChvccj4fOOgSYRLCIhYMS+n5S5XXC4xSI1JlVIuQDOcwsO8orzhg91Lo5Usyygox91+tBlHT5nUutTvPohwJ7xJ/1PnOrxgooYr9izO2BPGLCCdgeshE6k6nOhFoYsULxum0KMGo/tpWqRsKwQPglpenbW/M6IqBQQ2ZdOVoS8l647TznNHsmY6qGgThHkLS2yFqg1F3DDbTvSWXeUlA1pAAMF+TzD96lPWWJxh/UrYytkUjZyW//tKmh+OacfIaXQvCQ4bqO3a1jpQVS3vpe9O5Y+2DDBpdANSt17LPTG0/vuj/aH4E6EIDXjbMl6EWWEySd9l0M+H90qZ5yJq8OxeJj/ckuwkp+H+Qi2YbtMH6zgllwp3k80lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwsDGvyh14nM+TXNBMGdVKsRDxztaXSWvmYF5o2hMV46DtRKUv3XCBNq0mybrGxc8eC3YxvrX3YhCRaIVV/n2/CA==" } ] } ], - "Wallet disconnectBlock should remove minersFee transactions": [ + "Wallet shouldDecryptForAccount should return false for an account created after the header": [ { "value": { "version": 4, - "id": "9fcf3b16-1c4f-4a39-8b86-2f3fa8072833", - "name": "a", - "spendingKey": "9ace62028db6bc54d16c3773f6d42834e008b24078d7bb5401354afd15e70040", - "viewKey": "eb66405a64ad09358f93e9a38c3467b4bfa0a7d945ce89b09a53682049024803baa1a59434dfd01f668da5572e6fe80dc40f0df4fe0acdb6de36fb1e16c09eea", - "incomingViewKey": "0c6d858f2365bf1de92b145432f2e938cdfce1fa2e0e9168196b603b84645e00", - "outgoingViewKey": "9ed004a9bd5c88b0cab75aa01c29916a40f67a07d3c0bacfaac041a5e06d7cb5", - "publicAddress": "9a8787574625ba72f6bb0707dc3d055bf29b9810910f0e75ab20d64a1b0e2610", + "id": "11033864-5f47-41eb-b7b5-91b713a63239", + "name": "test", + "spendingKey": "a86f0e2bcca2fabd80d36b0fc5095523f3161e03d179634f2b8a8b0aba30edab", + "viewKey": "117029994f58adefc5f0ec01657d85e6eecbf6171186c493d16454b47d7f132d19992c4b5b8ba70905516f365b9907cfa483649fff11272f6600df2af631c1d3", + "incomingViewKey": "d64cc966ecd93fea10610e78803648f34b2e9d084ea9dd909e4a06b8a126ba07", + "outgoingViewKey": "851ee2cb193f56a66e242c5d2ba4ace7a653fb1d6b11476cc78d98e1e0d3525b", + "publicAddress": "132e02ec40e55f3f0b5e53721f41539e2559c3da3435a4128e2de74cc6ec9bad", "createdAt": { "hash": { "type": "Buffer", @@ -6548,7 +5334,7 @@ "sequence": 1 }, "scanningEnabled": true, - "proofAuthorizingKey": "c2c64c5284b54d248abe1bb97082323ceae5448b78f1b647d24095a882453906" + "proofAuthorizingKey": "18813dfc16bf034f84e3213c1e7d10d2f5b86da87d0520e2e063b9c899095409" }, "head": { "hash": { @@ -6564,15 +5350,15 @@ "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", "noteCommitment": { "type": "Buffer", - "data": "base64:BK09Iduh+yZA9TBEQBvakLm/dVaT+lyl0St9px8BgUs=" + "data": "base64:oL6ChZ4Ly5JPu2d4tRTaerDeczEoWTNMR8BPSdlyC18=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:xLnOApyO6msCHA0mKFC6QfObZRJcZoqWL8OQNfrQo0w=" + "data": "base64:7pYycxMVG5LSCil+Dr0/ffdPvPBzSKAsJ0BS7vt6xTc=" }, "target": "9282972777491357380673661573939192202192629606981189395159182914949423", "randomness": "0", - "timestamp": 1717538867634, + "timestamp": 1717539002251, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", "noteSize": 4, "work": "0" @@ -6580,22 +5366,22 @@ "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAArBIIeopY9Le/A5S2FpsUqFDMU2FQuoIDG7SJVsnKfDaAzymoWjz2esM9yxhJedrKeku53CULpASR1jDhQTsnHf13h4ZkUlFC7wJ1BSygRsCZv6NCdwnc1dNb5EZKymY2kj4sBTmS82T4xnyydkfhCaNaWKZJz/9agL0WkUlq+JcAURDoGQ8Wua57z3XKuUqTEMXYe4AsXvfbVVhO60YRIM7tGC5DPiDkLDun1qoksBaKYMxmo+LplRYE1NYiuSb80RZEdadBeBmRgLVyEx3LxljFCLYHW7xUpYOr+qYRoVsl+RCa0HSXrn0mhQKUYB06yGlduKN//o3gYio+wW/tcaH3/rMIa8ZkrkTQ+nzfDAm6a0J12VDrSAdestI1LTVxMjl3hLpXzvtl+IfFVFfEqgI9sDYq72/bDF8mIF2xUoWBllYhuq8i+YXxrLrtcOkzJ3G0lfEKpwxfB+kHS96bValK1CsTYXHr+jbI2DTcQFvE2rp7fj2rhDNymgPCO5m7mkP9bwNR4xvjGThuaR6K0eLXdc41MCsSjp/S7nGN/ae+LRisyADv6N15SkcqIHa6aJYTHHT6Xlt1j8XHOMhtkhFkCYr1RUpIhCicQk1DTmK7TSrkfeC4ZElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwRgirMlKyM3DQ1advz1sstRkruHRrxEtjQrNQxq4/uy2RWCPXbcHPlunyCO63S3hTvmqQFtSjyHRspyQhJGdkBQ==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAQWhZPSMc2rjX9x3Tf9wVm6W3XpdQNa9FrLxztLw4ONG1M+OLlAZ5n0ZrAZnbgrN+/RA+wisQNxN1gmrHoTO9GVFCyCCI0+mPEHK2PfdKhP+o65UGd70/+DCVBgr/b4rLGcKI5lUECt7nulxLkadWfuIjgRxOPUwunu5Z0KK72/oFDtDef3eUguxBTaQWwO4Z5tLhSwHD8ky+btDYX/4nahaXmataGge/xfnc858XyMKkVHE1KMssIWqATqHVz7rjjdNP4ViotOGY+0Y+6evAr9GvA6QYpa+cZ+NyJO0n/7qtx8mYb/+B/kKWggXOQdkv5YSemxqRXCwV+NYJ4LW4YflHA6iH2c1psJWW+p26lYhHPQXwd7XpRT9g2okgsaFZNr1QlrfNx/qG7pRBYYAIvoq1Tj+rWQ+3q8ElHbXDcxLaSLJgRk13O0deztI5l8tN/134hG7ZkXM0fVKfyfZ6ausW1CB4z6Ql+vTrD9k9IFIUv9qHMK2xfZzhSV3ar9cajxK4nqOPJ/73vnJm/knl1bfW5iSZu4cJDq6hbU2bLNx6f2vA4LODEyWUak55wgFel/aJ1BQreaqYK/hmRPsvDz9CCERiKnqIS3zBsMafmjmtvjgyb4OzRElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwnmC0egssnuPLB4XCtvfHNXGqdw/xPf3kURrN9kQeTSV3UQJ5XhZnQs79BcZ8FbaF4GhfxspKbm1mAmxC0ku7Ag==" } ] } ], - "Wallet disconnectBlock should update balance hash and sequence for each block": [ + "Wallet shouldDecryptForAccount should return true for an account created at the header": [ { "value": { "version": 4, - "id": "6a5c48e9-63b0-4fee-ba88-1547466299cb", - "name": "a", - "spendingKey": "c0ae2e6716930fc6837ff659953d4416cdd0999add33c4a6bfb7b748c5d5f96d", - "viewKey": "a7c10ef904c8865218ade06e4d57697d6aa04ddc6a7bce052c14a559ac8ed8425e14852afa6c3ec155f082c50fa05f35c6b679a3b827e8d6f3e537c0affc39ef", - "incomingViewKey": "42594ce61502059464feb01764689c46fafcabdc62d178e0888b1f4fde333505", - "outgoingViewKey": "e250f39b02cb196bbbe57e381ab199ea21ae82e9dfaabd95f82aa6dcad713e5f", - "publicAddress": "135e42de661dbade17189fb1b52ebe7b73af3f00b0a22236468c3fcd5a60cc09", + "id": "22ad26f8-6324-4047-94f6-6320745e7664", + "name": "test", + "spendingKey": "5f65a8c9dc83cafa7c62a9831653e5c14131dae0c217cdc7409835145ceaae3b", + "viewKey": "666f5d9dcadaf6c5395eb11cdea1650879e36783dca34683635e33e6bfc543ce4413114f480e2abcbd0e0910d2fcc37a6b042129458d282dcc3477620c24eb01", + "incomingViewKey": "31b3d71788afbcccdf4e8b1aafaee039bfc41bc768c6d9dc04c1774f671e1106", + "outgoingViewKey": "2f1b93b172f76c3cd8db1e33fbdb4d09ad2f56e53b8756496201f8e69f94cc20", + "publicAddress": "3c0e7e7752ece79518668342353f58c0e2ded73c5f8ff59bab2dc934a650dc5d", "createdAt": { "hash": { "type": "Buffer", @@ -6604,7 +5390,7 @@ "sequence": 1 }, "scanningEnabled": true, - "proofAuthorizingKey": "7fb4be33957e2929393f676c52a61da3fd30f7d07cc9e324c63ff7beeeaf5f08" + "proofAuthorizingKey": "a09f3fc03ef8e59fc4b7f4e5c90f920ca113ccb6572761da439cbb0bbf6cce0d" }, "head": { "hash": { @@ -6614,16 +5400,44 @@ "sequence": 1 } }, + { + "header": { + "sequence": 2, + "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", + "noteCommitment": { + "type": "Buffer", + "data": "base64:neId5as8nWnh1dkeNwfT60oMa8Eimkjep3sqjDz35Ew=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:xfYXQYm39V4hSkYFeMAWOI25Kw5iUTCY3bRCmb+6D88=" + }, + "target": "9282972777491357380673661573939192202192629606981189395159182914949423", + "randomness": "0", + "timestamp": 1717539004596, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 4, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAQAvre+kQkIaCW7kQ1/ZTGhm1BlX0yfJDob4ZNUEVx7OYjqwI9S9DEnnPsw4Ui6sbYbhQ7UK96yCy7MrcLvTogCAVEcpAxvhwSh6KN9aHglavTbp2dovF3LzFHVKjwM6W54QY1/guZlg9jsf9vJq2to2F6KIj0iupDgtVWZL5ZykMv1/4c5IhCAbFgxCbbmfwn0VHec7qsvoID+NTnxbozPPgDQuB7ymZrAafEj0zHLOuSpk6bIHUYHoTyINvdI82QcfNpGVI4j3bwyQoiHYoOWNjBsnUa4Fzv3L7uFAQ1djs8Z1eH8W1056B/xMzTf8MZUbA8s2DjrXdM4CSRubuihtUBdtzNyUXhCVDbEprbHLiehM4RAwbjqo2B8WcLPxxRsezfH54n+iIo60PEnjm1/eynKLAB2cBzJwUTnb3uzfSIb2M/lJ3S6RTXWKdIlZgKqdgTcEFTil9l8/5CV+kuLnKiUvvd0tzf3UxXIdgsyEsat27IRfRTRYAbhI0fWbIRUvy8x7dpWO2sfCEHIJrITqsk+bdztvywVrEeLkhewdJ6PrX+6j5M8Vr9Vu8iS5lLbSRUCqDwNTaTnRkASmqeTUcPzGiVQbMmt5UhSE+O/ail/Uh7rDqpklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwyocN2WaEeJlxznepvq5LKiCOcApaZIhLhZNlyTGgi4TQZpRqPbpTMB8/aTS7bD7ES+29kxkULU4fhbyekZinDA==" + } + ] + } + ], + "Wallet scan should scan until the chain head": [ { "value": { "version": 4, - "id": "e55bd8cf-aba0-40e4-927e-40be6949497c", - "name": "b", - "spendingKey": "bb3ba1a4e7c3bc528aaeab2633d92a8eca762d943aab5cbfb7b0d4caf2a6e517", - "viewKey": "894854302b48846111ee21d32cf2b84959586ac66f782f0ff907173145deca737982c369eb28891ecd91c2a11e319d4db020cc7091e6e715ef4b9dc6721d2723", - "incomingViewKey": "a986bd3bca479e5ec9a5a8f26a0b234b49d1ff9c5327b9917d57913d4bfcc503", - "outgoingViewKey": "eb4440e0bd5787b009ae6a71d0b2d7b493fdfe0d95d33be05e6e6dcd0da49eb2", - "publicAddress": "92056c5da34c774e45c9192f4d54cdc7b4e5bfc068897e49cffe47f797f0a543", + "id": "f0c05cc6-518e-4a60-8c0e-36b624461c02", + "name": "a", + "spendingKey": "cb469a5b96113d3ce511481ea95f5af796246c8210ee36ce933459f20f9ad054", + "viewKey": "4ae13a3528b39c2159b934eca7835ab728d2cb6cf053d103bd90e2c1bf8e1b6c3358415e2dd8955c9c35f33fff9888a0d39f7168ccab32b57b8443adf2d4d5a4", + "incomingViewKey": "ce8f3645d46a27302d7cf8f50b925fd6093efa5d0fb1281f2e05a6f299b07505", + "outgoingViewKey": "cc5eaab7ea9948a69faf90cde50994cf5229b3d1a4ed346009895e4089b3deeb", + "publicAddress": "58ad1cffd3236ef303e9543a48ea92784f46233e97de4f739abb432860bc7244", "createdAt": { "hash": { "type": "Buffer", @@ -6632,7 +5446,7 @@ "sequence": 1 }, "scanningEnabled": true, - "proofAuthorizingKey": "7fcdfc565d9816e4c386cdb82217885c7ae2e603033177bd4c91d7a9d85b860c" + "proofAuthorizingKey": "2a24fb483ca3e2f2d5e1dc91513da2b6026b6c89b92e0fa154e9d05d4fe56502" }, "head": { "hash": { @@ -6648,15 +5462,15 @@ "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", "noteCommitment": { "type": "Buffer", - "data": "base64:ckxG76qAzR/l+BL7Es+E/PfyYSHovhqtZl/Xcqcq9Vs=" + "data": "base64:/00uglzCYK1RtfBd+WM7QsY8fcMjUE+tPuHc9GBkgSc=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:vFQG9StojtP6rZwpVrufvNhCI7L3mJfz/dAOEqJTNdA=" + "data": "base64:y8WerlC5JWcBLf17AIqMoKxfYsNZvHczLdfal/RGwgg=" }, "target": "9282972777491357380673661573939192202192629606981189395159182914949423", "randomness": "0", - "timestamp": 1717538871563, + "timestamp": 1717539009281, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", "noteSize": 4, "work": "0" @@ -6664,25 +5478,25 @@ "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAb8ykFyFvqfsUq5qJSKhinnnhZq4RywzYBhvcwieC1MqDi7DmhWd5H06hln+Z9x37G5qrE7HJJNdid63HeOpGE+L6ZjotHVchkR0QHFoGl9igHFTFe5ubwCRjUBpT6QdFjIbUAWiCjx9SQaCHRokXhAEsE4s7f3T2xgu6U3EjZ/YCKgmdKUaMz7bkFopaUwMOIHXu6jo2Tf5DLHOP6DUYobrfLg6fRgmREwmaf/y01fWMFbWgixOBQkcheY9ZKNnSH3e+DekFb7hdKnwSkLQV1LeD4rEbtjPww+00fMU3csea8gqD7AycNObbUWKbpMKcD45cPvBUrIhOizW40wyll54QQSu3fDveTEng8CQ5vsOjBnxNN67sqWUaxVr5U8BXNvkijakskyhefQ7peFtjO+EXyUimd5xrxzmgzbf0bTYUyTO3rUmGgNXhkGvv5XQvm3NvSNhm8aqr50WPpzX/2770ebg0wuu8w5pBKoktB+stJy/3oJotk5WIlVQIR5ubKiyOsjBsIR74OCVSvAkvEtGbnb6G/IhCxwkPL2kmG47pKzlSl8aw+YKFFBAa019Q7pbznPz65qNAYw5RsGHdcSutjdHGrhl8Amrja5ciRAo+Uzo8N1d7uUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwOBCNIrHuv4VUgVjwKUZ22sRoe5B72Fhasp5jT2x07bLykW6rw+kRPGjThAfGucAB53oNPylWoSd08f2prZVPAg==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAUxDTstYMuM9cawjYTcco2Rm43dbO0mhx5TdArJFcC62j068X726p5jAwYoKZoZ67qvXlWAS71Ezaug9k199xVN7HiZbw8hIhr141W0DWZoSY2A4ck9/j53UHZ5irLzjOGtRLRg3hzUGfJcUNoBsxjS8CwAliIczo9xJUlhnCicIDlA2uHFPoYWUeAzX2uACvsSpb9zdjFdoAtcEXPTpj05VFac0duw3kjHmDMJm1/beCyZpPVZx69pjDzSAp/Qlp1WsH7TQxRGWGvdy/oYRXFsI0KtmPhVKtzPAyc78WNn3h3En5gGcnzr/LHT5DUnTeCputh8QgYsJ/PtCX+wy/Sb7L8UnZWkqkXBhe1HkRrOYdR0VjQuVztszS915xO/tKwTQJPQR/TZwAnQu4nRbcDyVZVPeUpOaWGqE2WBcoY9tNZ6vcsE5FMg8E2P3G1BCGaeArJOqbMOpNSdVskpXDqIWWQhN3vR0t5dFnu08CYF5fgnPK0Hv8BbswFQCjsoV3ciltsQ5KKOXHIuCs2kT7FwpDQnR9Hy5NySzk3QKoP9YZTqRmf06iCoxsqs77Rv+n0VlgQGCLAeeK+YFAyeUab+NNybVcVXSCkTA7y3AH2JFlTiL4EXGavUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwYS+KKDPB3TsOXtkukoBjlMZZZ8q+QpNVTZz/leVM0NGVpTdh0RUsbf54yQbeeqDX7cFl4dY+lsZyR7uj7s7DBA==" } ] }, { "header": { "sequence": 3, - "previousBlockHash": "26B5A48FD98F6C8DC5FDD8FAEEF8142AE63AA8EE4FFBCDE6E0818F7692A848C8", + "previousBlockHash": "8B89B43F3956FC769F957449516569E48AAE76C7E1516F43781F37B40DDE6741", "noteCommitment": { "type": "Buffer", - "data": "base64:ARTqhia4P+mIapFqlSO2WMNTE9+TqldyOE0EdSNSXxM=" + "data": "base64:uo9tMuotmcfPO6KvlL6q4CnesDqEYlm7/TFnZpHWTFA=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:+Z1XAIlRfVvNS5Q4nVfMakJsXu8ibAGUluggK9h1W4E=" + "data": "base64:mzGsYnnneE49w7ACX3U8Fg0FStW0D3fmPnEhZXI84xw=" }, "target": "9255858786337818395603165512831024101510453493377417362192396248796027", "randomness": "0", - "timestamp": 1717538873930, + "timestamp": 1717539010301, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", "noteSize": 5, "work": "0" @@ -6690,22 +5504,22 @@ "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAADeTqEiiS6zAtcGIUeFyXJ24W4aKQuMDbRhXeJ1s2GMSOtgmwruJLzr82q9bADT2qD5V3tPNngpeyqzdmB2ofbtbBIvg8ienVGrWidUBUrlCFSS6TCrspbpwJ2hIneojYKyq7Y24ZKe+YlmQAYNQoSy6Mw7kVNMgoR84/vEWJoMABKq/QKMgN8dyJJA22E62jGp52BeS7DBHNNl1Ap4Ppom1kN0QNNoA4rsJQbSbW/LuBFMHGHsX3LOgDa2qww5/arCXIe6b6wD14My6H1YjEFx0WwEElaEm+0u1U2vhI7OJbFKf7/uyG4aIn+g5LA7I4kMf72oG7gyewwAaAMEyCxKH/KLDafAn97PnEJ0xI9yBjr09pTXGMrB8tXzM9F0FQglhEhPOQtzNYiAcElPkDWG4zpeQpQIVAmClnzDjWw5Yh3D8r3TB4wZ9BiuYH3YrSPuA1pedV9QhUUYE8QMJSU842TSmRUkOJ7JJR1iNoDb1efTnjsaEjTcHYwWw5cm5SKmFkv77A1FGdvwuc8w9B/z08kLOblZERs4zMvVhFoJ6QwK6rj+/mvcnXFVpcmXxe5HKXzjZeJdl8hX09ghI8TfP4emeXFD1Zxi3hA90ubmiCpuEF2j5xEUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwbhDlC542gvg5F15aWnw2PLKX6mVnFxbkCDHEQg/l2KbveB57nBCFLBQgwOsXUksRdzEORk7GdY7AVJq+CbgeAQ==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAm6ILXOTB+khyWx3f4nNeMYILKANSUsv6Vf96Stg+qmaKLl90+O/8xwrViZfXoKbS4+pokN3N+6CWOVSEgGQ6FXkV/iaNvSnGHZD83/Fg1s6PQm3b6eRg8UBbAU+IQi0i8iOSlVro8M+XZ8ChJrAqFLvvVEhh/uobrCCRYYqrWgwAi17NqR0zbtGA/mLbW1z+2ngREYTnGEfrtjo0YK0rTlzPJkxF8bsQu5nn4I43XZmNJ64fmHr9lIWoed/wQ17ErBDexmCW48XxxXtHj1TXXyAdTZ8br+wXRuDA3Jae+KM5fgIRfoUIM4/bbzt5bcZRDxIGkygVw8PYAyjbhtq9nbA3lv1U9+hz6JFp8XI0ZxC40dH6wKEAMJRKwKGjeAlUphPSkVfDRJnHRmmIrAkPJxtKJKVQF1qTpz/DRzYacDQYfdr8abQ7QGwltMhuWeESYKd5B+UxwyL4zy6ew8MRq8fDEQSnnnVSWsYfrdGmoQcXgqh3oomq/rmEhgsemhwDJ/rnEeJ2MTESpc6n1xV3MunG9jNNMCBk8rzZwHMZmQg39j7mydsv90nlZJ5gaGM5k/SOAzekaECc79++dwkUiSebWeCMSb6e0fYS8rWQ/I1Dhn8sBYi/W0lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwBDKVr94wIo44rKdGWzeNvRGHkMwEMw3uAZV9HBE6mG+KJ30/UMOSL6QMU3GphsQH7P9h2ZSKhiVMXrikOgo7Bw==" } ] } ], - "Wallet disconnectBlock should update balance hash and sequence for each asset in each block": [ + "Wallet scan should start from null account head": [ { "value": { "version": 4, - "id": "049ba4f6-931a-44ea-aa5f-ef433ec90753", - "name": "a", - "spendingKey": "20e380868cfc0b2756eadff9402b3916341731118b077552cd9eec97c9c1c00a", - "viewKey": "7a4da4fbd1efa4d0afb8739778f43f690a1b310a49fb1c33f70d85ed443594602a00b0cc239cadebdc9c7860ba96a344c5b2911b01efe18ea9d75123fdc4d0a2", - "incomingViewKey": "082730efefa0ab9c386a1ed5bd0a064f42240aeca8e9a3fd5a5311d06750b204", - "outgoingViewKey": "26c142151e6a3c3c88f0e6c863722b32b76ae10f2e39d4bb13060e7baacdc5b9", - "publicAddress": "518cdb40b18edcc515f251ab82e56b1b33850a5a9ec837c81973bb2274f85654", + "id": "fa5fec21-c63c-498a-80bb-5919bee4f57c", + "name": "accountA", + "spendingKey": "2089eed9e71a6ca6ae3fe89417ca1f42349aad0b2ed0f1da13fc958d84032880", + "viewKey": "5dad30944afa1173644eafbd2e4938cd3228d3aaab8668587a2c0ab0cf42cf256ab4365696caeb17efe20b909935f90e5baf6d84b2d70f7fda4a15440aeeba5d", + "incomingViewKey": "ed5859e15f2ad48861e603e4b8fcd74cc22637a12e9a4e3ddd8a4c5c03908b07", + "outgoingViewKey": "6ae21c18dd5b081ecec4fe73fc417ea7c83213e218403b3b80a92d8f0420ab20", + "publicAddress": "b6a489a014a64d0113c110531b99e19927088f301bedd11034121c28ff977848", "createdAt": { "hash": { "type": "Buffer", @@ -6714,7 +5528,7 @@ "sequence": 1 }, "scanningEnabled": true, - "proofAuthorizingKey": "9f3a339fbf57675eda822fe6434f13822ce64a5d2d5d6884fc98c77615195402" + "proofAuthorizingKey": "8083d151507df2903b0e39ad090c3467a8035e6d230348638b5c8fa4a53e2607" }, "head": { "hash": { @@ -6730,15 +5544,15 @@ "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", "noteCommitment": { "type": "Buffer", - "data": "base64:s4Yi/MuKDM4qGHH1j/dzHXG6aXnE+fcZx7w72b1w8Do=" + "data": "base64:RpA3KWtFNM2ycx4RqUuxT/lTJXhNsgSSzA+s/MjUzFk=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:2ce5E7c03qw6ZPD37elDhbyzxZXSrNyCJsQ9Mmnezfs=" + "data": "base64:kC61YxPC+w4CJ48uIDdKrdlZvlYygzEdESlNqDfQj+k=" }, "target": "9282972777491357380673661573939192202192629606981189395159182914949423", "randomness": "0", - "timestamp": 1717538878477, + "timestamp": 1717539012639, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", "noteSize": 4, "work": "0" @@ -6746,82 +5560,76 @@ "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAA+d6Bh3rNKCxPVVCuAf4ZKLZvmtE6tF//46sa4FYpxEWSOpzBFpq4UcwpHkLEC2GFWY5VC0hY6dSnG3/yPD/O7AeYeL/oxRBMcTIB4v2uuEO1cMebwoVpdAW8uDEkgTSC4rpTG2esj7qRv+ZLdc3whdcsGbSgzvAO5eFoeuosPQwWX+7Rbk3boL/Lo6qPpFBn78j9aI9rNI5YxNu7ZO0VFYQO1IDDcpKzMn8Lcrfi4uGR8Y/RsIF8DGO8sIG6SqKbMCM1ovrdR7BieNuUPeVpLJZb9ahRA/F32rrZXEuHoCy+fxZZYJqcs8JOXGwD31gCn0+g+yq8kBvjAtmzomY1u9UjxFBkddY0RY64QGJKexS5H6AGPuYUfYZOXZFdbc9ShHAqrcboyYvUr2+pbCCMrmpOuZd5lIEktGhTNfO5/7FrB9RBTMhrFopQkmCKNSg0YQ3bpRPLml+8ZE2YThLyrUtn4949dcqPA5O6oy7m7lZAUXCED8xvd/fUruPrmTWXh/Nnck1s0aebuj+jNt+qIHnCv2RuHNxVE4UhuGNgdzQD6AhrLMBQiZ6avbdswENIiyHcYP2q5jSjFzN/hhJch7U+zI2vxdiUmnta6pSUwkdnRIvU+IYzaElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwk5w+JVKihJUmq/7Uc27qM/oIgGSA6aZGBLLJXd2qyW+z3jjAjBlf+IrovzqLwsB423tlhOIGos/MXtR95IkbDA==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAQtcKGcQLA9vdKYUbfiboDRG3yNKRFR+TYJ/xaVIdd1ezoqSGFv7an9yxIx+jZqggiPeT3jBvxXc5dkGCWtC4aBBgms+g6U1iPf747E8V8tuxabDVbG4ZUUH8z2J7UfO+Tkj85q3VZTik/LNZJMw4PqM8lNixWgPSf0mbNeJx9LgQGyfPwlFJi4r102u7pUTy6NrzD4fJUdMVJ57pI2sHs+luhZEiNy5G/PU/kHlTUGeqWGpWLyV0X8HcrmFL1yUnvDTqXI5wGVxlRL1LKxhYZ9/bjZgvzCQqJin+IYLc7u+HrcfezmDEmdPUsBnAi2Jsx6k7Wpk7C2NAmvFsTP1UTBVMQ7yvBFWuBr4oIF7X+iEQPm6IxXQhkeopc4V/UkFTbt7GOPPPxivTYQw3RGo2eExeyTosat7UvwzZ/OQxQNjSKCa+U3/G2isyvH+rUqDU5VUKTXgUN+BB/4Ev49nu4dSo3Xq4S4lEoGz7QBaLscCBrvTKnHU+GXpNO/KpgZmkMWV8P8mgDBLmmkeSg8ZvrHPOHwhT0+k5cdotIR8xJ0NfAmZ/J3v3tjct5axZZdm/dymwlxT9OjxbNZBWQfpgwghXg+KYILEMVMVDhhQJ7bmDT112vhoDzklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw2ggYFzS9r0pWoLNkQXMT911ZDG0P+EdOhVbSNjRSS0tFLid01pUX8beOMYMESLQDWCpl9awFqHDFqJGqWwlRAQ==" } ] }, { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGy967/fBpCLW9sv0oCvwmbsaQuFPDohRKI8di80SzN2zW5wURMHQj1vAeztAf1NKT4clMEFh1t6ecQfm4hWGn/rF4zn3Xt4m55JEkDjrnKuyh8UZQrhABH71w7i2B25nshb0bg+E62Omo+O0wFRaOy05griKdK3lETKCnGUQ5WANjKOvVRcbIu62Fk3AB+GwdhRuhCr4hvnzEmx/c0j/Hrtd3hX7pdZiJoMp4zyvOQOxp/XEaWLt5ZsELzOUyEvgVPEG252Kxrs4z6m1Y4yIl8GvDoeT0gLwIv3Uw60S8Sr9P6cb7Bi6+5Uy1IOdCIphOuQ8/kodbKzvelPDQAMbYJc3iPDOj6rxaN6rTjzZJZxXC+tGHFsuze66x6t6/+UyIIrLG0zWTgIfaEktINGshdWpxssVJZu58h57l/xOahzMil5OxpLfyD2OuFiHqPomiuuNbBL5AAQZPyJuQyJ7YLZkfJcuJ5j5SLlqQk6w2jeCBWcieBphWUFPSXpyML8coUyj3T/6AY970+VFx4gfXIzy55v6DFkUhZw0pSQeLbGw56IM1miMUaOWcZPER7NO/PwtEjJbvFhGMrDboLe3RMviTz1pHG9HvhqrJm8SQWoLzL6G4BOnT7kIpyfULZcUrqMYNhwWPk7fsDUkqU7b+BsQOBGJFlRKnE1ZkNodwSfJZdTKUoCM8gxCJlepOXmzPQxkozWqTK6kCg5JHEg1WAOi53M8sTtIgRAKVWxY+k6SHXaGzeEZm7l2VgwfrzJiLfKep1F6ZtoKpSN+dG2oTE1Zwfacyy8VmIzjlkVln955e4wNsJ7vaQ37i2gpB2QTGgpGu13A1NaThreUi7STsOWFIN5BmB95DQQfwpUL98uaWYhSqW/25iJ1+ew/TKM+vgP0MUvBGsJs7lmeFiHzznKQAxFqgN2fqkMXH/B9KisbRlnlpeUGe64G6u5tAHXo/8O05f+TUSHjtvEzu4NTcp7OlhQ3MDekUYzbQLGO3MUV8lGrguVrGzOFClqeyDfIGXO7InT4VlRmYWtlYXNzZXQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG1ldGFkYXRhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAF8utaQNXTxJwjztt8ATwGNp6cVIG3oVpIzivdvv9L8PEu4gOAPAzhitVZqKE1Q61g9hly65kMvGTYp2sqjpZQrBPJCYPyxhXSG9gcEohagom2FmbDIcV27bgO/KY2X5a4wraxrmKzIYFi3J1DqDLkX1RSdQcG6bSvp3IsKjqwsE" - }, - { - "header": { - "sequence": 3, - "previousBlockHash": "B2570284AC115B3A9CFAA38EF8F03F6B8997B59655DBE0EF2CAA9DC2F05B0BB4", - "noteCommitment": { - "type": "Buffer", - "data": "base64:Xz5s56uEpF5d/BpUbB+6qmZ5+7a6G3UXQpPKyQBslmY=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:L61kuPw1B5sAoRz1Y0bWK4YU1WwvfrtKSynuFbuRiE0=" + "value": { + "version": 4, + "id": "b348877f-52c4-4880-8a4c-1c41f458c46e", + "name": "accountB", + "spendingKey": "fd92f9b2fe73330502288db549743d676172927667cf615226256bbd6f6a2a3d", + "viewKey": "dc745ff1c68bb7ed051719541823aca83421d6a55f23818aaa692b0c26b85a0bc0931f4addc90bd6b9c8c36e3a6e792c7b6c13b2312ef35ba95cb54c73846eee", + "incomingViewKey": "217269c4aa780e41dd102d3bd6dbf3a192a637b5cebb4ca730be5b8bbd5aa403", + "outgoingViewKey": "8e6945c8a702223641536e38de45e76cd64ef9e8ce64f2f901ce7ae8ca6e8288", + "publicAddress": "b85eb15dcc56677ff073dea9ebf79d284f6f34a83466dab734cb3f5e3afb53b6", + "createdAt": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 }, - "target": "9260366780148527510972123832573278885902566341756516011968728852484845", - "randomness": "0", - "timestamp": 1717538884282, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 6, - "work": "0" + "scanningEnabled": true, + "proofAuthorizingKey": "46af1b8daf03a4f4aee94a987e6d590bc7ffa7cb6781ee82b5bae126e53c6006" }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAGzkoYW2EUxZoYAo7xCqsuB45+79IKlj8x1uQ6PQmrsSFhk1yaPVI1H5LtK6tkJ4EDKFVHoyELL+ZBtQsE8SBWU05MCihwSV7f3DWaS0ticeZzDRjCWm+6MsOcCba0V31lDiiv3J5HBAYqlSqlclJAxLIoGtwROS8bBRMcidfVvwY+XEnIeZCNmjWGGb2zVwJrLUCa11Uk7EKXPxEver8UOVGb8qY7wO6oNWnQwFdCl648kqWmeXCmXYAp2zbpstLpUzA+oCRyaJe0ROeAbTYzTNkzkgZ/5A0YZNkbQm9tf3my+uHgUA6DC9GF4eZT8UZcSCnNrkc+IBc8Nq084AzNT7NkGl3X2aW/4CrVxzFZXvk8xSamzehf5QL6B/mdfMU9FlzZ7hsi12RBaCUjyxX7MMSnPhcTIZvfUVpiHdAFp46qzJMeQXoAuokH+M+hwPntAxirLePWVaTZ+zFYTWaSjwdQf937+PFjPlLA+E+ZlprknN4va68G9Uzh0h5/iUyjZdK0AcFrLMAJxnIv5JxF3BdJSAVwS1cV9w9mh2RMk98xB/PCiEDonVdvsKdolPAHvhokpwRpVkktAQzJh93wfIf3oUT6xx88+3a4ku1L+d+x4PK1h5v10lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw8utdH0ZHQwkpSjjtvVFWCz9fx7VrMp2Ely4hmsA5ZkP1u6qkyThgMmwDXGbuOY+HA7lszscsamAm/Pnp6Yv1CA==" - }, - { + "head": { + "hash": { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGy967/fBpCLW9sv0oCvwmbsaQuFPDohRKI8di80SzN2zW5wURMHQj1vAeztAf1NKT4clMEFh1t6ecQfm4hWGn/rF4zn3Xt4m55JEkDjrnKuyh8UZQrhABH71w7i2B25nshb0bg+E62Omo+O0wFRaOy05griKdK3lETKCnGUQ5WANjKOvVRcbIu62Fk3AB+GwdhRuhCr4hvnzEmx/c0j/Hrtd3hX7pdZiJoMp4zyvOQOxp/XEaWLt5ZsELzOUyEvgVPEG252Kxrs4z6m1Y4yIl8GvDoeT0gLwIv3Uw60S8Sr9P6cb7Bi6+5Uy1IOdCIphOuQ8/kodbKzvelPDQAMbYJc3iPDOj6rxaN6rTjzZJZxXC+tGHFsuze66x6t6/+UyIIrLG0zWTgIfaEktINGshdWpxssVJZu58h57l/xOahzMil5OxpLfyD2OuFiHqPomiuuNbBL5AAQZPyJuQyJ7YLZkfJcuJ5j5SLlqQk6w2jeCBWcieBphWUFPSXpyML8coUyj3T/6AY970+VFx4gfXIzy55v6DFkUhZw0pSQeLbGw56IM1miMUaOWcZPER7NO/PwtEjJbvFhGMrDboLe3RMviTz1pHG9HvhqrJm8SQWoLzL6G4BOnT7kIpyfULZcUrqMYNhwWPk7fsDUkqU7b+BsQOBGJFlRKnE1ZkNodwSfJZdTKUoCM8gxCJlepOXmzPQxkozWqTK6kCg5JHEg1WAOi53M8sTtIgRAKVWxY+k6SHXaGzeEZm7l2VgwfrzJiLfKep1F6ZtoKpSN+dG2oTE1Zwfacyy8VmIzjlkVln955e4wNsJ7vaQ37i2gpB2QTGgpGu13A1NaThreUi7STsOWFIN5BmB95DQQfwpUL98uaWYhSqW/25iJ1+ew/TKM+vgP0MUvBGsJs7lmeFiHzznKQAxFqgN2fqkMXH/B9KisbRlnlpeUGe64G6u5tAHXo/8O05f+TUSHjtvEzu4NTcp7OlhQ3MDekUYzbQLGO3MUV8lGrguVrGzOFClqeyDfIGXO7InT4VlRmYWtlYXNzZXQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG1ldGFkYXRhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAF8utaQNXTxJwjztt8ATwGNp6cVIG3oVpIzivdvv9L8PEu4gOAPAzhitVZqKE1Q61g9hly65kMvGTYp2sqjpZQrBPJCYPyxhXSG9gcEohagom2FmbDIcV27bgO/KY2X5a4wraxrmKzIYFi3J1DqDLkX1RSdQcG6bSvp3IsKjqwsE" - } - ] + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + } }, { "header": { - "sequence": 4, - "previousBlockHash": "C0BDF738AD62CDCF238CC8CA39B8BCEF0FEC0B0ED663C7A48C34A0F7C3D4398C", + "sequence": 3, + "previousBlockHash": "09FFBB8D53A173E1A982C8ECB57ACC9651732D0BBE0BCFF971F19B097F9E72FA", "noteCommitment": { "type": "Buffer", - "data": "base64:sivJwFVBBCDl41P4R3jX9tvWsP5y6f3y6lPa56RzWms=" + "data": "base64:KP/vitIP8dVAxPlWs3MzTfd7PzSY2sKpfA2IIjVDkh0=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:x7Xae19m0YrW0vFyKxOPS5E6H133rkrVIqc6ldiUnl0=" + "data": "base64:RKvoN7dEaA18p2zAP9UGIMXNfnvpA1Wdnycb0NaXCPo=" }, - "target": "9233318228143625020618577701423519925017621426082203201059080050516648", + "target": "9255858786337818395603165512831024101510453493377417362192396248796027", "randomness": "0", - "timestamp": 1717538886454, + "timestamp": 1717539013985, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 7, + "noteSize": 5, "work": "0" }, "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAt9ZAf2K52BMpV6vLbiOPzv4vQATwf3NbDNIGK/tqW7OGX2Yupt4uTqg4hkIEXVAnRvjgTrMVA1jiQtN1lndRD1GlHBgdbW3Fi+hPsiDiutiJa4jNNqW52gFG3kOaEMQ9Vg7blTAmC7QAE2at7FOodSNwOntfZK90MICARSJEdyUSzu1Ux6Q1W53yT2S1jElaFM2dZsK27XfzyqEvVOFIVXOSNUtRH3VkYD5mNV/1ZImKoNK1WOXPOdIGz2JMGOW/U95dF+vLwP/ER86oKepca4A8wHoCdulq4QON4IJ5VotUmiGqASRhr+3DT0eoEtnfJXEQLf8OPeFvObkHFdDMwb4MiNmLlWLiGofkaRSzOI+MY40d0/DWJDTI2Vi9IF4OD/avim1M61x2G9x8OgWn7x+K/yGrojF64oNSYV+sFFKDBiVWPZC9z/hSBW1/XBkLqlACtTUeYr1qEjMduaKSKVbXa4T/W6ImVnPpmxmcpXgZFBMHFGy80wgBun0REor05tDCDunbBYWQqObBNfUga5lM9IPyfZGHY2iybo5YHtErrpkyrZT/VI2IfnsSUf6kXK9Hb8P3LCiqYS9PsD2/VsRN2xYYOc8p47oPWo4F5HT05r5TyfAD7Ulyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwQHLFya9LuojFQffCrOPp02iOHhG9Y5aW2uaFx0Gm04Yzm8H0uC9YBzK/SF4+JAVsnY8d7zR0bLPzGoahh6saCw==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAeRsNEYt3ZwfhpUmTnlAoxMI6+BpLof6oRfHanFWaLQqWZCetZjOwdBadG2PWNRfhOYCj5kCz/FYXyqKDMKkTU/gS5tSiLixEqeVWt+LwUneKKoyXAeZ1OKNH/obHr4wFzvBwbPZ1/NhhgsGvbcBmENXpKynPgC4At7PCqBjLn6MS+xh8L8JI2YI25c2Jzac7boKEO4SUJWqQjnhT/PVNx2NJkd+ET9pPxDPxVJ9qaEGN5lmieKU0h91OfnpxUPWoHvbHt0fyfrEXLJOH2IMF1P6q8YPzmBNIPE9uWSh1Khrcv2cKbkul0cpw3Nt32rShV5kTakqHe/LipBTzKGmRSyfMk3R1qvkdot4OrlSGrgB9MMJKLf9yjvMe2Mq3p0tRzViHcNTZm4LWDwbaG6MdKaHz94M4iDqzrLa4lxGQaNoV6qLzRvvUtvliIlUh6ZRyXS37gNlD7Q7BNWuGEMsDmjy4xt0/fNsbO14ZaTKnn+EPbGECCOoDKX1yDFBlhzCAOEd41+Mi1AT641saSnvO5sMHoLy2r4x+lrDE7qyCL/3SClcmj0PFbi+CjPhSJn40hErDnV3//Q+X5tw+NcSBzwydSpdZgwwRm38Y+h3u+IsG281wffNTR0lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw2eSVCgULZgJi31KzK3GdX62J/O4YGGwndBTL55y1Qd0m4Jq3ikdnPKJCLa67MczlYI9hwYzENBQbt3O3NOeRBw==" } ] } ], - "Wallet disconnectBlock should skip disconnecting for accounts with scanningEnabled set to false": [ + "Wallet scan should update balance hash and sequence for each block": [ { "value": { "version": 4, - "id": "cea4db72-3c0e-4490-ba85-0a19f1b2af42", + "id": "825e4a80-f3fc-4244-a3e1-dce2193fcd55", "name": "a", - "spendingKey": "d0ec738764e95ace955f1d7b432b4f130efcf2049b0c2354bcb852cd8e226d6c", - "viewKey": "ed77109abffb7d9e35de05a3d4d4a8958f639943c3e487871ab4e7b41c5c9911aa7269bc46ab31c43f036a9f6198fa86d59b4bd21022319f1975da8ee6d32a22", - "incomingViewKey": "46eab4105e43d0021db1fd1fe3140e7e23e951efae0c6c13d130282b1e3ec000", - "outgoingViewKey": "b788c45b68200423b608cf34888daeb2f56938e76c8d0297a572e43c989655f5", - "publicAddress": "95205789be04b75526c4c33241dc8a94add1e0ac4455a66786bf53c84952cc3e", + "spendingKey": "58eb718331c282d7fd759fee0a3ebd0196ae918bb2bc2085da041f41aed207a2", + "viewKey": "ab85cfb9a1ee4922b24d909d6c0e495d4f2d742c3a0afc872c488a836d551371a29325b2f86e28a87c0f425c44eeaacd2acbbb4e88f3ef3a35b47567e4b6388f", + "incomingViewKey": "7d8dd3ea50047ad4447a9916de0f34bc03927712d8a617ba2c3012b33989e906", + "outgoingViewKey": "b20629e4e0a199ad01436d5ed504b0e912a3b7dfe64f21bd2ba5b0b099cdd220", + "publicAddress": "14e8a4486b79f64937f8dd84d23afa5980728d1a9f63d546c55d96b3755d605c", "createdAt": { "hash": { "type": "Buffer", @@ -6830,7 +5638,7 @@ "sequence": 1 }, "scanningEnabled": true, - "proofAuthorizingKey": "6ae14be9b436bfecba83f6fa2bb91a9de744591bb43f41746e5aa965690c8605" + "proofAuthorizingKey": "b3b33adb285f558e666e66d61d70f04c1440f1de96692d8edc8b4e564b9a0805" }, "head": { "hash": { @@ -6843,13 +5651,13 @@ { "value": { "version": 4, - "id": "72031132-15e3-436b-bc2c-ee915c5b454b", + "id": "ae195ec3-2434-499a-ba5e-1e7525fc67cc", "name": "b", - "spendingKey": "5261a189da5e08d5797137e520abbec9b401603e58a597263ceae9b5c3a0b042", - "viewKey": "773d68c98f3e4197c379b784213098c0dc5eeba9cd2396d884c37176826d73221a504ade9945c0b6e03ee0e65f77b05447085e713a434e3a23f46bf415995b0d", - "incomingViewKey": "c8933e4fc82fb3d0b145ad385e9db66ac6e6fcbf5ae274991eb5c11226ae0f07", - "outgoingViewKey": "92af0cd3d4f015a0c6bfb0caa6ebf667a2851436b7445fece8766cca68a0bd78", - "publicAddress": "c703444078753dffeba8416cd0b152f9317bd190474ee6206328d166ba79cc9b", + "spendingKey": "81465f82a3e863de768db3f3df447c88fd66a9fcd74d7b832080a81b8dfebf29", + "viewKey": "27f155cd9d320b59881f4ec9101e10f3ea45ac361ae12213d3f92cfe2fb13e6fa40f057a9d1059c1fc20fd16bc34ae3571aecb36bd70fb762296e83143931c8e", + "incomingViewKey": "f03820937c6de19e91747b494159535ec3385451436faccfd8dfd9f8c7859401", + "outgoingViewKey": "ed0fde53f1dbf38d1b40e983ebde9b8ee6536153885e772b055d4bba7f3accba", + "publicAddress": "671f81804898b2f7002bb07a27b76b73fba95f0b0bc134a5ae4325f8bf8fb633", "createdAt": { "hash": { "type": "Buffer", @@ -6858,7 +5666,7 @@ "sequence": 1 }, "scanningEnabled": true, - "proofAuthorizingKey": "2700d803eb6def99a93347f9b798e663c4420ca874a559582c24d868bfa4fa00" + "proofAuthorizingKey": "cf173acbf8aaa3e24f6ebc7c15cf0f9d59c6048e503083bfa1b8ce232f44c50a" }, "head": { "hash": { @@ -6874,15 +5682,15 @@ "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", "noteCommitment": { "type": "Buffer", - "data": "base64:4Pm7/rxUpCE6r1IMblGXJTOhuJmrjwRA9OOv+r1faSk=" + "data": "base64:EPBO4Pb0coY6KJ9Vv+xO1izVPFOemeKI6im+oqxOr1s=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:D5TmiDwxrHVWaxxwPp0bOs88tEbBbkYASoGLXC5d7Ac=" + "data": "base64:SruRXSo5H/JY9OIhb23x420ryCwvMoBRZ/5VkHgTkt4=" }, "target": "9282972777491357380673661573939192202192629606981189395159182914949423", "randomness": "0", - "timestamp": 1717538908054, + "timestamp": 1718998708731, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", "noteSize": 4, "work": "0" @@ -6890,25 +5698,25 @@ "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAlUK4uq++YpXh5AxTydB7Y4bEJe/mmVapHPB4BAL0CoK21Q7MpGTPBCm0U5jAbHFCPB7ADfLgaV34rqKCefaqfbT9UBSAr7uyfcVz5k78CvSwNSAG061Wi0r6J77dA8jfk85O94SKd/AEpB3xoPSWxuEkM4qLbh6Prfg4e8d+haUTeroaP1Lb4XiIJxugJl0qBDpiBZFJp8FcPW8hMlm6l2S4plniz93UhmYkdrATyWuS3kOwxB80J/zIqgKMCYnGRSuE6LSzc+UN8+F/8DoMiRLECFZodh688aKUDa911YitHlfGWwzNP7euvSZQLIdtfH+tqCMf+dUO6Lnk2m846fQ1kRDMKAVTz0TT9BLbaIbWVT9Io6cEwn26Q2Yy8u0nkIXcYFTZSvP9SN02gT7b2Vb1A1hkNXfOGozjASmway5O6zznsxk8CVUqQGVfH5HwOREl+RqCrcduephTUIwupXPkwcIC31qKGYIa8sqBTnc9GbDA3yocaOdSYRcuDBFBYr/ofZ4MWJiJJXIMEMZNVPx4l/aoZ8rVX4zDcia1Z6hOej60KYeKsc407IwCt6NZcp2FROpIEtVVOn6G5Af4Esb+KW8x4PsJcGh1dt/L3RjQ8tEB1J40hklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwmvC5vkg8ztfVFGvQ4mtMVsoIy70lGzD54s2+0kEzUrUJBFBvjx3tlk4XyyvGPkXqbwwi8wkbMGkPkSBAKZYaBw==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAeEasFfctBRZ04NSNOOpYZNWtKYKZ4w61b3ESf47GUfOxEgHgijAycu3lld2Z9tLc8Z6RIzUjJQG/AjAWtWHI9AFXiSkviCNrH5TKGDvEhJuS8aUTDPlUfytEmGkdl8yhOcchAoKpA/hlZg9Vl3f4+QPcnON7rSX3lkpVhtpnzJsDoj1fxFThkleGQ73DQdkB/oPA6lSP3iGJGh8regrjiIz7FwWDyxjkODuDE5MRiMu2SUoAcpjZcJ2Eo8wBqWL2l38PcMhKOpbvD4xD1aZbJbCX4x7/SHeWLkFbshdetUU5Xo3p4e7eNbCS20poGMVzN2GH3oj0y4+1DWSq7VvMLQr2LKMWkPWjPs0o+dzN28EOhywyytVOsvfnYhsp8mduf4EdUUhpQSBPVAOCr13yyidRhmWevoPIkTKr3KqrdtGZ8F1DGE/5A164rk41rMH8uT9CuwnL6LAdPHLBjAuwKzeaqY10y23clN7uCKvzWx+UsxsR+aGWbT+R856WE8y2eWCAbz7Jh4jO/qAXpgpLtLIdRrTt46ZkRjwt3ALDpMQbINh9Sv+vRBNOb/rJVSBBE938xSp3coMV2JLEO6Ll44C1EEaBPFrFusU5CoY9jguyj8igwleSfklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwJi14SmKiVWsrsTo7VD5PJ2mj7WFP15n2jV916tGxx9MA7Y8mLVaOhWbSuoygEy97RUlNgGX97py2OndJs2DFDQ==" } ] }, { "header": { "sequence": 3, - "previousBlockHash": "18CBE685174195063E79E28674202485FFB63ED6F47B3388F9566FFDE5CA1EFD", + "previousBlockHash": "B5539191CBF67B06B628EE57C0E75FBDF89950E9610558B37C34BDE4C3A7B433", "noteCommitment": { "type": "Buffer", - "data": "base64:ogJoHxeBjrLVpdDXTwUon7gP/v5ODhfYI5vOQceOJUc=" + "data": "base64:TKfwwMYhHPL86FtdOkBeKPx2G9uct6rI2VZfSOw4WyI=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:1ZVDi5SxN4jhWm5e9/YnuNkCiGqr/ySypdNkzmwolHU=" + "data": "base64:83FGXGFrEJmYij5di0lZO/429lDYKHNl98YT4d7lp38=" }, "target": "9255858786337818395603165512831024101510453493377417362192396248796027", "randomness": "0", - "timestamp": 1717538910047, + "timestamp": 1718998709182, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", "noteSize": 5, "work": "0" @@ -6916,22 +5724,22 @@ "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAgJAYr7G9B4yiJ80g1Sg0aghZxGcyDMMzKqmulsKZd5usbNt59K48GDCfhYgR3doj+5WcPF2n5Zoa/73oScN0lmDLsuz4eTPKNdUDepU9TgGP/dDI2UpeGODBeRii3mfHhdVOsMTRwfE0pzk3Bnx5ICtIFcBwhQNT9RRJbILfwEsCdx4Jfwyd3eEoWE9YLHcJtcFIqwbMnvJAgKhbRmug0kEiHdt1IRJ6byv8teGpxHexpEagw+8GraJAxbHqGgzCSmEOlKEZCyrFg7OZQpUO1+DDyTQXqoqrXyTLn1yhZeyYYLz7kgSB2YX2h/PKMCmI3P3R/ffQ1byeFitRVSU40d3vLElWt/ewXfibIL31u6pvN4MEdW4hvLTwMfU/QHAdLTh4ZN2idnLiukKIfC3CySgL4xK5TVcd8ftyfJGC9dAdAXkYYhNQuwFrvUoB6tS4+/rBnpqFnAZ/kEk77iorm7jEY/ibvUiUqCxAkfr+D+jqCA8Pvbk6JQc/9O5AoUc9EG4+bgnccCZcdHkBgXI9viPNqbBtu8lEm7YQUDgxtzQvanTBsIpR4xG2VQQCZ+2H6CY1Xzvh2etJ4v4jRvZnnM09DHChD/TbpFXFvBYc3utRl3SWbFCHjUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw2AM7OHElJs2qtKyQmxYHsmSd4JQBOoKKV/nhIFVH6cb7Is/6Kxuq3xUgg8ZJznXGc7+jMM2krHDSm74GQRfqBQ==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAA72ClAMJ9fcgPPhZOTzW+gBJUYlDxpH7FdOWkAB9Rj76pQvLwaK2yX3NO8RYmdwE33xJoL0rbuJ/ElbaXOTbDVdXzCThjcnKUs0L+1Ks3YCW3SoMdNGZ/2g+18hH16nDA2uCVu2gnSWeNNT06FdxxkNgUjY+JqAPE2KX8obpHYpgQ95+tFdX4qJ1Xsa5q2v0DATHgfqEWZAuv73BX5jXlPK0z+fARRXxUlvEhnSwEuBKruu8JNrW1qSozJO6j/ZnAxzpFhW9AaH2EFD3J9McN6X39H+KS097+CjzLA8qzy5YsKNBokORChRI6byvo3kc3hEx9HhIx5a2fdMfdGWs3jbzOi+1O4WiBLMUyq//BPlqv8YCyG7ZJGVaB2FTR6A83LJ4wacpsIKdmY0ZJkFrrFIhKdznDNaMFSUvR6aNzA1Twonhw8YhNq0U3RbMMbVEYnXPCVyU9DfA980b/KHFkGtjorxdZSpfkjMvPzmWpVXHEHMPTrWT0CdP32QVxdjU1pd9FUYYQnufXVtpzH3kF9qP5lIa//v4Xa+d+tlDBv1ZJIkP2JfhCSF4obHuq4IArE1gqRH23t50XiseJNx99IJtacP/KHY+oF2uOrngJGuGMIzmG3W/v3Elyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwor/BSgv1V4DhZv1kjV+3mBf6+i4HSOSrj6blyhHQO7JoN83/EBbj+/U1RKM/TmPJsyn4yWu6saUfo8Kc0kukAA==" } ] } ], - "Wallet resetAccount should create a new account with the same keys but different id": [ + "Wallet scan should update balance hash and sequence for each asset in each block": [ { "value": { "version": 4, - "id": "f53847de-227a-481b-a812-d7d3bc470f79", + "id": "65e0e2a3-b6f7-4244-b081-4dc218c09a68", "name": "a", - "spendingKey": "8b98a67d7682196a381b5d60a2620f2c91e5b73a2b2e3f7fa820df66658799c4", - "viewKey": "20775b11a44869e536657449c5855cd0915b71a7113bf49c743606420414273852c0c2aa8c2750a118e1b8a6a2203df3b344438b7c2ed1485385ebbec84742cc", - "incomingViewKey": "6109c2999c98a2e918b72c61e86da7f0e0abe9149bdcc850bc27a1eb42f44407", - "outgoingViewKey": "1f5613cf9e3adca3828dbc5d240fb945f8737681782080eb49a4f7e5a97a144f", - "publicAddress": "9219c0cded1632973b6f30fe89a1ef5d2ee497a43a9e8b4f327ad5e2c74bdd09", + "spendingKey": "4d79a56e084d8a0d2cea281dd016a5778188e6261777d680c75d61193678e45c", + "viewKey": "3d958c1c0fa717d3f7aab984994430f65567c758572a91447c74b1e119b1c3e00163509e747a47e11b9235b611502bea61adf296f7ddd2a70d60f4fb90937732", + "incomingViewKey": "f68ef0ae034a1d451e3b0865297008c2ab42ba3935efc844c6ae45c87c542505", + "outgoingViewKey": "661cb216ea8f7e48fe14352cc795c1e6ace047a0c96cd0ce45ab9116d9812657", + "publicAddress": "e508e5c2ffe1c3b175047408199665151183cea699d68e00780ce4a30a023214", "createdAt": { "hash": { "type": "Buffer", @@ -6940,7 +5748,7 @@ "sequence": 1 }, "scanningEnabled": true, - "proofAuthorizingKey": "363be292208a39201f35e92ca187ce0c4cd09dff07b555edc2b1af6d38158705" + "proofAuthorizingKey": "d5f3cb5409dfce37fb857e9c039826a0520b398f755558d5e5645d2b03830203" }, "head": { "hash": { @@ -6949,79 +5757,105 @@ }, "sequence": 1 } - } - ], - "Wallet resetAccount should set the reset account balance to 0": [ + }, { - "value": { - "version": 4, - "id": "6a9ff94a-d3f6-4fb9-89f4-0ba9f707c04a", - "name": "a", - "spendingKey": "937a478517b57e3edac6b5f362910c7333d95fcc58c6fa400dac30b05441e57d", - "viewKey": "b443df461a21c2f783a01d9735720aee1df503aedbfdaf8c7166f49b2f2e801b96e721162122300197db9d96e5399154b732711c15d06b76ae231d2fbaa989d8", - "incomingViewKey": "e19764232ec43709b83322ddb76d7a1cba8276194e97bdb6ccf0c457aa19d200", - "outgoingViewKey": "3dbc7a26ca52b85339ae4dfa94e90394a15e162081d537657b565c1a65554a57", - "publicAddress": "b4230d53076043fec8aa43688879cfa6a3286f6a5f3ac64719cf9fa33744d206", - "createdAt": { - "hash": { - "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" - }, - "sequence": 1 + "header": { + "sequence": 2, + "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", + "noteCommitment": { + "type": "Buffer", + "data": "base64:4NS7yLFXJ7lejwrSwGvf2GWI3+1I4aqq8ZpDbytqvl8=" }, - "scanningEnabled": true, - "proofAuthorizingKey": "b623eb9b8d6578c459eea70e0e562faa59576cdaba377cb66bc6e49e2ad06b0b" - }, - "head": { - "hash": { + "transactionCommitment": { "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + "data": "base64:le3k1kL/1Ikpp38S/WYk6ma7da/Ia/c25RjBV7vmcyE=" }, - "sequence": 1 - } - } - ], - "Wallet resetAccount should set the reset account head to null": [ + "target": "9282972777491357380673661573939192202192629606981189395159182914949423", + "randomness": "0", + "timestamp": 1718998710216, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 4, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAuxQW7dJNUZQiCBlTjmyYaI7bhlo50XhgS7BW36kT/7WkA5dSrsBHZXtVfvAh9yW8gh0SPe4OVZeelHSG+vgRwC3B1EzqlcFJ/wg69h/jtoqAIf0oGubE/TtCliw6aeQV06LXBdavxkIEGTnns7gArKSwB5c6eDXrJz5bSmNQp6sLA0RnkNz9QjRON20LUkCjo3EVi6/9DmQaDpVofip1tl/Kb1UgUWnLfbHu100KFa+GITlCwzoeKJCR5B4g84g4bDN9Z7PZurX+HbvqLJgNncJtpsgzuU6x7zcyqgwJvkm6Qn5pjz7IOu2txRkrzKY0IgOFzbFqHqa16jStcP7bPP9WU01bl/JMdqIeeGM8PRCaIOrvGS/PPd3pNsLzrqVi0CRu75T1I1kpAhskMXM6TV8LJ9OSjIJ8ZSsWZGqRz41UJlRJCjNpO7hJKvWSatYZf1pRMZPo4IXAZpc0X3dGFqyQJnDL1crRjeZPRKfeLnegTz4HwaY2Zd7ewKLfJ9T3us7P5ZUE4YiI8cfZrTPhePfDTQUWtmhGUHchXbsJMDuZ5HZKaCOlYr/4qWH1vEAG9/By3TggQB8UDuKRHyilW9UDy7dMGqiOwEUUIp6To012ir24eBudiUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwyRjJG/EXJ5fUz1Cs4gZS1EAN4MSIWrYkR7VlWBLEDGcpHW5tcFRgftSvFl3VSHdRm2CsdKdy2wbYbMFulQYdCA==" + } + ] + }, { - "value": { - "version": 4, - "id": "4eec859d-9c89-4908-a23c-4cded4b294c2", - "name": "a", - "spendingKey": "361eaae46d35035ae781a36b9e340258fd5afc2c9d3ebb24a80bd62303578b87", - "viewKey": "42208315b537e8d625a3c2ae5b77185c6b2cee1552233c7edd1a367ddfb39a54ccbde3760a337020c7ed42a0e3c75911ce6a10eab5de52551a445170db68f507", - "incomingViewKey": "169016b8098a97c18599273861c150e2232c7ea5bc93189d0eb076405920e807", - "outgoingViewKey": "ea8bb7fb76575ec9e5c3f5ab3ed106882d99b9b7fcc9afc224e0ce595e3f52f2", - "publicAddress": "8336fb0657aa4cd82cfb5fb4b6723300af8d8cd64f86b14ece8b0230c6c807a4", - "createdAt": { - "hash": { - "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" - }, - "sequence": 1 + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsSkluerLUWvC5zECd9H09NAGcrk72CjBgCVe6mHWU5OQnohpcUVmSSrXizsbx4UGJIHBmWQhNNisr+Fj2isdMMZrLsSckU8H0ZRXFuZJSW6Zx6zbF9a3M9QPeQiqkSPRdXJgEtjNNyrqZshYTlhsAYHd+vQryTQemDmvX4B6qjQTu495Qn9OyZkVv1Tx1YvygkDcO1xWjZvQp8RtFskMOLcfcwtnO6455RjcoHJPCXSlfqks2A1bXvzurDUQb6er+HdBomaeEJWQ3SALOeiFVOdjcU2KGonw3/bBIG9QhCBGNuwtfOMCpbqoaE0vdGX56WvuBfO9TUgadZsGQuuFQlT7RTYkIuUyHGoAew3cLBu41Xj4vgQQumOdewasZ38ezI280bPh3ySbGJxlW6sQeAiZYrN/OdQtjwoG186EWmcebNhlyNRyXCm3St+914OfruZsO44jU4ODdog3QGShdI1c+ZkYph/xXxOQGvUHm5yTD6T7mkm7YUpmnL8yLsVjpZi7MWlrvgPiP5T8TqZRedEa5EFw4zb8uYx3Az5QoWhaNH+SdlGhduayYeohi6M5Hn9l+KNWWb3yzC2yvDsrGp1A8j4W/jqfcLRdBIj7Fnsemhm/1nqhsqgLFfeGgHC1H7MVOvw+EFjBLYpwJ51vSbSAj6e1rSGIMLCOWNZkAPrGAvBRp6UWpfwTqQY0af2eWbZxMTCrncyaaZizys3Ef73yfggzpjLvltLEPfcbFXQAJG/1G0BCzX6xK0ZJsk6nK33Oc6T5We5dy1ODLnqpYo9ROPdpFuSosxnFFu5UEsby6CnpSOCqHSKSnyH9MfUYR8VQ/hvM2G9RqA46ugWELPovEfJS74aHDyQqfz4CPJsEuh9RBlMBLhuWX5ODVpO5g9f+/YfIQWQ/Bq7fg0FocA7WHotA2GgajPoMWuoYLp61URHOwn+cwyOgtbNz7RdzXAnCHrvIjuQRQurSkafvLwnR8zXeoqJr5Qjlwv/hw7F1BHQIGZZlFRGDzqaZ1o4AeAzkowoCMhRmYWtlYXNzZXQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG1ldGFkYXRhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMKAAAAAAAAAHsPTkV4veuMKoWfqTn4c40zztpYF2Ld0MxjnYcvp//rktg3o/nfF6Xzl+mY5MG9OvlbcNHHTu4vIY+TJChUFwB1SxZ1/fsleNYb7n8UXIYSwdFyz9o2C3VdVvMp+fUbYn1P1Uz+TS9uTm5Uyu8RRvPEz40Ez53X0awGvBp6uUAC" + }, + { + "header": { + "sequence": 3, + "previousBlockHash": "272FB9B5AAB050F9784343C1FE626C0F666E5A7418C06FE76D6E1166CEA75E1B", + "noteCommitment": { + "type": "Buffer", + "data": "base64:R+qEOUj5s/kM3zyG7IlcXqeaUi1E09iK4bgC/82opgg=" }, - "scanningEnabled": true, - "proofAuthorizingKey": "42a275b3cb8c60e9b90cc9e4d8ae72487cd3af1eff1dd61ec1b2cda588ce460b" + "transactionCommitment": { + "type": "Buffer", + "data": "base64:zQTJ9s7FJAAJmeU/gcdiOYHWpf7ororQ7fWEMOrwPvk=" + }, + "target": "9255858786337818395603165512831024101510453493377417362192396248796027", + "randomness": "0", + "timestamp": 1718998711370, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 6, + "work": "0" }, - "head": { - "hash": { + "transactions": [ + { "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAlHkmFjj+49T6eBDK+xP0DK8MOchyOu6SPtFQsLqPPQ+qIlz5nFS/B566IT7doYmiq9nRR09JcFnONh/BuoAF0Bs+uBzwA0Fp4OXUUvAvTciyHavRyYHy3D2Htd69GwnAIAFwq6HnvIbmajV5Xf7QcgvSL7ozSpNPTCdWoIRGkaAVnkXsqi18QGCJl+3fLtrqLOIGzf0W40g25EpfXTsT32JLu4dYaCWhXtXxnvXqiK+CBGSxQiOqAMs9Dm45VFfn2NS6mj+EX4vsKEgtrajseDHpOiI/aFsqQTbQNUCT87YNJeW7jPk310pg0kU6oHrYdnyjwcmQLm7jGAoCCaBWzmXats9rAYNtunXfxG26bS7ruz6HQvkSKmmMi5aWxcNHSdb3BDrM1Z4Slav4TdcmVHVkxl0cJObA4cghRFmQys18CQKKi5AxCMso/puqGUtIET4FcFqsN9Fw+seV+8jVbqhcqSSgtYkehyU/qjJj0vm6C3UnAnZus/ViabS+PIxH53ogLBLqtUeLdV1SFiy0A3QJgoAzyLdG2Xm1UxnV8hn67lQmRQS6ahd7LFlzNC3tEYvao1sIN5+ac7c2syoOqoot7L3XcOQtJ35Dz0EVOfnmIprc+0SFWklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwkqGM4g5fA4H/ZjvQBZvYEFHTo/KKyT8JwgK1AJ7SUlHFhjgk8tMpgUqgLb/y1lSewRzpUZU1lINhcL6HWsGXBQ==" }, - "sequence": 1 - } + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsSkluerLUWvC5zECd9H09NAGcrk72CjBgCVe6mHWU5OQnohpcUVmSSrXizsbx4UGJIHBmWQhNNisr+Fj2isdMMZrLsSckU8H0ZRXFuZJSW6Zx6zbF9a3M9QPeQiqkSPRdXJgEtjNNyrqZshYTlhsAYHd+vQryTQemDmvX4B6qjQTu495Qn9OyZkVv1Tx1YvygkDcO1xWjZvQp8RtFskMOLcfcwtnO6455RjcoHJPCXSlfqks2A1bXvzurDUQb6er+HdBomaeEJWQ3SALOeiFVOdjcU2KGonw3/bBIG9QhCBGNuwtfOMCpbqoaE0vdGX56WvuBfO9TUgadZsGQuuFQlT7RTYkIuUyHGoAew3cLBu41Xj4vgQQumOdewasZ38ezI280bPh3ySbGJxlW6sQeAiZYrN/OdQtjwoG186EWmcebNhlyNRyXCm3St+914OfruZsO44jU4ODdog3QGShdI1c+ZkYph/xXxOQGvUHm5yTD6T7mkm7YUpmnL8yLsVjpZi7MWlrvgPiP5T8TqZRedEa5EFw4zb8uYx3Az5QoWhaNH+SdlGhduayYeohi6M5Hn9l+KNWWb3yzC2yvDsrGp1A8j4W/jqfcLRdBIj7Fnsemhm/1nqhsqgLFfeGgHC1H7MVOvw+EFjBLYpwJ51vSbSAj6e1rSGIMLCOWNZkAPrGAvBRp6UWpfwTqQY0af2eWbZxMTCrncyaaZizys3Ef73yfggzpjLvltLEPfcbFXQAJG/1G0BCzX6xK0ZJsk6nK33Oc6T5We5dy1ODLnqpYo9ROPdpFuSosxnFFu5UEsby6CnpSOCqHSKSnyH9MfUYR8VQ/hvM2G9RqA46ugWELPovEfJS74aHDyQqfz4CPJsEuh9RBlMBLhuWX5ODVpO5g9f+/YfIQWQ/Bq7fg0FocA7WHotA2GgajPoMWuoYLp61URHOwn+cwyOgtbNz7RdzXAnCHrvIjuQRQurSkafvLwnR8zXeoqJr5Qjlwv/hw7F1BHQIGZZlFRGDzqaZ1o4AeAzkowoCMhRmYWtlYXNzZXQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG1ldGFkYXRhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMKAAAAAAAAAHsPTkV4veuMKoWfqTn4c40zztpYF2Ld0MxjnYcvp//rktg3o/nfF6Xzl+mY5MG9OvlbcNHHTu4vIY+TJChUFwB1SxZ1/fsleNYb7n8UXIYSwdFyz9o2C3VdVvMp+fUbYn1P1Uz+TS9uTm5Uyu8RRvPEz40Ez53X0awGvBp6uUAC" + } + ] + }, + { + "header": { + "sequence": 4, + "previousBlockHash": "93DC731FEC65C2E24E97378DEDD55D439FCBE79E56CC5C6944161F44FB109E40", + "noteCommitment": { + "type": "Buffer", + "data": "base64:kBHF3YNxOL8IilNDokogvegDjm/I9lyfjlDm6JvSNGQ=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:Bv2NFa1AlF5PoTAOmrvgJMKq9fJl13iSdftNIS4tdZ0=" + }, + "target": "9228823284279306817296266184515742822248210830185427859262273659833347", + "randomness": "0", + "timestamp": 1718998711826, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 7, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAAPFFBmW8j/PyVUgfNGgfykCVdiLfUUWcO6tUmbAUbFmvENyjwQlIydjPxm/dxavuyPCiYqLtRVgKVBRBaN3MCGxAqHeqmTHDgdUrBhYFW0CSzgOw+p1ptuixYO7OF3vt6HEuHsDNhlMEPnwVNaOUfPDJYgtf8S5dMHz8AIGYNCgOZmhaRhK1yjEAzyORc+cafbEOyD4jPlFLffaN6wCOjyVj+egevkeWjFwnpXqzyp2CwNdwfvPXvWsDgfRiOioMLkSOuIwjVWTdkFzVDVP3T2CyP2II2ShS9HNYSeTsI/YBU4zSDLGdNM+x2EVGYD0NghsodJCwEz3sxVt83eNTjNKvg40G2+h2rN+U382OvyKN9/ZP4xAWELu/XOmzf39zgR0J0dOxnV8XX2JlH6tQt1Pyuen9V7wPoqIsGIoD9JPb19PIIFluJOg7t47oxHopHpWiTLHhm3jZfz0WdurvZIptXU35MkXWEemxGbOMLqUwxt/SPhU47JbYLWBpNyyUHfBl/GlXoAJ5fYLKZDxnnz+UGyGGFSRq3/q+kYHWgbNMD7VLSdr78x+jDiaIBNucfeDsXV+Z/j5ZTudoWEZn+hsfnFDxvHDOfJ7kd5alq8NXHJIr2gbOnklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwZ86XEuVDtOd4ACDILit2J+sMsZUUNrNCfU8To3kNidcl297v8EvP6TcPpGnCAYlekcuysdQy/Gy70aaou0KmBg==" + } + ] } ], - "Wallet resetAccount should mark the account for deletion": [ + "Wallet scan should save assets from the chain the account does not own": [ { "value": { "version": 4, - "id": "1db0d7c0-5dc0-4af1-9349-6dfdd1eec19a", + "id": "bdc181a6-6b55-49dc-9e59-c0902bf5b8ec", "name": "a", - "spendingKey": "d380f4af79c40738657e0ee8007a4759f9486df02022273d48e2fa9cd6576563", - "viewKey": "7d408b8858c58099450f0ea14ad0e810064ff08a73078617753eb29d30b7854aea22a9f5ed8612759086087d7b78b3aa50913829f494820a533ce5f13ddc7291", - "incomingViewKey": "f16815402bf70f6e6ef3b167a3a940419db3d05f8b6eb56cff9d09373bef4900", - "outgoingViewKey": "92a38016572d0afc6a1c7bb92632134c761b4ef0dc82e6083b61c8ffd5a7c1cd", - "publicAddress": "2b617eadeb40c7e6679212318210dd34de44ae591cbb1245a80563bade2e9706", + "spendingKey": "7d48d21dad81529168478dd42c385abad164a8b745b2313dc767ddb76d994948", + "viewKey": "fdae9c1c296edfb134e49d1aa46c64d05417a7c940a8436ebed2a2b761701edc0f8d0bbe124ad2d7f6a6232dbe403b48505378f18f66ebf428378304a443966c", + "incomingViewKey": "1b5f8e55cc7fe97298fb0c30ed94d2a639fcd79c4c174fcd5051f490ebf8a605", + "outgoingViewKey": "bdfc222fbcd687066795224ccc27d04fb698c9caa56d7c87bba012ab7c907cd6", + "publicAddress": "c253b29c18945be96e99e6787635cb8111d144fad1e4bf06f4224dd4deb0b54e", "createdAt": { "hash": { "type": "Buffer", @@ -7030,7 +5864,7 @@ "sequence": 1 }, "scanningEnabled": true, - "proofAuthorizingKey": "c35690ea9aedc88905087aee7b51edb296caa78169107d016a7c2e785676bc0b" + "proofAuthorizingKey": "cbc742cb6fdb5dabd8e1c61e202845fd518dcdf371dc9d97911c86ad60b88a07" }, "head": { "hash": { @@ -7039,19 +5873,17 @@ }, "sequence": 1 } - } - ], - "Wallet resetAccount should optionally set createdAt to null": [ + }, { "value": { "version": 4, - "id": "7beffcb8-b04c-4563-a719-631d6e742547", - "name": "a", - "spendingKey": "d02703f5b2ce1d0e9fec295b9ebdc26abf840553564c7c6c82741f7f85be236f", - "viewKey": "8dfcd122af2b54d80db4593bb9c01c01a4b2dd0552907dd93c6bee790429905e18d941069116640a12c94d619f770d43b2267174b23ff5557d57c396aad28b9d", - "incomingViewKey": "f35802b507f06f6c9f0bbeb9875da6d290b147a0586c7cb83e341c120a005c04", - "outgoingViewKey": "0f418c817a72226b81e89cd2bc1166bb593d6469aadfb758301a5972a99f849e", - "publicAddress": "98648a14194cd07bc1fa21d34bdb15fd41d556250dcc10f35888f24191cab41c", + "id": "e4a46dd4-2963-4a3f-8f8e-21743f7e36ca", + "name": "b", + "spendingKey": "f3dc9f070a757849476e8b6a7c81e5877641de307db7c78f71ee4d4c22f24844", + "viewKey": "35dcdd6a8a7862e03ef133e1b1f028864644d41a57963b5698c6ce3d6f842d6e8e099be4cc1e5dba687563ff94cd1c7bbdab80f6d4c96b598ea694992d6b796d", + "incomingViewKey": "4fa528a002b17148e058ac6853e546e1a8c5fcc36d1dfee7d226bb3e14aa8204", + "outgoingViewKey": "8363fa72f466c437fa86902e36b035c63505128eee67b0626fd9ef95374d647e", + "publicAddress": "b0ce6cca74144339b1a1f4e75569d937a51e00cbc1487857564ddf40d4082f07", "createdAt": { "hash": { "type": "Buffer", @@ -7060,7 +5892,7 @@ "sequence": 1 }, "scanningEnabled": true, - "proofAuthorizingKey": "6f473605fc3fab9a66ea0f715ad6aeb36d624045086bd6c442497af0d9771103" + "proofAuthorizingKey": "1edf1b1ef2e6d68c9d6f79a7aebef28a66023ae210d609d5019588289a5d0b0a" }, "head": { "hash": { @@ -7076,15 +5908,15 @@ "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", "noteCommitment": { "type": "Buffer", - "data": "base64:xxBl7uwenihtMyNth1+es8eijtbg0APwhjU5JCkEXmI=" + "data": "base64:0oCyhTiqAZnyKvyvwDkJ1fXFKQ/UwC+XSWLFvm7B208=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:0AZsQZxjyOjkBfy5wcV0LvCB407iMYL/C86Rx7pxIgY=" + "data": "base64:dfExbCGnuMJybrBuH6nRpd4+oXyRPDJyDmpnrla812M=" }, "target": "9282972777491357380673661573939192202192629606981189395159182914949423", "randomness": "0", - "timestamp": 1717538924255, + "timestamp": 1718998712927, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", "noteSize": 4, "work": "0" @@ -7092,136 +5924,90 @@ "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAU3NULCyyfGTLdHPRcjrQu6xvlLDHRFNKQjpVRtnVe0aFKPWfudzbpib8u+yazaCbxvmBHvvnU3Tf8vEF00ny33Lgs1Y6bIA54mCbacBeT12recZHGrkqG/KW3ddUYwMxWb4J8XEaJcpEjX6ZjHsJUTz6nAtRA2K339Q7GJSQpvYRrzBTxwpfsrmoerV3Amn1BJACOJDGfAqQSqfLcNY8gPDB612FWTDZfq/hBk64WeCKyLL53ZuzHjQlpwRhqpT4Bmj3h4W3RoSFE6dEA+16ns1bdWkdG6nPWWqYYpHRlJziwkq0n4TBICEn+yrxWCJkWhAXjm/EKCndP7v2N8Qr8SH7dmBmcYSGmuEwRmN18CJJjim0xJAh157fy/mSRCJnc/FBr9plEGUmcA72m0XCiDOXtuFmOsWHoIk1siOcWFBA31MMKzsst+IrnOxX245T/co+fWCTOfWCXXQrmxAdB+iAtPmzgmO8SAlA06DJmDmtBeUVHb2vsXIXZDJjsM/jnFwV5c2vD9VeN30jf2WGwdZlOsdZbXj/59kWhruEWdWZ3XthLQqRki0fLoYGwn43HQblYP9RvwipJWmR6a6nj6ryB5DiGJ0NKWZ0lSlMJ4mJ7lw6WGUuHElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwEbvDPp+RDW8PbuCORTKWYb3bJycg1pljPBwWGbYnqt1iumQhbXVkBooC4EvqlNL2gNOd/iaBJ4FStugrQKLkAw==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAuT/alo07JnoPN5dRhQh+6/w06bPgI5p4PHdHqUm1fPON32EEVBtLg70eV25lfx6f94FMf0sZfh65dC87WqwbxeFw2BThu93vb7Qm28V5UMawD5iCI0u5PyuFasE2A0R8yBaPWKk8vhGwO9DPZRZ3qsZq9d5M+9/5/o/iXlSpK80X+rZsRmGTrZrX3cu8FZlIjpwg3oW4dWMEyyMjNPcjEOrLkX1d2E1wPFszJhp8vIekEEsB/xb14OFfZ5GYUHha2wBGHedlbM0e3goFlM+o4ixqjR2zYb+2gWNS7H2EvTez5t5DMvqaBBKsR1iv4tHqDohyk2roorG2Egqn2twwZglAvpdbWxviA0XCCW4WXACCYHKyWwjo59DR1h81KaNbkONqxfD0+EIUZAJFOQmUjdbWdBP3ncjVbIDlTnfJsYQSUwJBGXiPmAA8cj7oJ8c0hXRKEn9REWOiXvhrsW7BMeM7T8mO+MY31aY6LNrty8r35+7pwOnHrmjEgxqnYErMZUgWIsRTzuQlmd4tmyIMAzw6wfQ6ySXM5gztmAiHqHswZb49KYOlLP8PK2cGbnBWC5L8M+F4vikKLab9o0WLuIj6aweCVT4Mj3dGoOh+StT7sDDQd8imlElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw5ao6b2Po5V/WyZJsLpEEy/MMw5pvWW9Zan47u1OtIGr++SK2gVFrJ27EDS3kM015GsavU7sjg6oFk4TojxG3BA==" } ] }, { - "value": { - "version": 4, - "id": "7d4d70b2-6ec7-4167-9151-f1438c7b091f", - "name": "b", - "spendingKey": "dfeb5befd86eeec4a28484a98ae0945bef3d08d66820f23d641248d455dd8a6c", - "viewKey": "ea99d3ba32e2afdf7868ec05b672a611c7027fa1a0c2eaf0e46cc8eca047f14b8ed9d2b0980196608ff44f698b8b4f01f626a79bf764fc64d705d8d0293dd236", - "incomingViewKey": "3b7294d5f761708107d3de2fe1988055dd54c68e4718af20d7fe1acfd7532702", - "outgoingViewKey": "a9186f68b889911d78461e9b5576aae0b2d97547ba4fe809b36b53a53651ad70", - "publicAddress": "bccc050a0c7444743fb01d59230dde81003021d6cea4d8b239afe021102463e7", - "createdAt": { - "hash": { - "type": "Buffer", - "data": "base64:mZq6o8uyv4LYoSbNLuuK+fF4tYM65yBRkmI4JuPAnok=" - }, - "sequence": 2 - }, - "scanningEnabled": true, - "proofAuthorizingKey": "43394e75285fa9d2c1785fe2758c26820966f0e0d38803ce0b21d8cb406efd08" - }, - "head": { - "hash": { - "type": "Buffer", - "data": "base64:mZq6o8uyv4LYoSbNLuuK+fF4tYM65yBRkmI4JuPAnok=" - }, - "sequence": 2 - } - } - ], - "Wallet resetAccount should optionally set scanningEnabled to true": [ + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAr3z206a5rUhzKJ1PC9ZwCsJnyl3xxi+OL6vd8grPLEmpgTz8GQna5Xx/xRnmVgE3FGd2BtpUiQfwzYp945ryzkeztzFZQAWlRdKyrqsUsqanHd55LDnZEPf7mKJkTRSsgQd1xmqd+ZZ0XZUowFaoXj0hQsqXaDOD8mjxsa++ex8LKVT6frtt02xtFbtr2qJ/olVS1OpwpqyLlcgRTlUP1/T/0eDOVAUyQAMrLBC/8dKOxfQ345n00/bC4W+EZfqnp+9OumCTjFyjuq9WN88vuXlI9AUA+z5T64MDGPcs2eRb98zQTS3k0AfxvRocHeOQ5ddTMnn57y+9v9/MPoEZx/QDwSAdkas7/Qcf2DdHhjrGhTjmSgpbSmbg4obPfDYmvzWaNQL/QZ/3P1XL5bU7Cvv0k3JSr/1w4s6fvUAA84Rlnz6Yn1jS1iqe87CxIUtJQ1wwcxR1Sg/RmmrRWvObgKZmCE88eqtQCbhvU1FKUU4TwkctlbOnEG+MbN9CeC2Z4i0epyIw96oUhkclo1CocjKlemvpIIoLvVlMN/k31hPzO/9gxkW1HxUeuQQVwSZqEx0GjUCMRL91JtDiwMjJWsIDk7ys3z3/uVmpXxiUQ3hxDLjTmOKYiqaOcGd+e+40tYKrbuKpC9eg4tPR0mWXR75bcRFL2WIx++sXvm0RFZPgLxGirUqCB8VmQJ9OsKRvk07fB11aZkRkutNkV1fYZHJi9zd/nmyrrjWVRxQa5NMY65ZqrVPBow8u81PRrreRhVQR6Js9ci2A7hWkp3t1v8P+FIsBKF+ct7OFHEuMXJgN65m2gzJ8P0xbHtTu6yTmfS5V4YfVUX1uR2VCVVKONQEjf8EcKeZDD7ga1NeUbaoMuXBn200Cc+DranuFsGeVR5Ht6eKnLC3gzlGjuX/XnfOlp12X8b4pjefe3neg01A4RsuaqqlmO4of5rTKLaT9tOG0yZ86tiv+R6EhuCeky/hq2DgSiZoKwlOynBiUW+lumeZ4djXLgRHRRPrR5L8G9CJN1N6wtU5mYWtlYXNzZXQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG1ldGFkYXRhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoKAAAAAAAAACEmPOiEeDtHhHphVmloBA6u+Vqp3QdND7mmOCfuem9MLaQJtzH5bGRy0xAJlk92F0pSjwBj/Lz/IOvISnV/PwlcO2Sq3MirhgCNadmJeWO5gABO/gDELQX1DfIyemNgby79UkS8swG68VnulnCMAQewcKbHLPbuhOPKlbfFv80C" + }, { - "value": { - "version": 4, - "id": "c71a1138-638e-44fe-8058-6f61c4837c63", - "name": "a", - "spendingKey": "ecce415425e647d632f625effdb1717428b14a35a8c29bf1d8961b028be538a4", - "viewKey": "f9af8ad35f04c95bdd6b84694755bd5dc5cd92345f8262a33558632f491e145970f01a3d9e095287f2f3bc8f1a020799007eb914e439842918857737d89d8a6f", - "incomingViewKey": "368140c29ca137998fedb7e6e51f20411db9dd56a796764d9e361590ed23de07", - "outgoingViewKey": "acd19c3801777aa4fd97cf7819d08d3bece3d14b83245fe29b24acec1bb4fe96", - "publicAddress": "81ac0d338d2048bac791a3cfb92818638d183465c3fc20d24dccd73e0e442d8d", - "createdAt": { - "hash": { - "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" - }, - "sequence": 1 - }, - "scanningEnabled": true, - "proofAuthorizingKey": "eebe1953bc0241b2e20885684b0c533e110ee701b2efd97afea2ef00c999360e" - }, - "head": { - "hash": { + "header": { + "sequence": 3, + "previousBlockHash": "A1DFD858C000115E3B6DD56D93625B25E839A4416DC12A53C0D46C9B627398B9", + "noteCommitment": { "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + "data": "base64:28uBqeZXKceWrBSOAt3/AosjWSybUxDbN2DivVo1/00=" }, - "sequence": 1 - } - } - ], - "Wallet getTransactionType should return miner type for minersFee transactions": [ - { - "value": { - "version": 4, - "id": "c56fbe5c-2319-43c6-9c74-6957bd458e80", - "name": "a", - "spendingKey": "e64dd4e579c36542e7bb22de61769f11119a7449f2a28a48ce1461d8cfe4ea29", - "viewKey": "c9f799ff86541fec1f0d242c4f48056292ee077d739b5ac24a5a2d9636bc7d0f05522b614e5300c3bfcdb64f81d19390ece894886a632128503c66b644d4c452", - "incomingViewKey": "514c3812e86bf59e651f35cdf5797b41d1c3dafa1d9f3a6005781b18ac9ecb06", - "outgoingViewKey": "702f217dc84ba67dfa4bc09a3c8f6491514c9b5b1b05891ec4b9bc762ff9d4db", - "publicAddress": "60f29d4d089cbefe816d8892bc7a9e39b14541f4e8ab805819b3381ea3cd3d01", - "createdAt": { - "hash": { - "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" - }, - "sequence": 1 + "transactionCommitment": { + "type": "Buffer", + "data": "base64:eTSIjSVeiLWU6KZ4TYOaoeashqqY6Grbml/nvZBuOfI=" }, - "scanningEnabled": true, - "proofAuthorizingKey": "03aec8ded54e30e5422791974a8fc3ff5f0b9ec7ae7ff71b599962a024983508" + "target": "9255858786337818395603165512831024101510453493377417362192396248796027", + "randomness": "0", + "timestamp": 1718998714070, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 6, + "work": "0" }, - "head": { - "hash": { + "transactions": [ + { "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAA/NJnmbh919a25sPLqkCkNxs+97nPuRPu54dBxfk+pV+vYZO48n2zfdtPqwsBBR3zd8d6USGF152cERr7hBwryUM5JbRCm3CJ0Rw2ohacwAqNnm7CuRly7T5PSxUreOXsTuDZOC0dv2Lz9wrnpCxkjBc/XffUV9EkT9QVoo0lfgENz3kih+rZeC/BvqIflJ0N4G839gmsVvonA6jzxChoNl705MkhyKZlQFTs4mNSF5ahwJMUKwj0EJRZWU3PQwJX8VKeHo+ZLyzPuhVd8H5PmJnSnJnsU92L+x12wRrU/yNd1oWOkOoYlC4Jvd4MUgK3K7tUI1VSM7LaNzB7XAvEgFMm8guqltnaVEQRizkv54Gr6l6xcUs1kg//VlhWKgxPJgpgAnwmA/7LDAr+zbZp3nupMUXKUuH7oR4b9SSao1n/WgzM7hbGBvcMxKSOceKZi02tPWRVcrjQ5APtFeF14P1/U9qeZKEk3MMaU0v2RC1Cp61oWidypjxxy2hWuHj2xiECFsVj3hG8gzSuVqU6K3WNEPt4C3fvazy1JAW13BCBdyBMQg6l48mix6joQJ2HwJNgTcg6c7dpkoSaMkqwzXpSTJRVFQKDjl8OHf0k9r6pq9bBXdp3HElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwR0LObUeOt1vE1Miyq610+3dTq9KFagXjt3ieQZG9uu5cHAvDvl+DfkSchQ18KQVNcnvF6i0SCgkd2rH/eGVLAQ==" }, - "sequence": 1 - } + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAr3z206a5rUhzKJ1PC9ZwCsJnyl3xxi+OL6vd8grPLEmpgTz8GQna5Xx/xRnmVgE3FGd2BtpUiQfwzYp945ryzkeztzFZQAWlRdKyrqsUsqanHd55LDnZEPf7mKJkTRSsgQd1xmqd+ZZ0XZUowFaoXj0hQsqXaDOD8mjxsa++ex8LKVT6frtt02xtFbtr2qJ/olVS1OpwpqyLlcgRTlUP1/T/0eDOVAUyQAMrLBC/8dKOxfQ345n00/bC4W+EZfqnp+9OumCTjFyjuq9WN88vuXlI9AUA+z5T64MDGPcs2eRb98zQTS3k0AfxvRocHeOQ5ddTMnn57y+9v9/MPoEZx/QDwSAdkas7/Qcf2DdHhjrGhTjmSgpbSmbg4obPfDYmvzWaNQL/QZ/3P1XL5bU7Cvv0k3JSr/1w4s6fvUAA84Rlnz6Yn1jS1iqe87CxIUtJQ1wwcxR1Sg/RmmrRWvObgKZmCE88eqtQCbhvU1FKUU4TwkctlbOnEG+MbN9CeC2Z4i0epyIw96oUhkclo1CocjKlemvpIIoLvVlMN/k31hPzO/9gxkW1HxUeuQQVwSZqEx0GjUCMRL91JtDiwMjJWsIDk7ys3z3/uVmpXxiUQ3hxDLjTmOKYiqaOcGd+e+40tYKrbuKpC9eg4tPR0mWXR75bcRFL2WIx++sXvm0RFZPgLxGirUqCB8VmQJ9OsKRvk07fB11aZkRkutNkV1fYZHJi9zd/nmyrrjWVRxQa5NMY65ZqrVPBow8u81PRrreRhVQR6Js9ci2A7hWkp3t1v8P+FIsBKF+ct7OFHEuMXJgN65m2gzJ8P0xbHtTu6yTmfS5V4YfVUX1uR2VCVVKONQEjf8EcKeZDD7ga1NeUbaoMuXBn200Cc+DranuFsGeVR5Ht6eKnLC3gzlGjuX/XnfOlp12X8b4pjefe3neg01A4RsuaqqlmO4of5rTKLaT9tOG0yZ86tiv+R6EhuCeky/hq2DgSiZoKwlOynBiUW+lumeZ4djXLgRHRRPrR5L8G9CJN1N6wtU5mYWtlYXNzZXQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG1ldGFkYXRhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoKAAAAAAAAACEmPOiEeDtHhHphVmloBA6u+Vqp3QdND7mmOCfuem9MLaQJtzH5bGRy0xAJlk92F0pSjwBj/Lz/IOvISnV/PwlcO2Sq3MirhgCNadmJeWO5gABO/gDELQX1DfIyemNgby79UkS8swG68VnulnCMAQewcKbHLPbuhOPKlbfFv80C" + } + ] + }, + { + "type": "Buffer", + "data": "base64:AQEAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsf46DKX34ev/n8SRi3cxGBCmV2/IZhZ7XFSVuadJmoyH+dz/UEq8ZAOggG2ih6PggKl1waEF6bmeDVt9HmA99K3mpNftYD/U9HeO4ZluPimmFn/JS0m6rNMy9Da7eQf8QrGUET+zkkcDxl+kLX2s/IC8qgG/k3GriLSSw7Hy22wAqroYfAyiiB/QBHyKIoeceRxO8o6UU27c5iq9qB+Z3aFylmal4o7aMLsgA1D5tGmqTK7NBUzy9le+QozrTcrq2VyROuYMPxDKgO6hsR8QmYLSGsz1QaEZQ4IBis7Bbv4WG+LohLJgy00cTfmcaRMQw5+ygwn6dwyvY/8XhKAU0tvLganmVynHlqwUjgLd/wKLI1ksm1MQ2zdg4r1aNf9NBgAAAHGMXWlmiez+Bt1uJnIJLiYxY75a4tnUcqQ7anXQpUo15bN0ZEAMRZOSTTBZjIEEoPovmmDVoNT2i17iXRdml9qR9cdNtaghFFWApvDNVbVTHzjCiekU/wSVIvn5/1WpDJlT465OqqW2d7607ZaByNbsGKoIWL7H+GWT9C9bAk6jWzK9Y23HvEEpUlDR04tCg4qiNmyZ5NPr/ww58X+hR32NukYgjUdONxFIYFpqcJlnia8adu07ERfdoG17V9hqghj6zr5MlRUbD0skMFr5JDgy/Sv0GaXpSXC1619uBtmUqhyW7ulf7SKrN8VDAIn6UajiIF26Jl1uJxVLfVoVxwg5k8VnYVCaR8P2Cm11a2dhyYvSXLANoc3Crui4xCI+8HFV4eB6KXQp01hpJ6dNA628zct/6pFP5tS2EphjGZPcgW9WVM1xesV3lkFDebI055w5f/tQZjRhRtDkqFezDErDRBIXuUCDsivEah+l6ccwrgO51y46NxBgWYrC7A3GOP1p25WpZkMEEnV/GZ2LSeQGyPy/8FKzgHo+gLVDyvpKO7uePvbWs3vcc2xzlO7qzrzOWokNe8VSHYFvGiFLKkN0bVtg92lpeWuhWNjiPSMczkGKzwd3/6XdP0WPczanQlJbKNOeoEV5ZRP+SPXv+cx7jz0u73OoLroaGs1ndFPgQCfzRfUf62FUxFVd0U0aFMnSRQtu3K+W1QmIh08LfdPWABakAm2AiUA9uzYat6O7E6UqnzFX6uwGesCiUnTUCV1TdJrrS7fE57DlExcy80P3KXaU7k/tZSA6Elgx5hd+bXlcZRunI1Kn8xb0d+oPUTX7dOYj4xE6j9MishxxPBzIHD7C170tiBEvKDobGSZHOsPcAho8uvqUXcvAN22xJXc6pyfWH1+HMvoRJHtA6mEg9T2ORyBlILJEdoIBgyTPE3E/yqd27lYAY0PJHg8JqLPiL15ZihxhXfvBcn3Pa2TPXD09vEawKjxgVSb8TcNUjPgUcdIcxnCHnsLf2aVdwErvutecZ/gwXEJqI5ubkXCDDTRDRX+rK8+HQVptrtdffzrGCFftztxGrDK4IiWSaOVWjOC9hRJfDBZQ7TP/VDstweDNPMTzEkfgfNIyrmDRUxA93G8NGcxOf/8GdaVYRJ87aZYZKSsEG2YuxbtwJPz3fb8nkQ+BKf+x4Knfo2TjLP5Xz4EOyCoWEWiNyv0MaTYGBQByNQzdDkPRAPDFuSw4vrGHLRunbYkTF3o4b1NLIn5/uK7GUHE1o4ENf4/bgZAzCEzMwI1yMEDexp4s15BzPWGwuJG5o6c//vSC90DjKUKFE6caTEGn7IWLTFmpkV2RzSPJQuV46rMLTQmh9J0RKTqikl1zS+DAixGec371JUy0cxvEGPVYfIAgCZEWtIRkcyJZHMjph/3mtzuLfkatu1YyMYwiO9M7EOgEy/QPt1j6wL6VN84zEG61bOpNGoxe/kxnp3GCneESt6rnKZ5v+GGGLORd9pZAjr6XCXgL7y+OhyEq8ns4zUyPsSl0384S25HGgJ5zHfmBO3aNrgBvtMnIFNMFXE1ybHGup4SNsQQHe7YSdoBbbD6QwSHxDQ==" }, { "header": { - "sequence": 2, - "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", + "sequence": 4, + "previousBlockHash": "7785D93CF60D2D01E7438966BCB020416F6FCD85CE6598C7AAEA3DB91D11ED36", "noteCommitment": { "type": "Buffer", - "data": "base64:D+WvBzZCzglfbki2aW7CExBQTYwhthCDqqGeTJNA3AE=" + "data": "base64:SvlE/JLGCc3Dc9aof+eSJoAXgQaRjYTRwnaar87sFBA=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:tZDwrof0mSVCzaFO/8KbpJjC4UzZlApxhdkikVYRcMc=" + "data": "base64:2/p55iiSZWuGQrCipruiSF4TzxZR843SFsl5A/gIvEk=" }, - "target": "9282972777491357380673661573939192202192629606981189395159182914949423", + "target": "9228823284279306817296266184515742822248210830185427859262273659833347", "randomness": "0", - "timestamp": 1717538940787, + "timestamp": 1718998716388, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 4, + "noteSize": 9, "work": "0" }, "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAlzbVRjPC61/JquWjwWyxyuF8Aaxg9sW3d6vGFmVfHF2tIu4Fml71ATpmI0i6X92Fx9irMPI2CIh+UFgO2PmR6wsYv2gWaT6XQURcSGiO+NmB0zXFRDq4boO5uuSRfRwitcRjKhO+b3uqlLLOWzz61l1qjHH/Qpj+vio90vrOQgcCwMjDNE1P8fOhIQmPOhf46oixUERd/zPqEECvaVpml+4R2lYCwJJoYKvqqP1FL5+1ufTRdMr6YQ3g3KuJJSQBCepqWzFiTInca95LI5LUVfYsnkj7o5pQjG9FmeSDWCtTC2S2qInyEMFZDCGmbINwUoeROqz36qIvLPkdwnEs66gFaV6Ki85sVtxBNS53Z2gJN5SVLKqsoBhaEdY8EpkwjbgQmEs+lRsAIr2H/BnTpAr+JGTEQKTpyS9UK8jIOV2SHDAr54ogOLdQU/t6e8rFmvaMupO/zMktpLWXU5Wx/B9JFvKUTY/M3nmdhDmoFvzI1QGZklfTPzhvOqLVZmmZyOEZc8yL6ciwWG6g98V5Bw2l4dJvsziVSZskXhqLdHmmv9zqH0ER0I4PDYA2kOvbgRAZeoddLkWBGNbJgSWhOM8AqkaxanwG3NaCCkFLx2Y9pwjSz0YUiklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw+4Y2WOP5osklh8+xp33c4C6rsgG4d5R+Qkd4DAI/eICJfe4OsYSH7BQSSMt9KcOdZcT1/zgYQNkooCuo8LewAg==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAjPFV3XQn55MP/1zlKrJa2F7ArSZpTb63+NrkKiV0OGeTl0Ky1k01lcAqaz+ZRo7RTSSjyUXDWy442D6UclW3Wuv+yK2fwVesLnt+GsFrO6ugw4+E8KnnC94ltRT76ocN1nOY5w/is5bzQv4F+M0QY/ECeD0/9ih67wTSkn97agUERNxwE6b46wWXoRJxSB1JhnvSAIaVJv9h/cKe9D/+NSK8k6mjhoF0QxLDH9h6fS6gcDNFr55dV58kMOLdfothrRYMz0csZgsFRD+LQd9cvBUz1NORynwqtS8RWOOwwpwI3KYEO7YAX4JSgHVsapDyr87Oe0ojhSj1XfYpEzelFmcYNoeb2J18oOGWTtpHy9QiJrkyN+O9mNr88ihBkEUhoFfKLSwNHMBK/+d49VDDuCtnyKcVsMt2Grw/ZEqLYt2Xlweo/zzaHiVfjwPQh98lSLledVi99a39jKO0jOCdMYe3glvmnazaATAZzzhUhX0Ky7VDpn7V6NGtg9zSZiEUz7n0rYldNKiLA2Yk+1Coi/J0cyI1BpHRM9HyCAesO6XC/15xpyAhJT+AlXGZPcyWPpl5XuQWZet7liFIpmkvmT4KQ5QycA7ghZdUE74faShfVaUqeRicNklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwvmIZviEQ49o3CTCqj9KCyEpeYfFmGPWHuRj+en5mO2E7hvOnf2vGFI3F6IQg1oIEg3k8r8oS+kKTZXdt/6enCQ==" + }, + { + "type": "Buffer", + "data": "base64:AQEAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsf46DKX34ev/n8SRi3cxGBCmV2/IZhZ7XFSVuadJmoyH+dz/UEq8ZAOggG2ih6PggKl1waEF6bmeDVt9HmA99K3mpNftYD/U9HeO4ZluPimmFn/JS0m6rNMy9Da7eQf8QrGUET+zkkcDxl+kLX2s/IC8qgG/k3GriLSSw7Hy22wAqroYfAyiiB/QBHyKIoeceRxO8o6UU27c5iq9qB+Z3aFylmal4o7aMLsgA1D5tGmqTK7NBUzy9le+QozrTcrq2VyROuYMPxDKgO6hsR8QmYLSGsz1QaEZQ4IBis7Bbv4WG+LohLJgy00cTfmcaRMQw5+ygwn6dwyvY/8XhKAU0tvLganmVynHlqwUjgLd/wKLI1ksm1MQ2zdg4r1aNf9NBgAAAHGMXWlmiez+Bt1uJnIJLiYxY75a4tnUcqQ7anXQpUo15bN0ZEAMRZOSTTBZjIEEoPovmmDVoNT2i17iXRdml9qR9cdNtaghFFWApvDNVbVTHzjCiekU/wSVIvn5/1WpDJlT465OqqW2d7607ZaByNbsGKoIWL7H+GWT9C9bAk6jWzK9Y23HvEEpUlDR04tCg4qiNmyZ5NPr/ww58X+hR32NukYgjUdONxFIYFpqcJlnia8adu07ERfdoG17V9hqghj6zr5MlRUbD0skMFr5JDgy/Sv0GaXpSXC1619uBtmUqhyW7ulf7SKrN8VDAIn6UajiIF26Jl1uJxVLfVoVxwg5k8VnYVCaR8P2Cm11a2dhyYvSXLANoc3Crui4xCI+8HFV4eB6KXQp01hpJ6dNA628zct/6pFP5tS2EphjGZPcgW9WVM1xesV3lkFDebI055w5f/tQZjRhRtDkqFezDErDRBIXuUCDsivEah+l6ccwrgO51y46NxBgWYrC7A3GOP1p25WpZkMEEnV/GZ2LSeQGyPy/8FKzgHo+gLVDyvpKO7uePvbWs3vcc2xzlO7qzrzOWokNe8VSHYFvGiFLKkN0bVtg92lpeWuhWNjiPSMczkGKzwd3/6XdP0WPczanQlJbKNOeoEV5ZRP+SPXv+cx7jz0u73OoLroaGs1ndFPgQCfzRfUf62FUxFVd0U0aFMnSRQtu3K+W1QmIh08LfdPWABakAm2AiUA9uzYat6O7E6UqnzFX6uwGesCiUnTUCV1TdJrrS7fE57DlExcy80P3KXaU7k/tZSA6Elgx5hd+bXlcZRunI1Kn8xb0d+oPUTX7dOYj4xE6j9MishxxPBzIHD7C170tiBEvKDobGSZHOsPcAho8uvqUXcvAN22xJXc6pyfWH1+HMvoRJHtA6mEg9T2ORyBlILJEdoIBgyTPE3E/yqd27lYAY0PJHg8JqLPiL15ZihxhXfvBcn3Pa2TPXD09vEawKjxgVSb8TcNUjPgUcdIcxnCHnsLf2aVdwErvutecZ/gwXEJqI5ubkXCDDTRDRX+rK8+HQVptrtdffzrGCFftztxGrDK4IiWSaOVWjOC9hRJfDBZQ7TP/VDstweDNPMTzEkfgfNIyrmDRUxA93G8NGcxOf/8GdaVYRJ87aZYZKSsEG2YuxbtwJPz3fb8nkQ+BKf+x4Knfo2TjLP5Xz4EOyCoWEWiNyv0MaTYGBQByNQzdDkPRAPDFuSw4vrGHLRunbYkTF3o4b1NLIn5/uK7GUHE1o4ENf4/bgZAzCEzMwI1yMEDexp4s15BzPWGwuJG5o6c//vSC90DjKUKFE6caTEGn7IWLTFmpkV2RzSPJQuV46rMLTQmh9J0RKTqikl1zS+DAixGec371JUy0cxvEGPVYfIAgCZEWtIRkcyJZHMjph/3mtzuLfkatu1YyMYwiO9M7EOgEy/QPt1j6wL6VN84zEG61bOpNGoxe/kxnp3GCneESt6rnKZ5v+GGGLORd9pZAjr6XCXgL7y+OhyEq8ns4zUyPsSl0384S25HGgJ5zHfmBO3aNrgBvtMnIFNMFXE1ybHGup4SNsQQHe7YSdoBbbD6QwSHxDQ==" } ] } ], - "Wallet getTransactionType should return send type for outgoing transactions": [ + "Wallet scan should add transactions to accounts if the account spends, but does not receive notes": [ { "value": { "version": 4, - "id": "64e75cf9-efd5-44ee-90ae-35c791638917", + "id": "50376cb0-c18c-4a9f-b2d8-48130a3b36f8", "name": "a", - "spendingKey": "846f74914a7f7fe27a35df50c4459a65af4b8d1317638b5c7d08ecff5a894e07", - "viewKey": "df507062f8bb6759ff5626cec5a59ac49a173906e94bef23ca185bdfaf3a691e918383a46293981fb85b4971a798c56cad7315f35b2aa11bef4116f449aca84b", - "incomingViewKey": "15b6ef66795b5a640221a5fe863b69542ca92aaade03e33d4c828b1aee050205", - "outgoingViewKey": "ee464e9cc173682b92fe04a12db52e03e8951d02d58049776c774c450cebec77", - "publicAddress": "fc1b87236e98d329028c59dcb55139dece067d9a8092fc02f92bb83d5afd6cbf", + "spendingKey": "0fbe0f47e68c6ae12f774705faf73f426c3b82687d9f6c436835b405555479e9", + "viewKey": "6fccd442bad1509317a3483da3e1065b5c5f968904c6e64cbbb23b89f275a6a3a42004ed5cfde6716878f66d504ae3787322dd024906ca4942bcfa163fcbd5d3", + "incomingViewKey": "cc9f96ea76668ecca95562334d936d0deec92e4f851b201941480a73cf58c207", + "outgoingViewKey": "392d5baa236ace5670483c774b1d89f105ec83d2c878e08f4985300ed2a09145", + "publicAddress": "a0fe3b97b976c443140e07deeb5fe308bbaa2001b9ff49b4ad86df9c8d272f96", "createdAt": { "hash": { "type": "Buffer", @@ -7230,7 +6016,7 @@ "sequence": 1 }, "scanningEnabled": true, - "proofAuthorizingKey": "dd2c457f45e3131857b78dbf882f21d5f825f81362f7211860f565ce9ada9d05" + "proofAuthorizingKey": "769f765514f867ef878297cc07f437344893ac7f82a85762d39d95eeea470906" }, "head": { "hash": { @@ -7243,13 +6029,13 @@ { "value": { "version": 4, - "id": "a4e9c220-3d1c-4e4c-9d24-4424ee2d47bd", + "id": "d37ffaf0-847d-4284-942b-c83d69031d48", "name": "b", - "spendingKey": "9a915605737f1a94b9cc8db0d7fb3d7b4e6cd0c3ec25a2b92971d5d32677121a", - "viewKey": "944293a643ac12d0fd3f9528dab304777b10702243562f8532b890b4acd0a41fedb2e3045bf3385e577dc051807e559cb8ef243292101e473c07d0980edc6d72", - "incomingViewKey": "13de79e7e2ef97fea168a875f3f78d0b4e40bc17757c46d673475b992b6dce01", - "outgoingViewKey": "539ea34dcb6523714f018c29b17dc0450fe1735f0acc7980e74038a1ac7f88b7", - "publicAddress": "5ec695f11f12ae8e29f508edfef57acf4a2f1ec4a157c803c9d6365ce119143b", + "spendingKey": "6f3ea4580e54053f905b710dcca5b09ccbf0cda779fb4edffc18dcb9225be680", + "viewKey": "2f963c00eafac58da9fb02ee32d2d57112a57f6d84827a817844452300b2450ced5ae3a4753c0904327ce7e680150388f840daffa414be9530f45b3d57da51e5", + "incomingViewKey": "4bda4aecbc3ae34e47d40ae5849e5348dfc59f2364ab6b1130f85d7ea2500304", + "outgoingViewKey": "7c9eeab937c4849bf319e38559a73e654ce1ce067e8f68d2516483661747d615", + "publicAddress": "d7b74f04612a48ba0add85013e3df5fff7e4e9ad71d928da534eb9550d6d67dc", "createdAt": { "hash": { "type": "Buffer", @@ -7258,7 +6044,7 @@ "sequence": 1 }, "scanningEnabled": true, - "proofAuthorizingKey": "640914444bada025c574a7553cbad78e573d6ec2fae65c1df5321db909d1e609" + "proofAuthorizingKey": "e2419be2dfdbe1ecafb99d0e09d27ca845d0ca4745323e77b2a576d46d9ab207" }, "head": { "hash": { @@ -7274,15 +6060,15 @@ "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", "noteCommitment": { "type": "Buffer", - "data": "base64:kD/0V2KfYuAAuyhjJ1rEUdjuFosJ5ZOXBGS6fa+MCms=" + "data": "base64:ZVsuuTLt4XhvcZnBSSV6uaOWDkjBTAmYHoL+zv08BkQ=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:qn/FQnlKaVfstPrKsqMgT74EPCnldIDowffOxo8imuU=" + "data": "base64:/vA3ZYYNHb17hemzV6AksqInp+MGQwTtFaD41tZmpv8=" }, "target": "9282972777491357380673661573939192202192629606981189395159182914949423", "randomness": "0", - "timestamp": 1717538943989, + "timestamp": 1718998717727, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", "noteSize": 4, "work": "0" @@ -7290,95 +6076,117 @@ "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAARrRd4fMOdXv6ERlKatGHMjzlPZZxMB2JQS/Er5qjq8GorCef/Bk0Dc5HW7+t5L4U8e/YW7+hV43jtiD/wqQIa590jbWOqPPvYzrWGKZXBguXnxyq0EqhayGREmDIApDdFNxWm/Pn/RvXiIbQ71FLAo+y2Zphnk7RYanKTOM/ohcTx1bgVF9L54fk72WX+1LvY2JT1jr59Pd0PjyveSrpjICvv7bw4WVKbEgrrOCBrc+rt93jsA8lJ5a3L8R2ykHOfWw/hfGcn6wycv/oNT9oFggWBhntgE4CpLpREmVuP0DSlzUa8Vv54f/thmfBT+ZcX1BLbwZNvFdqdlm9meldKt4JIrXWxYwowFrwYdJV5icZza1/39PU8OXLvY48ItE9Q6xuYmIUGQiJ677uTcIELMgB0cYKPN3BsCz3k9/kwumdBHlQPXfnIFQkjCrXnKTxXiEcL52qAjgJaniiCBlC9idGL9bijOYSPweGUa++/R3mYZbtibA6IsZxqatBw4NAwruXDsS1iEoMrwq3lA0uIyovbo3x8LPVflanA2F8SQpjxnpl+PNm3z3qwAtmNH8EfY0S9EN81cvPI5tucJglsOcuf2W6OLxSu+8eKZW2uvCHb2pkSFIlMElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwQwjNX1alENo2d91FWMLxrni6nUGPSHwxCzMmSvVpHSVN2PVwQEkrHpL1m9y7WwWDaALzaxqHs7+TkIYf0IeHCg==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAjefRxfyJ8okVx86BcEIDpaa2kstW1lXDQm8IZH9IY3KTdjy0tgtVjdpcbOGB3csSu1v81gI0ykaJVqCF2Umltnx0n0MqrSAmJwCPKgd2AX+iIVWDK4hCma3etSmtNlMfnvGWGCA54YhqDI7omkG/pSWCKbARQhCSJv8SmQaQjhsA82bhUKiLsfHpQu6Ztqnfz7OCWvWwItFJHJa0Ll3De1J3+rut+nm666F66y7jRG20WCzFyVBBLAZgGc2JiNgOJcwo4Xa9yLwVIGt7OJzMNsGRE190MtcykPUMb5CJQJNTi117Q56luVOHZ9hwhoj7NLswBz5DKoEmJ/u9oBhbscky2pJNiJbbmuCcFRKXmoBfYU5cewVoys5hddOqcPAWBZkVre7mez9bwX/Y3HHtrlt6RFvfQAUuOBaNYAnA30nDDE01JuqqnRlo/uRpCa0XmCEfpfsmHUbyQy2IgZcdGUQAu1keFRbqJPEINmnza1MG3iVt35CDEWC5rp3os07qU4DussT/m2T81QnJQJS51adCg4sU6OXujBDSSn6VTFxzKzg0l0wZmfFqynAfgmkrFjDf6B+RgNPxR0plYkDU8Qyf7P7RHiq6OTClqgn48739Xmq7NSBeyUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwcXPRTd7YL+fhiiZj1zkQA8oXhFBArzNDklDUIBmoUZYq8e7ot2HkenZ1gMeu1aLnZBLODeiQP5c2FZmLVDsxCg==" } ] }, { "header": { "sequence": 3, - "previousBlockHash": "40B02466CAF9ED8415965338E5CE0EAD1E7D27C275E6CAD55BD573A04B1B9034", + "previousBlockHash": "DF97E204760D5DEB4EB34DD842375E408DED59D23EB68EE93EB7A576FD62B48D", "noteCommitment": { "type": "Buffer", - "data": "base64:wxUR8U5uQ5+diof3bZLH1O8Q7n5E+T69JYjYZ7aaczA=" + "data": "base64:tN2/rx1uS9oklsWNiQHT4Pujqkn2H5rxhsVzcazDmGs=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:uiQHkSFVPaWVvtcrOnglAc8idhVSfYoagSvqphapeC8=" + "data": "base64:K+Rq7lGlObLNMuI2//UwZ/ehCYQyh+z1w/TfqEy8ZZA=" }, "target": "9255858786337818395603165512831024101510453493377417362192396248796027", "randomness": "0", - "timestamp": 1717538945379, + "timestamp": 1718998719572, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 5, + "noteSize": 6, "work": "0" }, "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAo8hSIw/8R+iPBJtDF4t23PlICjM8tzIy5+Mhmu1cAzWovsye+5OC8dBlnCWItgwZPRSsJBkOHjfVxc7DhXuGft+T1UsaLtOXizE/tjKkJNeIfYhREDfyl1hkVLuUgjXbVo0c2hvwfdoXxSBErwRt2bQ+7rXXSxlh7oTW/I1xJL8N15qz0PBLg+QTjsPp2L2dZALD80agZlXOjnflmxYX2bzgcqVd6M9lsRbUdnsuSnKUOT1kxw0I1cigm5IipCFlaUwNJteT6fan3M/MBD4YEViYg3C4bFdB6RjW37/AMxFNUcz4QKCPjJEhUH94EcWo+WegWsBNykALQNuOOoiVybTDdLhRK+VQ7/yoXv+qZIddNQYZlhSTNwP7toBxzy4rBBXwp43PqEh4jhQvgstcGWYo540HFVLFYiQ7rrje31abqqtU2RrGVtsQrxZazxqXwnrJsd8FTnOs6ImbGDP5PdNDE/OoAh5ozhWM5WzjOuummjzj93sx4G99naHuF8Ey+VvFPexFY3aYLzni2fW5/uXibLJI4y5wtR2lvtMj7mLfz2Tjq0CUAbArYtwbyJdVLPO3cOiJDgOcnFBc5rJ6poU4vEMPDFW4XMihGL+SnMPW7VEJ/JwZMElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwYWRFBFNE4rl0YdYwffKKrmmNXZD9pTHOKfqya37ws1u6kD15uzqCrw+dxd++66U4o67ghgJujvNcYQHvUZkrBQ==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdiUEf////8AAAAAjn4SqHnpJxr3xEfdcSrwlvWIoEWaDasAuZ5vUfgiCoKuSkc3jW1T7dlGW41k0jiaBeOJRc+zUBj+gSGzzjRG2ENvggcoXgJyjEwgFt8Bh2SyxpnA2Z3vzHqOJiULG11euI7YPgcDOTTWgefBjhvh3020lK1NvnPW1NJ9fey5iUwT1NUaEnBYHDKPP3KUVBeSSLprn010P9vrFaZJMP28T3lsiDeAubaG0xOU/Os3pTazewIQOeq2iB7m/ne2WmhxxGdQBYgYBcIPmE+A/K6mTTRxLNJmpfBB9il71o3FvJJBOFC3RRlIXIZL81HGOAhUjNckpIePL129h2SBzMgPZWo9pfFcRTQIMgUq09L3mx2Ya9UdBUJDD4Itm22Szbket0TZyVoELvKdeYIvbMc1NAKwZ81K4dO9GdC94TtUOJK6zv7SABfxXdFqFTY7PcgiqX+BsFCMhCavExwQra8hFUkHxjL8K+AgYTXv6Ne2Uswimjd03oK2NEAwq4Z5Dsf5NRfbo03H6a/m9jGtaXsikR/42TT3naFRrrdLNsJxkk51jOGg3yi8sx9X3w39+HhgOH0I+EnSnJzmf/f+fhXv6BE6kDV+kdRWJByTLQDHN3BqSesV6JQSj0lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw3YCfbUGhIenmguozd1lj8ctMn8wXOl+ZLuVbZlC8Awj8kucMYJ3n5OCT6Fct7V8+99kJEKif90l/ob8RcMEbBg==" + }, + { + "type": "Buffer", + "data": "base64:AQEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/5M1dwAAAAAAAAAAM2xsqx3frTSOWm+6ENKY9y756KtJ3CDwyvveW6xlwNOr/LdsdENo3unQFw7FLWUjvp6jekw3VXe0gRXbRManpQp7NcK3odB6NwKT+SXcM1ewVt9hw2a+meFS4sHMeFA09uM1CJMLCzL7jcciT6A9SeS9vcOa2UHFAN2L0jKtRaAXREMBVslN/KRIEP5Epqbdy26a2M0xLo18diUy0nb/6iwM5aClDKiqyQRc9Afvw3SGWAqibRVcKnK/95b8zL4GCNypMZGg0j0KZuZ+tSoadSvnXf2Fh6uNlXQM8X/xGyACMyLOAB151BuEhI7RaXYwnc4fITADa4+K5gPso7FuAWVbLrky7eF4b3GZwUklermjlg5IwUwJmB6C/s79PAZEBAAAAJ5TiFx0SaOjKaHCJUmLmAiKir+xFMtYsM/z/yTkJx4U72zhychk6tWtCaq2RWuU+wmwjtHhPAFbpuZCCbJIlZO/ZXmgvXLITzAI+16T4h5fedRbdjcsHC6sRpvidV8AB4MAu0k1AwXvXna6hHEWTnLjcoEQc5rk8iMhF9dTjuuXsan2PIDQeap5VZk5xmCYaoygBpklFBg5lXFWEbK6FW595U5sv1CPxhibEviQS4W/naqk4RKBKbERtVroScJmNRFy+pITLt56oXVO/jSd4IqB0vs50h5y7cMtGzG6h2Ia7Bnsq2pcYwpB/eWuIbB+gY2iB4Zs3eaRrbpgEGfpIcUKIAZzlCJV0qnmYXyJ1IdF7HE+Y2N7uiNDVoDke4SA8LTKknDmTb7sRopOEd5/+6rKwxYfMxd8HmdRAK232aPIg/qxOjxPCdQ43eRZ2CwQnuAKXY0sJRQ1L+nA+hjiLUIhf52DvxtFp5lDoCZwCUQn7dtDMXjm3FPqYaRFnNMHZQMA9WyApCGlbe8HDjmRJQhrzciXwUWPjgzUIu6VzAjumTAOWilggYPrScPtRGiwC4gn1feS/4u0Rf3S2EtEJzbtbsEi0zIXpiK3GfSwas4MzBVKqm9ZjAAgadV7kDKfVPUSXxFSA+xsWNHmXwKGig4+TFywvt9kpAmGAFluAhouGxeJea+Bi6JAgspVKi6OH9dfyLy+zHmw1J+xRs/cNEET8cht9gT2l0pPTaEpOqeiNI+dkQFzp8GwJq/Z+cOkTuN1oYJwXiGKLodSDaPoXXye3/0B6uSU6nugo+dunCgfTcc2UJrHGYPKRASwzIf9My17sjhnLMuZNy+wmNS6ruKgrLSI753bEL+EgVjeL6+uGlijAJm6uQSfdPgtF4y/lPGSWNDkNooF" } ] + } + ], + "Wallet scan should set null account.createdAt for the first on-chain transaction of an account": [ + { + "value": { + "version": 4, + "id": "98991cea-da6a-4bbf-8cc5-4fdd27f81271", + "name": "accountA", + "spendingKey": "6c5a641a371df373dd39dfc3ecc0d984999ad3a7d0a0786ab13d0e15e1ade682", + "viewKey": "09fc30937fd87b9910cbd75580559afb6825c020d589d66ab3daa550be6a0a9bb0c6ea88d93cecdfe7cc675c523c6a2bf7cf2f04f8f2e1f2953bd9be95a49539", + "incomingViewKey": "5db14e89c345663d5f066d7ce62e2d22f98a3c8f038c068bc8d48bab84b6f307", + "outgoingViewKey": "85de8a992117c4880fac395536df58f1eb2ff4c06634e30ee9393ac90ebd457f", + "publicAddress": "e9c1fb3d3841e52e96d6cff8eac4e8f5cc0f1bd0a07a5bfac5bd5ec99cb997c7", + "createdAt": null, + "scanningEnabled": true, + "proofAuthorizingKey": "d71357283f7d946802c5893f6bf994c6faf8097caf27adba4f04b87ea6724904" + }, + "head": null }, { "header": { - "sequence": 4, - "previousBlockHash": "9C5B62C46AE334039F95FA2D1283B13CCF490FDDE4AC28D78BFA62B7F90456A9", + "sequence": 2, + "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", "noteCommitment": { "type": "Buffer", - "data": "base64:DL2vFwoSCgdRX3juXF6dXT9YxBSigN2wXN9V7ownxVk=" + "data": "base64:TQXdLry7EgfukF8ipqsKdRTM+FJcOnnnVczBUoke7iU=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:1LvYS+S1Dn96TH3DwZo3mKvnZmFLPGErmtJL8Cp+dr8=" + "data": "base64:6oPCNz+EGoWrITI2NYnEYeGjbiOcwv/JAvMLq8dTqKU=" }, - "target": "9237817552710710459325694168790757901687427753068917234625768156097641", + "target": "9282972777491357380673661573939192202192629606981189395159182914949423", "randomness": "0", - "timestamp": 1717538960856, + "timestamp": 1718998720696, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 8, + "noteSize": 4, "work": "0" }, "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/2vKiP////8AAAAA/LHvmXP0C7WunnQq4s5Sb0sSsAv7OM9rwNhnVxL3jqWopCzCiW8R7M/1UrcIYS1l20OqB/HXuMbW9FJiyM7290ZKA46AX3X6M7688rXQ55+ZiM2ODDygDexvMukbR3Ta0nLxUay/HDdkYkiDYZ0xKwhPKo1KZWjd/svnQ6w3gMEBBHZe/plDym+VJTAWJ84+/L3/cg9uClWIPob01zqm2GESETQzjeviPgtndP+9Gf+o2MAH+3ne0IyfPEqP5s1mVggJaNOwacMIEKMG4kY6GOkKAzQAT/ThnjG3zMMke46cxA91SjrRsyXCXuo2bjvJpoE45vypUdONEI6XRiNUJ30g70leY40A0KefYfWbBEV32qMtHFTxPRpxAV5BpI5lIBR1nOpgnKe2XZe/fsGquEQoi6vRDw1EIsqpV+RzqKUnz3PXr7SDBs+Np/ukf9bKV6iL8nn3/SuPAJqZMBX/6DigDo9h4elsBfnT50X+yDAti0FzJlGUXrnghwvtVomqgAFsUB1LRA7ooSOy1ZHUumA3ZtOkfYIUK3nNfEfo2dlrie4yxWFnjPdajSPGyE7pZiExygSIkRYkPFV/RbAT4wp5gUJAS7xwExEL6fjOkA7X8hIAh6xDiklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwFrKErzF+1B8ZY9ppvwcve/QJqV5qA1G0JvfTdbjTQdwBFbJ1b1G8nhrJ8Ypo+uOFL1fvIldpZwQnEDt1GNYyCw==" - }, - { - "type": "Buffer", - "data": "base64:AQEAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAb/X0X/HI7xUdgYl1jiGPiR4t7HdilFNJ1ImbNhdb+3GqmA0ZOezL4zI07AqSDpfDCVxGFUWVZtI71GNgXkYgffijxVP0HB5WCJY00I8pr/yILWkGTmsGx2ba+nCETyGQzTynYOHQDPSKCjP6WeVNQYBGH1NS31VmfQabfM/BBmESEMsMRGeMnMVkVEfpIJc+RC6pk2X9V7/8sR2He1f0eaVP3nrumv3RCZ06HlWv/qqk4jNc2bYxPuX1QbEcN1+cp2jpwjaZVj8Mz7bCq0vuFVmh4MPNgIFzBkXALZDfr+8r42ClnixuJnRnycBDTR+Rxk+30ixo2f8H75jO/yZKpsMVEfFObkOfnYqH922Sx9TvEO5+RPk+vSWI2Ge2mnMwBQAAAFxR7JF5Oo2tKN4jwUixToZndxikLOQEZNNxXB01L5mCAyNgCmShjCt/7QWttLAwWnyb+r04vzOlok1r2bQFKN6t87sPBvP28FFHv7i101RFKYReRYTof/CrTgpQPKqMCIbjqqtSMFYv/Ecp2P5bmN2Xir/5Y4rrJose9rF0VqDgvoa9zqn3Ei9lkAcyHTTUa6ak0XMP1ilQ6wdnR7XMU8M24DeuVY/hqzlNIiBoVciLwQXPNZy2hm+rRneLDNRYvhnmaBEuzloZ5uM0yQqK+Luo0N28+Q8bzHEpz3j8VAiFbDRgeZw/LL1L+mdgW0OxK45s8LmwjtsOAYLmwD8MIlPU3jR75tgMMs+UBhyft2OBW2hEYkt0+wm3TgS9z248nl10eHEuSCtU3TKhbLl5oyPOIZcHDgUTf/GtX/Df4Xo19Xs54U6ordx9+ScZk8wnCibCyUCbSb1YC2nYu3yDpXMqEGoGtcFJOefQl0gBMAm68YjAsB6yy/ibxv62sqYIJs/2LHc17sb2WKxTTkMZxppQrtCadW4FqnS+hujPOc+i9gABoKUyqZCs1IMumY7g3T9qPbq3tnY8QfgB382mP5PRJoLmrX4lPWXKUVTqrY1RsteaqnYCKF11mHY1rBRxpcdZJgqntDNreaapPwDts/U5DDir1JXObJXJOVDDOaUajllDNz8BXkikmV27kYa6i6vEywcwTRIXnx1b/Hk7xr2tV27dHIJV5zsZ3zrVlHfQEii7xxQIm1sN6+O97hiyqQtMIZWVeuLtlO2t7b24p0x5ADrKJ3JSvzcE3qNszUTf3k9+6fIAcKyoSp+Epd3KpmLa2t00adRUyYWMew0z3w2SFot8+TkgZiCBxjderq9bcwqiSnIGVeSL6zVh1AVgUX3zwdw1CbuRjTYwc9Q65Ftz9ew13CEUWqS+7PTW5tl26Gje0oN8BGgMrFstW2tF3p2yHOeik9YX/UY+4WI1tuk9E5fdHezUQbgZKnqt0Qw1lQiCxbMmLS+GBZwxgR1fLKo0B2o0zbWA9+kVBkBLHQMykP6hhqWMgFf+s05kAYslZlBaKNcYO5OG0zDnpunoTSTcCdtLVizIW3E074MnKvPuKMauuW9SBS39FTJ850PyFCeRz9ExEeModGNZFtFjyQDu+DhhfO8UNAKyyn00CfhH4YVprDWn3fCfz6bj1KOqjSnuWXS285pppECdE+nVE2V7LVDTexWYJyyjmVlRY0m0NLTNrjLRWxzT0loESC45zs/M66e8EdWM50zduL1aAeQreNpaWwBGg8rUwQuuWomwyAcVo2+GgTqRC3kFCtQSVaHB801WHcguech1wTaEN1hl9NjMCEOWYyqaJEwUoNlz+lhrlrTfb0QWCXz3d+X3Ci7R2xhyNv6Dv7+HIHKLASNOMkksbpyTUdkYaXeK2B+vs3shVhFX6WnM8+0jZq0ZT91XBybLPUfZR1LpwlYHaBLvJwvZGZ1TGlItQkJ4aHmcgtOQmp7G9p/vV0RQlTIlO96ioiSHoui8Qv3Qp7uSltg9Ip5GCu9WvlYzhdTeShCnlrWhrtrYO0eJCtGN1SG8o6v0UBK78mkVRlyedx9LBw==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAm3cSdXbX7cKHnSCrfA+gGBUvoBPRkrzbSOKHj6Jj/musrgqgsGRLp6MtrA4KrDN1sc8KjM8UpwGNwKUqz9+gXA8EGlp+V4I7tELelqBbg/uQkK/LUqq0uzEoRdOswE5dyA44piCvU1cbbteME37SzwX5e0bBmDyavD22IuivygACQtkSLdjtH/rjU+U5+8ID3xPRAx94raBT9GZMzws5Rmgkh/5cOiKi5UnlY3B2CS6lckx8r02PYALueYyHBq9BHqFdjIAx+ZSX214tP+T5SMnlBhG6NSOEojSu4JQ6O7HUGUnIf2xhwLsg0ftP1CdHKB9GfFHnDnfNOEDOGKA7AfJ8qQWlzTjymKxWVcmsd4UjUC1MSKlo3igCU2/x3ZZedQfUp/yiH0A8tW5lhwvZckrGBQ4mWtLAk21QYd7A8AQprr4wwaQ10mRe7s00L3e2sH3g07d59mAalpVYqLm0sKrKzF6KqW0Z9OVtApvMjxIat6TW3dVNHucaLvDQCFRE7c1M/F7n/Jf7fv0/2Q7k7tD15AGuRCoL5bWfS3fSJKg6YFvnJOLHZngbGyTq8LOoFuUYDRu8aeRliMaPZdv7Ln3CMwqa2JPSpdC5wiOJ1SJZNoiQw+fs00lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwJ84t4RTp8dTjF6gNHcHGuMgql9+jfMDOV1AEHjHQkqpp+qAzf3chVdnOqj2Hh9CwA8kwKnpcIrsh1grpcnk4BA==" } ] } ], - "Wallet getTransactionType should return send type for mint transactions": [ + "Wallet scan should not set account.createdAt if the account has no transaction on the block": [ { "value": { "version": 4, - "id": "1752aafb-063a-407e-9a89-fa6cf21251df", - "name": "a", - "spendingKey": "3ddf6ef059038d3e00eb9c054356b73243d47b655afb53de6780406ed467b70b", - "viewKey": "93cb0e9ef0adc763018cc7cccdb287024460bd9de22778d649bc021f436275a5bb98700cc9e01b463d2eb1c6fc73468874076e37224ae57fff95d51dee4566c9", - "incomingViewKey": "e1d116d102f3832dee495bf0b8e22e9ac241e394c839f4a3cc6c17b70a1ec701", - "outgoingViewKey": "c481bc21735be6f39e11cdcafba614db85f4183153b8b539641ea0830fd3c11d", - "publicAddress": "f0fbe34510ec326ba09245a4d54837dad8b32031a2d9fcad7cc79e66f3effd17", - "createdAt": { - "hash": { - "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" - }, - "sequence": 1 - }, + "id": "a31335b0-59a0-4544-8168-d812ed76e603", + "name": "accountA", + "spendingKey": "87b2bd40fd9bb27d8cb5553cd63f162ede5d5b95b988a09f93bb0373afca66e7", + "viewKey": "112d5ed92dd70bae4cf2f11d74d93ab643ee0953294cb9974c135faeaccdcd4009444fd2ab596ec499a47d599770a9e2cc4460afdaaafa354bb1ca449bdfb206", + "incomingViewKey": "2b96bca15ecb9cb436ca4d770d3d8a4b9545cd353c666c4dcc4fe77601a50806", + "outgoingViewKey": "357c78b412cc8fd39cd0ca4d6387cc5efcd7e3101465607734923b39d463da3a", + "publicAddress": "e7ef66ff93467d483d1f8b42e4d569501cfc567448ec7b302bac008da172f4be", + "createdAt": null, "scanningEnabled": true, - "proofAuthorizingKey": "ae8e40d882b798ec0ad76c8cd52bf7930efe746e038b86607520c2016388910c" + "proofAuthorizingKey": "6c50131848a61ce5f7d26de20ddd6286864f022ab88c78704f9b858ee540210e" }, - "head": { - "hash": { - "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" - }, - "sequence": 1 - } + "head": null + }, + { + "value": { + "version": 4, + "id": "a009f9c2-b16b-4500-b246-2e94506ebcb9", + "name": "accountB", + "spendingKey": "21aaf945865c7910e0cbbf02aa1aa9990907451c0bdd35d71a74d2e007cdec03", + "viewKey": "0f7035d736159ca841c02b6df564491448a45fd054a3d4cb2bd33f5a236f57942e93ab131eb4a97e06e2e3671f99d9052f7f63f2309e8435e0137a9bcc027616", + "incomingViewKey": "bab6b41768380ff997078c8305b688fe92358b181d7244c1929bbb7c1f8b8d02", + "outgoingViewKey": "d300ab9a2c9e0237d9555fda97832feff2bdbcb73e58fa87ab67031609694ec9", + "publicAddress": "368de5243f8a31b2979a7b9ab6234e6d0d4e391e393a894a3e4febb77e323687", + "createdAt": null, + "scanningEnabled": true, + "proofAuthorizingKey": "d37cdf6fef4c6dadf450d22d8695ac754930a7b110e7fe48d2bc0d7daaf53e00" + }, + "head": null }, { "header": { @@ -7386,15 +6194,15 @@ "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", "noteCommitment": { "type": "Buffer", - "data": "base64:onCdNmggF/2oGVp4f/p8oknj0nj8lc/SLDHFGX/YWUI=" + "data": "base64:rno/E0mfHjie+7Kc3aS30qPrnU4yZFtw1DlqCfdLExQ=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:52ERR+LGjawjWBROzSmoSEo9uPzsNdDEI8sI9O63sJo=" + "data": "base64:nHkAiwD89LJtKTABXYEM8jZDg4LqcgvyM3nVaorULCk=" }, "target": "9282972777491357380673661573939192202192629606981189395159182914949423", "randomness": "0", - "timestamp": 1717538965971, + "timestamp": 1718998721727, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", "noteSize": 4, "work": "0" @@ -7402,56 +6210,92 @@ "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAArn5L3SkJFV6D2iI0M6BIYRDQBFYZmqWKrv4hi1j/W6SXq9VIai5CjFHYLIaXlJAEhNtquTP6IgL9896gqhnPqbdhbd6HycGg6y+OqPoNQwOE3VG/Mv4hPqMWnmzBsGZKnWyg2+IeIOvoKSewBuEMklUN5o0uFz0XRXFI0wxXuVkMSJDOn/Nv5yedmJBfu/IqEux6Brr+a4GnLZR6RprhtIxRnS0srk51wjCjdqN8peeQ+WiWTwgJa/MzU4l3v0OCN0rWHZl4b2Tt1dmb0RNpzW9UB+YFe1ATOl1OzosOKebiivMk0TUKtpOntjzGXqLA7gH4pdN1FepmKPily3yl5IegfpR7B+tQnjCzPXWOqSs5Wcjm5HcwceztZYly9yomBmTrGZ/peNaBim5F0ckO17BTQjQhS/8AZIo4SYmP8VuLirAmnRo1oy8hgGynYBzbTbJDPj3HEsT1xQRzB5+ed+28CWVuwfpA9tC9tpFpSWFe7HX4cvIQZBkojzPG/1Py+dODzRnQLv7VrshbnpcwAO2UPr2AHLG8Fwc7zIAZ24F6eNHN65aHb+dUhvHXjTP4iDlHg6yNXllku3FKEvc8kVQaB2LhPHW3lwKnNBYFQOlWMcIrwYuODUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwcjJfwd0I9efczfg20oav1ibON8LckBbQkoXToi18vhnsAyplf0g+wdX/SK2N5eEXIyK7pJ3qeVlt7H+vHCijBg==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAc2P9rmGqlrHZ/ADOkq/2N8hhuWHb9hcqIngJz6OSyeW0sYPMCbG3ngxXoj1hvRpoNQWfoTP3MUFEAwdV520XHN/nQsGZqkjzEzC9opAjd0SmIsjqAsoeL1b/6XgpzHp/M0RhEEAq/B1XUcG1jqMwsKjHpjeX831joS7aW2kyBY8SuHCVlbbBh7fp9lWIa/fi3IYN6DSsyGEJYlPdvP8Hq9Pthe+OnTjRfmiFoqa3DwSUCuVzGT96b8LXdANDvI3NqjpY4WU0kmfPjKm47nXPL5x/NwD2MJVpC3BbOWuAz5l7baRoAzMtnkXII1lZ4s3mipJVG4ztLCAnJDSAhrg4Kh2uKZUL8IcX+1E1oJEuUK95C++C3idzEJlNnc1YGdFZKBC95GPPz0c9VmViQu2a95iSh6Kox0KvdJnJUtHwR/G16Mqp0no7V3DHdqBQQQFAfrWKlFS/wlUY6+6C7o3p5s+P2lsoEwnsAdXMPOSAEbrcz7T1I5ldjZI4akSmoK1nSWylneCVDOTwQgfyN8d5WEDEUyrOBhY9JOIMpGzc6PQKZ5YJ0VZbai5RmTif8Bxxl7R9hZdlXV/PxrQX7ABixov3NL0E/f2GG1v3Nyk3Dla6a/tZPoZBCklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw+cugJ+ZCekWQXEr/BamcuY0rk+UejCo407FMBBxjKQ6/HMcCUJWq2u0ZwRDSVrYhjWCmDox/ZUzkKdJop0O8Bw==" } ] - }, + } + ], + "Wallet scan should not set account.createdAt if it is not null": [ { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+MdUUPjPr8bYZCJtC3J2W4iA938sRS3Qoe2BZJzBrgWKvokrOsO0O/hDpcz5SvYv1bSNzwldDXrJoRIzVMB+cYyX6fkN0Cx/oAZlukvFI/muwiPA75GDk8tHuYvEoDvTw7WRve/ltH+QC/NJpquGnsv3svnkZj7qar4pEEQbNpAZovB/TUJD7Unzoae4escwbKsFkdh67iuegyxt26gIe8IHn2kcvn3fS/bsQO55NcSXC7CauLu2F3gmjLbgq9KaOpbbwifsHGXM+zW/UWzL/V8HL9FAISt+4NxP9wxwvxa//SRdJ7MguUEr8JXVSQxK5Y1xL+gipkqwzwqOshkcNIGpoX4013FSoIAbcnzrBqHWfhGihtHLeDyC9co8Lgpo/kVYSvJnqgtopdigb+8VY254wEvt8QA3vByw115LBm1x5yRh3mAxFa1aSjedz0X58ErncHLAoXqOXZbsnxLACEtjkb6dulKxdvzl0MGQBZvwYDCnlrq7t5M1NJlnMNWbCm+zmPCTEq4lLPRKMj5yoO0p0i1vDZqSpoatJbFHE6xMFcuyGC0DGpNHRCoFlfh2TNXLkaZl2OKsob4EjsS+vqnT5yCnIGbe8PfBVWwN5zwePJrYYJspTfBUnQ08ui+eGoprZlSX6jYdY7h/lO7TXalWQ0iqeZGcNlwLwF/wlnSTnyuGOOuzAxuSfR+TbvyIunSmOlLl9+2rnJ6f7vRly0RpUJWc0UbMp5ReHEgT6FrQRkJy2nAEWEKipTKuJGYKzt8RxpaobwfYK2A+9kJYds/lbtE9twVmj64i/CQxWL+zkurINVrYaSMbMEckGH47cH8xEzMFdc0cb++2gIvRLrJd7nRuHbO+ELzsz48eW2lGZL5PTuLqZ5u0sxzI7HOs0Tscv/xS4t8BAd8djZffsitKJDqPKSTpmRwkpkCBtxymMrFqTXujAkrxQ4vWUK1jlES6PNB5dntroZqwWXBNALcXRL7lNOrP8PvjRRDsMmugkkWk1Ug32tizIDGi2fytfMeeZvPv/RdmYWtlYXNzZXQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG1ldGFkYXRhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAKVllL5fZK+LL8CsKp+KUlDcVZSF7SgJeIKXj6e+BAY+rWp+ecYfUBZLX7ZrP+JQXsA1JfRbjB9cPp1n6ltc+Ag+smvti84jb2uZThx+QUg3rENLxJc8EeuLnnMV6fA3pt4YSEZ1gBEbth0piU1z9vPdnpyi8jS5HrWwtBHLKngF" + "value": { + "version": 4, + "id": "b51a2177-7bf9-49d5-b3c8-7020567c2f78", + "name": "accountA", + "spendingKey": "641c1bdfcfb9c53b5fa91b612d083e66f03cb3d18e7a733b9e6b12062baa8b4f", + "viewKey": "d3b69546923d9ae28bc804f2236e10e8a9209ea8327792bb5810f18079185642765e95bf26c434cda64e5a3e899c6f9cbe8270dd163b8cbbe87b7b3e6e8b2d11", + "incomingViewKey": "e10aae9a56527576cc9fc13320972cb64795c4e09b2a49033c80bbafd275fa00", + "outgoingViewKey": "24e88559218318ed0d30fb12626f7ebd5d1eae39c7c648f3344925c2e4f8513a", + "publicAddress": "0951bd228d8b1d4d0b374478d0358ff586c4372f1bedd7eaaac4c5672c2f2819", + "createdAt": null, + "scanningEnabled": true, + "proofAuthorizingKey": "6bcffffdd490ffba451aded0449ea15d42f27df3b8e7be94e658d309e8563807" + }, + "head": null }, { "header": { - "sequence": 3, - "previousBlockHash": "87E305098235CD4ED1E59AAB0E750C25DE65C2808B5142C0DBF463975747C6DF", + "sequence": 2, + "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", "noteCommitment": { "type": "Buffer", - "data": "base64:xOp7eiljMucd2lTHf590CbEP6FhPcEsBkx8RuinEsxI=" + "data": "base64:CeM7ZiqpJ94aF3xuvweO8TbeF37XmbC7kmG8B8pDATc=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:Nixjzd7o7fnd1LWmI1xLyZegfs7QSYMTwiLyggwrzgk=" + "data": "base64:hsNOgWGdqZ5Kqzhnm/t36IqzIC7khF2HYAXQL2+olNY=" }, - "target": "9260366780148527510972123832573278885902566341756516011968728852484845", + "target": "9282972777491357380673661573939192202192629606981189395159182914949423", "randomness": "0", - "timestamp": 1717538973214, + "timestamp": 1718998722800, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 6, + "noteSize": 4, "work": "0" }, "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAKF84UDt0oViCmGUPnejc+ywBy30UoeOGW2bUrCMI34Cg9rR2FynPxlwGN+QgmBxjnEHIDdLHLIvswKI7uV9lA3kCQNrhje05X1q3cG1/zHWNXqOUYWwN0igYCCUH3eWBNR9pv2jTtH5JTGomyYvQEbqQkTezxQfYbxTCUXFZ39QWxxhwHrM7pg4krwcwucTl6DBpTnekawRDmg41eUZ4qIAI0vwjkzvIWiebFupRaICATpH1koxEMAwzbUKeNntYeWCNFqmeX656N73yeAMfq5uOYkv9Drf1PWRTG2t+bud0UbN2p4H7MYha9Ih4bPgAncyt+JpIuo/aiOsjzwE7kRw5eJE4Yz6IKVRG8UjyoMrpiqJPAOcMeWn6h7WjaPhRz6i6+dnYjaojCXuQj5xmzg2ppthvdABgqVYLJ2eeMsICvfLZ85b1hyYjcaLTbKiBzq3ccxEHQrBMNm2Tm2feN/898gKKGCqDD4NaRzVozuEm4U3Muyl5yJG3ErHYdPXYCS550Joxk3PQl6S7w94yAZKMMUXTBatCVcc5sK/7/LU1gmjBmkjp+8ZKdTnQR5In8HRh8HygMxNhPA0tKSO2kAYGG8EdvMsdzeZKndldn7pVbhLGwuPQ/klyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwqcoKO324naEHo7H3CsJYViRrjbMdiIaOSYTVU7gVuHC6DBbVm5CuAu1beM7a+33QhqICVQS6w4uRSaj+mJrNCQ==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAn5mKakjLbopC8b5ZMYWuYrmA8HMrzaVfHwpxYS7BNdaAP3OobriYPDls/HjhK+2EimlsSX68i+cRJPzZkYnBQRlqt1VkURq5lcA++FaCYfGpN6tbBWzY6JyxFJvivYuE/Q/boYalvm4J3J/aYNN4MNp2q7Fp6wyxiuipBInyXXsCpSbWXbkJxOieX//N3ZIpbh2BmNkJzNWC3dYbbLxfiRrBeIBsxbe1KgwswZ+qfwKyh5LdabL4R+42odr25+AtYb0Yzwirq8dKt+/uiKc7MYrKUmgidhypu8kNK48owiK1osx7aOJsxKWnLIl86rz2uBni01HShu1utmLrYJDhhY6L8X0bsEH5hvUhwklnDEeEeQV/g27GnFrdE9CZ0QtonFxbIysdXgyb8RA6cBhpfdyAAwb9Eref/FvUx4wxm4P24VEBtEuHwbaXAam1/s5IbzpAKChX9t8tlc2Hs1pongPsa76/t1X0N7BxBlhYfSeGVIw9mEUFvTpryibIf1IysgU2r53gnr9pj9TO/Yy3usn1SF72mda/zCRVcTO1YhwfGkTyMEm3WNByI7zqlLeshvDHHyQHYVUhfLssbRdDIZ1OHd3etfOqtLJoMFvI79PmNOwQlV3JzElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwnYMsLZBmmyxiPmVnZO5txPHfqPHzz03HI6s3tO+QftPoBniGe05y117jKTLztGOKR4Whtx+BqmSSv0oKQDkBAg==" + } + ] + }, + { + "header": { + "sequence": 3, + "previousBlockHash": "F68930008A6CEE0775619E6B57CE0E00E23B8B3D46DDA0AEABFE278208A5C932", + "noteCommitment": { + "type": "Buffer", + "data": "base64:J2DN23oTrpIte4AeFhXEQbTMzX1UTOeZQI7CAnw/4Eg=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:wLuMntvBDYmme1IFV1r3M1J3eO0bTWoMaClwFcxAclE=" }, + "target": "9255858786337818395603165512831024101510453493377417362192396248796027", + "randomness": "0", + "timestamp": 1718998723311, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 5, + "work": "0" + }, + "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+MdUUPjPr8bYZCJtC3J2W4iA938sRS3Qoe2BZJzBrgWKvokrOsO0O/hDpcz5SvYv1bSNzwldDXrJoRIzVMB+cYyX6fkN0Cx/oAZlukvFI/muwiPA75GDk8tHuYvEoDvTw7WRve/ltH+QC/NJpquGnsv3svnkZj7qar4pEEQbNpAZovB/TUJD7Unzoae4escwbKsFkdh67iuegyxt26gIe8IHn2kcvn3fS/bsQO55NcSXC7CauLu2F3gmjLbgq9KaOpbbwifsHGXM+zW/UWzL/V8HL9FAISt+4NxP9wxwvxa//SRdJ7MguUEr8JXVSQxK5Y1xL+gipkqwzwqOshkcNIGpoX4013FSoIAbcnzrBqHWfhGihtHLeDyC9co8Lgpo/kVYSvJnqgtopdigb+8VY254wEvt8QA3vByw115LBm1x5yRh3mAxFa1aSjedz0X58ErncHLAoXqOXZbsnxLACEtjkb6dulKxdvzl0MGQBZvwYDCnlrq7t5M1NJlnMNWbCm+zmPCTEq4lLPRKMj5yoO0p0i1vDZqSpoatJbFHE6xMFcuyGC0DGpNHRCoFlfh2TNXLkaZl2OKsob4EjsS+vqnT5yCnIGbe8PfBVWwN5zwePJrYYJspTfBUnQ08ui+eGoprZlSX6jYdY7h/lO7TXalWQ0iqeZGcNlwLwF/wlnSTnyuGOOuzAxuSfR+TbvyIunSmOlLl9+2rnJ6f7vRly0RpUJWc0UbMp5ReHEgT6FrQRkJy2nAEWEKipTKuJGYKzt8RxpaobwfYK2A+9kJYds/lbtE9twVmj64i/CQxWL+zkurINVrYaSMbMEckGH47cH8xEzMFdc0cb++2gIvRLrJd7nRuHbO+ELzsz48eW2lGZL5PTuLqZ5u0sxzI7HOs0Tscv/xS4t8BAd8djZffsitKJDqPKSTpmRwkpkCBtxymMrFqTXujAkrxQ4vWUK1jlES6PNB5dntroZqwWXBNALcXRL7lNOrP8PvjRRDsMmugkkWk1Ug32tizIDGi2fytfMeeZvPv/RdmYWtlYXNzZXQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG1ldGFkYXRhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAKVllL5fZK+LL8CsKp+KUlDcVZSF7SgJeIKXj6e+BAY+rWp+ecYfUBZLX7ZrP+JQXsA1JfRbjB9cPp1n6ltc+Ag+smvti84jb2uZThx+QUg3rENLxJc8EeuLnnMV6fA3pt4YSEZ1gBEbth0piU1z9vPdnpyi8jS5HrWwtBHLKngF" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAOT4hp3kzfrJQfa/A0mGj7voP84AvUQajpSsBdj97I3CvILgRKetnGcnBe8ffBA2aUf8gdbAFW4TdU+NDHL28tA0AacTubqNK5sdrTxiHfxGl5C9JqPAs3ATFmeElsHaOWSaqHS7mV0cCBuH1M0JEuzGsaKNTL2jRvC9rTWApsmAV1yKqiAspfwMN166BvOxrskd7uPDN8lWPnwjdQI29aZD4ZU/ihjM1W4A/ppIOhKaEY0mIXpeiOzgWA3EAIE1APAPsJR+7z+CHAvdHWFe+IMBzHsOsWz+vuMbtDU98c2WsDjRG9R8G2kqVanpwyloy7SZg686AQ5p2wDbMeMDfA+fww+zD+p87VoNL3zxP4Nzw+QnDst1tM3zpaQouHa4T0rt5OB3AFBrZMAcOEZ9RbT/Ucq+hGa12HR2WWrugM+KpgEfJkcYXZ18iLAWKiJACUH7DUPmrszPtpcESfarxluXhjOQHHOVWLCI4xIEZqRwsfAdOvoMIXRi40K0xB+UJpHANOE9eo8Ss54gfXmIbhLDpRkfCeTw/ms++0vyPt0j/DM7wEF2XaFccF4l7FuK/cgR/RYWC6HwIHmKlQ/FiP7dV7/eY4ChEzvpbNPVnED6+Wuk7VE9Dhklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwV+gJr6dA7B2IZy8lSR8WsYLaRBzYXKisGusQfhGTjINnFFWXdvx3VgP0qYv3c09MlLd2r+fcRBlPyDC0Z5DQBw==" } ] } ], - "Wallet getTransactionType should return send type for burn transactions": [ + "Wallet scan should skip updating accounts with scanningEnabled set to false": [ { "value": { "version": 4, - "id": "e70d60b0-ed2c-4ecd-8733-6868e06a1f07", + "id": "1e4922c6-aad6-4092-91a5-2f338fcd26d4", "name": "a", - "spendingKey": "1e0f64aa9f3399ff327fcee2f958d2878b22c330976591ce22260ed49b7a6ae2", - "viewKey": "f24aa2d07299bd40c42bde10abbac5d2eb8a610ed05e69cb09e058427deb3aad28024d98a0418fe395b0923a0063926ec3674da1b2d70a08d0d6c85a332c6265", - "incomingViewKey": "f9203e5893973e234d850b65573003ba04f89c231195d0598a4198c446d89102", - "outgoingViewKey": "641d47cd60fb9991e6c62561f53f3b557f04a285ae6924cc5914718e9fbbe138", - "publicAddress": "cec7be662b6bac78af667994b490f26857d18dca1e728488ffe7de0b01c4404e", + "spendingKey": "50defddc864b45ae3d92b0663d1ed98ade1d7f4cfc7da5609b73122abae7862c", + "viewKey": "bb5ca714f08db91372f4ac368253bb91675cab092b2a443227f85d30498aacbf12d3c65d86b6c8342760ba3d9f5789959ab875c70b3d77b93ffb582dbe6ee8a0", + "incomingViewKey": "d4f4638e9621a02550df9c0e7aa46bbd556a6cbd5469a860801cfbb85682ef05", + "outgoingViewKey": "654d1cecc91700d92d4f1e0d6381ad6f27e593fe587f509b45dd337cbde0aa1d", + "publicAddress": "4106a42311ec85d37716faec49be530a90885dbb5ed126bb0f67d69ac3839ef3", "createdAt": { "hash": { "type": "Buffer", @@ -7460,7 +6304,35 @@ "sequence": 1 }, "scanningEnabled": true, - "proofAuthorizingKey": "23b064a3b8d0933b948996bf738832e9f7c65e859c7112dd9b3ab9309db3d507" + "proofAuthorizingKey": "fb887f4f928541aa4ff3d1a93d527dcfa29778255ad7dd6cfbe24e1725ab6804" + }, + "head": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + } + }, + { + "value": { + "version": 4, + "id": "878e5aae-8a5b-4a0b-8b81-cfe176fcaabd", + "name": "b", + "spendingKey": "17bc6df6fe6cd3500b85aebbb86a9626c62c57098b63d2ce18ff125b9bd89185", + "viewKey": "ffc8e1787c9bbbcb75f3ba139943747f3cc3914f3c4e87e6531bbf3cdeb7da6f9f750bc2a14677d316aeda30f0c6919ffdb45c3166255a05652ebcc7c6893cde", + "incomingViewKey": "bd582662218864859210d8a719129a19dcf7a879e4d05a13597abf7023199f00", + "outgoingViewKey": "d7be5cd02680db56a1eae3d0dbbc4d8e88743d21ef2581dd40c07be295f5c584", + "publicAddress": "5af1ab5b21b972f6cd638eeb7165b67d1b3db81164f4d0f17ca5ed0e9713d1d2", + "createdAt": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + }, + "scanningEnabled": true, + "proofAuthorizingKey": "ac3815e4928d9f9eee9faf47f3cf37b389c6d439699e5486df2c14449560630e" }, "head": { "hash": { @@ -7476,15 +6348,15 @@ "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", "noteCommitment": { "type": "Buffer", - "data": "base64:aS7ASLGMZiv7hpmqlHeNB5FRMyV91rVJBc1tPoKm1C8=" + "data": "base64:R+jWuC0JYf0T7xNmD6XGJgIcuA5oePRNISk3RICRaQs=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:AuB8iwuUK4wG0Mq67TGU6TTpY4xgsEAbVKgn0qS0tI4=" + "data": "base64:JsO3m4JXINrXPB6EI20vO0aFSyjip9mhInzjDrLW/Kc=" }, "target": "9282972777491357380673661573939192202192629606981189395159182914949423", "randomness": "0", - "timestamp": 1717538977678, + "timestamp": 1718998724419, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", "noteSize": 4, "work": "0" @@ -7492,90 +6364,48 @@ "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAT4+USY6FnToSV7ZjcHzWvUT9p6fvxmTd0dFshKKHhaOwV6UxnRaFMxwRGAiRQmkQs/crpIVhpvceXbUV0C/YbCWZr2K+T0GRnnxGzHWROC+y3YMorg10M5SUK57UFTD9z0pZhMJzJTqx4Wt/JLwXgwbEzamfBEBSQNyYM4ZX+NoZh/7ySogA208M4saEhys9gwb6DRcPdIpXozNsnnGN7miACrdJcyi/oF9akZyooCaRsGJCV4GDZ00lnor4AESThyoGb2xHW4YjCNfqEbdANtuECOKFGMc5B2SHb4h3m1gmH0T2wBHj9ToomU27LHKtGLe5XdEU1ibsfrwgFin0P7R7AJRrXhcw2xmxgiy3p1DpsCJyzEMSM2ApROZmxyYEkSAEnZ4GUvasMfxQh06GBZRVgrwDcRzod8HAcaJaFNExqNMayN+hVYOz64arKT1yAMGyKsdrhUtFz5HFVv0EVxz/tjwZDulRKp3TPwKCVw/9Z8U8etc7CNnBNUM/AAfuLbeXCKyrAga7Wgc613aUtt2cm91yRg4zREMCETkzgYPVqS0K2iXmTqha/GRiOC2pCYlfetpSemH4eOE7ql1eA7XCulNxv2/rFeTznc1aElOagai+E7Eyzklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwmv67lpCUh67l1lWOSSZZrAwIbOxlwXQx2mUV/wjgZkqaS6b1DxMVg4lRdMz1336XflHtqPG5UhzuZdIy3XQRDg==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAABcSOR4fMrH91YBEfpzjRHFiGoXDVJNK8ysZAKcvxf0anR3ylnovmFXuUbPhhtuiLLbCbaa3ptq1msDsQ5wR9y8HtL9ucYNgfA9sEIp8PGIyolMqmhlhnH+vSVbe/n6ui25mTa4oMKmwlBtvY9zkpoKrTA704CiXKQ87wSqYtp/oE+Q0yDWSDxNg8FW1a4JfO7aOVoOQNEZlDvku8JUCc7tfeAB2kyO4KIZrw6uFyN46F2jaoVvrlx7+MYUtthgTutjsnVw1nIOo0ugOuIYGgBAEoN1+AEaaVSiupeMc4m+vEX+4WvW4F4jvsSxTgSMbWX0ooN05QjbqSJwAYhO0ZYixW8AJuEiJM0UEKXFGTmOfemL5IMCNP3aCNUCQuER0KHqi7Zo+R/hX1HK5yKya5mT9kDuCIHwtmlKsNCZXdIsdBgVyS41L7wRNx94YHNeVefzbxfue69hcPuR9uAU2fAaJDSifKrAvoTAF2kql6fuvNL7DzuLXYdUfy/MDYXbhvsJE+Gt9m5j2fl7pVxhQaygdOUHykt96gJp8KEIO7nr/tOHsH4iV1qzBiEHYSu0Z5JN1cYTGCvDJLQXmPBXq9AQqg3jF1dQ5c7Y13HZW4+Sx5ikMUQKMlq0lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwIlCkMe8MTJOaB+rlORtldvZZB3Hm0AaQCl/r9Ms/p1vvlNtgSQSE9hk5vCcFRBuvI0hHL0DgMjzyB4ATD+QRBA==" } ] }, - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE77QpulZtkpkkf24CYcBP2qUgX+qSRIB+djV1VVfhzejHnuJ4vnj4QJahrQ35gb1z+6a/BaGG3zTTlp7ZrOk1ieWdwIDTSZoBDMLtRkTi2q0QwhnZmIUJ+i9mqVLUh2MYvsqnmNs9ClsqeB/fYPnwP9ZP3w/KMCrx3juijlfWjQNcsLqn+SMA3Q5ApFY+k0ZIX4hyLHWbOI4VCOb3Jei8rlQgo77HmjLpFOnmcLLSYyp+RsVm8BzJ4/3I2GADRJL63S7AWdej9mHqCRgJSnLxqEZLdTwyqHpyqsmfxKBHOKBnOW9Qn4pUWDHWtSGi6fPEyvdwSBWTMxalBkwujTRaB7hArdVpXzGZwbLKvCaRqPSjpSTK8W8ggd7u6WVbsZb9JWOz3+ShA1lZh4xsPsv2P1uqulzIzNoQglCPj2wnDBzMG4FFgvaUr8pP/XPpeSKnSbS8PmvQpAcifZZK5l4YZaBOiucPgmywFCpIwqgjB4i8a8UYGjW+tA1LGVmVGnhy7e/muL/xlK6SEKDtgF068Fpey7+rCsXI1m4wIxVw4tT/Y7aWa8C+jhqxHGOObv1hp13/71EQE/oE2WOE4cqcVlzTP7vUl5aW2IMT1k4yRVqNy6mNG7YgTHpGB2YC1znaYP92M0BJkhnyJG85qrgClhZgC5GzlT8P0umRD9IbgIyIajGL1kxZrHHtIImqywLFuc9CgVTlmBkJbO9RtJtifYuqITaEJ4bj6e0M7/fX+N786SrzdkjWWLWqsGfRaoszUx5mSYl1h0UJFY4B8sNq6U84A5qBtgIjnZtF6sKLFPky9Vtc7iY0ZXLxdo8NQhf3kyUlKBuZoq4Mqg/0Xuj21EFw4Lug2X6EXBiIeJplV/HCe9fxfq59ypcyA0H60+pVtUYuQ/amJ1XdcpYC1a5AAUbdGPpY4d2s3i2nTQEOVEON/RapXwSY8exLECBRuHHelTtBwDlm7sjb8kIfHQHnWLqtqcnrwNOzse+ZitrrHivZnmUtJDyaFfRjcoecoSI/+feCwHEQE5mYWtlYXNzZXQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG1ldGFkYXRhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsKAAAAAAAAAILb/O4cVis/DloIJXLK6zg3y2uKNGph8FYoizUSjKzfb6nKQ7gufjpDqROnU3F6q/rbkGbK7VKWMESV44HVDAdEabfmg+yZgHyrPqcXoXgr8Zw2LAjTWNg3brj9Kuwk7eq1xsSQL2MI0eS4HTCls3v4D8X2HV2Flngb0/vlWWIC" - }, { "header": { "sequence": 3, - "previousBlockHash": "216409CB9937C70C611CC4FA9BFA37518E3AA47236B7EBC514C71E78A39926F2", + "previousBlockHash": "A3202B2AA6172D4DC91676FA64361471F0358A92D5EF98B74E15DBBD43B36208", "noteCommitment": { "type": "Buffer", - "data": "base64:mK95bK5rOxJgUHgQ/d1RvV/JLGkdNqXvwt+wt41hjGM=" + "data": "base64:ocIRbw4Uovz4bkldejTirUObQWEIwYsZhJ+8OXKfvSE=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:2CY+t+au4Gl01WHD7KhEkKoAYC+O+FVMLwXrwcu7xLk=" + "data": "base64:OkCsn3smkIs07W+07rjSCr7ocka+/jAEEJ0b0wRWPCI=" }, "target": "9255858786337818395603165512831024101510453493377417362192396248796027", "randomness": "0", - "timestamp": 1717538981685, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 6, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAwIl34DAsfiNW+UPDnL2HSTpcTliMyVpHxLy8DYdIkdumwfJ25zQsU3N/1UaavA7hK7IhK8axVCZN/3kgNixHiHw9E1r1qiyRaegyOPP+RJO1R2IcLhaNqzQwsNsKoa4qq6j9qDzscfyuNO6D1EJ/ILY2kNEFjqWKwd+B2I0i3fkRBJVCweBA/ctV3KJh8E6qgysP5lNwaSvBO3jc8RE4/+JviszvLXTyQArXDUjzVu2I3wkguvUbnkbO9HY+MdKM0fRwTRUxjSbYSaoDWrJ88SychritYLhoLlXf1a19kt87HsCyUmYvHXIt2/76PY3O48X3JBmxlsXOUVmVGerwDkcEsYeFKwejca+GPz/6TtcbDy0kGwNdnNU/3EHotKpAL1UGFmBV8Zab71cXH/Pxtnwsx6swtrvuhsbK+B5JZCm7yrEeXnrgL1uX09nqYi2ktmWGJmAhE7pio837v0DKCW2u1V2pisUTAiHOxfngkQ3PFr+YCJs9Ah1jq8pO5nl2vHUQwzTXl2wQQ51z//nYaipev4kXNrbF62tNDi8eg8FVbgpEAk8Uu3wMSWLSA5/PyN/T7kkTPJSxDaFhKBZx0f/apTC++RK7W5ngLfNNcTGZ03XSHfyX9klyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwA96BvNjRm4Z61DvxXmKG+5jFYELBdvqecqwWOOZpCWBWIaHcE85CVEEgJSstW7xB2DRMqh78BRlmzLxpRxYwAw==" - }, - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE77QpulZtkpkkf24CYcBP2qUgX+qSRIB+djV1VVfhzejHnuJ4vnj4QJahrQ35gb1z+6a/BaGG3zTTlp7ZrOk1ieWdwIDTSZoBDMLtRkTi2q0QwhnZmIUJ+i9mqVLUh2MYvsqnmNs9ClsqeB/fYPnwP9ZP3w/KMCrx3juijlfWjQNcsLqn+SMA3Q5ApFY+k0ZIX4hyLHWbOI4VCOb3Jei8rlQgo77HmjLpFOnmcLLSYyp+RsVm8BzJ4/3I2GADRJL63S7AWdej9mHqCRgJSnLxqEZLdTwyqHpyqsmfxKBHOKBnOW9Qn4pUWDHWtSGi6fPEyvdwSBWTMxalBkwujTRaB7hArdVpXzGZwbLKvCaRqPSjpSTK8W8ggd7u6WVbsZb9JWOz3+ShA1lZh4xsPsv2P1uqulzIzNoQglCPj2wnDBzMG4FFgvaUr8pP/XPpeSKnSbS8PmvQpAcifZZK5l4YZaBOiucPgmywFCpIwqgjB4i8a8UYGjW+tA1LGVmVGnhy7e/muL/xlK6SEKDtgF068Fpey7+rCsXI1m4wIxVw4tT/Y7aWa8C+jhqxHGOObv1hp13/71EQE/oE2WOE4cqcVlzTP7vUl5aW2IMT1k4yRVqNy6mNG7YgTHpGB2YC1znaYP92M0BJkhnyJG85qrgClhZgC5GzlT8P0umRD9IbgIyIajGL1kxZrHHtIImqywLFuc9CgVTlmBkJbO9RtJtifYuqITaEJ4bj6e0M7/fX+N786SrzdkjWWLWqsGfRaoszUx5mSYl1h0UJFY4B8sNq6U84A5qBtgIjnZtF6sKLFPky9Vtc7iY0ZXLxdo8NQhf3kyUlKBuZoq4Mqg/0Xuj21EFw4Lug2X6EXBiIeJplV/HCe9fxfq59ypcyA0H60+pVtUYuQ/amJ1XdcpYC1a5AAUbdGPpY4d2s3i2nTQEOVEON/RapXwSY8exLECBRuHHelTtBwDlm7sjb8kIfHQHnWLqtqcnrwNOzse+ZitrrHivZnmUtJDyaFfRjcoecoSI/+feCwHEQE5mYWtlYXNzZXQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG1ldGFkYXRhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsKAAAAAAAAAILb/O4cVis/DloIJXLK6zg3y2uKNGph8FYoizUSjKzfb6nKQ7gufjpDqROnU3F6q/rbkGbK7VKWMESV44HVDAdEabfmg+yZgHyrPqcXoXgr8Zw2LAjTWNg3brj9Kuwk7eq1xsSQL2MI0eS4HTCls3v4D8X2HV2Flngb0/vlWWIC" - } - ] - }, - { - "type": "Buffer", - "data": "base64:AQEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAE1J8HBgNQSQ/ZwFj7dtD2OFVEooj4VItPMQhtqRNNbKzUsO9C1ImuiFKLhUEzpWRbPF5IhgeD8VcvJnWWLyC/mmSNZM9dS1/9NmGo9Qb4KK5kqHj/Mb0DAe6GiM7ksVwIpnZn0aEDD07vohnfgpHRcSG5/xeD5G9fNHlO9346HsN64VZGXEJHvxEWdkpjPeBFvXGXtM9pbqB2diUQ1i1qP9W060lZ8joZGIA/PTU2y+GlCXP5WEh7fcoA6CYuebrQYF4/aEHt0spOiRa514jFHI54jbcpQxEbNFAECAPJLITLfpcmgk4Nnj1DqOEF8qQPQdYkkpzPsSv6vu/IhAlQpiveWyuazsSYFB4EP3dUb1fySxpHTal78LfsLeNYYxjBgAAAFAcQYJ3Bjq80IkYQGlRobMuZrHVChVRfKaZI8t4870WcA+2DPrv8jMttuiYGurEAP+Y5oTlQBoHuMzQTmmLOMzKjmps0sXGaTm1qyIss3xMqc2CC60VRcdEbk1vDsVvAaWwS+yns3B+uLn3GDgZ722Ak7R2pIXks4Lai2UCgmaaF74bkbbULeNB8ly6jDZl1ZToANqnpE9ExyZPlW1oJVaPNW/hZ+tZKI2TOKMWgcp+pLeIsscVA65ZFpl440aotBb30DXZr4u1RXEi1+o9X9GCb00T18SahJNy1rg6IUcc2W9Ng+cSUB5c8C8qAS1qKYdHUk7PMj7bQx1a7zqOYXuIvIvALh6LePls7Y1a/09v6iEEbCU0UJY5U7VquVMj+IhcfpvXN5iYcuqC50QPI/GwI5qN0R7cysC67bQEfKqmzf/YMYc8WUf8VBqX59oU9zduR9aevFzwdMNNNRFr+hQ8pbyJoBupGRQ1MYoLKHgsVyKJabsgvZvqDqk/3Wjuaz/IIuBWNVUMmXV/Cap+nM7vSXVynOxFKsZiupZJA/cYjW9LSx6tZP3mLoKCn9sJOakXu68vbOifl2BA22ksZO0vJXl9ZgEG9/uE+iI7mZn0aXNWiIkrwyUmWpFxY25Qeeo4tEkH6CJgDqMQ8QMfAcgW6n+//Ifzzo/TUezwoAjoUZYY7daOszTIhY6zKvDZ0O4weI3KryPDBbLwxd1Yzd04VnF/PPFTlMxg6hepb+CRfvQP5HnlKGKUQ8Uq5wLB5zvRp6vOmu2W2Jq/twaQlF8ZVOuzyfHC3oQpb5/Q9Jp8tBtlSPxp2Zy0STzNBJRcKFx87GU9Q2vbV/qrj77lqIoBxrjeDLGrSwIAAAAAAAAADQNXKeAIKXatYnxF4RvRddJ5EsDu4ittGEX3M350r81G1g686V86OMk1c5iiGqaVDRZ61tuvRWO750wKKFJxCQ==" - }, - { - "header": { - "sequence": 4, - "previousBlockHash": "28BA7F2C93974C90AA11A503B27C976B6EED085470CDF11A6E8242C77889C413", - "noteCommitment": { - "type": "Buffer", - "data": "base64:i1hZd72Q/bi6aCdWOqGg4I1ixsl+M48AxPfbG/X5aGA=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:FotkS0I+a4FhPq4s9AAPgzPktQ/bWyZezOo4EA+Nmsk=" - }, - "target": "9233318228143625020618577701423519925017621426082203201059080050516648", - "randomness": "0", - "timestamp": 1717538987224, + "timestamp": 1718998724870, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 8, + "noteSize": 5, "work": "0" }, "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAALVdeHAARF6+/FPvLKt6au1F+pPgisG9zBFVL4JYvR1m45/gQDxhSDVUzWnoEG6JvR4btm2AmemzicsIL48qB00kn1K9y5Djtm07eB1DBrCOS+1dICZZGpd75VzCRjLczVUWR2mAjLoHo7iO4YKiov2+nw/k9RSjomzHISATKZUsSl+fwW/+6GnEiPXAzAgbsKItpXNUVwXW7qag3afvSr0M1nCHHBToAOqUdpxSDjkKwOLVoSVcgYigagqIcYUhtOHthUFEIlTYIf9GrPexHctQW64+ktX0/LhzotMbipFGSHXin8Mb01H1GFFn2z2d28qlUCrHpdhdGLJJyhdeg3Y2ZMYqsA9YlMtsM9sBlutEo9wRNtOuZuBgvQSgGy8RYBlox+/u82x9J76TfbOiYu5zaMdbhHPKyCV04KEusfMhVOWuZveLhhLTdwKBdibzSEhGz7NII7mSomBPuE/oF5UnMbaaT7ANHAgQPOKPszprz1JtT0YquQ+O+9KGzSQy0UAapPRt+fzQLsvBldcarcoBzW+ugFoCChcDA2KmLsOhdg9yhN2kFGOEAKmeBN9H1oc/X/YxFlRPIW9C+sb/adN6TOgU7ZY+PW+KYA521TaK1fCkf/ZmIWklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwVnmp2/WjL5jliFYsJ6hCSIiLkZ7VqivBFmkJO7lkHQa6Io3ccBDSdQidWSK+Y569Kf9LBH5MrTsMDAcA5UkkAA==" - }, - { - "type": "Buffer", - "data": "base64:AQEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAE1J8HBgNQSQ/ZwFj7dtD2OFVEooj4VItPMQhtqRNNbKzUsO9C1ImuiFKLhUEzpWRbPF5IhgeD8VcvJnWWLyC/mmSNZM9dS1/9NmGo9Qb4KK5kqHj/Mb0DAe6GiM7ksVwIpnZn0aEDD07vohnfgpHRcSG5/xeD5G9fNHlO9346HsN64VZGXEJHvxEWdkpjPeBFvXGXtM9pbqB2diUQ1i1qP9W060lZ8joZGIA/PTU2y+GlCXP5WEh7fcoA6CYuebrQYF4/aEHt0spOiRa514jFHI54jbcpQxEbNFAECAPJLITLfpcmgk4Nnj1DqOEF8qQPQdYkkpzPsSv6vu/IhAlQpiveWyuazsSYFB4EP3dUb1fySxpHTal78LfsLeNYYxjBgAAAFAcQYJ3Bjq80IkYQGlRobMuZrHVChVRfKaZI8t4870WcA+2DPrv8jMttuiYGurEAP+Y5oTlQBoHuMzQTmmLOMzKjmps0sXGaTm1qyIss3xMqc2CC60VRcdEbk1vDsVvAaWwS+yns3B+uLn3GDgZ722Ak7R2pIXks4Lai2UCgmaaF74bkbbULeNB8ly6jDZl1ZToANqnpE9ExyZPlW1oJVaPNW/hZ+tZKI2TOKMWgcp+pLeIsscVA65ZFpl440aotBb30DXZr4u1RXEi1+o9X9GCb00T18SahJNy1rg6IUcc2W9Ng+cSUB5c8C8qAS1qKYdHUk7PMj7bQx1a7zqOYXuIvIvALh6LePls7Y1a/09v6iEEbCU0UJY5U7VquVMj+IhcfpvXN5iYcuqC50QPI/GwI5qN0R7cysC67bQEfKqmzf/YMYc8WUf8VBqX59oU9zduR9aevFzwdMNNNRFr+hQ8pbyJoBupGRQ1MYoLKHgsVyKJabsgvZvqDqk/3Wjuaz/IIuBWNVUMmXV/Cap+nM7vSXVynOxFKsZiupZJA/cYjW9LSx6tZP3mLoKCn9sJOakXu68vbOifl2BA22ksZO0vJXl9ZgEG9/uE+iI7mZn0aXNWiIkrwyUmWpFxY25Qeeo4tEkH6CJgDqMQ8QMfAcgW6n+//Ifzzo/TUezwoAjoUZYY7daOszTIhY6zKvDZ0O4weI3KryPDBbLwxd1Yzd04VnF/PPFTlMxg6hepb+CRfvQP5HnlKGKUQ8Uq5wLB5zvRp6vOmu2W2Jq/twaQlF8ZVOuzyfHC3oQpb5/Q9Jp8tBtlSPxp2Zy0STzNBJRcKFx87GU9Q2vbV/qrj77lqIoBxrjeDLGrSwIAAAAAAAAADQNXKeAIKXatYnxF4RvRddJ5EsDu4ittGEX3M350r81G1g686V86OMk1c5iiGqaVDRZ61tuvRWO750wKKFJxCQ==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAA8Sewl9kPhrjCT6DVMfsB/rMJBKnw4Zoa9ZJvwoZzedWFfWg7lB3XtZhQgTy0GnaZQ6D7YgrdGmqQRwc6vcsTJEUL40Kxb/ZovEVB0tHyxaixZngyKSqCvmvrqWfJJtWgBneH1hBSgcIb3GO9iHCLpLLvKNFmeyZusuK9RnCuX54U3Zugm1nE7PDt6UF67gR4hHaiN8WRp/hnKSyQfRoOQUS91+6D5aCYCqacSWIgPgWkP9s6oAUvB5RbpYF7OK/uGwb7wZdLCVl/9zgh8O/VycsPYs0vVJPkC7Sue0JVIjrEh3w/MIMnxVGoBaVtj5Iow5/1YUvAl7a/JxSYuq1vLOoJJ0uhF6OJXoFJjZDI2RbXPLRc3zAqEXdZUUu1EvEID22SkKpwJmgW/TaYzy9G7OecPHJh2w5k1lhkEO7/CM3km6/MbrpFWCViX0RDRBVoYIJ9kX4tUOA5ZXUGSxkpVjnDZp6hhnHHFeeUMpFGRHiI5zGk0xPx6BC5sp4Co81KVhYQwcnPq/kfUHL9r36GHMIBc4k+oMU7WnPIdVDGlhQXxPCG6MO7ff6euBjJBgAv8WeSsE+Jf4KgOdxlRChD1awCZqe9G9yTl4rxXNkvUfez09hW+dde7Ulyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw3rmmGw6WUA70k+ltmyiVsBsG504wgWV9kCr9GDQrAi972Ha1IpaiTyR8A0yj5ylqLBnf3+p8kBoyGhWbAaH4BQ==" } ] } ], - "Wallet getTransactionType should return receive type for incoming transactions": [ + "Wallet scan should update transactions in the walletDb with blockHash and sequence null": [ { "value": { "version": 4, - "id": "c4cb3024-e8b7-434d-8829-9335377d66eb", + "id": "aa597976-6ade-4d4e-87b5-8113e3f2da93", "name": "a", - "spendingKey": "14693cb6c6e5ceedd843f678db9bc375ce44c7073f37c9eed6d3dea779ab8bf9", - "viewKey": "418a47bf9602431caa7790bcc6d72980af04ec20426d099a7e0f212bccbe9eacfe08b43fc99d13b7f87c7fcc34893d010ecf193e57a767716b2186f5d00cd5d5", - "incomingViewKey": "6d2e22e99680c3c63fe31d6398793f9b87454432b01ddb8482692eb597d66606", - "outgoingViewKey": "6c88876709c07716f48b19d8056980876a7cd803854f30c6c70091577a6ef8c1", - "publicAddress": "6ca52578ba0d94daee94af9fe5603043acd6efd1b1a9e8c54647f59b1cf18f99", + "spendingKey": "32f81470c56f97f4c52cd402f93f3d92839ae6433f682320ea895a7249d19226", + "viewKey": "2982ac68b5ede7dbb8eed2644df70e082adff97e6b68ffd4636d7704826a06038f7061c45cd2df510bcecec3b381f45a4588fa2841dc39d215304b1505f1980d", + "incomingViewKey": "d9b0d9e337cd2063abf908919b180e6ff2f9a86a0856ce449cf05ad0b3de3903", + "outgoingViewKey": "e7c1b9a80c8928a1c520625ceddaef379f9bed16bb994ea0d9a2ca8b42724af2", + "publicAddress": "52dc14a8935ec7e6bac79e73da8f145ebc1ddaf36cf02a61ff9ee408ff59c134", "createdAt": { "hash": { "type": "Buffer", @@ -7584,7 +6414,7 @@ "sequence": 1 }, "scanningEnabled": true, - "proofAuthorizingKey": "a8b6d0e280b9332339356cd93dc93653375ce5aa88d013394e07a8dddea9d409" + "proofAuthorizingKey": "b7f018120431d77811103d474ad0ce7885a0f93bf7e5b542f9738d9f0a5a870a" }, "head": { "hash": { @@ -7595,15 +6425,15 @@ } }, { - "value": { - "version": 4, - "id": "20efe043-89bc-48e0-8ee0-07b0fac2cb40", - "name": "b", - "spendingKey": "202d96f2615513c2ede0c1bff0cb0e5cc2625d1579f9de24c324097913f161c0", - "viewKey": "643cc5658542c1ecce532fc5a94e099521978a3cc47b5ce1552ec0dbf8128ce3aa620a8fecad587f018946a95bfe2678912b7e5acd932cf9988d1689722e7a0e", - "incomingViewKey": "9dff42b9726e1ac5354bae32ce2462d85dd985488ca3fad3579675b65cf4ce04", - "outgoingViewKey": "1801e8be9cce2b842805bb8d05744ed4b9073d1f2047c2e718c09715892d336c", - "publicAddress": "3bd5dff2753a8a2b0761c27f468cea32effcca7fa479d66abd38a70a32062a64", + "value": { + "version": 4, + "id": "aa99f6b1-bc95-4570-aad5-9d7350d021b6", + "name": "b", + "spendingKey": "02bc7fab396c8ffeffa7049c6954748ce9efe8e3d80f403407461ab86f115859", + "viewKey": "9f394e59eb9d01bded00ecd56092494d52ef401b33b4f0a6264d48ade1ccf5ced01bded720763c6ca99f93f6318d3c55d1463f206de35e3d5b4e431b91dc370e", + "incomingViewKey": "013d3e467fd07dbc3d362994855e1e3f760b33f5ee1f3fa4c9ca2eeb6595b102", + "outgoingViewKey": "2c2261868d1c92906c7fc63067916e0e9de04d842d99596743b41085d77af779", + "publicAddress": "52cc478f846e52c5736fd12fb3dc1bf5d34185f77cf20539492bd36cdf6054f3", "createdAt": { "hash": { "type": "Buffer", @@ -7612,7 +6442,7 @@ "sequence": 1 }, "scanningEnabled": true, - "proofAuthorizingKey": "f942a40b3b8b18debe70aae80f451b1fd280934cac610a51a82fe75264946503" + "proofAuthorizingKey": "ab27a089182c52ec712e77d2ee9b3a980c895cfd75e357f3f7947a07186c8809" }, "head": { "hash": { @@ -7628,15 +6458,15 @@ "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", "noteCommitment": { "type": "Buffer", - "data": "base64:UuhrkF4SAaKe7XkXXUMxX/eU7R+6uIiJXh0LwCbpEVc=" + "data": "base64:QTtGxhAGyL1j0nNoBVSltclqiCQrsibApaMtyQbf/Wc=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:KCOjP37PoO4h14Z+sNC07HD8JS12DtSF95A3Yxq3E1w=" + "data": "base64:RWDv0e1VGnDos0ZWR4MZYI7AE2mK55ibduV+nIyLX0A=" }, "target": "9282972777491357380673661573939192202192629606981189395159182914949423", "randomness": "0", - "timestamp": 1717538989717, + "timestamp": 1718998725908, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", "noteSize": 4, "work": "0" @@ -7644,25 +6474,25 @@ "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAA1K21zyIuRHaG9i/n5UhbPUTahRf/4H4W+mzCiPTAqEiwbAkw8MrpIm3E8pHrRGmU2HNXJ+H+oQ49lV9NIKD2Qe6okGoHDqIaRFMrSB++FL+DfoPlUyq7G3O8cmRHYRkQt4Fnnwl6v/QDhmDAtR4FnHQYlJKnw3rwSzneEGwlUpQCT6Hbc/KJd/jp5aEhQfmkXCB+YoVB5P9vQ/8/PeXxaa9xSLFZM5riRUjEjVb6WUGxP5wJ52DZcKSd2EFmwcf3bjSmUFYqloenbkqzGN2orjOoEQzYlcMECr9K3fXXJp2o+kvWp/BR209jz872Zirvk6dBazZvMJ40LZL9IGpGEa0eDU/0aJOW2oOZD+P9Tw4W9vmhgslgWhrbkF1/d7AZj+Xh4USFX55U6njxIS0ctalLqlASWo3bRmut2K7aaj6EDE/PUozwwftYUqSJNJv4zGEfGBzkAbvmlyzCqgrt5xXzS2t5wkEfklaNOIeX2t2Q1f/qQagdlCBSQIdRVEsLmrK2OKFub2zcQBI/RPpMDZDz4bXvBfvaBtJ46bd0hkJwn79oB0+IxCw9K/tNc8ZKYrKCLsBbikw5ejvKhTanPzXGv75dd/jQoYC9XZaC1Gy2PLZ2VBtkmUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwBJSgfDD70PDdz4bvhExyqIAPyqo1n2ywSkzhWkWPV4L+DyiX06NGiIennDE2lDt3PLJ6vpbLNvCTuJp3+YEICg==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAA3J1ZzKogOU3C47WORiXCSkQ8m70xzpUIc/9wXSvGEIOYDlRDN61GD699/0ZGCjtSwNajcStquhjLNR5yMfExUCPpxD3qEiFJ4CTefEHwrDSK8Gg+zOjuui38mVx+4JdUAGiwNRp4IBsaRGy+gbP2CGXU8TWQYlwFtZDraWAxp0YPNeFh7woEklOSLWHdQD165Iz2xyVPa3NrWCDGtBDYO6yUZIOy/d1NPXvvY7+WrEKFtBIU1PK0CoupmXCBoW0Ou/c7HEydHhe1kjqm1TxTr9ZHJ/S086t65w+jZnHzilpytmW4lW0175fdEG5ONqPP23vK/zAgu1hbmixz0XPPOCfLQVXq2HggXSzCA96b9129Wcg4upyNsA/b+RzEbm5FWXbzU4uxfy6WXt/yJE6So+lJ5c3gKTXuJdT4S3/wikLSUB4bWENKz4nwHmr2rCjIFRerSXGGg0JjCqn6nCJRR3mIY9tU1jgrhuo3fVUVf41BmEDuPzvy4lx41NU7jtw3LI0eS9Vq72/hnrKPWF2JVhUodkbWdgoDm9xvjm8mg3nSfBaMUC6IbiSj84KSB6nztz65IQJN4RcvV7vWold5PUrxO6ZE8wBkX21oUhHP4T8rUGF0M69EM0lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwtXnZ/VzfzcL3ri5t0USzXR2/DwdG5f4YzhJftD99QF9+Yzck2MV5XpK1jBbxiPeFTY8ldLO45l7gOCKXSbnIAQ==" } ] }, { "header": { "sequence": 3, - "previousBlockHash": "8F3C9A535641712B724F5EF936F8136F5BCDA81DB0CF3BAA5D619CC6290B7A9F", + "previousBlockHash": "D766E02BFF74FA6273774954B60CABF52D665E050FB58631E30E7F4EA4BBC6A4", "noteCommitment": { "type": "Buffer", - "data": "base64:5XpURaP5TgcLXs7ttAKzKPPxuVeVdZsobHnDo2vLgzU=" + "data": "base64:O9eQaFpLD66t7aBv0GozR8/lPcH9VRfM97FZqsBBRgY=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:Adzrr8VU5KnMuAKnawAvcj2gZh/FhUp0FyXyK8lqUvE=" + "data": "base64:HHwO7qVISPZmBlU29haBBjYP3krd2JywcL8jfI+2miQ=" }, "target": "9255858786337818395603165512831024101510453493377417362192396248796027", "randomness": "0", - "timestamp": 1717538990741, + "timestamp": 1718998726349, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", "noteSize": 5, "work": "0" @@ -7670,25 +6500,25 @@ "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAd60WzsCia5aaqjCnF6aJ1UydAjAz2I/pTIsZ3EVSOo2jU/SWIkYWD/J+4XSx/ExymiJXkc6Ej5Z7oT1vDcAHH66dbS3dX5QC+HxEwObJrGCEA/XjqgQ1Vdc/UnsZuEEw/ccoJWqL41gPubhQDDIXvyWICZCErjg9C40Mlpx/Q18Ksk1BMzVYJuVOSsWyVxwYgfR3EYCqFgrnwQ1Y1dqNKWphFJvpuvDfPH64lBpv9b2THjfG5A6t4FpGfiASD8tqcKJk9huNpi4QxkuEwnySxhl3xcNUablkBI7JCKTJNXVLS6PSwV6pOgZLg9QlnEW1qYYtpzTbBIImBjgBOipU1XmfzHF9UVbYz1IHyH8sihWIqHI7ncZlaSbl1amQ2x1GSqTrxZAZ+y0fSIYI9kZ6eSfnXE9yNexHeBOjCsPpQTs87GtS6byjl7AhclfkKHHx241Q/OFONj5I4E5qTlGH7F//93RI8G0nR341Fl2T7MnPaViGk+VW1068Zad3JYOyRvz0zSJa0RAu2yOmStFgVwP8SZOu8SDXtoqDrnVhWu9CbBl1j2U3i56Nm/YzzFivOT8gqRl/ZHItJDG4RbnyXQv+9JgwnRkhnEYq0569/hLbSYfCvuSMm0lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwfP+B7tcXM8iblSEyZ7NIjkA+i6DPBlebCklGY03N80IoLIVFmvSTs00ITfc4HYEjGcK8Rg+spqUoBs//SqfMBA==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAfGjm0Z1/yMIHLjaWKRGexawHI9fz5MYrXMp4iZ8iD/Oo+a4liZGIqPe0slCHfEF3DNcq1/7xVj+BZG4fVph9NagvNKeG1/Egr7IiuRRk3xO0bRznmOvcBxk7lGWTURU3FiaSC+VU/2f9Hbm4Jv+kPpx7yC9v+539wgp25fNIH7gWKgCfE9e1YsvYFICT1G/qjebaCWg3sJ2J01xM0dRaWaxV7XAtpBJHRhk0ba3mtXurNaDstCPeTZSuR/71x7kIKp4TS43A7gRNPxjNlCQngvF4bYbNyTae2+xOWfxG7ozlqbPmL5Q1LelRdrvG3meU1PKM5UWG8r8TElLrvvRMGyjRLDnPYhwWy1A4rNoNQuHiKBhMt5sWZNHrh03zntJA1Kb7g3HE2aHStoLFqhWTk/5IsDGJuDLL7/eSWWyNuwy0HvgQk9gUngVRdlxnSrtT32gcBeDxZdlDlJreZAp9wz0x9SHnASc5gBQko7zLA7tUsHvOHg73UQc7iFlLidaB5ph240US7hFgv4XC5RaVWlrtEJJbaCkDGGbD90QnRxzHtSZQhmzdubmCEFZQpcASYroU+rNbURkllhI07QZfM0Jt3leO67XfU5F0O/rT6BppbfPVeMJdJElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwZGpVs31XVgcXJyT4T+MGSb3Gs+mmU5bqriJE5kEZa+buYF2Tl9xKApsFOP2+PSAZXbL8dkUq3TgvAlqsuz2cDA==" } ] }, { "header": { "sequence": 4, - "previousBlockHash": "4030109C2193ABAD2C1196BACC0FAD459A5554B2466AB2EF45D0575AE893A08C", + "previousBlockHash": "9F0C15CE5430B84B7FDE1B61E0400D4B4292E64060312DF36EFF68BD8FBC9803", "noteCommitment": { "type": "Buffer", - "data": "base64:j5RhH+NP7THvS7URjv95YuJAxQmARx7NlsFgETIiA0E=" + "data": "base64:KbDDm1t0aOo0yYessRIxW3MTgQ7sarNwShrNHJ33CnA=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:3ufKD/Tu2NIj6DUMd2pAp0MHYtxGs/Wcttu0MSsshXQ=" + "data": "base64:PO9wVkBUUO63nIu6lRt1Kz51iUnisv+M+fsqFIJMXh4=" }, "target": "9228823284279306817296266184515742822248210830185427859262273659833347", "randomness": "0", - "timestamp": 1717538995575, + "timestamp": 1718998728632, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", "noteSize": 8, "work": "0" @@ -7696,26 +6526,26 @@ "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/2vKiP////8AAAAAHJw1xcOYxGD9SzcMislG4w/p9rVrkr+aQg+SYuyZPRm1AGU5Y6frFpwXvNVKJxPRtGPMGBkHbJJfe4Fph8DLjAfxQ+4T6Smu2BwucDTn3/CAyy6aJt8zwRuWt7kjvL1qXco3PgVr1tW38pVDdDTMX4V1gNIhCZM/8xSjPly/UhURjqWieS2DuC/glh66pElUgoVH4GwqN++85C4h7Qtdepct+FgHYT9pAsUreVnvavCF2ba65DVhvhei2cnVYr1Smx3iUwemI3T/pjU1513Xh7lZPiwKgw+vpbMdwe5P1MOEyQDJrG3cUVgoJTP3d4bQ6V9q2zcbOmmM6Cmva/G7aBB2RlgEwT/4Dx5UKbnkEdZPILTpnXdEAjXm4r/HvSc9VqsYHulj0g7/KTR76fyx71aB4DmRX935gHtnmdx2NoVEE5vxwGRKmfwnIUfFmOroRXLFeAIgtMwIAuV4TPWiIVkM+xAm5q7nrhq2fJriMQjyDDFuyALoEvnqpyLyKY9VvTlkmEVS0pB3OSn/KK4HApF6uTyev6cPtwOho6zd/nl0kllfeAm2Qos4Tq5sp9tI1FBqDT8KJtThHQ06gHL8UTo0bnjqcmWL9nGmb/aI/gaJysn0Cox1dElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwhsNBOFeqO40AS+WoO72jhts1jCfAtN5qQVQ1Hf+MfbJW0wQ5B5Zz/TKrbnx3c2P5n8l9cXWaVATIjL/xePWEDQ==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/2vKiP////8AAAAAtiOSV3p9zp6O+X+5e9vCduAlLw9LX2wTc/YfxtY2yqqguRCDzRStLxl6xKrK1X76/yFLtvk2+ACEJCcTY26TU9gw9WMeLwHX9d5+BNRQSxyRhADz33+zgTf3FUtBWnQT4DSksHsyR0GAiUK82oNOW/MGJJCsCWsGEBsyzUl7NOEB9zu1PQrkqrFL+4bD6SM/2BOaQFVZhJCyaXUWpmjhBUjOUpJfdFNfN7cjnGbnfrCURSiFumfCVJHzY0VluShuJ/TZuLYn3YHnt5P8OokXojuNXFXWYY9dhWooC7bPb+7bsrQfcbWrPsxMg8+OgQL/JhJHrQxBoHr72zBsB78mvTRlZ8H10OX13kl1/6BmS+i+3aeNLuX7C0JqaMKamQ8HyxpATaaX8GYgz3qPHKc+O3z4VVnzHaHdCKuCw7dVsF9+oHjzhnVGL1y3ZXCrchv8BabH69+D2/RtqihaNu+mnYuHOTmVIYZVGlblK2iDSrl8TcdhsAzAmyCCkBhB1xsap5h4Bh09HB99uxZVoqOTy9qikuQKam3cf7xUtnBcVOsYtehVdGcmgoANsMOKIqYH450xm2/9u1sVCOxcLP/cnFa/YsV4Qbxhn2ASOu9z5rx7OhS4t8TrVUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwdVaf8Lf+/mpO3lXd8f/l4wpF6ejFqSW0ZIu+mQ5EXkZLj+iOwnowVDqgMnpYjZneQp2Bu/o4snPFfaOrm2nNBA==" }, { "type": "Buffer", - "data": "base64:AQEAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAU9DQfBkBhR+iUr9GxTbNVob7ycwXFBHQbXwz4HSReCCX6487hT7JLOfPVdd7qyCeaGFRLssZkBw35LlN7TU7+3jbPMxOyvXwBmm2KBx6QR2xrREdBUXZZlqWgvshWUtDQ0Aj4C0Vwcj6H8nfb9oEVCsKPSLQeO9vhAC+n/hBIcAGS63PNrJOm/pABp0KGelVKEYSQ+AWz3ftbfqiQvVOXaqSt8OIxB9qaOBor3kQ6umTEc1Yxll6uqsTEVz1SKlNG20UMOdpQwjGzFi+e9ehrmSqUXun22UG1fIWg04emtgZAbF+NXSrmLZhkuTr6Bp6n65GmGLFYoy5YgUN4el4guV6VEWj+U4HC17O7bQCsyjz8blXlXWbKGx5w6Nry4M1BQAAAI/SmkkM5k4vLO5PR0Ph793f8pUZEC+ILXBXOTLdd6PhP5ky4/WcAgtGlHtrIh9QAuW1FFUgXyt7nkMu8QWkx7zDhcFjfczgrbRjPcjTDeRZKwLGdMgFw8geqHy1StLPCZcJJSKZJqrMga/H/S/Qw62bSrNJOI5SLQz3mtLQSbC0/A6tCuYSYDL4dAPyCd6sm6gNoi/vb9UOfmE6h6/Kvi6wayxUp/7wr5+M4Sfe5lpLW6OZCaJxD9eC7eSB6u1JVgzMFGHHuGihZ0hbx42jD4mFLwKGxtytWLnYH2qO8G2IkDVdx9eQQH/sX1SbCbHr3bU7mhf5zJQXuZAgChjOjRlpSIHWWVgrzuFt2WCGsGqTaszU/k9l2O0pXqdHm7cysZg1uA+Bo8lZ25lAnVMJEZorOi/VcbD//p9DxYXpKbGs9F1/9c8/hJkOcT4tIFaxZ9vWMEaN2Mh72PnwV5+Bg2s5HjgK1ztIDMOptjID/WDgjGmT3bhkRCpmsTJYQ3jdn8cPa0RjriTVoMzUMVWNYl15gz9Q+2CDtoy3+bT52psTQeLSpNo54JtxGNCW8ct9v0A/6mCf/9nYsJGIe86Xez9J+R6vAplqTx52lcqc6tH1VhVrzIEZELcslXEMJnjVISJjA/GHf89FTunxkopoPS0aBCGYlsfGAsv97340psZuF6j2xXJh29MLPj1DIQRoQWBY+b5oMd4nDemJuN+rYqp7oq1Q3MS2yug3nvVS0SDRHgBTK2AfRZRU0yXJUiyqJaunpBjtq/1TWVM/TRjsuKb0aJe6cFn14tnpunkyhx0YfSP2YkDr1WmQ3Pqhdd6lj4Iduk/Og+LAeo/AxaqFueKBED6ZRsUaNxPzehA5DZ/n6xs3AQv/3naEuSgmRhW2QF/L2eL245ePYLuLm30TdjdgFnA4DSeMbEjujtfq23iPEyt3m0rjTbsBJOr3FXzyaYbF7dnfjsIaoUu+Bar0A3OfXJBcX/3zBLUj6VNK+A0WX7ceBHWtjayVoJfyahmj/FYAFswYsa6PutSHgQ1mq+wD4vZIFqeMFelynXWWz/aGjOHZ0AHedkLfb6HrR7Nqd9HVO531fRDytf00wIecZcSPFvSLWDestcCMu0qxshKf2/t99OLMFWzwEtQyZNS+hUGf+1I5SgRMI7vY3E0SmA5jDXb/EfayXxoJgDxedfXXrqeO88zeFykcQoI0DV4Zts62pZ98rdLCzV2COQrPj6Eu9bLqTImHMWrAh1+tVmyotnz1fZEpe+8eWFznAL8C9l75eBKSl2aHTlrsUOvdbOlCawP4XQ0SK9jtaRzwSxE2ibBRvt1t9FGB36D+355NlXK8olT2DE9G5I6uC20KN1+StDZGlyn931FcziYp7R1Kc05wXGCFIGKlwb6kjyZ13IMY2mzP4LzWmycg2owURFgdXCL9+CUGO3NaBSJ9RzlFUunq7xLqNoHLz+PrNxTmKFFXlBVyGoD3hQ5/W7bfGi/C6U9pAHInIgjId+kZnuiS97ykO8+veG8387640rOLWl2QOZ7twQSfJt2ytvPi6gHPJ+5ENAxMzpnfakuThJZjoVtbfITANU4HRchbzlfYAw==" + "data": "base64:AQEAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAhaDaJtsn/DQIALcjOtUSProfA8O7Q6T1g1JjAHiTTeKNJtZZb6/YCp4dpznozj5m90+83gGtjZQIoOO8LhkqEZV6zGixOWAJ03ZoiDuVH6GzJAq8WTGXLgkBg/iPNbNxsC8vblH68YvgqojbFgUqY84A3ueP0/5KhZ7My94honMIT9LdkuyjAxear2R6XUoBPEWKab4NQmXe0z9RuxRoKSUhNCeDD6PE5ER/+anQD6qD6EKqSMfoncijyDxz3vsnGfgdZRuMRCOVg5RoLOaCmWf78cTFqgCOzVH7wGh+4ws55m174WZaPKdyMLf/v6iyibg+XP8e39LWadmpQoZi2zvXkGhaSw+ure2gb9BqM0fP5T3B/VUXzPexWarAQUYGBQAAAMKDF7Dblp5wSMp02Tdk9NnT2Y+I2YqK1FTGlaEo3TdzZwwuo1fDePbgEEBeh3cHhpLt0ECPZfAO277UVyqJ/enLHU7h1eUXqSWamWC6u/Ngg0V/KaLgusJHOB7MAtTpA4VMBtjw4JbtSfFY6qfflt9SXas7uMP5xo2WeRd5UuOZUh8bzD0fM3bzEicZMdUGnLn9pGKHoYyDDKhPRdSrhDFHXhvlHWfckZ6fwaU4YvlaJInbC82S/BVHdjj8doGHYBdCrA9RKP1okFNTCresl39xdbO/ST+R5kVK6GdKnA0fW8/CP7Dmago0EAOLAppqaoTUp2zQXfdWF71OfnvF0pBR24y3Le5vICEuQq0OkdSiD4fcWxbTgY3XlZcM744pHn3GOs4HIlYyF2bVMJ05EhbCgcXTXmj+RQDgATmJ6JK2Xhf80rnM9FC7zUcjdGeNCUig8ago2apajmjBShhOICetkQxVNgb9iwqqblLay/yNI/W04fdkyn5HjvgnLXXxA04DxddgKJX3eaQHVKfXyglHjsZn7zorUsVeuxYwtzEVVxn44T39ufsi1i1syyVqF/mNmJ93qOMxONZ2MK0543DXjBap5+2Gzez/9I3h8D3jnoXHc+N3ulilL6XCpr8X9XGtZV3quIGa0hrr9GsCm96/lroTjmw4FdyW7oHp3ypEn/3EgzCHh8AL9wVytRtHuUzbdZU8n80Lo/WtP+OB0lPSFz26orHR+x89r6FSiLjJ1+nukAVrZ7SD5G33uXdPRj9ftdrIsAhaGE7fLxPHV3aV0pLvG2qqMgGm9CF7du43RiWDIsSMFWmxkOXaY1MsT3BreYi8q/M4OF4QiWV+ppXg/+tIPRWk7ZAu/UI5bBJLlDycxb9bOBWOL3UIuA7GaniNK9LLCcgGqwYUOzelTNM8FVZ4dlD5tZTi4VUNFK1+6/G7jY2hAbQPLCW82G8ne8D1ZAYWcjwpYUYBPkvUZP6WfBptBInQbf1+UM+kL9AhXetUIzM9uWSY86qhkoqILytOBytqTjDjmNKdTtAAW/RDks3NiNSqQ7DCioAvzqOBL3vKcy7e0TR1PsrHpbgPDA1h157VB0RVzFekmYWb5+qVuZ4lU82hatkS7g0ln/kSzdRPLjqfEXiYOkOLfc0ggT1K+wlQgMIiUrwHCgdu9K46LdUzNlpatXBd2Bkou77Py1FB2AMtG4Rv6yUOkoc18EsyzoHH7lHxWWmBT/n4gU4ll/H1zQgJSBDjFqpC8vurgcxXBUIBLnsfvxeRkil/CvFhbPQKkzigA3CkpM1BByQFElugudeEW+OxXc9m54bWOL2QkSWcHO0MVSqN7EjjPTwj6imloNMYW64QVd6PArloWRBGTYN+Acj0NmdACpfFQ+w9HVSiUk3sWIV88XtjBhuMHlDI15KkhA2UjnugQrIPFC8r6wjNQiXK2xT+SMvFEL60Fhi+D6w/H605/ozA6gVO1c18MXw5DiYVtLZcQf0f6f7SFBjizt2NMp/1RhsKRdSyosV7TzHL+MgIFRQWa+KRGIGZh7s5hCdT0LKoKE43mSqxkhPXcRGH9rbr1k2VJ9/QH+if3JoKTKqKlS6+DQ==" } ] } ], - "Wallet shouldDecryptForAccount should return true for an account with null createdAt": [ + "Wallet scan should update the account head hash to the previous block": [ { "value": { "version": 4, - "id": "ab5b44be-38b3-4c52-8872-8f93b269b817", - "name": "test", - "spendingKey": "ba906d52efbd927f0be11d429358919ea1c87fbb7a4498f8e2ecd046a2793a71", - "viewKey": "fa278f55c53812b3bca2ddd7c0878050b6522f9f87288c3d03250fba9a5bf236fc5e71eac8694878b8c810d96d5c5721b9f1b3507a86eba039e893d09092e89e", - "incomingViewKey": "74d4b2b2c1cc39f4097b90c8b50a3bae0c85c04a3e588e922a18742b70b53304", - "outgoingViewKey": "7f7a01e7efdb53e7b4a12ca4664c0277429205c6b21e5532965f6add9967f36d", - "publicAddress": "74f189128d5f91e129af0bd86d986b948f21ab00561e7b47285000968b8df845", + "id": "63220a32-4403-4509-af43-7d3bd0f2dac3", + "name": "a", + "spendingKey": "c330e22814fad3116109025186b5dfb43024c56abd6265eba92b1aeb375106a3", + "viewKey": "ed1e0690b0d522b6d875ac45a1781ed269c85fa12e06d6c7b30bf9bcaae9ba269b5a6135b8e04f2f22ed949f7831e6b68a6a3985e518b2eb7151faeb4d2d156b", + "incomingViewKey": "0724670f39a3cbb2ff425f30aeba7b2aa2a923d0e693c92559dbde859c5e9704", + "outgoingViewKey": "0fe5cb9227cc49ba6385988f093e750a9d509cd9e4f3c5e090d4411327b2d06b", + "publicAddress": "ca61fe0a1e39bf3887ade3b530c8829f549b44fb8c84f5b5180eb20ba1140969", "createdAt": { "hash": { "type": "Buffer", @@ -7724,7 +6554,7 @@ "sequence": 1 }, "scanningEnabled": true, - "proofAuthorizingKey": "d4da17a97007808a389d636669d59efcae825d66cced3bb52c813e5dbf9b8e08" + "proofAuthorizingKey": "e0bf1c29b5aecc238f68aaec9f7f640c8820c4a5fd1389c20bf3422cd40d4706" }, "head": { "hash": { @@ -7734,44 +6564,16 @@ "sequence": 1 } }, - { - "header": { - "sequence": 2, - "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", - "noteCommitment": { - "type": "Buffer", - "data": "base64:Ye223RdSL5Fj+ilufxi5m1pJ2cQEP04YtZP40xumgT0=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:VuyFBIxcZoBgF75z/D7ExBC3xFJKkzk0ASQhfIm5fdo=" - }, - "target": "9282972777491357380673661573939192202192629606981189395159182914949423", - "randomness": "0", - "timestamp": 1717538998177, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 4, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAtaBpU33iI5phDHMDr379VGMo9mtOeclLnyNPE/Gk5DWD5XURR1gDcbaRZ6brJn/o63t1yIvzMq+mFjGuFOksTn4Vc3VUMFbNJcRAI4x4iBm1EqQTd5sA8eaSeb9lz0bMpT/fXduflL5uKiSHJ5WIlZ5zeaG3DVvH5eirAN9kJ2USZ9YJUA9SsDK/wJPlqVm7BL0/ph0kJ/UXL6pQawgLiHy7w0lu+wWEtX39Fc4nnB6ZsY6VSb77x5Jg4CTrX2AK3unixfUmZFKutH5d3DkGYKLwfIoIMQmTx3sqlbHHeHhCzAJhoLhYP9V3FE7rwc/KOjMitlzx3tfWF/loGkfrz7nWbaS7hEC1n60pu6SWwxQa1ntzfbFCpDfghO1CCWkrB1UDDbAZruUIuCLu1gqGGD+NLZMLed1KvcYTlcoGH6BHKmP576imyeZbSQHLkUWBBQ4pIAa+gfejAcE5asKsUt5MMjVa/LZsbt32mW707oF/ZLJgPOmMoFufLww9EB220o52pYQG1bGshC4agxJik2t936biKrUn+cSFDx7ODmpo18U4DyfykcxwCLbrcYkMoHX8HmyiTzhc7NIh0P95WpvuyUwg/UasBxNbxb6mHgzjck1zZQ8MIUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwVBoeIcfVogURg03ma8kl1MPPqMaSumSYTJLxHHmyK+f4idC1ofgBJ5PJsOd8NFqNgWb4t4NFwv0xkcV9jdloBQ==" - } - ] - } - ], - "Wallet shouldDecryptForAccount should return true for an account with createdAt earlier than the header": [ { "value": { "version": 4, - "id": "e4e8e6e1-2e12-4718-9113-80c11fee565f", - "name": "test", - "spendingKey": "8803cd390dc21e390155bcdb76703829be72bdd0d34883e9767b3e9a7ecaca3c", - "viewKey": "911c59f20fe23ea928efe890c6a3fafbc026008bc2efd219c61b76a2515049038b81f13675c60d7a7dcc024027dee03d3680e79c39a5067814f90fc9dfac5b41", - "incomingViewKey": "ee7d2844f24f69e6b7ac13b9016cdf6ebfd3281ce832bf9aae209485bfc02004", - "outgoingViewKey": "494d3e951b10776159af788756fc79169babd1c44674fd36abcfade121882735", - "publicAddress": "71fb7ef377bbe2d80361b858ab2d8cd2dc526bd5e1591f794e7d213f890d1644", + "id": "edeba17d-ddd3-4b62-a8f6-415bb61a8567", + "name": "b", + "spendingKey": "892fec6b956a1f4fe033efc2ee4c150d198b2aaa2a38a2578891d3f33e825ce5", + "viewKey": "dd03fcd010aafbf08ec089bce39ac5a5268cbe1298b44512c20dcef279af4bcbe7326c3cf6ae1456336249057896bf0368cd54118697a8b877dbcc565138374b", + "incomingViewKey": "27c2edc9e1452c416a8fa8a111041eb7c799fb3809945375e00ff72d5b20f503", + "outgoingViewKey": "1110a22e0daf369fae6a371d8a6ceb5ff2a94a529a83ce92efb2fb789a5819ba", + "publicAddress": "b764ef63638d4b4e41678d678f165f7421ae529483cf8dcc93cc2b2e6a7fdbd9", "createdAt": { "hash": { "type": "Buffer", @@ -7780,7 +6582,7 @@ "sequence": 1 }, "scanningEnabled": true, - "proofAuthorizingKey": "b8510ed4d78dab26b05034300b9192410c0f91ebf109c60f9d3261835d5f960d" + "proofAuthorizingKey": "4300937bd2f0c2d6e192b0943009980478a0b956b8d015862188bf1b4ff80e0e" }, "head": { "hash": { @@ -7796,15 +6598,15 @@ "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", "noteCommitment": { "type": "Buffer", - "data": "base64:CrdKzR6+2LH4Vt+MAuJNoo7NDeOEBXMeHt9dh/7/zhE=" + "data": "base64:d2LF3PDsPRhfgw4pk92GNhjzxFLj7EHvRa1ZMk9n/04=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:6anoi2aMrsOrpvlT148T0G5FALnPyYATB1ycah0mQx4=" + "data": "base64:C7zJP6liRkuYSNRLCQNzCjxt6JnF/IaQfBqoEotnONI=" }, "target": "9282972777491357380673661573939192202192629606981189395159182914949423", "randomness": "0", - "timestamp": 1717539000204, + "timestamp": 1718998729703, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", "noteSize": 4, "work": "0" @@ -7812,78 +6614,78 @@ "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAXW00UnSpuO8qpo2Jyg3B/tpZdqG4VCXnE21y1dO3szKRW1IX+QU5tTiRscWoIIrLesCowNl+UW+H9Yh9c2f45nHsQ/UJMXrWQuHBc9B+SJ6luZht+E60UMdqZ4AiBwKyWpW8qcPo4W1huZaRjjgYcGA+0Hg0dPCOeEFKyc94wXoZz8eED57unrjvPC76XQJP8MX/15TOEHpxWEpvuprzT6W4lkHbFlDS59bzvWH/ENCnikKBV496LqMVOhiLvxPYChvccj4fOOgSYRLCIhYMS+n5S5XXC4xSI1JlVIuQDOcwsO8orzhg91Lo5Usyygox91+tBlHT5nUutTvPohwJ7xJ/1PnOrxgooYr9izO2BPGLCCdgeshE6k6nOhFoYsULxum0KMGo/tpWqRsKwQPglpenbW/M6IqBQQ2ZdOVoS8l647TznNHsmY6qGgThHkLS2yFqg1F3DDbTvSWXeUlA1pAAMF+TzD96lPWWJxh/UrYytkUjZyW//tKmh+OacfIaXQvCQ4bqO3a1jpQVS3vpe9O5Y+2DDBpdANSt17LPTG0/vuj/aH4E6EIDXjbMl6EWWEySd9l0M+H90qZ5yJq8OxeJj/ckuwkp+H+Qi2YbtMH6zgllwp3k80lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwsDGvyh14nM+TXNBMGdVKsRDxztaXSWvmYF5o2hMV46DtRKUv3XCBNq0mybrGxc8eC3YxvrX3YhCRaIVV/n2/CA==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAANVl/XAxlKVm+Wiwz8REf6J69AiIlCz7H4Ad+OOBV752S+UaCzexMix+6s/AGZAz8j3o54DgtxE0PJY4RDO/QEvQCjmn9YRn4UB8k9R61+seihlTOQUmj4Ns65GwDNHJGe9YH6gKHBV7qdbhs0awIVKzPL1tumDJFuFEq2w/axiET0PUcySpClQB5/YaLtIe2S3Kj2O1T5zs+jh1lV3wY317cs0qWTx7RsEyJacl/fm2Yc4b+7MeKg6xqtgnRQ+6CWrsdnmEHgzczICUFQAKqWEIx2J32ax6aH+b4aEsUw+jeHgRoHhgt80m8cwdvxBJdfTap7Lqt7UNfe1G+0DRzb1LkgL958DcVzvyWokZV7OP0NoZsZlfnWHM+cPHDPSdN1DRNd5cyDgFyhU603ATIxVIUqYDDPn4YSUVjW5R/eV5huLBVTrCnLJuCdjb4BLiAdchECdfeYpZjS4pdb9BLba4iNX9l1Y0unT2PQoyy+JHwKKQ09Tk49zLBEsTwoAb90ZLNyCwHl3/hLbWTo82mpKcJyFGc4A9n6EDBYxJqxuwLB4CLfcuhLPf8s68LyusxDM7+XKmxAQqsClcG4HUnZI3BYBwUdsec7LjeE253EtZeWaAZulCiKUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwoEL4AQU3Gt96xS5iy2fQiL6tjZ149m5BPQTHdKV1F9jEi2Cf81MC2qrKfnftjQeqTSY36NVK03Kx4s6UROtsCw==" } ] - } - ], - "Wallet shouldDecryptForAccount should return false for an account created after the header": [ + }, { - "value": { - "version": 4, - "id": "11033864-5f47-41eb-b7b5-91b713a63239", - "name": "test", - "spendingKey": "a86f0e2bcca2fabd80d36b0fc5095523f3161e03d179634f2b8a8b0aba30edab", - "viewKey": "117029994f58adefc5f0ec01657d85e6eecbf6171186c493d16454b47d7f132d19992c4b5b8ba70905516f365b9907cfa483649fff11272f6600df2af631c1d3", - "incomingViewKey": "d64cc966ecd93fea10610e78803648f34b2e9d084ea9dd909e4a06b8a126ba07", - "outgoingViewKey": "851ee2cb193f56a66e242c5d2ba4ace7a653fb1d6b11476cc78d98e1e0d3525b", - "publicAddress": "132e02ec40e55f3f0b5e53721f41539e2559c3da3435a4128e2de74cc6ec9bad", - "createdAt": { - "hash": { - "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" - }, - "sequence": 1 + "header": { + "sequence": 3, + "previousBlockHash": "275222D3A20E9183D3589D087629D1B42A08E0045E2458E0CCF168E36A45E832", + "noteCommitment": { + "type": "Buffer", + "data": "base64:Kic4MpK22UVhbzQ1TFQjGvHy6UQFcn/UOH4etRS+Zig=" }, - "scanningEnabled": true, - "proofAuthorizingKey": "18813dfc16bf034f84e3213c1e7d10d2f5b86da87d0520e2e063b9c899095409" - }, - "head": { - "hash": { + "transactionCommitment": { "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + "data": "base64:LxSuzQfsGrSXBMhxKO9TeWtDNuM1DXwap2bfvFYZe10=" }, - "sequence": 1 - } + "target": "9255858786337818395603165512831024101510453493377417362192396248796027", + "randomness": "0", + "timestamp": 1718998730163, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 5, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAA+5Z3w4OeTJZKCQa6r33v8CF8cJh9PnY0WAW+cZeQqBOZqvw8cpGCoQYRP4qgcdmezBk/Sk5SlR3vZagEi3wDPAFeg539olCZWUq6MHFXJVyFzVq0eJ3DehjSTmiWZC3eXEpEzZQYksp+vnI113atPMmF07AjgaSjHI/JXjPwNPUXXwylSTAD6NP1NHuZl9vhcS5XFx0CPh9A2nosh6ZncRkI6Qce50Aa5W4MB/fLGYiiMcogoaLIno9lx1OlzzfT4BdEzMfsc61xJCYcpLSIMKjRMd4jf48jjz4enw5SYVbjMkBKXmvYHFZqnePQH8pYa/Y/Ig56ymmLXQSQ6r/FcHdhnqzUj6U0GP9Ng8RkUkZCQJXcNLqkv5Z6t6WJBoAd7M/kKo0Mjm1GSXJeZtkzvW0XtVyUNX03ppjeyAGf9AQ70CN3Z5WqH55J50wEYAvgDjFpOSmfhZAKDomOB+AYYa9Vg+idjMArvUgyDbgY94retXDxXa/qklt5tbFG2iI10iIH/huEhit2tIJanr6nKDe8ep+gngZOmeNR9c5yr3k1P33peAP5wfJt0DznjuPBXaLUjnlE6Hz7R9adaZh8rX6FNjb21/WY0cpoOmtjAhqLlcxvCBSqEklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAweBE+qXELXjPpXxgjOvQbeH2si8wyiXBk14rdaFRiHCPQZDFokcwwKTS8tILc6pR9U1Bt/0vMXxSHjj6gOUPZBw==" + } + ] }, { "header": { - "sequence": 2, - "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", + "sequence": 4, + "previousBlockHash": "A8DA1388883F1124C6C93B6E8190361DA577A134FB8BA066DE906D22A0B4D3D6", "noteCommitment": { "type": "Buffer", - "data": "base64:oL6ChZ4Ly5JPu2d4tRTaerDeczEoWTNMR8BPSdlyC18=" + "data": "base64:Eid7GfqN3PnQq7+9G1LjRGQ21NdwxpmeEx3Bdhe+ugU=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:7pYycxMVG5LSCil+Dr0/ffdPvPBzSKAsJ0BS7vt6xTc=" + "data": "base64:9QOVLzJMhQU5G8zrzhLcmf+P3vHPd+uEkOnRenm2+g4=" }, - "target": "9282972777491357380673661573939192202192629606981189395159182914949423", + "target": "9228823284279306817296266184515742822248210830185427859262273659833347", "randomness": "0", - "timestamp": 1717539002251, + "timestamp": 1718998732418, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 4, + "noteSize": 8, "work": "0" }, "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAQWhZPSMc2rjX9x3Tf9wVm6W3XpdQNa9FrLxztLw4ONG1M+OLlAZ5n0ZrAZnbgrN+/RA+wisQNxN1gmrHoTO9GVFCyCCI0+mPEHK2PfdKhP+o65UGd70/+DCVBgr/b4rLGcKI5lUECt7nulxLkadWfuIjgRxOPUwunu5Z0KK72/oFDtDef3eUguxBTaQWwO4Z5tLhSwHD8ky+btDYX/4nahaXmataGge/xfnc858XyMKkVHE1KMssIWqATqHVz7rjjdNP4ViotOGY+0Y+6evAr9GvA6QYpa+cZ+NyJO0n/7qtx8mYb/+B/kKWggXOQdkv5YSemxqRXCwV+NYJ4LW4YflHA6iH2c1psJWW+p26lYhHPQXwd7XpRT9g2okgsaFZNr1QlrfNx/qG7pRBYYAIvoq1Tj+rWQ+3q8ElHbXDcxLaSLJgRk13O0deztI5l8tN/134hG7ZkXM0fVKfyfZ6ausW1CB4z6Ql+vTrD9k9IFIUv9qHMK2xfZzhSV3ar9cajxK4nqOPJ/73vnJm/knl1bfW5iSZu4cJDq6hbU2bLNx6f2vA4LODEyWUak55wgFel/aJ1BQreaqYK/hmRPsvDz9CCERiKnqIS3zBsMafmjmtvjgyb4OzRElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwnmC0egssnuPLB4XCtvfHNXGqdw/xPf3kURrN9kQeTSV3UQJ5XhZnQs79BcZ8FbaF4GhfxspKbm1mAmxC0ku7Ag==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/2vKiP////8AAAAAt+cn3qJcRwVyEOKWXOMqawRL5Ttlk9enBHO49M0mmY6Izd+CBftG7BpsHRCWT6ff7djnzwE/OaDsavpsDG30CPYq4JpARM6WeOd8pEx4LMSGETDlHAHQH6f5ZjwQ/0c0bfjdBlAO/TjZgz2NMc4Ndgam7iSqro4dVDlx9WMEBRENVp2SfZALgPST1PN7xpBVdeK2qD8p/1LHkoxmnbbKo/14BSU9RXc0a5qYMZPanomhABqHckJuS/rMPDgtMQDLODIm35/p9aWv3j+SbVe+uCfmisdQoNaXP2oP/McxVh004Rabdr12pRgHfQSIWGs0BN+ImvAXB6slhCy/X9Ghv8Ff/W51Ugvjh2Bh5D2iOM2qN+fxUUhhpP90ROP9UZoGFGPgW0/ubCxPcIhaX33YDt5DtI00RWHCfuUIJFIpzhkne13sx4yXKErSIcQDjKQEbXoSZVg3siRUYx2xQM8FgltJW/k5l2VplSvhJ/xJ+r8rexWx7qmjm4SBeyg3/TBAH7givJIwP2/PRCw18Vaaq6/9g700XjQEvyAxFZJ41kXsJvkNjVZmxuMPnVasAfHy0zAW5yomA61xlAEp41JQdToQ+NwI9fr/9Tvy9EQVV/EvJPXmpyIsiUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw/EZca1Sac0WEAqFsXKvj5uB1v0QXOb+qET6fTEI4wCgkPFvEL2uNyBOfhLBKW4Reg/MwHilwcWHUiFEYkAanCQ==" + }, + { + "type": "Buffer", + "data": "base64:AQEAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAA7tp/JQGkCLvuRBrvr2P/0/shks3UYAMZ3sQBH+vgt2WCf9E0VXB9XAWBa2DbECphBYxQZl7vK2JFpTUiNVf91aESOZsUHj6wMn5gFwvNQ8unXIagP96Ws+vvDFAHtI9nz3zQDB3we77E2GAwuxHKCfedtl4MrY9rE+Tj4pgvsfkIPsXWE4DRftXjO/PpcKeCjPHqXtwlP4Qv3YK+8HFBBA2cUxwoKPCgwRULCgtYYMKCsAKVrsflmOw0U/zxvm8ch804VnFmvX+pS4jS1ajzj2Fx0Z8ZmYuk5ZXztk3Sj8KJivkzdg/jaipUrD7keOX15pOky8cQHJoTcgcawA3E8SonODKSttlFYW80NUxUIxrx8ulEBXJ/1Dh+HrUUvmYoBQAAAO3Lwnk0qZ52dlBxi6YP9mVik3pQNnJPhvqOvWlCLmOEdqyfwjFW3pQGxNRMek3YD9afRndo/I+yPaJP77/G14VBMsjhDkd/FGdV8YcoxyEd4H70QZDQBNlLGZCwNc32A5Hn4YRUZGPjklMAM7rH46VFd9cTzJvpWAtkfoXCaR+cngx2U7G5iuzkNc91gRw5m4XI8CAQydYtCLlQ6hWVZ0KhLGy0g8BagybsLjeT8M7HL1uDL1RuRA4F0inkUOI/1wxwgYjHx/TABO/u0YEGDVP2xRlSBGIs23GfhaNdKZ6udN0GZEwrl1dBQ8dGY/pJsq7loRp6N7blWPFsieZk/x8ELGWF74dpSW2WfnovnKP1WvljNLIupLqZACg8BAedkR3bidZzzNw34u1td2W1Z7Ab7+QRO9ikUK5zGH0uXjpXB7cJhbz0OA+hsoTKKxwDmQdt/W8iDni9ONKAqmblcjpAgE+mU9XBgHwMRZ0pnt/Ua9OWBI8j9/JMUJk39/P1K2qEfKux1brHEjifROZCeKrPrn7orjbAuSV/qjzO2gQTed3B9g071I6ppk7nzYEB/mhlqxvEojPLRNWY5tezFRMkZ6cz2F3hlwY6mZ6TNxBksvSkcpj1esKHlLok7hjKiQdsj+5RBBbNIiKC2ytTL+g44S9zliIDvFroJYIp5AGeN42orbfej+0iuH+/T1wl4/i8CvqCLqvwT95jeRK9NuIjWZ5+OII8GgZZvhYei50AvVj08ueV1u1vv2wUYy4qPwQmaoIEi+BtPkU3wZT937SFz90Vr4JjJo8J2id0SbXoDtXxnqa7qLOMhampNiBYrSEoHOpqKXlIww38vkIP2Cr+/aglHYBAS1H6sxvImro8IL1eO2h9UDC1X4tu42iER+E4oiLpaYVnnHmeG0A8wY5iX+0bmqmbDL0ldnMg3ojQ61pqWi29ClYMhDnfjn90juYsEAmvHW4cwUDggpRLPuhs7zD1F05nu/ykZiSftxQBKxe+G89rlQ6W1fACeMFrQ6ql6KduInuxiKhTdLrIU6i9zW6IKFufCgrNXJH1TFHOEMzNXhNLMyIdP5U9b5tzHj9UoPDL9XwhTpdMZiDaCySoiSaekaqmcE3YBduOev/ZiaaK8VlC/kKko6ZdhXRNsKygc8QY0qhtZc/4enVn6FBUQEv7NSdefLt0eEuUk5QMEX1favkBCjItGsUXFgoMXyYEF2KEpySj6TCBQAmCVYTNB0Nz2U98ElMGZuYSJj2XwTqmBheeDUihUgsZgWy59ikDY/MDGYrojsvS8C+FWOOkBjTX5PmDniXt8twrMJwPMC9wlKYd1p6zRxM8wQGK49hwVAcFuoGjtIUnEIzNfFGTsPPywGhJvIg980HgYwA0mVl79U1onk2NtrlVpWbqzRHdwTxkQ/pGkSJfo2n59PH7uV3hkI9xUmuyLv7wGaEUHoHu2/oztfGJSYlQc+i6MeXh2753uhaq4TeCalVdVDulM16dY3TCiwSTIVTvLIoGGTJk6C+ycweal6x/NvfrLanTyE/5miDHVpta6dc3NRncxezyGXsZ2Uc9Qd9m8atO1vgzBfV4agGp6cKHPXt6Cw==" } ] } ], - "Wallet shouldDecryptForAccount should return true for an account created at the header": [ + "Wallet scan should update the account unconfirmed balance": [ { "value": { "version": 4, - "id": "22ad26f8-6324-4047-94f6-6320745e7664", - "name": "test", - "spendingKey": "5f65a8c9dc83cafa7c62a9831653e5c14131dae0c217cdc7409835145ceaae3b", - "viewKey": "666f5d9dcadaf6c5395eb11cdea1650879e36783dca34683635e33e6bfc543ce4413114f480e2abcbd0e0910d2fcc37a6b042129458d282dcc3477620c24eb01", - "incomingViewKey": "31b3d71788afbcccdf4e8b1aafaee039bfc41bc768c6d9dc04c1774f671e1106", - "outgoingViewKey": "2f1b93b172f76c3cd8db1e33fbdb4d09ad2f56e53b8756496201f8e69f94cc20", - "publicAddress": "3c0e7e7752ece79518668342353f58c0e2ded73c5f8ff59bab2dc934a650dc5d", + "id": "443cbfa0-dc5f-4a55-abd7-188b9989ca51", + "name": "a", + "spendingKey": "f77400ae038d4abcc3ad56c5656736e00a5705e92727b0bc0336d9adbaad4c64", + "viewKey": "1a7549089d44ed91832f8c04a5a2251c9c39382dc2bab1e97ff411f6e07e57347306079f43ab37c1f0b3d6f3b8ceae98096bee94a7f30aceb43ef2d8268b9cab", + "incomingViewKey": "cba672f8f62be3a6063a5ed589a699690899f458ab51fc5f6f56994a23126f00", + "outgoingViewKey": "5a30ff3926020d28cfcd71f654c9a60a0de2802143ac931eb507d09a6714039c", + "publicAddress": "0b1ed1b1bba0c28586e1cd5676452941716045048536a7e172861aa6ef2e99e8", "createdAt": { "hash": { "type": "Buffer", @@ -7892,7 +6694,7 @@ "sequence": 1 }, "scanningEnabled": true, - "proofAuthorizingKey": "a09f3fc03ef8e59fc4b7f4e5c90f920ca113ccb6572761da439cbb0bbf6cce0d" + "proofAuthorizingKey": "ba62929ac5412d6e59e72a2047916f3e4bd2332c4f20de1a9c17c1dabe79600e" }, "head": { "hash": { @@ -7902,44 +6704,16 @@ "sequence": 1 } }, - { - "header": { - "sequence": 2, - "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", - "noteCommitment": { - "type": "Buffer", - "data": "base64:neId5as8nWnh1dkeNwfT60oMa8Eimkjep3sqjDz35Ew=" - }, - "transactionCommitment": { - "type": "Buffer", - "data": "base64:xfYXQYm39V4hSkYFeMAWOI25Kw5iUTCY3bRCmb+6D88=" - }, - "target": "9282972777491357380673661573939192202192629606981189395159182914949423", - "randomness": "0", - "timestamp": 1717539004596, - "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 4, - "work": "0" - }, - "transactions": [ - { - "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAQAvre+kQkIaCW7kQ1/ZTGhm1BlX0yfJDob4ZNUEVx7OYjqwI9S9DEnnPsw4Ui6sbYbhQ7UK96yCy7MrcLvTogCAVEcpAxvhwSh6KN9aHglavTbp2dovF3LzFHVKjwM6W54QY1/guZlg9jsf9vJq2to2F6KIj0iupDgtVWZL5ZykMv1/4c5IhCAbFgxCbbmfwn0VHec7qsvoID+NTnxbozPPgDQuB7ymZrAafEj0zHLOuSpk6bIHUYHoTyINvdI82QcfNpGVI4j3bwyQoiHYoOWNjBsnUa4Fzv3L7uFAQ1djs8Z1eH8W1056B/xMzTf8MZUbA8s2DjrXdM4CSRubuihtUBdtzNyUXhCVDbEprbHLiehM4RAwbjqo2B8WcLPxxRsezfH54n+iIo60PEnjm1/eynKLAB2cBzJwUTnb3uzfSIb2M/lJ3S6RTXWKdIlZgKqdgTcEFTil9l8/5CV+kuLnKiUvvd0tzf3UxXIdgsyEsat27IRfRTRYAbhI0fWbIRUvy8x7dpWO2sfCEHIJrITqsk+bdztvywVrEeLkhewdJ6PrX+6j5M8Vr9Vu8iS5lLbSRUCqDwNTaTnRkASmqeTUcPzGiVQbMmt5UhSE+O/ail/Uh7rDqpklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwyocN2WaEeJlxznepvq5LKiCOcApaZIhLhZNlyTGgi4TQZpRqPbpTMB8/aTS7bD7ES+29kxkULU4fhbyekZinDA==" - } - ] - } - ], - "Wallet scan should scan until the chain head": [ { "value": { "version": 4, - "id": "f0c05cc6-518e-4a60-8c0e-36b624461c02", - "name": "a", - "spendingKey": "cb469a5b96113d3ce511481ea95f5af796246c8210ee36ce933459f20f9ad054", - "viewKey": "4ae13a3528b39c2159b934eca7835ab728d2cb6cf053d103bd90e2c1bf8e1b6c3358415e2dd8955c9c35f33fff9888a0d39f7168ccab32b57b8443adf2d4d5a4", - "incomingViewKey": "ce8f3645d46a27302d7cf8f50b925fd6093efa5d0fb1281f2e05a6f299b07505", - "outgoingViewKey": "cc5eaab7ea9948a69faf90cde50994cf5229b3d1a4ed346009895e4089b3deeb", - "publicAddress": "58ad1cffd3236ef303e9543a48ea92784f46233e97de4f739abb432860bc7244", + "id": "e1f17f03-19ee-4855-a041-7c20c3163504", + "name": "b", + "spendingKey": "e1a1fca44e6fb879b0ed333e17655940b0bd0ea76d29c7471395987574ac4200", + "viewKey": "eb24c844e8cd929092d85ec5b8aec0ab5ac0f1e98e8387a2710e5c62d06f9a44d1d2271d657c5a11b6efe8a7977b919c3acfc0d52b5083a4826d93718f40382a", + "incomingViewKey": "a090e822c984a1e0242eecb707f95a44c0a6e451fdf71b46118367b0ccae0e03", + "outgoingViewKey": "14b7d822c079bb399a090253e1acb60d7fb34afa929b5fdb07b675b4d8142b29", + "publicAddress": "98157d7ae91fa6b63134ab69de8b2b846e46f7244584421186a60db6d707ff27", "createdAt": { "hash": { "type": "Buffer", @@ -7948,7 +6722,7 @@ "sequence": 1 }, "scanningEnabled": true, - "proofAuthorizingKey": "2a24fb483ca3e2f2d5e1dc91513da2b6026b6c89b92e0fa154e9d05d4fe56502" + "proofAuthorizingKey": "c44b0f397080feeb29e812bda53ac2329a176f0904cf6c15cd68ece8215f280b" }, "head": { "hash": { @@ -7964,15 +6738,15 @@ "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", "noteCommitment": { "type": "Buffer", - "data": "base64:/00uglzCYK1RtfBd+WM7QsY8fcMjUE+tPuHc9GBkgSc=" + "data": "base64:JAOuWmBu/5e/8/RiCwKZWAF/U5Ax4X/kpb9MJZRh5wI=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:y8WerlC5JWcBLf17AIqMoKxfYsNZvHczLdfal/RGwgg=" + "data": "base64:3TdAabY4irz2YH3Y9erSn7R0uoEZvf8HriiPOT6H//0=" }, "target": "9282972777491357380673661573939192202192629606981189395159182914949423", "randomness": "0", - "timestamp": 1717539009281, + "timestamp": 1718998733489, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", "noteSize": 4, "work": "0" @@ -7980,48 +6754,52 @@ "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAUxDTstYMuM9cawjYTcco2Rm43dbO0mhx5TdArJFcC62j068X726p5jAwYoKZoZ67qvXlWAS71Ezaug9k199xVN7HiZbw8hIhr141W0DWZoSY2A4ck9/j53UHZ5irLzjOGtRLRg3hzUGfJcUNoBsxjS8CwAliIczo9xJUlhnCicIDlA2uHFPoYWUeAzX2uACvsSpb9zdjFdoAtcEXPTpj05VFac0duw3kjHmDMJm1/beCyZpPVZx69pjDzSAp/Qlp1WsH7TQxRGWGvdy/oYRXFsI0KtmPhVKtzPAyc78WNn3h3En5gGcnzr/LHT5DUnTeCputh8QgYsJ/PtCX+wy/Sb7L8UnZWkqkXBhe1HkRrOYdR0VjQuVztszS915xO/tKwTQJPQR/TZwAnQu4nRbcDyVZVPeUpOaWGqE2WBcoY9tNZ6vcsE5FMg8E2P3G1BCGaeArJOqbMOpNSdVskpXDqIWWQhN3vR0t5dFnu08CYF5fgnPK0Hv8BbswFQCjsoV3ciltsQ5KKOXHIuCs2kT7FwpDQnR9Hy5NySzk3QKoP9YZTqRmf06iCoxsqs77Rv+n0VlgQGCLAeeK+YFAyeUab+NNybVcVXSCkTA7y3AH2JFlTiL4EXGavUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwYS+KKDPB3TsOXtkukoBjlMZZZ8q+QpNVTZz/leVM0NGVpTdh0RUsbf54yQbeeqDX7cFl4dY+lsZyR7uj7s7DBA==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAANJgWLJuWiGs1umanMHj1+nIfhsODke6cO7kFZb/Ys7GBwbgJ+mA706Y2OsRUHD0ir13Ewe+vE6jD+Bn0xZsbNrR2fj1mTBZ1v66Mf6WnKhGjW/dGQr1a0Z+pdp3ZkZMDs9ltPB/NGQTivkB1dP/BZ5yiKQvtrgwsQW2xNhzCq9gCkdalu7CDFX5l9FeJZT/OATXmXE6y+9yFlxxCgtGqIAFgsii9n9VMwUIQotsL+UWrATdSfXEpRASrEANGCzfOPXAeRP+q+yXpVWhrPtOYSgTGYrTx/BdMlXfZVTyBgh2x0JWIQ6b92NO9w0K10LbM8ukfCYZApkKMXv3dCfZz2b4WQtpsU+xsaT4fameg1JGFbhC4DGryDJerTcdli0sD/xIBNKiWj25hsrRN6r7uAEjfJEreSBx36QWWWg0E1WZ1Lr7pfEN65m03PNOgTdvulYzOVwshMIRmpxRIj85QxFg3QKAmiYCstq6b51MHhmvtBrnEMdyCO6xceQpqM5SbaN8CCwYn+GANpJT4UpDThK1ywk5ScMmIRU5wR+kiMtNFc6SYTMzqdFfgfe2+VUZ9Ndnkw8FyI35CFNoM1Gqpm2zaL8BDcrE+JWy03dEku+bQp4qXq5oExUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwEirJVXAhrO/3zGPMr2Bq8cDxcXIIG81dg2J6xSS3qFYXXquSRWYL3pthOXm9H33iASoggKbPsj2tLHZFEm/HBw==" } ] }, { "header": { "sequence": 3, - "previousBlockHash": "8B89B43F3956FC769F957449516569E48AAE76C7E1516F43781F37B40DDE6741", + "previousBlockHash": "86B25C4958CEBDE15BC9CD38D25DE3A9487F08DBEB8F7057B885D31E51FE9ABE", "noteCommitment": { "type": "Buffer", - "data": "base64:uo9tMuotmcfPO6KvlL6q4CnesDqEYlm7/TFnZpHWTFA=" + "data": "base64:2UkxK9N8+IJzC7/AFAF1+lHXNakTzXfVG+i9iRr2BDg=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:mzGsYnnneE49w7ACX3U8Fg0FStW0D3fmPnEhZXI84xw=" + "data": "base64:yMOSFF+Pmzh+4AGWUj8UXhnXrk1ldk8xAO6Gh9iLbw8=" }, "target": "9255858786337818395603165512831024101510453493377417362192396248796027", "randomness": "0", - "timestamp": 1717539010301, + "timestamp": 1718998735748, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", - "noteSize": 5, + "noteSize": 7, "work": "0" }, "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAm6ILXOTB+khyWx3f4nNeMYILKANSUsv6Vf96Stg+qmaKLl90+O/8xwrViZfXoKbS4+pokN3N+6CWOVSEgGQ6FXkV/iaNvSnGHZD83/Fg1s6PQm3b6eRg8UBbAU+IQi0i8iOSlVro8M+XZ8ChJrAqFLvvVEhh/uobrCCRYYqrWgwAi17NqR0zbtGA/mLbW1z+2ngREYTnGEfrtjo0YK0rTlzPJkxF8bsQu5nn4I43XZmNJ64fmHr9lIWoed/wQ17ErBDexmCW48XxxXtHj1TXXyAdTZ8br+wXRuDA3Jae+KM5fgIRfoUIM4/bbzt5bcZRDxIGkygVw8PYAyjbhtq9nbA3lv1U9+hz6JFp8XI0ZxC40dH6wKEAMJRKwKGjeAlUphPSkVfDRJnHRmmIrAkPJxtKJKVQF1qTpz/DRzYacDQYfdr8abQ7QGwltMhuWeESYKd5B+UxwyL4zy6ew8MRq8fDEQSnnnVSWsYfrdGmoQcXgqh3oomq/rmEhgsemhwDJ/rnEeJ2MTESpc6n1xV3MunG9jNNMCBk8rzZwHMZmQg39j7mydsv90nlZJ5gaGM5k/SOAzekaECc79++dwkUiSebWeCMSb6e0fYS8rWQ/I1Dhn8sBYi/W0lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwBDKVr94wIo44rKdGWzeNvRGHkMwEMw3uAZV9HBE6mG+KJ30/UMOSL6QMU3GphsQH7P9h2ZSKhiVMXrikOgo7Bw==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/2vKiP////8AAAAA+y4bbBfJu5rxeGt8f4v2JdCYoEQwuO9i5ncX3YN9PeavmpTnsGlqdmdPYi1GAnVSuwu3of+lz82jlIGlAMzXln4aYnGa9nzGVtcEVY89VMe2syy3nY6jc2RbTluOPAnWFjPqwnmEF2SK9mXQPe/RI4xQKz12rxbYjLMJECkS9jwMBxjtxwWZamlEOR0fD3wvYNN9dZSSAywxsVuorYhFx+pw0sQSiTSKUrENDr/ysia2hSGJu6QCo/OIqQc7tw2bCcR3ukhPp/IKDJXy0qkPpRvDPjhzL3qKQh6CJTP4twVA/T3px1ERow8pPt1mh0kWb7usEDdTNuYmVUqjqryG3++MfhdG2wkTuvWCH2AEmzf+W9hOpnI10T+IkP0EZoQBtg3l7GyQ/hgadXKMPTvfkfeyGP0SjQX7B+Q8z6kRWMefoLCfGJogfZ9EQR0mEA1xsDgLbQ3i8Q5JqP6BD6FS4eVKi/vi/qtJjfXbIn2t29pF8nGt1PI7WZDVs+aC9IXjF3ueUJONVm8KOD9bmgZkBRsB5ekI31dPsx80t1FeCePpEkL5QYJbUX34+r/MBDFe8ODwwtIx+/VOcXncsUXZz0os/gzApgqcyby9X1kab6gmoRX5XlEq80lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw3fD2hzP8yNJGC1ql1ANxzu9H5/UpQY0fQ8+9O6OFxrtDIkzuZbBCyvE5FFSg/ZnQrX6FYA9SbAFMxmSyaRUVAw==" + }, + { + "type": "Buffer", + "data": "base64:AQEAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAqWZmNvRWwun5hB2oWP8cbPik5Gujgnh+skmTGFMPl4u4UGj1JBY8uDsVOzYgKgO/KRoNy6RzudW+2/RZeQz8Z7/UD1S66YRbTK66ca1fTcyEjwxZuseoaMJGfivTnNTaBtcoiWkYUn/vNpWii76sG4o95pPhlxEZ1L1OvJl4A1gEEq7OLKy3xf6OBnMUJlN8OZC/aqrsV6BCq6UZa3SFEOqa3v9fLSLklarZM/CqM5OVDX6MWU/QAIASRwG/AWMDea/iEAnHEC+WzshCL4LhHAXg7PdCnnC9chJYzcEvNeYld9aXGVQBJvbSHbhx2cvBPgbpsfib9p8m0uFJs+9YyCQDrlpgbv+Xv/P0YgsCmVgBf1OQMeF/5KW/TCWUYecCBAAAAJ4acn5O9z7n7PyXoFg1IcXYHJR04zc6JzR2s9hPYkHRWrC5Dv5uDDlrJyheqnFnGYf7kK/qMh03+p0I2XDUA6pv90LaptdIoTMRjgqFYBWw9Fzh1QUhGkttX4qnM19TBoGyjSkqyEeO2D7byk/LpvwUaOYXqXZf2LtgsYAZTXnadjba0NvB8hTDjDMBWEl+v4WANXX8pD1r0TPhc7jLs1dFLqio1qcgDfDtc3Mdb/5MCc5BKdhrfXTv5tsbFgKTmgJ0WBwpnGLxO+DZS9k14l+F16PfVdXfES1QqdgRFhg71FtZ1GFA4Lav9nVr2o7B6ImaQYBxa2mKTQUiPizxpVDiaaPsUq/9IrskpLG1lKWvETSrKc9oNV8BQrCw8EdCutFDRRmw3QWOAigwVe31QNoEY5LolXY07bjiLklhJyC9tELzY/EjVywoPrYHAkQo5eAI/9hFaZIPOSYYb5nOUltGCFHK7sq7a4KjdKSWRSde6N3HgZ+ATWtx9ZGvLCNeyApwhbobJhPDAhil5Vb7080pm5yfJ6eYpmxrRBy2wBtswxVjmpt7Ly0A+QFzAnwntF/ocyqq+lF521bnukBSstULxJtpGENAVr69h9ICeDFrwCVbwXW9G6Vf6/qUZdx+reWtACIz2Ii7+pkDOG1iKZg5Y3Ux+sKesLJvLKLqMl3+hAkpe/PhYd4A7572P2768CG6RpolNhDUy2H1T8Z7/F2p8x2Kw/dnAsgu1BfCvARfdZYZVhHHp1hBLuICHpi2Izb1I2CBtFlAfmAmREZDB1emCfyOdra0Wzn1sH1MgJAyTuzrChSNFu+AJO8WuDuyNsMnMVRPTQi6rx7smsiqbmgyXjEMjNd2oFLU+1niQqCZcXxX5JzZsy6FvQy0e1vEzaIaYjTOijyFNw0jjd6drdLGtHa7PdWePXYeeWJyJij4i0bE5f0ke5MCrIdus0Hfn+iPhHsDmVcRLtynfcLnmOAtPSI7DZuB/3g2eIlfmcxKSZRYFrpYse+kyIE6sjsYyx7SRlZm6pakIqHwIufXU1mKmeXEjHHyfA0/EomcP5TaVtmtf6jJEpjVuA9+8KzfvSqupJIiDXCGs+nahT5/CbYTQnhZLsmQiq6mHlvWGb9hfyLimT5HsEd5kcXV4FCNeqsZCnT9sbJdBb9zNqpS1rv3RQ/fotNKBTwwisK1UqjzjB2LnewSYeaAVCGDMYjzA80qrc72Si/5OYXu9hUzj1JRCOuOGpKJsZe0eJwUTzlGyJllbuRZaJKC5mjCXTzl6ihQ+/iKg4LLc6jC/ewkMUoWgYWgIQBahy18Nn+2rOWZA7ciABWpD0iYQn7Qia9qI7MCJAChYZOsjTPKnmwFli0ESdh74ABfKO4t5GHTmbroysAH5SUL+B8rZAzWofgQCeFwo1sSqeg4D33OeifUDPQBdS4LjchfmYoxSxl9/Eidu8yoFuGbAWOcH8cwiGGtH85P0dSXaTYXT+wjZrQhA5psNg542svtU754sGUkJRR+UJwkSFg2HS61SHounGQ7niB6EgrGmiLtzpyQ93EmLhFlfG+c08K814r9QAZ04m9TCrAN46e7tvFVomOEmP21Cw==" } ] } ], - "Wallet scan should start from null account head": [ + "Wallet scan should skip disconnecting for accounts with scanningEnabled set to false": [ { "value": { "version": 4, - "id": "fa5fec21-c63c-498a-80bb-5919bee4f57c", - "name": "accountA", - "spendingKey": "2089eed9e71a6ca6ae3fe89417ca1f42349aad0b2ed0f1da13fc958d84032880", - "viewKey": "5dad30944afa1173644eafbd2e4938cd3228d3aaab8668587a2c0ab0cf42cf256ab4365696caeb17efe20b909935f90e5baf6d84b2d70f7fda4a15440aeeba5d", - "incomingViewKey": "ed5859e15f2ad48861e603e4b8fcd74cc22637a12e9a4e3ddd8a4c5c03908b07", - "outgoingViewKey": "6ae21c18dd5b081ecec4fe73fc417ea7c83213e218403b3b80a92d8f0420ab20", - "publicAddress": "b6a489a014a64d0113c110531b99e19927088f301bedd11034121c28ff977848", + "id": "d01c45d9-1c27-441e-b784-ff8af537c9e0", + "name": "a", + "spendingKey": "8f9f64a1eaff9f7feed5244b5356aa61c8edab7d83227136ce701e69c1d0a2fa", + "viewKey": "9ca7f43bc49a93232132fb6eff5762dbe7ce62cdff57a3e276a3f3fc1d68fbed02965c2a565c2e807f24fe62cdf6ece4a44c55f542f43285f2cec5a92e3bb7bc", + "incomingViewKey": "ca7688753ac80b4babd412c1ac2b39148856a7ca306a54f361782ec9fca2e604", + "outgoingViewKey": "16fe0cacedf66074cc835585b159b984784685a157c2511394c2ff5cb1893f3c", + "publicAddress": "9075283923f7eb216acc138b4412e2b78ddc99f48c9867d516beeddf84e0d872", "createdAt": { "hash": { "type": "Buffer", @@ -8030,7 +6808,35 @@ "sequence": 1 }, "scanningEnabled": true, - "proofAuthorizingKey": "8083d151507df2903b0e39ad090c3467a8035e6d230348638b5c8fa4a53e2607" + "proofAuthorizingKey": "8b709ee47be8e24d64970d6ac14fe5e14552af8acec8c486b3cc69f0313bb802" + }, + "head": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + } + }, + { + "value": { + "version": 4, + "id": "66ac2ad9-775f-4674-b49d-7277abed0d18", + "name": "b", + "spendingKey": "7c524fdba59b45ca4c01b65be6aa1c4edf287788bcd7529f2da08cd786ea56e1", + "viewKey": "e76d6d8128c44b4bda9bb58f2b663641342fefd79f98dca8429046653aa2ba44f36c4af64d07a47d38ab353022697331e19b8016c850ea7157b640680e9ec0ee", + "incomingViewKey": "de480528573e53b2139f742f194cb99984f10df212edb1e6590c9dbe8127dc02", + "outgoingViewKey": "bfa120aa34568cbfd328b9d6da5057dfa6308a09ab338f0c1b7e348265bfa8f1", + "publicAddress": "6e05c6c0a4eb2a30a09dc8806240d36a766c2fc3b672857a9f465749cbad3bbe", + "createdAt": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + }, + "scanningEnabled": true, + "proofAuthorizingKey": "8091bea3e0c5c249a43ba005b99fce709dfe1505bcab213233f8e09fe2e3b005" }, "head": { "hash": { @@ -8046,15 +6852,15 @@ "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", "noteCommitment": { "type": "Buffer", - "data": "base64:RpA3KWtFNM2ycx4RqUuxT/lTJXhNsgSSzA+s/MjUzFk=" + "data": "base64:MTg/aR9gMZCMIXUUkINNLEVV+pZz1Je97ekm9yvSsXM=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:kC61YxPC+w4CJ48uIDdKrdlZvlYygzEdESlNqDfQj+k=" + "data": "base64:6bRyH7X/5l6rOOtDOqQh+aqq5M34RnhIQ1dtomZx/FY=" }, "target": "9282972777491357380673661573939192202192629606981189395159182914949423", "randomness": "0", - "timestamp": 1717539012639, + "timestamp": 1718998736844, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", "noteSize": 4, "work": "0" @@ -8062,53 +6868,25 @@ "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAQtcKGcQLA9vdKYUbfiboDRG3yNKRFR+TYJ/xaVIdd1ezoqSGFv7an9yxIx+jZqggiPeT3jBvxXc5dkGCWtC4aBBgms+g6U1iPf747E8V8tuxabDVbG4ZUUH8z2J7UfO+Tkj85q3VZTik/LNZJMw4PqM8lNixWgPSf0mbNeJx9LgQGyfPwlFJi4r102u7pUTy6NrzD4fJUdMVJ57pI2sHs+luhZEiNy5G/PU/kHlTUGeqWGpWLyV0X8HcrmFL1yUnvDTqXI5wGVxlRL1LKxhYZ9/bjZgvzCQqJin+IYLc7u+HrcfezmDEmdPUsBnAi2Jsx6k7Wpk7C2NAmvFsTP1UTBVMQ7yvBFWuBr4oIF7X+iEQPm6IxXQhkeopc4V/UkFTbt7GOPPPxivTYQw3RGo2eExeyTosat7UvwzZ/OQxQNjSKCa+U3/G2isyvH+rUqDU5VUKTXgUN+BB/4Ev49nu4dSo3Xq4S4lEoGz7QBaLscCBrvTKnHU+GXpNO/KpgZmkMWV8P8mgDBLmmkeSg8ZvrHPOHwhT0+k5cdotIR8xJ0NfAmZ/J3v3tjct5axZZdm/dymwlxT9OjxbNZBWQfpgwghXg+KYILEMVMVDhhQJ7bmDT112vhoDzklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw2ggYFzS9r0pWoLNkQXMT911ZDG0P+EdOhVbSNjRSS0tFLid01pUX8beOMYMESLQDWCpl9awFqHDFqJGqWwlRAQ==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAojYc9cW5YD6f/aC9RGr7cMD5+abPX0cvDTjbIYQ70Bmi8U277G26BgwbJrhL67BBLx52FXA4vIrElodtFoXpUNtM3jE8clfPTgpjZ3mbzZWWfiRWi1pRlsleMs9GH03VMPltTl43JPVR7nZPskdUTWXSwQL8etZHzGYdXA7bwagD4At1E5cZknuDV0+TO2o1dbvwHUG/hLnTc/jughmpIbMJkstaIL96XajYJ+w/sBuDujSehZIus3hGf/kWHlsUz97iCSfHoU/VFe/VyHyH/0nQe0sZnKwQY6M5onFLOqupQukswdz86Cn6uzVK5xJIn1AqMSwIlHebVe5w8bCEOhtd2QhhwcLP/s+tTS31vJjXofak69IziudGgUf00GFN7sxVLPlMV6tzj7bkVV55fAOijqmYT4ojcGQbGr9LdI4lwNvr6yq9xeqZj+4Ok6ZitG12MStvsxZo49ObhkXGh+EVd05+eL6uMpOK/MsnQ7PSQVEYfEA4RFNY+ROCjNgkFyFuS3Wgt76netqrrgFzuvsuW+bRtlMS0xpALhvtJnMyLVruXQ4Lb3/NAiSao21ch4IDNGkRmLwmxeXqyG4FCGmOeq38eQYFwElymIKkbNw35mineXu2wElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwLQADJ0kFUwvmaZChkqEgsM2amGHvPB+NHgy1y2uVuJ0Qb5C23ATbXfWgvKvy/Zz1XEck4fBw5N/vBpI3UJ01AA==" } ] }, - { - "value": { - "version": 4, - "id": "b348877f-52c4-4880-8a4c-1c41f458c46e", - "name": "accountB", - "spendingKey": "fd92f9b2fe73330502288db549743d676172927667cf615226256bbd6f6a2a3d", - "viewKey": "dc745ff1c68bb7ed051719541823aca83421d6a55f23818aaa692b0c26b85a0bc0931f4addc90bd6b9c8c36e3a6e792c7b6c13b2312ef35ba95cb54c73846eee", - "incomingViewKey": "217269c4aa780e41dd102d3bd6dbf3a192a637b5cebb4ca730be5b8bbd5aa403", - "outgoingViewKey": "8e6945c8a702223641536e38de45e76cd64ef9e8ce64f2f901ce7ae8ca6e8288", - "publicAddress": "b85eb15dcc56677ff073dea9ebf79d284f6f34a83466dab734cb3f5e3afb53b6", - "createdAt": { - "hash": { - "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" - }, - "sequence": 1 - }, - "scanningEnabled": true, - "proofAuthorizingKey": "46af1b8daf03a4f4aee94a987e6d590bc7ffa7cb6781ee82b5bae126e53c6006" - }, - "head": { - "hash": { - "type": "Buffer", - "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" - }, - "sequence": 1 - } - }, { "header": { "sequence": 3, - "previousBlockHash": "09FFBB8D53A173E1A982C8ECB57ACC9651732D0BBE0BCFF971F19B097F9E72FA", + "previousBlockHash": "5A1DFE92484FB9E71E8A586CC2382906E260D9077C20C1300942A9409F020952", "noteCommitment": { "type": "Buffer", - "data": "base64:KP/vitIP8dVAxPlWs3MzTfd7PzSY2sKpfA2IIjVDkh0=" + "data": "base64:nCNnG+aGfdXDWeaYKsjwyu9ucIDwL/+HKQ6PV4Gf2GM=" }, "transactionCommitment": { "type": "Buffer", - "data": "base64:RKvoN7dEaA18p2zAP9UGIMXNfnvpA1Wdnycb0NaXCPo=" + "data": "base64:ayPbzwWzU73tXogX3NQtyxd6PqidvHJnHOnEjEn12O0=" }, "target": "9255858786337818395603165512831024101510453493377417362192396248796027", "randomness": "0", - "timestamp": 1717539013985, + "timestamp": 1718998737312, "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", "noteSize": 5, "work": "0" @@ -8116,7 +6894,7 @@ "transactions": [ { "type": "Buffer", - "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAeRsNEYt3ZwfhpUmTnlAoxMI6+BpLof6oRfHanFWaLQqWZCetZjOwdBadG2PWNRfhOYCj5kCz/FYXyqKDMKkTU/gS5tSiLixEqeVWt+LwUneKKoyXAeZ1OKNH/obHr4wFzvBwbPZ1/NhhgsGvbcBmENXpKynPgC4At7PCqBjLn6MS+xh8L8JI2YI25c2Jzac7boKEO4SUJWqQjnhT/PVNx2NJkd+ET9pPxDPxVJ9qaEGN5lmieKU0h91OfnpxUPWoHvbHt0fyfrEXLJOH2IMF1P6q8YPzmBNIPE9uWSh1Khrcv2cKbkul0cpw3Nt32rShV5kTakqHe/LipBTzKGmRSyfMk3R1qvkdot4OrlSGrgB9MMJKLf9yjvMe2Mq3p0tRzViHcNTZm4LWDwbaG6MdKaHz94M4iDqzrLa4lxGQaNoV6qLzRvvUtvliIlUh6ZRyXS37gNlD7Q7BNWuGEMsDmjy4xt0/fNsbO14ZaTKnn+EPbGECCOoDKX1yDFBlhzCAOEd41+Mi1AT641saSnvO5sMHoLy2r4x+lrDE7qyCL/3SClcmj0PFbi+CjPhSJn40hErDnV3//Q+X5tw+NcSBzwydSpdZgwwRm38Y+h3u+IsG281wffNTR0lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw2eSVCgULZgJi31KzK3GdX62J/O4YGGwndBTL55y1Qd0m4Jq3ikdnPKJCLa67MczlYI9hwYzENBQbt3O3NOeRBw==" + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAA4q5cDD3EIrK9jOzo3PTC5uyeeHAVhKl+DEjb+FwJzjqIllvMNzG29ysYAQGkeN6Qo9SfgtWUbEItsWGmIBdg3bjgKP5hS6iz9gKzkziLaOKPSn61Ins3rPBJgvdZO8YMKnPNqTor47YDW2xTnN09+SAWW5paLU2ruhY8Iz3VBigH1Ayqt9c00F9u57jGqrRkgBd0ADzFW677S//uXe6JWzMV47CV7TJAA/uR0zgK1e65FV2I1oFBmNXLWAQEcOKlP4rSA1rk4y2gi7y2IJLIb9IboomSB8w/k7q7i6DUSuX7NCGLpNt+nLJP5zoTtftGvDxLiVXypzELKdYQ5s3XqJ8DsRlQM2BnNYFRfVsl/fpoqvAMoVNWuiv5Z4Sm2mVi8W9oSGy0p3xfa2BGpALMOjyGynNVRbzGCbDs0HryROqLxEMBx0YtgzDIurk8cnGM0LnGhOkr6zmf0GvkxuipCeDbaMGcL1oBoZMnfd+J34EHIEkHDiYlyg9basmgETPkp9oRtQn9OBtic8UZmYcKBwBL4s1s/sugVBCb9k/cyUVY8PUi1Mfld3Y1xmYub0ozh/qB9VAUiIBJJbc4SuE6YytRlhD4tb9FFCqUADMBjOS7gqrPTgnnzklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw+x1olFr+T/SNNAY+6xlsbb3HAc5jNQUfPi2EzjciwJqkati98bg7bw0CCEJrkhy/TgNv7MCMyLO+nBimjO9GAQ==" } ] } diff --git a/ironfish/src/wallet/errors.ts b/ironfish/src/wallet/errors.ts index 344c0b2690..342b79c235 100644 --- a/ironfish/src/wallet/errors.ts +++ b/ironfish/src/wallet/errors.ts @@ -43,6 +43,15 @@ export class DuplicateAccountNameError extends Error { } } +export class DuplicateSpendingKeyError extends Error { + name = this.constructor.name + + constructor(name: string) { + super() + this.message = `Account already exists with provided spending key: ${name}` + } +} + export class DuplicateMultisigSecretNameError extends Error { name = this.constructor.name diff --git a/ironfish/src/wallet/scanner/__fixtures__/noteDecryptor.test.ts.fixture b/ironfish/src/wallet/scanner/__fixtures__/noteDecryptor.test.ts.fixture new file mode 100644 index 0000000000..ad8c84fd9e --- /dev/null +++ b/ironfish/src/wallet/scanner/__fixtures__/noteDecryptor.test.ts.fixture @@ -0,0 +1,372 @@ +{ + "BackgroundNoteDecryptor decrypts notes belonging to different accounts": [ + { + "value": { + "version": 4, + "id": "7c2f8d96-d106-4a28-881d-0575c83fc525", + "name": "a", + "spendingKey": "f66c365bf79c2dd79c4020d5bc1035a11801381ac4629cffdfa005416249d5fd", + "viewKey": "486d222400ee1d48bd41e283c35d2bd40db403d5b0672b5172d4cfd96ac9aa69a48c884a14fdc0f9028bb54997a9e310bc92af843f6d62619ad9845347825b4c", + "incomingViewKey": "f7ce154974e2e67d0f0527f1654849ba381db5114607729ee7a607b9e0dbe500", + "outgoingViewKey": "d572ef776cff8911609bbf1d17b0f99cf7d7b7106ca22e00fa23f4a356598f2a", + "publicAddress": "45e654e5369ac6542c7b58f0f75cd33c438b0e2c3e37a7a4d49fa240b9b30670", + "createdAt": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + }, + "scanningEnabled": true, + "proofAuthorizingKey": "8047e668c477f7dce2814d832cf6b7f990db8951cc62a56693969fade5054900" + }, + "head": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + } + }, + { + "value": { + "version": 4, + "id": "4b4c7ca5-fd2b-4206-a961-308db8ce37e5", + "name": "b", + "spendingKey": "0b4d99be40fc3749e078258919ac9ad72034a726a200013a07100ed8a286125c", + "viewKey": "82cd94e815cb70ce2a4b6662ce8a08dfbfd161f95848edb7e7f52774c99809996ef81b670e345dae038a8ff1bbf9c49b5747dc5a590bf9aeae6551b712e2bc55", + "incomingViewKey": "466ba7009f92c950750d20749d905fece3006fa34e25add7884db8de417b2102", + "outgoingViewKey": "6e620f74dd727ea99416dcd5d72ab047970b142d80ad68d5f0a17511ad9f3b08", + "publicAddress": "ea4d3578d46302ab6445616cd13a74bcf7de9fb20019ebb5a0b0e2312558b114", + "createdAt": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + }, + "scanningEnabled": true, + "proofAuthorizingKey": "add170181082155557e9ff7286b63b63d5217924574dad4a8f4765a550035f08" + }, + "head": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + } + }, + { + "header": { + "sequence": 2, + "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", + "noteCommitment": { + "type": "Buffer", + "data": "base64:zfcr+TmDxhEwAhBQ/zi4z0MNzxv242jhJ4ucXIlPFzI=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:SUuYRMd5Qz0Ciet3ll6faNPap5vv9b0psomXeZokN70=" + }, + "target": "9282972777491357380673661573939192202192629606981189395159182914949423", + "randomness": "0", + "timestamp": 1719013983104, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 4, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAQAq8G7wyJyJ0lbGbSN0FjqU50rhwY8Ryio8RZEi010+k8gLmU0Ql9OoeLqakhwhV/orlG+D9yYPAf/o1y8oslnckAdP24c5kEt1gJXACPZmFHEn77TFYhRkY/cA+zOOSp7XCMjvJZVKFv/xfxQlWmv2D+Sz00+GErhwXga1/WXMFjqm2Ejhs7RneoIeo3VmnBEPiiOKYK8g5ZpnEqDrhonxbyPTUpLzVOSf1FG8hdWCxk+TAv6qyWVqwae+5te3fjdRrSDosdGakBVQhHnRJvJFozLGMb2nZZbrgJX4XEV08w7rBG2D+gKG+6PnwejPr8JjJzI8tcgbE8f7crO0AnR1eWXyrt/t6XC/72YTz7x9uA233fNnVfCJa5gmIx0oYtgTlRGya1cT3dVYfHr6/JadS2IUh/vPfOKifhN8Lb+QbmFiXU0T1Iut1UygpTgYlbTk6Gl3FVEb9gsUMPyBiLDVto5f4wUa17QGKnYreZ5OodaL060Hwiu1eqm9d1NAOFSoSS1rkqQinRuV2pb2hx+lS/tzC13viR0Mn4hfxI0ixrYkm2PCu9vZCjsjOlx9194GdRcr09QdWDcvE5sGTNUrdrGh3Uh1UpqlgHGl2y+/8xlk+8ES1ZUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwY8CLN3dtklbk+71Z3ZBasuh+e7H3gNrrY3feBdbEf4qepCuIcTsr96KrImOmoncBy1xLZ6OE+v3p17MqTbSgDQ==" + } + ] + }, + { + "header": { + "sequence": 3, + "previousBlockHash": "9AEF6C533357CADE4EBA52F9BDCDB30438040F1A45C016790431844C500B3922", + "noteCommitment": { + "type": "Buffer", + "data": "base64:6LzdpRPQw5UEiyYLfq+gNCYUUmtuXvFxHYjnYpTXXlI=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:bu5PcDPnz0TRVNVxZgu5SL4dzMMqPxK4gNc7zSt38Jw=" + }, + "target": "9255858786337818395603165512831024101510453493377417362192396248796027", + "randomness": "0", + "timestamp": 1719013983570, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 5, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAZNxfcOB5YKDBOvla+GNPw2DLu3Gm0ACWELT7kUEgchizubqY95Wi84gd/5GDThRPc2cJOxb2I78dnj8h08UZWoDHpOAoTbBCdrrjjVnP1GKgI9OIAa3laTQBiubuHQGL5+B5saW2+r+mS8fZ9+k8trMHhOoaGEYe9CTVrzOW2zwFYCo6CSffGx87oWy/dcnLZbTb7LpoJVoZt2J1Aaw8rhe50WiNCs+zXeKQlhR51UK2QeV89b1fL7m6tlDa9k6/57jdOab8R6TI7W3ytKnvBTDeh4IShPCV7W2FNgmfyWVl9NKobJkqKbT6I7isH8ISJMrzAzMAxhjD+VhexiZ6RD9DLxKYBZ6Npt1CHtb9n4H7qiSrk7x0E8KXWOmwayg3wtCVbdYJROxjtvD8rBsuQ19l4FHWwB6CvC6Ym9APDa6WLL24nnYJMWKGu25QM+uFccS8LneKtZd/TtyashnCkEq9O1m0G0QwklU9EtrDj3ER3kYCiyq5mcgKVEyi6Mukyg8iH+nPJfkLb+yP/31OQKmGF1GoK0zGHvBWKPT2kiprBs73Zvc0Z17o3q+JdrHUjKgZlTr7964+13ZLxpe5+KMABIiazK0to5p8z4KO/v02t07aS/eXh0lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwllbQhfxkZEA21dRZH0vXYKiLYIthVFgfMkCZHguQ6bGcJIphOvNXP6I+MPLwCTS6QVfF1gJrVOObmQYO23cTAA==" + } + ] + }, + { + "header": { + "sequence": 4, + "previousBlockHash": "1B5F9F573B52E43AD92585AF9DD1A874E8937B7122ABAC70ACE36CBA06B25331", + "noteCommitment": { + "type": "Buffer", + "data": "base64:ZUFgR526J0OKlmRQS/CAroqhfGg2G1xtWGsHuUea6hc=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:GepXK1fb8/C9smsskZsjKNoioqiTjx8C9Qz4AuIdwd4=" + }, + "target": "9228823284279306817296266184515742822248210830185427859262273659833347", + "randomness": "0", + "timestamp": 1719013984028, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 6, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAKJusIm4uyCbXLeFzOHmM24RcR6HrFoTl0GeA4jb4xXOvfFkpf7q4oxpJFQPEAu7QjlIzKUGAUM4sMGtGjmcIPKNlu5HhpiXxgNTUijiFwXWkRQ5aTM0l+lsA2N+5QCn/hutfipLICJCPAeVOME8uqZlQGRB0JtjZRuEVDXJcYQcSLf76Z+e5Kezt90MeDC4Bx8Xq7xtY+nSl9y7GmCYV3yctcYZkGPyCl0c43arBFxCQRvYKXM0VAtoifDLu53a5q54etzSu18AhPrs/3U+l9YzlvUysOv575Tvt0MEHdxl5p9AdjWNF7+DqGzhspj8A9TdCG0lX92+o9fZi4BEK73Jg11sln+bGL55rU7DLG0KQ52gbNzwBp3MIlkxb0IFYjUMmdomQnhHFX3ggdTXNTyqiT9+v9FRkdiaZXQ8Lgq3lb/J+8YK7u9GtBYlhWI1JWt9g3gwaY211NAmnfdSeE2GY7fK28h0yRaPGQHKDIcQAO1eJb7RE5x4q8siTER4Qt1MqhUNLNMAMQ2Zw5XwTuRKsxMSmKa7MmCUfICir8LxYf6fV8aRux1Ky1Ql3+Dx8cXjoYxtcoQDOjjlHnX5ppbqcjfQHqX/3K+C4TFDFNYmmKJBusrFct0lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwRXXta8pMisoYkCOUozZOpBRR7/g1hSlJ9ld8HQD0Wik58roilhIQ2RetZLgctMVp+4mNV1jCksj2cEdz60kIBA==" + } + ] + }, + { + "header": { + "sequence": 5, + "previousBlockHash": "7C790FAF96B3CBE01175DAFF6701F00A05FCC8A5895848244D2B306095FC62E2", + "noteCommitment": { + "type": "Buffer", + "data": "base64:zEuM9e2y5xNNUEEQYz3H/ojBpYY5fYUx86aqwOITUis=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:jds30z/+5CO/wYdxVkmfC8ojAAUdiIG8cg8J1bUUdFc=" + }, + "target": "9201866281654531936596795386791503876274441021197252859723586932895305", + "randomness": "0", + "timestamp": 1719013984487, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 7, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAo31EbF9w6iJEtStNy5UF5HeE3hCdr4rQs8juSHbFlVeGBStzUm9uvdQswl2VbiuEsikkAmSYpJ2lVAALfSiZXvdZiWCXTpcBUYsG8HRUzamxoLklvfsgHwSy6+jR4z268ViDl2NnxuqGWNlbcSQWqzCPmm7UNCWn5ocDeGAW0wQYJGKt337ygAdkUxHPXgRszAOAYVARhSXcWr4shiik+ccDHJkvQbUy0sIuRySQmSWs8/hBbekusUCQmriSJSds2d/juoZ8uZpF4EbcX4Xhm6KpmRJE6AdwgHKg/WRhneTTMIcY6Ms1dDETHS5f4HES2q68waF5shIiSdkM6DR+W+q/NnS4FhKok0fQs1/ckKz5BpbQLh3TgkchA92IHd4eAyjr+8Rcw8XmuPZP9UBMIznhjPwgHOVre3QXdud1Vgl0b5vP+YFOxQa9SlyYR6FT0H3BxR4rYR3U0ELCG2F0CrREqMJR1vRvrjgoS8yIxWZlxeCnFI8QsyGQnZKgtqq8WpeJ2FaV/Pz2/XugVsGrp8Gv+QFSCuhLIHYC+p42Rau9POk+7V37oEljyK6ORGA6DvyuyqyD2rhu9gl28vuo/e/Wkge1UVDsVpWPck02op1jPQF+zCn7mklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwXusFrGBzhSSnLHx/FMWedk17JjjT+ZH9tbyXQqW9bSKYuQwkJyJg9z8VH5iwPw0D1PfyMK1LsdvKYqO8RZM2DA==" + } + ] + }, + { + "header": { + "sequence": 6, + "previousBlockHash": "C673C584B178FC9B3A7BDE769B4EEF7A51EA9D929C1ED2EA5A4B44249DEC9648", + "noteCommitment": { + "type": "Buffer", + "data": "base64:vt5teZZqKbnfAHGKZbeOyhQQehfMlh/aufipw5zLYmg=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:E4KPQTuECSzAvG4GUVp8+1Q8r2WAnS7Xq7inHoS2RZ4=" + }, + "target": "9174987784651351638043000274530578397566067964335270621952759689537226", + "randomness": "0", + "timestamp": 1719013984938, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 8, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAKpkPS4Hj9c9ixRHHxEjRXdXiV7A+hx1XUOSmK8cJFiuoO4nrqdvev+AVFvpcR4pjQOhgQ0IYvsFfha1XjblrmYOYuCM/Wweyjr/n0TyWQPSHurdlFtvYemF/kATVwwheRxAsDfUN73CI4A28dGvxdiEk0um4acmweQiXPoN1Va4ZiEIYn3a+58vNNlI521SNiJVGj3WEnNIb2pTu7ok8sqQFgICIWyvqmoWI2e6Hl5qpl935x5CZ3JPoyPNvfn22Lt42yqWMm4OZshGr60hyJmaS2pRvO1J+aEfyWelKreeoyATKi+mYtHMibVHWI5YtjMm1hQVI12xflZr5XoIJ8xx9y9QRdfSLRnETJ/w7ulQUshB0JeQQ+SvZK+x4dFcXgksWXlw6convFzyLzefr1zDCF7jcozFRI4WZd/hxKYQiuliHl6cM/Ds03nxkRcHZKcsSmhs2p0Bczx7tA2CvQtivwjzAYTH6ZJMSmuwYikDGStmWwYDFOlr62Mv+ldtno/4sPYbfpeOuiXQ7DD/mW/kxEqmxvEz9OnZJ54/3VjVJsc62oufIuZlZnRCk9qfx046wMPERKnzQNlKSsyy+nOajFwqAIvXTn+nBCsank84d0Z79tlVViElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwZopsGf7sdqk8u/NJ9MPZ7YFqPPXX9jlaDJw5qtltuW9m74JVkY4do391FYpEnLVUutxvAX76GnU2fOe86/i9Cw==" + } + ] + }, + { + "header": { + "sequence": 7, + "previousBlockHash": "952A76040CB63CFF045161F69659B67A637045CE326B9126783AE9420A126B84", + "noteCommitment": { + "type": "Buffer", + "data": "base64:XowEcJ2nvlme3vb9TCWJOp2hG5JgYmzeZcMtX7xttSw=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:U15nmA2QKt/vY0DpOmNu62eilnZgJ7afFAg/iZoPMfc=" + }, + "target": "9148187795366513087508709149025146424715856256637674150531751753357577", + "randomness": "0", + "timestamp": 1719013985385, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 9, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAVaAhcF+a4ploA1H9QP92QhV4lCYh5PrmxunwZHE9ooKLpaY6axzOBPyVdeLg5BT3jbr0cOzHnoqHefoaPo0IkhPmhJZzQIbM164/Ndthqb6ZZTewyWeOu/LWIqY/d3E6iE0htcn2goPo890hX1tZzBFiDTv9AJ9/tPNCfu3CVgEAgjzafD2J+QCSqhqG0LpknJe7iwuEuwY2DlN/MnDJH9JLjMhl1/3BIlFvH9YYpNayEdNHeQ5+bRaEt+3xliDVDlLj6qSwnkai1hyN7NjFZQCgW9PALi+WldskVESIROFQXKxTZoiC3Lg2mv/c1/c0JxZO2s3fsBKC5EgIVOXMJpQB5ZSmenngk1atop7hWaPW5h4ENmlD8YtQevoridU8dMimhPfxr85uCoGhaHqxAtDPCh2rUMUgMIU/1o0Cokz1W8v0m0wb94pK3DZyW01qbSiX/wpaE5O+mi3t2VH789JvRXVDfMNPp45C5VMgnyKvTdwG1koaGzUqu8qRd8Db9b372iHXBaNHJTO7BXZr9jhoY+ZMVSFKQ6FAUAu2GHARBNqiTPSghk8cD+CcUFVVFnGUsEIMLA76i2G6Hw736DPs/Od32tk6tLLy3L/ZIp3I8htZtzZqOklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwmjrNuynol5WyiDDUhbMWOzJ6t5Ege0Rv6RTMllKRQiqENrQkAEcrRb9LF+CgR6IlngJ8OTnNZxkSTZZD/90DAA==" + } + ] + }, + { + "header": { + "sequence": 8, + "previousBlockHash": "B3DEDD5D8C85C37BCCFDF449114E6DE67397003A405BBFEB50BD2BD21E8B4B27", + "noteCommitment": { + "type": "Buffer", + "data": "base64:zSBTZjhUjSW2wQS7w/yFg3BuUj8igHc8REsCXYCRgU0=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:mkiBdnLtYJN2lug0zNW245DPmmAFKExG53giOOEQYmU=" + }, + "target": "9121466311864876128923245652724724632104869735746188813030060672759072", + "randomness": "0", + "timestamp": 1719013985850, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 10, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAe/iqmEOwcKZ1RHevgjbadRohwDQqN77ozsyQeFJot6aKqrIQqvh1iGQpkNYExElCm+TjedkNHGyKhV1FuBRrnZanfh6dTT+NpR9NyA5Cw8uFUsCVqyndQi7b2Z+aRcqDZaCKofLSWnW7Ip0IfTaZgp78v2HtznDB0kFpt1QWe0cCJfLnzvBDY1EEi6/JEKgRHTVw+GLA4n0AnC2pUq25LlCrTw8OZCjyH9jV+7tfFWqsQuakW5YxRh8xmfwc8X/db92kxlV1+APBd2k5NnNoEx6qmhZeCRVBV/fvyGOUKQDjJXTeZuLrZoYiBDdn4QUq0oP3wZq4P3vhwf5xQNRQidtWCCEZDkunygFu5qBd/9L6LEw6XJA3giPElz2oj+ZzGv2N1a7WLJaElLZ4SHuseHTYPJmC/znlf0EJXIUAr1ZqaRnSIx3NTWaqlelaMnJKb3QsO91txLPEKlY84pEjTqBL/OUiRvqJiAHhy9k3OuSo+0CpVlIILYSCod72ddgL1cKwTQo/Emr++UBp3l9CoR0lOym4QqOwZxUdESOBVfvYjvkpSsIVwCQ+cRmTZ80N3CSqDczEq6L/h72yMRkNdnDzz4kAwsOscJg4MRKRh5R4YXx2zEY57klyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw+BhqUywJBzVApbpJNc+CNoUVtT1tJKDOaoFHdPYAHlHOCWpUcfYWeXY1Yc3Q9D13o33FsXhMLKBMRXZsovB8Bg==" + } + ] + }, + { + "header": { + "sequence": 9, + "previousBlockHash": "6832C7361633BF97D10F3FFAA6BD1C8634BB33274C5B89938B487A1433E19863", + "noteCommitment": { + "type": "Buffer", + "data": "base64:XgO5QrXMKhjdE2HvXo4aFzLmlB3S8jZ45l9ok890mC8=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:XpOB9/4QyyJp5Z2xm9HEvBdd2z9tdEsWm/iBS6dUL8M=" + }, + "target": "9094823328238119324660168503613036415495463326164889575918026009508991", + "randomness": "0", + "timestamp": 1719013986328, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 11, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAnYD2TvWi5cr0GeFdDSkpF1ySC28asDLBqJQNURctoDSHd7eaNiMSAk8VMyonnGnc3gv9/VZP60Uz9LPrGwrg2tOJgbXF5lVy02IFwnhccAmsCChQ46AiZAwSu2BQ/BUgs8zptmZmv0VByJfT6Lnmq5J03GUlbBYpzUTwR65Zo3EITPHA4nH7mvZXcCskqMx3WR5L4U173iYz/bfFeEw3h322NyvqFqp0Du3otzILyY6CD+X52ZRsUSBHKoaF+F8/fmgBwPR0IE7EduabjqlC6Mdm+2Cmmih+QopyHIsry32Ey+QjGQyyWz9M2zWrL85GzWxRQRLzjWZDjtqM9IWZHp8o3R/FU0SXJS90XrXedgMFAk4L6Ixu413Sskk3FoYfG52pBmJqbVVxREt8p5dMFQEjr2/qW6fkZmaqHQYuoJ/vPmMItlXtJSSNDkjNnxeGZa9ok2CzSZ4M+RYIBhPRWQk+NFo8AjDZyYyAIjlC72QujwPSC4++dmDXZF/1PwG9eCctK/nqdeLZINXxE9rDTKv4CgZHwe2Zkqr6+2omPgtzuVnJWlBJybJC/WjyxbR8n2/QHlpTU7j5qvEE96ZvXqUokjvCLmofV6qW5nlAw90vYS3hJQga4Ulyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwLFsK5tlrIkpat7cVN46dfaL70TluCu639PCk5yYotx/LRPD1kZOfRd4Gz+VU/bHEbmwL/Jq6BEWaOIkGkSGsCQ==" + } + ] + }, + { + "header": { + "sequence": 10, + "previousBlockHash": "58A0523684A584E001C874EFADC62F1E460EDF2697B8D9F511E18642E5F725D4", + "noteCommitment": { + "type": "Buffer", + "data": "base64:i4N5y96CuXjhqSFostekgl7/bhDtPAJFZ6HmO1++yys=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:bWKBnZxozSWU/k9Z4+Smbev7L8FCAoceXwrF/MRbeNY=" + }, + "target": "9068258834662928698220540790897658244352076778286486653826470223999191", + "randomness": "0", + "timestamp": 1719013986791, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 12, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAxBnmx8YmVy4Uba/bf0FZsUaXaevReHvPPTwzEcnAEUKvNBqOJTopDOa3ge/F8fij6EGE7yoFexmwpFirko1WH2NHgCSPGO8PrLwcg35BNe+WyBCvo8wdJrGgGOFfvEsRl/iTGYlqXEFeUpj4j1suW2zEFb/umx0UHBSDdkHtaGIZyTC+G17B5hnAbfBtNpG+Wkww23OB8LEZjdCN8ALT/sKBnJDI7Q6iInf0qH0aQh2wngF8LgL7b5DziBnE9l7sVclXo+SQQxixNn+P4CUS98SYVM/HFaUT6CPpsJeJu/j/pqT6ekkbDhdmss934GvP94wQLa0eVHxlwAl6pkrxiXBbtR5G98Sr4z9rXX9c3eIl0CoBN8Icoovbziuj9whuwvhyGbl2Vgb5v/3JCSO2xuglGtiRGdqstZlJnafN410nX8dmOtDZ4uKYbX+91ElnO2H/zQk4BnHCIuKYWO0pnlw0qrQID7s46ajoubh246fTaRrN/1ZUhdCzWEnkMmFy5tqjG7NbzEiJrK2S12ap5WsSi+QaHxCILZnmRIR1UP2lv/iAB2dtS0N/t2aMV6Vx3V2WF8VzLknEeve6jkYaOONf8Vq8d/yHjGKZbqBrRThD3hsMGTH5eklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwVlgb3VAxYA4/quGjTO2DnRUhwBax0oH45Alvd5CHvUUKdFvrCkSP4PoUr0ARmkKwZ87ZCdwDRDmmdp0hVL8WDA==" + } + ] + }, + { + "header": { + "sequence": 11, + "previousBlockHash": "EE1E11960354D5C94848038886BE22CBF0660BACD52A44E69A8C94ECAD783D61", + "noteCommitment": { + "type": "Buffer", + "data": "base64:DqLRDXMZ92KgoBoHoEEvBul0Qa9NKA1GIxOCZuwWqnM=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:PRosVo1ZTB77kalVWa9c15z/6GsYCKd97N4IJU2sXPQ=" + }, + "target": "9041772817458669358631436925553476123971485443441062513642264290171806", + "randomness": "0", + "timestamp": 1719013987272, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 13, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAA8v2KH1eaCGWjnmjsTf8l4CS4qrP7QtikWedpfGFIjZeTY0pFCd4LUpChinhP9zHbbIvKxHf4EFZfra1pG6lWj0ChaoJnExsHC6OwUH3v2yO58kxa4muyzv0+RvUM2+ufyLHNWRcD5DIoBSTaORxGR39LiFO/3d8V776E2EhxbScJXyBY7kN+RP57eoCvfiBVaB0F92NZS/oQAdwJGqJBQpfMOQkXycx1jnd5aB5hsByJ3Pe61FucFx7hE26aLknQSqGhozj9Wlb573FIcJZ5qV1s9JcIZCnoVMw1YZOTnGndFvgPcBbXCkeQ61DMnrRf2/OpjLluEdzKB+z9L/q7WfPYAR5oIHUYKEOGHIPPBlc5WIu9Uvhm6W18XqWjmdkgETEmCjnvzYviapfgW1/eQRqIc9llgIMvgFPQG9hueZMyoZdaZVKlUgsOWfgxNbfGKdXbNTqPQdd0w7nV1ddPwqn0ct+eEtbTnF9JuoQNTQGys7SvUx3B6FiN6GPXCk3TuqIAk1WqY31A8ZAGXgw2IjYVWVaxfbVbsSvoox0OhnqwIKKv9ARshpF8jOk98MaGbARGRDu1G08d/38CoLblGp0rc0xUt0GpMOamD2bVWYvCvNlnAXiU6klyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwoaqz/TkttWazh30GCjZi05aD0ExFz97kO6rq+RU6+ZnULmanCEfTiIk5yX+RaXVX1FCz6ygL/iCCkJFzaeE5Ag==" + } + ] + }, + { + "header": { + "sequence": 12, + "previousBlockHash": "CB4DB234446AEFBEBC3111BF2861682D233AEBB9899A0776D1B230CDDB7AAD50", + "noteCommitment": { + "type": "Buffer", + "data": "base64:MXyx0nQL1BKvC52C7mi+es1dDeReLAAp0hidjFU0ayw=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:lbUUxQRyI685D5d8NCxSs77BBV288Vls/6szjg4lwqo=" + }, + "target": "9015361047625083866771187507615534750461425295595622380322060663659456", + "randomness": "0", + "timestamp": 1719013987740, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 14, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAPrfs2jjx/bvllkzfBQxXgFv6RZv8Fa7mN2koSRMrgTCZq8oXgOrPCvT8NpuIfZ5lM+Ui4HqR00HWa84Z/BleqS0Q5jdT+vIw5ne5lNqUc4SXSkh8u+kXnXtEm2werA1xGlz6Mg31m1T/0id3DK1PhqVLMyyt1/QLtEpLxAzoOCEY8LswOKvdlBePclwVuHm9miQqDTrFRumOXVjvz75eJPQIF2WNugKXcPqhtHHKeuKByHPrtnWoVDYbP9qlS2PHJF7skRWTxkh0nwiVjZXLVlPHe3vrs3npIF7IMXb6UkAxLKcEoLjSf8gWAuJ9kz80sC9456UlL8LddQlafDhqoVO8SD2v22iUqhStGUOqqfuav9jYpPTJtKTsxyMbvyEe8gJJtoJeDyJZl5PWW4IKuUfU0JQuJqw0/WW5VzWPeRSsBv5uVOasQGX43r99wkX55APEa+uu13jXJFrNoRVMguMssjzLuS0rNthoFM7yaLJ7O43ruRCJ3fFehJ98bCUb/fnRG8YjMTac0mNt1oUYqyENk+u+qFOYqrzRAYZI5zip4cYa6gWYd2tFrs4Xhk/ZK72cnTp9ygyyeHPtKxPw8NezsIkcrOtsGIBTY6OVR9X0rF/ThNr+9klyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwLGUCF/Z+XiDH2AgVuK+HpcZsvlpJ31H6ecDPjnNG90ECqN30w/xRMC/p4chq0bM1ZCq+zKySY0ns4HQV4jt2Bg==" + } + ] + }, + { + "header": { + "sequence": 13, + "previousBlockHash": "985678547DEFBDB3E3875327CA873EE69A3616E9DEEA2893F4E617A0469FFD4C", + "noteCommitment": { + "type": "Buffer", + "data": "base64:4+CqnqYonOwdj1ImVbCCN1MzdSbtT3rpmmuqhMkPzjA=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:t9Dh0IBHhXIjkc8pS9gbvggzcy1tplXV0UsKJsjSvfE=" + }, + "target": "8989027764587843972078000359639078132662736945816568766992021111212360", + "randomness": "0", + "timestamp": 1719013988207, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 15, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAm/YVZ+H4eL6lQXt1cRWkNAAJ97Xo8fX55KT0+/Z0JJuR6MMRsvCgk1P0L7DfVCbHlFqSHyeylSXnVgyc/3YGlkM1lxohBzHA833kIWzeVHq4K0KYoTmHsD1zLaMY4qlc1BZSwSgXJwzwmijlM0+aHCSXwfIaIzQMvKYwB9KFPcgERtWjSaAzFm/2xLyGB0k97EeGjgCj4GVXIHeNTL48eMJbKkqQdNFdZWfh8ZxoVeqzcB5et7A07p0HUPuJcXfqqqW5/HhucZp7++27dKT2V+UHriHNSf9jkkpBEGs6r2gMkSFw9RSoF/NM7hRCEsPBceUOcmxGDwia9oMVXK6IS5RhomnxrmJf+doryU0xsKXq3Y76pQTMSawwT9LzoG9LMKJSZPPfx8fzXUYQDLwFHUFljA0dxoFXyxWFk4M5WjK5hDFcjVRzqKnJEPnEGBpxuiVNwdWcq5kuUCf3A21L/SD3nzbqLIK6aNi0RaZNV4rVHk7CIIzNYtho4OcgPtjA3dE4ltM0RUfhNC+AHIRGQbjgFHlV/kKc5AGEf1c+I804dP/L2EjLOPUq9J7eM4DWt2GhhfDRIH6EBdM3Z2bgT/nB0oGKuVHCSXM6dxV7jsfZZ1nrvQlC/Elyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw84uTMTAkYg86x/oEy8JUbwEE+zFrZUJ6PutlyD78PLEdNlgTbfLTyilb/z/pseY5W4Te5EJPPHwaj6ezR1agBg==" + } + ] + } + ] +} \ No newline at end of file diff --git a/ironfish/src/wallet/scanner/__fixtures__/walletScanner.test.ts.fixture b/ironfish/src/wallet/scanner/__fixtures__/walletScanner.test.ts.fixture new file mode 100644 index 0000000000..e4e86e3d9a --- /dev/null +++ b/ironfish/src/wallet/scanner/__fixtures__/walletScanner.test.ts.fixture @@ -0,0 +1,1764 @@ +{ + "WalletScanner adds transactions to the wallet db with decrypted notes": [ + { + "value": { + "version": 4, + "id": "d1cf4a73-26ba-463e-84dd-db70931caaef", + "name": "a", + "spendingKey": "dec96500a1803c548afc31244b1c3c2af1dd2e656a6f5cce4eae23b40b8f245a", + "viewKey": "c2b12faf677f79b93f770adb4ffc7c2e3cba20a277645a676a58724782ffe861d1d88fcd45ed80e5e16a1320ff875250eb0f614a34d368db9b7f2b59efa5f93b", + "incomingViewKey": "d2d98c9c0cfb2051ea4dea5948bdfa35a18db6b244706a48fec8fd9c0eab4e05", + "outgoingViewKey": "ebc96689717ae1fb810465e5b827b03c849b4e17c9caa336190159db3c212b05", + "publicAddress": "cf2deda03dfb466f832c25aee99f6aae5e65d87ccf89120c2168eb9a15e39000", + "createdAt": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + }, + "scanningEnabled": true, + "proofAuthorizingKey": "d8e8073254aae15fe24704d590fa37ca0c396026ef5bdb2c6012bf044d5d5408" + }, + "head": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + } + }, + { + "header": { + "sequence": 2, + "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", + "noteCommitment": { + "type": "Buffer", + "data": "base64:itEBRkuh+NpQRbD6hs9/4O9Vv7mfl2/pQ8ntJJLn7Qw=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:il3l3FuDvwOhXk7L4snmAUPdAMnJZYQ6UotnfP178Fc=" + }, + "target": "9282972777491357380673661573939192202192629606981189395159182914949423", + "randomness": "0", + "timestamp": 1719441703087, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 4, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAWnEuHSSveUq4ZoQoRPTTrnZ/6EFMa5OBfv9Fzk2gsDaRTm15GIdSlbIVvScNfI5gCG/SelzULkElM04+cnrE1j594IpBErw7xWf2mxkNOsKZ48P0tYyyTEPlXp98g/C9EAY/4pPIEC+eOuCzboW6SvPJMzecOgYBuDhpMhaG//oRDuNHvYug7JoFbJH6wObIWhJM6oixok3tsFKlT8Qs1CJd9ZBrtfKwZ6TpEC/0gbGY5Dmy1nmgVG03ge/WzGTRPuYrPHVbxR2qD9PXwrJhKrs9x6aGbwG9uAPKounEJ5wxuEhw5MTscaUknt38YpdhcKLgcAniLt3Jw/QWeKeiCvkOTLSBNf/dSDw79YFEvFKfzi6dRV7v+myr+M297MIRzmcUX11BzPP/2IHji37MC3OWJf7Xrj7qu2OS1qU9+MnPOdKRIb+YCrrTu22xR0ya3dpryD0/5IuHYDFTQAMYqBXDGBK2ZHhsz8TV29T9Li2ggPKSqIN5M3zD3wG5Sw4JLtl2/g4ulpCpskMwGGd+ft2Q0bMTC5rko60WNf34aSJHCSl415N6yJK4vJFQK2e+qGsbrcLTb8UGgIaWIOssGAyH0z89DMthYiP8O80uoq6nvoS8rpLhiUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwYRGel8eDPjscFom3Ss+KyCvF2mZ6ITTaAE3CaNd/pQsH7kbKfzN3/4PetOD614d/IyZar3jqwioeDgp2o97VCQ==" + } + ] + }, + { + "header": { + "sequence": 3, + "previousBlockHash": "BD771382B6F51DBAD16BBF20828E397304360B8F4C41EA4AAE4F899DCA091348", + "noteCommitment": { + "type": "Buffer", + "data": "base64:GI9hJ67TDZtvgeaDQWMz5v8BU3x4KLOebmx6LX3IDBk=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:apcufvG/5MYo2BuJxXgf/0XKvpyWF1PUUVfMbOT7kB4=" + }, + "target": "9255858786337818395603165512831024101510453493377417362192396248796027", + "randomness": "0", + "timestamp": 1719441703553, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 5, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAev/XVrZBMN/+tj4cnb5nDkkOKHeMS1Oo/udw+KFj8MSjevA2febVCbQWbtdVF622fZilPU6egNmyuBKSRHrqFCjB5dDFINgwyBP5NBqmsYeIrfnb/2K4YkHN6aWl7D+PH/p1n2DsVyyX6LyQtinl7inmIXtUu5G5zHKTJ/3aljoMSaXrtUuvyeZhXiT2vNEZ/aju1zsFZU5WFryRBrPoxdE23WjhNUfz4xHwxPdLBfivYp1O2jdNUlG6INpxNWxxy+s2pH3ct7Eby6eBHrEzDR7npfVjQnpWdMFbFnTQ29aGAxg4fsGM+H6QdCvvUg1QkUwnPfNC2UwnCg8QlhX3y0b/PdkiF/0hDetDv2bMlBWU9fwnfzftnUlX76pA6UFbJp6IdKhRM8Yu+Pbs5JkdO1lXDusx4Czv1kzhWqS9psGjHMboT/pCtLhZaeMmBI1LTaHSgpfq/PhcdQ7I2wzLmnztZQz1eRbf2uKmycLqiWUt0zvqt8ODu74BWzMVD21Yj3BM9CthY32ikWAUzUnI+AAIf1+eeUD/rxcI583dl5cmGhN/fYP2OlwF1rZBk7soFrOT5bvma+w3+RoqhjzJP6lT5UHwrY9vRSd3BipYWvytSdUVcI+X2Ulyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwK+0oMAXwcI6ruO8mM0tz6ivDuImpFkTRswicw6hYfgtKM1uycguZow8m4QYbnrU1xyRBWrqAbeHelR9cJfedBQ==" + } + ] + }, + { + "header": { + "sequence": 4, + "previousBlockHash": "C3C3D2CA169A13FEDEECC66178A2A186F405B60CC5B7E66C795464614A752CAF", + "noteCommitment": { + "type": "Buffer", + "data": "base64:zWgjVHbnPw8JQmC9NL5vMtrb9ReTUjqCBvHUS9DBFEU=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:X8E0ZOL8NQZcDOubQBJRvGi7wg4cdEQllw7D1Yivv0I=" + }, + "target": "9228823284279306817296266184515742822248210830185427859262273659833347", + "randomness": "0", + "timestamp": 1719441704027, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 6, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAd/4AdJJdsAtp5NFcJ31d5YC26X8zbPWS3V3AFRedjoyG6S0abi+QVAEL9+R7+dgh3rIVUjfLS93XTdRNZI8HS4fHoCcMs3qy/1DGARr6enW0nSZk/AwN8Hdjs68ykYfzTuxQDMJrlhWn6h/XctyymTjlqIHGA6kuRP7X2lB04F0EPOei4YZGCsry42zXXQUmwxJIPEdZk1DCYmoaVxKKv+0ww1L7Hj7Xs5o69Qt95h2gogpZKKaepMbteFB1Rn3Kfz0xSpkx79A61Q6BrtEDfRbEF/Dp9EDzMyrNPfM4nLiW/MnMLReIiOU8JcnkxcGrQPu4r1mfW3ptu1mVA7CIQxHimKAmHmdt2Y9khCpJQKpyKQ46JqIwD/bxCqcfJ7odhYPzBMrNc8AerIs08aN9odE9A+KTskRo0jchZJuEaaf+2NvgRRA9w2qYQ709d5jhf+gIlWxFghhonu4kKvF8qJcZeyQY4wvzhufeYL46bx7w8L/0FdZDLfXY/POIgm6/3//GSAmx5k16Rgsi3BrkT7wv+BaChtxRuKV3sji86HxlpQOW88Dlid+g5dRj2wsJyfH8QjkbcoIrq4VIMqfX7RqtlRFTsVoBCQx4jOhN0R62umnKztgN2Ulyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwWkIKQufSaYEC5DGaLxzHP5Kx7SDL66mZgY9ZyJnhQ1mhH+V1bMV/aoBrG9mVSkmG/sy8vlXN4WU6jk7Eb7qgDA==" + } + ] + } + ], + "WalletScanner updates the account head hash": [ + { + "value": { + "version": 4, + "id": "4845feb1-b76b-4675-a4a0-0386104197b3", + "name": "a", + "spendingKey": "8864a332b9ffe6ac4f9ebcb5756086285e3799f30a432cdd7ffb9d1a6d39b000", + "viewKey": "09d115a480a1d2b1b8a149a68542a7ed251d573af7c807b17e98bb529892d8b1e74605cacb2e2473a9f83ec96d8acd3e435254dd63b6b50bf4cb1f67febc8980", + "incomingViewKey": "958e5c34a309ccd6faad896122a1ea549803d423e78c002a3fcba6cc7db95704", + "outgoingViewKey": "cb7ad68454680fc415010dbb0cea2e18dac420cc34566fda8047bfb4e5d74ba9", + "publicAddress": "012d22c53dd3aa7cc986bd8755f8a7af024c3154bc170c8a588d4dbd55bcc416", + "createdAt": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + }, + "scanningEnabled": true, + "proofAuthorizingKey": "faa1fc9d7137e3cb50ecd6e02dadfd30af82a1ec5c2ea9a8e482fc20ed60ae08" + }, + "head": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + } + }, + { + "header": { + "sequence": 2, + "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", + "noteCommitment": { + "type": "Buffer", + "data": "base64:0yP53NgcgapmcTlawnhFEADpOt3D8bPEZTqA2OopGSE=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:4xqaNuh/b3OqHXC5adH+PM9V9G7195kNile9LCOumDc=" + }, + "target": "9282972777491357380673661573939192202192629606981189395159182914949423", + "randomness": "0", + "timestamp": 1719441704807, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 4, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAADkyAZx9VeNdAbJwLTnTKAe8+xo/bb7LVT/oTP/wHjQyGaAdsW7NUXP+Wy+l6oRrvR38y+gqpM4ArMNb5bqAHtUyI66srXud4dvDQL8wEkD65l5HzkTr6ez8bD9EKpvQXluSPu31cn6JsmYVPxzfdi8JAXsAohW2jehBOx2bqMKsHpcp9mDatVtBs7hwtJ9nD1mCOfk+bLJqs+kxscHxtJj+4SsQ37KoV2Wk6O7XL+5CV97iBFhfUtrh/M6GJjSvvdjyaoM/FBPe6/8DmFV+d0iToMW6H3UiJda6CoJ8kKJpYi7Y0lz4v/M0tFI3EiMPrDADlwOGpJYZ0S20TFDemROedpEs7IOkjfHhw+CL4DurUfT31gW8fBXklb6VdbaspTAu/jwoUUXCmQ29l55PHrJz05RJJuEOe61hdbPabisWisiUIk6eeR0ijQCWzUTOFMK0ml+fqdPQlS/Dd1/MlUOpp0ApM5zyrSbHw1EHihWmQu5k/NjScIemsKPYItfqHCCiIlwvE/sCYEB9J4UF385h0Cue1iHIW6hBrSUMREKuTcVB2crFrAaZc6Drx4/foy8b74IjnYFolJnj/5BWj0b+5ty2NG67fUroo3+P5E/sySN2oekhOoElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw8K31x/ZrfevKhpGEccgYy+TZ5zIc2kodOYlG+rY/DEZdgfxlxpUL0dbUine/x0KBZDnqPBOqxadikP+veqDCAQ==" + } + ] + }, + { + "header": { + "sequence": 3, + "previousBlockHash": "84E024B89F913F167200B32F0C043FEAC806E0FE96B2B2CC0D49FF9D6ED413F6", + "noteCommitment": { + "type": "Buffer", + "data": "base64:eGT2PrD9wxP0pCoqeqOdHuCEOmoCa8Pp+c6NLtxdmzo=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:RDvoWjRIxsSVM5ctsU417Zwa6H3H9HicqiHES5dGZI8=" + }, + "target": "9255858786337818395603165512831024101510453493377417362192396248796027", + "randomness": "0", + "timestamp": 1719441705285, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 5, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAALOJRFX+2wNDH/UBKelg3Vvh5g5AfkdivpDMA7lMhty+UBHCJXFrlkQRKV/kNlakvAklq6iYHZYplbLlvvAbLvjG23E675POU+CeZR92crOmvaEMUV+SDo+U8fuJzyg0zkwaTi/oUBWs6A7q+5tYOib/mgKHekf3/3MjixeMCGpwOUHeBjJIiNmtGXBQHlSJhLWb3VJ+UvdRNcQAEGDpB2iWfqkgv3HRSehYlhxtvNBGGM4m/y4z05O55DbIBua+fZKWvn7ONZwJix0xyGt2ZWYT4t974cGFmvK2qgwMGf66A1b8D4g0Wlsox/7k2ZeYwLegvXVDoY3aff2pPvKVfuvCGCqSEcgX5mmGpLHSL5SDPrD/Rgv0HYJiPe4sShiEkYjjiynfHdyqz0wII1m2OQt1OZC8Q//smh/Wi9uuEmo9Ukd9Qd2+X4sEB2Pa5H/QCVlXh1N1muRXpH8feELQKYw0UyL0MK8XpeulcFHa9QLUoLS0tVuiJ02of2dqPpYQsoS+EV/Csj1YGqxO+JfjondVhNhwoLyl+4dinOpb+7SIc5dgHaCVFll6MQpH+mkc0figt7Bn8MOXPCq75BwhGvcJsVHNQeDDr3Rhg1lm/yDOcg6h0gHXLoElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwZ+aYeJt37LklpZxHcMExSuceAui6llbkPXNt5Nva+PAka8Q6LPw98mcjbodVcxjgmri3iFAKfa3cWehZoNzkAA==" + } + ] + }, + { + "header": { + "sequence": 4, + "previousBlockHash": "92C047025D6E0D505BB553F35E15A608FAAC31A096EA5B1B80310CD04FC1AAB6", + "noteCommitment": { + "type": "Buffer", + "data": "base64:4vrfGlMPz/rVKYTJk9cR5DiFvvltdENwkp3iBQWASyo=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:yuz27wPlERZ9zvnUtE9m+9aJGfzQaueZdRXrAjFpd2w=" + }, + "target": "9228823284279306817296266184515742822248210830185427859262273659833347", + "randomness": "0", + "timestamp": 1719441705753, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 6, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAVV72G2AbMfeY4iqe9DUR3dNwVBULTM8anEaHxKuOmWKHz0JYmYQ+7Dvg3eyhLvqNzM3WWPCLVmr7EaCoEU1Hb5r97OJzHx46HW+JUGKB1uOWg0Y8IXU8YFZfQTkO4HRMqS9Ga/rTUYOjUKWYNaz98f9fK/cdd7Zt2A+cgxXj35AA0ij4aP3c+CSOCtNGMlXRpwckTO4kWXij4eelqzO957265yJlk5w3IkNwsakjNmioVHFoSnADKvLNmdP9T4OOGkP3FBzGIwsLAXstXm0CdZE6QcJA2r1nfrysym6fi0l84vRCgCKr3UrAsdgjsyB8L7RNY28qM6rGdBe68JWFWR7qGh/aJ82u2e6+OXb7QAgq1O1FtzGvP7PpT0r0+p9tQP30ZC1oRTAxVokTBKL4Zi+sRkIFmC6nhuDoKrhaBGLqlK7TsMdcQ8eSpGrn53HZmBdXPpt/xnrrNwC3YoHPAR4f1RQ1J56aYvJi/75omAs0ePBdaafeXK+MU2rX12Yj4KOARd1RT49zdcm5XUoS+Y3XLXoYEYDfsKhK6Z5RFZfkpo51su7LYAu1N3pJhxpDdpsZ0T1wtK1qQEPr+TonfTKBhFs4iakIftqgR7KraXRTMPCTevaGb0lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwZzTk55BdcsixSDHZtS9Ucqx38nIr4P+IUUNk5b5y2rLmh3yM1GCuspaNQb5nKQGa8FoTjLa4/w70QmDO3LjRCA==" + } + ] + } + ], + "WalletScanner ignores accounts that have scanning disabled": [ + { + "value": { + "version": 4, + "id": "065b1469-8875-4ee1-bbe7-6d36561d8de1", + "name": "a", + "spendingKey": "fd0a9e9f4d537a70c486eb2da068df45f231b6aeab564cdcdddc4064fd4eb9dc", + "viewKey": "25fb041e50363538fa6f9657e7c8224ff63a1954c55f61c130d1b1157dabc0adad00669610f7247e238f22f0dc359d4844932fbc86d99057d4e82f66534de65f", + "incomingViewKey": "b53fe8b6b6d13b89bf030ef7764855ca4bf8d9f24e1033e942c2038ca1d9d807", + "outgoingViewKey": "210eed54a39f09e7c97ed4114d69d1ee265d0c724da681451dd461ce353d895c", + "publicAddress": "9fced945add6d7beeca3bfc0bc951f3cb758463a3845487b96f2187c086b40c4", + "createdAt": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + }, + "scanningEnabled": true, + "proofAuthorizingKey": "5ef2b62c3676bdf5da4d6915f0fbca870a1852c605521caff0399e0b9b1e4005" + }, + "head": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + } + }, + { + "value": { + "version": 4, + "id": "c986f231-7f91-452f-a91a-2cf792fb8b5f", + "name": "b", + "spendingKey": "506cc73cf1bef79d4d4d367b47e84c3a13d238cc61dcc558579ccfe453a504b9", + "viewKey": "c1a3951064fba9f691d3273c47c5be0d45fdc4143798a43b918f613e87dd0a0224001643acfa030d51ff991eb925563045444e8183869f1282663ce5adceb384", + "incomingViewKey": "0ce9869ce32bb9b8363ca02519cb37b7121a987005fd3ebc7ad4bb803fc49c02", + "outgoingViewKey": "ae150ab59040f0ac65c451cd68122b37e75aba445673d1dd5fe0d4f77b4f4386", + "publicAddress": "fdc8750b5b06467ca88a2351b01fe1c04c22374cebc4910e167532428d0f4dc6", + "createdAt": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + }, + "scanningEnabled": true, + "proofAuthorizingKey": "9dbe4ceefa60801569a907266c225bb491b1b9f7fe77c6338faab50395051300" + }, + "head": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + } + }, + { + "value": { + "version": 4, + "id": "3247103c-f0f6-44be-aab9-3caebdeeed97", + "name": "c", + "spendingKey": "0a20db55d442b982b7ec8e472d4de751253656e7a8c9d8a7c4a2bca178fd4a0d", + "viewKey": "e12f8440a0d53301d668fc283f7a8a8ecde21d3c0c61fa219416bc17e48d8535ffc49c82da7f38b40bbdf08623075f097227e9c7ce136b95bc3465501c5a395e", + "incomingViewKey": "9d17222d43f5d3810d5c8c315ec56981d62bd449949e97ff15084f683f442d00", + "outgoingViewKey": "61604829e709df68364562002bce307167489162682dd783612dedbf467b2d7f", + "publicAddress": "7657b2be336b7f421204d3f77d6ef6987987c0ff26d2eb126d16df76377b6102", + "createdAt": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + }, + "scanningEnabled": true, + "proofAuthorizingKey": "065b39b91094875391065c11b4537a87c56354a4ac5d328cc030a870dde6060a" + }, + "head": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + } + }, + { + "value": { + "version": 4, + "id": "14622193-0462-478e-a64b-1052fe31b17e", + "name": "d", + "spendingKey": "9a5484f82aeb1c23964d85390b1c4e003e4c640652d1617638454ac0cd5ea1a2", + "viewKey": "c6ee78b3c8ab7d29a5946163254036ef01ee62d6579bcbd7a4877a5910f6bec6ad767a68541e702565c185d83b79b5a34bb546dd0f2051f2833bb865e8a1fd9f", + "incomingViewKey": "9204a43c2e699d4d1c1ee89a37e8125c11de657653462a1130e76e6e34983800", + "outgoingViewKey": "ab6bf9dd3118cfd00564519429a1d4a81819bcd5a7b7f7cc82317c72ba610da4", + "publicAddress": "58d0e4790b30940363a48dc576826307f71ccbb8258d79fc47f20337269ebf50", + "createdAt": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + }, + "scanningEnabled": true, + "proofAuthorizingKey": "7909244afc59a8a93f67ed1e6dfb5a424d981aea2aaeaca2c97e25cae6403a0e" + }, + "head": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + } + }, + { + "header": { + "sequence": 2, + "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", + "noteCommitment": { + "type": "Buffer", + "data": "base64:6jaJJl61oR/k59FxFDFByNwVYS+CwucrEoluoYlFXGQ=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:6sKQ4yRZDjKOT5nvXwWg5LZniN+7sfyD0AikFfmgqxY=" + }, + "target": "9282972777491357380673661573939192202192629606981189395159182914949423", + "randomness": "0", + "timestamp": 1719441706482, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 4, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAqMbKPDNR2Yts4XeNiR3HUxI3t09nM/0J9tUHZ5hCFA6xy1hGlqQJqCnwU8ZWqhdxRQmFio+Z8zkts/vig1T1QXcot3t4tGfzlNt+yUxOORGgrCjxHDMI2dWLRlE+SJWX/OvjoA4gjmcXwXXxRPaPVXGJ20itMr7qNQtZb07GSnEMyE5OjS4CetFJyvbyBw6/eEta4ygjzFeqKcU2Iv5QoOoSE405rF/ZdUsajTjF0GKCG0jtR9wAX4dUKnjTDa0ZLh56cWQ2DZQdJ/oRuRRC1FRpi+btePyLfTnN8XjqwMULyQJybCMhGuCM9OTyhZDgohAAJbHMhe9RGQYRxPdwsx5fPwV+nLoW6KeQhgAcsGTo3bp3+Q8PtVVbVs2T4GhsjbUk5oco0ZNK5+BW8ljdEgPfXBmOb1PPv9NOeHFzRj/aK0ViaBhYC5Iuy4oGyHMXscxwVdhPdKpd5+7rGHeAXIkF+Sp7glkvhBj5yhJk1xqDZYZsLmRYbor8/n+SVMNqxO/5Px1QIOriMA5yP04KdhBvgeNEqWi6ivYRfUnwvOKTOKA693DkoRJ/A36fSk+GKDlm4X+94yUpvyGYr9XSGyW7N9AFi16wBqBWGQqMP/q78l75fojYUElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw1z+InxdLdAscu0OPEqQwCDIahWk+CCvOgRcfuc+JwuFM8ctzXOkXW/Znf/cDYKz0ONx/fDUNYnLeX/pI0P8QAQ==" + } + ] + }, + { + "header": { + "sequence": 3, + "previousBlockHash": "01FBE0D832AF2D36749432271E8E02FFEB76F377410E73C66C59BAABE4274D37", + "noteCommitment": { + "type": "Buffer", + "data": "base64:wyhr9qpeBSVCzDqyyxvbDVG1+8LQ5Q6pbIVtuHrOJFI=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:/RoQcHHeRE1iEnYSvmRc1tA90LB6kQahXFECIx2uy7c=" + }, + "target": "9255858786337818395603165512831024101510453493377417362192396248796027", + "randomness": "0", + "timestamp": 1719441706961, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 5, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAKsDfnw1z8D5WxMUkzL1jM2oa/32D+JvMnwvl7GiYA26XfVg8AC+TYl8TC1SYiGJaY74jDGrVp9szDWKTraM0CIifnJI1JLqewZipjMm/C2yJzyZiAH0cqMmCkO2uDkl3eO/jiHnO+QksXcQE2ZWlsu9/OhQlD0m2snk65d7mmNYHgOXpsASBTc9HqTyFsNdjIfmRnro9pc+5GGw95EuTiNHzoEzDQs5sbzOfVeEFo6WrL92hiXQ6Pz+nZpOtUmT3KorezFva0Nm4pa1GOipFMAc2zOWI1LNSxQuAd4r1RUN86/o8kZxugBsBUF8edT4uQyWvkj5Nm3TFOPlb+Ek/m53nDCDh4mBqZdEZfFYl0uxmQ1BViA6SfNzW2WPf9FwEikZYpTUEE9x0yRnOcF4w5L/vXyKRIUrs9mU60poJW4ZZ3kGOIofurPE9O/p9yRDfoqkoNpJKBI+Yb2EGW+KWk5JG7KNyufZ1rSWckFhFtWHd/DoFHayM/Dc5iH/z7GnZyVU8R4Cz9IAR/v8MEjSkc+M3+By9INB5pOK36jNzBg7RBvbQX2CilHw/ohT7c8Frmf6IZ2zNyMMCyAi4oXj7zsypMEvv9v+NSwehxPn8zeMB3MoSXnfzwElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwlAXuvSVA6UI2UOLCrtB8B+NXJCZuh8egx1aFSrSNtkAKHrIgXSBpZ99n2tRE1z9rphTlbxWbdATbiJpW8VrFCA==" + } + ] + }, + { + "header": { + "sequence": 4, + "previousBlockHash": "4C25AD18B5FD890D7151EF9F12CBBC5DC49B7CF79BE2A5437FE15BA660F7D11A", + "noteCommitment": { + "type": "Buffer", + "data": "base64:7Q/OPCaCRx+rkjjgRo3mirLyPr/NRnDjFKz5uIwdukg=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:QtmrusnKO2T3Ay4C2b02NKppz2dMwSnDtM+LdnwEq9c=" + }, + "target": "9228823284279306817296266184515742822248210830185427859262273659833347", + "randomness": "0", + "timestamp": 1719441707431, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 6, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAyukXH/ZnanqTAxDwpA8M112/riPdGFT5eMgYNPGrnVWG3KTVTvGkgdVi4ax6eUulFJDnd1xoq07fl2NPEk+URLBeAotFQxEt26PpVh6b/jy0k5tfE0rJIOhncgVJMwf29DFnAjMEIAvIOLPT9qVbLNQEMY6pFyiDQKt8OyKgVRgPjgBZeZaWzzA0Yir78n3iPQ4sDzYdWY26CN6pe3Rf6kHh+HuVD5Seb+FsIggpE1mBhYABy9oK6GXq4qI65NDsLwsGoVH5Qz2VUMHlNZbZL8OC7ViGtasy6EbCOneuI+7kCGyB5T0J+kxEzfRmJvdZL1yag1RSx9FxWFRPmnXggMZPpSAGYKAi9gWItsWcv/pUgMK09I0KED7q1WxckTQ4AbcOnyV5mF6AzxDnon/05TU5bLVgcEVjQtcI2V91yefkRAsjKgsv7gKZTeX/cWhv2wIYzbUSsv31ZY2n6rbnb3FxJitBuFD5Fi2KRlsiLBQ5qhOiuGG+Vs0UPmdIWDvKUIOzJzcjb0I5ZUs3xcKE87z5KpBsvqIfM3h6c+BszNHDtHoUzJ73j6B8eLVgPTJ+dpdEJkaZZtRRI13wdZoJZft3Lg1LvTqmVRgbjig0Nww3z6DFAh8VHklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwOtDS2Qw2/8ZrRoPibD3/w6c4TUZuXVe7uVlcVxBtaGPLE6xfuW7jcWf654NM/oUAshVSibAfIoMA5XuFJxa4AQ==" + } + ] + }, + { + "header": { + "sequence": 5, + "previousBlockHash": "6C0FFCCB541112535C9D3F7FACA59206E97D7F8C03819F76DF5D3BDB16C37EB7", + "noteCommitment": { + "type": "Buffer", + "data": "base64:l1cZSZAZP+Xa3HOzuU/VQ2EEGfXgciHvljUkalQmZHA=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:Xn5b79Q4VamUTW4LCp0dFs5Amcs4q7wQ6GCp+KzijaY=" + }, + "target": "9201866281654531936596795386791503876274441021197252859723586932895305", + "randomness": "0", + "timestamp": 1719441707902, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 7, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAA+HDDRgCSqtfU+unIAQmlR7lr+Vl15xGMpiJE97r6lA+xA+ePuQHVUR1+GV4Ipdc5hMz88i71DeQj7sF4jpZmhovomQuSnV/4+up8smfdzU+C5RhT6YEFTvp5z5bWxTIl+9wNboZpmNIGLUxLFbiFe/Unzh0V03ffsI3vIAikUQsLEsN2eHzXixufZEM/6U2Cr2LLIgwb/zzILagG432iByw5PVtwXD+9E6ye4q+8OXCvrZwCe1Sm/rrpTYcIEFrlH9ujolXdynOpfl2W1m79V85xv7myyedadpdgBf98hYIBfS13BeDgRxmUhIvxayp+HmQ6tnl8mAYvC23hWU4/Ep+Ox301S6rAhsv7bCIXZYGuVwxpWV/DZovCh8NCe5FmqBfa6BxaA2p+qnCAEqkvO/pB9NjaE2DJB2GfVt+6OGlPEYc5+UOpWxMFQw8DFB1DyJxpvHNxbVQ+VBic7cjQl/QeBKE5fxidJdXnGYfGSuuHZghBFkIZCJfrhMbcnNJuaGFvnNaJxfd0L8P+jND5R+SjEgjvJPh4IrqPKbMXG5v3ubYidIC48Md01wBQKOdYmdlLtkq7vcI9rcUdWUr2GbFvksNza9SmE1yGimVvZ79j6ksLp+3WP0lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwcsoJNdbrQJXDZlew3/ExS2Fo5DGeXnf99Mqrl6vRFFYbkJUuoHbR7Q835Da8c/lJIh0JTNV7kRdqCBsCSdqhAQ==" + } + ] + }, + { + "header": { + "sequence": 6, + "previousBlockHash": "D18C0BD715B3742DE3EE603FA5464013713CD3EC47516601CEB2F1C92636A1E5", + "noteCommitment": { + "type": "Buffer", + "data": "base64:z8pNfaYp9hR0Vdfjvcxw1dNpnVLFozRRKdUNvIZdhFc=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:ACdINcnUrHT649NvK9h/Ueb9HjNPli5Iedp3Nv9LkAw=" + }, + "target": "9174987784651351638043000274530578397566067964335270621952759689537226", + "randomness": "0", + "timestamp": 1719441708372, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 8, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAPqmLs3kEtsp6RDX27GEwYjJ/swB+dCIticFhUkR5PFKRpqDK0qtlfAz05kPvCEMeXTiuG4Ej/a+Bq4gWGIFc2oKT2nErneqA9qEfiESkRzyVEi/cjWAoGaWC0sHhhYQoJDKNCEwQ7CwqLnkjtFm5kdd5J2/5/wOt+KtPD7B/NvEOMAM0Z7vsc9SX8wcI0sJiHCMVeemCTG1+KEOJSrhI+L9gtdbWbGl8MyL6gpBkLpmM5YXEPgGlOliSUFUbwq7aGQch2ITMSK81YsTTf+7dn3up8FIROe7OVQIXcd3gaFO886h0aL/+z9Ef5/GGqkipIDJgzVZOHhRivXi7ZCSBEsqyk7QL9D723uYGFWDfht5tBDsGse2QVssYTOwctr0ThSDur6eFui9IV0qbm06ksd3DvwxGryg4UEwJEL+xBqp/WYhMAlW2wwSSqXHqqo0DjOQirJyvVE0b6xFWiDQk6TzgE6+EcAAgltmqMGcf/NSiuXWBk5EEAxTljgdivN2d7Z4R/G1PtOMUFrM1l3CdcfDmFPqQuLZ3vSFxqY9/PguHIP0qW9POjrk93IgKsq6GN9oHuq+/zynvjvp4VXQHEkZzPZn7c32mbzMiMBhbklAt3XD2DIIzhElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwcwRDzsXh5cxHX35HkJ1kQdotmhaWO6ytlzJpO2q51d5Wopic26jC3z+8ZHtDu6ot5FKg+d6JvTL6gtXFuyhWBg==" + } + ] + }, + { + "header": { + "sequence": 7, + "previousBlockHash": "0BB4B6B6E56E8C9A863EA4266D2D75D79E23E28779483EE7337EE4F757B5F049", + "noteCommitment": { + "type": "Buffer", + "data": "base64:k3BDdZVJODTWmPWsUvVNBH54zyAJBTGcYegReQeHhyM=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:cWMk8WHQB6zLDM7ilPcWI09ki2ensf/wyXSMFjhf2x4=" + }, + "target": "9148187795366513087508709149025146424715856256637674150531751753357577", + "randomness": "0", + "timestamp": 1719441708837, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 9, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAbnLEHaOgEnj+BuzPXF/0zlnW7ZxZytlIqi2EsXbAkBCqmHLASf7uaDoyOH5QcbjMY3qwjgHuoTaKdCvKSKFG4Ak0A5M4NnC+PNDyc/mj2ku2IVrA1E8BmQNs5wgFWlOW3sy1OcnkE69b4ln1n9He/uen3q/EsmhkJNZKe/OftXkJB2j+N+3OBGWSUaUEbBh2gaH2JmXIKHdBEUFngu/JEPXNOF2iyQaaCIEFNkoe2uyxrwsULYDIYnFVR1ZMWrQ7MG3Po04muutSIXMtaky7S+AdCk2efHNJqzxFQRJaA668/pnQVHqkr7z9PLdRt32mqRS9baFtsfBJ71UZgOWgI8Jb81Lb5k0BNfWLrg/PvOLrAs9VhKqQxgffmAL3bY8T06DrAcIbM2L+ac9k10XKsRjejBq46jcbB6Jnzk22AI4/2+pqZSzltRAddtOFkZUmQvL9EMSEsy5vG/dqomndgeFpFNA3F47LXtmFn2vXaraiZbovuFFRGCBFx4GwQCXo5IPXEkRDU8REmx+pC4vuym3p7wZzBII8TkN+fqiCwSSt3xaemYD6GdKuO+LuzPInqFjhNK0/OLOKk6V3SIVVhpswyrk0UW9hQ2RbjsR9h+yXibUB4woaKElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwjUHz9KZjRvDfUpZtLjkDOjuDQ5op+Z0l9unsXY1Uc7O4Nv2qgAa2IDLfi52UMd8O80h1yzGqc5b07P+sKRtTCg==" + } + ] + }, + { + "header": { + "sequence": 8, + "previousBlockHash": "DD2E10F6A5EEE09B16680D21855369F2271D9FA73BDBC300FBBB891049F3D7A5", + "noteCommitment": { + "type": "Buffer", + "data": "base64:ml8D5iykqwVr05+UxsQ5DRamCVvVfGN3SswiLeCHW1o=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:2qqjRiEepseDBj20XRTF6iHPuR5wfZgMQy9TzmVtcqI=" + }, + "target": "9121466311864876128923245652724724632104869735746188813030060672759072", + "randomness": "0", + "timestamp": 1719441709303, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 10, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAA21ilbjArKP+C4LpwOnmDLX7uf0OckijaP3ilua55UYS5eFH8tRd05pWBm0VwtWA7TsTogKdGp3v9tVXUWCj5H0Vss+53PruNDYmqcnsulY6hbk+2JT3SKLD2dZIPfwvPe6nAHcrhYQFGhVd3nHlayfjUvxRGYG+vpVIKBK5K9koNNCH/63L7QoVc7k90yH76rk2eTnAINO9qMTG1cxOePap/c2CTEOKUJCTrhzoixBC0U2NkODHHwJZaf8Z9kgGf/Tdwc/V6Uw+OillwSQ8P7g1BJLZQz+IQOyntED2VpEBoq71z1ntz9xhq+L/59b1OV0ZQiuPbBfJMLRfvlbQjmmOeYIv1XJibBHLUV+odU/bGuaZiYed5UQ/EeC4BZGJWgw/GJ/g6M2t5wujBVJdWZHdeBVkLi3PHr9RoRw+6OGANyuIGZAs9YEkrnUt7weViRmO14GLnbgJzlKnuTTRxEJd6scs6+LQJwjxKqTH2Z/kcnZ++uy0h8ZmfhHE/AqGaDc3roqWsI5KnEVa3l6hrdvfakZrIlqBlHVG3A5bJQSpLLgISA5TEKfvOXLCZgSeV+dFjGlK+/tONsneaph1AzzGEZWfcNP1NYsYmlo/8F68Du4tMTzIRzUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwzrU/k7Joho9/q9tte08Zb2lMIVC+Z+N9zu9NVNUgOw6Rrix1XS5hhpZMJg8Bpgstix4y5KecXbg8kBQZUI9kAA==" + } + ] + }, + { + "header": { + "sequence": 9, + "previousBlockHash": "68A8E7E164F55EAE6C472227972BC9F36715D3334BA410E856D0B716FE454354", + "noteCommitment": { + "type": "Buffer", + "data": "base64:A0EePpa2R8oKPAW/9QsU4IsShV/gXumNWosUa+SwjE0=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:lqyBehni47RhZPoC+o+W5yLgAxSsKeOSX1GGUEJD/Xo=" + }, + "target": "9094823328238119324660168503613036415495463326164889575918026009508991", + "randomness": "0", + "timestamp": 1719441709765, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 11, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAuWwvugJs406ahfgO6OdzFvIgr3h+590GcwHZfAL0wq2PgfQiAFCyU5/HKtALDLNgeAAs5M+M4QOIS1DMbbCTWvMOh1XKjRslqiADR2HzOCqjiSyK94jYw9HvhcIZF5njDk2chAyxaMoqwuHKDsEAGHcyTLTeVmfQBebnAe6NtsYKS5V+Q8O2w+FR8d/noKKHP3zht7ZARE7WcA0VU+0++mcPIW5BnNrfI3jl1uQCyzyLNAvXSe0oWmxPAzy2lo59hy2mJ//I4iTu5kfqhWZj1AVgQhRNGDe55g5Ypsr4o3ivyOZoZExuQd+azZiVtwVrbYzrWVj39Wo/W4ug1SxrQhKY3yCxXfT2C7q9rZbx/VqVwX9Z/ua6nCbvpQYw8NM3I1ty8CO7CoWyMpB8TH8zcZB78vqapSGfnsIXcv09fgXbpuV1Rqpp5qkYOi8wsYECiGS4TWYDr+xOPxEorBddzCGDRbvu2dwBdsX/RV4SjfizP97+uEP3OYelDL0Vo7j2ffS+EzRg/JdSuAGzbeYr3OgC+uBp7mil31v6KyqIXi3mJZPSyOhmqcPRCQ+/h0lDcU6vaFVV+fR5Ojlw0xIrKZBr01ILydtb4sx3gMxg6Dpb5ueEnMfoTklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwaoEq8vrFIXGk/vwRx65L89NP65JXnguMH14mcNj9aZjXLVFIcD8kvDnaGLO2yzsbFpvztR/MhA+RVc8Ux09bCg==" + } + ] + } + ], + "WalletScanner skips decryption for accounts with createdAt later than the block header": [ + { + "value": { + "version": 4, + "id": "d9a15ffb-857b-4b35-9cdd-f6aebd6fafb4", + "name": "a", + "spendingKey": "22b1818679e09c97ffd67ae0860ccaa55b2647bdc4e9c7124f7d1bda0f56afcf", + "viewKey": "2c0c02c7affbd92a2e0ebe4e92c26a40e2a75648edd6a3120e7847f3d8b022dc72611332c4649d178fd1146cfda95188fbd84c78476d617163b071a2115b00cf", + "incomingViewKey": "8725edfa3900dc75bd03d9b3d5cfa0660343b51184180e58325f78ea726a9305", + "outgoingViewKey": "b451d2f3e6f74f91db3ee30066d9da1bfe910ea92b96a8bcd894d4f08b6b82d6", + "publicAddress": "3caf65b0e6927c83b65dd4a4665ad94374bed54388eb75b7891d24ec52cef4d3", + "createdAt": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + }, + "scanningEnabled": true, + "proofAuthorizingKey": "d6fa34fa12847f56e656c4053b6ab91ee02ccf0ac38390cbb0fa82361ca86d0a" + }, + "head": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + } + }, + { + "header": { + "sequence": 2, + "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", + "noteCommitment": { + "type": "Buffer", + "data": "base64:t/nGRBfEM41bTDxqlaX709f32cBhvjnkDBuhenxUZFE=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:U/40oB03yqTvyY7aSV79yLUPad/shYB6WTv9jd5Kxak=" + }, + "target": "9282972777491357380673661573939192202192629606981189395159182914949423", + "randomness": "0", + "timestamp": 1719441710613, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 4, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAA/esP+kmF8bkJ1NxWAyk2dmoqjlCOs4l2wFfu1/iCzO+p5NndvXVSnThaEUKtr2Rq8aq4Kq1mShyptH74ToK0O0SIyUN631Fcf6XOjVuyCb65EvVqj/8RvBA87I+m+2aLSyhl0ktuZMl3pQzPATdp8cML2HsUWiZCiTS/CUco79wTflqXlBsFEZSsjT1kilmVxwquvQt9qESHLb29Y9XWJnHSbrlwWNfiefTSvHrqVaKEaeys3SrVzyNSkvJOvHNPnpZdvTBLumnJfcViYjA0gahA1CPKODcRzPv820Zskp8hsauw3byb+xVfCZQGA5melUg9x348Eatp/5WmM3ZTRZ+61GOXhfiJVSeS+JluL7zkzgNkxG8qKxc/pmtGRsBrloy5KKtN1jY7BB9r7qqqvD0WAdXknZkqpsBFtJ5qeup68B7TAfbTBHdUh5vAbdtCbxoANOLQNrdKM7fGEc9f37KkJk9KucJdfAY6BYA3bK41jVZgBLzaA0tEAXx9N9MAVUW8Pftt+xowV3XrWzjO2G6UHvS8Y6lpNR9rc687O5ogLrKyvqE6pYXdWFesdm1VvE7E/ALgQxYPJMZRyVQaU9RXkNrUixVyo7/1dKNjlBgCg3GC9OyqaElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwrRTjhXSQIwdA/IwpRPE92hipHCD86Bd8uVV7UY700aWK5JcRmYYUTCBHlr3EaAP0tNqY6uH4T3xUxi2hMUzwBw==" + } + ] + }, + { + "header": { + "sequence": 3, + "previousBlockHash": "B69F5673E6D012B151A6E7F1EF4A49BF8982BDFFF46F5E15116E4D52163D641A", + "noteCommitment": { + "type": "Buffer", + "data": "base64:O5Ti0VZzOH2K5836j7oYVkvXnRyaO3ftHWYowlVy/1I=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:DIlzKFLoKriJ60ZF5Z9nW+RMbEBDl9nsXK2m+xubzxk=" + }, + "target": "9255858786337818395603165512831024101510453493377417362192396248796027", + "randomness": "0", + "timestamp": 1719441711079, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 5, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAtNXI4O2D3UHH3OTDo/uka34tATF91q0lEAriziW4/jqpVdJKRQaod2TfnAR2SsYWJsiMNTv4xXatHuCP9xSDvKuKDLe53JDUBatP4wsRLAW3kBcHTNrc91Jh4Ixjc3VATU65ok079ONqvsYhQEOKEDW5FRosPEhnxo4edvpdxFgO+ScfLYdofprgR9Tca4lWQmrHCdt8qibqLTeK4MwEfTPAbn3Lz1nP0xU1PCoIIIOT0jBeAe6nhuh+GTSr9xxxezvMWC/XiS3SKHvOKKrQVUvZT1TcwWA1cBJdMBQQir8itqTArADqCF/U401oxKu/9SfNqM0stq2BW5IrReKKXtkIpsv3ZLCy22Ytuw14nzWxPUeSN4Z1VfRYVRjmpepDho5JxB/UCFL7e+P/oSZkygTfZ+0uKlPIyzRc47SGP0kgTFszyFeURXpbzzfkY+nukmjhk6t+TCbKjksYaSM1cR7ZQ7PL0Yx0bRrVoYVYTZlKGD+J6u07CzyUvWlbMhh1+EtH5nmi8zUtdUUVqNrpuY52jCucc8BqOwdUp62GL8UM8eCJxiUvJEnZSMDGndFP1kbLxCdhybgMwcu9An20LGOL20ahOeyD2/7uqrUKDW9tKEcVOr5VwUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwqaZ3rvg2P6S4roBKdX7YfKVaLgQxWauz1mqT6E7e2pQmDQhrLq2KOmLtGAL2UDIXyzMuaTnXwwUMgkd+xonyAQ==" + } + ] + }, + { + "header": { + "sequence": 4, + "previousBlockHash": "F8C3A577B51F46225FAE20DD8B4A69882C775183A262032F8B7739EF067C4BB1", + "noteCommitment": { + "type": "Buffer", + "data": "base64:eRIDTZE+Z87/uElJHpqUwrNlHDuCezdU3SN+XaAzfTU=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:5H/Mr/pypUmRoTmGXiaWRVkeYmFJveBYv/8DvQxh+KU=" + }, + "target": "9228823284279306817296266184515742822248210830185427859262273659833347", + "randomness": "0", + "timestamp": 1719441711542, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 6, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAK2c0dfSgQKwQDHZWhi98pAEQKTri9HeXcVAST303romkp/rz0+oDYCPVrCPg3HciREuiW3d6upXvQSI2uCRLUx/l3vD7t2UtkxrRU/9cI1iw6QhKMi82kbQzwVVV8Br2Cpn2n+u7Vi7238UuH66I1nDnNtMBodKhsu1zoMrbzbsGIUwgHRwBUbGAT+e9RUGM0kMBr6VXCUgD/XCYpYJN6A/BIflVu0DRocgqqFyZbp6S/j+joJqsxRl5cYt1PQ1E3X0htjCBE4XtD2m8RKkpknRFVs09l/5WxoKRl2CuG2xfR1SroDKEk38Y8m1SQCPkpIkiVrjEgrdPSwMFz0mH8rYJ2iKoFSG1soeAT2U6svW81enpg2OVuya9iqmHKAEuXWlnruzI2W7ZXOc8/5SlIDUkbFIoiSongTOGsSi/LhL2xPVgLJkc97cHNJpSsv/qID+FBKN0skuHduZ7pMghl0ZA/tGx0dfjuwn7PVZwdhZVW2tP85o9WZl0LdP5PsBJtJTmR+J+A4Q/XXC9JOwodtqMZefQTXjPOyuhs+7a1Byw2oIYGwSe983ASM02a0OxH0IbKT0NpLtWmUvjMDrHPROaANJTybw0I+RQ3FXeF0sFTuyDxGoxB0lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwoiMgzBfo7rCtYWvJwbmHLpmTA9hSjXqLmOblA/ojpWnmL98ZGsDxzfQGJmhhyK86xANnS9T5CHfUwFsGoUFKAw==" + } + ] + }, + { + "value": { + "version": 4, + "id": "c1f6dd22-e561-4f82-8e6a-9c971f15b29f", + "name": "b", + "spendingKey": "bf4b4f8c66d092df8a26a7011821f031f8ad5afe8b1fdc4acda68f555dc16752", + "viewKey": "589dee75144a22afbd2a397ee9607f5ddc375ff63b3b9fdf49c0ce73b6789f65ffbac13dfb77c2b254f6f1e87f426359609280253dce6867d59dd99d1c8faf0e", + "incomingViewKey": "469135ad8fa89d4673d6d1338e19e2e6fc8a6c15d63084957315b72229451b06", + "outgoingViewKey": "270b99007c639c03e1eef6cf30afcba910f9105461590e6500f7f9339cac28ba", + "publicAddress": "7f64a69fdbcb9360ef620bdb024b781c162c7319bb5a107a087dd13abdc09466", + "createdAt": { + "hash": { + "type": "Buffer", + "data": "base64:/ipYiaG2PnsWFJVFjVpEDDjM5lxOzAzZ4d8hkQR/kU4=" + }, + "sequence": 4 + }, + "scanningEnabled": true, + "proofAuthorizingKey": "f23a343fffb68241b5fc6e287a79c2e65647d1179a3429f14caeb0062d2f2802" + }, + "head": { + "hash": { + "type": "Buffer", + "data": "base64:/ipYiaG2PnsWFJVFjVpEDDjM5lxOzAzZ4d8hkQR/kU4=" + }, + "sequence": 4 + } + }, + { + "header": { + "sequence": 5, + "previousBlockHash": "FE2A5889A1B63E7B161495458D5A440C38CCE65C4ECC0CD9E1DF2191047F914E", + "noteCommitment": { + "type": "Buffer", + "data": "base64:p3+mAe7ZXnQg0WEvnZ+ueOASbdoQy9rq1uT1ZCCWDyU=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:jIxPONrZpSh6C1zCW4eGEYHV73i1iEwB0NDY0q+JH8Q=" + }, + "target": "9201866281654531936596795386791503876274441021197252859723586932895305", + "randomness": "0", + "timestamp": 1719441712010, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 7, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAA0PREpfnx1UrnX+G4RxRIE3vdgJodv+Gx6c8Wj5Hl3vCB/F0eRwdvjmvzJXUoAb0vH5hiOyE38jRlTvXTy9Djy/yAu6aZsSD8uMDmDYz0JPW13VFFV+uXEhI+BAr0yWlYLT309wTlGuZYTRERzlaAfJivK9J0HWmlRYI//tLbKXURurGgQg0ydm/y9dr+yy9SbSr7UfF4vjzRzH34PwK6kldpt2mjcXvkimOuQkkpmJ+xzWUHhP+vBtd4xZeFn9jII0kmSjOgHkMa7W6krvRwoE08HS2YdzycTbtNAQL0UgXrgjzr1gMcdPQJMsQ0tpNdOoOq4ES/RVmxBFGoU2v/nz9kEwuUGZitKQRwgE0cKUzx+cJ+vinOSQHCjX7EW+BvWy96VqbH2nEdFbQv3fIEcxEWTFl2JWZxL6YnQI31el6sZ/p0hhmLWnBTRI27xe2v/qKCr3FYWYf93idp5eUWvX5f7xVGt02YTDnOguReTs/NccxhA6ngIfo2BNeHr1xqtqYuqByks2Er5cnEjZoHYtI6+bDd/ubH2BFZtYei3YPbAFV5ek0utWHr9lg6xAdZrNMOzrlH0rZtQgN/4w8a34Pau20xBcFcSkXZKEzXx3N6AsKH7qFZiUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwIdhdPRFQi2+z4y4df/EZISDxdU6TiHEdm47T18UKlGsrTwPVFjtibl3l4GX6er/2jc2MmRVhY86YxBYnKLOLAA==" + } + ] + }, + { + "header": { + "sequence": 6, + "previousBlockHash": "689314CE4EE1C3BBE6EFBA25F64A8596EB38F70F25BFDF6F1D71448D82409B9C", + "noteCommitment": { + "type": "Buffer", + "data": "base64:EUSZDapvMTqNwZ/wIVqbZ27l520PL5mcDpFjqO4J0Dc=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:wYTT4nOnC08v1j4QD2y7+y7Ltj/sLzRMAo0DG+H7fMU=" + }, + "target": "9174987784651351638043000274530578397566067964335270621952759689537226", + "randomness": "0", + "timestamp": 1719441712468, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 8, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAwB9MZEdyIee95Jkofyz0wz8rvOnpqd4WcrhQhDMGyuWurYlBXBftPylZZTDIpw3DWvRNKJ1kiaJ+fFs0pjlJCImf/meYPcbg+F4iQa/rtJCIYwaRgPppCPTQ4cDYvU63n8wANuR/TUXtp0xqO+RD7ugTe/+nO18p5zeQD2K6rzYJyefXm3/IA8oy8RlVhZhuF/CsgdhO4jlLwKn7xJI6uVrhsRmrYgZ+cZWAffK170ao0EtQaUbImLdhMpApQuwcYalLPvSuhZsmmXVVxw7kLELWZjY4QZgL6RoxR3A+MV7qpc9CluvOH4VKsT4kO1js9mAKyVKMFsaGDnxRRu8+LGacuXJT8CKTsT5huUtjTpOHy3YSDiIfW05QcVRWgCwFLQGrqOFpa/N3Tm4PUBAH5eOlA8r/JGQa+7wuB2yfGxVv9XwegM5aVWVvpua9u5mghvP22wmWHmMeHoIiP2afwtXtzn2VZyWqYcRidwjwGcMyqtGlEO3GefgFdjJ7FhtJMEeppUmk2EnjX6efHuSOMbzrWNCamS/qq0zXeQq5MHZkL4pEwMdYpe0/uGlZuZF4Dc/ES5cNM3M3SRrGQhFNLJ7aWgJzKthI2mobBBG0/n5y6vOY6lIe0klyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwd+jPU9f18mMXt3vsQOcw7J+kn3dhQCpscxHOFR/KeC81K5IG2VuVSbddtR8u282W3qB4+Zd34WAD5renxxe1AQ==" + } + ] + }, + { + "header": { + "sequence": 7, + "previousBlockHash": "18ECF56F6B123864351D989605EC8FAB4C24BFD4393BB6FCDDDE54E42C8E47A5", + "noteCommitment": { + "type": "Buffer", + "data": "base64:VOICD+MfsxjYm5nKiJ5i26H8B5ij7LYE67TfmvIGnCM=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:hcYO831nU2O+SraZYl9+P1G2gPzqzcRE4xMWIBJq5gY=" + }, + "target": "9148187795366513087508709149025146424715856256637674150531751753357577", + "randomness": "0", + "timestamp": 1719441712938, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 9, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAzXqmfHoGn3bU85f/Ho32mrrGpf+a1i8zalQyF5dqFQCNJBER8uHVNIJB06fECw20Os742eM/qSXRTTx6Fb8ndjPuu7D2sB/SROe0yod2db6QtpMqpJ+hroCaWb0GW7bS7Za30ZOLkJ5guJESPduOn4l7qa0H5EHxnB0GqyG/lJkXRwFGQPSd6sFqXC/86GVvtVIaZ1b/8w9iD7svVmtHsGMe49XFeXGwzik4a57E1Ja3BIMtYhOQgwWxi1kgmHJdZ+RVUJnMpdG/OkxvuOsSfXYkV9U29+IOKL5RpzYdGzELq6npjoo4lnRIZIYuE8xs9u4go7wSJ2XRB0C1XchAEQfGb4BA4oOjLskIRhnzqjLGTORjhVDnwozg13QV3Y1z6moVGKH15E26ZWuicVI6iKBHWsUoy1Wdyfkl8SBAC7ABhWy3gQ8YsO2aW5rL67GqlSIzjfhuTFBkHbJjGsv0Q7lNGkAIUmoNNZ5HvuZ6B/bF14Yrh57kVIaJ3QofdLu39g3r1CwHy6Nciw1fOf/3fKggvJDAvQPMPnLVIMmnDce9vq3ur24qX+JIwAQYTTuWpwbDf9vOKBfvMqDxNXGkeuamS55yVeoVmpjiQAl6jK2HrW8nkbsaKElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw0eqROTMQ4tkbiKk4O0z+Hp1nYZIoviQc9R4HXTa/JNiUsJbdb45S5i/tUQWr1fot/1SHcn1z7LVtS5dNj3xEBw==" + } + ] + } + ], + "WalletScanner skips blocks preceeding the lowest createdAt": [ + { + "value": { + "version": 4, + "id": "0f3912c7-d0dd-494e-8b8d-f0fb45510f22", + "name": "a", + "spendingKey": "1616f3fddfd2ccccf7fc1ba6d43ca07ebaaa7da1cfed5b4df8a05aafeb5ea0c6", + "viewKey": "c2d1aa0928bd76503b0b02affb8ee9b3efc1238aa34f595da93d24acf0b1b03274ea6a1474eaed8f1b451eabe3223a82a013a07373ce23e060b13b489d6bbd61", + "incomingViewKey": "d92c1aaca2cfc6d8d2191b38cd371ff05113e8a881cb8fc7a5f780276d83ff03", + "outgoingViewKey": "75bf194d2ed96fc414dd7731be658d53eb695481a043955bdce568a5034e6826", + "publicAddress": "669c07cc167c86b1b6cbb66dd3ae7a6a4487764d134defa5ff05c8aaeb15f1ce", + "createdAt": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + }, + "scanningEnabled": true, + "proofAuthorizingKey": "1a08001b02f599ef90837fe444719105d73e8fdcc0f0c986a5e27a14b8524505" + }, + "head": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + } + }, + { + "header": { + "sequence": 2, + "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", + "noteCommitment": { + "type": "Buffer", + "data": "base64:n+sWWQKt9PbwH7itYIFkNooevniZOIfYBzKE0+xGoSI=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:xTnWIr3ftgauGO15C55qB/rZQSdUmk9t0gFa/WD0xds=" + }, + "target": "9282972777491357380673661573939192202192629606981189395159182914949423", + "randomness": "0", + "timestamp": 1719441713706, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 4, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAaSjZbAIdjtuTTaVpUn0OR4V8vg5kicC0o1hrMufop6Kho3YexaBPGIarOwPBk2F1PRukFnGDRV0wNtoSYkGSo85WND5oQCDoLzUlvBd1mzaXs8lSAOU//4uait4ov45uDToS2tldx5nEymYIOss6fimjQ/cdlqsJ78sOOTZ3brIJwIxU4lGLNbyiFpH4u9GKxD783SV+YZHVajGXdYNngvYqlxKJOvF5io+6McKWZoyka4LlUFtIK5aanCVYzAJShZdBvajRZXeVHkHAa+tqyafcdDnNx5Q6indRxTuQJnl4zla5xh2fNuc2tp5IHpeYr3bApMGEGOZ1G11S+W7w7vWJ1ZkUwP3I8ME/UA2sIgkmK5tIuwPM3QT4yhvdY0840nVFs5XE63/a672GXHa1OQMirduB/ajEpfwnL6LV1lj/YLt6ooe2x/AIp8wsvuzdrRvy2M+fUlCnq1tJuXRfD3fl4yx6iZIG3LwWE8A/zr6C/RUWO6hwTAON5+dSzSSi/hBOcDA6XqOnQ/e5I8lwFhklECpZqdfR9bOuo/zdM13wnEmayBU/yuQfQkGr/ynFCAQtcSzW9z1ujtnC5y0hUGKcH+xpV09IgKEpCH/nSbCqvB6g6wwNUElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwjk62f8n+8CMYl8g8kq6FzMdsckL2QLK7rUji+URQMm3FoOMmFjiB/s+r2h4wJ+45M7LgYOKsrhudonvGuTujDA==" + } + ] + }, + { + "header": { + "sequence": 3, + "previousBlockHash": "0E8FEBC9A909790C9187E134B4A60AF90DB372D207886A2232FFDF775E43227F", + "noteCommitment": { + "type": "Buffer", + "data": "base64:s3Z9V1u6TfkPU6X485a3RY/cnkStRIntVC6kx9pmr2I=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:npxn/zG7ccyTfS/RVk6NqFxXNTAiBmDp9uh+4KyoZZs=" + }, + "target": "9255858786337818395603165512831024101510453493377417362192396248796027", + "randomness": "0", + "timestamp": 1719441714178, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 5, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAMKtT3oq1JfB+hNdK3rhdddiav6Gjul0r6/uhW2xqWG+oLDDwd1mtek0+3VH3pmV4IeauHL2+A6B+iZd0kEYzcZTkv0NyR2i/nFwR4GwgUu2ywL1s2r2BdLgoM16l12Ihys7IZMDZbfgZCGWBXzWPfvZXPyXw7Q8BrFwukeE29bUOKBlfTSYgaQtbmNpDP9obaj5by+Ld4Wo9fuJlBbawRK/13rI696XGxV1XvTdj3vWVYQQ2OmN+8qRHSpo2xiCg1fW3N73VpM2UorqhwVSAT0kigxxXpoRtXrl+FvmHwjLECmIZQXZ78D41fdn7kO6iyAkyjKwh705kmVCLbDqXH40JMwzCdxqbHnPsXLFELLGcVKCR9sY/JH+/kX5444sVl5d4CMkfOSlVwWXanBFRBPlNgQ9lZSaiQmXr8Gcm4RrziQQU4Iqj7piTxULqrxiTZZQBXrQAIh+W0In4QaGmhnT4efW7Zj6ri8Pliccvh8aicXuwULB1KUUmpYVvZ0286q8chbb4+7npLGwkrdxf8J1ZVill8+YTEKjkujMOAjY62F/9ahe2tw52+Hb8ZG+oAe0SULRoHtHBNN3efdygB1qetUNJLf1/I8ccWzGz3GmBeHrBHMKHIUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwUiK0RaSNlbAhO4HW4JAEMFCOektB/wIZcp1LCmsiEgpGLT/xfgZ2J3Jl/8WkcQ1JPg2QlDWsXVTVffCysfekCg==" + } + ] + }, + { + "header": { + "sequence": 4, + "previousBlockHash": "050ADA5533F338F1BA0C69A22373CC1C1720034401038699C5FC087FA41F8458", + "noteCommitment": { + "type": "Buffer", + "data": "base64:jFaBsVq1mcjZ2booxT9RGj8YlxLixkSETDInn5a/dHI=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:IcQgSI+5kTae2zkZc+OKhqL/U9tdCz9ljq2w0p1Cw18=" + }, + "target": "9228823284279306817296266184515742822248210830185427859262273659833347", + "randomness": "0", + "timestamp": 1719441714662, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 6, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAwpgPAEyajkka4eeMl1Tk7vzRxWDNfzQ80jLD+sl94z6BTuM0npeeAz1butHPEloBEStOgU9GLY+Yz7RZL6Tw1uapHzy0v9zgAWJ1fraC2zqZglZN1owevbu4xrj+mPawJnxHifmDmANPtNaZmeFqJP8gMzJ4Aq/eNPK8tbr00scXoqunHXbYvUdOX58xFRGa26FkoUguSVYf9Vv3WI00ycBpeNB7xrSmG7L0aqgHswy1DcCrgQN/6f376sfgWvGOn030p0T4U8BsjDkts5LnOnAmDpyKhDSUzEuGW0d4oC0Ds2mP69qH5VZeUSBv7nTg188EL/IP76k+MuviK+exc+WIboGykNdBnFzXfC+4bp7FetmJGcwYHpxjEZbCJ6wohCysB7WcUEdB1keMTtlLi1nLRZRhiydnL4B29nWvCQ9/erdiNdV813a9MDxHJ/b7BGLLY6WA54A94eIiUuZACDFWX5oBCooplTRo99JCf5Zxz7Kz8LSWN6EqqNd8BiVuvyk0pe/v9VbDR4cPjJT2hToWAcD5eBdczRbe5wEjTBc5ZAccKncWAUCh4nRMVKORg27mdx2AXJq7ugkuodJ5bYr7ntBDgnIGsUitIcIB76yKP93XaU5D5Ulyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwh+p9VR4u5B/UFJ6w8Mocg0H/QdLwjnL8ZafcCM/Mg/NcOn83fK5gKEKkMDEjClA1eclNc+T6v52xmbcIZlHLAw==" + } + ] + }, + { + "value": { + "version": 4, + "id": "2ab7a678-7f34-4cb1-8a0a-bec779f935d4", + "name": "b", + "spendingKey": "7ae31eef18f3a40596fce5062202676e5dfbd3d015a674ff76857fd97b9ad623", + "viewKey": "75e1defc921bb4d6a2487cb79748674ee91a2977f93779871280a6b37e9072a581595f2e115fd38dd1d994600fb8fb412771ae1672a62056462b4072d95a756c", + "incomingViewKey": "effdc9b669b507c5c5c6ff4a024adb3a067c0c7a983cfee72d3863289cae0105", + "outgoingViewKey": "d2a463ef226bd1a539ae966e4486b4d73b545ea427cdd57a3c36332fb745ef84", + "publicAddress": "6cdb2bfcb2befcf5dba27e11dce86bc37e8c0f8d028c816d462bf580014ce92c", + "createdAt": { + "hash": { + "type": "Buffer", + "data": "base64:AjZ0RgBBNBs4qIs7/5Po/PuL/08a3K8UkG5w6p6VNmA=" + }, + "sequence": 4 + }, + "scanningEnabled": true, + "proofAuthorizingKey": "b3ec5c5ecd614b5ca21e5b1d19e2967d3e4d9b46a2f7a596b3973a5df932d709" + }, + "head": { + "hash": { + "type": "Buffer", + "data": "base64:AjZ0RgBBNBs4qIs7/5Po/PuL/08a3K8UkG5w6p6VNmA=" + }, + "sequence": 4 + } + }, + { + "header": { + "sequence": 5, + "previousBlockHash": "023674460041341B38A88B3BFF93E8FCFB8BFF4F1ADCAF14906E70EA9E953660", + "noteCommitment": { + "type": "Buffer", + "data": "base64:rhCy5v+aagBLTFzuRQLjb3qxjOObCYAxsLPBlf/++T4=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:P1UY1e3sVBtSfeNG0CIizxZi2crCe8Lo+30reKwJCxA=" + }, + "target": "9201866281654531936596795386791503876274441021197252859723586932895305", + "randomness": "0", + "timestamp": 1719441715146, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 7, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAs54E9HWNTTiXFcBvkNzmyp562MuJF9Dsose2yAlsx5S531ki6xZ7opTMKPUADdiIgrw30h5xiDdZQK5r5XaJjqK+HUYia5Rtd/HTCTbxwvSyV1zl6S1iMLP1kJQHmhg42Y372K2XQsJy5wk8fDj0gCLMqZ8DvM8FvipBRMLzwg4ACkc0iKce6VRCzPr021BFY8hbrqDCzcyODl9KXkNe7Nb8f7KaN+RPF778eFiUNkCNti4ing6qS4v/Z4QLiwdrm5h1JWh+RCCPOws9pf5BRNgLYKpv1ZxREHNbKVWKCpyFMGDa4Zqg3MaKz4mb2tKtoLVyQcHL7Me7ja1gJW+k11zTvdmAAzUWJIU2Dybu9n11HajhFh9MxW+magWkp30tOitFdzA4WlT2h0HRdWNph6iGRjgZrtfdRIZudjnosTB4pAe0Vujx+U9VDAB1VliMtFRYAqO2E7RTzSs+1IqxNNEvfxTV6zqro6MfOl5YbZOcWSxBMW/o3kS+B0xE7R2cSamOG0bskTY2fMFZZl4uwE6sCs6PkwNjI7Ta8jAFT9YWoaOBJAX7a+PYZjxuXPSN6nXMJX4BXzo5AwS1+jhHLkqY/C5sQwiUkmaIxO5RwKLDpE309V1dl0lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwOKaw1frd5RHcG7TER8VH5D8xxpsm7HMr0AwyENLbFpmpxiwIF0Fg1/G49EfilNsX/SlAvDgB2rlaRb9maiJmBg==" + } + ] + }, + { + "header": { + "sequence": 6, + "previousBlockHash": "C9669A682E4EE5610FB8750FA51020662AF29F6811ECE62785088AD27700B8EE", + "noteCommitment": { + "type": "Buffer", + "data": "base64:n75LmFooqdVeYYip4h/WFM6VFxCZ9OES4nfZUv7a52s=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:93lLj1s7YLC+TooYjqFjGmn6zgoVpIF/bmdX8RgTfIc=" + }, + "target": "9174987784651351638043000274530578397566067964335270621952759689537226", + "randomness": "0", + "timestamp": 1719441715604, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 8, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAj4CiLhs2IHU1PkFZKltmxULim5udHt8s2bh+Uv/UU4uou3DVVEiH4lQdvRw9yA5zqnAOWmOl6oBsRVgrKn8fLcwmOiZsXl1bgrlUkqGPOEChrHJVTlt/qAF6xa9PuxvIhgoLBMFxEtORRDkC+5RckP8M3dvIBF3+3cxTSSdqUBUKg/CUNxXaMgVi3S0xU9y1nTOYEu4sFtVzNYNjAY5MmoICcWngxxnQzSkwqTVurbC4CxW/42UbMFCR/LlgzELYFJpLhxgz6jR7Fu2QrAxu81860jWVOs4OeeWiCCU3p2++jyB0Hcweu/3IP7/eP+aUm0ecVRxaiFXo9cpNGoCoSsbV+/zKv/MLnUd9QKIuNDBb8/n9tAEeOZUt/e8VfpIMBo8+eSTUbXmybS0T8slHq8ORVO1TmFDcN7wsT0ED35vWaUzIk9Otn1vpnAJibvmbGlFUp7BpLz3J6KH54ImmLqqb95aJohKJmqeZFuTkLy6N5DRhtN5Q88cQhMz3R5+Li2PZy8NpYLlk4mJypfyGYhiky0LqEPUfI91Bm1Zx3NACD1VBlItLYBoI7LjFrinEHs1xxSm1AVVJxd4Ckktjsl9ILly9yH6rZplmiqBFbvGKpLgkxIMU8Ulyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwO4LoCRuzeFt+cisoqjfFzzGZ3yDmDtGicWz35r3oF6UCZbUR1RIHLxN8Ja9on7VzfEm7Fn0nwdTRYW1HfqRRCQ==" + } + ] + }, + { + "header": { + "sequence": 7, + "previousBlockHash": "A562DF2A70F3C895A03FB74102E9659F9900F8B54E9DAEA04CD087ED24E44755", + "noteCommitment": { + "type": "Buffer", + "data": "base64:Z77o6+kbFLouSQoNIerXjL23qy5nbYjBRfHsVMiDvz0=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:hfRtvGkUUTRcbaf1+ETs7yEs8cp0C2feg0RtAFwtqD0=" + }, + "target": "9148187795366513087508709149025146424715856256637674150531751753357577", + "randomness": "0", + "timestamp": 1719441716107, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 9, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAA4FcrJ0yOAGHyKR/q+WLSBtoBXhWAVIJn9kUe7zTPpeyBUB2CsG2Ikrd80KVFy3V50rocDc6Vh+Sv0KNNquREpsOeYmarnlUTf5HGL/Vvt/O4G1vj49j9N36GgGwCptsB8KqEYYS8W9mxsPVZGU5hn3IpCLi+7U4rkpcJFPDtgsAXoWBkHKatWfiYm73gYHtIIG4mtLJPGz1WxLOiDO5JMvhl7LeqJxoomCPwn2ZkCPWw6uxZ1WEIiXu8IOHupCzKehp3wJ8NjegQch73s6UVmxLiyBuH5cutxC7XsHxmJtbVfdDUrL4sF1x1o3O6CSTgs4JQE9h4IK8IbJyofpRZYm2f/HyYDdFrwEGgy7Ey42kP91mAOAykEiyf/YaUrxg7gJawArtUqeX7BJEWxITpvv86uClQNHTlyv66TgAi5jYrZltV6ETHXoLgvUK+KNC+ifR7iXkOoUEjtSVurff0OmAf2nixpYA+4MVXbBKS4oxgfn5U6rBgFxLAm3dqLbUMPHI5b17NOEMfhGBfaUfVEzQjNvs0g1N/2Xamlsv+V9RTkqPqUVQaUlnuIourCuMrwHpAE5nHkfKNbKbMNZSeNKjcPT6lpPI9m9C8tQXSMLMVAh7d/yAD+0lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwCT2TGuANbPq8HuWQmlT2a8TnepbB3DCQAZ6zLH+x1CaFcRCSt6NxlfLDzrrMKMBGHgYp1SmO2fhIBnf/sQNtBQ==" + } + ] + } + ], + "WalletScanner restarts scanning when accounts are imported": [ + { + "value": { + "version": 4, + "id": "fe28d0e8-833d-4a92-9e3d-ed6208fe7667", + "name": "a", + "spendingKey": "c9d732595166f6b8a4f285f4df0ee76adb106b0c39615895422a633a08035d24", + "viewKey": "9518d298441f85255980a09aa07d8280d159e77b892b39c88d8cb8d5854f58219775f94ffb45bfb9046868cf82683acb24995d7f1f3d2216323c9403ffc80c04", + "incomingViewKey": "ea7dc790dafb32a077078d0590313d0f1ceea22cbe9c0145fb7a6481c1693603", + "outgoingViewKey": "c702677769d9853277836e270ea232f1e81b4f804074eeec27a1da371e534379", + "publicAddress": "bbd37319139d42a222151a92f482b48e4381f48ae1cc1b83f92f7b278c57d3d8", + "createdAt": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + }, + "scanningEnabled": true, + "proofAuthorizingKey": "513fd18713e16aa52ff01fe6f9b9a651b28088e229c8e1e050e0507978839306" + }, + "head": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + } + }, + { + "header": { + "sequence": 2, + "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", + "noteCommitment": { + "type": "Buffer", + "data": "base64:zesnAHOaaPkl0/TO9DoQ0ZLtdUyoy+Gm2q3p/pSWmnA=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:kOw3BW+L/nRPNpJDVjsqXkF5IH10JZSCpi1bFUfxsHk=" + }, + "target": "9282972777491357380673661573939192202192629606981189395159182914949423", + "randomness": "0", + "timestamp": 1719441717120, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 4, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAMihdYOG31F9KdpljKhP1NL0cUntNX7RhcDH+BUxV0+WxJwyG9GtxEcw+kEvnHUl2q6wntoA3jgQFnlNmeClscGdiFtM0VxUvqI4uwlVvJz6zO3OPengore7jvSZujc5CKRgS6NH5BLodY+6wxL1+ZyXx63H/n3y9rXSAWrbfXmgIbYzwhdzulg7ePDE6xAl+Zwtcy4lAIas9i4bSM6rnkqks5e71WWqRHbIwXvZeRRWqAmZlomEp67dM1u9bAXcgSQOQQU9KCC2Rw+tLuGiniATTfmo6pSoMV2ICfyxBU84/VEnUuKuvIyMMXpN16Y2T7hZ9xyspOgBprgwQ4jpiazeYo5vk2pSB1MSm/VADqLTUI1Sr0wjbcqDRdAlc74RmQ1QFbtVesTtY2pINnj5UXJjTU+8SIC68r6JkHCYAPVNWihG2KUYzE5IGRuOLe60oi/ZzLtB+kaR4eVWWWXB1Y9cPFO4i1J0EJdYQb5JYeYWmQEUhuQ2xhiSTb8XhilF+rQBk+brdNRau0xUhDJz0ScfQreNt+C5pVnwST4n2chz3IWt797PkmanYGNmKR/9F4+B738nfzbdRCKfUS95Gm+lVO+UB0LWosQCbRiNiEcF1a61D/ChqyElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwKIcU6uhqwIsl+OCYnKU+YJ7ziYvkYXpF/R4xr3hKJCHzZ2MaSsenna91kR0alVNOeQ7ujnmUXbZjMqZz5poAAA==" + } + ] + }, + { + "header": { + "sequence": 3, + "previousBlockHash": "C8CA8E6A876D5878FAD70AF8B1FEC153FBB8A7EE0BEB8FD1F734C2B938ABF1A3", + "noteCommitment": { + "type": "Buffer", + "data": "base64:1Rn0AErDH/BbtTxnDaBwFo60NbkEGgyXjs1d1aWy8i0=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:uWKhSe/jmCtM1SuBEktGCP+AE/nY34LoRQN1t/FgiVo=" + }, + "target": "9255858786337818395603165512831024101510453493377417362192396248796027", + "randomness": "0", + "timestamp": 1719441717605, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 5, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAUkStbxnJv14xGa4ZJcqzts5BPy8iqSUhz4hx/IbvP5+vA059uEDC9nIl/AusFM1TsAcqGkE15a6pLTGKgdMRzeUhXOpuA/Qp5hOXymRz0RupSSU3RNFtlpZ88VdnjkTe9PxAanWEnja4cESktVTOtdcShFtSNU8YRbVwHH5uI0sEEDSwpUKirB5rM0nlfFZNPyKuklJ05YCKpWAUmNPUq0DYmVRfOBfcy7omRFjzCIyJiVFs1CmK2FRsFAFtdCD4ikJwTumlgloqThMRFamNjn70hh9HgoCDpT+BhWUVB0AFZothSQpRoSjJXyD18s88M2xYpFRZjYfT4g0pHxYwRq4vT8UYnEPoU2yBDXPkLj9b92fALPMl1U5aQCDxd8tf3aVIQWAMlQMWuQi13EY9NVh9YV3NaBKaemoUmfOBNQCZsQcNuNCAdgwR/xCAPuEr4HaE/oR6wQZpBhDLIEOcx0UcAaDKU1InbGq98r//iWsklMgFaAWsIxQXF0FSWTN1WkcvgHDCxhjJS2mcxjXwRJ5a0d1moYW6n29MQIjXehiZpPJePrE7xnK6jxqfI7HGPcTesBLgUAxxeztAyEXOdG/R7VenvRp52s0MFn7/PiAje7GlC0RGVklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwsPgtteMzJa4nKsHJfHj/MWEdvBeejIxX4C+ppoUraAN0PwnujqDeIKppcl+de6Ht1FdYzwh6RJK1kkXfxZ1EAA==" + } + ] + }, + { + "header": { + "sequence": 4, + "previousBlockHash": "17D18CBE275C4EA79045FBB9A0152C81C5BDAA792D9412BE14E00E12B5550FCF", + "noteCommitment": { + "type": "Buffer", + "data": "base64:0BqcEKChkWcfXhBfKdW6MhM6MQRy0FoFf1erPAVQ3FU=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:Y19EIjCOwps4v9oLCvj50uAqdtqFSeKa8Xj63zIpyIk=" + }, + "target": "9228823284279306817296266184515742822248210830185427859262273659833347", + "randomness": "0", + "timestamp": 1719441718073, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 6, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAm1c920uLO3/jJmQCI47v9aMbzLLCyH8K+QA2e51OIWa489yxqWBZlY1ftJv4e6rq+kjzI1Ku3pYAHj4pzE6H/Xunvvp2CoGYJA1OSsOYFlKzGpNIf7Roy26zLwp+jevTRc9ZTy3N8+1KvpqWui4Qbuns0KLBsj64bKGaS2qtTUMIJ/VuCkpmftHkTzAYVrGmYArEASuOjnOvLlwThgW7O/gGItUJV07lkjQrm71w0lKtOnOJsnN5xEfwoVFs8OahIp4NATJFEyvUaybmrF9FRJColZ/xHS7q0Y6aI8wQKbLEuuFrcXEtwriK2IjUMbTgMFXJak0HS2t4CQu3vke1t2CI5edDd1lq1jMgal5/K/l4Yu2LSeijdUc2rV+Kd9ZXjod5YnlejZIEP+3vkix1A3JHruU38pvZSct1guQZWymBdi3eqHvh+/gCGgQdlNZhbA00teKkiDDVPAS72y+pwnJP5XasbMdol1YKLkjK1xDtl6IJc2cDBrmoqiruC0kNIhyp4qFRLC9pvJtk9I0n7FWYBYwYBfEU958bpO3avxxZ8Qqju4bXmjy5r8prYpPAdmWixHqpwo3+i7kVPh6IqEmlMNo47fkqLc8N9Df7uqtDQ5qFYze6VUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw8WS+j73JJrv0TpdwwzTbigj27kjmsDVuLwjhWJxG0ut0MPLWf4Ihcme7ZLdzipDDuh1eRmeBXx3h/RuPmvH0DQ==" + } + ] + }, + { + "header": { + "sequence": 5, + "previousBlockHash": "5B39752EBABBDA851444F03E035BC0B6E04612C13C50B82A8CCB145361AAC51B", + "noteCommitment": { + "type": "Buffer", + "data": "base64:fR9+wSJRKfKxT/12apfk0tNAgy+zDinHornWgrFSFQ4=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:3DhppDVoL/8nVjdNcxebZOU+iEQrpY7LDZs4Z9HeN04=" + }, + "target": "9201866281654531936596795386791503876274441021197252859723586932895305", + "randomness": "0", + "timestamp": 1719441718552, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 7, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAA84sgWcXoPfqmoR7nHjM155OIkQqj8zxt0TOatCy+KAmYlhquVcZjNKiSWHH9Sqrg2RAcL6Fv764HTdxRq9eTG9ofRyrR5B0jCEAgKruELDK4fbgw/w7WihKUtmVeoi/7kA5trExOzUONhHqC6DlihZOeyyXaSZsxTWOlMGP7t2QK8WplmnZ4mHfrIhDFyn0QJfgKM9MUD+sDESpBLVE1lhXYf6EnrACz5oDAgQ+EX0er+4pugnFW9vyZWwIR0a+8qF9pYz+Hkk2zWvZNfkYjMMrIa4hDgDTOlEdlMiRmry3U3gsKGk8fMoSmKW5Hqdip8RkzSpQLpjHdtxZLOj9scrPnNQ7oly43dPx94FWQ4fL7MwHAZcI5dz7Jf9xnF6Ru0J9D2Eeh2z099QMVQugUd9ps7oUz+LOMcLMu1cdcC2U15hywzkJnyDb8M1q+DIXTdOqvV78MxJwf3FZb0uu8FxMCHYkCLD+n5mES4+lXzARVKuPGJ+EKnfITmeoKqylaCuQ2Bx/Xtg6QscKwSCDhgAn8aEQJQU6/GuwBvJ7vl9cukJ7JAqg/IoLkbRyLfq29s/0BTT+4yRDVY7JEoZfNsBQWL0aHh3XQB6BOHNA3XrkLJY9Ow4EaUElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwHKzxAbQx5rHwq9DRAumevsJceAwH6j0INM2nyXE0l5k9vMWzIiA+QRxWb/vEbg0zUFCL4tmtZmKEpueHOUPrDQ==" + } + ] + }, + { + "header": { + "sequence": 6, + "previousBlockHash": "2E9D77A3CD1594D60F226EE0ABC1C3D71DE2E5F37EC4F768B438CDD865378B52", + "noteCommitment": { + "type": "Buffer", + "data": "base64:AZ9SRuU38eL+Y3fG5n+4ojeU30otj/iQZL6ToiPEHi8=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:3+eSpl6evErbkDzWw2g1cwEsVwpHL073Kl6lwvRjMJA=" + }, + "target": "9174987784651351638043000274530578397566067964335270621952759689537226", + "randomness": "0", + "timestamp": 1719441719027, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 8, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAXuppMbOuX1P9Nb+QEj3LUtC20xc1z4Y7hGdhOXteKuaECo5jbIGFOGQd12ubGWqlkFf4kFHszm9u4I3ICVKIvpPqND5YmkXij5qqeNEgwgKC55tSykuv9eHIM3fHaQMgzQVhlnrd6ifhYCit3V6JFa0FrxXcviSZ19uuiVufFO0Q+Rsp7nBYSc3nVIDTq0PQmxaNrwrWOkLGwFBmvknqC2LzLKIs75Zbqo98HymeGPKQ5mIAwPzhoqf4/oqNS2hwozrOrFayLiM9YJrxnsCII44iKi1RSfYWa7kiYxqnpDREyP/uwaX35Q9bnu5gkzac3d7EUHgJjhZPCTux0uRrRbY3eT7cJny9NzSvMK4mx2r5L/2ViuzKme9cdogZrScaMhHrM18mpNu642M+DM2wM+hmB1X3gk5zOhabQoyYg9MKgWTIydyq1BWvqooeqEQUcNt2UDR0oYdmE8ta4bn1MUTuB5B+bBHckDe8jDRdlxHuWlPccw77A8mjFuDHoT2+u/KKZd4vpGnxqIKs3vv+kDvN9zp2dRQhJIFbCssld1jIhFVS1cQEt7W1+TbkPsGlcjg8X/b0PSz+KCuNEHoQ2sYyxXOkdTOwJqIlO3quegpu3Ds0+UcM8Elyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwh9ZL5A3gdeb0gUiDRfzGnIXygpFPj/BBlRsTuIa+9DLHVZ9C7ckg76VIIDsdewZHWypZOnKirTJyVTeDoclnCg==" + } + ] + }, + { + "value": { + "version": 4, + "id": "e456bae9-7fa6-4bc8-a07a-df3134b43499", + "name": "b", + "spendingKey": "3255f21950748d71ebbf2c076fc83b9ce7d0a36bf20f65434f59dff5710640f5", + "viewKey": "c42287b519e46eafbbb030babe8f51ce959098806661a3ed1835f8bcbd726ab78414c529999900bae72e13d829c6ec915982445df1fcaa7efd7c393fa88d0357", + "incomingViewKey": "5ba98e55e02563842dbe144f53295a69befdc21a9295e606f66a068dd0063a04", + "outgoingViewKey": "3e8256d8194cad6296eeb0efc3b4069b3eb6bae6e433923a65d677d077596224", + "publicAddress": "77b8690e1d2306024d5c2d715a61e959d357799a81ebfd109f12257515eb9d73", + "createdAt": { + "hash": { + "type": "Buffer", + "data": "base64:+pRJwuyUK5S49lKeCQlMuoe6W9+noGtRD7+S/PseErY=" + }, + "sequence": 6 + }, + "scanningEnabled": true, + "proofAuthorizingKey": "0362ef3d9cf083545988a4229b6021f77b9874795e6142b1f01c21cc1a61e90b" + }, + "head": { + "hash": { + "type": "Buffer", + "data": "base64:+pRJwuyUK5S49lKeCQlMuoe6W9+noGtRD7+S/PseErY=" + }, + "sequence": 6 + } + }, + { + "header": { + "sequence": 7, + "previousBlockHash": "FA9449C2EC942B94B8F6529E09094CBA87BA5BDFA7A06B510FBF92FCFB1E12B6", + "noteCommitment": { + "type": "Buffer", + "data": "base64:wJvBtKKtiM3i7C+pOQw3tOjSwKpAJ0B1fLQ29S08N1w=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:wpt/AHXDmcSysIT52HZwG3R5Fb6qXd+A38RDFLVT904=" + }, + "target": "9148187795366513087508709149025146424715856256637674150531751753357577", + "randomness": "0", + "timestamp": 1719441719496, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 9, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAA1aD62FhUOYX08jpTsSGet3Xw+/WPICIfF97I0ENKeWGHIqANRp/qcVvJ3HfYCWWvdNXrDdM9GU+oISWfuGXsqDwZz5ZkeGXyJV+9jX8nn1+rJ3wqzVmpdFXPArMCvIkA8b2wWIzG2Gtp/h7oBTkF2c3XBV0TFp0JXmdSfsl6L2MMqCOy5A6vIAPTIyvlpqSRN05wM1d5iz8yJfvvT2mpSD4syggBvH3PizIlJARWw8ezd0h/PabLS6mgNSdy0JGGNe8eI+ViDJNbpaCJBU3BO9FIF7zLTrbrpUslXdIOj0qnJGd+mjV5NzufnpsCcJ1TyitG3RzvoQnucWEriCHq2Btz5vuX1KuZjDowe1LIMRqtMyYO0tH8+Iy0Hg6YXgtIspIDSjkGAloto55Z+CVgVuQJEjiMU8DGERB4bf3h4kuC/da+JzPCPfcTh9W2Qphm+1C43A1lkIJlTScjAuFvcaRfVuragRIpWssDL6xkgoyT1VjHTMs7+ushaLGAqz4pq1DntKQvASh77UZVQH2N4keJhYmuIXdwkf7Fxe/Eou8uqs32Gmf7Qmg6PDIDNKptEeh70cwOkKrUPFU6ephodisM2mBnQLTo3YSAqByeP8gDfVXTPUTcnUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwe/hyyBzA4hnSsCXpBnk09GP6mRkhhBpOtANmUldRXJ7iotke/xgANc19FA+lTyojHHduyzv72chwzzplWjgJBg==" + } + ] + }, + { + "header": { + "sequence": 8, + "previousBlockHash": "310A4EA8214CC2537225A980D0DEC08BC9A8A9831D63CE2B928B06903F8A7B59", + "noteCommitment": { + "type": "Buffer", + "data": "base64:o1UlnyKvu2N77NW8IkjtH0dH8lr0nZnqhA+cGwkurxw=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:qaQSGOM2f+O+IQnwWwTephTeKSA1/CCrrQmdtuil5SY=" + }, + "target": "9121466311864876128923245652724724632104869735746188813030060672759072", + "randomness": "0", + "timestamp": 1719441719966, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 10, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAoOwj0D3ax9FG+clbD7etJj5uTK5MiID03p2Na1JC07SDCYd/EVLeRkW4EqnedD77jWZNt7VvtGPi4vnTP8vcy0G7aPA5RL0A91qIZdrqKhuSyu5wVdx84XSAB8hcm2cLLfu9650q2aQZNxXlx3uheRwxOENo3oGW40ZBvvREWrkGjyIdUL7qUYC2QkN6u/bR7f8IMg8rKz8EpAUF2clTrbLI/FTR+ADe7B2V1nD4gKeYcv2nrjjxzdW/nkJxJGfD9S76UsCjSiQB2Oy7w2BB+mQVEHozdf3kC0SSVQ9xDYgI8/OV7oYj3nf/WEqWZzjQhk0aDSPcZJmHc15pesL1NJ0e/9l78g7MiE40rsHc1bCtzTLUCmUn60NO/tlxiu0eIWpBme266FomnDGC1JEArdyw7LCBmLKbKbBvYm7MW44xGPtqOUQ5kK37ny6ZVNt1SIEq9KZAhmqKtWGzP1a5mu210axjLiP4ley3/qDrWI/sHYJfWYQiar2yH55agQ77agxqhGXDF86Tpqu0SJ93srH32DGEsaex+ocTS9wmRcmEoIvGaiamKqEiBRpEH3T9C5b2UxKYpwbqutHJRhgXM7uZ4QUiUXdVlMn/EQGwp5sISQAUR4rgwUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwvCow5y3rRpVL2N1EBcSDL9A/Iqg9/ChqFM2OGwgCAXJ/GHA93wZdyhahefLwTobpHAUjIcvx8bjtlUh0X/0/Bw==" + } + ] + }, + { + "header": { + "sequence": 9, + "previousBlockHash": "D3F62D4AA18D107C962B87B0334AE09C65879473148623CFB3AED58BC7E207F5", + "noteCommitment": { + "type": "Buffer", + "data": "base64:cYtqOqKYIXJxWqNDoAe97uJzPq9y246RZlCat3WrZh8=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:BF2xeNj2jEpOOggwo1ZnL0GqUYJM3G2hV8oDN0/+Znk=" + }, + "target": "9094823328238119324660168503613036415495463326164889575918026009508991", + "randomness": "0", + "timestamp": 1719441720458, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 11, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAtIiNhGQHI592BD+2jwj1Hux4xU/1MQRUZgJuYVztJIODD8v556Mk/6/4S9ukVaexxVrIfvAYTROVMcb/drdmU/wul3zeHT3ixNN0lqzEABiEcpTRZRhVNjDmlSmE1F6RB8Xmdjz/afkGR5UB9nnzHxxguJUyM+2PF80dmuiAdmgTEyYhesAfl4o7nkKPABmE90st1gOs7+zIGyxc4/fQ2H0w9iq/GWicrdiCOcFJ+V2qzkEQRbqPPUnZnBHjINDeVUCAnzhGxseYJwbdDMytR+s58eI44qC9to/8FhreTWmsB+VQWHblCbOsMHHGQ99V2dBPilX0rqswdPB28KE5Z5gGXGltQ+PJeferK86c/s7EvJY+IF1CrPXTzrHsfaktE8D8+Ol0twKjQUE+Jk9MDggfQBJ1MMq50O6OIAt4dtXVGtc0HaFZ6TQBSnbmpzHzMeIslDuL1XWw/QmRzvzTb0WL2Bl6bpu1yx4MG0DKfKFEs529HOfZqYPaeG6VNkwFwPOKIkjo3czg9fn5SddOhr9kgtSfK9jw8j8o8NUZcKyyh151a8t9UjNBQVwSQacHFvc0mMdSOJrrvaDPFTIW+8kGBxCCNbFcfaqyvO+10ktxMTq3HOFp7Elyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwao5gAd6MisvctVeYZ03+D5IQh3WLQo0a/iDliETlqxzeHMVgoT6BuA2WpoF3kSXFs3hT6Qva6OhyawvDl3DlCw==" + } + ] + }, + { + "header": { + "sequence": 10, + "previousBlockHash": "53EB267C5DF1F5B5072C3159B66F8D1B50CD168B375B59E3FD6E6A7BC565D490", + "noteCommitment": { + "type": "Buffer", + "data": "base64:ev3+y7hDnHIyE6if3ebI3ghqYLww3T5bXm8n7eA9uDw=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:t4ybCJL2S4+VF6crnGawfekJPE87oU1+DODUqlvdRPQ=" + }, + "target": "9068258834662928698220540790897658244352076778286486653826470223999191", + "randomness": "0", + "timestamp": 1719441720930, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 12, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAE6GygXOf4j5BWdT54nOCh1LUxINfXl078ml5S+oGhU2wx7vinzi0qjBA5rNzwjLbTqA+76y6A9p0kiC015v8f9GmodXeBtIYgbvgoHVJH2W3s4FYdZvB1EOSuJ/tAmcLQPFR+0+yTwVPntIqRdcP0aeeWYDYYJQU5BeXQCdS15gOsREn6rTQBE/s4SN71KqX6/kfBXB6dDOpxDiyEQa5BSkEn6gBIsXUKiYgNd+IO42twxIGxhtYyhe6RpK768kEij7hzkdxLX5iCVNPieBoduZWDlj8S+L5ti/04TRdvFCP235VW7NhrNvptyi0sl5IQnQPi1po0gkIBg/HqBspWzFnzs0YPCrUYeny/jbSetdvBgW0adGw2yneLxD5STRvtcilpInmVp/r4pdn4k+dRckUPcyPgMiLx4xoGdr+88IvghXNortlt+4VspSNgWdLjI0cevUfkXTfaJABcXZnlZOTwiDyk1+H7IJOHJumfaYGYULKGG2TAVbdUi+nedQMEMJS6Z4SSsiwdsiapeGPQ3WbIgUe7DWPxXEw22mnkAYRqaXt4nzvc2IaEXLTcJLYqSjMHRCE0Z6qewZ1jbzwxxTdQ9DHcOXyPezWm+Cfe2iPYDs0bjEaBElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwSIDJaB3bHEHS7BP8+JxkwqnH3yDLXK1NCBN6pT1RP0MRIlqm82jKO0lN5VOuSv8ikxtE5Fj5fS82EBnvrPDpBg==" + } + ] + }, + { + "header": { + "sequence": 11, + "previousBlockHash": "4A82EA2E6B86275150FEC2C6AC1FDB1A2262462DEDFCE722ED151E2A5D974A76", + "noteCommitment": { + "type": "Buffer", + "data": "base64:6FzMIVYGtIqhuJo1jE5SdOhYSqPvEoYdiFtHCNei3D4=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:wmh124Szjs67KYcdnrL53mz6/+x3QXeiEqTSs8MxNYI=" + }, + "target": "9041772817458669358631436925553476123971485443441062513642264290171806", + "randomness": "0", + "timestamp": 1719441721391, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 13, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAGo2d4Xh7XjUHD+Z5PP/YK1fMNt2Rm54fo4Ur6DRViteRWqVhbLy+3PbLLA2r3GuBThxhgcK7rv4plClp0NJndKoYWCq6fMzOo/Jp+W/YGVmk1q9591gptLOXoO1dpBYtJGHDwvNEkiEBxB47pYYRfINPfql94z0W1M2Sro3R410P9+pOwQ9JYdWmWSnCl3txn1eEmYPNVPFcGbsd8ZzhOhkIDV7qSTCAxdoWSAKYiNawFC/sRCxGYWHArMbTJ9aqCnNAy+OKd7xokz+4XWNEVuncZFUSuEJjrtiLsbq8qUS1PFCeak6KBWeMo1ncjTNLQ2RCQXnqlQOud4BjRIsN7nMyOQXr/R5LUf7OQ+wfWmiVsQbHBfAsss8KIxN3lUZny2voX9xVxStOadO6ETC9KbMVOdmVKpVwlmSd0c9bEGVaRBGaXNLTeLHxLdpqgwput5rgqgwMiFQnprT3snD5e7tBJ/yrWpo8lPuSjjvJJOace6d+Q/1q8vkcVFDDzlLTIDnb5h1qygCxfZyZW7RmM3l5HcLn6vXBUG4JaKC2GW1LYAHdCAMfhIIdEsQgRCl3jz0s6g8r9Ao+CriifmqaWuy2hWwmTHL2Ajgb6CTT4spj74tEHUf34Elyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwu3yIJiuBIErbZCJyytdbtIVAotG6Ri8FaPKaopuUp+8PlMMYf5C1CGqJ7jYnM1XEGf2Zap6VhPbpSsA9sa+LBg==" + } + ] + } + ], + "WalletScanner restarts scanning when accounts are deleted": [ + { + "value": { + "version": 4, + "id": "5608f677-7560-4083-b0e1-c0a3bc57925d", + "name": "a", + "spendingKey": "dcac9d1a7fd7dbfadd9bd43ab3685aea9c5b3b74a4d7c9ea1cf40070ca7fb998", + "viewKey": "606e9b1087636b5c49fae5c3895de7de284e279c1f483cee1cb8aa61998697a8159675e7626ba5b6e72571753245a163b67912c632c1865c0ad5140f9188740b", + "incomingViewKey": "a7c09bfaf0cf05f6612408e7b7b8b67b10a35bbe66df052af0fc0cedad26dd06", + "outgoingViewKey": "792733ae07f1adc6fe9937578ef5c4c62684a11a3d5c49ee74554996fddecc9c", + "publicAddress": "12ff1c08a13d088f5a32dc32856c4802fdcd456d249bf598c1c862bdfc512107", + "createdAt": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + }, + "scanningEnabled": true, + "proofAuthorizingKey": "8ed1d285981ae911bcd04fbcca375f5e4ca9cfa556e98a6d1645ecef721b6308" + }, + "head": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + } + }, + { + "header": { + "sequence": 2, + "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", + "noteCommitment": { + "type": "Buffer", + "data": "base64:CWScPwTfahtcIMboVijiRAd5hMgWKrjBrcqXOcyYUTM=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:kuoQg7iqkHOZbvaPo4S47KRDH5yAp/FntwfS9Qip60E=" + }, + "target": "9282972777491357380673661573939192202192629606981189395159182914949423", + "randomness": "0", + "timestamp": 1719441722383, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 4, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAZnIqq8GI+k1soBWMVkwTI+IF1w8RptHRWvDsIVXv1LOSG15YUnoylKYevcaKzyEV2wxE4fxLJah/mZyejjt1h1D8JYrJI4pWZ7PZP24uHWOGJjtZfI8xo2ci1FdHJbaDwXPRaQp/L+Vh4dkvu6pAaia4A4TNwe6p5kjt4PZOuVMK0XF/ZYaHC8AajbbqWlQ2W9TNhwDa9UTD+jLExW1DF///HKanqNVsEkE48orp3sSQ0xn8j2AoNsvjA0NHY7h750eUv/JrypqZzxGgGlK/Uas6ySweqZogvmcevTgZTEjYtrVK1l7ChwkK2fKWpo1Pn1Lg0NtNt2fqeaqcZJCy1V51zZgZ4GcG+SMH030h/PKPf+88FMHk4W6UDVEGBxRqiyDo2LzrWI5OtACMX7GWjVmXREdwYtcVWW0akUdUHMWGHLiu2LB6Gx6VznR+75ksPpBxGWB0c+/B4ctP+aeAhtvCPGZR6w1ILh1QnxT72rmn1bfTBNsJ8nnu+zml5Xrfzg6/4XsoZryqto6BR2lAEjilGdHzidQvuPnG44WPHEgHbszzRucDs0Usk96uV3WBhT+fJ5njuBfv2HD04IMJpHdzFEANjzggw3wi1jSHqUkltjsR5xX9xElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwFSb9Otwas5kPt7gNIWpLZ+HcswCkTmqOjOZmWm7SjQRSV3u0wU5t2gIgnZwz2J3ghl6TLwziif1z0XNzvIfiAA==" + } + ] + }, + { + "header": { + "sequence": 3, + "previousBlockHash": "466643FB4B18A594EF5DBB72ED5B4BF5ABE28D2E1EC1D21751AEE7D51FBFD15F", + "noteCommitment": { + "type": "Buffer", + "data": "base64:zyTGIUK6jeU1Ir1DyS5BTmP3ldDdnxxqTI4dZNkVa0g=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:LFCORxJMq7CzP89Fk9vHv5iBkgXlcetC7lcy2zUFi2Q=" + }, + "target": "9255858786337818395603165512831024101510453493377417362192396248796027", + "randomness": "0", + "timestamp": 1719441722848, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 5, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAB6XmNKp1IY1aEURzAqClfKG/fy/G4zdecGyD2x+B7Kelb9cDyxG6fMF21oVZ87u44EfCCKQDjrVvO6ORC2aSOCGxt9JHO+DJrmL4HGJqAwumHFVtVGgO9p9Er/p303UAB7Az46NXKB1+8sE43C2bNNhgvw4gYxgjU3d1PqZqs08TaQEJLLpX5DU2xkAAkUfhDGkl3w4GsgiCE6wcjNLHIedkqnmNPnhrLUeqJCSSut+xraTLuKPsFj9F9eBNWlAic4XcT4XjG/iK4zvY3DMfTKDi3M6+zpqNDqWLU4fMY1afTr42eqDb5zdaS898Mf67pML/5agQ6gTkhCDCSTcWOHrpyEJVduXbbarmEqoOAVjStgpz7bT2x+jFwcc9+WxCCBoxydOWK1oAABatXfPp/L49tEqp7laroroRjhsDjCql3ZkIxgw8itbXFrX61Bc2/KODWhhbwT/GPwc8p9kzPlk0XCTC3FroB9ZX6A6b/gl1VExsArUFNk2TRqfKqZjuB+3oXCKZiKqQ+k5QJrYwYsuHCMZfeuwzLaduPs8XjuM5rkgLAEPtVUjPNWd66KXymp6xzcF2jbBOGED52luOjRwMe58wGoKYcEGVw9fCmFiBU53pS6nvfElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwBbOg6xkDd2TUpT7SGMFhk7mVfpTs9qNVhPvgkmJBG1O+Lx2kh9m/ChxDDn8/KgzIMyNkRFr6DsusJF3EXSkAAw==" + } + ] + }, + { + "header": { + "sequence": 4, + "previousBlockHash": "B58450CD35422E5444F91873E650DC3F2CF8E786579285BDF92C55F6D6E08173", + "noteCommitment": { + "type": "Buffer", + "data": "base64:6qloozS5eLcmWGvV+SkTYcF5t0xSQVv9zk4Q/GcP7ks=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:bOgn8i0XizwLH4BR6KZI68hq/3tF2XIZkFzXXutixwU=" + }, + "target": "9228823284279306817296266184515742822248210830185427859262273659833347", + "randomness": "0", + "timestamp": 1719441723332, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 6, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAPlTDIPH+5KJOavtB06clP3o926BhqmULU6lOcwv4+xKArGOM7GDKRSnUNrFxzyC2TlIcEHckCBJ/1o4CKyJyEjPA3Z3E7A56Yw+ho4TPdUuQftQpaJCIawzeno96qTDhSpqfVVK7SHiYLScjTLyManq8b+KFBeO1mK8M7spJHPMSR4sy4ZNoWO16DcKWR8S0RAaRE+HWarUzn8npKJ5SWDRy9G1oDPrmzJyPNZd902uR65bvMBzSPsuDQ0psttmvbDRuGizinxELPAD48x/uD0yWPRNVsz3KsZIoPteRyYKa22erA8L69d0FYPpVuNgl5Yh5hQ2F6cUz9DJyOuUNWN3hR2FC0I+NuD8CMQC9MSJ0wyOu9tCSEWFNaWHNPlkOu/+hjcCJRBN5EJLIpFuHMUZVcJW4wKJqPt94LRIepAFHzSPVOy0qsgufLXIc9QOqk8csuJMEv+iQU4u5PaFHBihVvUwS2fIWE3xT5LsNFC494509RrNQkH/Wk2yj+UotZn475ZcNpDyhsUoDSZazc16O3ojcGZ3WVAHvN3/qi0QqV4JILiMcxnocyimS5JgoB1yaeMK2bGWkND6Bw+H+z8eBWnEWEO4dXEZWx5ymRVJOX06UFa6TNklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwV1zcPBDJn9ojn0ISFZ/oT/1kYxVbwU+D5ZC+aP+tj4NaT6ZN4n/5PW1OG5OUpfNgnr2KU0VvBOvVtYd2tPMaBg==" + } + ] + }, + { + "header": { + "sequence": 5, + "previousBlockHash": "B482FC6360EDDBD188F0FC05287C2FA687583C062192C3737CF836ED179EB8C1", + "noteCommitment": { + "type": "Buffer", + "data": "base64:Wv+VfZYw0Y+eVslZb19l4M2X2CdLiWm05kjIpZ0qyic=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:FRBKSxosajxBo4ELpBQCL2iF+f1Jc8GXYGhzqRAIgww=" + }, + "target": "9201866281654531936596795386791503876274441021197252859723586932895305", + "randomness": "0", + "timestamp": 1719441723791, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 7, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAgcY9hi1n/ejp07obbwNB+8IEmPjRas1IH4LyS0Ru9FilZV+UUZoxOkonNJ/MqV0BUqWCcNPsLN4MW0WUpCTYtQDolVa1p/ZrC4BAXhPl/s2Op0RJw6WbaErKgq9V8s9S9HJAQdBANSEEZzMoiFoszDt6UMdw/yhVePJqegbcGqMTKbxGq7Csw2Q1d4SD/SOvcVHr7db1dIthic13H80+JYTqlWv2POgM+o6vsJp+9HeLSKYGAfCdFZivDyCaKmjWR/uerw3Fd5Fa6Z9B4hgaTUsg0BPKs32rNBXQBs2+42dIo9IoY9vpbvpFfJ4mtMHyEIcQLbhmLaBl+bTWiRC0BSUjtsH/wzRtwyRQjkwf+GAOe5BdlLmUhXFOABp5idZg2hnM3aglQfeSJkvJVQVuBGCffH4XR8fiAYpIRamQwtMFNPHvFc/reY1Qew8WmlJ2zNNo+2/TGz/fQlqyRR4TQ/QBby/LZ73ZGRBj02/6tpmHNafiO/yig4K5QPod7/w1VnSQef+c10U97dHxa5FhR+cZplJfVCHnA0hq32l1RoY9G6bFISazQsZdzCq89OFBl0vZXTKryFPGpcsp2OhJrmY8+lMaj2sPahGnxF0OyK8ge7ptPrU9eklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwSU3pHewJqqCx6vPFXUijDU4+dVQbkUIvFcjjo24Sftxyg3QBH0k38MPHtLE3CtuzDZSMzZbYPT7/lupzKz09CA==" + } + ] + }, + { + "header": { + "sequence": 6, + "previousBlockHash": "92BDAC53C9E46C08D28E7B5F42D873AD7740D9DA8E6671C658E4EDBAC4D65F27", + "noteCommitment": { + "type": "Buffer", + "data": "base64:ymX9ZhiQmvKURrRAWADntPSogpuulpZubDclLilywyQ=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:lQXSmilggkyT+uHihSzAP3A49aib6QfmFoEH0O6s2aI=" + }, + "target": "9174987784651351638043000274530578397566067964335270621952759689537226", + "randomness": "0", + "timestamp": 1719441724261, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 8, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAboCjeRJkAvi2tcNO+D4UJNicmWF0rozhHdMyFknr4pKyXkDINjF013wrOvy95oZcNCjU/FXlRvLHcnfNnh+fe1NL2Y1dUYG9rElI67VRe1SYlnmmG0Rvrs95ObuZTnoVTp7v1qj5r18834JV+4WXBIxWee4n1LCnEoy2Z2t/zOQJPAGV7nrzpMw/xs+zr8bs4GEl+a9VMDcP+foCEVwagTr8iuxdlSnSo+daLAbXZqK0n48re7hkaxq2hNK/zGsPJ1MS+VvQIvO/+nbR6IK8Ev3mr+WY6mX531UIFJXweKfhQzfGIKjtfRgX0jWvYAP1WSa/WH/No+cGD0JNnW9EQxJEQujJyYWq5fe5zPEaYlaf00bdr0uENHPPf/Nm+L8NaUF9S2QS9Emkv+mQkE5QP3mw1klOMYIe5pg51mesXPJ+uCxQKCi4v7b2PsMRGoXJMu+vpIaELQpw3TTt00VlTS7/8u57sQFsIiXSdZU2uWbcYGFLMsaOCVL8FAi8xbizqkCmncEO4+c1BDt4IoJdcCEGd8AweW09Tc05Wyn/93KqMY+YcArebYFKa8Ox62V1T42Fh5IkuPjmXhK7GAzU77evl03TA/VRAuA2BtmgPrFLnXfcCXl9/klyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwawhG1frCkchqhA+Dk+hMmuc7QhhB/Kj/P9PriQwAsghJhUWdWXRm7y1rLsOaEXdy53klgVh598Jlk12bBCExBA==" + } + ] + }, + { + "value": { + "version": 4, + "id": "d3fb02e9-e057-4488-8ee5-776e98a95832", + "name": "b", + "spendingKey": "6b56d56e3307f99c16185bb7ae745a2c5d5e2750296a9c006dd6b8f7bd668d09", + "viewKey": "9125d6ca8bfdee1648ddfeb582e3342dc190b8b01bdf9adc6da7e8729692384385b00b181f670011c76c16cb5e67bfcf5bd9441410da8df7fc9cad095d9edaf2", + "incomingViewKey": "51a727e16a0be7e2b97b7dd528b4231d27346ffc10e01ff95d21fbcf2d042605", + "outgoingViewKey": "f9f3036afc899e86e59114786107175f84c55a23c9c1510e694b3a36e83a6959", + "publicAddress": "bd5031bf9cb4087f3069771013b389ea777cd9239fddb51a336b81273f044658", + "createdAt": { + "hash": { + "type": "Buffer", + "data": "base64:DB8f5WPbF66VwBmmV7BJ3g/M1epyx0+0vepdatNnVwY=" + }, + "sequence": 6 + }, + "scanningEnabled": true, + "proofAuthorizingKey": "17293732da2ea50bedb20d45d87054bd8a5612b989f82b6c34e09c857c585304" + }, + "head": { + "hash": { + "type": "Buffer", + "data": "base64:DB8f5WPbF66VwBmmV7BJ3g/M1epyx0+0vepdatNnVwY=" + }, + "sequence": 6 + } + }, + { + "header": { + "sequence": 7, + "previousBlockHash": "0C1F1FE563DB17AE95C019A657B049DE0FCCD5EA72C74FB4BDEA5D6AD3675706", + "noteCommitment": { + "type": "Buffer", + "data": "base64:N3ATvm8lufM1rk6wyRWgp8+BM/aVcpHsvGz2gJ7kfxA=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:76y+Po/GE64VvnutdpKl6U6B8GqPi3eBb6tZFmRGkYA=" + }, + "target": "9148187795366513087508709149025146424715856256637674150531751753357577", + "randomness": "0", + "timestamp": 1719441724731, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 9, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAlSavJP4InzBX36z/iM/PlcD/t9MYWTVQWgL6qgLHaBKEX0ZdvSdDwZOEkAimcbkmeJkyhcbBxv38bS4wlhhlPINKRWShGyrkkx313CEImoGGpPSbklrqORWwwL5j39WWrOfgMm78NkkkAsoiYBgy8jdW8+uD/5FW0e7XoYzvyGUX3M7OeFVfaaJY6mRTi8oSBezVZyAevBJl5a3vsN7QyZRXdtNT4fQd+Dt/zDtBe2+m7fS78GTI6xKkvSrHreMscdK3/gUOvDibX64BhQYAmNS+nvY7/ywapHngJuRa1UjsaOm5/6vKV93Njx4mH60NP5Ld3kignMVb9o6MEeAfwLLSMkzxwVNASydKSwTfL1M/aIz0XeOoODyEAcPw2D1UeOBYf0Lr7i7wVvniV4XMXRMHcTGdo6tdRy7LvV6ziogmHFPTd8Hb7ovGINqots1msah+kCPs8JNuhdEuinFdsi2ExUAO5SX235lENWya8//aRNRti4IuA/P4OMVMpQ2TPhwCEa1zP0ds+vgSUmzHghazLLPRj2bdrQPvmKkEK6WG4UgcPUDsCNlsQmzSHZn4RVUQM3Zdj3BxklKiqFqWvh9q75/41g+r9qzkEwEUjEvK2Iv6uG0DBUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw8GB2r5+jcduJ3AHZAccMM/gKGcxPuMQmcovNB9efttPsR6he/57tprIY0uRySZ5aQ0mzHhYzi26R9ki8uiiuAA==" + } + ] + }, + { + "header": { + "sequence": 8, + "previousBlockHash": "9BD5C0D1F722DE36579E2FBE9961B5E1A4D2C3DA6B77C5195450FFFE7CA6E7B6", + "noteCommitment": { + "type": "Buffer", + "data": "base64:p5YfW0brP61LtOloOp9jgWexJy8oNt/KJ3g6Fw8MJ2g=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:HCPGx500t1evPWdtEc/LncU5TAedjob8/sYhK3RbIvY=" + }, + "target": "9121466311864876128923245652724724632104869735746188813030060672759072", + "randomness": "0", + "timestamp": 1719441725197, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 10, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAArP4v5qoPhEx1Ig1ccVMB+sStk1ZxSkn+QTY3zSYickSRv7SO0KlXsci//yVMyH0Yqu6oLmOYFRAhhwOQPu4H4HhurAIGux+ZnlXAM1d7CaCkNO60wcOGxxo6nSTqblg4Yg5TTY4m+y9HBuvjQRvdBmR1TJ214Hq84w1mnjL+k7IPmmujJLPsZtTarlJt3UYebNMSLtqPqabUy5emWwcKNUD7P92st8vDZgxutrXiqM6lhkQTL7r3jeCngaekzkbH89ZwKVFoBIa7AR+ocVUmvBF0Wi8NtFt2SO42qzWufiQx+hcezxKLTtYFdcOJ3DasRUp9cEPv31cPw1sC61D3hOVpwLvP1P9KU7u5q6JL9uIW3vfgPBi6Us1HBOyGAR1bjlFolSltR306ys7hXrJU7py+Lmpyeiy6tEycfUuHP+r7ApnHKSqW8k1sqSIxzbX9vY8AjYNHdWp6bwpSNBn59AaxlBejMY18cTI9jCL1OJLbGi46Z4PvYzMnKPVixHyCWVkoAAnmkKQsGXGZBDrY5EYRXfERxkun4mrzo9NlFr5sOiG4TWfsz2B/FQOJRVLB3Mx1HIHXJ4LP6jlP4+VoYPcvRMneXvY19m2jhTmz8FggcHSdzPG5QElyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwkqi/ZSTnMp8qNRLXx55SbglxuBMIxFoylHDjfnDxQTMepPKUCIPZrZAUUdoVp4apCz43/7yZ6348ShDR+j21Aw==" + } + ] + }, + { + "header": { + "sequence": 9, + "previousBlockHash": "6B4D69F0949383DB8FDF24297DAC2425532007FDFD7A25ADD90676435BA1D86E", + "noteCommitment": { + "type": "Buffer", + "data": "base64:vDbEB8W1fxR5mChrwiqsiO9K4fbk1By4Z9jpMz3WugE=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:/Q9bBFoh2VEVU3hCwwyEeO2ApkAxEJ4MfvsxVDq9Ftk=" + }, + "target": "9094823328238119324660168503613036415495463326164889575918026009508991", + "randomness": "0", + "timestamp": 1719441725665, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 11, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAfz5rQhRv2LBNplPaQ+NoyVfp06EWxT06seFXZOF++1S1iWKU8HyorFHN9Sv8Ht6MRTlL/BJH5xlPxk2Q7uJGUHvMWNYrYpfn0VlgODodVqC5+M2qGyrvKBdbPl0m9QLjpMwMerjGFQMsPgSTTUClB3nAbYF9lVwnFE+9EPXhQWwRBY3rlpJbZK1sNgr8suuXm4KJ3phM/ADfxEbwYkO8S8stBvGAYRQCxBTt9lpetnS2opy5lRj1mcDisOqbgXNPZWhqHludnnr9Bmt91c9KmbJwJlSyTVqtOJ4AEhoH9SJLH7rs8cKQCkJvmbGsjW4VGxraiH+/X2EjT+IEnE6xCBcTc+nqiwo4VePsgc+ingnsBw64nTGaAQpGnwdIqb5pAxIOm/rrdpefaTl/60Qmy40/KnNEeM6wLWu/gMwLsioSCwu+FCBqxtcANgpDfPjct0xjEHkhnJmMPgXKdq1+6ck8HWYY+EYWJ2/iE0+Hl6j/tnQITJQ7N59LICPv3ZHoyMBzh/IGwD5uQOb8JbELwe4Q8Sje83FoDaxNVoj0s/c84xBqO067bsBh1QkoxftJKh7HP6XcWRCL62VgsA9UGDFOhcZ+O0HVyvPTTmDC4kcxl6XUUpk48Elyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwDrM4b0FM0s6fmfR6ipUs7INRo7EsioJr6Xyl75ONFu0WvVglWLtZS9YgjLe9iKsXF2AGORwu/LTou2A2L0nZDQ==" + } + ] + }, + { + "header": { + "sequence": 10, + "previousBlockHash": "62A65BD939DAF14EB812793DAD1D68A266B0BCFB28C1AA9F5515AD0587B278A5", + "noteCommitment": { + "type": "Buffer", + "data": "base64:30GdhXpk+n+fdrFVsXASqdE2WONKm/R/nrN4Vz3mpkk=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:Yj+qdmmsGqfavNNYPMBJFxm8SSQAOZSRxHm9FtlfEBw=" + }, + "target": "9068258834662928698220540790897658244352076778286486653826470223999191", + "randomness": "0", + "timestamp": 1719441726164, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 12, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAALPlrZRN+QtSZwyPJLy8lyUnHIvNRT7dPZp8KCxZxIzajyEKRYomauhJNnI9RqQCe4QuosEBFd3QufrhusPFx9FK7AsKGs8Mc1uOe5k2vg6eOLVTjwAnhn7k2Lc39xmpSvE8ofKFOPGai+PFIBuNx+aJnJUVY6hhP0v/0ENrex1QBxThKWyBV+4+vTqSWCXTO4SBAhmnXtox6wK1ZOmaq4HJqimB+fP31e2VBY5sFEHKCq5BuoWQVgCY/1PsU71LLJkRmCUwYgAWLfTwVfF0EwOlSVs50TG5W/rhE7gjzUA7dOhN+4jiUTlpF+VbBS6p1tzWAgfSJtyBjTgA9Bbc2hR5aW3WitwAzJvBvVB4v43A5CE4OFEBSFK/LFyieCfRguWcu4eTjSH70QoSC2oPArO0pFicRipSTyDCRcJgLidBPWVjwVnzpVGZAeZ0tmsdCf+m27orjKo7KWiWut9gn0YFOZwsDKyLWRKTrNHcgCWsysFYjM06BUC5Amn/1BvQCHZWUgi3IFFJNiELTf9XnhTS9F1XnJjjZ2HZWClSQnhT2W9x7o29v1yiv/gfZg3l3ntNtF9IRMe2Zbs6kDSk9A6EyiGHFaWVuRRZTxy545FGLR+J/d03dHUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwyQwNLQepGN1OnDu1Muhv2MqHQ4xFe/YRgZQTNXmGtUOrbJwJL9QPT/Jvd18qPZtuE/Q998PMgc/Ku/uUnAc1AQ==" + } + ] + }, + { + "header": { + "sequence": 11, + "previousBlockHash": "0697AD0245CC3C719CF76286F5C3240C079739B00010E8F0F56B33EB7F115422", + "noteCommitment": { + "type": "Buffer", + "data": "base64:pTTTACel4n/TI5E8pC4OfkpmN/EGiE6uCOF7va/nVFE=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:SN/R5FVlbTQjQ4zdbX50e3lYih0ZJS34ZANClBCDSFk=" + }, + "target": "9041772817458669358631436925553476123971485443441062513642264290171806", + "randomness": "0", + "timestamp": 1719441726654, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 13, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAcSX496FUPqOo4TjxtcTJqOJRxy4epG6ODKzmXaPDiT6tqmamSHBb7AUPM4Bt3cE1I05zqNs+vNQGGskW/gkVVp0JB/Mbfg0S/Q9fHx0m/fSA2LwK1kPnu7qAl+QSToDygk0h8PFn5wCh/TCN83X+VYEtSS9JStlgHHmcp3RTOCYQ5OEsn6ZqAiHiBMbvN7wQ1e8ZCoMU1C7vB/bhahqh9XhfJxuM9duvpUzWf1ABl5SK9ymQw3Lsa7pOw6BFwtl0ZzK+L136imutpyTZ4IMDT2RP/UYFAqQAN3r1DyZ9z+HeyOKC2ZWiJ8jjuqvCcANG62WXTQfhqHsZ+6DhBTb9n4KpxqBsxx4afJz0382XxCRRAlu2A26s0NWtUnFH+05HF1Ho2rjojh97JR3V59l84nCWDJMrO9aTTFeNbG01fSpegIUqraPG+afinlZKufkKOM2W/qOq+i47c8eLlWNrdpSDZ+w24qoCyQdW5WHYJOMfz2eKd2YvphEklqK7pYRmp3uXRQicum971Rs8qIo4S+Hze7ijRk/pO1zqmfwkzw+0XJBKDH2QejItxWlUnq55WwFQjU8seMN84dSizfYdn5FBc+yltI4xOj2CLAd1iU1KUcBOB5kpIUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwx3/YX2hVCm/eHIvDALpWilSatlN5BqfDouDTE+VaHSDD4m9HNKVwZpecj7PF/AKo3fBowJcylj+YwAxxvg7ZCQ==" + } + ] + } + ], + "WalletScanner restarts scanning when accounts are reset": [ + { + "value": { + "version": 4, + "id": "1d470276-d2ea-41cf-8904-079670baca37", + "name": "a", + "spendingKey": "31f0b594e6a695a50328c7874f9d23f72a4fb297d49f3b1512db5969a7d0ce25", + "viewKey": "004f4b700a6548829f2595590d5ac8c1be1e8dc306bca774a1a7a1d7c42c379864fcb81fda30fae499a587a80d3cd7c5207c3bf2c90c463898a1de0903c51712", + "incomingViewKey": "2854702acce3ba91d33a3e2853a718d9626f5b37e4100e36c657f8813e2bce04", + "outgoingViewKey": "0d44394d2615186e9480110ae402b81e69128ecf1e3c3c462b2cdbb323519328", + "publicAddress": "63193f684d12f5f2189cb682334aca7c19564f0400b50258b43eebd7875bdf34", + "createdAt": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + }, + "scanningEnabled": true, + "proofAuthorizingKey": "a01d10fb10b31e4ae723892a440753e3b8c40ff23b6f635de2f8fd915109e606" + }, + "head": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + } + }, + { + "header": { + "sequence": 2, + "previousBlockHash": "4791D7AE9F97DF100EF1558E84772D6A09B43762388283F75C6F20A32A88AA86", + "noteCommitment": { + "type": "Buffer", + "data": "base64:o/aMntQ2IGPF18tp3O2D3KzGHRuLXZTqgQ+SVBflPTg=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:WLUEt6WpH5tQWoWuTDEgAngpK3UuO78z/jOIiB0JSO4=" + }, + "target": "9282972777491357380673661573939192202192629606981189395159182914949423", + "randomness": "0", + "timestamp": 1719441727667, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 4, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAZ9WrJ5qT6rk3666j+0MGkC51IY7ge8UuYWnJ2Aai2p2SjokDjnRaEclv6MHxahvqHnpjQBffym1WDIwkxuFHmhcJWMIz5WQwuPI9/heDZt+OPD91L2/Mz37pDoG6M7gD9ShaNRC3SAb4U4WZg+v/HFsKjCXTXIaJC1mCGxJTfJ0EZGS+Etsuinks0pOu30tdSY7vq2dMpuREpmRVHh3M+p+lCPhtBLULlp/rwWuBEr6llY4KcIkqICURe49pRwumxprhtzkYloXquamstGvA8FjRh7aJ86rqK3JDln0PuE2dXpaGVa8KPPtgQv3o0dwnZU0k+AfcnYLIRznvWKGD0ec53Hv47P7qc5jBuErBvHiKf8z2qpGg5jzsfK1FjGhrqYSmnml4EIMac8otmeMPPtynwMUN8ZVlEZ/K/juUB0RZGPSR4fhroLUFIqi8fmOQvYBt9to8ycSwpmCPlu/MnOPpF3u3BdaYux35n4QFU93JwLNj+xOkNzDgbHn9uAwgsj9O7Ky9E/cZQLmBX8T3pNAJOiEDh+zxFw5ItvpAL9GqlYzV3R4rN4fvJoQ7NFyHavocIH/2e2iE1kEnPMpAEEoKC2w+SpCR5rp7jj0rL6ruOxMZF57PbUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwDe91Aey5ZIoY6QgZpSDQb7EcUpirBsMb9fUyns9pqYbLlNxpUPODCLYm/w9qfTRY0hbrfnuwJ5Ksr4hBEEfhAw==" + } + ] + }, + { + "header": { + "sequence": 3, + "previousBlockHash": "9516FF4C8650796025AF4FC6A13FC033766F1E6F32FB203E3562DAAFB9DF0794", + "noteCommitment": { + "type": "Buffer", + "data": "base64:n7WhruSOYlHdzmXQ8623/m6JA4f4UNHJvw49tRgF6Es=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:TcR8dCjz1KafvPTpoXyaOdrfX452N0ky+VIy7+oRcpo=" + }, + "target": "9255858786337818395603165512831024101510453493377417362192396248796027", + "randomness": "0", + "timestamp": 1719441728127, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 5, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAzawMVj35WwB5iqVoxBvfa/MH8coQ59PAIidM7hSNd7u4XqrDEKQHo7DGK/UfWpRKZIFACWyWMa7NuFTY+byae5k6NPkOrXzvynGy+FRrc+Wxgiko1nc8iwYjWCv4eVATbSgW7nNzwaXFb+aKVYI6gOpAbWuIkWqo09TvSF+cG8YFRYkSSdjyxf7QACJI4Ltis/qChWSKEApBflq0SYk8M8ubbJKi6FbDl7Syq8bcnnW5aspJeOTzInfk1+xuIwRW0KJMn+ZayDuTywF/xqPOYJmu5CZrmgQPQ6mOP/pSR5ixzuggufDGyyws3gDW12saJQnM88T+BUVFBCF9nTCkFeFBPjm6DevmOtthtd42pytHNEbt9WgdLjrg4jssyJMSdV0Qp7VV+2TkIoV3kbYqEhUXrU6sZfeSfyWFcBVt4Nicr1z03qGFfZEjOzb7IKJf4PBgtk0chiUkf1NwcvaRHR7B+bIm+0tftxR+/1yaFGfJJ1crJYfr4k+ENHMFH+xHDL7Cknr1xyve9VQMMIRVmXPk3yy/lrVCilrrJGz5QCgJutiNNp5f7K4hq+7s4reQn6PlXBtjDG1+5HywBVHYpsJVSTxf05FFRRE4ESgNS76nqYS2VLz74klyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw0/P2UgYHAJ8OVGWRUsY5K4szn30ehU7Phu5nG0Q98/Ijg3o+WTPBbUGhg2OaH5GAti+FCi+MENAB1IYQfQzhAw==" + } + ] + }, + { + "header": { + "sequence": 4, + "previousBlockHash": "1CC0F6BE54A623A0B0AC13E0A41A14ADE49A0E214B3E26F2FCCC109993F8F76F", + "noteCommitment": { + "type": "Buffer", + "data": "base64:s/TbP//NX4N1uVEg4cAjgzAsCsMBivJawUN03ssIyhY=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:AoNUIkCzQdk6lISiTioaAD6h4GcqiGLFCjPlZzPLoVU=" + }, + "target": "9228823284279306817296266184515742822248210830185427859262273659833347", + "randomness": "0", + "timestamp": 1719441728574, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 6, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAA/f8lGM1diIN/TGfxQa5m4Yh5gbEYdtBrAMeFmrp52MiCrS+R9HkZvTbzqyt7zewkoA6TMjJmiuWrgWyGNfu4csVpIrTJ/CUY/FC7LHHs7qSK76JEUW0x4UrbP7fJqvUKcxHSv2POYPfFsniAd/j3/AEr947rXk/vEbfK9PonGZIBPca/Pw9AQVOioqeiPJOHabEUHXvXtFdmgCf4GZHArNuRxIPmHYNPPevamn2x/Ey4nn+iB0ouM+/meFKa+RZfrWhY6YKkX01hSR35SQLVKkXdYulQBx0fVggplXh1OKQhtTuMq7ht2jr2eY3KaiLM7JgNt97CFNJbOcS18T6Ji4/lw6Dwax+JaI1gbtO79IVl/6JdEARBZqwS+0FPYvk6forfgLp0OyJx6zeSx/jmYTMss1h7tI0Z1l7ncyzVCOx6Sg+N5E0HtAHUesnW8YxYo9kDnM7el4ogd1jIAEBOV6yuIvZ6DAgfLdHQzFJ6ph11R/JyTwSxalxRfqtJPcesd7NL8pbL+FO8/2wgv0U2JhuMqx1TAZi/AaaYtFvVoQnsFdfVi6cT0EqIqsprKDiPcCbZWnKD7/opbo3+DmHtgoUW8ipOWQPNwegIYbNtUlmqH/YI3+aTq0lyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw5VIIZj/q1ET+T7hlOn3tMl4l/VLHOYvcUlXqDsFU8ktlzQr1NX7qIXNV/3fZQu2u4aktXiz1/ZG/g8ZAv5jiAA==" + } + ] + }, + { + "header": { + "sequence": 5, + "previousBlockHash": "76CA8ADA5607F4B0D5B17ED4F9D47E09174EE39FBB7A3094298B2CA23D2A9745", + "noteCommitment": { + "type": "Buffer", + "data": "base64:+LliQic2PDDrTqKNNxZagq3h8/AvRKz5r4w2z+kEsWo=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:P7S39hVJs4dVJgBEECmP54qPs3Bv+07+9aV/1eqTDoA=" + }, + "target": "9201866281654531936596795386791503876274441021197252859723586932895305", + "randomness": "0", + "timestamp": 1719441729028, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 7, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAxeeweRxo6iD3UcX4YXg1XwMknBV1aVkLwNfgye3ZDcOJVsC2JE/9012EEZ2ts8MQs7/PkGwHhvNuUOxQg6+sDv+NjzvGPYPiiTn4FNBhxbCsDx2f8M6KT0arJtIslzdQPehs3OVemEILnv+YT/tfGcyfWLpRg8Z5FHirnEN6qocGgUTBt95RADnq7z7Vnixy4MbiArkO8I5fjNcfwDouZTRJwFiQO8QnHiAHg9vUJGeRPGNC/4BILyT5gHnoFoTgxl/w9RZf9ReTQ+NvBIOgueSi7Q3Ppr98HQwTxVDoW9q1yBRa2hey/DF7WSs8EEmdRvZiqeDp0pjDwnGPXpUgXQAxsu4BaasNvB8mexjSWKwudPEHmkk9tQOBIZZzgmo4LvGtt7IbeTL9Omy9CYigpHm0DPtENirBtzaQbtBny2UUcvQH0X7vslfFrMg0tfW7BR6TrEOk5P7fMhfsX942WzqWv4h9hbrTMeN4j40N/8VeOObAES7rCL88qANBNUybNDVsWVQLxRhgoS7jSKjSKqcfPrIVzAj6pjJBQclh7veuYP9UaGD5fj8jVdSKsZAJ18SYOd2y2JSGHNBkXyIq/Bbm4k2A+mWDMVXlEMaI7G6LbuGEbEfhnUlyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw8v24RV1PeDi9MINLvOGvzD7M0IqLrTLyK9tHcaUUWSaQjUMMRVnUeFbzIM+0P2tGnclKf8NXpbsZjdtSi65jAQ==" + } + ] + }, + { + "header": { + "sequence": 6, + "previousBlockHash": "FE9F2C2EF1A280EE9F453B561E9E0EDB9DF95CA68A8CFB61206B06C63245CD0B", + "noteCommitment": { + "type": "Buffer", + "data": "base64:+06hDLNIGHR6hgoU3FNLh2fO5Er6p5RYs5AsN0wSvQU=" + }, + "transactionCommitment": { + "type": "Buffer", + "data": "base64:mciVbP+cWYTL43++zveilipF5aqb5Epyy8towzxjFkg=" + }, + "target": "9174987784651351638043000274530578397566067964335270621952759689537226", + "randomness": "0", + "timestamp": 1719441729496, + "graffiti": "0000000000000000000000000000000000000000000000000000000000000000", + "noteSize": 8, + "work": "0" + }, + "transactions": [ + { + "type": "Buffer", + "data": "base64:AQAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGzKiP////8AAAAAICBDDjaZTzDXobtlSEQHQNuc7wbFkF5LDqtvgnEoSj64ZMHwTi2MSIM+mOeeUHalIr1lQn15FhOc+vR21CxnMATPpQTutKO5mSp1xXUDEUmYn8CHjUuEUT53aIzftuXqE3xEa3NHxmA+uf30HEgC5j/B8mnPBesNw+JeYisBd3ISJ/9boxXBUK4J/MmFv/H3KZA+JBGDteH+/AIE5WyQyjL0YAVTK0frAr20W80+sZmEHpeL87oSpUMoSp2dmTLc387TQVXgqZ+uEiGDsNeycoWGMI0oCIV/lQmeo8xj4aXxRteViJDfoU5wt/v/I95DALPR+wMPRdQiKwr9ReuCEztGVVOK535c8QimYYaKQpVW1iVZ1+aa7W76kO0cJM0s1lG8o1uT4ktFMS/XK+6pGkmO3eiAPduR+PTq6ARH75MKAjDarGTHPD8WVzttDkFWMvnB2rHtFSrL8eO3Z1jKmt7OGLHvxPvoVlYA5nKNr2j1emesyGmmVS9p4Pn1IZUnSVuemDaoF/jpbSwWyfLSVvPd97ARQkitNQS/n0rlO+7AeIlruw7gOutSduazCDIoQYJGcNGYtjToyhtRSIdTeFUhzHMK9ZMT9apQ9mmDJqS2QK9S2+Lhbklyb24gRmlzaCBub3RlIGVuY3J5cHRpb24gbWluZXIga2V5MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwHCCkwG0JEW+vfgElBFXqaqC+qmQw6+8fLbv4HdV7h5c4McA0TJEe+ChIrc8h6exdmKOGOsQvUjGvvDR41zuoDA==" + } + ] + } + ] +} \ No newline at end of file diff --git a/ironfish/src/wallet/scanner/chainProcessorWithTransactions.ts b/ironfish/src/wallet/scanner/chainProcessorWithTransactions.ts new file mode 100644 index 0000000000..52ee2ff997 --- /dev/null +++ b/ironfish/src/wallet/scanner/chainProcessorWithTransactions.ts @@ -0,0 +1,50 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +import { Assert } from '../../assert' +import { Blockchain } from '../../blockchain' +import { ChainProcessor } from '../../chainProcessor' +import { Event } from '../../event' +import { Logger } from '../../logger' +import { BlockHeader, Transaction } from '../../primitives' + +export class ChainProcessorWithTransactions { + chainProcessor: ChainProcessor + onAdd = new Event<[{ header: BlockHeader; transactions: Transaction[] }]>() + onRemove = new Event<[{ header: BlockHeader; transactions: Transaction[] }]>() + + get hash(): Buffer | null { + return this.chainProcessor.hash + } + set hash(value: Buffer | null) { + this.chainProcessor.hash = value + } + + async update(options?: { signal?: AbortSignal }): Promise<{ hashChanged: boolean }> { + return this.chainProcessor.update(options) + } + + constructor(options: { + logger?: Logger + chain: Blockchain + head: Buffer | null + maxQueueSize?: number | null + }) { + this.chainProcessor = new ChainProcessor(options) + + this.chainProcessor.onAdd.on(async (header: BlockHeader) => { + const block = await this.chainProcessor.chain.getBlock(header) + Assert.isNotNull(block) + const transactions = block.transactions + await this.onAdd.emitAsync({ header, transactions }) + }) + + this.chainProcessor.onRemove.on(async (header: BlockHeader) => { + const block = await this.chainProcessor.chain.getBlock(header) + Assert.isNotNull(block) + const transactions = block.transactions + await this.onRemove.emitAsync({ header, transactions }) + }) + } +} diff --git a/ironfish/src/wallet/scanner/noteDecryptor.test.ts b/ironfish/src/wallet/scanner/noteDecryptor.test.ts new file mode 100644 index 0000000000..c3490595cb --- /dev/null +++ b/ironfish/src/wallet/scanner/noteDecryptor.test.ts @@ -0,0 +1,144 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +import { Assert } from '../../assert' +import { Block } from '../../primitives' +import { createNodeTest, useAccountFixture, useMinerBlockFixture } from '../../testUtilities' +import { Account } from '../../wallet' +import { BackgroundNoteDecryptor, DecryptNotesFromTransactionsCallback } from './noteDecryptor' + +describe('BackgroundNoteDecryptor', () => { + const nodeTest = createNodeTest() + + /** + * Creates a series of notes on the chain, and returns the blocks that contain such notes. + */ + const createTestNotes = async ( + spec: ReadonlyArray<[account: Account, notesCount: number]>, + ): Promise> => { + const blocks = [] + for (const [account, notesCount] of spec) { + for (let i = 0; i < notesCount; i++) { + const block = await useMinerBlockFixture( + nodeTest.chain, + undefined, + account, + nodeTest.wallet, + ) + await expect(nodeTest.chain).toAddBlock(block) + blocks.push(block) + } + } + return blocks + } + + it('decrypts notes belonging to different accounts', async () => { + const accountA = await useAccountFixture(nodeTest.wallet, 'a') + const accountB = await useAccountFixture(nodeTest.wallet, 'b') + + const blocks = await createTestNotes([ + [accountA, 5], + [accountB, 3], + [accountA, 2], + [accountB, 2], + ]) + expect(blocks.length).toBe(12) + + const decryptor = new BackgroundNoteDecryptor(nodeTest.workerPool, nodeTest.sdk.config, { + decryptForSpender: true, + }) + + decryptor.start() + + const callback = jest.fn() + + for (const block of blocks) { + await decryptor.decryptNotesFromBlock( + block.header, + block.transactions, + [accountA, accountB], + callback, + ) + } + + await decryptor.flush() + decryptor.stop() + + // Check that the callback was called the right number of times + expect(callback).toHaveBeenCalledTimes(2 * blocks.length) + + // Check that the correct number of notes was decrypted + const totalNotesCount = new Map() + for (const [account, _blockHeader, transactions] of callback.mock.calls) { + let notesForAccount = totalNotesCount.get(account.id) ?? 0 + notesForAccount += transactions + .map(({ decryptedNotes }) => decryptedNotes.length) + .reduce((acc, item) => acc + item, 0) + totalNotesCount.set(account.id, notesForAccount) + } + expect(totalNotesCount).toEqual( + new Map([ + [accountA.id, 7], + [accountB.id, 5], + ]), + ) + + // Check the individual callback calls + const expectedCalls = [ + { account: accountA, block: blocks[0], decrypted: true }, + { account: accountB, block: blocks[0], decrypted: false }, + { account: accountA, block: blocks[1], decrypted: true }, + { account: accountB, block: blocks[1], decrypted: false }, + { account: accountA, block: blocks[2], decrypted: true }, + { account: accountB, block: blocks[2], decrypted: false }, + { account: accountA, block: blocks[3], decrypted: true }, + { account: accountB, block: blocks[3], decrypted: false }, + { account: accountA, block: blocks[4], decrypted: true }, + { account: accountB, block: blocks[4], decrypted: false }, + + { account: accountA, block: blocks[5], decrypted: false }, + { account: accountB, block: blocks[5], decrypted: true }, + { account: accountA, block: blocks[6], decrypted: false }, + { account: accountB, block: blocks[6], decrypted: true }, + { account: accountA, block: blocks[7], decrypted: false }, + { account: accountB, block: blocks[7], decrypted: true }, + + { account: accountA, block: blocks[8], decrypted: true }, + { account: accountB, block: blocks[8], decrypted: false }, + { account: accountA, block: blocks[9], decrypted: true }, + { account: accountB, block: blocks[9], decrypted: false }, + + { account: accountA, block: blocks[10], decrypted: false }, + { account: accountB, block: blocks[10], decrypted: true }, + { account: accountA, block: blocks[11], decrypted: false }, + { account: accountB, block: blocks[11], decrypted: true }, + ] + expect(callback).toHaveBeenCalledTimes(expectedCalls.length) + + let noteIndex = nodeTest.chain.genesis.noteSize + + for (const [callIndex, { account, block, decrypted }] of expectedCalls.entries()) { + const transactions = block.transactions.map((transaction) => { + const decryptedNotes = [] + if (decrypted) { + Assert.isNotNull(noteIndex) + decryptedNotes.push({ + index: noteIndex, + forSpender: false, + hash: expect.anything(), + nullifier: expect.anything(), + serializedNote: expect.anything(), + }) + noteIndex += 1 + } + return { transaction, decryptedNotes } + }) + expect(callback).toHaveBeenNthCalledWith( + callIndex + 1, + account, + block.header, + transactions, + ) + } + }) +}) diff --git a/ironfish/src/wallet/scanner/noteDecryptor.ts b/ironfish/src/wallet/scanner/noteDecryptor.ts new file mode 100644 index 0000000000..924bbef172 --- /dev/null +++ b/ironfish/src/wallet/scanner/noteDecryptor.ts @@ -0,0 +1,269 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +import { Assert } from '../../assert' +import { Config } from '../../fileStores' +import { BlockHeader } from '../../primitives' +import { Transaction } from '../../primitives/transaction' +import { AsyncQueue } from '../../utils/asyncQueue' +import { PromiseUtils } from '../../utils/promise' +import { WorkerPool } from '../../workerPool' +import { Job } from '../../workerPool/job' +import { + DecryptedNote, + DecryptNotesOptions, + DecryptNotesRequest, + DecryptNotesResponse, + DecryptNotesSharedAccountKeys, +} from '../../workerPool/tasks/decryptNotes' +import { JobAbortedError } from '../../workerPool/tasks/jobAbort' +import { Account } from '../account/account' + +export type DecryptNotesFromTransactionsCallback = ( + account: Account, + blockHeader: BlockHeader, + transactions: Array<{ transaction: Transaction; decryptedNotes: Array }>, +) => Promise + +type DecryptQueueItem = { + job: Job + blockHeader: BlockHeader + transactions: ReadonlyArray + accounts: ReadonlyArray + callback: DecryptNotesFromTransactionsCallback +} + +export class BackgroundNoteDecryptor { + private isStarted = false + + private triggerFlushed: (() => void) | null = null + private triggerStopped: (() => void) | null = null + + private onFlushed: Promise = Promise.resolve() + private onStopped: Promise = Promise.resolve() + + private readonly workerPool: WorkerPool + private readonly options: DecryptNotesOptions + private readonly decryptQueue: AsyncQueue + + private accounts: ReadonlyArray + private sharedAccountKeys: DecryptNotesSharedAccountKeys + + constructor(workerPool: WorkerPool, config: Config, options: DecryptNotesOptions) { + this.workerPool = workerPool + this.options = options + + let queueSize = 8 * workerPool.numWorkers + const maxQueueSize = config.get('walletSyncingMaxConcurrency') + if (maxQueueSize > 0) { + queueSize = Math.min(queueSize, maxQueueSize) + } + queueSize = Math.max(queueSize, 1) + this.decryptQueue = new AsyncQueue(queueSize) + + this.accounts = [] + this.sharedAccountKeys = new DecryptNotesSharedAccountKeys([]) + } + + start(abort?: AbortController) { + if (!this.isStarted) { + this.isStarted = true + this.onStopped = new Promise((resolve) => (this.triggerStopped = resolve)) + void this.decryptLoop() + + if (abort) { + abort.signal.addEventListener('abort', this.stop.bind(this)) + } + } + } + + stop() { + if (this.isStarted) { + this.isStarted = false + for (const { job } of this.decryptQueue) { + job.abort() + } + this.decryptQueue.clear() + if (this.triggerStopped) { + this.triggerStopped() + } + } + } + + private async decryptLoop(): Promise { + let resolve: (value: DecryptQueueItem | void) => unknown + let reject: (reason?: unknown) => void + + this.onStopped.then( + (value) => resolve?.(value), + (err) => reject?.(err), + ) + + while (this.isStarted) { + if (this.decryptQueue.isEmpty() && this.triggerFlushed) { + this.triggerFlushed() + this.triggerFlushed = null + } + + const [promise, resolveNew, rejectNew] = PromiseUtils.split() + resolve = resolveNew + reject = rejectNew + + this.decryptQueue.pop().then( + (value) => resolve(value), + (err) => reject(err), + ) + + const item = await promise + if (!item) { + break + } + + const { job, blockHeader, transactions, accounts, callback } = item + + let decryptNotesResponse + try { + decryptNotesResponse = await job.result() + } catch (e) { + if (e instanceof JobAbortedError) { + break + } + throw e + } + + if (!this.isStarted) { + break + } + + Assert.isInstanceOf(decryptNotesResponse, DecryptNotesResponse) + const decryptedNotes = decryptNotesResponse.mapToAccounts( + accounts.map((account) => ({ accountId: account.id })), + ) + + for (const { account, decryptedTransactions } of regroupNotes( + accounts, + transactions, + decryptedNotes, + )) { + if (!this.isStarted) { + break + } + await callback(account, blockHeader, decryptedTransactions) + } + } + } + + /** + * Waits for all the in flight decrypt requests to be fully processed. + */ + async flush(): Promise { + if (!this.isStarted) { + return + } + await this.onFlushed + } + + decryptNotesFromBlock( + blockHeader: BlockHeader, + transactions: ReadonlyArray, + accounts: ReadonlyArray, + callback: DecryptNotesFromTransactionsCallback, + ): Promise { + if (!this.isStarted) { + throw new Error('decryptor was not started') + } + + this.updateAccounts(accounts) + + if (!this.triggerFlushed) { + this.onFlushed = new Promise((resolve) => (this.triggerFlushed = resolve)) + } + + Assert.isNotNull(blockHeader.noteSize) + + const encryptedNotes = [] + let currentNoteIndex = transactions + .map((transaction) => transaction.notes.length) + .reduce((accumulator, numNotes) => accumulator - numNotes, blockHeader.noteSize) + + for (const transaction of transactions) { + for (const note of transaction.notes) { + encryptedNotes.push({ serializedNote: note.serialize(), currentNoteIndex }) + currentNoteIndex++ + } + } + + const decryptNotesRequest = new DecryptNotesRequest( + this.sharedAccountKeys, + encryptedNotes, + this.options, + ) + const job = this.workerPool.execute(decryptNotesRequest) + + return this.decryptQueue.push({ + job, + blockHeader, + transactions, + accounts: this.accounts, + callback, + }) + } + + private updateAccounts(newAccounts: ReadonlyArray) { + if ( + newAccounts.length === this.accounts.length && + newAccounts.every((account, index) => account === this.accounts[index]) + ) { + // No change + return + } + + // Because `decryptLoop` does not use `this.accounts` or + // `this.sharedAccountKeys` directly, we can swap their value without the + // need to flush the queue. This is safe as long as the value is not + // mutated. + this.accounts = newAccounts + this.sharedAccountKeys = new DecryptNotesSharedAccountKeys( + newAccounts.map((account) => ({ + incomingViewKey: Buffer.from(account.incomingViewKey, 'hex'), + outgoingViewKey: Buffer.from(account.outgoingViewKey, 'hex'), + viewKey: Buffer.from(account.viewKey, 'hex'), + })), + ) + } +} + +/** + * Reassociates each decrypted note to its corresponding transaction. + */ +function* regroupNotes( + accounts: ReadonlyArray, + transactions: ReadonlyArray, + decryptedNotes: ReadonlyMap>, +): Generator<{ + account: Account + decryptedTransactions: Array<{ + transaction: Transaction + decryptedNotes: Array + }> +}> { + for (const account of accounts) { + let notesOffset = 0 + const flatNotes: ReadonlyArray = + decryptedNotes.get(account.id) ?? [] + const groupedNotes: Array<{ + transaction: Transaction + decryptedNotes: Array + }> = [] + + for (const transaction of transactions) { + const decryptedNotes = flatNotes + .slice(notesOffset, notesOffset + transaction.notes.length) + .filter((note) => note !== undefined) as Array + groupedNotes.push({ transaction, decryptedNotes }) + notesOffset += transaction.notes.length + } + + yield { account, decryptedTransactions: groupedNotes } + } +} diff --git a/ironfish/src/wallet/scanner/remoteChainProcessor.test.ts b/ironfish/src/wallet/scanner/remoteChainProcessor.test.ts index 78a385b128..dae7a3f897 100644 --- a/ironfish/src/wallet/scanner/remoteChainProcessor.test.ts +++ b/ironfish/src/wallet/scanner/remoteChainProcessor.test.ts @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +import type { Mock } from 'jest-mock' import { BlockHeader } from '../../primitives' import { ALL_API_NAMESPACES, RpcMemoryClient } from '../../rpc' import { createNodeTest, useMinerBlockFixture } from '../../testUtilities' @@ -46,7 +47,7 @@ describe('RemoteChainProcessor', () => { maxQueueSize: 10, }) - const onEvent: jest.Mock = jest.fn() + const onEvent: Mock<(header: BlockHeader, event: 'add' | 'remove') => void> = jest.fn() processor.onAdd.on((block) => onEvent(block.header, 'add')) processor.onRemove.on((block) => onEvent(block.header, 'remove')) @@ -101,7 +102,7 @@ describe('RemoteChainProcessor', () => { maxQueueSize: 10, }) - const onEvent: jest.Mock = jest.fn() + const onEvent: Mock<(header: BlockHeader, event: 'add' | 'remove') => void> = jest.fn() processor.onAdd.on((block) => onEvent(block.header, 'add')) processor.onRemove.on((block) => onEvent(block.header, 'remove')) diff --git a/ironfish/src/wallet/scanner/scanState.ts b/ironfish/src/wallet/scanner/scanState.ts index eda13da0a5..f79eccc1f4 100644 --- a/ironfish/src/wallet/scanner/scanState.ts +++ b/ironfish/src/wallet/scanner/scanState.ts @@ -16,7 +16,9 @@ export class ScanState { readonly end: HeadValue readonly startedAt: number readonly abortController: AbortController - readonly onTransaction = new Event<[sequence: number, endSequence: number]>() + readonly onTransaction = new Event< + [sequence: number, endSequence: number, action: 'connect' | 'disconnect'] + >() readonly speed = new Meter() private runningPromise: Promise @@ -43,11 +45,11 @@ export class ScanState { return (remaining / this.speed.rate1m) * 1000 } - signal(header: BlockHeader): void { + signal(header: BlockHeader, action: 'connect' | 'disconnect'): void { this.hash = header.hash this.sequence = header.sequence this.speed.add(1) - this.onTransaction.emit(header.sequence, this.end.sequence) + this.onTransaction.emit(header.sequence, this.end.sequence, action) } signalComplete(): void { diff --git a/ironfish/src/wallet/scanner/walletScanner.test.ts b/ironfish/src/wallet/scanner/walletScanner.test.ts new file mode 100644 index 0000000000..9a039160fb --- /dev/null +++ b/ironfish/src/wallet/scanner/walletScanner.test.ts @@ -0,0 +1,472 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +import { Asset } from '@ironfish/rust-nodejs' +import { Assert } from '../../assert' +import { Blockchain } from '../../blockchain' +import { Block, BlockHeader } from '../../primitives' +import { createNodeTest, useAccountFixture, useMinerBlockFixture } from '../../testUtilities' +import { AsyncUtils } from '../../utils' +import { Account, Wallet } from '../../wallet' +import { BackgroundNoteDecryptor } from './noteDecryptor' + +describe('WalletScanner', () => { + const nodeTest = createNodeTest() + + beforeEach(() => { + jest.restoreAllMocks() + }) + + /** + * Creates a series of notes on the chain, and returns the blocks that contain such notes. + */ + const createTestNotes = async ( + chain: Blockchain, + wallet: Wallet, + spec: ReadonlyArray<[account: Account, notesCount: number]>, + ): Promise> => { + const blocks = [] + for (const [account, notesCount] of spec) { + for (let i = 0; i < notesCount; i++) { + const block = await useMinerBlockFixture(chain, undefined, account, wallet) + await expect(chain).toAddBlock(block) + blocks.push(block) + } + } + return blocks + } + + it('adds transactions to the wallet db with decrypted notes', async () => { + const connectBlockForAccount = jest.spyOn(nodeTest.wallet, 'connectBlockForAccount') + + const account = await useAccountFixture(nodeTest.wallet, 'a') + const blocks = await createTestNotes(nodeTest.chain, nodeTest.wallet, [[account, 3]]) + + expect(connectBlockForAccount).not.toHaveBeenCalled() + await nodeTest.wallet.scan() + expect(connectBlockForAccount).toHaveBeenCalledTimes(3) + + const initialNoteIndex = nodeTest.chain.genesis.noteSize + Assert.isNotNull(initialNoteIndex) + + for (const [i, block] of blocks.entries()) { + expect(block.transactions.length).toBe(1) + + expect(connectBlockForAccount).toHaveBeenNthCalledWith( + i + 1, + account, + block.header, + block.transactions.map((transaction) => ({ + transaction, + decryptedNotes: [ + expect.objectContaining({ + index: i + initialNoteIndex, + forSpender: false, + hash: expect.anything(), + nullifier: expect.anything(), + serializedNote: expect.anything(), + }), + ], + })), + true, + ) + + for (const transaction of block.transactions) { + const storedTransaction = await account.getTransaction(transaction.hash()) + expect(storedTransaction).toBeDefined() + expect(storedTransaction?.blockHash).toEqual(block.header.hash) + expect(storedTransaction?.sequence).toEqual(block.header.sequence) + } + } + + const allStoredTransactions = await AsyncUtils.materialize(account.getTransactions()) + expect(allStoredTransactions.length).toBe(3) + + await expect(account.getBalance(Asset.nativeId(), 0)).resolves.toMatchObject({ + confirmed: 3n * 2000000000n, + unconfirmed: 3n * 2000000000n, + }) + }) + + it('updates the account head hash', async () => { + const account = await useAccountFixture(nodeTest.wallet, 'a') + const blocks = await createTestNotes(nodeTest.chain, nodeTest.wallet, [[account, 3]]) + + await nodeTest.wallet.scan() + + const accountHead = await account.getHead() + expect(accountHead?.hash).toEqualHash(blocks[2].header.hash) + }) + + it('ignores accounts that have scanning disabled', async () => { + const connectBlockForAccount = jest.spyOn(nodeTest.wallet, 'connectBlockForAccount') + + const accountA = await useAccountFixture(nodeTest.wallet, 'a') + const accountB = await useAccountFixture(nodeTest.wallet, 'b') + const accountC = await useAccountFixture(nodeTest.wallet, 'c') + const accountD = await useAccountFixture(nodeTest.wallet, 'd') + + await accountB.updateScanningEnabled(false) + await accountD.updateScanningEnabled(false) + + const blocks = await createTestNotes(nodeTest.chain, nodeTest.wallet, [ + [accountA, 1], + [accountB, 1], + [accountC, 1], + [accountD, 1], + [accountD, 1], + [accountB, 1], + [accountA, 1], + [accountC, 1], + ]) + + expect(connectBlockForAccount).not.toHaveBeenCalled() + await nodeTest.wallet.scan() + expect(connectBlockForAccount).toHaveBeenCalledTimes(16) + + const initialNoteIndex = nodeTest.chain.genesis.noteSize + Assert.isNotNull(initialNoteIndex) + + const expectedConnectedAccountBlocks = [ + { account: accountA, block: blocks[0], decryptedNoteIndexes: [initialNoteIndex] }, + { account: accountC, block: blocks[0], decryptedNoteIndexes: [] }, + { account: accountA, block: blocks[1], decryptedNoteIndexes: [] }, + { account: accountC, block: blocks[1], decryptedNoteIndexes: [] }, + { account: accountA, block: blocks[2], decryptedNoteIndexes: [] }, + { account: accountC, block: blocks[2], decryptedNoteIndexes: [initialNoteIndex + 2] }, + { account: accountA, block: blocks[3], decryptedNoteIndexes: [] }, + { account: accountC, block: blocks[3], decryptedNoteIndexes: [] }, + { account: accountA, block: blocks[4], decryptedNoteIndexes: [] }, + { account: accountC, block: blocks[4], decryptedNoteIndexes: [] }, + { account: accountA, block: blocks[5], decryptedNoteIndexes: [] }, + { account: accountC, block: blocks[5], decryptedNoteIndexes: [] }, + { account: accountA, block: blocks[6], decryptedNoteIndexes: [initialNoteIndex + 6] }, + { account: accountC, block: blocks[6], decryptedNoteIndexes: [] }, + { account: accountA, block: blocks[7], decryptedNoteIndexes: [] }, + { account: accountC, block: blocks[7], decryptedNoteIndexes: [initialNoteIndex + 7] }, + ] + + for (const [ + i, + { account, block, decryptedNoteIndexes }, + ] of expectedConnectedAccountBlocks.entries()) { + expect(block.transactions.length).toBe(1) + + expect(connectBlockForAccount).toHaveBeenNthCalledWith( + i + 1, + account, + block.header, + block.transactions.map((transaction) => ({ + transaction, + decryptedNotes: decryptedNoteIndexes.map( + (index) => + expect.objectContaining({ + index, + forSpender: false, + hash: expect.anything(), + nullifier: expect.anything(), + serializedNote: expect.anything(), + }) as unknown, + ), + })), + true, + ) + + for (const transaction of block.transactions) { + const storedTransaction = await account.getTransaction(transaction.hash()) + if (!decryptedNoteIndexes.length) { + expect(storedTransaction).not.toBeDefined() + } else { + expect(storedTransaction).toBeDefined() + expect(storedTransaction?.blockHash).toEqual(block.header.hash) + expect(storedTransaction?.sequence).toEqual(block.header.sequence) + } + } + } + + await expect(nodeTest.wallet.getBalance(accountA, Asset.nativeId())).resolves.toMatchObject( + { + confirmed: 2n * 2000000000n, + unconfirmed: 2n * 2000000000n, + }, + ) + await expect(nodeTest.wallet.getBalance(accountB, Asset.nativeId())).resolves.toMatchObject( + { + confirmed: 0n, + unconfirmed: 0n, + }, + ) + await expect(nodeTest.wallet.getBalance(accountC, Asset.nativeId())).resolves.toMatchObject( + { + confirmed: 2n * 2000000000n, + unconfirmed: 2n * 2000000000n, + }, + ) + await expect(nodeTest.wallet.getBalance(accountD, Asset.nativeId())).resolves.toMatchObject( + { + confirmed: 0n, + unconfirmed: 0n, + }, + ) + + expect((await accountA.getHead())?.hash).toEqualHash(blocks[7].header.hash) + expect((await accountB.getHead())?.hash).toEqualHash(nodeTest.chain.genesis.hash) + expect((await accountC.getHead())?.hash).toEqualHash(blocks[7].header.hash) + expect((await accountD.getHead())?.hash).toEqualHash(nodeTest.chain.genesis.hash) + }) + + it('skips decryption for accounts with createdAt later than the block header', async () => { + const accountA = await useAccountFixture(nodeTest.wallet, 'a') + expect(accountA.createdAt?.hash).toEqualHash(nodeTest.chain.genesis.hash) + + const firstBlocks = await createTestNotes(nodeTest.chain, nodeTest.wallet, [[accountA, 3]]) + + const accountB = await useAccountFixture(nodeTest.wallet, 'b') + expect(accountB.createdAt?.hash).toEqualHash(firstBlocks[2].header.hash) + + const lastBlocks = await createTestNotes(nodeTest.chain, nodeTest.wallet, [[accountB, 3]]) + + const decryptNotesFromBlock = jest.spyOn( + BackgroundNoteDecryptor.prototype, + 'decryptNotesFromBlock', + ) + + await nodeTest.wallet.reset() + await nodeTest.wallet.scan() + + const genesisBlock = await nodeTest.chain.getBlock(nodeTest.chain.genesis) + Assert.isNotNull(genesisBlock) + + const blocks = [genesisBlock, ...firstBlocks, ...lastBlocks] + + expect(decryptNotesFromBlock).toHaveBeenCalledTimes(blocks.length) + + for (const [i, block] of blocks.slice(1, 3).entries()) { + expect(decryptNotesFromBlock).toHaveBeenNthCalledWith( + i + 2, + block.header, + block.transactions, + [expect.objectContaining({ incomingViewKey: accountA.incomingViewKey })], + expect.anything(), + ) + } + for (const [i, block] of blocks.slice(3).entries()) { + expect(decryptNotesFromBlock).toHaveBeenNthCalledWith( + i + 4, + block.header, + block.transactions, + [ + expect.objectContaining({ incomingViewKey: accountA.incomingViewKey }), + expect.objectContaining({ name: accountB.name }), + ], + expect.anything(), + ) + } + }) + + it('skips blocks preceeding the lowest createdAt', async () => { + const decryptNotesFromBlock = jest.spyOn( + BackgroundNoteDecryptor.prototype, + 'decryptNotesFromBlock', + ) + const connectBlockForAccount = jest.spyOn(nodeTest.wallet, 'connectBlockForAccount') + + const accountA = await useAccountFixture(nodeTest.wallet, 'a') + const firstBlocks = await createTestNotes(nodeTest.chain, nodeTest.wallet, [[accountA, 3]]) + await nodeTest.wallet.removeAccount(accountA) + + const accountB = await useAccountFixture(nodeTest.wallet, 'b') + const lastBlocks = await createTestNotes(nodeTest.chain, nodeTest.wallet, [[accountB, 3]]) + + await nodeTest.wallet.reset() + await nodeTest.wallet.scan() + + const blocks = [firstBlocks[2], ...lastBlocks] + + expect(decryptNotesFromBlock).toHaveBeenCalledTimes(blocks.length) + expect(connectBlockForAccount).toHaveBeenCalledTimes(blocks.length) + + for (const [i, block] of blocks.entries()) { + expect(decryptNotesFromBlock).toHaveBeenNthCalledWith( + i + 1, + block.header, + block.transactions, + [expect.objectContaining({ incomingViewKey: accountB.incomingViewKey })], + expect.anything(), + ) + expect(connectBlockForAccount).toHaveBeenNthCalledWith( + i + 1, + expect.objectContaining({ incomingViewKey: accountB.incomingViewKey }), + block.header, + expect.anything(), + true, + ) + } + }) + + describe('restarts scanning', () => { + // Set up the BackgroundNoteDecryptor so that we can pause and resume the + // scan after each block that gets processed. + let continueScan: () => void = () => {} + let notifyDecryptCall: ((blockHeader: BlockHeader) => void) | null = null + let decryptCallPromise: Promise | null = null + + const nextDecryptCall = async (): Promise => { + Assert.isNotNull(decryptCallPromise) + const blockHeader = await decryptCallPromise + decryptCallPromise = new Promise((resolve) => { + notifyDecryptCall = resolve + }) + return blockHeader + } + + const patchWalletScanner = (wallet: Wallet) => { + const connectBlockOrig = wallet.scanner.connectBlock.bind(wallet.scanner) + jest + .spyOn(wallet.scanner, 'connectBlock') + .mockImplementation(async (blockHeader, ...args) => { + Assert.isNotNull(notifyDecryptCall) + notifyDecryptCall(blockHeader) + void connectBlockOrig(blockHeader, ...args) + return new Promise((resolve) => { + continueScan = resolve + }) + }) + + decryptCallPromise = new Promise((resolve) => { + notifyDecryptCall = resolve + }) + } + + it('when accounts are imported', async () => { + const { chain, wallet } = await nodeTest.createSetup({ + config: { walletSyncingMaxQueueSize: 1 }, + }) + patchWalletScanner(wallet) + + // Create 2 accounts, and remove the first one (so that we can re-import it later) + const genesisBlock = await chain.getBlock(chain.genesis) + Assert.isNotNull(genesisBlock) + const blocks = [genesisBlock] + const accountA = await useAccountFixture(wallet, 'a') + blocks.push(...(await createTestNotes(chain, wallet, [[accountA, 5]]))) + const accountB = await useAccountFixture(wallet, 'b') + blocks.push(...(await createTestNotes(chain, wallet, [[accountB, 5]]))) + await wallet.removeAccount(accountA) + + expect(blocks.length).toBe(11) + + // Start scanning + await wallet.reset() + const scanPromise = wallet.scan() + + // Check that the scanning begins at the `accountB` creation block (and scan a few blocks) + for (let i = 5; i <= 8; i++) { + continueScan() + const firstBlockHeader = await nextDecryptCall() + expect(firstBlockHeader.hash).toEqualHash(blocks[i].header.hash) + } + + // Now import `accountA` + await wallet.importAccount(accountA.serialize()) + + // Check that scanning resumes at the `accountA` creation block (and scan till the end) + for (let i = 0; i <= 10; i++) { + continueScan() + const blockHeader = await nextDecryptCall() + expect(blockHeader.hash).toEqualHash(blocks[i].header.hash) + } + + // Scan should be done + continueScan() + await scanPromise + }) + + it('when accounts are deleted', async () => { + const { chain, wallet } = await nodeTest.createSetup({ + config: { walletSyncingMaxQueueSize: 1 }, + }) + patchWalletScanner(wallet) + + // Create 2 accounts + const genesisBlock = await chain.getBlock(chain.genesis) + Assert.isNotNull(genesisBlock) + const blocks = [genesisBlock] + const accountA = await useAccountFixture(wallet, 'a') + blocks.push(...(await createTestNotes(chain, wallet, [[accountA, 5]]))) + const accountB = await useAccountFixture(wallet, 'b') + blocks.push(...(await createTestNotes(chain, wallet, [[accountB, 5]]))) + + expect(blocks.length).toBe(11) + + // Start scanning + await wallet.reset() + const scanPromise = wallet.scan() + + // Check that the scanning begins at the `accountA` creation block (and scan a few blocks) + for (let i = 0; i <= 2; i++) { + continueScan() + const blockHeader = await nextDecryptCall() + expect(blockHeader.hash).toEqualHash(blocks[i].header.hash) + } + + // Now delete `accountA` + // + // (Need to use `removeAccountByName` instead of `removeAccount` because + // the previous call to `wallet.reset()` has caused the account id to + // change) + await wallet.removeAccountByName(accountA.name) + + // Check that scanning skips blocks and resumes at the `accountB` creation block (and scan till the end) + for (let i = 5; i <= 10; i++) { + continueScan() + const blockHeader = await nextDecryptCall() + expect(blockHeader.hash).toEqualHash(blocks[i].header.hash) + } + + // Scan should be done + continueScan() + await scanPromise + }) + + it('when accounts are reset', async () => { + const { chain, wallet } = await nodeTest.createSetup({ + config: { walletSyncingMaxQueueSize: 1 }, + }) + patchWalletScanner(wallet) + + const genesisBlock = await chain.getBlock(chain.genesis) + Assert.isNotNull(genesisBlock) + const blocks = [genesisBlock] + const account = await useAccountFixture(wallet, 'a') + blocks.push(...(await createTestNotes(chain, wallet, [[account, 5]]))) + + expect(blocks.length).toBe(6) + + // Start scanning + await wallet.reset() + const scanPromise = wallet.scan() + + // Check that the scanning begins at the genesis block (and scan a few blocks) + for (let i = 0; i <= 3; i++) { + continueScan() + const blockHeader = await nextDecryptCall() + expect(blockHeader.hash).toEqualHash(blocks[i].header.hash) + } + + // Reset the wallet + await wallet.reset() + + // Check that scanning restarts from the genesis block (and scan till the end) + for (let i = 0; i <= 5; i++) { + continueScan() + const blockHeader = await nextDecryptCall() + expect(blockHeader.hash).toEqualHash(blocks[i].header.hash) + } + + // Scan should be done + continueScan() + await scanPromise + }) + }) +}) diff --git a/ironfish/src/wallet/scanner/walletScanner.ts b/ironfish/src/wallet/scanner/walletScanner.ts index 89a2793ce3..64e74126cd 100644 --- a/ironfish/src/wallet/scanner/walletScanner.ts +++ b/ironfish/src/wallet/scanner/walletScanner.ts @@ -1,40 +1,54 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ - +import type { Blockchain } from '../../blockchain' +import type { RpcClient } from '../../rpc' +import type { Account } from '../account/account' import type { Wallet } from '../wallet' -import { BufferMap } from 'buffer-map' -import { Assert } from '../../assert' +import type { HeadValue } from '../walletdb/headValue' import { Config } from '../../fileStores' import { Logger } from '../../logger' import { Mutex } from '../../mutex' import { BlockHeader, Transaction } from '../../primitives' -import { RpcClient } from '../../rpc' -import { AsyncUtils, BufferUtils, HashUtils } from '../../utils' -import { DecryptedNote } from '../../workerPool/tasks/decryptNotes' +import { BufferUtils, HashUtils } from '../../utils' +import { WorkerPool } from '../../workerPool' +import { ChainProcessorWithTransactions } from './chainProcessorWithTransactions' +import { BackgroundNoteDecryptor } from './noteDecryptor' import { RemoteChainProcessor } from './remoteChainProcessor' import { ScanState } from './scanState' export class WalletScanner { readonly logger: Logger - readonly nodeClient: RpcClient | null readonly wallet: Wallet + readonly workerPool: WorkerPool + readonly config: Config + + readonly chain: Blockchain | null = null + readonly nodeClient: RpcClient | null = null - maxQueueSize: number state: ScanState | null = null lock: Mutex = new Mutex() + /** + * A snapshot of the accounts that have `scanningEnabled` set to true. Used + * to tell what accounts should be scanned, and from what block. + */ + private scanningAccounts = new Array<{ account: Account; scanFrom: HeadValue | null }>() + constructor(options: { logger: Logger - nodeClient: RpcClient | null wallet: Wallet - maxQueueSize: number + workerPool: WorkerPool config: Config + nodeClient?: RpcClient | null + chain?: Blockchain | null }) { this.logger = options.logger - this.nodeClient = options.nodeClient this.wallet = options.wallet - this.maxQueueSize = options.maxQueueSize + this.workerPool = options.workerPool + this.config = options.config + this.chain = options.chain ?? null + this.nodeClient = options.nodeClient ?? null } get running(): boolean { @@ -61,24 +75,26 @@ export class WalletScanner { } try { - const start = await this.wallet.getEarliestHead() + await this.refreshScanningAccounts() + + const start = this.getEarliestHead() const end = await this.wallet.getChainHead() - const chainProcessor = new RemoteChainProcessor({ - logger: this.logger, - nodeClient: this.nodeClient, - maxQueueSize: this.maxQueueSize, - head: start?.hash ?? null, + const decryptor = new BackgroundNoteDecryptor(this.workerPool, this.config, { + decryptForSpender: false, + skipNoteValidation: true, }) + const chainProcessor = this.getChainProcessor(start) + chainProcessor.onAdd.on(async ({ header, transactions }) => { - await this.connectBlock(header, transactions, this.state?.abortController) - this.state?.signal(header) + await this.connectBlock(header, transactions, decryptor, this.state?.abortController) + this.state?.signal(header, 'connect') }) chainProcessor.onRemove.on(async ({ header, transactions }) => { await this.disconnectBlock(header, transactions, this.state?.abortController) - this.state?.signal(header) + this.state?.signal(header, 'disconnect') }) // Once we set up ChainProcessor, if the start is null we want to use @@ -93,15 +109,31 @@ export class WalletScanner { `Scan starting from block ${scan.start.sequence} to ${scan.start.sequence}`, ) + decryptor.start(scan.abortController) + void (async () => { let hashChanged = true + while (hashChanged) { - const head = await this.wallet.getEarliestHead() - chainProcessor.hash = head?.hash ?? null + if (scan.abortController.signal.aborted) { + return + } + + if (this.haveWalletAccountsChanged()) { + // Accounts have changed in the wallet. Wait for all pending + // decrypt requests to be completed, then update the head of the + // chain processor. + await decryptor.flush() + await this.refreshScanningAccounts() + const head = this.getEarliestHead() + chainProcessor.hash = head?.hash ?? null + } const result = await chainProcessor.update({ signal: scan.abortController.signal }) hashChanged = result.hashChanged } + + await decryptor.flush() })() .then(() => { this.logger.debug( @@ -111,6 +143,8 @@ export class WalletScanner { ) }) .finally(() => { + decryptor.stop() + if (this.state === scan) { this.state = null } @@ -127,6 +161,7 @@ export class WalletScanner { async connectBlock( blockHeader: BlockHeader, transactions: Transaction[], + decryptor: BackgroundNoteDecryptor, abort?: AbortController, ): Promise { if (blockHeader.sequence % 100 === 0) { @@ -137,110 +172,151 @@ export class WalletScanner { ) } - const accounts = await AsyncUtils.filter(this.wallet.listAccounts(), async (account) => { - if (!account.scanningEnabled) { - return false - } - - const accountHead = await account.getHead() - - if (!accountHead) { - return blockHeader.sequence === 1 - } else { - return BufferUtils.equalsNullable(accountHead.hash, blockHeader.previousBlockHash) - } - }) - - const shouldDecryptAccounts = accounts.filter((a) => - this.wallet.shouldDecryptForAccount(blockHeader, a), - ) - - const shouldDecryptAccountIds = new Set(shouldDecryptAccounts.map((a) => a.id)) - - const decryptedTransactions = await Promise.all( - getTransactionsWithNoteIndex(blockHeader, transactions).map( - ({ transaction, initialNoteIndex }) => - this.wallet - .decryptNotes(transaction, initialNoteIndex, false, shouldDecryptAccounts) - .then((r) => ({ - result: r, - transaction, - })), - ), - ) - - // account id -> transaction hash -> Array - const decryptedNotesMap: Map>> = new Map() - for (const { transaction, result } of decryptedTransactions) { - for (const [accountId, decryptedNotes] of result) { - const accountTxnsMap = - decryptedNotesMap.get(accountId) ?? new BufferMap>() - accountTxnsMap.set(transaction.hash(), decryptedNotes) - decryptedNotesMap.set(accountId, accountTxnsMap) + const connectOnlyAccounts = new Array() + const decryptAndConnectAccounts = new Array() + + for (const candidate of this.scanningAccounts) { + if ( + !candidate.scanFrom || + BufferUtils.equalsNullable(candidate.scanFrom.hash, blockHeader.previousBlockHash) + ) { + candidate.scanFrom = null + + if ( + candidate.account.createdAt === null || + blockHeader.sequence >= candidate.account.createdAt.sequence + ) { + decryptAndConnectAccounts.push(candidate.account) + } else { + connectOnlyAccounts.push(candidate.account) + } } } - for (const account of accounts) { + for (const account of connectOnlyAccounts) { if (abort?.signal.aborted) { return } + await this.wallet.connectBlockForAccount(account, blockHeader, [], false) + } - const accountTxnsMap = decryptedNotesMap.get(account.id) - - const txns = transactions.map((transaction) => ({ - transaction, - decryptedNotes: accountTxnsMap?.get(transaction.hash()) ?? [], - })) - - await this.wallet.connectBlockForAccount( - account, - blockHeader, - txns, - shouldDecryptAccountIds.has(account.id), - ) + if (abort?.signal.aborted) { + return } + + return decryptor.decryptNotesFromBlock( + blockHeader, + transactions, + decryptAndConnectAccounts, + async (account, blockHeader, transactions) => { + if (abort?.signal.aborted) { + return + } + await this.wallet.connectBlockForAccount(account, blockHeader, transactions, true) + }, + ) } - async disconnectBlock( + private async disconnectBlock( header: BlockHeader, transactions: Transaction[], abort?: AbortController, ): Promise { this.logger.debug(`AccountHead DEL: ${header.sequence} => ${Number(header.sequence) - 1}`) - const accounts = await AsyncUtils.filter(this.wallet.listAccounts(), async (account) => { - if (!account.scanningEnabled) { - return false - } - - const accountHead = await account.getHead() - - return BufferUtils.equalsNullable(accountHead?.hash ?? null, header.hash) - }) + const accounts = (await this.getScanningAccountsWithHead()).filter(({ head }) => + BufferUtils.equalsNullable(head?.hash, header.hash), + ) - for (const account of accounts) { + for (const { account } of accounts) { if (abort?.signal.aborted) { return } - await this.wallet.disconnectBlockForAccount(account, header, transactions) } + + for (const account of this.scanningAccounts) { + if (account.scanFrom && BufferUtils.equalsNullable(account.scanFrom.hash, header.hash)) { + account.scanFrom = null + } + } + } + + getChainProcessor( + start: HeadValue | null, + ): ChainProcessorWithTransactions | RemoteChainProcessor { + const head = start?.hash ?? null + + if (this.chain) { + return new ChainProcessorWithTransactions({ + logger: this.logger, + chain: this.chain, + maxQueueSize: this.config.get('walletSyncingMaxQueueSize'), + head, + }) + } + + if (this.nodeClient) { + return new RemoteChainProcessor({ + logger: this.logger, + nodeClient: this.nodeClient, + maxQueueSize: this.config.get('walletSyncingMaxQueueSize'), + head, + }) + } + + throw new Error('WalletScanner requires either chain or client') } -} -function getTransactionsWithNoteIndex( - header: BlockHeader, - transactions: Transaction[], -): Array<{ transaction: Transaction; initialNoteIndex: number }> { - Assert.isNotNull(header.noteSize) - let initialNoteIndex = header.noteSize + /** + * Checks whether `scanningAccounts` is stale or up-to-date. + */ + private haveWalletAccountsChanged(): boolean { + const accountIds = new Set( + this.wallet.accounts + .filter((account) => account.scanningEnabled) + .map((account) => account.id), + ) + return ( + this.scanningAccounts.length !== accountIds.size || + !this.scanningAccounts.every(({ account }) => accountIds.has(account.id)) + ) + } - const result = [] + private getScanningAccountsWithHead(): Promise< + Array<{ account: Account; head: HeadValue | null }> + > { + return this.wallet.walletDb.db.withTransaction(null, async (tx) => + Promise.all( + this.wallet.accounts + .filter((account) => account.scanningEnabled) + .map(async (account) => ({ + account, + head: await account.getHead(tx), + })), + ), + ) + } - for (const transaction of transactions.slice().reverse()) { - initialNoteIndex -= transaction.notes.length - result.push({ transaction, initialNoteIndex }) + /** + * Replaces `scanningAccounts` with fresh values from the wallet. + */ + private async refreshScanningAccounts(): Promise { + this.scanningAccounts = (await this.getScanningAccountsWithHead()).map( + ({ account, head }) => ({ account, scanFrom: head }), + ) } - return result.slice().reverse() + private getEarliestHead(): HeadValue | null { + let earliestHead = null + for (const { scanFrom: head } of this.scanningAccounts) { + if (!head) { + return null + } + if (!earliestHead || earliestHead.sequence > head.sequence) { + earliestHead = head + } + } + return earliestHead + } } diff --git a/ironfish/src/wallet/wallet.test.slow.ts b/ironfish/src/wallet/wallet.test.slow.ts index 9aa371f52e..754c7ac025 100644 --- a/ironfish/src/wallet/wallet.test.slow.ts +++ b/ironfish/src/wallet/wallet.test.slow.ts @@ -1,6 +1,7 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +import type { SpiedFunction } from 'jest-mock' import { Asset, ASSET_ID_LENGTH, generateKey, multisig } from '@ironfish/rust-nodejs' import { Assert } from '../assert' import { Transaction } from '../primitives' @@ -20,8 +21,8 @@ import { AssertMultisigSigner } from '../wallet' describe('Wallet', () => { const nodeTest = createNodeTest() - let targetMeetsSpy: jest.SpyInstance - let targetSpy: jest.SpyInstance + let targetMeetsSpy: SpiedFunction + let targetSpy: SpiedFunction beforeAll(async () => { targetMeetsSpy = jest.spyOn(Target, 'meets').mockImplementation(() => true) diff --git a/ironfish/src/wallet/wallet.test.ts b/ironfish/src/wallet/wallet.test.ts index ad79899bf9..71e3357ad8 100644 --- a/ironfish/src/wallet/wallet.test.ts +++ b/ironfish/src/wallet/wallet.test.ts @@ -22,7 +22,11 @@ import { } from '../testUtilities' import { AsyncUtils, BufferUtils, ORE_TO_IRON } from '../utils' import { Account, TransactionStatus, TransactionType } from '../wallet' -import { MaxMemoLengthError } from './errors' +import { + DuplicateAccountNameError, + DuplicateSpendingKeyError, + MaxMemoLengthError, +} from './errors' import { toAccountImport } from './exporter' import { AssetStatus, Wallet } from './wallet' @@ -284,155 +288,6 @@ describe('Wallet', () => { }) }) - describe('scan', () => { - it('should update head status', async () => { - // G -> 1 -> 2 - const { node } = nodeTest - - const accountA = await useAccountFixture(node.wallet, 'accountA') - - const block1 = await useMinerBlockFixture(node.chain, 2, accountA) - await expect(node.chain).toAddBlock(block1) - await node.wallet.scan() - - // create a second account and import it so that its head hash is null - const { node: nodeB } = await nodeTest.createSetup() - const toImport = await useAccountFixture(nodeB.wallet, 'accountB') - - const accountB = await node.wallet.importAccount(toImport) - - // Confirm pre-rescan state - await expect(accountA.getHead()).resolves.toEqual({ - hash: block1.header.hash, - sequence: block1.header.sequence, - }) - await expect(accountB.getHead()).resolves.toEqual(null) - - // Add second block - const block2 = await useMinerBlockFixture(node.chain, 3, accountA) - await expect(node.chain).toAddBlock(block2) - - await node.wallet.scan() - - await expect(accountA.getHead()).resolves.toEqual({ - hash: block2.header.hash, - sequence: block2.header.sequence, - }) - await expect(accountB.getHead()).resolves.toEqual({ - hash: block2.header.hash, - sequence: block2.header.sequence, - }) - }) - - it('should not scan if wallet is disabled', async () => { - const { wallet, chain } = await nodeTest.createSetup({ config: { enableWallet: false } }) - - // Create a new account but don't give it an account birthday so the wallet head does not update - await useAccountFixture(wallet, 'test', { createdAt: null }) - - const block1 = await useMinerBlockFixture(chain) - await expect(chain).toAddBlock(block1) - - const scanSpy = jest.spyOn(wallet.scanner, 'scan') - await wallet.scan() - expect(scanSpy).not.toHaveBeenCalled() - }) - - it('should not scan if all accounts are up to date', async () => { - const { chain, wallet } = nodeTest - - const accountA = await useAccountFixture(wallet, 'accountA') - const accountB = await useAccountFixture(wallet, 'accountB') - - const block1 = await useMinerBlockFixture(chain) - await expect(chain).toAddBlock(block1) - - await wallet.scan() - - await expect(accountA.getHead()).resolves.toEqual({ - hash: block1.header.hash, - sequence: block1.header.sequence, - }) - await expect(accountB.getHead()).resolves.toEqual({ - hash: block1.header.hash, - sequence: block1.header.sequence, - }) - - const connectSpy = jest.spyOn(wallet, 'connectBlockForAccount') - - await wallet.scan() - - expect(connectSpy).not.toHaveBeenCalled() - }) - - it('should scan until the chain head', async () => { - const { node } = await nodeTest.createSetup() - - // create an account so that the wallet will sync - await useAccountFixture(node.wallet, 'a') - - // update wallet to genesis block - await node.wallet.scan() - - const block2 = await useMinerBlockFixture(node.chain, undefined) - await expect(node.chain).toAddBlock(block2) - const block3 = await useMinerBlockFixture(node.chain, undefined) - await expect(node.chain).toAddBlock(block3) - - expect(node.chain.head.hash).toEqualHash(block3.header.hash) - - let head = await node.wallet.getEarliestHead() - expect(head?.hash).toEqualHash(node.chain.genesis.hash) - - // set max syncing queue to 1 so that wallet only fetches one block at a time - node.wallet.scanner.maxQueueSize = 1 - - await node.wallet.scan() - - head = await node.wallet.getEarliestHead() - expect(head?.hash).toEqualHash(node.chain.head.hash) - }) - - it('should start from null account head', async () => { - // G -> 1 -> 2 - const { node } = nodeTest - - const accountA = await useAccountFixture(node.wallet, 'accountA') - - const block1 = await useMinerBlockFixture(node.chain, 2, accountA) - await expect(node.chain).toAddBlock(block1) - await node.wallet.scan() - - // create a second account and import it so that its head hash is null - const { node: nodeB } = await nodeTest.createSetup() - const toImport = await useAccountFixture(nodeB.wallet, 'accountB') - - const accountB = await node.wallet.importAccount(toImport) - - // Confirm pre-rescan state - await expect(accountA.getHead()).resolves.toEqual({ - hash: block1.header.hash, - sequence: block1.header.sequence, - }) - await expect(accountB.getHead()).resolves.toEqual(null) - - // Add second block - const block2 = await useMinerBlockFixture(node.chain, 3, accountA) - await expect(node.chain).toAddBlock(block2) - - await node.wallet.scan() - - await expect(accountA.getHead()).resolves.toEqual({ - hash: block2.header.hash, - sequence: block2.header.sequence, - }) - await expect(accountB.getHead()).resolves.toEqual({ - hash: block2.header.hash, - sequence: block2.header.sequence, - }) - }) - }) - describe('getBalances', () => { it('returns balances for all unspent notes across assets for an account', async () => { const { node } = await nodeTest.createSetup() @@ -648,7 +503,7 @@ describe('Wallet', () => { expect(node.wallet.accountExists(account.name)).toEqual(true) await expect(node.wallet.importAccount(account)).rejects.toThrow( - 'Account already exists with the name', + DuplicateAccountNameError, ) }) @@ -662,9 +517,7 @@ describe('Wallet', () => { const clone = { ...account } clone.name = 'Different name' - await expect(node.wallet.importAccount(clone)).rejects.toThrow( - 'Account already exists with provided spending key', - ) + await expect(node.wallet.importAccount(clone)).rejects.toThrow(DuplicateSpendingKeyError) }) it('should be able to import an account from solely its view keys', async () => { @@ -1617,181 +1470,152 @@ describe('Wallet', () => { }) }) - describe('connectBlock', () => { - it('should add transactions to the walletDb with blockHash and sequence set', async () => { - const { node } = await nodeTest.createSetup() + describe('scan', () => { + it('should update head status', async () => { + // G -> 1 -> 2 + const { node } = nodeTest - const accountA = await useAccountFixture(node.wallet, 'a') - const accountB = await useAccountFixture(node.wallet, 'b') + const accountA = await useAccountFixture(node.wallet, 'accountA') - const blockA1 = await useMinerBlockFixture(node.chain, undefined, accountA, node.wallet) - await expect(node.chain).toAddBlock(blockA1) + const block1 = await useMinerBlockFixture(node.chain, 2, accountA) + await expect(node.chain).toAddBlock(block1) await node.wallet.scan() - const { block: blockA2, transaction } = await useBlockWithTx(node, accountA, accountB) - await expect(node.chain).toAddBlock(blockA2) - - const transactions = await node.chain.getBlockTransactions(blockA2.header) - await node.wallet.scanner.connectBlock( - blockA2.header, - transactions.map((t) => t.transaction), - ) - - const transactionValue = await accountA.getTransaction(transaction.hash()) + // create a second account and import it so that its head hash is null + const { node: nodeB } = await nodeTest.createSetup() + const toImport = await useAccountFixture(nodeB.wallet, 'accountB') - expect(transactionValue).toBeDefined() - expect(transactionValue?.blockHash).toEqualHash(blockA2.header.hash) - expect(transactionValue?.sequence).toEqual(blockA2.header.sequence) - }) + const accountB = await node.wallet.importAccount(toImport) - it('should update the account head hash', async () => { - const { node } = await nodeTest.createSetup() + // Confirm pre-rescan state + await expect(accountA.getHead()).resolves.toEqual({ + hash: block1.header.hash, + sequence: block1.header.sequence, + }) + await expect(accountB.getHead()).resolves.toEqual(null) - const accountA = await useAccountFixture(node.wallet, 'a') - const accountB = await useAccountFixture(node.wallet, 'b') + // Add second block + const block2 = await useMinerBlockFixture(node.chain, 3, accountA) + await expect(node.chain).toAddBlock(block2) - const blockA1 = await useMinerBlockFixture(node.chain, undefined, accountA, node.wallet) - await expect(node.chain).toAddBlock(blockA1) await node.wallet.scan() - const { block: blockA2 } = await useBlockWithTx(node, accountA, accountB) - await expect(node.chain).toAddBlock(blockA2) + await expect(accountA.getHead()).resolves.toEqual({ + hash: block2.header.hash, + sequence: block2.header.sequence, + }) + await expect(accountB.getHead()).resolves.toEqual({ + hash: block2.header.hash, + sequence: block2.header.sequence, + }) + }) - const transactions = await node.chain.getBlockTransactions(blockA2.header) - await node.wallet.scanner.connectBlock( - blockA2.header, - transactions.map((t) => t.transaction), - ) + it('should not scan if wallet is disabled', async () => { + const { wallet, chain } = await nodeTest.createSetup({ config: { enableWallet: false } }) - const accountAHead = await accountA.getHead() + // Create a new account but don't give it an account birthday so the wallet head does not update + await useAccountFixture(wallet, 'test', { createdAt: null }) - expect(accountAHead?.hash).toEqualHash(blockA2.header.hash) + const block1 = await useMinerBlockFixture(chain) + await expect(chain).toAddBlock(block1) + + const scanSpy = jest.spyOn(wallet.scanner, 'scan') + await wallet.scan() + expect(scanSpy).not.toHaveBeenCalled() }) - it('should update the account unconfirmed balance', async () => { - const { node } = await nodeTest.createSetup() + it('should not scan if all accounts are up to date', async () => { + const { chain, wallet } = nodeTest - const accountA = await useAccountFixture(node.wallet, 'a') - const accountB = await useAccountFixture(node.wallet, 'b') + const accountA = await useAccountFixture(wallet, 'accountA') + const accountB = await useAccountFixture(wallet, 'accountB') - const blockA1 = await useMinerBlockFixture(node.chain, undefined, accountA, node.wallet) - await expect(node.chain).toAddBlock(blockA1) - await node.wallet.scan() + const block1 = await useMinerBlockFixture(chain) + await expect(chain).toAddBlock(block1) - const balanceBefore = await accountA.getUnconfirmedBalance(Asset.nativeId()) - expect(balanceBefore.unconfirmed).toEqual(2000000000n) + await wallet.scan() - const { block: blockA2 } = await useBlockWithTx(node, accountA, accountB, false) - await expect(node.chain).toAddBlock(blockA2) + await expect(accountA.getHead()).resolves.toEqual({ + hash: block1.header.hash, + sequence: block1.header.sequence, + }) + await expect(accountB.getHead()).resolves.toEqual({ + hash: block1.header.hash, + sequence: block1.header.sequence, + }) - const transactions = await node.chain.getBlockTransactions(blockA2.header) - await node.wallet.scanner.connectBlock( - blockA2.header, - transactions.map((t) => t.transaction), - ) + const connectSpy = jest.spyOn(wallet, 'connectBlockForAccount') + + await wallet.scan() - const balanceAfter = await accountA.getUnconfirmedBalance(Asset.nativeId()) - expect(balanceAfter.unconfirmed).toEqual(1999999998n) + expect(connectSpy).not.toHaveBeenCalled() }) - it('should not connect blocks behind the account head', async () => { + it('should scan until the chain head', async () => { const { node } = await nodeTest.createSetup() - const accountA = await useAccountFixture(node.wallet, 'a') + // create an account so that the wallet will sync + await useAccountFixture(node.wallet, 'a') - const blockA1 = await useMinerBlockFixture(node.chain, undefined, accountA, node.wallet) - await expect(node.chain).toAddBlock(blockA1) + // update wallet to genesis block await node.wallet.scan() - const blockA2 = await useMinerBlockFixture(node.chain, undefined, accountA, node.wallet) - await expect(node.chain).toAddBlock(blockA2) - - const transactions = await node.chain.getBlockTransactions(blockA2.header) - await node.wallet.scanner.connectBlock( - blockA2.header, - transactions.map((t) => t.transaction), - ) - - let accountAHead = await accountA.getHead() - expect(accountAHead?.hash).toEqualHash(blockA2.header.hash) - - // Try to connect A2 again - await node.wallet.scanner.connectBlock( - blockA1.header, - transactions.map((t) => t.transaction), - ) + const block2 = await useMinerBlockFixture(node.chain, undefined) + await expect(node.chain).toAddBlock(block2) + const block3 = await useMinerBlockFixture(node.chain, undefined) + await expect(node.chain).toAddBlock(block3) - // accountA head hash should be unchanged - accountAHead = await accountA.getHead() - expect(accountAHead?.hash).toEqualHash(blockA2.header.hash) - }) + expect(node.chain.head.hash).toEqualHash(block3.header.hash) - it('should not connect blocks equal to the account head', async () => { - const { node } = await nodeTest.createSetup() + let head = await node.wallet.getEarliestHead() + expect(head?.hash).toEqualHash(node.chain.genesis.hash) - const accountA = await useAccountFixture(node.wallet, 'a') + // set max syncing queue to 1 so that wallet only fetches one block at a time + node.wallet.scanner.config.set('walletSyncingMaxQueueSize', 1) - const blockA1 = await useMinerBlockFixture(node.chain, undefined, accountA, node.wallet) - await expect(node.chain).toAddBlock(blockA1) await node.wallet.scan() - const blockA2 = await useMinerBlockFixture(node.chain, undefined, accountA, node.wallet) - await expect(node.chain).toAddBlock(blockA2) - - const transactionsA2 = await node.chain.getBlockTransactions(blockA2.header) - await node.wallet.scanner.connectBlock( - blockA2.header, - transactionsA2.map((t) => t.transaction), - ) - - let accountAHead = await accountA.getHead() - expect(accountAHead?.hash).toEqualHash(blockA2.header.hash) - - const updateHeadSpy = jest.spyOn(accountA, 'updateHead') - - // Try to connect A1 again - const transactionsA1 = await node.chain.getBlockTransactions(blockA1.header) - await node.wallet.scanner.connectBlock( - blockA1.header, - transactionsA1.map((t) => t.transaction), - ) - - expect(updateHeadSpy).not.toHaveBeenCalled() - - accountAHead = await accountA.getHead() - expect(accountAHead?.hash).toEqualHash(blockA2.header.hash) + head = await node.wallet.getEarliestHead() + expect(head?.hash).toEqualHash(node.chain.head.hash) }) - it('should not connect blocks more than one block ahead of the account head', async () => { - const { node } = await nodeTest.createSetup() + it('should start from null account head', async () => { + // G -> 1 -> 2 + const { node } = nodeTest - const accountA = await useAccountFixture(node.wallet, 'a') + const accountA = await useAccountFixture(node.wallet, 'accountA') - const blockA1 = await useMinerBlockFixture(node.chain, undefined, accountA, node.wallet) - await expect(node.chain).toAddBlock(blockA1) + const block1 = await useMinerBlockFixture(node.chain, 2, accountA) + await expect(node.chain).toAddBlock(block1) await node.wallet.scan() - const blockA2 = await useMinerBlockFixture(node.chain, undefined, accountA, node.wallet) - await expect(node.chain).toAddBlock(blockA2) - const blockA3 = await useMinerBlockFixture(node.chain, undefined, accountA, node.wallet) - await expect(node.chain).toAddBlock(blockA3) + // create a second account and import it so that its head hash is null + const { node: nodeB } = await nodeTest.createSetup() + const toImport = await useAccountFixture(nodeB.wallet, 'accountB') - let accountAHead = await accountA.getHead() - expect(accountAHead?.hash).toEqualHash(blockA1.header.hash) + const accountB = await node.wallet.importAccount(toImport) - const updateHeadSpy = jest.spyOn(accountA, 'updateHead') + // Confirm pre-rescan state + await expect(accountA.getHead()).resolves.toEqual({ + hash: block1.header.hash, + sequence: block1.header.sequence, + }) + await expect(accountB.getHead()).resolves.toEqual(null) - // Try to connect A3 - const transactionsA3 = await node.chain.getBlockTransactions(blockA3.header) - await node.wallet.scanner.connectBlock( - blockA3.header, - transactionsA3.map((t) => t.transaction), - ) + // Add second block + const block2 = await useMinerBlockFixture(node.chain, 3, accountA) + await expect(node.chain).toAddBlock(block2) - expect(updateHeadSpy).not.toHaveBeenCalled() + await node.wallet.scan() - accountAHead = await accountA.getHead() - expect(accountAHead?.hash).toEqualHash(blockA1.header.hash) + await expect(accountA.getHead()).resolves.toEqual({ + hash: block2.header.hash, + sequence: block2.header.sequence, + }) + await expect(accountB.getHead()).resolves.toEqual({ + hash: block2.header.hash, + sequence: block2.header.sequence, + }) }) it('should update balance hash and sequence for each block', async () => { @@ -2046,51 +1870,6 @@ describe('Wallet', () => { expect(accountA.createdAt?.sequence).toEqual(block2.header.sequence) }) - it('should skip decryption for accounts with createdAt later than the block header', async () => { - const { node: nodeA } = await nodeTest.createSetup() - - let accountA: Account | null = await useAccountFixture(nodeA.wallet, 'a') - - const block2 = await useMinerBlockFixture(nodeA.chain, 2, undefined) - await nodeA.chain.addBlock(block2) - await nodeA.wallet.scan() - const block3 = await useMinerBlockFixture(nodeA.chain, 2, undefined) - await nodeA.chain.addBlock(block3) - await nodeA.wallet.scan() - - // create second account with createdAt at block 3 - const accountB = await useAccountFixture(nodeA.wallet, 'b') - - expect(accountB.createdAt).not.toBeNull() - expect(accountB.createdAt?.sequence).toEqual(block3.header.sequence) - - // reset wallet - await nodeA.wallet.reset() - - // account instances will have changed after reset, so re-load accountA - accountA = nodeA.wallet.getAccountByName('a') - Assert.isNotNull(accountA) - - const transactions = await nodeA.chain.getBlockTransactions(nodeA.chain.genesis) - await nodeA.wallet.scanner.connectBlock( - nodeA.chain.genesis, - transactions.map((t) => t.transaction), - ) - - const decryptSpy = jest.spyOn(nodeA.wallet, 'decryptNotes') - - // reconnect block2 - const transactions2 = await nodeA.chain.getBlockTransactions(block2.header) - await nodeA.wallet.scanner.connectBlock( - block2.header, - transactions2.map((t) => t.transaction), - ) - - // see that decryption was skipped for accountB - expect(decryptSpy).toHaveBeenCalledTimes(1) - expect(decryptSpy.mock.lastCall?.[3]).toEqual([accountA]) - }) - it('should skip updating accounts with scanningEnabled set to false', async () => { const { node } = await nodeTest.createSetup() const accountA: Account = await useAccountFixture(node.wallet, 'a') @@ -2112,51 +1891,7 @@ describe('Wallet', () => { expect(aHead.sequence).toBe(1) expect(bHead.sequence).toBe(3) }) - }) - - describe('getAssetStatus', () => { - it('should return the correct status for assets', async () => { - const { node } = await nodeTest.createSetup() - const account = await useAccountFixture(node.wallet) - const mined = await useMinerBlockFixture(node.chain, 2, account) - await expect(node.chain).toAddBlock(mined) - await node.wallet.scan() - - const asset = new Asset(account.publicAddress, 'asset', 'metadata') - const value = BigInt(10) - const mintBlock = await useMintBlockFixture({ - node, - account, - asset, - value, - }) - - let assetValue = await node.wallet.walletDb.getAsset(account, asset.id()) - Assert.isNotUndefined(assetValue) - - // Check status before added to a block - expect(await node.wallet.getAssetStatus(account, assetValue)).toEqual(AssetStatus.PENDING) - - // Add to a block and check different confirmation ranges - await expect(node.chain).toAddBlock(mintBlock) - await node.wallet.scan() - assetValue = await node.wallet.walletDb.getAsset(account, asset.id()) - Assert.isNotUndefined(assetValue) - expect(await node.wallet.getAssetStatus(account, assetValue)).toEqual( - AssetStatus.CONFIRMED, - ) - expect( - await node.wallet.getAssetStatus(account, assetValue, { confirmations: 2 }), - ).toEqual(AssetStatus.UNCONFIRMED) - - // Remove the head and check status - jest.spyOn(account, 'getHead').mockResolvedValueOnce(Promise.resolve(null)) - expect(await node.wallet.getAssetStatus(account, assetValue)).toEqual(AssetStatus.UNKNOWN) - }) - }) - - describe('disconnectBlock', () => { it('should update transactions in the walletDb with blockHash and sequence null', async () => { const { node } = await nodeTest.createSetup() @@ -2252,248 +1987,80 @@ describe('Wallet', () => { expect(balanceAfterDisconnect.unconfirmed).toEqual(2000000000n) }) - it('should not disconnect blocks before the account head', async () => { + it('should skip disconnecting for accounts with scanningEnabled set to false', async () => { const { node } = await nodeTest.createSetup() const accountA = await useAccountFixture(node.wallet, 'a') + const accountB = await useAccountFixture(node.wallet, 'b') const blockA1 = await useMinerBlockFixture(node.chain, undefined, accountA, node.wallet) await expect(node.chain).toAddBlock(blockA1) - await node.wallet.scan() - const blockA2 = await useMinerBlockFixture(node.chain, undefined, accountA, node.wallet) await expect(node.chain).toAddBlock(blockA2) - await node.wallet.scan() - - let accountAHead = await accountA.getHead() - expect(accountAHead?.hash).toEqualHash(blockA2.header.hash) - - // Try to disconnect blockA1 - const transactions = await node.chain.getBlockTransactions(blockA1.header) - await node.wallet.scanner.disconnectBlock( - blockA1.header, - transactions.map((t) => t.transaction), - ) - - // Verify accountA head hash unchanged - accountAHead = await accountA.getHead() - expect(accountAHead?.hash).toEqualHash(blockA2.header.hash) - }) - - it('should not disconnect blocks ahead of the account head', async () => { - const { node } = await nodeTest.createSetup() - const accountA = await useAccountFixture(node.wallet, 'a') - - const blockA1 = await useMinerBlockFixture(node.chain, undefined, accountA, node.wallet) - await expect(node.chain).toAddBlock(blockA1) await node.wallet.scan() - const blockA2 = await useMinerBlockFixture(node.chain, undefined, accountA, node.wallet) - await node.chain.addBlock(blockA2) - let accountAHead = await accountA.getHead() - expect(accountAHead?.hash).toEqualHash(blockA1.header.hash) - - const updateHeadSpy = jest.spyOn(accountA, 'updateHead') - - // Try to disconnect blockA2 - const transactions = await node.chain.getBlockTransactions(blockA2.header) - await node.wallet.scanner.disconnectBlock( - blockA2.header, - transactions.map((t) => t.transaction), - ) - - expect(updateHeadSpy).not.toHaveBeenCalled() - - accountAHead = await accountA.getHead() - expect(accountAHead?.hash).toEqualHash(blockA1.header.hash) - }) - - it('should remove minersFee transactions', async () => { - const { node } = await nodeTest.createSetup() - - const accountA = await useAccountFixture(node.wallet, 'a') - - const blockA1 = await useMinerBlockFixture(node.chain, undefined, accountA, node.wallet) - const transaction = blockA1.transactions[0] - - Assert.isTrue(transaction.isMinersFee()) - - await expect(node.chain).toAddBlock(blockA1) - await node.wallet.scan() - - const accountAHead = await accountA.getHead() - expect(accountAHead?.hash).toEqualHash(blockA1.header.hash) - await expect(accountA.hasTransaction(transaction.hash())).resolves.toEqual(true) - - // disconnect blockA1 - const transactions = await node.chain.getBlockTransactions(blockA1.header) - await node.wallet.scanner.disconnectBlock( - blockA1.header, - transactions.map((t) => t.transaction), - ) - - await expect(accountA.hasTransaction(transaction.hash())).resolves.toEqual(false) - }) - - it('should update balance hash and sequence for each block', async () => { - const { node } = await nodeTest.createSetup() + let accountBHead = await accountB.getHead() - const accountA = await useAccountFixture(node.wallet, 'a') - const accountB = await useAccountFixture(node.wallet, 'b') + expect(accountAHead?.hash).toEqualHash(blockA2.header.hash) + expect(accountBHead?.hash).toEqualHash(blockA2.header.hash) - const blockA1 = await useMinerBlockFixture(node.chain, undefined, accountA, node.wallet) - await expect(node.chain).toAddBlock(blockA1) - await node.wallet.scan() + await accountA.updateScanningEnabled(false) - await expect(accountA.getUnconfirmedBalance(Asset.nativeId())).resolves.toMatchObject({ - blockHash: blockA1.header.hash, - sequence: blockA1.header.sequence, - unconfirmed: 2000000000n, - }) - await expect(accountB.getUnconfirmedBalance(Asset.nativeId())).resolves.toMatchObject({ - blockHash: blockA1.header.hash, - sequence: blockA1.header.sequence, - unconfirmed: 0n, + await node.chain.blockchainDb.db.transaction(async (tx) => { + await node.chain.disconnect(blockA2, tx) }) - const blockA2 = await useMinerBlockFixture(node.chain, undefined, accountB, node.wallet) - await expect(node.chain).toAddBlock(blockA2) await node.wallet.scan() - await expect(accountA.getUnconfirmedBalance(Asset.nativeId())).resolves.toMatchObject({ - blockHash: blockA2.header.hash, - sequence: blockA2.header.sequence, - unconfirmed: 2000000000n, - }) - await expect(accountB.getUnconfirmedBalance(Asset.nativeId())).resolves.toMatchObject({ - blockHash: blockA2.header.hash, - sequence: blockA2.header.sequence, - unconfirmed: 2000000000n, - }) - - const transactions = await node.chain.getBlockTransactions(blockA2.header) - await node.wallet.scanner.disconnectBlock( - blockA2.header, - transactions.map((t) => t.transaction), - ) + accountAHead = await accountA.getHead() + accountBHead = await accountB.getHead() - await expect(accountA.getUnconfirmedBalance(Asset.nativeId())).resolves.toMatchObject({ - blockHash: blockA1.header.hash, - sequence: blockA1.header.sequence, - unconfirmed: 2000000000n, - }) - await expect(accountB.getUnconfirmedBalance(Asset.nativeId())).resolves.toMatchObject({ - blockHash: blockA1.header.hash, - sequence: blockA1.header.sequence, - unconfirmed: 0n, - }) + expect(accountAHead?.hash).toEqualHash(blockA2.header.hash) + expect(accountBHead?.hash).toEqualHash(blockA2.header.previousBlockHash) }) + }) - it('should update balance hash and sequence for each asset in each block', async () => { + describe('getAssetStatus', () => { + it('should return the correct status for assets', async () => { const { node } = await nodeTest.createSetup() + const account = await useAccountFixture(node.wallet) - const accountA = await useAccountFixture(node.wallet, 'a') - - const blockA1 = await useMinerBlockFixture(node.chain, undefined, accountA, node.wallet) - await expect(node.chain).toAddBlock(blockA1) + const mined = await useMinerBlockFixture(node.chain, 2, account) + await expect(node.chain).toAddBlock(mined) await node.wallet.scan() - await expect(accountA.getUnconfirmedBalance(Asset.nativeId())).resolves.toMatchObject({ - blockHash: blockA1.header.hash, - sequence: blockA1.header.sequence, - unconfirmed: 2000000000n, - }) - - const asset = new Asset(accountA.publicAddress, 'fakeasset', 'metadata') + const asset = new Asset(account.publicAddress, 'asset', 'metadata') const value = BigInt(10) const mintBlock = await useMintBlockFixture({ node, - account: accountA, + account, asset, value, - sequence: 3, - }) - await expect(node.chain).toAddBlock(mintBlock) - await node.wallet.scan() - - await expect(accountA.getUnconfirmedBalance(Asset.nativeId())).resolves.toMatchObject({ - blockHash: mintBlock.header.hash, - sequence: mintBlock.header.sequence, - unconfirmed: 2000000000n, - }) - await expect(accountA.getUnconfirmedBalance(asset.id())).resolves.toMatchObject({ - blockHash: mintBlock.header.hash, - sequence: mintBlock.header.sequence, - unconfirmed: value, }) - const blockA3 = await useMinerBlockFixture(node.chain, undefined, accountA, node.wallet) - await expect(node.chain).toAddBlock(blockA3) - await node.wallet.scan() - - await expect(accountA.getUnconfirmedBalance(Asset.nativeId())).resolves.toMatchObject({ - blockHash: blockA3.header.hash, - sequence: blockA3.header.sequence, - unconfirmed: 4000000000n, - }) - await expect(accountA.getUnconfirmedBalance(asset.id())).resolves.toMatchObject({ - blockHash: blockA3.header.hash, - sequence: blockA3.header.sequence, - unconfirmed: value, - }) - - const transactions = await node.chain.getBlockTransactions(blockA3.header) - await node.wallet.scanner.disconnectBlock( - blockA3.header, - transactions.map((t) => t.transaction), - ) - - await expect(accountA.getUnconfirmedBalance(Asset.nativeId())).resolves.toMatchObject({ - blockHash: mintBlock.header.hash, - sequence: mintBlock.header.sequence, - unconfirmed: 2000000000n, - }) - await expect(accountA.getUnconfirmedBalance(asset.id())).resolves.toMatchObject({ - blockHash: mintBlock.header.hash, - sequence: mintBlock.header.sequence, - unconfirmed: value, - }) - }) - - it('should skip disconnecting for accounts with scanningEnabled set to false', async () => { - const { node } = await nodeTest.createSetup() - - const accountA = await useAccountFixture(node.wallet, 'a') - const accountB = await useAccountFixture(node.wallet, 'b') - - const blockA1 = await useMinerBlockFixture(node.chain, undefined, accountA, node.wallet) - await expect(node.chain).toAddBlock(blockA1) - const blockA2 = await useMinerBlockFixture(node.chain, undefined, accountA, node.wallet) - await expect(node.chain).toAddBlock(blockA2) - - await node.wallet.scan() - - let accountAHead = await accountA.getHead() - let accountBHead = await accountB.getHead() - - expect(accountAHead?.hash).toEqualHash(blockA2.header.hash) - expect(accountBHead?.hash).toEqualHash(blockA2.header.hash) - - await accountA.updateScanningEnabled(false) + let assetValue = await node.wallet.walletDb.getAsset(account, asset.id()) + Assert.isNotUndefined(assetValue) - await node.chain.blockchainDb.db.transaction(async (tx) => { - await node.chain.disconnect(blockA2, tx) - }) + // Check status before added to a block + expect(await node.wallet.getAssetStatus(account, assetValue)).toEqual(AssetStatus.PENDING) + // Add to a block and check different confirmation ranges + await expect(node.chain).toAddBlock(mintBlock) await node.wallet.scan() + assetValue = await node.wallet.walletDb.getAsset(account, asset.id()) + Assert.isNotUndefined(assetValue) + expect(await node.wallet.getAssetStatus(account, assetValue)).toEqual( + AssetStatus.CONFIRMED, + ) + expect( + await node.wallet.getAssetStatus(account, assetValue, { confirmations: 2 }), + ).toEqual(AssetStatus.UNCONFIRMED) - accountAHead = await accountA.getHead() - accountBHead = await accountB.getHead() - - expect(accountAHead?.hash).toEqualHash(blockA2.header.hash) - expect(accountBHead?.hash).toEqualHash(blockA2.header.previousBlockHash) + // Remove the head and check status + jest.spyOn(account, 'getHead').mockResolvedValueOnce(null) + expect(await node.wallet.getAssetStatus(account, assetValue)).toEqual(AssetStatus.UNKNOWN) }) }) diff --git a/ironfish/src/wallet/wallet.ts b/ironfish/src/wallet/wallet.ts index c2c2d44f4b..cb5215c514 100644 --- a/ironfish/src/wallet/wallet.ts +++ b/ironfish/src/wallet/wallet.ts @@ -1,6 +1,7 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +import type { Blockchain } from '../blockchain' import { Asset, generateKey, @@ -45,6 +46,7 @@ import { AssetBalances } from './assetBalances' import { DuplicateAccountNameError, DuplicateMultisigSecretNameError, + DuplicateSpendingKeyError, MaxMemoLengthError, NotEnoughFundsError, } from './errors' @@ -91,7 +93,7 @@ export class Wallet { readonly onAccountImported = new Event<[account: Account]>() readonly onAccountRemoved = new Event<[account: Account]>() - protected readonly accounts = new Map() + protected readonly accountById = new Map() readonly walletDb: WalletDB private readonly logger: Logger readonly workerPool: WorkerPool @@ -120,6 +122,7 @@ export class Wallet { consensus, networkId, nodeClient, + chain, }: { config: Config database: WalletDB @@ -129,6 +132,7 @@ export class Wallet { consensus: Consensus networkId: number nodeClient: RpcClient | null + chain: Blockchain | null }) { this.config = config this.logger = logger.withTag('accounts') @@ -143,10 +147,11 @@ export class Wallet { this.scanner = new WalletScanner({ wallet: this, + workerPool: this.workerPool, logger: this.logger, + config: this.config, nodeClient: this.nodeClient, - maxQueueSize: this.config.get('walletSyncingMaxQueueSize'), - config: config, + chain: chain, }) } @@ -169,7 +174,7 @@ export class Wallet { return null } - if (this.listAccounts().length === 0) { + if (this.accounts.length === 0) { return null } @@ -205,7 +210,7 @@ export class Wallet { private async load(): Promise { for await (const accountValue of this.walletDb.loadAccounts()) { const account = new Account({ accountValue, walletDb: this.walletDb }) - this.accounts.set(account.id, account) + this.accountById.set(account.id, account) } const meta = await this.walletDb.loadAccountsMeta() @@ -213,7 +218,7 @@ export class Wallet { } private unload(): void { - this.accounts.clear() + this.accountById.clear() this.defaultAccount = null } @@ -317,22 +322,28 @@ export class Wallet { } } - async reset(options?: { - resetCreatedAt?: boolean - resetScanningEnabled?: boolean - tx?: IDatabaseTransaction - }): Promise { - await this.resetAccounts(options) + async reset( + options?: { + resetCreatedAt?: boolean + resetScanningEnabled?: boolean + }, + tx?: IDatabaseTransaction, + ): Promise { + await this.resetAccounts(options, tx) } - async resetAccounts(options?: { - resetCreatedAt?: boolean - resetScanningEnabled?: boolean - tx?: IDatabaseTransaction - }): Promise { - for (const account of this.listAccounts()) { - await this.resetAccount(account, options) - } + resetAccounts( + options?: { + resetCreatedAt?: boolean + resetScanningEnabled?: boolean + }, + tx?: IDatabaseTransaction, + ): Promise { + return this.walletDb.db.withTransaction(tx, async (tx) => { + for (const account of this.accounts) { + await this.resetAccount(account, options, tx) + } + }) } async decryptNotes( @@ -342,7 +353,7 @@ export class Wallet { accounts: ReadonlyArray, ): Promise>> { const workloadSize = 20 - const notePromises: Array>>> = [] + const notePromises: Array>>> = [] let decryptNotesPayloads = [] let currentNoteIndex = initialNoteIndex @@ -377,7 +388,9 @@ export class Wallet { for (const [accountId, decryptedNotes] of partialResult.entries()) { const list = mergedResults.get(accountId) Assert.isNotUndefined(list) - list.push(...(decryptedNotes.filter((note) => note !== null) as Array)) + list.push( + ...(decryptedNotes.filter((note) => note !== undefined) as Array), + ) } } @@ -387,12 +400,12 @@ export class Wallet { private decryptNotesFromTransaction( accounts: ReadonlyArray, encryptedNotes: Array, - ): Promise>> { + ): Promise>> { const accountKeys = accounts.map((account) => ({ accountId: account.id, - incomingViewKey: account.incomingViewKey, - outgoingViewKey: account.outgoingViewKey, - viewKey: account.viewKey, + incomingViewKey: Buffer.from(account.incomingViewKey, 'hex'), + outgoingViewKey: Buffer.from(account.outgoingViewKey, 'hex'), + viewKey: Buffer.from(account.viewKey, 'hex'), })) return this.workerPool.decryptNotes(accountKeys, encryptedNotes, { @@ -592,7 +605,7 @@ export class Wallet { async addPendingTransaction(transaction: Transaction): Promise { const accounts = await AsyncUtils.filter( - this.listAccounts(), + this.accounts, async (account) => !(await account.hasTransaction(transaction.hash())), ) @@ -611,7 +624,6 @@ export class Wallet { for (const account of accounts) { const decryptedNotes = decryptedNotesByAccountId.get(account.id) ?? [] - await this.backfillAssets(account, decryptedNotes, transaction.mints) await account.addPendingTransaction(transaction, decryptedNotes, head.sequence) } @@ -1098,7 +1110,7 @@ export class Wallet { } async rebroadcastTransactions(sequence: number): Promise { - for (const account of this.accounts.values()) { + for (const account of this.accountById.values()) { if (this.eventLoopAbortController.signal.aborted) { return } @@ -1142,7 +1154,7 @@ export class Wallet { } async expireTransactions(sequence: number): Promise { - for (const account of this.accounts.values()) { + for (const account of this.accountById.values()) { if (this.eventLoopAbortController.signal.aborted) { return } @@ -1296,7 +1308,7 @@ export class Wallet { await account.updateHead(createdAt, tx) }) - this.accounts.set(account.id, account) + this.accountById.set(account.id, account) if (options.setDefault) { await this.setDefaultAccount(account.name) @@ -1339,12 +1351,14 @@ export class Wallet { throw new DuplicateAccountNameError(name) } - const accounts = this.listAccounts() - if ( - accountValue.spendingKey && - accounts.find((a) => accountValue.spendingKey === a.spendingKey) - ) { - throw new Error(`Account already exists with provided spending key`) + if (accountValue.spendingKey) { + const duplicateSpendingAccount = this.accounts.find( + (a) => accountValue.spendingKey === a.spendingKey, + ) + + if (duplicateSpendingAccount) { + throw new DuplicateSpendingKeyError(duplicateSpendingAccount.name) + } } validateAccountImport(accountValue) @@ -1398,15 +1412,15 @@ export class Wallet { } }) - this.accounts.set(account.id, account) + this.accountById.set(account.id, account) this.logger.debug(`Account ${account.id} imported successfully`) this.onAccountImported.emit(account) return account } - listAccounts(): Account[] { - return Array.from(this.accounts.values()) + get accounts(): Account[] { + return Array.from(this.accountById.values()) } accountExists(name: string): boolean { @@ -1418,8 +1432,8 @@ export class Wallet { options?: { resetCreatedAt?: boolean resetScanningEnabled?: boolean - tx?: IDatabaseTransaction }, + tx?: IDatabaseTransaction, ): Promise { const newAccount = new Account({ accountValue: { @@ -1433,7 +1447,7 @@ export class Wallet { this.logger.debug(`Resetting account name: ${account.name}, id: ${account.id}`) - await this.walletDb.db.withTransaction(options?.tx, async (tx) => { + await this.walletDb.db.withTransaction(tx, async (tx) => { await this.walletDb.setAccount(newAccount, tx) if (newAccount.createdAt !== null) { @@ -1458,7 +1472,7 @@ export class Wallet { this.defaultAccount = newAccount.id } - this.accounts.set(newAccount.id, newAccount) + this.accountById.set(newAccount.id, newAccount) await this.removeAccount(account, tx) }) @@ -1474,7 +1488,8 @@ export class Wallet { } async removeAccount(account: Account, tx?: IDatabaseTransaction): Promise { - this.accounts.delete(account.id) + this.accountById.delete(account.id) + await this.walletDb.db.withTransaction(tx, async (tx) => { if (account.id === this.defaultAccount) { await this.walletDb.setDefaultAccount(null, tx) @@ -1534,26 +1549,22 @@ export class Wallet { this.defaultAccount = nextId } - getAccountByName(name: string): Account | null { - for (const account of this.accounts.values()) { - if (name === account.name) { + findAccount(predicate: (account: Account) => boolean): Account | null { + for (const account of this.accountById.values()) { + if (predicate(account)) { return account } } + return null } - getAccountByPublicAddress(publicAddress: string): Account | null { - for (const account of this.accounts.values()) { - if (publicAddress === account.publicAddress) { - return account - } - } - return null + getAccountByName(name: string): Account | null { + return this.findAccount((account) => account.name === name) } getAccount(id: string): Account | null { - const account = this.accounts.get(id) + const account = this.accountById.get(id) if (account) { return account @@ -1570,47 +1581,51 @@ export class Wallet { return this.getAccount(this.defaultAccount) } - async getEarliestHead(): Promise { - let earliestHead = null - for (const account of this.accounts.values()) { - if (!account.scanningEnabled) { - continue - } + getEarliestHead(tx?: IDatabaseTransaction): Promise { + return this.walletDb.db.withTransaction(tx, async (tx) => { + let earliestHead = null + for (const account of this.accountById.values()) { + if (!account.scanningEnabled) { + continue + } - const head = await account.getHead() + const head = await account.getHead(tx) - if (!head) { - return null - } + if (!head) { + return null + } - if (!earliestHead || earliestHead.sequence > head.sequence) { - earliestHead = head + if (!earliestHead || earliestHead.sequence > head.sequence) { + earliestHead = head + } } - } - return earliestHead + return earliestHead + }) } - async getLatestHead(): Promise { - let latestHead = null + getLatestHead(tx?: IDatabaseTransaction): Promise { + return this.walletDb.db.withTransaction(tx, async (tx) => { + let latestHead = null - for (const account of this.accounts.values()) { - if (!account.scanningEnabled) { - continue - } + for (const account of this.accountById.values()) { + if (!account.scanningEnabled) { + continue + } - const head = await account.getHead() + const head = await account.getHead(tx) - if (!head) { - continue - } + if (!head) { + continue + } - if (!latestHead || latestHead.sequence < head.sequence) { - latestHead = head + if (!latestHead || latestHead.sequence < head.sequence) { + latestHead = head + } } - } - return latestHead + return latestHead + }) } async isAccountUpToDate(account: Account, confirmations?: number): Promise { diff --git a/ironfish/src/wallet/walletdb/__fixtures__/walletdb.test.ts.fixture b/ironfish/src/wallet/walletdb/__fixtures__/walletdb.test.ts.fixture index efb0e518aa..36fc19d4c0 100644 --- a/ironfish/src/wallet/walletdb/__fixtures__/walletdb.test.ts.fixture +++ b/ironfish/src/wallet/walletdb/__fixtures__/walletdb.test.ts.fixture @@ -730,5 +730,65 @@ } ] } + ], + "WalletDB loadNoteHash loads the hash of a note given its nullifier": [ + { + "value": { + "version": 4, + "id": "16812363-20b7-4d3b-a5f1-d63f9c500e9e", + "name": "test", + "spendingKey": "42c4d417d5a6da2900cbfc8a32bfbedd8c96e1848dc4a22ec6b9386fd30d7f36", + "viewKey": "d220f7afded99beec10b955b4cd9e193f59a9b0cc3a6f0d5d284f606a442cbc52f1fdbfe00b35666fde4b01bddfb5179988d1b521ee318ebe4e7914e0aa080b7", + "incomingViewKey": "ff5905b8bd1238d6e7b48082ec38caa20b3481e4a3cd0ddcbdf4d071b347a406", + "outgoingViewKey": "805590598f08f2f6c3994315b8da4d0810049f010b33c46b5928487357f86250", + "publicAddress": "0a26afc3a56a3cbccd3eae6784885776df78f406235edcbd622feef724329220", + "createdAt": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + }, + "scanningEnabled": true, + "proofAuthorizingKey": "6a7b7fecfdb8b21f5521e323d7867fd556bdfaffc93679527f099e0118014d0d" + }, + "head": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + } + } + ], + "WalletDB loadNoteHash avoids hitting the database if the nullifier is known to be not present": [ + { + "value": { + "version": 4, + "id": "de2f768a-27d8-42b1-b23f-50423f469bbb", + "name": "test", + "spendingKey": "c3c9ba31682cab87d2388ad28e3c8a8e1141e802ab69beb1d2024dab7371d95c", + "viewKey": "38bfce8064573739fbe71f220bd1b055d85fa928bb12cab6ea6cec39228524c49011b98abac356d07ce11a9073d5257935459935c704f49189de32f7450cf7d4", + "incomingViewKey": "9ae8ad607e7429180f9c9b5c00c405945d0ece39ebc0bfb7298b7635ce2d9e06", + "outgoingViewKey": "d682f910ae6d4d1f55de2def975d4db0f66f9289fbdb503cd4a12672fdd03063", + "publicAddress": "89380c90a6c6829f7302e919932fa1b8f50c38c92f30f7313f4ce425062ebecc", + "createdAt": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + }, + "scanningEnabled": true, + "proofAuthorizingKey": "fd03d976919b66a79480321fb7a04076897c7feb5180df93089d78e39503b90a" + }, + "head": { + "hash": { + "type": "Buffer", + "data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY=" + }, + "sequence": 1 + } + } ] } \ No newline at end of file diff --git a/ironfish/src/wallet/walletdb/walletdb.test.ts b/ironfish/src/wallet/walletdb/walletdb.test.ts index 2d3f007cc6..90dc863fe7 100644 --- a/ironfish/src/wallet/walletdb/walletdb.test.ts +++ b/ironfish/src/wallet/walletdb/walletdb.test.ts @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import { Asset, multisig } from '@ironfish/rust-nodejs' +import { randomBytes } from 'crypto' import { Assert } from '../../assert' import { createNodeTest, @@ -357,6 +358,51 @@ describe('WalletDB', () => { }) }) + describe('loadNoteHash', () => { + it('loads the hash of a note given its nullifier', async () => { + const node = (await nodeTest.createSetup()).node + const walletDb = node.wallet.walletDb + const account = await useAccountFixture(node.wallet) + + const noteHash = randomBytes(32) + const nullifier = randomBytes(32) + + await expect(walletDb.loadNoteHash(account, nullifier)).resolves.toBeUndefined() + await walletDb.saveNullifierNoteHash(account, nullifier, noteHash) + await expect(walletDb.loadNoteHash(account, nullifier)).resolves.toEqual(noteHash) + }) + + it('avoids hitting the database if the nullifier is known to be not present', async () => { + const node = (await nodeTest.createSetup()).node + const walletDb = node.wallet.walletDb + const account = await useAccountFixture(node.wallet) + + const noteHash = randomBytes(32) + // Randomly generated nullifiers. Using a static string instead of + // randomBytes() because loadNoteHash uses a bloom filter, which is a + // probabilistic data structure. Using a random value for each test run + // would make the test flaky. + const nullifier = Buffer.from( + 'efc9eaadc6668b24900994670acad2010b497cbefdf7a27f5f463eba59b3ed14', + 'hex', + ) + const absentNullifier = Buffer.from( + '820fabbe98bc7a7054700861949b83cfaeb00f3b8ab4028299be7315a4c7b551', + 'hex', + ) + + await walletDb.saveNullifierNoteHash(account, nullifier, noteHash) + + const getSpy = jest.spyOn(walletDb.nullifierToNoteHash, 'get') + await expect(walletDb.loadNoteHash(account, nullifier)).resolves.toEqual(noteHash) + expect(getSpy).toHaveBeenCalled() + + getSpy.mockClear() + await expect(walletDb.loadNoteHash(account, absentNullifier)).resolves.toBeUndefined() + expect(getSpy).not.toHaveBeenCalled() + }) + }) + describe('loadTransactions', () => { it('loads transactions within a given key range', async () => { const node = (await nodeTest.createSetup()).node diff --git a/ironfish/src/wallet/walletdb/walletdb.ts b/ironfish/src/wallet/walletdb/walletdb.ts index 3020e64384..d1305dd84a 100644 --- a/ironfish/src/wallet/walletdb/walletdb.ts +++ b/ironfish/src/wallet/walletdb/walletdb.ts @@ -29,6 +29,7 @@ import { import { getPrefixesKeyRange, StorageUtils } from '../../storage/database/utils' import { createDB } from '../../storage/utils' import { BufferUtils } from '../../utils' +import { BloomFilter } from '../../utils/bloomFilter' import { WorkerPool } from '../../workerPool' import { Account, calculateAccountPrefix } from '../account/account' import { AccountValue, AccountValueEncoding } from './accountValue' @@ -147,6 +148,8 @@ export class WalletDB { cacheStores: Array> + nullifierBloomFilter: BloomFilter | null = null + constructor({ files, location, @@ -740,12 +743,40 @@ export class WalletDB { } } + private loadNullifierBloomFilter(tx?: IDatabaseTransaction): Promise { + if (this.nullifierBloomFilter) { + return Promise.resolve(this.nullifierBloomFilter) + } else { + return this.db.withTransaction(tx, async (tx) => { + if (this.nullifierBloomFilter) { + // A concurrent call to this function already created the filter + return this.nullifierBloomFilter + } + + const nullifierBloomFilter = new BloomFilter(0x800000) // 1 MiB bloom filter + for await (const [_accountPrefix, nullifier] of this.nullifierToNoteHash.getAllKeysIter( + tx, + )) { + nullifierBloomFilter.put(nullifier) + } + + this.nullifierBloomFilter = nullifierBloomFilter + return nullifierBloomFilter + }) + } + } + async loadNoteHash( account: Account, nullifier: Buffer, tx?: IDatabaseTransaction, ): Promise { - return this.nullifierToNoteHash.get([account.prefix, nullifier], tx) + const nullifierFilter = await this.loadNullifierBloomFilter(tx) + if (nullifierFilter.maybeHas(nullifier)) { + return this.nullifierToNoteHash.get([account.prefix, nullifier], tx) + } else { + return undefined + } } async saveNullifierNoteHash( @@ -755,6 +786,9 @@ export class WalletDB { tx?: IDatabaseTransaction, ): Promise { await this.nullifierToNoteHash.put([account.prefix, nullifier], noteHash, tx) + if (this.nullifierBloomFilter) { + this.nullifierBloomFilter.put(nullifier) + } } async *loadNullifierToNoteHash( @@ -780,6 +814,9 @@ export class WalletDB { nullifier: Buffer, tx?: IDatabaseTransaction, ): Promise { + // `nullifierBloomFilter` is unchanged after calling this method. The + // assumption is that this method is called rarely, and so special logic to + // "reset" the bloom filter is not deemed necessary. await this.nullifierToNoteHash.del([account.prefix, nullifier], tx) } @@ -791,7 +828,7 @@ export class WalletDB { ): Promise { await this.db.withTransaction(tx, async (tx) => { if (note.nullifier) { - await this.nullifierToNoteHash.put([account.prefix, note.nullifier], noteHash, tx) + await this.saveNullifierNoteHash(account, note.nullifier, noteHash, tx) } await this.setNoteHashSequence(account, noteHash, note.sequence, tx) @@ -1129,13 +1166,13 @@ export class WalletDB { } async cleanupDeletedAccounts(recordsToCleanup: number, signal?: AbortSignal): Promise { - for (const [accountId] of await this.accountIdsToCleanup.getAll()) { + for await (const [accountId] of this.accountIdsToCleanup.getAllIter()) { const prefix = calculateAccountPrefix(accountId) const range = StorageUtils.getPrefixKeyRange(prefix) for (const store of this.cacheStores) { for await (const key of store.getAllKeysIter(undefined, range)) { - if (signal?.aborted === true || recordsToCleanup === 0) { + if (signal?.aborted === true || recordsToCleanup <= 0) { return } @@ -1145,6 +1182,7 @@ export class WalletDB { } await this.accountIdsToCleanup.del(accountId) + recordsToCleanup-- } } @@ -1228,7 +1266,12 @@ export class WalletDB { nullifier: Buffer, tx?: IDatabaseTransaction, ): Promise { - return this.nullifierToTransactionHash.get([account.prefix, nullifier], tx) + const nullifierFilter = await this.loadNullifierBloomFilter(tx) + if (nullifierFilter.maybeHas(nullifier)) { + return this.nullifierToTransactionHash.get([account.prefix, nullifier], tx) + } else { + return undefined + } } async saveNullifierToTransactionHash( @@ -1242,6 +1285,9 @@ export class WalletDB { transaction.hash(), tx, ) + if (this.nullifierBloomFilter) { + this.nullifierBloomFilter.put(nullifier) + } } async deleteNullifierToTransactionHash( @@ -1249,6 +1295,9 @@ export class WalletDB { nullifier: Buffer, tx?: IDatabaseTransaction, ): Promise { + // `nullifierBloomFilter` is unchanged after calling this method. The + // assumption is that this method is called rarely, and so special logic to + // "reset" the bloom filter is not deemed necessary. await this.nullifierToTransactionHash.del([account.prefix, nullifier], tx) } diff --git a/ironfish/src/workerPool/pool.ts b/ironfish/src/workerPool/pool.ts index 39b2071d28..0487f26b3e 100644 --- a/ironfish/src/workerPool/pool.ts +++ b/ironfish/src/workerPool/pool.ts @@ -4,7 +4,6 @@ import { getCpuCount, UnsignedTransaction } from '@ironfish/rust-nodejs' import _ from 'lodash' -import { Assert } from '../assert' import { VerificationResult, VerificationResultReason } from '../consensus' import { createRootLogger, Logger } from '../logger' import { Meter, MetricsMonitor } from '../metrics' @@ -197,7 +196,7 @@ export class WorkerPool { accountKeys: ReadonlyArray<{ accountId: string } & DecryptNotesAccountKey>, encryptedNotes: ReadonlyArray, options: DecryptNotesOptions, - ): Promise>> { + ): Promise>> { const request = new DecryptNotesRequest(accountKeys, encryptedNotes, options) const response = await this.execute(request).result() @@ -205,28 +204,7 @@ export class WorkerPool { throw new Error('Invalid response') } - // The response contains a linear array of notes for efficiency, but we - // need to return a more structured response - - const decryptedNotesByAccount = new Map>() - for (const { accountId } of accountKeys) { - decryptedNotesByAccount.set(accountId, []) - } - - let index = 0 - for (const _ of encryptedNotes) { - for (const { accountId } of accountKeys) { - const nextNote: DecryptedNote | null | undefined = response.notes[index++] - const accountDecryptedNotes = decryptedNotesByAccount.get(accountId) - Assert.isNotUndefined(nextNote) - Assert.isNotUndefined(accountDecryptedNotes) - accountDecryptedNotes.push(nextNote) - } - } - - Assert.isEqual(index, response.notes.length) - - return decryptedNotesByAccount + return response.mapToAccounts(accountKeys) } /** @@ -247,7 +225,7 @@ export class WorkerPool { await this.execute(request).result() } - private execute(request: Readonly): Job { + execute(request: Readonly): Job { // Ensure that workers are started before handling jobs this.start() diff --git a/ironfish/src/workerPool/tasks/decryptNotes.test.ts b/ironfish/src/workerPool/tasks/decryptNotes.test.ts index efe1994d53..bf7404a44f 100644 --- a/ironfish/src/workerPool/tasks/decryptNotes.test.ts +++ b/ironfish/src/workerPool/tasks/decryptNotes.test.ts @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import { DECRYPTED_NOTE_LENGTH, ENCRYPTED_NOTE_LENGTH } from '@ironfish/rust-nodejs' +import { Assert } from '../../assert' import { createNodeTest, serializePayloadToBuffer, @@ -12,16 +13,22 @@ import { } from '../../testUtilities' import { ACCOUNT_KEY_LENGTH } from '../../wallet' import { VIEW_KEY_LENGTH } from '../../wallet/walletdb/accountValue' -import { DecryptNotesRequest, DecryptNotesResponse, DecryptNotesTask } from './decryptNotes' +import { + DecryptedNote, + DecryptNotesRequest, + DecryptNotesResponse, + DecryptNotesSharedAccountKeys, + DecryptNotesTask, +} from './decryptNotes' describe('DecryptNotesRequest', () => { it('serializes the object to a buffer and deserializes to the original object', () => { const request = new DecryptNotesRequest( [ { - incomingViewKey: Buffer.alloc(ACCOUNT_KEY_LENGTH, 1).toString('hex'), - outgoingViewKey: Buffer.alloc(ACCOUNT_KEY_LENGTH, 1).toString('hex'), - viewKey: Buffer.alloc(VIEW_KEY_LENGTH, 1).toString('hex'), + incomingViewKey: Buffer.alloc(ACCOUNT_KEY_LENGTH, 1), + outgoingViewKey: Buffer.alloc(ACCOUNT_KEY_LENGTH, 1), + viewKey: Buffer.alloc(VIEW_KEY_LENGTH, 1), }, ], [ @@ -32,11 +39,48 @@ describe('DecryptNotesRequest', () => { ], { decryptForSpender: true, + skipNoteValidation: false, + }, + 0, + ) + const buffer = serializePayloadToBuffer(request) + const deserializedRequest = DecryptNotesRequest.deserializePayload( + request.jobId, + buffer, + null, + ) + expect(deserializedRequest).toEqual(request) + }) + + it('serializes the object to a buffer and deserializes to the original object with shared memory keys', () => { + const sharedKeys = new DecryptNotesSharedAccountKeys([ + { + incomingViewKey: Buffer.alloc(ACCOUNT_KEY_LENGTH, 1), + outgoingViewKey: Buffer.alloc(ACCOUNT_KEY_LENGTH, 1), + viewKey: Buffer.alloc(VIEW_KEY_LENGTH, 1), + }, + ]) + const request = new DecryptNotesRequest( + sharedKeys, + [ + { + serializedNote: Buffer.alloc(ENCRYPTED_NOTE_LENGTH, 1), + currentNoteIndex: 2, + }, + ], + { + decryptForSpender: true, + skipNoteValidation: false, }, 0, ) const buffer = serializePayloadToBuffer(request) - const deserializedRequest = DecryptNotesRequest.deserializePayload(request.jobId, buffer) + const sharedMemory = request.getSharedMemoryPayload() + const deserializedRequest = DecryptNotesRequest.deserializePayload( + request.jobId, + buffer, + sharedMemory, + ) expect(deserializedRequest).toEqual(request) }) @@ -46,9 +90,9 @@ describe('DecryptNotesRequest', () => { const request = new DecryptNotesRequest( Array.from({ length: numAccounts }, () => ({ - incomingViewKey: Buffer.alloc(ACCOUNT_KEY_LENGTH, 1).toString('hex'), - outgoingViewKey: Buffer.alloc(ACCOUNT_KEY_LENGTH, 1).toString('hex'), - viewKey: Buffer.alloc(VIEW_KEY_LENGTH, 1).toString('hex'), + incomingViewKey: Buffer.alloc(ACCOUNT_KEY_LENGTH, 1), + outgoingViewKey: Buffer.alloc(ACCOUNT_KEY_LENGTH, 1), + viewKey: Buffer.alloc(VIEW_KEY_LENGTH, 1), })), Array.from({ length: numNotes }, () => ({ serializedNote: Buffer.alloc(ENCRYPTED_NOTE_LENGTH, 1), @@ -58,7 +102,11 @@ describe('DecryptNotesRequest', () => { 0, ) const buffer = serializePayloadToBuffer(request) - const deserializedRequest = DecryptNotesRequest.deserializePayload(request.jobId, buffer) + const deserializedRequest = DecryptNotesRequest.deserializePayload( + request.jobId, + buffer, + null, + ) expect(deserializedRequest.encryptedNotes).toHaveLength(numNotes) expect(deserializedRequest.accountKeys).toHaveLength(numAccounts) }) @@ -75,7 +123,7 @@ describe('DecryptNotesResponse', () => { nullifier: Buffer.alloc(32, 1), serializedNote: Buffer.alloc(DECRYPTED_NOTE_LENGTH, 1), }, - null, + undefined, ], 0, ) @@ -101,6 +149,71 @@ describe('DecryptNotesResponse', () => { const deserializedResponse = DecryptNotesResponse.deserializePayload(request.jobId, buffer) expect(deserializedResponse.notes).toHaveLength(length) }) + + it('uses sparses arrays to minimize memory usage', () => { + const notes = [] + const notesLength = 10000 + const testNote = { + forSpender: false, + index: 1, + hash: Buffer.alloc(32, 1), + nullifier: Buffer.alloc(32, 1), + serializedNote: Buffer.alloc(DECRYPTED_NOTE_LENGTH, 1), + } + notes[1000] = testNote + notes[2000] = testNote + notes[3000] = testNote + notes.length = notesLength + expect(notes).toHaveLength(notesLength) + + const response = new DecryptNotesResponse(notes, 0) + const buffer = serializePayloadToBuffer(response) + const deserializedResponse = DecryptNotesResponse.deserializePayload(response.jobId, buffer) + + expect(deserializedResponse.notes).toHaveLength(notesLength) + expect(deserializedResponse.notes).toEqual(notes) + + const explicitlySetNotes = new Array() + deserializedResponse.notes.forEach((note) => { + Assert.isNotUndefined(note) + explicitlySetNotes.push(note) + }) + expect(explicitlySetNotes).toHaveLength(3) + expect(explicitlySetNotes).toEqual([testNote, testNote, testNote]) + }) + + describe('mapToAccounts', () => { + it('returns a map linking each account to its notes', () => { + const accounts = 'abcdefghijklmnopqrstuvwxyz' + .split('') + .map((letter) => ({ accountId: letter })) + const notesPerAccount = 100 + const length = accounts.length * notesPerAccount + + const request = new DecryptNotesResponse( + Array.from({ length }, () => ({ + forSpender: false, + index: 1, + hash: Buffer.alloc(32, 1), + nullifier: Buffer.alloc(32, 1), + serializedNote: Buffer.alloc(DECRYPTED_NOTE_LENGTH, 1), + })), + 0, + ) + + const accountsToNotes = request.mapToAccounts(accounts) + expect(accountsToNotes.size).toBe(accounts.length) + + const returnedAccounts = Array.from(accountsToNotes.keys()) + .sort() + .map((accountId) => ({ accountId })) + expect(returnedAccounts).toEqual(accounts) + + for (const notes of accountsToNotes.values()) { + expect(notes.length).toBe(notesPerAccount) + } + }) + }) }) describe('DecryptNotesTask', () => { @@ -116,9 +229,9 @@ describe('DecryptNotesTask', () => { const request = new DecryptNotesRequest( [ { - incomingViewKey: account.incomingViewKey, - outgoingViewKey: account.outgoingViewKey, - viewKey: account.viewKey, + incomingViewKey: Buffer.from(account.incomingViewKey, 'hex'), + outgoingViewKey: Buffer.from(account.outgoingViewKey, 'hex'), + viewKey: Buffer.from(account.viewKey, 'hex'), }, ], [ @@ -159,9 +272,9 @@ describe('DecryptNotesTask', () => { const requestSpender = new DecryptNotesRequest( [ { - incomingViewKey: accountA.incomingViewKey, - outgoingViewKey: accountA.outgoingViewKey, - viewKey: accountA.viewKey, + incomingViewKey: Buffer.from(accountA.incomingViewKey, 'hex'), + outgoingViewKey: Buffer.from(accountA.outgoingViewKey, 'hex'), + viewKey: Buffer.from(accountA.viewKey, 'hex'), }, ], [ @@ -189,9 +302,9 @@ describe('DecryptNotesTask', () => { const requestNoSpender = new DecryptNotesRequest( [ { - incomingViewKey: accountA.incomingViewKey, - outgoingViewKey: accountA.outgoingViewKey, - viewKey: accountA.viewKey, + incomingViewKey: Buffer.from(accountA.incomingViewKey, 'hex'), + outgoingViewKey: Buffer.from(accountA.outgoingViewKey, 'hex'), + viewKey: Buffer.from(accountA.viewKey, 'hex'), }, ], [ @@ -204,7 +317,7 @@ describe('DecryptNotesTask', () => { ) const responseNoSpender = task.execute(requestNoSpender) - expect(responseNoSpender).toMatchObject({ notes: [null] }) + expect(responseNoSpender).toMatchObject({ notes: [undefined] }) }) }) }) diff --git a/ironfish/src/workerPool/tasks/decryptNotes.ts b/ironfish/src/workerPool/tasks/decryptNotes.ts index f65365a2c1..23ad380718 100644 --- a/ironfish/src/workerPool/tasks/decryptNotes.ts +++ b/ironfish/src/workerPool/tasks/decryptNotes.ts @@ -3,20 +3,26 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import { DECRYPTED_NOTE_LENGTH, ENCRYPTED_NOTE_LENGTH } from '@ironfish/rust-nodejs' import bufio from 'bufio' +import { Assert } from '../../assert' import { NoteEncrypted } from '../../primitives/noteEncrypted' import { ACCOUNT_KEY_LENGTH } from '../../wallet' import { VIEW_KEY_LENGTH } from '../../wallet/walletdb/accountValue' import { WorkerMessage, WorkerMessageType } from './workerMessage' import { WorkerTask } from './workerTask' +const NO_NOTE_INDEX: number = (1 << 32) - 1 + +const ACCOUNT_KEY_SIZE: number = ACCOUNT_KEY_LENGTH + ACCOUNT_KEY_LENGTH + VIEW_KEY_LENGTH + export interface DecryptNotesOptions { decryptForSpender: boolean + skipNoteValidation?: boolean } export interface DecryptNotesAccountKey { - incomingViewKey: string - outgoingViewKey: string - viewKey: string + incomingViewKey: Buffer + outgoingViewKey: Buffer + viewKey: Buffer } export interface DecryptNotesItem { @@ -32,15 +38,91 @@ export interface DecryptedNote { serializedNote: Buffer } -const NO_NOTE_INDEX: number = (1 << 32) - 1 +export type DecryptNotesAccountKeys = + | DecryptNotesInlineAccountKeys + | DecryptNotesSharedAccountKeys +export type ReadonlyDecryptNotesAccountKeys = + | ReadonlyDecryptNotesInlineAccountKeys + | DecryptNotesSharedAccountKeys + +export type DecryptNotesInlineAccountKeys = Array +export type ReadonlyDecryptNotesInlineAccountKeys = ReadonlyArray + +export class DecryptNotesSharedAccountKeys { + readonly length: number + readonly sharedBuffer: SharedArrayBuffer + + constructor(accountKeys: ReadonlyArray | SharedArrayBuffer) { + if (accountKeys instanceof SharedArrayBuffer) { + this.length = Math.trunc(accountKeys.byteLength / ACCOUNT_KEY_SIZE) + this.sharedBuffer = accountKeys + } else { + this.length = accountKeys.length + this.sharedBuffer = DecryptNotesSharedAccountKeys.serialize(accountKeys) + } + } + + at(index: number): DecryptNotesAccountKey | undefined { + if (index >= this.length) { + return undefined + } + + const incomingViewKeyStart = index * ACCOUNT_KEY_LENGTH + const outgoingViewKeyStart = this.length * ACCOUNT_KEY_LENGTH + index * ACCOUNT_KEY_LENGTH + const viewKeyStart = 2 * this.length * ACCOUNT_KEY_LENGTH + index * VIEW_KEY_LENGTH + + return { + incomingViewKey: Buffer.from(this.sharedBuffer, incomingViewKeyStart, ACCOUNT_KEY_LENGTH), + outgoingViewKey: Buffer.from(this.sharedBuffer, outgoingViewKeyStart, ACCOUNT_KEY_LENGTH), + viewKey: Buffer.from(this.sharedBuffer, viewKeyStart, VIEW_KEY_LENGTH), + } + } + + map(fn: (key: DecryptNotesAccountKey) => T): Array { + const result = new Array() + for (let index = 0; index < this.length; index++) { + const key = this.at(index) + Assert.isNotUndefined(key) + result.push(fn(key)) + } + return result + } + + private static serialize( + accountKeys: ReadonlyArray, + ): SharedArrayBuffer { + const size = ACCOUNT_KEY_SIZE * accountKeys.length + + const buffer = new SharedArrayBuffer(size) + const array = new Uint8Array(buffer) + let offset = 0 + + const write = (bytes: Buffer) => { + array.set(bytes, offset) + offset += bytes.length + } + + for (const key of accountKeys) { + write(key.incomingViewKey) + } + for (const key of accountKeys) { + write(key.outgoingViewKey) + } + for (const key of accountKeys) { + write(key.viewKey) + } + + return buffer + } +} export class DecryptNotesRequest extends WorkerMessage { - readonly accountKeys: ReadonlyArray + readonly accountKeys: ReadonlyDecryptNotesAccountKeys readonly encryptedNotes: ReadonlyArray readonly options: DecryptNotesOptions constructor( - accountKeys: ReadonlyArray, + accountKeys: ReadonlyDecryptNotesAccountKeys, encryptedNotes: ReadonlyArray, options: DecryptNotesOptions, jobId?: number, @@ -52,13 +134,19 @@ export class DecryptNotesRequest extends WorkerMessage { } serializePayload(bw: bufio.StaticWriter | bufio.BufferWriter): void { - bw.writeU8(this.options.decryptForSpender ? 1 : 0) - bw.writeU32(this.accountKeys.length) - - for (const key of this.accountKeys) { - bw.writeBytes(Buffer.from(key.incomingViewKey, 'hex')) - bw.writeBytes(Buffer.from(key.outgoingViewKey, 'hex')) - bw.writeBytes(Buffer.from(key.viewKey, 'hex')) + const flags = + (Number(this.options.decryptForSpender) << 0) | + (Number(this.options.skipNoteValidation ?? false) << 1) | + (Number(this.accountKeys instanceof DecryptNotesSharedAccountKeys) << 2) + bw.writeU8(flags) + + if (!(this.accountKeys instanceof DecryptNotesSharedAccountKeys)) { + bw.writeU32(this.accountKeys.length) + for (const key of this.accountKeys) { + bw.writeBytes(key.incomingViewKey) + bw.writeBytes(key.outgoingViewKey) + bw.writeBytes(key.viewKey) + } } for (const note of this.encryptedNotes) { @@ -67,21 +155,51 @@ export class DecryptNotesRequest extends WorkerMessage { } } - static deserializePayload(jobId: number, buffer: Buffer): DecryptNotesRequest { + getSharedMemoryPayload(): SharedArrayBuffer | null { + if (this.accountKeys instanceof DecryptNotesSharedAccountKeys) { + return this.accountKeys.sharedBuffer + } else { + return null + } + } + + static deserializePayload( + jobId: number, + buffer: Buffer, + sharedAccountKeys: SharedArrayBuffer | null, + ): DecryptNotesRequest { const reader = bufio.read(buffer, true) - const accountKeys = [] - const encryptedNotes = [] - const options = { decryptForSpender: reader.readU8() !== 0 } - - const keysLength = reader.readU32() - for (let i = 0; i < keysLength; i++) { - const incomingViewKey = reader.readBytes(ACCOUNT_KEY_LENGTH).toString('hex') - const outgoingViewKey = reader.readBytes(ACCOUNT_KEY_LENGTH).toString('hex') - const viewKey = reader.readBytes(VIEW_KEY_LENGTH).toString('hex') - accountKeys.push({ incomingViewKey, outgoingViewKey, viewKey }) + const flags = reader.readU8() + const options = { + decryptForSpender: !!(flags & (1 << 0)), + skipNoteValidation: !!(flags & (1 << 1)), + } + const hasSharedAccountKeys = flags & (1 << 2) + + let accountKeys: DecryptNotesAccountKeys + if (hasSharedAccountKeys) { + Assert.isNotNull( + sharedAccountKeys, + 'expected account keys to be provided as a SharedArrayBuffer', + ) + accountKeys = new DecryptNotesSharedAccountKeys(sharedAccountKeys) + } else { + Assert.isNull( + sharedAccountKeys, + 'account keys are already inline in the message, they should not be provided as a SharedArrayBuffer', + ) + const keysLength = reader.readU32() + accountKeys = new Array() + for (let i = 0; i < keysLength; i++) { + const incomingViewKey = reader.readBytes(ACCOUNT_KEY_LENGTH) + const outgoingViewKey = reader.readBytes(ACCOUNT_KEY_LENGTH) + const viewKey = reader.readBytes(VIEW_KEY_LENGTH) + accountKeys.push({ incomingViewKey, outgoingViewKey, viewKey }) + } } + const encryptedNotes = [] while (reader.left() > 0) { const serializedNote = reader.readBytes(ENCRYPTED_NOTE_LENGTH) let currentNoteIndex: number | null = reader.readU32() @@ -99,22 +217,21 @@ export class DecryptNotesRequest extends WorkerMessage { getSize(): number { const optionsSize = 1 - const keySize = ACCOUNT_KEY_LENGTH + ACCOUNT_KEY_LENGTH + VIEW_KEY_LENGTH const noteSize = ENCRYPTED_NOTE_LENGTH + 4 + let accountKeysSize = 0 - return ( - optionsSize + - 4 + - keySize * this.accountKeys.length + - noteSize * this.encryptedNotes.length - ) + if (!(this.accountKeys instanceof DecryptNotesSharedAccountKeys)) { + accountKeysSize += 4 + ACCOUNT_KEY_SIZE * this.accountKeys.length + } + + return optionsSize + accountKeysSize + noteSize * this.encryptedNotes.length } } export class DecryptNotesResponse extends WorkerMessage { - readonly notes: Array + readonly notes: Array - constructor(notes: Array, jobId: number) { + constructor(notes: Array, jobId: number) { super(WorkerMessageType.DecryptNotes, jobId) this.notes = notes } @@ -141,12 +258,15 @@ export class DecryptNotesResponse extends WorkerMessage { bw.writeU32(this.notes.length) - for (const [arrayIndex, note] of this.notes.entries()) { + // `this.notes` may be a sparse array. Using `forEach()` will skip the + // unset slots (as opposed to using `for (... of this.notes)`, which will + // iterate over the unset slots). + this.notes.forEach((note, notesArrayIndex) => { if (!note) { - continue + return } - bw.writeU32(arrayIndex) + bw.writeU32(notesArrayIndex) let flags = 0 flags |= Number(!!note.index) << 0 @@ -163,17 +283,17 @@ export class DecryptNotesResponse extends WorkerMessage { if (note.nullifier) { bw.writeHash(note.nullifier) } - } + }) } static deserializePayload(jobId: number, buffer: Buffer): DecryptNotesResponse { const reader = bufio.read(buffer) - const arrayLength = reader.readU32() - const notes = Array(arrayLength).fill(null) as Array + const notes = new Array() + notes.length = reader.readU32() while (reader.left() > 0) { - const arrayIndex = reader.readU32() + const notesArrayIndex = reader.readU32() const flags = reader.readU8() const hasIndex = flags & (1 << 0) @@ -192,7 +312,7 @@ export class DecryptNotesResponse extends WorkerMessage { nullifier = reader.readHash() } - notes[arrayIndex] = { + notes[notesArrayIndex] = { forSpender, index, hash, @@ -205,11 +325,11 @@ export class DecryptNotesResponse extends WorkerMessage { } getSize(): number { - let size = 4 - - for (const note of this.notes) { + // `this.notes` may be a sparse array. `reduce()` won't visit the unset + // slots in that case. + return this.notes.reduce((size, note) => { if (!note) { - continue + return size } size += 4 + 1 + 32 + DECRYPTED_NOTE_LENGTH @@ -221,9 +341,46 @@ export class DecryptNotesResponse extends WorkerMessage { if (note.nullifier) { size += 32 } + + return size + }, 4) + } + + /** + * Groups each note in the response by the account it belongs to. The + * `accounts` passed must be in the same order as the `accountKeys` in the + * `DecryptNotesRequest` that generated this response. + */ + mapToAccounts( + accounts: ReadonlyArray<{ accountId: string }>, + ): Map> { + if ( + !(this.notes.length === 0 && accounts.length === 0) && + this.notes.length % accounts.length !== 0 + ) { + throw new Error( + `${this.notes.length} notes cannot be mapped to ${accounts.length} accounts`, + ) } - return size + const notesPerAccount = Math.trunc(this.notes.length / accounts.length) + + const decryptedNotesByAccount: Array< + [accountId: string, notes: Array] + > = accounts.map(({ accountId }) => { + const accountNotes: Array = [] + accountNotes.length = notesPerAccount + return [accountId, accountNotes] + }) + + this.notes.forEach((note, notesArrayIndex) => { + const accountIndex = notesArrayIndex % accounts.length + const accountNotesArrayIndex = Math.trunc(notesArrayIndex / accounts.length) + const [_accountId, accountNotes] = decryptedNotesByAccount[accountIndex] + accountNotes[accountNotesArrayIndex] = note + }) + + return new Map(decryptedNotesByAccount) } } @@ -244,43 +401,54 @@ export class DecryptNotesTask extends WorkerTask { jobId, }: DecryptNotesRequest): DecryptNotesResponse { const decryptedNotes = [] + const incomingViewKeys = accountKeys.map(({ incomingViewKey }) => incomingViewKey) + const noteOptions = { + skipValidation: options.skipNoteValidation, + } + + decryptedNotes.length = incomingViewKeys.length * encryptedNotes.length + let decryptedNoteIndex = 0 for (const { serializedNote, currentNoteIndex } of encryptedNotes) { - const note = new NoteEncrypted(serializedNote) + const note = new NoteEncrypted(serializedNote, noteOptions) + const receivedNotes = note.decryptNoteForOwners(incomingViewKeys) - for (const { incomingViewKey, outgoingViewKey, viewKey } of accountKeys) { + for (const [accountIndex, receivedNote] of receivedNotes.entries()) { // Try decrypting the note as the owner - const receivedNote = note.decryptNoteForOwner(incomingViewKey) if (receivedNote && receivedNote.value() !== 0n) { - decryptedNotes.push({ + const key = accountKeys.at(accountIndex) + Assert.isNotUndefined(key) + decryptedNotes[decryptedNoteIndex++] = { index: currentNoteIndex, forSpender: false, hash: note.hash(), nullifier: currentNoteIndex !== null - ? receivedNote.nullifier(viewKey, BigInt(currentNoteIndex)) + ? receivedNote.nullifier(key.viewKey.toString('hex'), BigInt(currentNoteIndex)) : null, serializedNote: receivedNote.serialize(), - }) + } continue } if (options.decryptForSpender) { // Try decrypting the note as the spender - const spentNote = note.decryptNoteForSpender(outgoingViewKey) + const key = accountKeys.at(accountIndex) + Assert.isNotUndefined(key) + const spentNote = note.decryptNoteForSpender(key.outgoingViewKey) if (spentNote && spentNote.value() !== 0n) { - decryptedNotes.push({ + decryptedNotes[decryptedNoteIndex++] = { index: currentNoteIndex, forSpender: true, hash: note.hash(), nullifier: null, serializedNote: spentNote.serialize(), - }) + } continue } } - decryptedNotes.push(null) + decryptedNoteIndex++ } } diff --git a/ironfish/src/workerPool/tasks/jobAbort.ts b/ironfish/src/workerPool/tasks/jobAbort.ts index 055d11f8c7..442ba80746 100644 --- a/ironfish/src/workerPool/tasks/jobAbort.ts +++ b/ironfish/src/workerPool/tasks/jobAbort.ts @@ -12,8 +12,8 @@ export class JobAbortedMessage extends WorkerMessage { return } - static deserializePayload(): JobAbortedError { - return new JobAbortedError() + static deserializePayload(): JobAbortedMessage { + return new JobAbortedMessage() } getSize(): number { diff --git a/ironfish/src/workerPool/tasks/submitTelemetry.test.ts b/ironfish/src/workerPool/tasks/submitTelemetry.test.ts index a45bcf36b1..9d35b67ca7 100644 --- a/ironfish/src/workerPool/tasks/submitTelemetry.test.ts +++ b/ironfish/src/workerPool/tasks/submitTelemetry.test.ts @@ -65,9 +65,7 @@ describe('SubmitTelemetryResponse', () => { describe('SubmitTelemetryTask', () => { describe('execute', () => { it('submits points to the API', async () => { - const submitTelemetryPointsToApi = jest - .spyOn(axios, 'post') - .mockImplementationOnce(jest.fn()) + const submitTelemetryPointsToApi = jest.spyOn(axios, 'post').mockResolvedValueOnce(null) const mockMetric: Metric = { measurement: 'node', fields: [ diff --git a/ironfish/src/workerPool/tasks/workerMessage.ts b/ironfish/src/workerPool/tasks/workerMessage.ts index 6679eb7b76..da6da961a5 100644 --- a/ironfish/src/workerPool/tasks/workerMessage.ts +++ b/ironfish/src/workerPool/tasks/workerMessage.ts @@ -3,6 +3,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import bufio from 'bufio' +import { MessagePort, Worker as WorkerThread } from 'worker_threads' import { Serializable } from '../../common/serializable' import { WorkerHeader } from '../interfaces/workerHeader' @@ -34,6 +35,10 @@ export abstract class WorkerMessage implements Serializable { abstract serializePayload(bw: bufio.StaticWriter | bufio.BufferWriter): void abstract getSize(): number + getSharedMemoryPayload(): SharedArrayBuffer | null { + return null + } + static deserializeHeader(buffer: Buffer): WorkerHeader { const br = bufio.read(buffer) const jobId = Number(br.readU64()) @@ -46,6 +51,20 @@ export abstract class WorkerMessage implements Serializable { } } + /** + * Serializes the contents of this message into a `Buffer` to be sent to a + * worker. + * + * Note that the `Buffer` will be *transferred* to the destination worker. + * This means that the buffer will become inutilizable from the sending + * context once sent. For this reason, it's important that the returned + * `Buffer` does not reference any memory that will be needed later by the + * sending context. An easy way to ensure that is to create a new `Buffer` + * every time this method is called. + * + * See https://developer.mozilla.org/en-US/docs/Web/API/Worker/postMessage + * for more details on transfers. + */ serialize(): Buffer { const bw = bufio.write(WORKER_MESSAGE_HEADER_SIZE + this.getSize()) bw.writeU64(this.jobId) @@ -53,4 +72,10 @@ export abstract class WorkerMessage implements Serializable { this.serializePayload(bw) return bw.render() } + + post(thread: WorkerThread | MessagePort) { + const body = this.serialize().buffer + const sharedData = this.getSharedMemoryPayload() + thread.postMessage([body, sharedData], [body]) + } } diff --git a/ironfish/src/workerPool/tasks/workerMessages.test.perf.ts b/ironfish/src/workerPool/tasks/workerMessages.test.perf.ts index eae7d4baba..3cb5f1f8f2 100644 --- a/ironfish/src/workerPool/tasks/workerMessages.test.perf.ts +++ b/ironfish/src/workerPool/tasks/workerMessages.test.perf.ts @@ -68,7 +68,11 @@ describe('WorkerMessages', () => { const { block, transactions } = await useBlockWithTxs(nodeTest.node, txCount, account) await expect(nodeTest.chain).toAddBlock(block) - const accountKeys: DecryptNotesAccountKey = { ...account } + const accountKeys: DecryptNotesAccountKey = { + incomingViewKey: Buffer.from(account.incomingViewKey, 'hex'), + outgoingViewKey: Buffer.from(account.outgoingViewKey, 'hex'), + viewKey: Buffer.from(account.viewKey, 'hex'), + } const items: DecryptNotesItem[] = [] for (const transaction of transactions) { diff --git a/ironfish/src/workerPool/worker.ts b/ironfish/src/workerPool/worker.ts index 5cd46f2fa9..13313eaf90 100644 --- a/ironfish/src/workerPool/worker.ts +++ b/ironfish/src/workerPool/worker.ts @@ -61,9 +61,9 @@ export class Worker { send(message: WorkerMessage): void { if (this.thread) { - this.thread.postMessage(message.serialize()) + message.post(this.thread) } else if (this.parent) { - this.parent.postMessage(message.serialize()) + message.post(this.parent) } else { throw new Error(`Cannot send message: no thread or worker`) } @@ -115,7 +115,10 @@ export class Worker { initializeSapling() } - private onMessageFromParent = (request: Uint8Array): void => { + private onMessageFromParent = ([request, sharedMemory]: [ + request: Uint8Array, + sharedMemory: SharedArrayBuffer | null, + ]): void => { const message = Buffer.from(request) let header: WorkerHeader @@ -130,7 +133,7 @@ export class Worker { let requestBody: WorkerMessage try { - requestBody = this.parseRequest(jobId, type, body) + requestBody = this.parseRequest(jobId, type, body, sharedMemory) } catch { const args = `(jobId: ${jobId}, type: ${WorkerMessageType[type]}, body: '${body.toString( 'hex', @@ -165,7 +168,10 @@ export class Worker { }) } - private onMessageFromWorker = (response: Uint8Array): void => { + private onMessageFromWorker = ([response, _sharedMemory]: [ + response: Uint8Array, + sharedMemory: SharedArrayBuffer | null, + ]): void => { const message = Buffer.from(response) let header: WorkerHeader @@ -214,16 +220,21 @@ export class Worker { return } - private parseRequest(jobId: number, type: WorkerMessageType, request: Buffer): WorkerMessage { + private parseRequest( + jobId: number, + type: WorkerMessageType, + request: Buffer, + sharedMemory: SharedArrayBuffer | null, + ): WorkerMessage { switch (type) { case WorkerMessageType.CreateMinersFee: return CreateMinersFeeRequest.deserializePayload(jobId, request) case WorkerMessageType.PostTransaction: return PostTransactionRequest.deserializePayload(jobId, request) case WorkerMessageType.DecryptNotes: - return DecryptNotesRequest.deserializePayload(jobId, request) + return DecryptNotesRequest.deserializePayload(jobId, request, sharedMemory) case WorkerMessageType.JobAborted: - throw new Error('JobAbort should not be sent as a request') + return JobAbortedMessage.deserializePayload() case WorkerMessageType.JobError: throw new Error('JobError should not be sent as a request') case WorkerMessageType.Sleep: diff --git a/package.json b/package.json index a19c52affb..32b5f045d1 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,6 @@ "coverage:upload": "lerna exec '\"yarn codecov -t $CODECOV_TOKEN -f ./coverage/clover.xml -F $LERNA_PACKAGE_NAME -p $ROOT_PATH/ --disable=gcov\"'" }, "devDependencies": { - "@types/jest": "29.5.8", "@typescript-eslint/eslint-plugin": "6.19.0", "@typescript-eslint/parser": "6.19.0", "codecov": "3.8.3", diff --git a/supply-chain/audits.toml b/supply-chain/audits.toml index 916d3dd977..0ab61b20e5 100644 --- a/supply-chain/audits.toml +++ b/supply-chain/audits.toml @@ -63,7 +63,8 @@ delta = "1.9.3 -> 2.2.6" [[audits.jubjub]] who = "Andrea " criteria = "safe-to-deploy" -delta = "0.9.0 -> 0.9.0@git:a1a0c2ed69eec4d5d5e87842e2a40849f7fa4633" +delta = "0.9.0 -> 0.9.0@git:531157cfa7b81ade207e819ef50c563843b10e30" +importable = false notes = "Fork of the official jubjub owned by Iron Fish" [[audits.mio]] @@ -88,6 +89,16 @@ delta = "0.5.1 -> 0.5.1@git:311baf8865f6e21527d1f20750d8f2cf5c9e531a" importable = false notes = "Unreleased changes required by ironfish-frost to support multisig wallets" +[[audits.signal-hook]] +who = "andrea " +criteria = "safe-to-deploy" +version = "0.3.17" + +[[audits.signal-hook-registry]] +who = "andrea " +criteria = "safe-to-deploy" +delta = "1.4.1 -> 1.4.2" + [[audits.siphasher]] who = "Andrea " criteria = "safe-to-deploy" diff --git a/supply-chain/config.toml b/supply-chain/config.toml index 1d70d75448..52c74ea903 100644 --- a/supply-chain/config.toml +++ b/supply-chain/config.toml @@ -37,7 +37,7 @@ audit-as-crates-io = true [policy.ironfish_zkp] audit-as-crates-io = true -[policy."jubjub:0.9.0@git:a1a0c2ed69eec4d5d5e87842e2a40849f7fa4633"] +[policy."jubjub:0.9.0@git:531157cfa7b81ade207e819ef50c563843b10e30"] audit-as-crates-io = true [policy."reddsa:0.5.1@git:311baf8865f6e21527d1f20750d8f2cf5c9e531a"] @@ -182,10 +182,6 @@ criteria = "safe-to-deploy" version = "0.2.4" criteria = "safe-to-deploy" -[[exemptions.cobs]] -version = "0.2.3" -criteria = "safe-to-deploy" - [[exemptions.const-crc32]] version = "1.2.0" criteria = "safe-to-deploy" diff --git a/supply-chain/imports.lock b/supply-chain/imports.lock index b989759feb..f27eb30550 100644 --- a/supply-chain/imports.lock +++ b/supply-chain/imports.lock @@ -133,6 +133,12 @@ who = "Pat Hickey " criteria = "safe-to-deploy" version = "0.2.0" +[[audits.bytecode-alliance.audits.cobs]] +who = "Alex Crichton " +criteria = "safe-to-deploy" +version = "0.2.3" +notes = "No `unsafe` code in the crate and no usage of `std`" + [[audits.bytecode-alliance.audits.constant_time_eq]] who = "Nick Fitzgerald " criteria = "safe-to-deploy" @@ -298,6 +304,11 @@ criteria = "safe-to-deploy" version = "1.0.17" notes = "plenty of unsafe pointer and vec tricks, but in well-structured and commented code that appears to be correct" +[[audits.bytecode-alliance.audits.signal-hook-registry]] +who = "Pat Hickey " +criteria = "safe-to-deploy" +version = "1.4.1" + [[audits.bytecode-alliance.audits.slab]] who = "Pat Hickey " criteria = "safe-to-deploy" diff --git a/yarn.lock b/yarn.lock index 7a7ecb601f..bf681b4abe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15,6 +15,648 @@ "@jridgewell/gen-mapping" "^0.3.0" "@jridgewell/trace-mapping" "^0.3.9" +"@aws-crypto/crc32@5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/crc32/-/crc32-5.2.0.tgz#cfcc22570949c98c6689cfcbd2d693d36cdae2e1" + integrity sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg== + dependencies: + "@aws-crypto/util" "^5.2.0" + "@aws-sdk/types" "^3.222.0" + tslib "^2.6.2" + +"@aws-crypto/crc32c@5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/crc32c/-/crc32c-5.2.0.tgz#4e34aab7f419307821509a98b9b08e84e0c1917e" + integrity sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag== + dependencies: + "@aws-crypto/util" "^5.2.0" + "@aws-sdk/types" "^3.222.0" + tslib "^2.6.2" + +"@aws-crypto/sha1-browser@5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/sha1-browser/-/sha1-browser-5.2.0.tgz#b0ee2d2821d3861f017e965ef3b4cb38e3b6a0f4" + integrity sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg== + dependencies: + "@aws-crypto/supports-web-crypto" "^5.2.0" + "@aws-crypto/util" "^5.2.0" + "@aws-sdk/types" "^3.222.0" + "@aws-sdk/util-locate-window" "^3.0.0" + "@smithy/util-utf8" "^2.0.0" + tslib "^2.6.2" + +"@aws-crypto/sha256-browser@5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz#153895ef1dba6f9fce38af550e0ef58988eb649e" + integrity sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw== + dependencies: + "@aws-crypto/sha256-js" "^5.2.0" + "@aws-crypto/supports-web-crypto" "^5.2.0" + "@aws-crypto/util" "^5.2.0" + "@aws-sdk/types" "^3.222.0" + "@aws-sdk/util-locate-window" "^3.0.0" + "@smithy/util-utf8" "^2.0.0" + tslib "^2.6.2" + +"@aws-crypto/sha256-js@5.2.0", "@aws-crypto/sha256-js@^5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz#c4fdb773fdbed9a664fc1a95724e206cf3860042" + integrity sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA== + dependencies: + "@aws-crypto/util" "^5.2.0" + "@aws-sdk/types" "^3.222.0" + tslib "^2.6.2" + +"@aws-crypto/supports-web-crypto@^5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz#a1e399af29269be08e695109aa15da0a07b5b5fb" + integrity sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg== + dependencies: + tslib "^2.6.2" + +"@aws-crypto/util@^5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/util/-/util-5.2.0.tgz#71284c9cffe7927ddadac793c14f14886d3876da" + integrity sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ== + dependencies: + "@aws-sdk/types" "^3.222.0" + "@smithy/util-utf8" "^2.0.0" + tslib "^2.6.2" + +"@aws-sdk/client-cloudfront@^3.609.0": + version "3.613.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-cloudfront/-/client-cloudfront-3.613.0.tgz#0bdbdf7b61f03e8de4287879eaf0c7a28e779e5a" + integrity sha512-HLdRyouDGd+4OM0BX5u7JgF26e7YmZpdB3Xb3RZeHkAllkjP3O+GnEBPVVNtaJCtvTD2Tspv6/upjDF60b9SNg== + dependencies: + "@aws-crypto/sha256-browser" "5.2.0" + "@aws-crypto/sha256-js" "5.2.0" + "@aws-sdk/client-sso-oidc" "3.613.0" + "@aws-sdk/client-sts" "3.613.0" + "@aws-sdk/core" "3.609.0" + "@aws-sdk/credential-provider-node" "3.613.0" + "@aws-sdk/middleware-host-header" "3.609.0" + "@aws-sdk/middleware-logger" "3.609.0" + "@aws-sdk/middleware-recursion-detection" "3.609.0" + "@aws-sdk/middleware-user-agent" "3.609.0" + "@aws-sdk/region-config-resolver" "3.609.0" + "@aws-sdk/types" "3.609.0" + "@aws-sdk/util-endpoints" "3.609.0" + "@aws-sdk/util-user-agent-browser" "3.609.0" + "@aws-sdk/util-user-agent-node" "3.609.0" + "@aws-sdk/xml-builder" "3.609.0" + "@smithy/config-resolver" "^3.0.4" + "@smithy/core" "^2.2.4" + "@smithy/fetch-http-handler" "^3.2.0" + "@smithy/hash-node" "^3.0.3" + "@smithy/invalid-dependency" "^3.0.3" + "@smithy/middleware-content-length" "^3.0.3" + "@smithy/middleware-endpoint" "^3.0.4" + "@smithy/middleware-retry" "^3.0.7" + "@smithy/middleware-serde" "^3.0.3" + "@smithy/middleware-stack" "^3.0.3" + "@smithy/node-config-provider" "^3.1.3" + "@smithy/node-http-handler" "^3.1.1" + "@smithy/protocol-http" "^4.0.3" + "@smithy/smithy-client" "^3.1.5" + "@smithy/types" "^3.3.0" + "@smithy/url-parser" "^3.0.3" + "@smithy/util-base64" "^3.0.0" + "@smithy/util-body-length-browser" "^3.0.0" + "@smithy/util-body-length-node" "^3.0.0" + "@smithy/util-defaults-mode-browser" "^3.0.7" + "@smithy/util-defaults-mode-node" "^3.0.7" + "@smithy/util-endpoints" "^2.0.4" + "@smithy/util-middleware" "^3.0.3" + "@smithy/util-retry" "^3.0.3" + "@smithy/util-stream" "^3.0.5" + "@smithy/util-utf8" "^3.0.0" + "@smithy/util-waiter" "^3.1.2" + tslib "^2.6.2" + +"@aws-sdk/client-s3@^3.609.0": + version "3.613.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-s3/-/client-s3-3.613.0.tgz#780731af58c67f61aadb86a86f8896e0f3465973" + integrity sha512-JK0yjzZFa+/qVZawHasCG4yEEA7ITpBtNsn9ri7qUZDfSWxDDJpKgHI/ZWd4QXw3SLlBG9hoj+eNSroJXuv+hQ== + dependencies: + "@aws-crypto/sha1-browser" "5.2.0" + "@aws-crypto/sha256-browser" "5.2.0" + "@aws-crypto/sha256-js" "5.2.0" + "@aws-sdk/client-sso-oidc" "3.613.0" + "@aws-sdk/client-sts" "3.613.0" + "@aws-sdk/core" "3.609.0" + "@aws-sdk/credential-provider-node" "3.613.0" + "@aws-sdk/middleware-bucket-endpoint" "3.609.0" + "@aws-sdk/middleware-expect-continue" "3.609.0" + "@aws-sdk/middleware-flexible-checksums" "3.609.0" + "@aws-sdk/middleware-host-header" "3.609.0" + "@aws-sdk/middleware-location-constraint" "3.609.0" + "@aws-sdk/middleware-logger" "3.609.0" + "@aws-sdk/middleware-recursion-detection" "3.609.0" + "@aws-sdk/middleware-sdk-s3" "3.609.0" + "@aws-sdk/middleware-signing" "3.609.0" + "@aws-sdk/middleware-ssec" "3.609.0" + "@aws-sdk/middleware-user-agent" "3.609.0" + "@aws-sdk/region-config-resolver" "3.609.0" + "@aws-sdk/signature-v4-multi-region" "3.609.0" + "@aws-sdk/types" "3.609.0" + "@aws-sdk/util-endpoints" "3.609.0" + "@aws-sdk/util-user-agent-browser" "3.609.0" + "@aws-sdk/util-user-agent-node" "3.609.0" + "@aws-sdk/xml-builder" "3.609.0" + "@smithy/config-resolver" "^3.0.4" + "@smithy/core" "^2.2.4" + "@smithy/eventstream-serde-browser" "^3.0.4" + "@smithy/eventstream-serde-config-resolver" "^3.0.3" + "@smithy/eventstream-serde-node" "^3.0.4" + "@smithy/fetch-http-handler" "^3.2.0" + "@smithy/hash-blob-browser" "^3.1.2" + "@smithy/hash-node" "^3.0.3" + "@smithy/hash-stream-node" "^3.1.2" + "@smithy/invalid-dependency" "^3.0.3" + "@smithy/md5-js" "^3.0.3" + "@smithy/middleware-content-length" "^3.0.3" + "@smithy/middleware-endpoint" "^3.0.4" + "@smithy/middleware-retry" "^3.0.7" + "@smithy/middleware-serde" "^3.0.3" + "@smithy/middleware-stack" "^3.0.3" + "@smithy/node-config-provider" "^3.1.3" + "@smithy/node-http-handler" "^3.1.1" + "@smithy/protocol-http" "^4.0.3" + "@smithy/smithy-client" "^3.1.5" + "@smithy/types" "^3.3.0" + "@smithy/url-parser" "^3.0.3" + "@smithy/util-base64" "^3.0.0" + "@smithy/util-body-length-browser" "^3.0.0" + "@smithy/util-body-length-node" "^3.0.0" + "@smithy/util-defaults-mode-browser" "^3.0.7" + "@smithy/util-defaults-mode-node" "^3.0.7" + "@smithy/util-endpoints" "^2.0.4" + "@smithy/util-retry" "^3.0.3" + "@smithy/util-stream" "^3.0.5" + "@smithy/util-utf8" "^3.0.0" + "@smithy/util-waiter" "^3.1.2" + tslib "^2.6.2" + +"@aws-sdk/client-sso-oidc@3.613.0": + version "3.613.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.613.0.tgz#1c98f0fb1254692a9884534aa73c74cff04034e5" + integrity sha512-VINgHA30f6Itjtj6ZAxkx86XhyFYa7UBfv2Ju+9QGcAr2Y3HU+Mh9g6QaTwDqIM5QG6Pgss24NaAItWGJHFf5A== + dependencies: + "@aws-crypto/sha256-browser" "5.2.0" + "@aws-crypto/sha256-js" "5.2.0" + "@aws-sdk/core" "3.609.0" + "@aws-sdk/credential-provider-node" "3.613.0" + "@aws-sdk/middleware-host-header" "3.609.0" + "@aws-sdk/middleware-logger" "3.609.0" + "@aws-sdk/middleware-recursion-detection" "3.609.0" + "@aws-sdk/middleware-user-agent" "3.609.0" + "@aws-sdk/region-config-resolver" "3.609.0" + "@aws-sdk/types" "3.609.0" + "@aws-sdk/util-endpoints" "3.609.0" + "@aws-sdk/util-user-agent-browser" "3.609.0" + "@aws-sdk/util-user-agent-node" "3.609.0" + "@smithy/config-resolver" "^3.0.4" + "@smithy/core" "^2.2.4" + "@smithy/fetch-http-handler" "^3.2.0" + "@smithy/hash-node" "^3.0.3" + "@smithy/invalid-dependency" "^3.0.3" + "@smithy/middleware-content-length" "^3.0.3" + "@smithy/middleware-endpoint" "^3.0.4" + "@smithy/middleware-retry" "^3.0.7" + "@smithy/middleware-serde" "^3.0.3" + "@smithy/middleware-stack" "^3.0.3" + "@smithy/node-config-provider" "^3.1.3" + "@smithy/node-http-handler" "^3.1.1" + "@smithy/protocol-http" "^4.0.3" + "@smithy/smithy-client" "^3.1.5" + "@smithy/types" "^3.3.0" + "@smithy/url-parser" "^3.0.3" + "@smithy/util-base64" "^3.0.0" + "@smithy/util-body-length-browser" "^3.0.0" + "@smithy/util-body-length-node" "^3.0.0" + "@smithy/util-defaults-mode-browser" "^3.0.7" + "@smithy/util-defaults-mode-node" "^3.0.7" + "@smithy/util-endpoints" "^2.0.4" + "@smithy/util-middleware" "^3.0.3" + "@smithy/util-retry" "^3.0.3" + "@smithy/util-utf8" "^3.0.0" + tslib "^2.6.2" + +"@aws-sdk/client-sso@3.609.0": + version "3.609.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-sso/-/client-sso-3.609.0.tgz#2a99166694b64947ba5b7453f057772bd3bba5b8" + integrity sha512-gqXGFDkIpKHCKAbeJK4aIDt3tiwJ26Rf5Tqw9JS6BYXsdMeOB8FTzqD9R+Yc1epHd8s5L94sdqXT5PapgxFZrg== + dependencies: + "@aws-crypto/sha256-browser" "5.2.0" + "@aws-crypto/sha256-js" "5.2.0" + "@aws-sdk/core" "3.609.0" + "@aws-sdk/middleware-host-header" "3.609.0" + "@aws-sdk/middleware-logger" "3.609.0" + "@aws-sdk/middleware-recursion-detection" "3.609.0" + "@aws-sdk/middleware-user-agent" "3.609.0" + "@aws-sdk/region-config-resolver" "3.609.0" + "@aws-sdk/types" "3.609.0" + "@aws-sdk/util-endpoints" "3.609.0" + "@aws-sdk/util-user-agent-browser" "3.609.0" + "@aws-sdk/util-user-agent-node" "3.609.0" + "@smithy/config-resolver" "^3.0.4" + "@smithy/core" "^2.2.4" + "@smithy/fetch-http-handler" "^3.2.0" + "@smithy/hash-node" "^3.0.3" + "@smithy/invalid-dependency" "^3.0.3" + "@smithy/middleware-content-length" "^3.0.3" + "@smithy/middleware-endpoint" "^3.0.4" + "@smithy/middleware-retry" "^3.0.7" + "@smithy/middleware-serde" "^3.0.3" + "@smithy/middleware-stack" "^3.0.3" + "@smithy/node-config-provider" "^3.1.3" + "@smithy/node-http-handler" "^3.1.1" + "@smithy/protocol-http" "^4.0.3" + "@smithy/smithy-client" "^3.1.5" + "@smithy/types" "^3.3.0" + "@smithy/url-parser" "^3.0.3" + "@smithy/util-base64" "^3.0.0" + "@smithy/util-body-length-browser" "^3.0.0" + "@smithy/util-body-length-node" "^3.0.0" + "@smithy/util-defaults-mode-browser" "^3.0.7" + "@smithy/util-defaults-mode-node" "^3.0.7" + "@smithy/util-endpoints" "^2.0.4" + "@smithy/util-middleware" "^3.0.3" + "@smithy/util-retry" "^3.0.3" + "@smithy/util-utf8" "^3.0.0" + tslib "^2.6.2" + +"@aws-sdk/client-sts@3.613.0": + version "3.613.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-sts/-/client-sts-3.613.0.tgz#b648592d79dba0d4badaeacb4f33b3a2b158d0ca" + integrity sha512-S+KvQI4XEivY3vyIY+IPY7Fw8vFvX/q3pkNC9qEhnAs+/w7vT6vhVBHsaugYVlsMuNtNvmyc8P+Q/gzOEtLCTw== + dependencies: + "@aws-crypto/sha256-browser" "5.2.0" + "@aws-crypto/sha256-js" "5.2.0" + "@aws-sdk/client-sso-oidc" "3.613.0" + "@aws-sdk/core" "3.609.0" + "@aws-sdk/credential-provider-node" "3.613.0" + "@aws-sdk/middleware-host-header" "3.609.0" + "@aws-sdk/middleware-logger" "3.609.0" + "@aws-sdk/middleware-recursion-detection" "3.609.0" + "@aws-sdk/middleware-user-agent" "3.609.0" + "@aws-sdk/region-config-resolver" "3.609.0" + "@aws-sdk/types" "3.609.0" + "@aws-sdk/util-endpoints" "3.609.0" + "@aws-sdk/util-user-agent-browser" "3.609.0" + "@aws-sdk/util-user-agent-node" "3.609.0" + "@smithy/config-resolver" "^3.0.4" + "@smithy/core" "^2.2.4" + "@smithy/fetch-http-handler" "^3.2.0" + "@smithy/hash-node" "^3.0.3" + "@smithy/invalid-dependency" "^3.0.3" + "@smithy/middleware-content-length" "^3.0.3" + "@smithy/middleware-endpoint" "^3.0.4" + "@smithy/middleware-retry" "^3.0.7" + "@smithy/middleware-serde" "^3.0.3" + "@smithy/middleware-stack" "^3.0.3" + "@smithy/node-config-provider" "^3.1.3" + "@smithy/node-http-handler" "^3.1.1" + "@smithy/protocol-http" "^4.0.3" + "@smithy/smithy-client" "^3.1.5" + "@smithy/types" "^3.3.0" + "@smithy/url-parser" "^3.0.3" + "@smithy/util-base64" "^3.0.0" + "@smithy/util-body-length-browser" "^3.0.0" + "@smithy/util-body-length-node" "^3.0.0" + "@smithy/util-defaults-mode-browser" "^3.0.7" + "@smithy/util-defaults-mode-node" "^3.0.7" + "@smithy/util-endpoints" "^2.0.4" + "@smithy/util-middleware" "^3.0.3" + "@smithy/util-retry" "^3.0.3" + "@smithy/util-utf8" "^3.0.0" + tslib "^2.6.2" + +"@aws-sdk/core@3.609.0": + version "3.609.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/core/-/core-3.609.0.tgz#4c3994cd341452d1ef1a8b5e81a16442a7422287" + integrity sha512-ptqw+DTxLr01+pKjDUuo53SEDzI+7nFM3WfQaEo0yhDg8vWw8PER4sWj1Ysx67ksctnZesPUjqxd5SHbtdBxiA== + dependencies: + "@smithy/core" "^2.2.4" + "@smithy/protocol-http" "^4.0.3" + "@smithy/signature-v4" "^3.1.2" + "@smithy/smithy-client" "^3.1.5" + "@smithy/types" "^3.3.0" + fast-xml-parser "4.2.5" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-env@3.609.0": + version "3.609.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-env/-/credential-provider-env-3.609.0.tgz#b3f32e5a8ff8b541e151eadadfb60283aa3d835e" + integrity sha512-v69ZCWcec2iuV9vLVJMa6fAb5xwkzN4jYIT8yjo2c4Ia/j976Q+TPf35Pnz5My48Xr94EFcaBazrWedF+kwfuQ== + dependencies: + "@aws-sdk/types" "3.609.0" + "@smithy/property-provider" "^3.1.3" + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-http@3.613.0": + version "3.613.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-http/-/credential-provider-http-3.613.0.tgz#bb7987f8f78bc3372c56aadb52e5ac965bf168ad" + integrity sha512-MCiUFxowFzprzIXFXsqbp/3DViJ7nFmBW+XJkoRQWqNmThbkz/E8sb40WmL9UFdZHJph2KDjzABKYH5f0lHZaA== + dependencies: + "@aws-sdk/types" "3.609.0" + "@smithy/fetch-http-handler" "^3.2.0" + "@smithy/node-http-handler" "^3.1.1" + "@smithy/property-provider" "^3.1.3" + "@smithy/protocol-http" "^4.0.3" + "@smithy/smithy-client" "^3.1.5" + "@smithy/types" "^3.3.0" + "@smithy/util-stream" "^3.0.5" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-ini@3.613.0": + version "3.613.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.613.0.tgz#11736835f330571d15d240bc6d7812c826d845b0" + integrity sha512-scHV7K0YpllYMWxPnqxssWU+7S3WNXH1m5Rw8Ax96pfcfnaoatiWXps2XSSdGlChdF9gNVnewjRKFOTLyyzdAw== + dependencies: + "@aws-sdk/credential-provider-env" "3.609.0" + "@aws-sdk/credential-provider-http" "3.613.0" + "@aws-sdk/credential-provider-process" "3.609.0" + "@aws-sdk/credential-provider-sso" "3.609.0" + "@aws-sdk/credential-provider-web-identity" "3.609.0" + "@aws-sdk/types" "3.609.0" + "@smithy/credential-provider-imds" "^3.1.3" + "@smithy/property-provider" "^3.1.3" + "@smithy/shared-ini-file-loader" "^3.1.3" + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-node@3.613.0": + version "3.613.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-node/-/credential-provider-node-3.613.0.tgz#9d9a03658e9b5e657fd3b75955e58971d62c2e0c" + integrity sha512-n3yd0CDuUKcQFhjRLAQfQpZyZ2ddrHC7QOKQqE+Fkx+Fs5zoG+NRLK1EBkBW/G9zk8Ck4+rG3OOI3CuNpJ2PCw== + dependencies: + "@aws-sdk/credential-provider-env" "3.609.0" + "@aws-sdk/credential-provider-http" "3.613.0" + "@aws-sdk/credential-provider-ini" "3.613.0" + "@aws-sdk/credential-provider-process" "3.609.0" + "@aws-sdk/credential-provider-sso" "3.609.0" + "@aws-sdk/credential-provider-web-identity" "3.609.0" + "@aws-sdk/types" "3.609.0" + "@smithy/credential-provider-imds" "^3.1.3" + "@smithy/property-provider" "^3.1.3" + "@smithy/shared-ini-file-loader" "^3.1.3" + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-process@3.609.0": + version "3.609.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-process/-/credential-provider-process-3.609.0.tgz#2bfa160eec4be8532a45061810466ee3462ce240" + integrity sha512-Ux35nGOSJKZWUIM3Ny0ROZ8cqPRUEkh+tR3X2o9ydEbFiLq3eMMyEnHJqx4EeUjLRchidlm4CCid9GxMe5/gdw== + dependencies: + "@aws-sdk/types" "3.609.0" + "@smithy/property-provider" "^3.1.3" + "@smithy/shared-ini-file-loader" "^3.1.3" + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-sso@3.609.0": + version "3.609.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.609.0.tgz#94da403a000060700a34ee62fcf119fd4cacf167" + integrity sha512-oQPGDKMMIxjvTcm86g07RPYeC7mCNk+29dPpY15ZAPRpAF7F0tircsC3wT9fHzNaKShEyK5LuI5Kg/uxsdy+Iw== + dependencies: + "@aws-sdk/client-sso" "3.609.0" + "@aws-sdk/token-providers" "3.609.0" + "@aws-sdk/types" "3.609.0" + "@smithy/property-provider" "^3.1.3" + "@smithy/shared-ini-file-loader" "^3.1.3" + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-web-identity@3.609.0": + version "3.609.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.609.0.tgz#d29222d6894347ee89c781ea090d388656df1d2a" + integrity sha512-U+PG8NhlYYF45zbr1km3ROtBMYqyyj/oK8NRp++UHHeuavgrP+4wJ4wQnlEaKvJBjevfo3+dlIBcaeQ7NYejWg== + dependencies: + "@aws-sdk/types" "3.609.0" + "@smithy/property-provider" "^3.1.3" + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@aws-sdk/middleware-bucket-endpoint@3.609.0": + version "3.609.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.609.0.tgz#f6f1e366c1816292d6e78866653c6e7122b7932f" + integrity sha512-QhHRfr4e7FqaMUAnOAFdQVOR3yDLw40i1IZPo+TeiKyev9LEyYEX2l6DbdaIwAztofOpAxfFNj/IJ0V/efzz/w== + dependencies: + "@aws-sdk/types" "3.609.0" + "@aws-sdk/util-arn-parser" "3.568.0" + "@smithy/node-config-provider" "^3.1.3" + "@smithy/protocol-http" "^4.0.3" + "@smithy/types" "^3.3.0" + "@smithy/util-config-provider" "^3.0.0" + tslib "^2.6.2" + +"@aws-sdk/middleware-expect-continue@3.609.0": + version "3.609.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.609.0.tgz#89af76f115aa5fadd5a82fe4e95a64cb15150517" + integrity sha512-+zeg//mSer4JZRxOB/4mUOMUJyuYPwATnIC5moBB8P8Xe+mJaVRFy8qlCtzYNj2TycnlsBPzTK0j7P1yvDh97w== + dependencies: + "@aws-sdk/types" "3.609.0" + "@smithy/protocol-http" "^4.0.3" + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@aws-sdk/middleware-flexible-checksums@3.609.0": + version "3.609.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.609.0.tgz#3bcd54d64e65808f2053d5a38053625cacb5464a" + integrity sha512-TJ4WE+ehT+qcrhr7/yJCzmJJPmUoPPWIbCnFzqGxauH/dpVBCslmd1vZg3h2VnfRiaDkc6f68dqYVc29CaurhQ== + dependencies: + "@aws-crypto/crc32" "5.2.0" + "@aws-crypto/crc32c" "5.2.0" + "@aws-sdk/types" "3.609.0" + "@smithy/is-array-buffer" "^3.0.0" + "@smithy/protocol-http" "^4.0.3" + "@smithy/types" "^3.3.0" + "@smithy/util-utf8" "^3.0.0" + tslib "^2.6.2" + +"@aws-sdk/middleware-host-header@3.609.0": + version "3.609.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-host-header/-/middleware-host-header-3.609.0.tgz#844302cb905e4d09b9a1ea4bfa96729833068913" + integrity sha512-iTKfo158lc4jLDfYeZmYMIBHsn8m6zX+XB6birCSNZ/rrlzAkPbGE43CNdKfvjyWdqgLMRXF+B+OcZRvqhMXPQ== + dependencies: + "@aws-sdk/types" "3.609.0" + "@smithy/protocol-http" "^4.0.3" + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@aws-sdk/middleware-location-constraint@3.609.0": + version "3.609.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.609.0.tgz#7ed82d71e5ddcd50683ef2bbde10d1cc2492057e" + integrity sha512-xzsdoTkszGVqGVPjUmgoP7TORiByLueMHieI1fhQL888WPdqctwAx3ES6d/bA9Q/i8jnc6hs+Fjhy8UvBTkE9A== + dependencies: + "@aws-sdk/types" "3.609.0" + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@aws-sdk/middleware-logger@3.609.0": + version "3.609.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-logger/-/middleware-logger-3.609.0.tgz#ed44d201f091b8bac908cbf14724c7a4d492553f" + integrity sha512-S62U2dy4jMDhDFDK5gZ4VxFdWzCtLzwbYyFZx2uvPYTECkepLUfzLic2BHg2Qvtu4QjX+oGE3P/7fwaGIsGNuQ== + dependencies: + "@aws-sdk/types" "3.609.0" + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@aws-sdk/middleware-recursion-detection@3.609.0": + version "3.609.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.609.0.tgz#b7b869aaeac021a43dbea1435eaea81e5d2460b1" + integrity sha512-6sewsYB7/o/nbUfA99Aa/LokM+a/u4Wpm/X2o0RxOsDtSB795ObebLJe2BxY5UssbGaWkn7LswyfvrdZNXNj1w== + dependencies: + "@aws-sdk/types" "3.609.0" + "@smithy/protocol-http" "^4.0.3" + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@aws-sdk/middleware-sdk-s3@3.609.0": + version "3.609.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.609.0.tgz#a743bd63adf786c7c6d4b9102946b67a5032d1f4" + integrity sha512-kvwjL6OJFhAGWoYaIWR7HmILjiVk6xVj6QEU6qZMA7FtGgvlKi4pLfs8Of+hQqo+2TEhUoxG/5t6WqwB8uxjsw== + dependencies: + "@aws-sdk/types" "3.609.0" + "@aws-sdk/util-arn-parser" "3.568.0" + "@smithy/node-config-provider" "^3.1.3" + "@smithy/protocol-http" "^4.0.3" + "@smithy/signature-v4" "^3.1.2" + "@smithy/smithy-client" "^3.1.5" + "@smithy/types" "^3.3.0" + "@smithy/util-config-provider" "^3.0.0" + tslib "^2.6.2" + +"@aws-sdk/middleware-signing@3.609.0": + version "3.609.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-signing/-/middleware-signing-3.609.0.tgz#7e5c4e70302bf87a7aa3dfde83ec1b387bf819f0" + integrity sha512-2w3dBLjQVKIajYzokO4hduq8/0hSMUYHHmIo1Kdl+MSY8uwRBt12bLL6pyreobTcRMxizvn2ph/CQ9I1ST/WGQ== + dependencies: + "@aws-sdk/types" "3.609.0" + "@smithy/property-provider" "^3.1.3" + "@smithy/protocol-http" "^4.0.3" + "@smithy/signature-v4" "^3.1.2" + "@smithy/types" "^3.3.0" + "@smithy/util-middleware" "^3.0.3" + tslib "^2.6.2" + +"@aws-sdk/middleware-ssec@3.609.0": + version "3.609.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-ssec/-/middleware-ssec-3.609.0.tgz#b87a8bc6133f3f6bdc6801183d0f9dad3f93cf9f" + integrity sha512-GZSD1s7+JswWOTamVap79QiDaIV7byJFssBW68GYjyRS5EBjNfwA/8s+6uE6g39R3ojyTbYOmvcANoZEhSULXg== + dependencies: + "@aws-sdk/types" "3.609.0" + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@aws-sdk/middleware-user-agent@3.609.0": + version "3.609.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.609.0.tgz#eb3b7c604817be42f7ecd97988dda69a22e6011b" + integrity sha512-nbq7MXRmeXm4IDqh+sJRAxGPAq0OfGmGIwKvJcw66hLoG8CmhhVMZmIAEBDFr57S+YajGwnLLRt+eMI05MMeVA== + dependencies: + "@aws-sdk/types" "3.609.0" + "@aws-sdk/util-endpoints" "3.609.0" + "@smithy/protocol-http" "^4.0.3" + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@aws-sdk/region-config-resolver@3.609.0": + version "3.609.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/region-config-resolver/-/region-config-resolver-3.609.0.tgz#68fe568d1c69f35f7fa3d66f718bd5751b1debda" + integrity sha512-lMHBG8zg9GWYBc9/XVPKyuAUd7iKqfPP7z04zGta2kGNOKbUTeqmAdc1gJGku75p4kglIPlGBorOxti8DhRmKw== + dependencies: + "@aws-sdk/types" "3.609.0" + "@smithy/node-config-provider" "^3.1.3" + "@smithy/types" "^3.3.0" + "@smithy/util-config-provider" "^3.0.0" + "@smithy/util-middleware" "^3.0.3" + tslib "^2.6.2" + +"@aws-sdk/signature-v4-multi-region@3.609.0": + version "3.609.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.609.0.tgz#c88c4a25713bd50b7b253d611e3d2473258087eb" + integrity sha512-FJs0BxVMyYOKNu7nzFI1kehfgWoYmdto5B8BSS29geUACF7jlOoeCfNZWVrnMjvAxVlSQ5O7Mr575932BnsycA== + dependencies: + "@aws-sdk/middleware-sdk-s3" "3.609.0" + "@aws-sdk/types" "3.609.0" + "@smithy/protocol-http" "^4.0.3" + "@smithy/signature-v4" "^3.1.2" + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@aws-sdk/token-providers@3.609.0": + version "3.609.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/token-providers/-/token-providers-3.609.0.tgz#cfa9cdc84fefe71277c7d44b08b09f42c16c1d66" + integrity sha512-WvhW/7XSf+H7YmtiIigQxfDVZVZI7mbKikQ09YpzN7FeN3TmYib1+0tB+EE9TbICkwssjiFc71FEBEh4K9grKQ== + dependencies: + "@aws-sdk/types" "3.609.0" + "@smithy/property-provider" "^3.1.3" + "@smithy/shared-ini-file-loader" "^3.1.3" + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@aws-sdk/types@3.609.0", "@aws-sdk/types@^3.222.0": + version "3.609.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/types/-/types-3.609.0.tgz#06b39d799c9f197a7b43670243e8e78a3bf7d6a5" + integrity sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q== + dependencies: + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@aws-sdk/util-arn-parser@3.568.0": + version "3.568.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-arn-parser/-/util-arn-parser-3.568.0.tgz#6a19a8c6bbaa520b6be1c278b2b8c17875b91527" + integrity sha512-XUKJWWo+KOB7fbnPP0+g/o5Ulku/X53t7i/h+sPHr5xxYTJJ9CYnbToo95mzxe7xWvkLrsNtJ8L+MnNn9INs2w== + dependencies: + tslib "^2.6.2" + +"@aws-sdk/util-endpoints@3.609.0": + version "3.609.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-endpoints/-/util-endpoints-3.609.0.tgz#e02d3fce2f999d750828dacf9f37289a1a48f6c9" + integrity sha512-Rh+3V8dOvEeE1aQmUy904DYWtLUEJ7Vf5XBPlQ6At3pBhp+zpXbsnpZzVL33c8lW1xfj6YPwtO6gOeEsl1juCQ== + dependencies: + "@aws-sdk/types" "3.609.0" + "@smithy/types" "^3.3.0" + "@smithy/util-endpoints" "^2.0.4" + tslib "^2.6.2" + +"@aws-sdk/util-locate-window@^3.0.0": + version "3.568.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-locate-window/-/util-locate-window-3.568.0.tgz#2acc4b2236af0d7494f7e517401ba6b3c4af11ff" + integrity sha512-3nh4TINkXYr+H41QaPelCceEB2FXP3fxp93YZXB/kqJvX0U9j0N0Uk45gvsjmEPzG8XxkPEeLIfT2I1M7A6Lig== + dependencies: + tslib "^2.6.2" + +"@aws-sdk/util-user-agent-browser@3.609.0": + version "3.609.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.609.0.tgz#aa15421b2e32ae8bc589dac2bd6e8969832ce588" + integrity sha512-fojPU+mNahzQ0YHYBsx0ZIhmMA96H+ZIZ665ObU9tl+SGdbLneVZVikGve+NmHTQwHzwkFsZYYnVKAkreJLAtA== + dependencies: + "@aws-sdk/types" "3.609.0" + "@smithy/types" "^3.3.0" + bowser "^2.11.0" + tslib "^2.6.2" + +"@aws-sdk/util-user-agent-node@3.609.0": + version "3.609.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.609.0.tgz#f8270517b2961cbf627e4e8fb6338ad153db44bb" + integrity sha512-DlZBwQ/HkZyf3pOWc7+wjJRk5R7x9YxHhs2szHwtv1IW30KMabjjjX0GMlGJ9LLkBHkbaaEY/w9Tkj12XRLhRg== + dependencies: + "@aws-sdk/types" "3.609.0" + "@smithy/node-config-provider" "^3.1.3" + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@aws-sdk/xml-builder@3.609.0": + version "3.609.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/xml-builder/-/xml-builder-3.609.0.tgz#eeb3d5cde000a23cfeeefe0354b6193440dc7d87" + integrity sha512-l9XxNcA4HX98rwCC2/KoiWcmEiRfZe4G+mYwDbCFT87JIMj6GBhLDkAzr/W8KAaA2IDr8Vc6J8fZPgVulxxfMA== + dependencies: + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.22.13": version "7.22.13" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e" @@ -270,13 +912,6 @@ dependencies: regenerator-runtime "^0.14.0" -"@babel/runtime@^7.21.0": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.7.tgz#f4f0d5530e8dbdf59b3451b9b3e594b6ba082e12" - integrity sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw== - dependencies: - regenerator-runtime "^0.14.0" - "@babel/template@^7.22.15", "@babel/template@^7.3.3": version "7.22.15" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38" @@ -422,6 +1057,64 @@ resolved "https://registry.yarnpkg.com/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz#98c23c950a3d9b6c8f0daed06da6c3af06981340" integrity sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q== +"@inquirer/confirm@^3.1.11", "@inquirer/confirm@^3.1.14": + version "3.1.14" + resolved "https://registry.yarnpkg.com/@inquirer/confirm/-/confirm-3.1.14.tgz#b50a156f2cc0a6f874f2d2ab1739e988fbf950f4" + integrity sha512-nbLSX37b2dGPtKWL3rPuR/5hOuD30S+pqJ/MuFiUEgN6GiMs8UMxiurKAMDzKt6C95ltjupa8zH6+3csXNHWpA== + dependencies: + "@inquirer/core" "^9.0.2" + "@inquirer/type" "^1.4.0" + +"@inquirer/core@^9.0.2": + version "9.0.2" + resolved "https://registry.yarnpkg.com/@inquirer/core/-/core-9.0.2.tgz#8be8782266f00129acb5c804537d1231b2fe3ac6" + integrity sha512-nguvH3TZar3ACwbytZrraRTzGqyxJfYJwv+ZwqZNatAosdWQMP1GV8zvmkNlBe2JeZSaw0WYBHZk52pDpWC9qA== + dependencies: + "@inquirer/figures" "^1.0.3" + "@inquirer/type" "^1.4.0" + "@types/mute-stream" "^0.0.4" + "@types/node" "^20.14.9" + "@types/wrap-ansi" "^3.0.0" + ansi-escapes "^4.3.2" + cli-spinners "^2.9.2" + cli-width "^4.1.0" + mute-stream "^1.0.0" + signal-exit "^4.1.0" + strip-ansi "^6.0.1" + wrap-ansi "^6.2.0" + yoctocolors-cjs "^2.1.2" + +"@inquirer/figures@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@inquirer/figures/-/figures-1.0.3.tgz#1227cc980f88e6d6ab85abadbf164f5038041edd" + integrity sha512-ErXXzENMH5pJt5/ssXV0DfWUZqly8nGzf0UcBV9xTnP+KyffE2mqyxIMBrZ8ijQck2nU0TQm40EQB53YreyWHw== + +"@inquirer/input@^2.1.9": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@inquirer/input/-/input-2.2.1.tgz#cb795ab12f25cc8c6eeb6f51f04c71a70e4067c8" + integrity sha512-Yl1G6h7qWydzrJwqN777geeJVaAFL5Ly83aZlw4xHf8Z/BoTMfKRheyuMaQwOG7LQ4e5nQP7PxXdEg4SzQ+OKw== + dependencies: + "@inquirer/core" "^9.0.2" + "@inquirer/type" "^1.4.0" + +"@inquirer/select@^2.3.10": + version "2.3.10" + resolved "https://registry.yarnpkg.com/@inquirer/select/-/select-2.3.10.tgz#4491805435984726c75f89e8f810ddb1fe503123" + integrity sha512-rr7iR0Zj1YFfgM8IUGimPD9Yukd+n/U63CnYT9kdum6DbRXtMxR45rrreP+EA9ixCnShr+W4xj7suRxC1+8t9g== + dependencies: + "@inquirer/core" "^9.0.2" + "@inquirer/figures" "^1.0.3" + "@inquirer/type" "^1.4.0" + ansi-escapes "^4.3.2" + yoctocolors-cjs "^2.1.2" + +"@inquirer/type@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@inquirer/type/-/type-1.4.0.tgz#3dd0c8f78c0548bbc18b9c07af16a86c4007e1f0" + integrity sha512-AjOqykVyjdJQvtfkNDGUyMYGF8xN50VUxftCQWsOyIo4DFRLr6VQhW0VItGI1JIyQGCGgIpKa7hMMwNhZb4OIw== + dependencies: + mute-stream "^1.0.0" + "@isaacs/string-locale-compare@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@isaacs/string-locale-compare/-/string-locale-compare-1.1.0.tgz#291c227e93fd407a96ecd59879a35809120e432b" @@ -511,13 +1204,6 @@ "@types/node" "*" jest-mock "^29.7.0" -"@jest/expect-utils@^29.3.1": - version "29.3.1" - resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.3.1.tgz#531f737039e9b9e27c42449798acb5bba01935b6" - integrity sha512-wlrznINZI5sMjwvUoLVk617ll/UYfGIZNxmbU+Pa7wmkL4vYzhV9R2pwVqUh4NWWuLQWkI8+8mOkxs//prKQ3g== - dependencies: - jest-get-type "^29.2.0" - "@jest/expect-utils@^29.7.0": version "29.7.0" resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6" @@ -809,6 +1495,70 @@ "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" +"@ledgerhq/devices@^8.0.0", "@ledgerhq/devices@^8.4.0": + version "8.4.0" + resolved "https://registry.yarnpkg.com/@ledgerhq/devices/-/devices-8.4.0.tgz#f3a03576d4a53d731bdaa212a00bd0adbfb86fb1" + integrity sha512-TUrMlWZJ+5AFp2lWMw4rGQoU+WtjIqlFX5SzQDL9phaUHrt4TFierAGHsaj5+tUHudhD4JhIaLI2cn1NOyq5NQ== + dependencies: + "@ledgerhq/errors" "^6.17.0" + "@ledgerhq/logs" "^6.12.0" + rxjs "^7.8.1" + semver "^7.3.5" + +"@ledgerhq/errors@^6.12.3", "@ledgerhq/errors@^6.17.0": + version "6.17.0" + resolved "https://registry.yarnpkg.com/@ledgerhq/errors/-/errors-6.17.0.tgz#0d56361fe6eb7de3b239e661710679f933f1fcca" + integrity sha512-xnOVpy/gUUkusEORdr2Qhw3Vd0MGfjyVGgkGR9Ck6FXE26OIdIQ3tNmG5BdZN+gwMMFJJVxxS4/hr0taQfZ43w== + +"@ledgerhq/hw-transport-node-hid-noevents@^6.30.1": + version "6.30.1" + resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport-node-hid-noevents/-/hw-transport-node-hid-noevents-6.30.1.tgz#e84854c809dda02bcb74a6d3dcc20b6014b5210d" + integrity sha512-9Mb5vDBXfSaRhfl0U2DnJLN4FgosfQopkzjzZYYHT3+s9XMot4WN/eWWbv5Ksx5qsV8RLQ77dewFFomNthm/vQ== + dependencies: + "@ledgerhq/devices" "^8.4.0" + "@ledgerhq/errors" "^6.17.0" + "@ledgerhq/hw-transport" "^6.31.0" + "@ledgerhq/logs" "^6.12.0" + node-hid "2.1.2" + +"@ledgerhq/hw-transport-node-hid@6.29.1": + version "6.29.1" + resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport-node-hid/-/hw-transport-node-hid-6.29.1.tgz#03dbeee6d77f8bb73ec1ef06902436fd137e47a0" + integrity sha512-l+zAfsE0uvo2/Wni0TSW+n6HoFmZdPH6ukrjPocY6jvbhcaxhpbK7ERvDpnZMir/pHwsDoAsvwPY/0sFRBf7bw== + dependencies: + "@ledgerhq/devices" "^8.4.0" + "@ledgerhq/errors" "^6.17.0" + "@ledgerhq/hw-transport" "^6.31.0" + "@ledgerhq/hw-transport-node-hid-noevents" "^6.30.1" + "@ledgerhq/logs" "^6.12.0" + lodash "^4.17.21" + node-hid "2.1.2" + usb "2.9.0" + +"@ledgerhq/hw-transport@6.28.1": + version "6.28.1" + resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport/-/hw-transport-6.28.1.tgz#cb22fe9bc23af4682c30f2aac7fe6f7ab13ed65a" + integrity sha512-RaZe+abn0zBIz82cE9tp7Y7aZkHWWbEaE2yJpfxT8AhFz3fx+BU0kLYzuRN9fmA7vKueNJ1MTVUCY+Ex9/CHSQ== + dependencies: + "@ledgerhq/devices" "^8.0.0" + "@ledgerhq/errors" "^6.12.3" + events "^3.3.0" + +"@ledgerhq/hw-transport@^6.31.0": + version "6.31.0" + resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport/-/hw-transport-6.31.0.tgz#82d8154bbcec8dc0104009a646159190fba5ae76" + integrity sha512-BY1poLk8vlJdIYngp8Zfaa/V9n14dqgt1G7iNetVRhJVFEKp9EYONeC3x6q/N7x81LUpzBk6M+T+s46Z4UiXHw== + dependencies: + "@ledgerhq/devices" "^8.4.0" + "@ledgerhq/errors" "^6.17.0" + "@ledgerhq/logs" "^6.12.0" + events "^3.3.0" + +"@ledgerhq/logs@^6.12.0": + version "6.12.0" + resolved "https://registry.yarnpkg.com/@ledgerhq/logs/-/logs-6.12.0.tgz#ad903528bf3687a44da435d7b2479d724d374f5d" + integrity sha512-ExDoj1QV5eC6TEbMdLUMMk9cfvNKhhv5gXol4SmULRVCx/3iyCPhJ74nsb3S0Vb+/f+XujBEj3vQn5+cwS0fNA== + "@lerna/add@6.4.1": version "6.4.1" resolved "https://registry.yarnpkg.com/@lerna/add/-/add-6.4.1.tgz#fa20fe9ff875dc5758141262c8cde0d9a6481ec4" @@ -1647,44 +2397,6 @@ treeverse "^2.0.0" walk-up-path "^1.0.0" -"@npmcli/arborist@^4.0.4": - version "4.3.1" - resolved "https://registry.yarnpkg.com/@npmcli/arborist/-/arborist-4.3.1.tgz#a08cddce3339882f688c1dea1651f6971e781c44" - integrity sha512-yMRgZVDpwWjplorzt9SFSaakWx6QIK248Nw4ZFgkrAy/GvJaFRaSZzE6nD7JBK5r8g/+PTxFq5Wj/sfciE7x+A== - dependencies: - "@isaacs/string-locale-compare" "^1.1.0" - "@npmcli/installed-package-contents" "^1.0.7" - "@npmcli/map-workspaces" "^2.0.0" - "@npmcli/metavuln-calculator" "^2.0.0" - "@npmcli/move-file" "^1.1.0" - "@npmcli/name-from-folder" "^1.0.1" - "@npmcli/node-gyp" "^1.0.3" - "@npmcli/package-json" "^1.0.1" - "@npmcli/run-script" "^2.0.0" - bin-links "^3.0.0" - cacache "^15.0.3" - common-ancestor-path "^1.0.1" - json-parse-even-better-errors "^2.3.1" - json-stringify-nice "^1.1.4" - mkdirp "^1.0.4" - mkdirp-infer-owner "^2.0.0" - npm-install-checks "^4.0.0" - npm-package-arg "^8.1.5" - npm-pick-manifest "^6.1.0" - npm-registry-fetch "^12.0.1" - pacote "^12.0.2" - parse-conflict-json "^2.0.1" - proc-log "^1.0.0" - promise-all-reject-late "^1.0.0" - promise-call-limit "^1.0.1" - read-package-json-fast "^2.0.2" - readdir-scoped-modules "^1.1.0" - rimraf "^3.0.2" - semver "^7.3.5" - ssri "^8.0.1" - treeverse "^1.0.4" - walk-up-path "^1.0.0" - "@npmcli/fs@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-1.0.0.tgz#589612cfad3a6ea0feafcb901d29c63fd52db09f" @@ -1701,20 +2413,6 @@ "@gar/promisify" "^1.1.3" semver "^7.3.5" -"@npmcli/git@^2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@npmcli/git/-/git-2.1.0.tgz#2fbd77e147530247d37f325930d457b3ebe894f6" - integrity sha512-/hBFX/QG1b+N7PZBFs0bi+evgRZcK9nWBxQKZkGoXUT5hJSwl5c4d7y8/hm+NQZRPhQ67RzFaj5UM9YeyKoryw== - dependencies: - "@npmcli/promise-spawn" "^1.3.2" - lru-cache "^6.0.0" - mkdirp "^1.0.4" - npm-pick-manifest "^6.1.1" - promise-inflight "^1.0.1" - promise-retry "^2.0.1" - semver "^7.3.5" - which "^2.0.2" - "@npmcli/git@^3.0.0": version "3.0.2" resolved "https://registry.yarnpkg.com/@npmcli/git/-/git-3.0.2.tgz#5c5de6b4d70474cf2d09af149ce42e4e1dacb931" @@ -1730,7 +2428,7 @@ semver "^7.3.5" which "^2.0.2" -"@npmcli/installed-package-contents@^1.0.6", "@npmcli/installed-package-contents@^1.0.7": +"@npmcli/installed-package-contents@^1.0.7": version "1.0.7" resolved "https://registry.yarnpkg.com/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz#ab7408c6147911b970a8abe261ce512232a3f4fa" integrity sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw== @@ -1738,16 +2436,6 @@ npm-bundled "^1.1.1" npm-normalize-package-bin "^1.0.1" -"@npmcli/map-workspaces@^2.0.0": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@npmcli/map-workspaces/-/map-workspaces-2.0.2.tgz#dfc87ced615afeb98a081da2aa9bba072bf6712d" - integrity sha512-ED54EslGsHFWBPN5x8JAOszuWywuoXYSi9E3HQRsgVkWnqsdTBJDSM4IFMRwmmBUbCHAxmP3wGLu1WMm4fhrOw== - dependencies: - "@npmcli/name-from-folder" "^1.0.1" - glob "^7.2.0" - minimatch "^5.0.1" - read-package-json-fast "^2.0.3" - "@npmcli/map-workspaces@^2.0.3": version "2.0.4" resolved "https://registry.yarnpkg.com/@npmcli/map-workspaces/-/map-workspaces-2.0.4.tgz#9e5e8ab655215a262aefabf139782b894e0504fc" @@ -1758,16 +2446,6 @@ minimatch "^5.0.1" read-package-json-fast "^2.0.3" -"@npmcli/metavuln-calculator@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@npmcli/metavuln-calculator/-/metavuln-calculator-2.0.0.tgz#70937b8b5a5cad5c588c8a7b38c4a8bd6f62c84c" - integrity sha512-VVW+JhWCKRwCTE+0xvD6p3uV4WpqocNYYtzyvenqL/u1Q3Xx6fGTJ+6UoIoii07fbuEO9U3IIyuGY0CYHDv1sg== - dependencies: - cacache "^15.0.5" - json-parse-even-better-errors "^2.3.1" - pacote "^12.0.0" - semver "^7.3.2" - "@npmcli/metavuln-calculator@^3.0.1": version "3.1.1" resolved "https://registry.yarnpkg.com/@npmcli/metavuln-calculator/-/metavuln-calculator-3.1.1.tgz#9359bd72b400f8353f6a28a25c8457b562602622" @@ -1778,7 +2456,7 @@ pacote "^13.0.3" semver "^7.3.5" -"@npmcli/move-file@^1.0.1", "@npmcli/move-file@^1.1.0", "@npmcli/move-file@^1.1.2": +"@npmcli/move-file@^1.0.1", "@npmcli/move-file@^1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.1.2.tgz#1a82c3e372f7cae9253eb66d72543d6b8685c674" integrity sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg== @@ -1799,23 +2477,11 @@ resolved "https://registry.yarnpkg.com/@npmcli/name-from-folder/-/name-from-folder-1.0.1.tgz#77ecd0a4fcb772ba6fe927e2e2e155fbec2e6b1a" integrity sha512-qq3oEfcLFwNfEYOQ8HLimRGKlD8WSeGEdtUa7hmzpR8Sa7haL1KVQrvgO6wqMjhWFFVjgtrh1gIxDz+P8sjUaA== -"@npmcli/node-gyp@^1.0.2", "@npmcli/node-gyp@^1.0.3": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@npmcli/node-gyp/-/node-gyp-1.0.3.tgz#a912e637418ffc5f2db375e93b85837691a43a33" - integrity sha512-fnkhw+fmX65kiLqk6E3BFLXNC26rUhK90zVwe2yncPliVT/Qos3xjhTLE59Df8KnPlcwIERXKVlU1bXoUQ+liA== - "@npmcli/node-gyp@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@npmcli/node-gyp/-/node-gyp-2.0.0.tgz#8c20e53e34e9078d18815c1d2dda6f2420d75e35" integrity sha512-doNI35wIe3bBaEgrlPfdJPaCpUR89pJWep4Hq3aRdh6gKazIVWfs0jHttvSSoq47ZXgC7h73kDsUl8AoIQUB+A== -"@npmcli/package-json@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@npmcli/package-json/-/package-json-1.0.1.tgz#1ed42f00febe5293c3502fd0ef785647355f6e89" - integrity sha512-y6jnu76E9C23osz8gEMBayZmaZ69vFOIk8vR1FJL/wbEJ54+9aVG9rLTjQKSXfgYZEr50nw1txBBFfBZZe+bYg== - dependencies: - json-parse-even-better-errors "^2.3.1" - "@npmcli/package-json@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@npmcli/package-json/-/package-json-2.0.0.tgz#3bbcf4677e21055adbe673d9f08c9f9cde942e4a" @@ -1823,13 +2489,6 @@ dependencies: json-parse-even-better-errors "^2.3.1" -"@npmcli/promise-spawn@^1.2.0", "@npmcli/promise-spawn@^1.3.2": - version "1.3.2" - resolved "https://registry.yarnpkg.com/@npmcli/promise-spawn/-/promise-spawn-1.3.2.tgz#42d4e56a8e9274fba180dabc0aea6e38f29274f5" - integrity sha512-QyAGYo/Fbj4MXeGdJcFzZ+FkDkomfRBrPM+9QYJSg+PxgAUL+LU3FneQk37rKR2/zjqkCV1BLHccX98wRXG3Sg== - dependencies: - infer-owner "^1.0.4" - "@npmcli/promise-spawn@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@npmcli/promise-spawn/-/promise-spawn-3.0.0.tgz#53283b5f18f855c6925f23c24e67c911501ef573" @@ -1837,16 +2496,6 @@ dependencies: infer-owner "^1.0.4" -"@npmcli/run-script@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@npmcli/run-script/-/run-script-2.0.0.tgz#9949c0cab415b17aaac279646db4f027d6f1e743" - integrity sha512-fSan/Pu11xS/TdaTpTB0MRn9guwGU8dye+x56mEVgBEd/QsybBbYcAL0phPXi8SGWFEChkQd6M9qL4y6VOpFig== - dependencies: - "@npmcli/node-gyp" "^1.0.2" - "@npmcli/promise-spawn" "^1.3.2" - node-gyp "^8.2.0" - read-package-json-fast "^2.0.1" - "@npmcli/run-script@^4.1.0", "@npmcli/run-script@^4.1.3", "@npmcli/run-script@^4.1.7": version "4.2.1" resolved "https://registry.yarnpkg.com/@npmcli/run-script/-/run-script-4.2.1.tgz#c07c5c71bc1c70a5f2a06b0d4da976641609b946" @@ -1883,321 +2532,74 @@ dependencies: nx "15.6.3" -"@oclif/color@^1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@oclif/color/-/color-1.0.1.tgz#20ab9205e0924c6388918a88874e1f4b32df9970" - integrity sha512-qjYr+izgWdIVOroiBKqTzQgc1r5Wd9QB1J7yGM2EeelqhBARiiVLRZL45vhV4zdyTRdDkZS0EBzFwQap+nliLA== - dependencies: - ansi-styles "^4.2.1" - chalk "^4.1.0" - strip-ansi "^6.0.1" - supports-color "^8.1.1" - tslib "^2" - -"@oclif/core@3.27.0": - version "3.27.0" - resolved "https://registry.yarnpkg.com/@oclif/core/-/core-3.27.0.tgz#a22a4ff4e5811db7a182b1687302237a57802381" - integrity sha512-Fg93aNFvXzBq5L7ztVHFP2nYwWU1oTCq48G0TjF/qC1UN36KWa2H5Hsm72kERd5x/sjy2M2Tn4kDEorUlpXOlw== +"@oclif/core@4.0.11", "@oclif/core@^4": + version "4.0.11" + resolved "https://registry.yarnpkg.com/@oclif/core/-/core-4.0.11.tgz#0a774d00ccab8ee63eb01c5ad2bffc69a170dba8" + integrity sha512-cZLLdSm9tGSbuoRjjgXf128zvPZH+afjQMQcrvDfoN347KvPg75ne8YJ8qHix+T3Vl03iXfgIH6guQN0kLgmjg== dependencies: - "@types/cli-progress" "^3.11.5" ansi-escapes "^4.3.2" - ansi-styles "^4.3.0" - cardinal "^2.1.1" - chalk "^4.1.2" + ansis "^3.1.1" clean-stack "^3.0.1" - cli-progress "^3.12.0" - color "^4.2.3" + cli-spinners "^2.9.2" debug "^4.3.5" ejs "^3.1.10" get-package-type "^0.1.0" globby "^11.1.0" - hyperlinker "^1.0.0" - indent-string "^4.0.0" - is-wsl "^2.2.0" - js-yaml "^3.14.1" - minimatch "^9.0.4" - natural-orderby "^2.0.3" - object-treeify "^1.1.33" - password-prompt "^1.1.3" - slice-ansi "^4.0.0" - string-width "^4.2.3" - strip-ansi "^6.0.1" - supports-color "^8.1.1" - supports-hyperlinks "^2.2.0" - widest-line "^3.1.0" - wordwrap "^1.0.0" - wrap-ansi "^7.0.0" - -"@oclif/core@^1.2.1", "@oclif/core@^1.3.6": - version "1.6.1" - resolved "https://registry.yarnpkg.com/@oclif/core/-/core-1.6.1.tgz#8300132782fd5845e3f08026f2fbd95917e8c2dd" - integrity sha512-qB33YT3JUc7oH3Mtoov8yRETdMiQKsQNdoB2ozRq8JOCxtqI2f0XiQ6eqes3GpeMZKucl4mmonws5LYraLdQlg== - dependencies: - "@oclif/linewrap" "^1.0.0" - "@oclif/screen" "^3.0.2" - ansi-escapes "^4.3.2" - ansi-styles "^4.3.0" - cardinal "^2.1.1" - chalk "^4.1.2" - clean-stack "^3.0.1" - cli-progress "^3.10.0" - debug "^4.3.3" - ejs "^3.1.6" - fs-extra "^9.1.0" - get-package-type "^0.1.0" - globby "^11.1.0" - hyperlinker "^1.0.0" - indent-string "^4.0.0" - is-wsl "^2.2.0" - js-yaml "^3.14.1" - lodash "^4.17.21" - natural-orderby "^2.0.3" - object-treeify "^1.1.33" - password-prompt "^1.1.2" - semver "^7.3.5" - string-width "^4.2.3" - strip-ansi "^6.0.1" - supports-color "^8.1.1" - supports-hyperlinks "^2.2.0" - tslib "^2.3.1" - widest-line "^3.1.0" - wrap-ansi "^7.0.0" - -"@oclif/core@^1.23.1": - version "1.26.2" - resolved "https://registry.yarnpkg.com/@oclif/core/-/core-1.26.2.tgz#763c68dc91388225acd6f0819c90f93e5d8cde41" - integrity sha512-6jYuZgXvHfOIc9GIaS4T3CIKGTjPmfAxuMcbCbMRKJJl4aq/4xeRlEz0E8/hz8HxvxZBGvN2GwAUHlrGWQVrVw== - dependencies: - "@oclif/linewrap" "^1.0.0" - "@oclif/screen" "^3.0.4" - ansi-escapes "^4.3.2" - ansi-styles "^4.3.0" - cardinal "^2.1.1" - chalk "^4.1.2" - clean-stack "^3.0.1" - cli-progress "^3.10.0" - debug "^4.3.4" - ejs "^3.1.6" - fs-extra "^9.1.0" - get-package-type "^0.1.0" - globby "^11.1.0" - hyperlinker "^1.0.0" - indent-string "^4.0.0" - is-wsl "^2.2.0" - js-yaml "^3.14.1" - natural-orderby "^2.0.3" - object-treeify "^1.1.33" - password-prompt "^1.1.2" - semver "^7.3.7" - string-width "^4.2.3" - strip-ansi "^6.0.1" - supports-color "^8.1.1" - supports-hyperlinks "^2.2.0" - tslib "^2.4.1" - widest-line "^3.1.0" - wrap-ansi "^7.0.0" - -"@oclif/core@^1.3.1": - version "1.6.3" - resolved "https://registry.yarnpkg.com/@oclif/core/-/core-1.6.3.tgz#3d1dd4e033f5512ac35963a73878257142390838" - integrity sha512-a3DrPNlOYemwnzxuJ3tINjqpMVIYe56Mg+XaQo0nGsqGSk69wF5Q/hD8plsWrtwdkeIxwxhgl7T699EJypAUwg== - dependencies: - "@oclif/linewrap" "^1.0.0" - "@oclif/screen" "^3.0.2" - ansi-escapes "^4.3.2" - ansi-styles "^4.3.0" - cardinal "^2.1.1" - chalk "^4.1.2" - clean-stack "^3.0.1" - cli-progress "^3.10.0" - debug "^4.3.3" - ejs "^3.1.6" - fs-extra "^9.1.0" - get-package-type "^0.1.0" - globby "^11.1.0" - hyperlinker "^1.0.0" - indent-string "^4.0.0" - is-wsl "^2.2.0" - js-yaml "^3.14.1" - lodash "^4.17.21" - natural-orderby "^2.0.3" - object-treeify "^1.1.33" - password-prompt "^1.1.2" - semver "^7.3.5" - string-width "^4.2.3" - strip-ansi "^6.0.1" - supports-color "^8.1.1" - supports-hyperlinks "^2.2.0" - tslib "^2.3.1" - widest-line "^3.1.0" - wrap-ansi "^7.0.0" - -"@oclif/core@^2.15.0", "@oclif/core@^2.7.1": - version "2.16.0" - resolved "https://registry.yarnpkg.com/@oclif/core/-/core-2.16.0.tgz#e6f3c6c359d4313a15403d8652bbdd0e99ce4b3a" - integrity sha512-dL6atBH0zCZl1A1IXCKJgLPrM/wR7K+Wi401E/IvqsK8m2iCHW+0TEOGrans/cuN3oTW+uxIyJFHJ8Im0k4qBw== - dependencies: - "@types/cli-progress" "^3.11.0" - ansi-escapes "^4.3.2" - ansi-styles "^4.3.0" - cardinal "^2.1.1" - chalk "^4.1.2" - clean-stack "^3.0.1" - cli-progress "^3.12.0" - debug "^4.3.4" - ejs "^3.1.8" - get-package-type "^0.1.0" - globby "^11.1.0" - hyperlinker "^1.0.0" - indent-string "^4.0.0" - is-wsl "^2.2.0" - js-yaml "^3.14.1" - natural-orderby "^2.0.3" - object-treeify "^1.1.33" - password-prompt "^1.1.2" - slice-ansi "^4.0.0" - string-width "^4.2.3" - strip-ansi "^6.0.1" - supports-color "^8.1.1" - supports-hyperlinks "^2.2.0" - ts-node "^10.9.1" - tslib "^2.5.0" - widest-line "^3.1.0" - wordwrap "^1.0.0" - wrap-ansi "^7.0.0" - -"@oclif/core@^2.8.7": - version "2.8.10" - resolved "https://registry.yarnpkg.com/@oclif/core/-/core-2.8.10.tgz#01d2ce3ad9f9f8679e3d4c506f528e9de7de74a5" - integrity sha512-coRn9vYDEnoE8Vg20aavts9+Bt5QrHhbdh0cDkImopV0MgT8i/VmgL04D33+qoHQH20XzBOMqrjk+bqQzqyaHg== - dependencies: - "@types/cli-progress" "^3.11.0" - ansi-escapes "^4.3.2" - ansi-styles "^4.3.0" - cardinal "^2.1.1" - chalk "^4.1.2" - clean-stack "^3.0.1" - cli-progress "^3.12.0" - debug "^4.3.4" - ejs "^3.1.8" - fs-extra "^9.1.0" - get-package-type "^0.1.0" - globby "^11.1.0" - hyperlinker "^1.0.0" indent-string "^4.0.0" is-wsl "^2.2.0" - js-yaml "^3.14.1" - natural-orderby "^2.0.3" - object-treeify "^1.1.33" - password-prompt "^1.1.2" - semver "^7.3.7" + lilconfig "^3.1.2" + minimatch "^9.0.5" string-width "^4.2.3" - strip-ansi "^6.0.1" - supports-color "^8.1.1" - supports-hyperlinks "^2.2.0" - ts-node "^10.9.1" - tslib "^2.5.0" + supports-color "^8" widest-line "^3.1.0" wordwrap "^1.0.0" wrap-ansi "^7.0.0" -"@oclif/linewrap@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@oclif/linewrap/-/linewrap-1.0.0.tgz#aedcb64b479d4db7be24196384897b5000901d91" - integrity sha512-Ups2dShK52xXa8w6iBWLgcjPJWjais6KPJQq3gQ/88AY6BXoTX+MIGFPrWQO1KLMiQfoTpcLnUwloN4brrVUHw== - -"@oclif/plugin-autocomplete@1.3.10": - version "1.3.10" - resolved "https://registry.yarnpkg.com/@oclif/plugin-autocomplete/-/plugin-autocomplete-1.3.10.tgz#3b6ff23ca03513f05b6719ddf51f01b35bd8bf69" - integrity sha512-oQl7ZqXhXJUOH26mDPcqcMGmcdIoK/uQPSpUBrfLa1iaQ30slTs0T7KOzg+vwKuPqIIF1nTCPuH67lE8GvUPTw== - dependencies: - "@oclif/core" "^1.23.1" - chalk "^4.1.0" - debug "^4.3.4" - fs-extra "^9.0.1" - -"@oclif/plugin-help@5.1.12": - version "5.1.12" - resolved "https://registry.yarnpkg.com/@oclif/plugin-help/-/plugin-help-5.1.12.tgz#24a18631eb9b22cb55e1a3b8e4f6039fd42727e6" - integrity sha512-HvH/RubJxqCinP0vUWQLTOboT+SfjfL8h40s+PymkWaldIcXlpoRaJX50vz+SjZIs7uewZwEk8fzLqpF/BWXlg== - dependencies: - "@oclif/core" "^1.3.6" - -"@oclif/plugin-help@^5.1.19": - version "5.2.20" - resolved "https://registry.yarnpkg.com/@oclif/plugin-help/-/plugin-help-5.2.20.tgz#4035a0ac231f95fb8e334da342175e3ca00f6abc" - integrity sha512-u+GXX/KAGL9S10LxAwNUaWdzbEBARJ92ogmM7g3gDVud2HioCmvWQCDohNRVZ9GYV9oKwZ/M8xwd6a1d95rEKQ== +"@oclif/plugin-autocomplete@3.1.6": + version "3.1.6" + resolved "https://registry.yarnpkg.com/@oclif/plugin-autocomplete/-/plugin-autocomplete-3.1.6.tgz#627ab2b0d9afa95b76f4dc0ba68c0980ee877740" + integrity sha512-Eo13RHSr7c5I5miatEBGhKVkLEADzN8taUlYOs5vbRWtWlR/FoDnwSZJ72gBvvayvCHEqlBOaNBn/wufxdrDAg== dependencies: - "@oclif/core" "^2.15.0" + "@oclif/core" "^4" + ansis "^3.2.0" + debug "^4.3.5" + ejs "^3.1.10" -"@oclif/plugin-not-found@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@oclif/plugin-not-found/-/plugin-not-found-2.3.1.tgz#8fe1019fdeeb77be055314662bb9180808222e80" - integrity sha512-AeNBw+zSkRpePmpXO8xlL072VF2/R2yK3qsVs/JF26Yw1w77TWuRTdFR+hFotJtFCJ4QYqhNtKSjdryCO9AXsA== +"@oclif/plugin-help@6.2.5", "@oclif/plugin-help@^6.2.2": + version "6.2.5" + resolved "https://registry.yarnpkg.com/@oclif/plugin-help/-/plugin-help-6.2.5.tgz#a1d8e8469b3447c055ca3ab5444388a822d06517" + integrity sha512-/NgP6j5THCWDxQj3Mba+IIidf8fBtOT5Wh6ygb2WdWLSxcsRXSQUiJKKOXu8e/N5+KQeuG2Yko2hFxd2cZUzMQ== dependencies: - "@oclif/color" "^1.0.0" - "@oclif/core" "^1.2.1" - fast-levenshtein "^3.0.0" - lodash "^4.17.21" + "@oclif/core" "^4" -"@oclif/plugin-not-found@^2.3.7": - version "2.4.3" - resolved "https://registry.yarnpkg.com/@oclif/plugin-not-found/-/plugin-not-found-2.4.3.tgz#3d24095adb0f3876cb4bcfdfdcb775086cf6d4b5" - integrity sha512-nIyaR4y692frwh7wIHZ3fb+2L6XEecQwRDIb4zbEam0TvaVmBQWZoColQyWA84ljFBPZ8XWiQyTz+ixSwdRkqg== +"@oclif/plugin-not-found@3.2.10", "@oclif/plugin-not-found@^3.2.3": + version "3.2.10" + resolved "https://registry.yarnpkg.com/@oclif/plugin-not-found/-/plugin-not-found-3.2.10.tgz#2d685d784ebc46a21f5b2d0c264ca44bb0f97547" + integrity sha512-Bevp3hcv1IhNgljugIhxL5ARcwxsQmiR9yGOozURuZBX3IjsHBPhI2I92wKA2KM5zRgh4zOm6gvoP8gcHlhLJA== dependencies: - "@oclif/core" "^2.15.0" - chalk "^4" + "@inquirer/confirm" "^3.1.14" + "@oclif/core" "^4" + ansis "^3.2.0" fast-levenshtein "^3.0.0" -"@oclif/plugin-warn-if-update-available@2.0.40": - version "2.0.40" - resolved "https://registry.yarnpkg.com/@oclif/plugin-warn-if-update-available/-/plugin-warn-if-update-available-2.0.40.tgz#17a9bf329ceffdfe578176e9cd7cc6feebcf3034" - integrity sha512-sVYAP/FHwfeljTBtjCIKuJeNpKOFE3mAGkssXyrDu2uodUJV3xvDZ6Lkj7jBaI0eeQEzrN1rTdcbfewifZ09xA== +"@oclif/plugin-warn-if-update-available@3.1.8", "@oclif/plugin-warn-if-update-available@^3.0.19": + version "3.1.8" + resolved "https://registry.yarnpkg.com/@oclif/plugin-warn-if-update-available/-/plugin-warn-if-update-available-3.1.8.tgz#9bef3c7d456bf359728b3d0093dec0d53f59c723" + integrity sha512-8MVaQGnvUq/mBYOVLVC1ZniwGHckRULS75s2PVT/9A4MRPzLmtNpaV8Ncra+X4cvxMJQB7KhbJN3v1itWyHnHg== dependencies: - "@oclif/core" "^2.8.7" - chalk "^4.1.0" - debug "^4.1.0" - fs-extra "^9.0.1" + "@oclif/core" "^4" + ansis "^3.2.0" + debug "^4.3.5" http-call "^5.2.2" lodash "^4.17.21" - semver "^7.5.3" - -"@oclif/plugin-warn-if-update-available@^2.0.14": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@oclif/plugin-warn-if-update-available/-/plugin-warn-if-update-available-2.1.1.tgz#e645d3d735241422d3f75e8fbf5c68db575f4c23" - integrity sha512-y7eSzT6R5bmTIJbiMMXgOlbBpcWXGlVhNeQJBLBCCy1+90Wbjyqf6uvY0i2WcO4sh/THTJ20qCW80j3XUlgDTA== - dependencies: - "@oclif/core" "^2.15.0" - chalk "^4.1.0" - debug "^4.1.0" - http-call "^5.2.2" - lodash.template "^4.5.0" - semver "^7.5.4" - -"@oclif/screen@^3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@oclif/screen/-/screen-3.0.2.tgz#969054308fe98d130c02844a45cc792199b75670" - integrity sha512-S/SF/XYJeevwIgHFmVDAFRUvM3m+OjhvCAYMk78ZJQCYCQ5wS7j+LTt1ZEv2jpEEGg2tx/F6TYYWxddNAYHrFQ== -"@oclif/screen@^3.0.4": - version "3.0.8" - resolved "https://registry.yarnpkg.com/@oclif/screen/-/screen-3.0.8.tgz#f746549c3ae52fdb7794dfc244dfba98ebca37f2" - integrity sha512-yx6KAqlt3TAHBduS2fMQtJDL2ufIHnDRArrJEOoTTuizxqmjLT+psGYOHpmMl3gvQpFJ11Hs76guUUktzAF9Bg== - -"@oclif/test@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@oclif/test/-/test-2.1.0.tgz#e5a0ba619c890770782e48c82d18f5921e2d2b9f" - integrity sha512-o+JTv3k28aMUxywJUlJY1/DORLqumoZFRII492phOmtXM16rD6Luy3z1qinT4BvEtPj2BzOPd2whr/VdYszaYw== - dependencies: - "@oclif/core" "^1.3.1" - fancy-test "^2.0.0" - -"@octokit/auth-token@^2.4.4": - version "2.5.0" - resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.5.0.tgz#27c37ea26c205f28443402477ffd261311f21e36" - integrity sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g== +"@oclif/test@4.0.4": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@oclif/test/-/test-4.0.4.tgz#e7e16d9a3edf2d2b83c8066f3f08569b4aa84e4f" + integrity sha512-O0lGcUl6sq4ijgjPimbx32O6DPCoHknzrNsA+X+XzWD9DsEv0SK6Tib2+22cOqLzLItr+gU73pIYttiD5+UWag== dependencies: - "@octokit/types" "^6.0.3" + ansis "^3.2.0" + debug "^4.3.5" "@octokit/auth-token@^3.0.0": version "3.0.1" @@ -2206,19 +2608,6 @@ dependencies: "@octokit/types" "^7.0.0" -"@octokit/core@^3.5.1": - version "3.5.1" - resolved "https://registry.yarnpkg.com/@octokit/core/-/core-3.5.1.tgz#8601ceeb1ec0e1b1b8217b960a413ed8e947809b" - integrity sha512-omncwpLVxMP+GLpLPgeGJBF6IWJFjXDS5flY5VbppePYX9XehevbDykRH9PdCdvqt9TS5AOTiDide7h0qrkHjw== - dependencies: - "@octokit/auth-token" "^2.4.4" - "@octokit/graphql" "^4.5.8" - "@octokit/request" "^5.6.0" - "@octokit/request-error" "^2.0.5" - "@octokit/types" "^6.0.3" - before-after-hook "^2.2.0" - universal-user-agent "^6.0.0" - "@octokit/core@^4.0.0": version "4.0.5" resolved "https://registry.yarnpkg.com/@octokit/core/-/core-4.0.5.tgz#589e68c0a35d2afdcd41dafceab072c2fbc6ab5f" @@ -2232,15 +2621,6 @@ before-after-hook "^2.2.0" universal-user-agent "^6.0.0" -"@octokit/endpoint@^6.0.1": - version "6.0.12" - resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-6.0.12.tgz#3b4d47a4b0e79b1027fb8d75d4221928b2d05658" - integrity sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA== - dependencies: - "@octokit/types" "^6.0.3" - is-plain-object "^5.0.0" - universal-user-agent "^6.0.0" - "@octokit/endpoint@^7.0.0": version "7.0.2" resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-7.0.2.tgz#11ee868406ba7bb1642e61bbe676d641f79f02be" @@ -2250,15 +2630,6 @@ is-plain-object "^5.0.0" universal-user-agent "^6.0.0" -"@octokit/graphql@^4.5.8": - version "4.8.0" - resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-4.8.0.tgz#664d9b11c0e12112cbf78e10f49a05959aa22cc3" - integrity sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg== - dependencies: - "@octokit/request" "^5.6.0" - "@octokit/types" "^6.0.3" - universal-user-agent "^6.0.0" - "@octokit/graphql@^5.0.0": version "5.0.1" resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-5.0.1.tgz#a06982514ad131fb6fbb9da968653b2233fade9b" @@ -2268,11 +2639,6 @@ "@octokit/types" "^7.0.0" universal-user-agent "^6.0.0" -"@octokit/openapi-types@^11.2.0": - version "11.2.0" - resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-11.2.0.tgz#b38d7fc3736d52a1e96b230c1ccd4a58a2f400a6" - integrity sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA== - "@octokit/openapi-types@^13.11.0": version "13.12.0" resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-13.12.0.tgz#cd49f28127ee06ee3edc6f2b5f5648c7332f6014" @@ -2283,13 +2649,6 @@ resolved "https://registry.yarnpkg.com/@octokit/plugin-enterprise-rest/-/plugin-enterprise-rest-6.0.1.tgz#e07896739618dab8da7d4077c658003775f95437" integrity sha512-93uGjlhUD+iNg1iWhUENAtJata6w5nE+V4urXOAlIXdco6xNZtUSfYY8dzp3Udy74aqO/B5UZL80x/YMa5PKRw== -"@octokit/plugin-paginate-rest@^2.16.8": - version "2.17.0" - resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.17.0.tgz#32e9c7cab2a374421d3d0de239102287d791bce7" - integrity sha512-tzMbrbnam2Mt4AhuyCHvpRkS0oZ5MvwwcQPYGtMv4tUa5kkzG58SVB0fcsLulOZQeRnOgdkZWkRUiyBlh0Bkyw== - dependencies: - "@octokit/types" "^6.34.0" - "@octokit/plugin-paginate-rest@^4.0.0": version "4.3.1" resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-4.3.1.tgz#553e653ee0318605acd23bf3a799c8bfafdedae3" @@ -2302,14 +2661,6 @@ resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz#5e50ed7083a613816b1e4a28aeec5fb7f1462e85" integrity sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA== -"@octokit/plugin-rest-endpoint-methods@^5.12.0": - version "5.13.0" - resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.13.0.tgz#8c46109021a3412233f6f50d28786f8e552427ba" - integrity sha512-uJjMTkN1KaOIgNtUPMtIXDOjx6dGYysdIFhgA52x4xSadQCz3b/zJexvITDVpANnfKPW/+E0xkOvLntqMYpviA== - dependencies: - "@octokit/types" "^6.34.0" - deprecation "^2.3.1" - "@octokit/plugin-rest-endpoint-methods@^6.0.0": version "6.6.2" resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-6.6.2.tgz#cfd1c7280940d5a82d9af12566bafcb33f22bee4" @@ -2318,15 +2669,6 @@ "@octokit/types" "^7.5.0" deprecation "^2.3.1" -"@octokit/request-error@^2.0.5", "@octokit/request-error@^2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-2.1.0.tgz#9e150357831bfc788d13a4fd4b1913d60c74d677" - integrity sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg== - dependencies: - "@octokit/types" "^6.0.3" - deprecation "^2.0.0" - once "^1.4.0" - "@octokit/request-error@^3.0.0": version "3.0.1" resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-3.0.1.tgz#3fd747913c06ab2195e52004a521889dadb4b295" @@ -2336,18 +2678,6 @@ deprecation "^2.0.0" once "^1.4.0" -"@octokit/request@^5.6.0": - version "5.6.2" - resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.6.2.tgz#1aa74d5da7b9e04ac60ef232edd9a7438dcf32d8" - integrity sha512-je66CvSEVf0jCpRISxkUcCa0UkxmFs6eGDRSbfJtAVwbLH5ceqF+YEyC8lj8ystKyZTy8adWr0qmkY52EfOeLA== - dependencies: - "@octokit/endpoint" "^6.0.1" - "@octokit/request-error" "^2.1.0" - "@octokit/types" "^6.16.1" - is-plain-object "^5.0.0" - node-fetch "^2.6.1" - universal-user-agent "^6.0.0" - "@octokit/request@^6.0.0": version "6.2.1" resolved "https://registry.yarnpkg.com/@octokit/request/-/request-6.2.1.tgz#3ceeb22dab09a29595d96594b6720fc14495cf4e" @@ -2360,16 +2690,6 @@ node-fetch "^2.6.7" universal-user-agent "^6.0.0" -"@octokit/rest@^18.0.6": - version "18.12.0" - resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-18.12.0.tgz#f06bc4952fc87130308d810ca9d00e79f6988881" - integrity sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q== - dependencies: - "@octokit/core" "^3.5.1" - "@octokit/plugin-paginate-rest" "^2.16.8" - "@octokit/plugin-request-log" "^1.0.4" - "@octokit/plugin-rest-endpoint-methods" "^5.12.0" - "@octokit/rest@^19.0.3": version "19.0.4" resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-19.0.4.tgz#fd8bed1cefffa486e9ae46a9dc608ce81bcfcbdd" @@ -2380,13 +2700,6 @@ "@octokit/plugin-request-log" "^1.0.4" "@octokit/plugin-rest-endpoint-methods" "^6.0.0" -"@octokit/types@^6.0.3", "@octokit/types@^6.16.1", "@octokit/types@^6.34.0": - version "6.34.0" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.34.0.tgz#c6021333334d1ecfb5d370a8798162ddf1ae8218" - integrity sha512-s1zLBjWhdEI2zwaoSgyOFoKSl109CUcVBCc7biPJ3aAf6LGLU6szDvi31JPU7bxfla2lqfhjbbg/5DdFNxOwHw== - dependencies: - "@octokit/openapi-types" "^11.2.0" - "@octokit/types@^7.0.0", "@octokit/types@^7.5.0": version "7.5.0" resolved "https://registry.yarnpkg.com/@octokit/types/-/types-7.5.0.tgz#85646021bd618467b7cc465d9734b3f2878c9fae" @@ -2499,17 +2812,10 @@ resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== -"@sindresorhus/is@^4.0.0": - version "4.6.0" - resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f" - integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw== - -"@sinonjs/commons@^1.7.0": - version "1.8.3" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d" - integrity sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ== - dependencies: - type-detect "4.0.8" +"@sindresorhus/is@^5.2.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-5.6.0.tgz#41dd6093d34652cddb5d5bdeee04eafc33826668" + integrity sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g== "@sinonjs/commons@^3.0.0": version "3.0.0" @@ -2525,19 +2831,499 @@ dependencies: "@sinonjs/commons" "^3.0.0" -"@sinonjs/fake-timers@^7.1.0": - version "7.1.2" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-7.1.2.tgz#2524eae70c4910edccf99b2f4e6efc5894aff7b5" - integrity sha512-iQADsW4LBMISqZ6Ci1dupJL9pprqwcVFTcOsEmQOEhW+KLCVn/Y4Jrvg2k19fIHCp+iFprriYPTdRcQR8NbUPg== +"@smithy/abort-controller@^3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@smithy/abort-controller/-/abort-controller-3.1.1.tgz#291210611ff6afecfc198d0ca72d5771d8461d16" + integrity sha512-MBJBiidoe+0cTFhyxT8g+9g7CeVccLM0IOKKUMCNQ1CNMJ/eIfoo0RTfVrXOONEI1UCN1W+zkiHSbzUNE9dZtQ== + dependencies: + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@smithy/chunked-blob-reader-native@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@smithy/chunked-blob-reader-native/-/chunked-blob-reader-native-3.0.0.tgz#f1104b30030f76f9aadcbd3cdca4377bd1ba2695" + integrity sha512-VDkpCYW+peSuM4zJip5WDfqvg2Mo/e8yxOv3VF1m11y7B8KKMKVFtmZWDe36Fvk8rGuWrPZHHXZ7rR7uM5yWyg== + dependencies: + "@smithy/util-base64" "^3.0.0" + tslib "^2.6.2" + +"@smithy/chunked-blob-reader@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@smithy/chunked-blob-reader/-/chunked-blob-reader-3.0.0.tgz#e5d3b04e9b273ba8b7ede47461e2aa96c8aa49e0" + integrity sha512-sbnURCwjF0gSToGlsBiAmd1lRCmSn72nu9axfJu5lIx6RUEgHu6GwTMbqCdhQSi0Pumcm5vFxsi9XWXb2mTaoA== + dependencies: + tslib "^2.6.2" + +"@smithy/config-resolver@^3.0.4", "@smithy/config-resolver@^3.0.5": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@smithy/config-resolver/-/config-resolver-3.0.5.tgz#727978bba7ace754c741c259486a19d3083431fd" + integrity sha512-SkW5LxfkSI1bUC74OtfBbdz+grQXYiPYolyu8VfpLIjEoN/sHVBlLeGXMQ1vX4ejkgfv6sxVbQJ32yF2cl1veA== + dependencies: + "@smithy/node-config-provider" "^3.1.4" + "@smithy/types" "^3.3.0" + "@smithy/util-config-provider" "^3.0.0" + "@smithy/util-middleware" "^3.0.3" + tslib "^2.6.2" + +"@smithy/core@^2.2.4": + version "2.2.6" + resolved "https://registry.yarnpkg.com/@smithy/core/-/core-2.2.6.tgz#05e3482079fff7522077e0f3ce2ee6cc507f461c" + integrity sha512-tBbVIv/ui7/lLTKayYJJvi8JLVL2SwOQTbNFEOrvzSE3ktByvsa1erwBOnAMo8N5Vu30g7lN4lLStrU75oDGuw== + dependencies: + "@smithy/middleware-endpoint" "^3.0.5" + "@smithy/middleware-retry" "^3.0.9" + "@smithy/middleware-serde" "^3.0.3" + "@smithy/protocol-http" "^4.0.3" + "@smithy/smithy-client" "^3.1.7" + "@smithy/types" "^3.3.0" + "@smithy/util-middleware" "^3.0.3" + tslib "^2.6.2" + +"@smithy/credential-provider-imds@^3.1.3", "@smithy/credential-provider-imds@^3.1.4": + version "3.1.4" + resolved "https://registry.yarnpkg.com/@smithy/credential-provider-imds/-/credential-provider-imds-3.1.4.tgz#797116f68cc3ffa658469558cc014f25d9febe09" + integrity sha512-NKyH01m97Xa5xf3pB2QOF3lnuE8RIK0hTVNU5zvZAwZU8uspYO4DHQVlK+Y5gwSrujTfHvbfd1D9UFJAc0iYKQ== + dependencies: + "@smithy/node-config-provider" "^3.1.4" + "@smithy/property-provider" "^3.1.3" + "@smithy/types" "^3.3.0" + "@smithy/url-parser" "^3.0.3" + tslib "^2.6.2" + +"@smithy/eventstream-codec@^3.1.2": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@smithy/eventstream-codec/-/eventstream-codec-3.1.2.tgz#4a1c72b34400631b829241151984a1ad8c4f963c" + integrity sha512-0mBcu49JWt4MXhrhRAlxASNy0IjDRFU+aWNDRal9OtUJvJNiwDuyKMUONSOjLjSCeGwZaE0wOErdqULer8r7yw== + dependencies: + "@aws-crypto/crc32" "5.2.0" + "@smithy/types" "^3.3.0" + "@smithy/util-hex-encoding" "^3.0.0" + tslib "^2.6.2" + +"@smithy/eventstream-serde-browser@^3.0.4": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-3.0.4.tgz#98d6e7ae60d297e37ee7775af2a7a8bbe574579d" + integrity sha512-Eo4anLZX6ltGJTZ5yJMc80gZPYYwBn44g0h7oFq6et+TYr5dUsTpIcDbz2evsOKIZhZ7zBoFWHtBXQ4QQeb5xA== + dependencies: + "@smithy/eventstream-serde-universal" "^3.0.4" + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@smithy/eventstream-serde-config-resolver@^3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-3.0.3.tgz#f852e096d0ad112363b4685e1d441088d1fce67a" + integrity sha512-NVTYjOuYpGfrN/VbRQgn31x73KDLfCXCsFdad8DiIc3IcdxL+dYA9zEQPyOP7Fy2QL8CPy2WE4WCUD+ZsLNfaQ== + dependencies: + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@smithy/eventstream-serde-node@^3.0.4": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-node/-/eventstream-serde-node-3.0.4.tgz#6301752ca51b3ebabcd2dec112f1dacd990de4c1" + integrity sha512-mjlG0OzGAYuUpdUpflfb9zyLrBGgmQmrobNT8b42ZTsGv/J03+t24uhhtVEKG/b2jFtPIHF74Bq+VUtbzEKOKg== + dependencies: + "@smithy/eventstream-serde-universal" "^3.0.4" + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@smithy/eventstream-serde-universal@^3.0.4": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-3.0.4.tgz#6754de5b94bdc286d8ef1d6bcf22d80f6ab68f30" + integrity sha512-Od9dv8zh3PgOD7Vj4T3HSuox16n0VG8jJIM2gvKASL6aCtcS8CfHZDWe1Ik3ZXW6xBouU+45Q5wgoliWDZiJ0A== + dependencies: + "@smithy/eventstream-codec" "^3.1.2" + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@smithy/fetch-http-handler@^3.2.0", "@smithy/fetch-http-handler@^3.2.1": + version "3.2.1" + resolved "https://registry.yarnpkg.com/@smithy/fetch-http-handler/-/fetch-http-handler-3.2.1.tgz#04ba6804cdf2b1cb783229eede6b9cd8653c5543" + integrity sha512-0w0bgUvZmfa0vHN8a+moByhCJT07WN6AHKEhFSOLsDpnszm+5dLVv5utGaqbhOrZ/aF5x3xuPMs/oMCd+4O5xg== + dependencies: + "@smithy/protocol-http" "^4.0.3" + "@smithy/querystring-builder" "^3.0.3" + "@smithy/types" "^3.3.0" + "@smithy/util-base64" "^3.0.0" + tslib "^2.6.2" + +"@smithy/hash-blob-browser@^3.1.2": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@smithy/hash-blob-browser/-/hash-blob-browser-3.1.2.tgz#90281c1f183d93686fb4f26107f1819644d68829" + integrity sha512-hAbfqN2UbISltakCC2TP0kx4LqXBttEv2MqSPE98gVuDFMf05lU+TpC41QtqGP3Ff5A3GwZMPfKnEy0VmEUpmg== + dependencies: + "@smithy/chunked-blob-reader" "^3.0.0" + "@smithy/chunked-blob-reader-native" "^3.0.0" + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@smithy/hash-node@^3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@smithy/hash-node/-/hash-node-3.0.3.tgz#82c5cb7b0f1a29ee7319081853d2d158c07dff24" + integrity sha512-2ctBXpPMG+B3BtWSGNnKELJ7SH9e4TNefJS0cd2eSkOOROeBnnVBnAy9LtJ8tY4vUEoe55N4CNPxzbWvR39iBw== + dependencies: + "@smithy/types" "^3.3.0" + "@smithy/util-buffer-from" "^3.0.0" + "@smithy/util-utf8" "^3.0.0" + tslib "^2.6.2" + +"@smithy/hash-stream-node@^3.1.2": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@smithy/hash-stream-node/-/hash-stream-node-3.1.2.tgz#89f0290ae44b113863878e75b10c484ff48af71c" + integrity sha512-PBgDMeEdDzi6JxKwbfBtwQG9eT9cVwsf0dZzLXoJF4sHKHs5HEo/3lJWpn6jibfJwT34I1EBXpBnZE8AxAft6g== + dependencies: + "@smithy/types" "^3.3.0" + "@smithy/util-utf8" "^3.0.0" + tslib "^2.6.2" + +"@smithy/invalid-dependency@^3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@smithy/invalid-dependency/-/invalid-dependency-3.0.3.tgz#8d9fd70e3a94b565a4eba4ffbdc95238e1930528" + integrity sha512-ID1eL/zpDULmHJbflb864k72/SNOZCADRc9i7Exq3RUNJw6raWUSlFEQ+3PX3EYs++bTxZB2dE9mEHTQLv61tw== + dependencies: + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@smithy/is-array-buffer@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz#f84f0d9f9a36601a9ca9381688bd1b726fd39111" + integrity sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA== + dependencies: + tslib "^2.6.2" + +"@smithy/is-array-buffer@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz#9a95c2d46b8768946a9eec7f935feaddcffa5e7a" + integrity sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ== + dependencies: + tslib "^2.6.2" + +"@smithy/md5-js@^3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@smithy/md5-js/-/md5-js-3.0.3.tgz#55ee40aa24075b096c39f7910590c18ff7660c98" + integrity sha512-O/SAkGVwpWmelpj/8yDtsaVe6sINHLB1q8YE/+ZQbDxIw3SRLbTZuRaI10K12sVoENdnHqzPp5i3/H+BcZ3m3Q== + dependencies: + "@smithy/types" "^3.3.0" + "@smithy/util-utf8" "^3.0.0" + tslib "^2.6.2" + +"@smithy/middleware-content-length@^3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@smithy/middleware-content-length/-/middleware-content-length-3.0.3.tgz#426a7f907cc3c0a5d81deb84e16d38303e5a9ad8" + integrity sha512-Dbz2bzexReYIQDWMr+gZhpwBetNXzbhnEMhYKA6urqmojO14CsXjnsoPYO8UL/xxcawn8ZsuVU61ElkLSltIUQ== + dependencies: + "@smithy/protocol-http" "^4.0.3" + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@smithy/middleware-endpoint@^3.0.4", "@smithy/middleware-endpoint@^3.0.5": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@smithy/middleware-endpoint/-/middleware-endpoint-3.0.5.tgz#76e8a559e891282d3ede9ab8e228e66cbee89b21" + integrity sha512-V4acqqrh5tDxUEGVTOgf2lYMZqPQsoGntCrjrJZEeBzEzDry2d2vcI1QCXhGltXPPY+BMc6eksZMguA9fIY8vA== + dependencies: + "@smithy/middleware-serde" "^3.0.3" + "@smithy/node-config-provider" "^3.1.4" + "@smithy/shared-ini-file-loader" "^3.1.4" + "@smithy/types" "^3.3.0" + "@smithy/url-parser" "^3.0.3" + "@smithy/util-middleware" "^3.0.3" + tslib "^2.6.2" + +"@smithy/middleware-retry@^3.0.7", "@smithy/middleware-retry@^3.0.9": + version "3.0.9" + resolved "https://registry.yarnpkg.com/@smithy/middleware-retry/-/middleware-retry-3.0.9.tgz#3d5c33b49ad372bf02c8525931febc5cc246815c" + integrity sha512-Mrv9omExU1gA7Y0VEJG2LieGfPYtwwcEiOnVGZ54a37NEMr66TJ0glFslOJFuKWG6izg5DpKIUmDV9rRxjm47Q== + dependencies: + "@smithy/node-config-provider" "^3.1.4" + "@smithy/protocol-http" "^4.0.3" + "@smithy/service-error-classification" "^3.0.3" + "@smithy/smithy-client" "^3.1.7" + "@smithy/types" "^3.3.0" + "@smithy/util-middleware" "^3.0.3" + "@smithy/util-retry" "^3.0.3" + tslib "^2.6.2" + uuid "^9.0.1" + +"@smithy/middleware-serde@^3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@smithy/middleware-serde/-/middleware-serde-3.0.3.tgz#74d974460f74d99f38c861e6862984543a880a66" + integrity sha512-puUbyJQBcg9eSErFXjKNiGILJGtiqmuuNKEYNYfUD57fUl4i9+mfmThtQhvFXU0hCVG0iEJhvQUipUf+/SsFdA== + dependencies: + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@smithy/middleware-stack@^3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@smithy/middleware-stack/-/middleware-stack-3.0.3.tgz#91845c7e61e6f137fa912b623b6def719a4f6ce7" + integrity sha512-r4klY9nFudB0r9UdSMaGSyjyQK5adUyPnQN/ZM6M75phTxOdnc/AhpvGD1fQUvgmqjQEBGCwpnPbDm8pH5PapA== + dependencies: + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@smithy/node-config-provider@^3.1.3", "@smithy/node-config-provider@^3.1.4": + version "3.1.4" + resolved "https://registry.yarnpkg.com/@smithy/node-config-provider/-/node-config-provider-3.1.4.tgz#05647bed666aa8036a1ad72323c1942e5d421be1" + integrity sha512-YvnElQy8HR4vDcAjoy7Xkx9YT8xZP4cBXcbJSgm/kxmiQu08DwUwj8rkGnyoJTpfl/3xYHH+d8zE+eHqoDCSdQ== + dependencies: + "@smithy/property-provider" "^3.1.3" + "@smithy/shared-ini-file-loader" "^3.1.4" + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@smithy/node-http-handler@^3.1.1", "@smithy/node-http-handler@^3.1.2": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@smithy/node-http-handler/-/node-http-handler-3.1.2.tgz#2d753c07f11e7a3da3534b156320d1e0e9401617" + integrity sha512-Td3rUNI7qqtoSLTsJBtsyfoG4cF/XMFmJr6Z2dX8QNzIi6tIW6YmuyFml8mJ2cNpyWNqITKbROMOFrvQjmsOvw== + dependencies: + "@smithy/abort-controller" "^3.1.1" + "@smithy/protocol-http" "^4.0.3" + "@smithy/querystring-builder" "^3.0.3" + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@smithy/property-provider@^3.1.3": + version "3.1.3" + resolved "https://registry.yarnpkg.com/@smithy/property-provider/-/property-provider-3.1.3.tgz#afd57ea82a3f6c79fbda95e3cb85c0ee0a79f39a" + integrity sha512-zahyOVR9Q4PEoguJ/NrFP4O7SMAfYO1HLhB18M+q+Z4KFd4V2obiMnlVoUFzFLSPeVt1POyNWneHHrZaTMoc/g== + dependencies: + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@smithy/protocol-http@^4.0.3": + version "4.0.3" + resolved "https://registry.yarnpkg.com/@smithy/protocol-http/-/protocol-http-4.0.3.tgz#acf16058504e3cce2dbe8abf94f7b544cd09d3f4" + integrity sha512-x5jmrCWwQlx+Zv4jAtc33ijJ+vqqYN+c/ZkrnpvEe/uDas7AT7A/4Rc2CdfxgWv4WFGmEqODIrrUToPN6DDkGw== + dependencies: + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@smithy/querystring-builder@^3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@smithy/querystring-builder/-/querystring-builder-3.0.3.tgz#6b0e566f885bb84938d077c69e8f8555f686af13" + integrity sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw== + dependencies: + "@smithy/types" "^3.3.0" + "@smithy/util-uri-escape" "^3.0.0" + tslib "^2.6.2" + +"@smithy/querystring-parser@^3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@smithy/querystring-parser/-/querystring-parser-3.0.3.tgz#272a6b83f88dfcbbec8283d72a6bde850cc00091" + integrity sha512-zahM1lQv2YjmznnfQsWbYojFe55l0SLG/988brlLv1i8z3dubloLF+75ATRsqPBboUXsW6I9CPGE5rQgLfY0vQ== + dependencies: + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@smithy/service-error-classification@^3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@smithy/service-error-classification/-/service-error-classification-3.0.3.tgz#73484255060a094aa9372f6cd972dcaf97e3ce80" + integrity sha512-Jn39sSl8cim/VlkLsUhRFq/dKDnRUFlfRkvhOJaUbLBXUsLRLNf9WaxDv/z9BjuQ3A6k/qE8af1lsqcwm7+DaQ== + dependencies: + "@smithy/types" "^3.3.0" + +"@smithy/shared-ini-file-loader@^3.1.3", "@smithy/shared-ini-file-loader@^3.1.4": + version "3.1.4" + resolved "https://registry.yarnpkg.com/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.4.tgz#7dceaf5a5307a2ee347ace8aba17312a1a3ede15" + integrity sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ== + dependencies: + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@smithy/signature-v4@^3.1.2": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@smithy/signature-v4/-/signature-v4-3.1.2.tgz#63fc0d4f9a955e902138fb0a57fafc96b9d4e8bb" + integrity sha512-3BcPylEsYtD0esM4Hoyml/+s7WP2LFhcM3J2AGdcL2vx9O60TtfpDOL72gjb4lU8NeRPeKAwR77YNyyGvMbuEA== + dependencies: + "@smithy/is-array-buffer" "^3.0.0" + "@smithy/types" "^3.3.0" + "@smithy/util-hex-encoding" "^3.0.0" + "@smithy/util-middleware" "^3.0.3" + "@smithy/util-uri-escape" "^3.0.0" + "@smithy/util-utf8" "^3.0.0" + tslib "^2.6.2" + +"@smithy/smithy-client@^3.1.5", "@smithy/smithy-client@^3.1.7": + version "3.1.7" + resolved "https://registry.yarnpkg.com/@smithy/smithy-client/-/smithy-client-3.1.7.tgz#56c1eee68b903053e246fb141253a567cc4d9930" + integrity sha512-nZbJZB0XI3YnaFBWGDBr7kjaew6O0oNYNmopyIz6gKZEbxzrtH7rwvU1GcVxcSFoOwWecLJEe79fxEMljHopFQ== + dependencies: + "@smithy/middleware-endpoint" "^3.0.5" + "@smithy/middleware-stack" "^3.0.3" + "@smithy/protocol-http" "^4.0.3" + "@smithy/types" "^3.3.0" + "@smithy/util-stream" "^3.0.6" + tslib "^2.6.2" + +"@smithy/types@^3.3.0": + version "3.3.0" + resolved "https://registry.yarnpkg.com/@smithy/types/-/types-3.3.0.tgz#fae037c733d09bc758946a01a3de0ef6e210b16b" + integrity sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA== + dependencies: + tslib "^2.6.2" + +"@smithy/url-parser@^3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@smithy/url-parser/-/url-parser-3.0.3.tgz#e8a060d9810b24b1870385fc2b02485b8a6c5955" + integrity sha512-pw3VtZtX2rg+s6HMs6/+u9+hu6oY6U7IohGhVNnjbgKy86wcIsSZwgHrFR+t67Uyxvp4Xz3p3kGXXIpTNisq8A== + dependencies: + "@smithy/querystring-parser" "^3.0.3" + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@smithy/util-base64@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@smithy/util-base64/-/util-base64-3.0.0.tgz#f7a9a82adf34e27a72d0719395713edf0e493017" + integrity sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ== + dependencies: + "@smithy/util-buffer-from" "^3.0.0" + "@smithy/util-utf8" "^3.0.0" + tslib "^2.6.2" + +"@smithy/util-body-length-browser@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@smithy/util-body-length-browser/-/util-body-length-browser-3.0.0.tgz#86ec2f6256310b4845a2f064e2f571c1ca164ded" + integrity sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ== + dependencies: + tslib "^2.6.2" + +"@smithy/util-body-length-node@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@smithy/util-body-length-node/-/util-body-length-node-3.0.0.tgz#99a291bae40d8932166907fe981d6a1f54298a6d" + integrity sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA== + dependencies: + tslib "^2.6.2" + +"@smithy/util-buffer-from@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz#6fc88585165ec73f8681d426d96de5d402021e4b" + integrity sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA== + dependencies: + "@smithy/is-array-buffer" "^2.2.0" + tslib "^2.6.2" + +"@smithy/util-buffer-from@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz#559fc1c86138a89b2edaefc1e6677780c24594e3" + integrity sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA== + dependencies: + "@smithy/is-array-buffer" "^3.0.0" + tslib "^2.6.2" + +"@smithy/util-config-provider@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@smithy/util-config-provider/-/util-config-provider-3.0.0.tgz#62c6b73b22a430e84888a8f8da4b6029dd5b8efe" + integrity sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ== + dependencies: + tslib "^2.6.2" + +"@smithy/util-defaults-mode-browser@^3.0.7": + version "3.0.9" + resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.9.tgz#a7035ca57f359810f52d828c68ad8746b0120113" + integrity sha512-WKPcElz92MAQG09miBdb0GxEH/MwD5GfE8g07WokITq5g6J1ROQfYCKC1wNnkqAGfrSywT7L0rdvvqlBplqiyA== + dependencies: + "@smithy/property-provider" "^3.1.3" + "@smithy/smithy-client" "^3.1.7" + "@smithy/types" "^3.3.0" + bowser "^2.11.0" + tslib "^2.6.2" + +"@smithy/util-defaults-mode-node@^3.0.7": + version "3.0.9" + resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.9.tgz#d31cd62e9bcc005f92923fc7b6bc0366c3b0478a" + integrity sha512-dQLrUqFxqpf0GvEKEuFdgXcdZwz6oFm752h4d6C7lQz+RLddf761L2r7dSwGWzESMMB3wKj0jL+skRhEGlecjw== + dependencies: + "@smithy/config-resolver" "^3.0.5" + "@smithy/credential-provider-imds" "^3.1.4" + "@smithy/node-config-provider" "^3.1.4" + "@smithy/property-provider" "^3.1.3" + "@smithy/smithy-client" "^3.1.7" + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@smithy/util-endpoints@^2.0.4": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@smithy/util-endpoints/-/util-endpoints-2.0.5.tgz#e3a7a4d1c41250bfd2b2d890d591273a7d8934be" + integrity sha512-ReQP0BWihIE68OAblC/WQmDD40Gx+QY1Ez8mTdFMXpmjfxSyz2fVQu3A4zXRfQU9sZXtewk3GmhfOHswvX+eNg== + dependencies: + "@smithy/node-config-provider" "^3.1.4" + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@smithy/util-hex-encoding@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@smithy/util-hex-encoding/-/util-hex-encoding-3.0.0.tgz#32938b33d5bf2a15796cd3f178a55b4155c535e6" + integrity sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ== + dependencies: + tslib "^2.6.2" + +"@smithy/util-middleware@^3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@smithy/util-middleware/-/util-middleware-3.0.3.tgz#07bf9602682f5a6c55bc2f0384303f85fc68c87e" + integrity sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw== + dependencies: + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@smithy/util-retry@^3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@smithy/util-retry/-/util-retry-3.0.3.tgz#9b2ac0dbb1c81f69812a8affa4d772bebfc0e049" + integrity sha512-AFw+hjpbtVApzpNDhbjNG5NA3kyoMs7vx0gsgmlJF4s+yz1Zlepde7J58zpIRIsdjc+emhpAITxA88qLkPF26w== + dependencies: + "@smithy/service-error-classification" "^3.0.3" + "@smithy/types" "^3.3.0" + tslib "^2.6.2" + +"@smithy/util-stream@^3.0.5", "@smithy/util-stream@^3.0.6": + version "3.0.6" + resolved "https://registry.yarnpkg.com/@smithy/util-stream/-/util-stream-3.0.6.tgz#233624e0e024f5846cf1fdbfb2a2ab5352d724ee" + integrity sha512-w9i//7egejAIvplX821rPWWgaiY1dxsQUw0hXX7qwa/uZ9U3zplqTQ871jWadkcVB9gFDhkPWYVZf4yfFbZ0xA== + dependencies: + "@smithy/fetch-http-handler" "^3.2.1" + "@smithy/node-http-handler" "^3.1.2" + "@smithy/types" "^3.3.0" + "@smithy/util-base64" "^3.0.0" + "@smithy/util-buffer-from" "^3.0.0" + "@smithy/util-hex-encoding" "^3.0.0" + "@smithy/util-utf8" "^3.0.0" + tslib "^2.6.2" + +"@smithy/util-uri-escape@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz#e43358a78bf45d50bb736770077f0f09195b6f54" + integrity sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg== + dependencies: + tslib "^2.6.2" + +"@smithy/util-utf8@^2.0.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@smithy/util-utf8/-/util-utf8-2.3.0.tgz#dd96d7640363259924a214313c3cf16e7dd329c5" + integrity sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A== + dependencies: + "@smithy/util-buffer-from" "^2.2.0" + tslib "^2.6.2" + +"@smithy/util-utf8@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@smithy/util-utf8/-/util-utf8-3.0.0.tgz#1a6a823d47cbec1fd6933e5fc87df975286d9d6a" + integrity sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA== + dependencies: + "@smithy/util-buffer-from" "^3.0.0" + tslib "^2.6.2" + +"@smithy/util-waiter@^3.1.2": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@smithy/util-waiter/-/util-waiter-3.1.2.tgz#2d40c3312f3537feee763459a19acafab4c75cf3" + integrity sha512-4pP0EV3iTsexDx+8PPGAKCQpd/6hsQBaQhqWzU4hqKPHN5epPsxKbvUTIiYIHTxaKt6/kEaqPBpu/ufvfbrRzw== dependencies: - "@sinonjs/commons" "^1.7.0" + "@smithy/abort-controller" "^3.1.1" + "@smithy/types" "^3.3.0" + tslib "^2.6.2" -"@szmarczak/http-timer@^4.0.5": - version "4.0.6" - resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz#b4a914bb62e7c272d4e5989fe4440f812ab1d807" - integrity sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w== +"@szmarczak/http-timer@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-5.0.1.tgz#c7c1bf1141cdd4751b0399c8fc7b8b664cd5be3a" + integrity sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw== dependencies: - defer-to-connect "^2.0.0" + defer-to-connect "^2.0.1" "@tootallnate/once@1": version "1.1.2" @@ -2619,32 +3405,10 @@ resolved "https://registry.yarnpkg.com/@types/buffer-json/-/buffer-json-2.0.0.tgz#6ec0ee9ba7334a378a9c1d849bccc1b079a33554" integrity sha512-nFKOrY93Tvv5Tobws+YbkGlPOJsn1nVpZah3BlSyQ4EniFm97KLvSr54tZ5xQp8mlf/XxbYwskNCYQB9EdrPlQ== -"@types/cacheable-request@^6.0.1": - version "6.0.3" - resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz#a430b3260466ca7b5ca5bfd735693b36e7a9d183" - integrity sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw== - dependencies: - "@types/http-cache-semantics" "*" - "@types/keyv" "^3.1.4" - "@types/node" "*" - "@types/responselike" "^1.0.0" - -"@types/chai@*": - version "4.2.22" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.22.tgz#47020d7e4cf19194d43b5202f35f75bd2ad35ce7" - integrity sha512-tFfcE+DSTzWAgifkjik9AySNqIyNoYwmR+uecPwwD/XRNfvOjmC/FjCxpiUGDkDVDphPfCUecSQVFw+lN3M3kQ== - -"@types/cli-progress@^3.11.0": - version "3.11.0" - resolved "https://registry.yarnpkg.com/@types/cli-progress/-/cli-progress-3.11.0.tgz#ec79df99b26757c3d1c7170af8422e0fc95eef7e" - integrity sha512-XhXhBv1R/q2ahF3BM7qT5HLzJNlIL0wbcGyZVjqOTqAybAnsLisd7gy1UCyIqpL+5Iv6XhlSyzjLCnI2sIdbCg== - dependencies: - "@types/node" "*" - -"@types/cli-progress@^3.11.5": - version "3.11.5" - resolved "https://registry.yarnpkg.com/@types/cli-progress/-/cli-progress-3.11.5.tgz#9518c745e78557efda057e3f96a5990c717268c3" - integrity sha512-D4PbNRbviKyppS5ivBGyFO29POlySLmA2HyUFE4p5QGazAMM3CwkKWcvTl8gvElSuxRh6FPKL8XmidX873ou4g== +"@types/cli-progress@3.11.6": + version "3.11.6" + resolved "https://registry.yarnpkg.com/@types/cli-progress/-/cli-progress-3.11.6.tgz#94b334ebe4190f710e51c1bf9b4fedb681fa9e45" + integrity sha512-cE3+jb9WRlu+uOSAugewNpITJDt1VF8dHOopPO4IABFc3SXYL5WE/+PTz/FCdZRRfIujiWW3n3aMbv1eIGVRWA== dependencies: "@types/node" "*" @@ -2660,11 +3424,6 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== -"@types/expect@^1.20.4": - version "1.20.4" - resolved "https://registry.yarnpkg.com/@types/expect/-/expect-1.20.4.tgz#8288e51737bf7e3ab5d7c77bfa695883745264e5" - integrity sha512-Q5Vn3yjTDyCMV50TB6VRIbQNxSE4OmZR86VSbGaNpfUolm0iePBB4KdEEHmxoY5sT2+2DIvXW0rvMDP2nHZ4Mg== - "@types/graceful-fs@^4.1.3": version "4.1.5" resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" @@ -2672,7 +3431,7 @@ dependencies: "@types/node" "*" -"@types/http-cache-semantics@*": +"@types/http-cache-semantics@^4.0.2": version "4.0.4" resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz#b979ebad3919799c979b17c72621c0bc0a31c6c4" integrity sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA== @@ -2708,14 +3467,6 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/jest@29.5.8": - version "29.5.8" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.8.tgz#ed5c256fe2bc7c38b1915ee5ef1ff24a3427e120" - integrity sha512-fXEFTxMV2Co8ZF5aYFJv+YeA08RTYJfhtN5c9JSv/mFEMe+xxjufCb+PHL+bJcMs/ebPUsBu+UNTEz+ydXrR6g== - dependencies: - expect "^29.0.0" - pretty-format "^29.0.0" - "@types/json-schema@^7.0.12": version "7.0.13" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.13.tgz#02c24f4363176d2d18fc8b70b9f3c54aba178a85" @@ -2738,13 +3489,6 @@ dependencies: "@types/node" "*" -"@types/keyv@^3.1.4": - version "3.1.4" - resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.4.tgz#3ccdb1c6751b0c7e52300bcdacd5bcbf8faa75b6" - integrity sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg== - dependencies: - "@types/node" "*" - "@types/leveldown@4.0.2": version "4.0.2" resolved "https://registry.yarnpkg.com/@types/leveldown/-/leveldown-4.0.2.tgz#edb44a33668ae58656721bb1852345e6a2f2e42a" @@ -2761,11 +3505,6 @@ "@types/abstract-leveldown" "*" "@types/node" "*" -"@types/lodash@*": - version "4.14.177" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.177.tgz#f70c0d19c30fab101cad46b52be60363c43c4578" - integrity sha512-0fDwydE2clKe9MNfvXHBHF9WEahRuj+msTuQqOmAApNORFvhMYZKNGGJdCzuhheVjMps/ti0Ak/iJPACMaevvw== - "@types/lodash@4.14.170": version "4.14.170" resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.170.tgz#0d67711d4bf7f4ca5147e9091b847479b87925d6" @@ -2795,6 +3534,13 @@ dependencies: "@types/node" "*" +"@types/mute-stream@^0.0.4": + version "0.0.4" + resolved "https://registry.yarnpkg.com/@types/mute-stream/-/mute-stream-0.0.4.tgz#77208e56a08767af6c5e1237be8888e2f255c478" + integrity sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow== + dependencies: + "@types/node" "*" + "@types/node-forge@1.0.2": version "1.0.2" resolved "https://registry.yarnpkg.com/@types/node-forge/-/node-forge-1.0.2.tgz#454299d3eaa846a38f8d88872a895b40a02e86dd" @@ -2812,10 +3558,12 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.63.tgz#1788fa8da838dbb5f9ea994b834278205db6ca2b" integrity sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ== -"@types/node@^15.6.1": - version "15.14.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-15.14.9.tgz#bc43c990c3c9be7281868bbc7b8fdd6e2b57adfa" - integrity sha512-qjd88DrCxupx/kJD5yQgZdcYKZKSIGBVDIBE1/LTGcNm3d2Np/jxojkdePDdfnBHJc5W7vSMpbJ1aB7p/Py69A== +"@types/node@^20.14.9": + version "20.14.10" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.14.10.tgz#a1a218290f1b6428682e3af044785e5874db469a" + integrity sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ== + dependencies: + undici-types "~5.26.4" "@types/normalize-package-data@^2.4.0": version "2.4.1" @@ -2827,13 +3575,6 @@ resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== -"@types/responselike@^1.0.0": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.3.tgz#cc29706f0a397cfe6df89debfe4bf5cea159db50" - integrity sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw== - dependencies: - "@types/node" "*" - "@types/semver@^7.3.12": version "7.3.13" resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.13.tgz#da4bfd73f49bd541d28920ab0e2bf0ee80f71c91" @@ -2844,13 +3585,6 @@ resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.2.tgz#31f6eec1ed7ec23f4f05608d3a2d381df041f564" integrity sha512-7aqorHYgdNO4DM36stTiGO3DvKoex9TQRwsJU6vMaFGyqpBA1MNZkz+PG3gaNUPpTAOYhT1WR7M1JyA3fbS9Cw== -"@types/sinon@*": - version "10.0.6" - resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-10.0.6.tgz#bc3faff5154e6ecb69b797d311b7cf0c1b523a1d" - integrity sha512-6EF+wzMWvBNeGrfP3Nx60hhx+FfwSg1JJBLAAP/IdIUq0EYkqCYf70VT3PhuhPX9eLD+Dp+lNdpb/ZeHG8Yezg== - dependencies: - "@sinonjs/fake-timers" "^7.1.0" - "@types/stack-utils@^2.0.0": version "2.0.1" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" @@ -2876,13 +3610,15 @@ resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.1.tgz#1a32969cf8f0364b3d8c8af9cc3555b7805df14f" integrity sha512-Y2mHTRAbqfFkpjldbkHGY8JIzRN6XqYRliG8/24FcHm2D2PwW24fl5xMRTVGdrb7iMrwCaIEbLWerGIkXuFWVg== -"@types/vinyl@^2.0.4": - version "2.0.6" - resolved "https://registry.yarnpkg.com/@types/vinyl/-/vinyl-2.0.6.tgz#b2d134603557a7c3d2b5d3dc23863ea2b5eb29b0" - integrity sha512-ayJ0iOCDNHnKpKTgBG6Q6JOnHTj9zFta+3j2b8Ejza0e4cvRyMn0ZoLEmbPrTHe5YYRlDYPvPWVdV4cTaRyH7g== - dependencies: - "@types/expect" "^1.20.4" - "@types/node" "*" +"@types/w3c-web-usb@^1.0.6": + version "1.0.10" + resolved "https://registry.yarnpkg.com/@types/w3c-web-usb/-/w3c-web-usb-1.0.10.tgz#cf89cccd2d93b6245e784c19afe0a9f5038d4528" + integrity sha512-CHgUI5kTc/QLMP8hODUHhge0D4vx+9UiAwIGiT0sTy/B2XpdX1U5rJt6JSISgr6ikRT7vxV9EVAFeYZqUnl1gQ== + +"@types/wrap-ansi@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz#18b97a972f94f60a679fd5c796d96421b9abb9fd" + integrity sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g== "@types/ws@8.5.4": version "8.5.4" @@ -3160,6 +3896,20 @@ dependencies: argparse "^2.0.1" +"@zondax/ledger-ironfish@0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@zondax/ledger-ironfish/-/ledger-ironfish-0.1.2.tgz#2ff93139c706734eb0d6800f743a9e0c2ae5268d" + integrity sha512-a9qnSOHxAf76pMonJBy5jI9oauR2W7WpVu/cCBs151uEW78NeSu4IMHOLGCo8KNiTPzpGwGa/7+1bpzxlQiEng== + dependencies: + "@zondax/ledger-js" "^0.2.1" + +"@zondax/ledger-js@^0.2.1": + version "0.2.2" + resolved "https://registry.yarnpkg.com/@zondax/ledger-js/-/ledger-js-0.2.2.tgz#b334cecaa372a8bfb91ae4fc5dd0d1c52411da4e" + integrity sha512-7wOUlRF2+kRaRU2KSzKb7XjPfScwEg3Cjg6NH/p+ikQLJ9eMkGC45NhSxYn8lixIIk+TgZ4yzTNOzFvF836gQw== + dependencies: + "@ledgerhq/hw-transport" "6.28.1" + JSONStream@^1.0.4: version "1.3.5" resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" @@ -3173,13 +3923,6 @@ abbrev@1: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== -abort-controller@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" - integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== - dependencies: - event-target-shim "^5.0.0" - abstract-leveldown@^7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-7.2.0.tgz#08d19d4e26fb5be426f7a57004851b39e1795a2e" @@ -3276,11 +4019,6 @@ ansi-colors@^4.1.1: resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== -ansi-escapes@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" - integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== - ansi-escapes@^4.2.1, ansi-escapes@^4.3.2: version "4.3.2" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" @@ -3293,29 +4031,19 @@ ansi-regex@^2.0.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= - ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= - -ansi-styles@^3.0.0, ansi-styles@^3.2.1: +ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== dependencies: color-convert "^1.9.0" -ansi-styles@^4.0.0, ansi-styles@^4.1.0, ansi-styles@^4.2.1, ansi-styles@^4.3.0: +ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== @@ -3327,10 +4055,10 @@ ansi-styles@^5.0.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== -ansicolors@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979" - integrity sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk= +ansis@^3.1.1, ansis@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ansis/-/ansis-3.2.0.tgz#0e050c5be94784f32ffdac4b84fccba064aeae4b" + integrity sha512-Yk3BkHH9U7oPyCN3gL5Tc7CpahG/+UFv/6UG03C311Vy9lzRmA5uoxDTpU9CO3rGHL6KzJz/pdDeXZCZ5Mu/Sg== anymatch@^3.0.3: version "3.1.2" @@ -3451,10 +4179,12 @@ assertion-error@^1.1.0: resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== -astral-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" - integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== +async-retry@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/async-retry/-/async-retry-1.3.3.tgz#0e7f36c04d8478e7a58bdbed80cedf977785f280" + integrity sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw== + dependencies: + retry "0.13.1" async@^3.2.3: version "3.2.4" @@ -3471,29 +4201,6 @@ at-least-node@^1.0.0: resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== -available-typed-arrays@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" - integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== - dependencies: - possible-typed-array-names "^1.0.0" - -aws-sdk@^2.1231.0: - version "2.1637.0" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1637.0.tgz#bcc5d7876d36b04b8f2663c101fa1eec22685c3c" - integrity sha512-oV5I/d9Bd9ktXPsHOOKaJy5R5ynN3XtxCzYn30xjTnkWmZx1QKD1BGmBGJR/DigdeNWvnuGWOSPh4KGkp6Jgag== - dependencies: - buffer "4.9.2" - events "1.1.1" - ieee754 "1.1.13" - jmespath "0.16.0" - querystring "0.2.0" - sax "1.2.1" - url "0.10.3" - util "^0.12.4" - uuid "8.0.0" - xml2js "0.6.2" - axios@1.7.2, axios@^1.0.0: version "1.7.2" resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.2.tgz#b625db8a7051fbea61c35a3cbb3a1daa7b9c7621" @@ -3568,7 +4275,7 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== -base64-js@^1.0.2, base64-js@^1.3.1: +base64-js@^1.3.1: version "1.5.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== @@ -3595,10 +4302,12 @@ bin-links@^3.0.0: rimraf "^3.0.0" write-file-atomic "^4.0.0" -binaryextensions@^4.15.0, binaryextensions@^4.16.0: - version "4.18.0" - resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-4.18.0.tgz#22aeada2d14de062c60e8ca59a504a5636a76ceb" - integrity sha512-PQu3Kyv9dM4FnwB7XGj1+HucW+ShvJzJqjuw1JkKVs1mWdwOKVcRjOi+pV9X52A0tNvrPCsPkbFFQb+wE1EAXw== +bindings@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" bl@^4.0.3, bl@^4.1.0: version "4.1.0" @@ -3626,6 +4335,11 @@ bn.js@^5.2.1: resolved "https://registry.npmmirror.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== +bowser@^2.11.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.11.0.tgz#5ca3c35757a7aa5771500c70a73a9f91ef420a8f" + integrity sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA== + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -3691,15 +4405,6 @@ buffer-map@0.0.7: resolved "https://registry.yarnpkg.com/buffer-map/-/buffer-map-0.0.7.tgz#5c2db65f7b3a723a2d9dff8e896fada3d2dc1c5d" integrity sha512-95try3p/vMRkIAAnJDaGkFhGpT/65NoeW6XelEPjAomWYR58RQtW4khn0SwKj34kZoE7uxL7w2koZSwbnszvQQ== -buffer@4.9.2: - version "4.9.2" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8" - integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg== - dependencies: - base64-js "^1.0.2" - ieee754 "^1.1.4" - isarray "^1.0.0" - buffer@6.0.3, buffer@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" @@ -3738,7 +4443,7 @@ byte-size@^7.0.0: resolved "https://registry.yarnpkg.com/byte-size/-/byte-size-7.0.1.tgz#b1daf3386de7ab9d706b941a748dbfc71130dee3" integrity sha512-crQdqyCwhokxwV1UyDzLZanhkugAgft7vt0qbbdt60C6Zf3CAiGmtUCylbtYwrU6loOUw3euGrNtW1J651ot1A== -cacache@^15.0.3, cacache@^15.0.5, cacache@^15.2.0: +cacache@^15.2.0: version "15.3.0" resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.3.0.tgz#dc85380fb2f556fe3dda4c719bfa0ec875a7f1eb" integrity sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ== @@ -3810,23 +4515,23 @@ cacache@^16.0.6, cacache@^16.1.0: tar "^6.1.11" unique-filename "^2.0.0" -cacheable-lookup@^5.0.3: - version "5.0.4" - resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005" - integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA== - -cacheable-request@^7.0.2: - version "7.0.4" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.4.tgz#7a33ebf08613178b403635be7b899d3e69bbe817" - integrity sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg== - dependencies: - clone-response "^1.0.2" - get-stream "^5.1.0" - http-cache-semantics "^4.0.0" - keyv "^4.0.0" - lowercase-keys "^2.0.0" - normalize-url "^6.0.1" - responselike "^2.0.0" +cacheable-lookup@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz#3476a8215d046e5a3202a9209dd13fec1f933a27" + integrity sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w== + +cacheable-request@^10.2.8: + version "10.2.14" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-10.2.14.tgz#eb915b665fda41b79652782df3f553449c406b9d" + integrity sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ== + dependencies: + "@types/http-cache-semantics" "^4.0.2" + get-stream "^6.0.1" + http-cache-semantics "^4.1.1" + keyv "^4.5.3" + mimic-response "^4.0.0" + normalize-url "^8.0.0" + responselike "^3.0.0" call-bind@^1.0.0, call-bind@^1.0.2: version "1.0.2" @@ -3836,22 +4541,19 @@ call-bind@^1.0.0, call-bind@^1.0.2: function-bind "^1.1.1" get-intrinsic "^1.0.2" -call-bind@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" - integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== - dependencies: - es-define-property "^1.0.0" - es-errors "^1.3.0" - function-bind "^1.1.2" - get-intrinsic "^1.2.4" - set-function-length "^1.2.1" - callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== +camel-case@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a" + integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw== + dependencies: + pascal-case "^3.1.2" + tslib "^2.0.3" + camelcase-keys@^6.2.2: version "6.2.2" resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0" @@ -3876,13 +4578,14 @@ caniuse-lite@^1.0.30001541: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001561.tgz#752f21f56f96f1b1a52e97aae98c57c562d5d9da" integrity sha512-NTt0DNoKe958Q0BE0j0c1V9jbUzhBxHIEJy7asmGrpE0yG63KTV7PLHPnK2E1O9RsQrQ081I3NLuXGS6zht3cw== -cardinal@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/cardinal/-/cardinal-2.1.1.tgz#7cc1055d822d212954d07b085dea251cc7bc5505" - integrity sha1-fMEFXYItISlU0HsIXeolHMe8VQU= +capital-case@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/capital-case/-/capital-case-1.0.4.tgz#9d130292353c9249f6b00fa5852bee38a717e669" + integrity sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A== dependencies: - ansicolors "~0.3.2" - redeyed "~2.1.0" + no-case "^3.0.4" + tslib "^2.0.3" + upper-case-first "^2.0.2" catering@^2.0.0, catering@^2.1.0: version "2.1.1" @@ -3901,7 +4604,7 @@ chai@4.2.0: pathval "^1.1.0" type-detect "^4.0.5" -chalk@4.1.2, chalk@^4, chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2: +chalk@4.1.2, chalk@^4, chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.1: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -3909,17 +4612,6 @@ chalk@4.1.2, chalk@^4, chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.1, c ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^1.0.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - chalk@^2.4.1, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -3929,6 +4621,24 @@ chalk@^2.4.1, chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" +change-case@^4: + version "4.1.2" + resolved "https://registry.yarnpkg.com/change-case/-/change-case-4.1.2.tgz#fedfc5f136045e2398c0410ee441f95704641e12" + integrity sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A== + dependencies: + camel-case "^4.1.2" + capital-case "^1.0.4" + constant-case "^3.0.4" + dot-case "^3.0.4" + header-case "^2.0.4" + no-case "^3.0.4" + param-case "^3.0.4" + pascal-case "^3.1.2" + path-case "^3.0.4" + sentence-case "^3.0.4" + snake-case "^3.0.4" + tslib "^2.0.3" + char-regex@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" @@ -3981,11 +4691,6 @@ clean-stack@^3.0.1: dependencies: escape-string-regexp "4.0.0" -cli-boxes@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143" - integrity sha1-T6kXw+WclKAEzWH47lCdplFocUM= - cli-cursor@3.1.0, cli-cursor@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" @@ -3993,37 +4698,33 @@ cli-cursor@3.1.0, cli-cursor@^3.1.0: dependencies: restore-cursor "^3.1.0" -cli-progress@3.12.0, cli-progress@^3.12.0: +cli-progress@3.12.0: version "3.12.0" resolved "https://registry.yarnpkg.com/cli-progress/-/cli-progress-3.12.0.tgz#807ee14b66bcc086258e444ad0f19e7d42577942" integrity sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A== dependencies: string-width "^4.2.3" -cli-progress@^3.10.0: - version "3.10.0" - resolved "https://registry.yarnpkg.com/cli-progress/-/cli-progress-3.10.0.tgz#63fd9d6343c598c93542fdfa3563a8b59887d78a" - integrity sha512-kLORQrhYCAtUPLZxqsAt2YJGOvRdt34+O6jl5cQGb7iF3dM55FQZlTR+rQyIK9JUcO9bBMwZsTlND+3dmFU2Cw== - dependencies: - string-width "^4.2.0" - cli-spinners@2.6.1, cli-spinners@^2.5.0: version "2.6.1" resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.6.1.tgz#adc954ebe281c37a6319bfa401e6dd2488ffb70d" integrity sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g== -cli-table@^0.3.1: - version "0.3.6" - resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.6.tgz#e9d6aa859c7fe636981fd3787378c2a20bce92fc" - integrity sha512-ZkNZbnZjKERTY5NwC2SeMeLeifSPq/pubeRoTpdr3WchLlnZg6hEgvHkK5zL7KNFdd9PmHN8lxrENUwI3cE8vQ== - dependencies: - colors "1.0.3" +cli-spinners@^2.9.2: + version "2.9.2" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.2.tgz#1773a8f4b9c4d6ac31563df53b3fc1d79462fe41" + integrity sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg== cli-width@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== +cli-width@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-4.1.0.tgz#42daac41d3c254ef38ad8ac037672130173691c5" + integrity sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ== + cliui@^7.0.2: version "7.0.4" resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" @@ -4042,11 +4743,6 @@ cliui@^8.0.1: strip-ansi "^6.0.1" wrap-ansi "^7.0.0" -clone-buffer@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58" - integrity sha1-4+JbIHrE5wGvch4staFnksrD3Fg= - clone-deep@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" @@ -4056,37 +4752,11 @@ clone-deep@^4.0.1: kind-of "^6.0.2" shallow-clone "^3.0.0" -clone-response@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.3.tgz#af2032aa47816399cf5f0a1d0db902f517abb8c3" - integrity sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA== - dependencies: - mimic-response "^1.0.0" - -clone-stats@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-1.0.0.tgz#b3782dff8bb5474e18b9b6bf0fdfe782f8777680" - integrity sha1-s3gt/4u1R04Yuba/D9/ngvh3doA= - clone@^1.0.2: version "1.0.4" resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= -clone@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" - integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= - -cloneable-readable@^1.0.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/cloneable-readable/-/cloneable-readable-1.1.3.tgz#120a00cb053bfb63a222e709f9683ea2e11d8cec" - integrity sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ== - dependencies: - inherits "^2.0.1" - process-nextick-args "^2.0.0" - readable-stream "^2.3.5" - cmd-shim@^4.0.1: version "4.1.0" resolved "https://registry.yarnpkg.com/cmd-shim/-/cmd-shim-4.1.0.tgz#b3a904a6743e9fede4148c6f3800bf2a08135bdd" @@ -4146,42 +4816,21 @@ color-name@1.1.3: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= -color-name@^1.0.0, color-name@~1.1.4: +color-name@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -color-string@^1.9.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4" - integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== - dependencies: - color-name "^1.0.0" - simple-swizzle "^0.2.2" - color-support@^1.1.2, color-support@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== -color@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/color/-/color-4.2.3.tgz#d781ecb5e57224ee43ea9627560107c0e0c6463a" - integrity sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A== - dependencies: - color-convert "^2.0.1" - color-string "^1.9.0" - colors@*, colors@1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== -colors@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" - integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs= - columnify@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/columnify/-/columnify-1.6.0.tgz#6989531713c9008bb29735e61e37acf5bd553cf3" @@ -4197,21 +4846,11 @@ combined-stream@^1.0.8: dependencies: delayed-stream "~1.0.0" -commander@7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-7.1.0.tgz#f2eaecf131f10e36e07d894698226e36ae0eb5ff" - integrity sha512-pRxBna3MJe6HKnBGsDyMv8ETbptw3axEdYHoqNh7gu5oDcew8fs0xnivZGm06Ogk8zGAJ9VX+OPEr2GXEQK4dg== - common-ancestor-path@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/common-ancestor-path/-/common-ancestor-path-1.0.1.tgz#4f7d2d1394d91b7abdf51871c62f71eadb0182a7" integrity sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w== -commondir@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" - integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= - compare-func@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/compare-func/-/compare-func-2.0.0.tgz#fb65e75edbddfd2e568554e8b5b05fff7a51fcb3" @@ -4235,21 +4874,6 @@ concat-stream@^2.0.0: readable-stream "^3.0.2" typedarray "^0.0.6" -concurrently@^7.6.0: - version "7.6.0" - resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-7.6.0.tgz#531a6f5f30cf616f355a4afb8f8fcb2bba65a49a" - integrity sha512-BKtRgvcJGeZ4XttiDiNcFiRlxoAeZOseqUvyYRUp/Vtd+9p1ULmeoSqGsDA+2ivdeDFpqrJvGvmI+StKfKl5hw== - dependencies: - chalk "^4.1.0" - date-fns "^2.29.1" - lodash "^4.17.21" - rxjs "^7.0.0" - shell-quote "^1.7.3" - spawn-command "^0.0.2-1" - supports-color "^8.1.0" - tree-kill "^1.2.2" - yargs "^17.3.1" - config-chain@^1.1.12: version "1.1.13" resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4" @@ -4268,6 +4892,15 @@ console-control-strings@^1.0.0, console-control-strings@^1.1.0, console-control- resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= +constant-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/constant-case/-/constant-case-3.0.4.tgz#3b84a9aeaf4cf31ec45e6bf5de91bdfb0589faf1" + integrity sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + upper-case "^2.0.2" + content-type@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" @@ -4408,18 +5041,7 @@ cross-env@7.0.3: dependencies: cross-spawn "^7.0.1" -cross-spawn@^6.0.5: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - -cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3: +cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -4438,23 +5060,11 @@ date-fns@2.16.1: resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.16.1.tgz#05775792c3f3331da812af253e1a935851d3834b" integrity sha512-sAJVKx/FqrLYHAQeN7VpJrPhagZc9R4ImZIWYRFZaaohR3KzmuK88touwsSwSVT8Qcbd4zoDsnGfX4GFB4imyQ== -date-fns@^2.29.1: - version "2.30.0" - resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.30.0.tgz#f367e644839ff57894ec6ac480de40cae4b0f4d0" - integrity sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw== - dependencies: - "@babel/runtime" "^7.21.0" - dateformat@^3.0.0: version "3.0.3" resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== -dateformat@^4.5.0: - version "4.6.3" - resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-4.6.3.tgz#556fa6497e5217fedb78821424f8a1c22fa3f4b5" - integrity sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA== - debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: version "4.3.2" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" @@ -4566,7 +5176,7 @@ defaults@^1.0.3: dependencies: clone "^1.0.2" -defer-to-connect@^2.0.0: +defer-to-connect@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== @@ -4579,15 +5189,6 @@ deferred-leveldown@~5.3.0: abstract-leveldown "~6.2.1" inherits "^2.0.3" -define-data-property@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" - integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== - dependencies: - es-define-property "^1.0.0" - es-errors "^1.3.0" - gopd "^1.0.1" - define-lazy-prop@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" @@ -4630,6 +5231,11 @@ detect-indent@^6.0.0: resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.1.0.tgz#592485ebbbf6b3b1ab2be175c8393d04ca0d57e6" integrity sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA== +detect-indent@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-7.0.1.tgz#cbb060a12842b9c4d333f1cac4aa4da1bb66bc25" + integrity sha512-Mc7QhQ8s+cLrnUfU/Ji94vG/r8M26m8f++vyres4ZoojaRDpZ1eSIh/EpzLNwlWuvzSZ3UbDFspjFvTDXe6e/g== + detect-libc@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" @@ -4645,6 +5251,11 @@ detect-newline@^3.0.0: resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== +detect-newline@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-4.0.1.tgz#fcefdb5713e1fb8cb2839b8b6ee22e6716ab8f23" + integrity sha512-qE3Veg1YXzGHQhlA6jzebZN2qVf6NX+A7m7qlhCGG30dJixrAQhYOsJjsnBjJkCSmuOPpCk30145fr8FV0bzog== + dezalgo@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" @@ -4653,11 +5264,6 @@ dezalgo@^1.0.0: asap "^2.0.0" wrappy "1" -diff-sequences@^29.3.1: - version "29.3.1" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.3.1.tgz#104b5b95fe725932421a9c6e5b4bef84c3f2249e" - integrity sha512-hlM3QR272NXCi4pq+N4Kok4kOp6EsgOM3ZSpJI7Da3UAs+Ttsi8MRmB6trM/lhyzUxGfOgnpkHtgqm5Q/CTcfQ== - diff-sequences@^29.6.3: version "29.6.3" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" @@ -4668,11 +5274,6 @@ diff@^4.0.1: resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== -diff@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" - integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== - dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" @@ -4694,6 +5295,14 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" +dot-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" + integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + dot-prop@^5.1.0: version "5.3.0" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" @@ -4718,7 +5327,7 @@ duplexer@^0.1.1, duplexer@~0.1.1: resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== -ejs@^3.1.10, ejs@^3.1.6, ejs@^3.1.7, ejs@^3.1.8: +ejs@^3.1.10, ejs@^3.1.7: version "3.1.8" resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.8.tgz#758d32910c78047585c7ef1f92f9ee041c1c190b" integrity sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ== @@ -4790,11 +5399,6 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -error@^10.4.0: - version "10.4.0" - resolved "https://registry.yarnpkg.com/error/-/error-10.4.0.tgz#6fcf0fd64bceb1e750f8ed9a3dd880f00e46a487" - integrity sha512-YxIFEJuhgcICugOUvRx5th0UM+ActZ9sjY0QJmeVwsQdvosZ7kYzc9QqS0Da3R5iUmgU5meGIxh0xBeZpMVeLw== - es-abstract@^1.19.0, es-abstract@^1.19.1: version "1.19.1" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3" @@ -4821,18 +5425,6 @@ es-abstract@^1.19.0, es-abstract@^1.19.1: string.prototype.trimstart "^1.0.4" unbox-primitive "^1.0.1" -es-define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" - integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== - dependencies: - get-intrinsic "^1.2.4" - -es-errors@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" - integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== - es-to-primitive@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" @@ -4852,7 +5444,7 @@ escape-string-regexp@4.0.0, escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: +escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= @@ -5029,7 +5621,7 @@ espree@^9.6.0, espree@^9.6.1: acorn-jsx "^5.3.2" eslint-visitor-keys "^3.4.1" -esprima@^4.0.0, esprima@~4.0.0: +esprima@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== @@ -5083,41 +5675,16 @@ event-stream@=3.3.4: stream-combiner "~0.0.4" through "~2.3.1" -event-target-shim@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" - integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== - eventemitter3@^4.0.4: version "4.0.7" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== -events@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" - integrity sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ= - events@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== -execa@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" - integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA== - dependencies: - cross-spawn "^7.0.0" - get-stream "^5.0.0" - human-signals "^1.1.1" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.0" - onetime "^5.1.0" - signal-exit "^3.0.2" - strip-final-newline "^2.0.0" - execa@^5.0.0: version "5.1.1" resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" @@ -5143,17 +5710,6 @@ expand-template@^2.0.3: resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== -expect@^29.0.0: - version "29.3.1" - resolved "https://registry.yarnpkg.com/expect/-/expect-29.3.1.tgz#92877aad3f7deefc2e3f6430dd195b92295554a6" - integrity sha512-gGb1yTgU30Q0O/tQq+z30KBWv24ApkMgFUpvKBkyLUBL68Wv8dHdJxTBZFl/iT8K/bqDHvUYRH6IIN3rToopPA== - dependencies: - "@jest/expect-utils" "^29.3.1" - jest-get-type "^29.2.0" - jest-matcher-utils "^29.3.1" - jest-message-util "^29.3.1" - jest-util "^29.3.1" - expect@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" @@ -5171,22 +5727,8 @@ external-editor@^3.0.3: integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== dependencies: chardet "^0.7.0" - iconv-lite "^0.4.24" - tmp "^0.0.33" - -fancy-test@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/fancy-test/-/fancy-test-2.0.0.tgz#f1477ae4190820318816914aabe273c0a0dbd597" - integrity sha512-SFb2D/VX9SV+wNYXO1IIh1wyxUC1GS0mYCFJOWD1ia7MPj9yE2G8jaPkw4t/pg0Sj7/YJP56OzMY4nAuJSOugQ== - dependencies: - "@types/chai" "*" - "@types/lodash" "*" - "@types/node" "*" - "@types/sinon" "*" - lodash "^4.17.13" - mock-stdin "^1.0.0" - nock "^13.0.0" - stdout-stderr "^0.1.9" + iconv-lite "^0.4.24" + tmp "^0.0.33" fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" @@ -5220,6 +5762,17 @@ fast-glob@^3.2.9: merge2 "^1.3.0" micromatch "^4.0.4" +fast-glob@^3.3.0: + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" @@ -5244,6 +5797,13 @@ fast-url-parser@^1.1.3: dependencies: punycode "^1.3.2" +fast-xml-parser@4.2.5: + version "4.2.5" + resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz#a6747a09296a6cb34f2ae634019bf1738f3b421f" + integrity sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g== + dependencies: + strnum "^1.0.5" + fastest-levenshtein@^1.0.7: version "1.0.12" resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz#9990f7d3a88cc5a9ffd1f1745745251700d497e2" @@ -5284,6 +5844,11 @@ file-entry-cache@^6.0.1: dependencies: flat-cache "^3.0.4" +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + filelist@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.2.tgz#80202f21462d4d1c2e214119b1807c1bc0380e5b" @@ -5321,14 +5886,6 @@ find-up@^5.0.0: locate-path "^6.0.0" path-exists "^4.0.0" -find-yarn-workspace-root2@1.2.16: - version "1.2.16" - resolved "https://registry.yarnpkg.com/find-yarn-workspace-root2/-/find-yarn-workspace-root2-1.2.16.tgz#60287009dd2f324f59646bdb4b7610a6b301c2a9" - integrity sha512-hr6hb1w8ePMpPVUK39S4RlwJzi+xPLuVuG8XlwXU3KD5Yn3qgBWVfy3AzNlDhWvE1EORCE65/Qm26rFQt3VLVA== - dependencies: - micromatch "^4.0.2" - pkg-dir "^4.2.0" - find-yarn-workspace-root@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz#f47fb8d239c900eb78179aa81b66673eac88f7bd" @@ -5336,13 +5893,6 @@ find-yarn-workspace-root@^2.0.0: dependencies: micromatch "^4.0.2" -first-chunk-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-2.0.0.tgz#1bdecdb8e083c0664b91945581577a43a9f31d70" - integrity sha1-G97NuOCDwGZLkZRVgVd6Q6nzHXA= - dependencies: - readable-stream "^2.0.2" - flat-cache@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" @@ -5371,12 +5921,10 @@ follow-redirects@^1.15.6: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== -for-each@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" - integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== - dependencies: - is-callable "^1.1.3" +form-data-encoder@^2.1.2: + version "2.1.4" + resolved "https://registry.yarnpkg.com/form-data-encoder/-/form-data-encoder-2.1.4.tgz#261ea35d2a70d48d30ec7a9603130fa5515e9cd5" + integrity sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw== form-data@^4.0.0: version "4.0.0" @@ -5415,7 +5963,7 @@ fs-extra@^8.1: jsonfile "^4.0.0" universalify "^0.1.0" -fs-extra@^9.0.1, fs-extra@^9.1.0: +fs-extra@^9.1.0: version "9.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== @@ -5452,11 +6000,6 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== -function-bind@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" - integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== - gauge@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/gauge/-/gauge-3.0.2.tgz#03bf4441c044383908bcfa0656ad91803259b395" @@ -5539,17 +6082,6 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: has "^1.0.3" has-symbols "^1.0.1" -get-intrinsic@^1.1.3, get-intrinsic@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" - integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== - dependencies: - es-errors "^1.3.0" - function-bind "^1.1.2" - has-proto "^1.0.1" - has-symbols "^1.0.3" - hasown "^2.0.0" - get-package-type@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" @@ -5570,19 +6102,12 @@ get-port@^5.1.1: resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ== -get-stdin@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" - integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4= - -get-stream@^5.0.0, get-stream@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" - integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== - dependencies: - pump "^3.0.0" +get-stdin@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-9.0.0.tgz#3983ff82e03d56f1b2ea0d3e60325f39d703a575" + integrity sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA== -get-stream@^6.0.0: +get-stream@^6.0.0, get-stream@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== @@ -5595,6 +6120,11 @@ get-symbol-description@^1.0.0: call-bind "^1.0.2" get-intrinsic "^1.1.1" +git-hooks-list@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/git-hooks-list/-/git-hooks-list-3.1.0.tgz#386dc531dcc17474cf094743ff30987a3d3e70fc" + integrity sha512-LF8VeHeR7v+wAbXqfgRlTSX/1BJR9Q1vEMR8JAz1cEg6GX07+zyj3sAdDvYjj/xnlIfVuGgj4qBei1K3hKH+PA== + git-raw-commits@^2.0.8: version "2.0.10" resolved "https://registry.yarnpkg.com/git-raw-commits/-/git-raw-commits-2.0.10.tgz#e2255ed9563b1c9c3ea6bd05806410290297bbc1" @@ -5649,17 +6179,10 @@ github-from-package@0.0.0: resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" integrity sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4= -github-slugger@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/github-slugger/-/github-slugger-1.5.0.tgz#17891bbc73232051474d68bd867a34625c955f7d" - integrity sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw== - -github-username@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/github-username/-/github-username-6.0.0.tgz#d543eced7295102996cd8e4e19050ebdcbe60658" - integrity sha512-7TTrRjxblSI5l6adk9zd+cV5d6i1OrJSo3Vr9xdGqFLBQo0mz5P9eIfKCDJ7eekVGGFLbce0qbPSnktXV2BjDQ== - dependencies: - "@octokit/rest" "^18.0.6" +github-slugger@^2: + version "2.0.0" + resolved "https://registry.yarnpkg.com/github-slugger/-/github-slugger-2.0.0.tgz#52cf2f9279a21eb6c59dd385b410f0c0adda8f1a" + integrity sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw== glob-parent@^5.1.1, glob-parent@^5.1.2: version "5.1.2" @@ -5687,7 +6210,7 @@ glob@7.1.4: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.0.0, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.2.0: +glob@^7.1.3, glob@^7.1.4, glob@^7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== @@ -5722,7 +6245,7 @@ globals@^13.19.0: dependencies: type-fest "^0.20.2" -globby@^11.0.1, globby@^11.0.2, globby@^11.0.3: +globby@^11.0.2: version "11.0.4" resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== @@ -5746,40 +6269,39 @@ globby@^11.0.4, globby@^11.1.0: merge2 "^1.4.1" slash "^3.0.0" -gopd@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" - integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== - dependencies: - get-intrinsic "^1.1.3" - -got@^11: - version "11.8.6" - resolved "https://registry.yarnpkg.com/got/-/got-11.8.6.tgz#276e827ead8772eddbcfc97170590b841823233a" - integrity sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g== - dependencies: - "@sindresorhus/is" "^4.0.0" - "@szmarczak/http-timer" "^4.0.5" - "@types/cacheable-request" "^6.0.1" - "@types/responselike" "^1.0.0" - cacheable-lookup "^5.0.3" - cacheable-request "^7.0.2" +globby@^13.1.2: + version "13.2.2" + resolved "https://registry.yarnpkg.com/globby/-/globby-13.2.2.tgz#63b90b1bf68619c2135475cbd4e71e66aa090592" + integrity sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w== + dependencies: + dir-glob "^3.0.1" + fast-glob "^3.3.0" + ignore "^5.2.4" + merge2 "^1.4.1" + slash "^4.0.0" + +got@^13: + version "13.0.0" + resolved "https://registry.yarnpkg.com/got/-/got-13.0.0.tgz#a2402862cef27a5d0d1b07c0fb25d12b58175422" + integrity sha512-XfBk1CxOOScDcMr9O1yKkNaQyy865NbYs+F7dr4H0LZMVgCj2Le59k6PqbNHoL5ToeaEQUYh6c6yMfVcc6SJxA== + dependencies: + "@sindresorhus/is" "^5.2.0" + "@szmarczak/http-timer" "^5.0.1" + cacheable-lookup "^7.0.0" + cacheable-request "^10.2.8" decompress-response "^6.0.0" - http2-wrapper "^1.0.0-beta.5.2" - lowercase-keys "^2.0.0" - p-cancelable "^2.0.0" - responselike "^2.0.0" + form-data-encoder "^2.1.2" + get-stream "^6.0.1" + http2-wrapper "^2.1.10" + lowercase-keys "^3.0.0" + p-cancelable "^3.0.0" + responselike "^3.0.0" graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.6: version "4.2.8" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== -graceful-fs@^4.1.5: - version "4.2.9" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" - integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== - graceful-fs@^4.2.9: version "4.2.10" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" @@ -5790,11 +6312,6 @@ graphemer@^1.4.0: resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== -grouped-queue@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/grouped-queue/-/grouped-queue-2.0.0.tgz#a2c6713f2171e45db2c300a3a9d7c119d694dac8" - integrity sha512-/PiFUa7WIsl48dUeCvhIHnwNmAAzlI/eHoJl0vu3nsFA366JleY7Ff8EVTplZu5kO0MIdZjKTTnzItL61ahbnw== - growly@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" @@ -5817,13 +6334,6 @@ hard-rejection@^2.1.0: resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= - dependencies: - ansi-regex "^2.0.0" - has-bigints@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" @@ -5839,28 +6349,11 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-property-descriptors@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" - integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== - dependencies: - es-define-property "^1.0.0" - -has-proto@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" - integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== - has-symbols@^1.0.1, has-symbols@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== -has-symbols@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" - integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== - has-tostringtag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" @@ -5868,13 +6361,6 @@ has-tostringtag@^1.0.0: dependencies: has-symbols "^1.0.2" -has-tostringtag@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" - integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== - dependencies: - has-symbols "^1.0.3" - has-unicode@^2.0.0, has-unicode@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" @@ -5887,12 +6373,13 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" -hasown@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" - integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== +header-case@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/header-case/-/header-case-2.0.4.tgz#5a42e63b55177349cf405beb8d775acabb92c063" + integrity sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q== dependencies: - function-bind "^1.1.2" + capital-case "^1.0.4" + tslib "^2.0.3" hosted-git-info@^2.1.4: version "2.8.9" @@ -5920,12 +6407,19 @@ hosted-git-info@^5.0.0: dependencies: lru-cache "^7.5.1" +hosted-git-info@^7.0.0: + version "7.0.2" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-7.0.2.tgz#9b751acac097757667f30114607ef7b661ff4f17" + integrity sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w== + dependencies: + lru-cache "^10.0.1" + html-escaper@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== -http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.0: +http-cache-semantics@^4.1.0, http-cache-semantics@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" integrity "sha1-q+AvyymFRgvwMjvmZENuw0dqbVo= sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" @@ -5960,13 +6454,13 @@ http-proxy-agent@^5.0.0: agent-base "6" debug "4" -http2-wrapper@^1.0.0-beta.5.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d" - integrity sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg== +http2-wrapper@^2.1.10: + version "2.2.1" + resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-2.2.1.tgz#310968153dcdedb160d8b72114363ef5fce1f64a" + integrity sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ== dependencies: quick-lru "^5.1.1" - resolve-alpn "^1.0.0" + resolve-alpn "^1.2.0" https-proxy-agent@^5.0.0: version "5.0.0" @@ -5976,11 +6470,6 @@ https-proxy-agent@^5.0.0: agent-base "6" debug "4" -human-signals@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" - integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== - human-signals@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" @@ -5993,11 +6482,6 @@ humanize-ms@^1.2.1: dependencies: ms "^2.0.0" -hyperlinker@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/hyperlinker/-/hyperlinker-1.0.0.tgz#23dc9e38a206b208ee49bc2d6c8ef47027df0c0e" - integrity sha512-Ty8UblRWFEcfSuIaajM34LdPXIhbs1ajEX/BBPv24J+enSVaEVY63xQ6lTO9VRYS5LAoghIG0IDJ+p+IPzKUQQ== - iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -6012,12 +6496,7 @@ iconv-lite@^0.6.2: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" -ieee754@1.1.13: - version "1.1.13" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" - integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== - -ieee754@^1.1.13, ieee754@^1.1.4, ieee754@^1.2.1: +ieee754@^1.1.13, ieee754@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== @@ -6029,13 +6508,6 @@ ignore-walk@3.0.4: dependencies: minimatch "^3.0.4" -ignore-walk@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-4.0.1.tgz#fc840e8346cf88a3a9380c5b17933cd8f4d39fa3" - integrity sha512-rzDQLaW4jQbh2YrOFlJdCtX8qgJTehFRYiUB2r1osqTeDzV/3+Jh8fz1oAPzUThf3iku8Ds4IDqawI5d8mUiQw== - dependencies: - minimatch "^3.0.4" - ignore-walk@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-5.0.1.tgz#5f199e23e1288f518d90358d461387788a154776" @@ -6102,7 +6574,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: +inherits@2, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -6125,7 +6597,7 @@ init-package-json@^3.0.2: validate-npm-package-license "^3.0.4" validate-npm-package-name "^4.0.0" -inquirer@8.2.5, inquirer@^8.0.0, inquirer@^8.2.4: +inquirer@8.2.5, inquirer@^8.2.4: version "8.2.5" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.2.5.tgz#d8654a7542c35a9b9e069d27e2df4858784d54f8" integrity sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ== @@ -6155,11 +6627,6 @@ internal-slot@^1.0.3: has "^1.0.3" side-channel "^1.0.4" -interpret@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" - integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== - ip@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" @@ -6170,24 +6637,11 @@ ip@^2.0.0: resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da" integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ== -is-arguments@^1.0.4: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" - integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= -is-arrayish@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" - integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== - is-bigint@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" @@ -6208,11 +6662,6 @@ is-buffer@^2.0.5: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== -is-callable@^1.1.3: - version "1.2.7" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" - integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== - is-callable@^1.1.4, is-callable@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" @@ -6263,11 +6712,6 @@ is-fullwidth-code-point@^1.0.0: dependencies: number-is-nan "^1.0.0" -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= - is-fullwidth-code-point@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" @@ -6278,13 +6722,6 @@ is-generator-fn@^2.0.0: resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== -is-generator-function@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" - integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== - dependencies: - has-tostringtag "^1.0.0" - is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" @@ -6339,6 +6776,11 @@ is-plain-obj@^2.0.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== +is-plain-obj@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-4.1.0.tgz#d65025edec3657ce032fd7db63c97883eaed71f0" + integrity sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg== + is-plain-object@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" @@ -6364,13 +6806,6 @@ is-retry-allowed@^1.1.0: resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg== -is-scoped@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-scoped/-/is-scoped-2.1.0.tgz#fef0713772658bdf5bee418608267ddae6d3566d" - integrity sha512-Cv4OpPTHAK9kHYzkzCrof3VJh7H/PrG2MBUMvvJebaaUMbqhm0YAtXnvh0I3Hnj2tMZWwrRROWLSgfJrKqWmlQ== - dependencies: - scoped-regex "^2.0.0" - is-shared-array-buffer@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" @@ -6409,13 +6844,6 @@ is-text-path@^1.0.1: dependencies: text-extensions "^1.0.0" -is-typed-array@^1.1.3: - version "1.1.13" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" - integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== - dependencies: - which-typed-array "^1.1.14" - is-typedarray@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" @@ -6426,11 +6854,6 @@ is-unicode-supported@^0.1.0: resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== -is-utf8@^0.2.0, is-utf8@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" - integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= - is-weakref@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.1.tgz#842dba4ec17fa9ac9850df2d6efbc1737274f2a2" @@ -6445,21 +6868,11 @@ is-wsl@^2.2.0: dependencies: is-docker "^2.0.0" -isarray@^1.0.0, isarray@~1.0.0: +isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= -isbinaryfile@^4.0.10: - version "4.0.10" - resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.10.tgz#0c5b5e30c2557a2f06febd37b7322946aaee42b3" - integrity sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw== - -isbinaryfile@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.8.tgz#5d34b94865bd4946633ecc78a026fc76c5b11fcf" - integrity sha512-53h6XFniq77YdW+spoRrebh0mnmTxRPTlcuIArO57lmMdq4uBKFKaeTjnb92oYWrSn/LVL+LT+Hap2tFQj8V+w== - isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -6624,16 +7037,6 @@ jest-config@^29.7.0: slash "^3.0.0" strip-json-comments "^3.1.1" -jest-diff@^29.3.1: - version "29.3.1" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.3.1.tgz#d8215b72fed8f1e647aed2cae6c752a89e757527" - integrity sha512-vU8vyiO7568tmin2lA3r2DP8oRvzhvRcD4DjpXc6uGveQodyk7CKLhQlCSiwgx3g0pFaE88/KLZ0yaTWMc4Uiw== - dependencies: - chalk "^4.0.0" - diff-sequences "^29.3.1" - jest-get-type "^29.2.0" - pretty-format "^29.3.1" - jest-diff@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a" @@ -6674,11 +7077,6 @@ jest-environment-node@^29.7.0: jest-mock "^29.7.0" jest-util "^29.7.0" -jest-get-type@^29.2.0: - version "29.2.0" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.2.0.tgz#726646f927ef61d583a3b3adb1ab13f3a5036408" - integrity sha512-uXNJlg8hKFEnDgFsrCjznB+sTxdkuqiCL6zMgA75qEbAJjJYTs9XPrvDctrEig2GDow22T/LvHgO57iJhXB/UA== - jest-get-type@^29.6.3: version "29.6.3" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" @@ -6753,16 +7151,6 @@ jest-leak-detector@^29.7.0: jest-get-type "^29.6.3" pretty-format "^29.7.0" -jest-matcher-utils@^29.3.1: - version "29.3.1" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.3.1.tgz#6e7f53512f80e817dfa148672bd2d5d04914a572" - integrity sha512-fkRMZUAScup3txIKfMe3AIZZmPEjWEdsPJFK3AIy5qRohWqQFg1qrmKfYXR9qEkNc7OdAu2N4KPHibEmy4HPeQ== - dependencies: - chalk "^4.0.0" - jest-diff "^29.3.1" - jest-get-type "^29.2.0" - pretty-format "^29.3.1" - jest-matcher-utils@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12" @@ -7011,17 +7399,12 @@ jest@29.7.0: import-local "^3.0.2" jest-cli "^29.7.0" -jmespath@0.16.0: - version "0.16.0" - resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.16.0.tgz#b15b0a85dfd4d930d43e69ed605943c802785076" - integrity sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw== - js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-yaml@3.14.1, js-yaml@^3.10.0, js-yaml@^3.13.0, js-yaml@^3.13.1, js-yaml@^3.14.1: +js-yaml@3.14.1, js-yaml@^3.10.0, js-yaml@^3.13.1: version "3.14.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== @@ -7141,7 +7524,7 @@ keccak@3.0.4: node-gyp-build "^4.2.0" readable-stream "^3.6.0" -keyv@^4.0.0: +keyv@^4.5.3: version "4.5.4" resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== @@ -7283,6 +7666,11 @@ libnpmpublish@^6.0.4: semver "^7.3.7" ssri "^9.0.0" +lilconfig@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.2.tgz#e4a7c3cb549e3a606c8dcc32e5ae1005e62c05cb" + integrity sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow== + lines-and-columns@^1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" @@ -7313,16 +7701,6 @@ load-json-file@^6.2.0: strip-bom "^4.0.0" type-fest "^0.6.0" -load-yaml-file@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/load-yaml-file/-/load-yaml-file-0.2.0.tgz#af854edaf2bea89346c07549122753c07372f64d" - integrity sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw== - dependencies: - graceful-fs "^4.1.5" - js-yaml "^3.13.0" - pify "^4.0.1" - strip-bom "^3.0.0" - locate-path@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" @@ -7350,11 +7728,6 @@ lodash-es@^4.17.11: resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== -lodash._reinterpolate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" - integrity sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA== - lodash.escaperegexp@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz#64762c48618082518ac3df4ccf5d5886dae20347" @@ -7400,32 +7773,12 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== -lodash.set@^4.3.2: - version "4.3.2" - resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23" - integrity sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM= - -lodash.template@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" - integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A== - dependencies: - lodash._reinterpolate "^3.0.0" - lodash.templatesettings "^4.0.0" - -lodash.templatesettings@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33" - integrity sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ== - dependencies: - lodash._reinterpolate "^3.0.0" - -lodash@4.17.21, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.15, lodash@^4.17.21: +lodash@4.17.21, lodash@^4.17.15, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -log-symbols@^4.0.0, log-symbols@^4.1.0: +log-symbols@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== @@ -7433,10 +7786,22 @@ log-symbols@^4.0.0, log-symbols@^4.1.0: chalk "^4.1.0" is-unicode-supported "^0.1.0" -lowercase-keys@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" - integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== +lower-case@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" + integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== + dependencies: + tslib "^2.0.3" + +lowercase-keys@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-3.0.0.tgz#c5e7d442e37ead247ae9db117a9d0a467c89d4f2" + integrity sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ== + +lru-cache@^10.0.1: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== lru-cache@^5.1.1: version "5.1.1" @@ -7482,28 +7847,6 @@ make-error@1.x, make-error@^1.1.1: resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== -make-fetch-happen@^10.0.1: - version "10.0.6" - resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-10.0.6.tgz#671269de09cc51208413460898efb7b36adf5534" - integrity sha512-4Gfh6lV3TLXmj7qz79hBFuvVqjYSMW6v2+sxtdX4LFQU0rK3V/txRjE0DoZb7X0IF3t9f8NO3CxPSWlvdckhVA== - dependencies: - agentkeepalive "^4.2.1" - cacache "^16.0.0" - http-cache-semantics "^4.1.0" - http-proxy-agent "^5.0.0" - https-proxy-agent "^5.0.0" - is-lambda "^1.0.1" - lru-cache "^7.5.1" - minipass "^3.1.6" - minipass-collect "^1.0.2" - minipass-fetch "^2.0.3" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.4" - negotiator "^0.6.3" - promise-retry "^2.0.1" - socks-proxy-agent "^6.1.1" - ssri "^8.0.1" - make-fetch-happen@^10.0.3, make-fetch-happen@^10.0.6: version "10.2.1" resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz#f5e3835c5e9817b617f2770870d9492d28678164" @@ -7570,32 +7913,6 @@ map-stream@~0.1.0: resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194" integrity sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ= -"mem-fs-editor@^8.1.2 || ^9.0.0": - version "9.4.0" - resolved "https://registry.yarnpkg.com/mem-fs-editor/-/mem-fs-editor-9.4.0.tgz#0cc1cf61350e33c25fc364c97fb0551eb32b8c9b" - integrity sha512-HSSOLSVRrsDdui9I6i96dDtG+oAez/4EB2g4cjSrNhgNQ3M+L57/+22NuPdORSoxvOHjIg/xeOE+C0wwF91D2g== - dependencies: - binaryextensions "^4.16.0" - commondir "^1.0.1" - deep-extend "^0.6.0" - ejs "^3.1.6" - globby "^11.0.3" - isbinaryfile "^4.0.8" - minimatch "^3.0.4" - multimatch "^5.0.0" - normalize-path "^3.0.0" - textextensions "^5.13.0" - -"mem-fs@^1.2.0 || ^2.0.0": - version "2.2.1" - resolved "https://registry.yarnpkg.com/mem-fs/-/mem-fs-2.2.1.tgz#c87bc8a53fb17971b129d4bcd59a9149fb78c5b1" - integrity sha512-yiAivd4xFOH/WXlUi6v/nKopBh1QLzwjFi36NK88cGt/PRXI8WeBASqY+YSjIVWvQTx3hR8zHKDBMV6hWmglNA== - dependencies: - "@types/node" "^15.6.1" - "@types/vinyl" "^2.0.4" - vinyl "^2.0.1" - vinyl-file "^3.0.0" - meow@^8.0.0: version "8.1.2" resolved "https://registry.yarnpkg.com/meow/-/meow-8.1.2.tgz#bcbe45bda0ee1729d350c03cffc8395a36c4e897" @@ -7648,16 +7965,16 @@ mimic-fn@^2.1.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== -mimic-response@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" - integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== - mimic-response@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== +mimic-response@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-4.0.0.tgz#35468b19e7c75d10f5165ea25e75a5ceea7cf70f" + integrity sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg== + min-indent@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" @@ -7691,10 +8008,10 @@ minimatch@^5.0.1: dependencies: brace-expansion "^2.0.1" -minimatch@^9.0.4: - version "9.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.4.tgz#8e49c731d1749cbec05050ee5145147b32496a51" - integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw== +minimatch@^9.0.5: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== dependencies: brace-expansion "^2.0.1" @@ -7707,7 +8024,7 @@ minimist-options@4.1.0: is-plain-obj "^1.1.0" kind-of "^6.0.3" -minimist@^1.1.0, minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5: +minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5: version "1.2.6" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== @@ -7724,7 +8041,7 @@ minipass-collect@^1.0.2: dependencies: minipass "^3.0.0" -minipass-fetch@^1.3.2, minipass-fetch@^1.4.1: +minipass-fetch@^1.3.2: version "1.4.1" resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-1.4.1.tgz#d75e0091daac1b0ffd7e9d41629faff7d0c1f1b6" integrity sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw== @@ -7824,11 +8141,6 @@ mkdirp@^1.0.3, mkdirp@^1.0.4: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -mock-stdin@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/mock-stdin/-/mock-stdin-1.0.0.tgz#efcfaf4b18077e14541742fd758b9cae4e5365ea" - integrity sha512-tukRdb9Beu27t6dN+XztSRHq9J0B/CoAOySGzHfn8UTfmqipA5yNT/sDUEyYdAV3Hpka6Wx6kOMxuObdOex60Q== - modify-values@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" @@ -7865,6 +8177,11 @@ mute-stream@0.0.8, mute-stream@~0.0.4: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== +mute-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-1.0.0.tgz#e31bd9fe62f0aed23520aa4324ea6671531e013e" + integrity sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA== + napi-build-utils@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806" @@ -7880,10 +8197,10 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= -natural-orderby@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/natural-orderby/-/natural-orderby-2.0.3.tgz#8623bc518ba162f8ff1cdb8941d74deb0fdcc016" - integrity sha512-p7KTHxU0CUrcOXe62Zfrb5Z13nLvPhSWR/so3kFulUQU0sgUll2Z0LwpsLN351eOOD+hRGu/F1g+6xDfPeD++Q== +natural-orderby@3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/natural-orderby/-/natural-orderby-3.0.2.tgz#1b874d685fbd68beab2c6e7d14f298e03d631ec3" + integrity sha512-x7ZdOwBxZCEm9MM7+eQCjkrNLrW3rkBKNHVr78zbtqnMGVNlnDi6C/eUEYgxHNrcbu0ymvjzcwIL/6H1iHri9g== negotiator@^0.6.2: version "0.6.2" @@ -7900,19 +8217,21 @@ neo-async@^2.6.0: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== +no-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" + integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== + dependencies: + lower-case "^2.0.2" + tslib "^2.0.3" -nock@^13.0.0: - version "13.2.1" - resolved "https://registry.yarnpkg.com/nock/-/nock-13.2.1.tgz#fcf5bdb9bb9f0554a84c25d3333166c0ffd80858" - integrity sha512-CoHAabbqq/xZEknubuyQMjq6Lfi5b7RtK6SoNK6m40lebGp3yiMagWtIoYaw2s9sISD7wPuCfwFpivVHX/35RA== +nock@13.5.4: + version "13.5.4" + resolved "https://registry.yarnpkg.com/nock/-/nock-13.5.4.tgz#8918f0addc70a63736170fef7106a9721e0dc479" + integrity sha512-yAyTfdeNJGGBFxWdzSKCBYxs5FxLbCg5X5Q4ets974hcQzG1+qCxvIyOo4j2Ry6MUlhWVMX4OoYDefAIIwupjw== dependencies: debug "^4.1.0" json-stringify-safe "^5.0.1" - lodash.set "^4.3.2" propagate "^2.0.0" node-abi@^3.3.0: @@ -7927,7 +8246,7 @@ node-addon-api@^2.0.0: resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== -node-addon-api@^3.2.1: +node-addon-api@^3.0.2, node-addon-api@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A== @@ -7937,6 +8256,11 @@ node-addon-api@^4.2.0: resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-4.3.0.tgz#52a1a0b475193e0928e98e0426a0d1254782b77f" integrity sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ== +node-addon-api@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-6.1.0.tgz#ac8470034e58e67d0c6f1204a18ae6995d9c0d76" + integrity sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA== + node-cleanup@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/node-cleanup/-/node-cleanup-2.1.2.tgz#7ac19abd297e09a7f72a71545d951b517e4dde2c" @@ -7975,7 +8299,7 @@ node-forge@1.3.1: resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== -node-gyp-build@^4.2.0: +node-gyp-build@^4.2.0, node-gyp-build@^4.5.0: version "4.8.1" resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.1.tgz#976d3ad905e71b76086f4f0b0d3637fe79b6cda5" integrity sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw== @@ -7985,7 +8309,7 @@ node-gyp-build@^4.3.0: resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.5.0.tgz#7a64eefa0b21112f89f58379da128ac177f20e40" integrity sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg== -node-gyp@8.4.1, node-gyp@8.x, node-gyp@^8.2.0: +node-gyp@8.4.1, node-gyp@8.x: version "8.4.1" resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-8.4.1.tgz#3d49308fc31f768180957d6b5746845fbd429937" integrity sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w== @@ -8017,6 +8341,15 @@ node-gyp@^9.0.0: tar "^6.1.2" which "^2.0.2" +node-hid@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/node-hid/-/node-hid-2.1.2.tgz#3145fa86ed4336a402a71e9f372c54213b88797c" + integrity sha512-qhCyQqrPpP93F/6Wc/xUR7L8mAJW0Z6R7HMQV8jCHHksAxNDe/4z4Un/H9CpLOT+5K39OPyt9tIQlavxWES3lg== + dependencies: + bindings "^1.5.0" + node-addon-api "^3.0.2" + prebuild-install "^7.1.1" + node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" @@ -8056,7 +8389,7 @@ normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" -normalize-package-data@^3.0.0, normalize-package-data@^3.0.3: +normalize-package-data@^3.0.0: version "3.0.3" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.3.tgz#dbcc3e2da59509a0983422884cd172eefdfa525e" integrity sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA== @@ -8076,15 +8409,24 @@ normalize-package-data@^4.0.0: semver "^7.3.5" validate-npm-package-license "^3.0.4" +normalize-package-data@^6: + version "6.0.2" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-6.0.2.tgz#a7bc22167fe24025412bcff0a9651eb768b03506" + integrity sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g== + dependencies: + hosted-git-info "^7.0.0" + semver "^7.3.5" + validate-npm-package-license "^3.0.4" + normalize-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== -normalize-url@^6.0.1: - version "6.1.0" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" - integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== +normalize-url@^8.0.0: + version "8.0.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-8.0.1.tgz#9b7d96af9836577c58f5883e939365fa15623a4a" + integrity sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w== npm-bundled@^1.1.1: version "1.1.2" @@ -8100,13 +8442,6 @@ npm-bundled@^2.0.0: dependencies: npm-normalize-package-bin "^2.0.0" -npm-install-checks@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/npm-install-checks/-/npm-install-checks-4.0.0.tgz#a37facc763a2fde0497ef2c6d0ac7c3fbe00d7b4" - integrity sha512-09OmyDkNLYwqKPOnbI8exiOZU2GVVmQp7tgez2BPi5OZC8M82elDAps7sxC4l//uSUtotWqoEIDwjRvWH4qz8w== - dependencies: - semver "^7.1.1" - npm-install-checks@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/npm-install-checks/-/npm-install-checks-5.0.0.tgz#5ff27d209a4e3542b8ac6b0c1db6063506248234" @@ -8133,15 +8468,6 @@ npm-package-arg@8.1.1: semver "^7.0.0" validate-npm-package-name "^3.0.0" -npm-package-arg@^8.0.1, npm-package-arg@^8.1.2, npm-package-arg@^8.1.5: - version "8.1.5" - resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-8.1.5.tgz#3369b2d5fe8fdc674baa7f1786514ddc15466e44" - integrity sha512-LhgZrg0n0VgvzVdSm1oiZworPbTxYHUJCgtsJW8mGvlDpxTM1vSJc3m5QZeUkhAHIzbz3VCHd/R4osi1L1Tg/Q== - dependencies: - hosted-git-info "^4.0.1" - semver "^7.3.4" - validate-npm-package-name "^3.0.0" - npm-package-arg@^9.0.0, npm-package-arg@^9.0.1: version "9.1.0" resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-9.1.0.tgz#a60e9f1e7c03e4e3e4e994ea87fff8b90b522987" @@ -8152,16 +8478,6 @@ npm-package-arg@^9.0.0, npm-package-arg@^9.0.1: semver "^7.3.5" validate-npm-package-name "^4.0.0" -npm-packlist@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-3.0.0.tgz#0370df5cfc2fcc8f79b8f42b37798dd9ee32c2a9" - integrity sha512-L/cbzmutAwII5glUcf2DBRNY/d0TFd4e/FnaZigJV6JD85RHZXJFGwCndjMWiiViiWSsWt3tiOLpI3ByTnIdFQ== - dependencies: - glob "^7.1.6" - ignore-walk "^4.0.1" - npm-bundled "^1.1.1" - npm-normalize-package-bin "^1.0.1" - npm-packlist@^5.1.0, npm-packlist@^5.1.1: version "5.1.3" resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-5.1.3.tgz#69d253e6fd664b9058b85005905012e00e69274b" @@ -8172,16 +8488,6 @@ npm-packlist@^5.1.0, npm-packlist@^5.1.1: npm-bundled "^2.0.0" npm-normalize-package-bin "^2.0.0" -npm-pick-manifest@^6.0.0, npm-pick-manifest@^6.1.0, npm-pick-manifest@^6.1.1: - version "6.1.1" - resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-6.1.1.tgz#7b5484ca2c908565f43b7f27644f36bb816f5148" - integrity sha512-dBsdBtORT84S8V8UTad1WlUyKIY9iMsAmqxHbLdeEeBNMLQDlDWWra3wYUx9EBEIiG/YwAy0XyNHDd2goAsfuA== - dependencies: - npm-install-checks "^4.0.0" - npm-normalize-package-bin "^1.0.1" - npm-package-arg "^8.1.2" - semver "^7.3.4" - npm-pick-manifest@^7.0.0: version "7.0.2" resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-7.0.2.tgz#1d372b4e7ea7c6712316c0e99388a73ed3496e84" @@ -8192,18 +8498,6 @@ npm-pick-manifest@^7.0.0: npm-package-arg "^9.0.0" semver "^7.3.5" -npm-registry-fetch@^12.0.0, npm-registry-fetch@^12.0.1: - version "12.0.2" - resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-12.0.2.tgz#ae583bb3c902a60dae43675b5e33b5b1f6159f1e" - integrity sha512-Df5QT3RaJnXYuOwtXBXS9BWs+tHH2olvkCLh6jcR/b/u3DvPMlp3J0TvvYwplPKxHMOwfg287PYih9QqaVFoKA== - dependencies: - make-fetch-happen "^10.0.1" - minipass "^3.1.6" - minipass-fetch "^1.4.1" - minipass-json-stream "^1.0.1" - minizlib "^2.1.2" - npm-package-arg "^8.1.5" - npm-registry-fetch@^13.0.0, npm-registry-fetch@^13.0.1, npm-registry-fetch@^13.3.0: version "13.3.1" resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-13.3.1.tgz#bb078b5fa6c52774116ae501ba1af2a33166af7e" @@ -8217,7 +8511,7 @@ npm-registry-fetch@^13.0.0, npm-registry-fetch@^13.0.1, npm-registry-fetch@^13.3 npm-package-arg "^9.0.1" proc-log "^2.0.0" -npm-run-path@^4.0.0, npm-run-path@^4.0.1: +npm-run-path@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== @@ -8325,11 +8619,6 @@ object-keys@^1.0.12, object-keys@^1.1.1: resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== -object-treeify@^1.1.33: - version "1.1.33" - resolved "https://registry.yarnpkg.com/object-treeify/-/object-treeify-1.1.33.tgz#f06fece986830a3cba78ddd32d4c11d1f76cdf40" - integrity sha512-EFVjAYfzWqWsBMRHPMAXLCDIJnpMhdWAqR7xG6M6a2cs6PMFpl/+Z20w9zDW4vkxOFfddegBKq9Rehd0bxWE7A== - object.assign@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" @@ -8349,30 +8638,35 @@ object.values@^1.1.3: define-properties "^1.1.3" es-abstract "^1.19.1" -oclif@3.7.2: - version "3.7.2" - resolved "https://registry.yarnpkg.com/oclif/-/oclif-3.7.2.tgz#52bcfc5fcdf996fc7f27a9d3729f63aa0c8225e3" - integrity sha512-mKzQQ4GFbsuqtzvN3nHYZu2SYLDX670Sa7UItTCOFNJY3S/e65Dcj+Nx/dBPMolESWjW6fIk8I8+kuGeiGVNXw== - dependencies: - "@oclif/core" "^2.7.1" - "@oclif/plugin-help" "^5.1.19" - "@oclif/plugin-not-found" "^2.3.7" - "@oclif/plugin-warn-if-update-available" "^2.0.14" - aws-sdk "^2.1231.0" - concurrently "^7.6.0" - debug "^4.3.3" +oclif@4.14.0: + version "4.14.0" + resolved "https://registry.yarnpkg.com/oclif/-/oclif-4.14.0.tgz#e13eb06c2eb3ab426bb2c5cf40d90e06f48d7155" + integrity sha512-k24YqM82RADFfQLEPEQqSjMweZjpdP9s3iQwSHk62AM8qdUyMd/4znbLxcscE+EczwIRmm+IcVOt9IrdIM/2zw== + dependencies: + "@aws-sdk/client-cloudfront" "^3.609.0" + "@aws-sdk/client-s3" "^3.609.0" + "@inquirer/confirm" "^3.1.11" + "@inquirer/input" "^2.1.9" + "@inquirer/select" "^2.3.10" + "@oclif/core" "^4" + "@oclif/plugin-help" "^6.2.2" + "@oclif/plugin-not-found" "^3.2.3" + "@oclif/plugin-warn-if-update-available" "^3.0.19" + async-retry "^1.3.3" + chalk "^4" + change-case "^4" + debug "^4.3.4" + ejs "^3.1.10" find-yarn-workspace-root "^2.0.0" fs-extra "^8.1" - github-slugger "^1.5.0" - got "^11" + github-slugger "^2" + got "^13" lodash "^4.17.21" - normalize-package-data "^3.0.3" - semver "^7.3.8" - shelljs "^0.8.5" - tslib "^2.3.1" - yeoman-environment "^3.11.1" - yeoman-generator "^5.6.1" - yosay "^2.0.2" + normalize-package-data "^6" + semver "^7.6.2" + sort-package-json "^2.10.0" + tiny-jsonc "^1.0.1" + validate-npm-package-name "^5.0.0" once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" @@ -8429,10 +8723,10 @@ os-tmpdir@~1.0.2: resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= -p-cancelable@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf" - integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg== +p-cancelable@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-3.0.0.tgz#63826694b54d61ca1c20ebcb6d3ecf5e14cd8050" + integrity sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw== p-finally@^1.0.0: version "1.0.0" @@ -8518,14 +8812,6 @@ p-timeout@^3.2.0: dependencies: p-finally "^1.0.0" -p-transform@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/p-transform/-/p-transform-1.3.0.tgz#2da960ba92c6a56efbe75cbd1edf3ea7b3191049" - integrity sha512-UJKdSzgd3KOnXXAtqN5+/eeHcvTn1hBkesEmElVgvO/NAYcxAvmjzIGmnNd3Tb/gRAvMBdNRFD4qAWdHxY6QXg== - dependencies: - debug "^4.3.2" - p-queue "^6.6.2" - p-try@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" @@ -8534,39 +8820,14 @@ p-try@^1.0.0: p-try@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== - -p-waterfall@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/p-waterfall/-/p-waterfall-2.1.1.tgz#63153a774f472ccdc4eb281cdb2967fcf158b2ee" - integrity sha512-RRTnDb2TBG/epPRI2yYXsimO0v3BXC8Yd3ogr1545IaqKK17VGhbWVeGGN+XfCm/08OK8635nH31c8bATkHuSw== - dependencies: - p-reduce "^2.0.0" - -pacote@^12.0.0, pacote@^12.0.2: - version "12.0.3" - resolved "https://registry.yarnpkg.com/pacote/-/pacote-12.0.3.tgz#b6f25868deb810e7e0ddf001be88da2bcaca57c7" - integrity sha512-CdYEl03JDrRO3x18uHjBYA9TyoW8gy+ThVcypcDkxPtKlw76e4ejhYB6i9lJ+/cebbjpqPW/CijjqxwDTts8Ow== - dependencies: - "@npmcli/git" "^2.1.0" - "@npmcli/installed-package-contents" "^1.0.6" - "@npmcli/promise-spawn" "^1.2.0" - "@npmcli/run-script" "^2.0.0" - cacache "^15.0.5" - chownr "^2.0.0" - fs-minipass "^2.1.0" - infer-owner "^1.0.4" - minipass "^3.1.3" - mkdirp "^1.0.3" - npm-package-arg "^8.0.1" - npm-packlist "^3.0.0" - npm-pick-manifest "^6.0.0" - npm-registry-fetch "^12.0.0" - promise-retry "^2.0.1" - read-package-json-fast "^2.0.1" - rimraf "^3.0.2" - ssri "^8.0.1" - tar "^6.1.0" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +p-waterfall@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/p-waterfall/-/p-waterfall-2.1.1.tgz#63153a774f472ccdc4eb281cdb2967fcf158b2ee" + integrity sha512-RRTnDb2TBG/epPRI2yYXsimO0v3BXC8Yd3ogr1545IaqKK17VGhbWVeGGN+XfCm/08OK8635nH31c8bATkHuSw== + dependencies: + p-reduce "^2.0.0" pacote@^13.0.3, pacote@^13.6.1: version "13.6.2" @@ -8595,10 +8856,13 @@ pacote@^13.0.3, pacote@^13.6.1: ssri "^9.0.0" tar "^6.1.11" -pad-component@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/pad-component/-/pad-component-0.0.1.tgz#ad1f22ce1bf0fdc0d6ddd908af17f351a404b8ac" - integrity sha1-rR8izhvw/cDW3dkIrxfzUaQEuKw= +param-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5" + integrity sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A== + dependencies: + dot-case "^3.0.4" + tslib "^2.0.3" parent-module@^1.0.0: version "1.0.1" @@ -8648,21 +8912,21 @@ parse-url@^8.1.0: dependencies: parse-path "^7.0.0" -password-prompt@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/password-prompt/-/password-prompt-1.1.2.tgz#85b2f93896c5bd9e9f2d6ff0627fa5af3dc00923" - integrity sha512-bpuBhROdrhuN3E7G/koAju0WjVw9/uQOG5Co5mokNj0MiOSBVZS1JTwM4zl55hu0WFmIEFvO9cU9sJQiBIYeIA== +pascal-case@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb" + integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g== dependencies: - ansi-escapes "^3.1.0" - cross-spawn "^6.0.5" + no-case "^3.0.4" + tslib "^2.0.3" -password-prompt@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/password-prompt/-/password-prompt-1.1.3.tgz#05e539f4e7ca4d6c865d479313f10eb9db63ee5f" - integrity sha512-HkrjG2aJlvF0t2BMH0e2LB/EHf3Lcq3fNMzy4GYHcQblAvOl+QQji1Lx7WRBMqpVK8p+KR7bCg7oqAMXtdgqyw== +path-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/path-case/-/path-case-3.0.4.tgz#9168645334eb942658375c56f80b4c0cb5f82c6f" + integrity sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg== dependencies: - ansi-escapes "^4.3.2" - cross-spawn "^7.0.3" + dot-case "^3.0.4" + tslib "^2.0.3" path-exists@^3.0.0: version "3.0.0" @@ -8679,11 +8943,6 @@ path-is-absolute@^1.0.0: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= -path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= - path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" @@ -8774,11 +9033,6 @@ pkg-up@^2.0.0: dependencies: find-up "^2.1.0" -possible-typed-array-names@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" - integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== - prebuild-install@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.0.1.tgz#c10075727c318efe72412f333e0ef625beaf3870" @@ -8798,15 +9052,23 @@ prebuild-install@^7.0.1: tar-fs "^2.0.0" tunnel-agent "^0.6.0" -preferred-pm@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/preferred-pm/-/preferred-pm-3.0.3.tgz#1b6338000371e3edbce52ef2e4f65eb2e73586d6" - integrity sha512-+wZgbxNES/KlJs9q40F/1sfOd/j7f1O9JaHcW5Dsn3aUUOZg3L2bjpVUcKV2jvtElYfoTuQiNeMfQJ4kwUAhCQ== +prebuild-install@^7.1.1: + version "7.1.2" + resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.1.2.tgz#a5fd9986f5a6251fbc47e1e5c65de71e68c0a056" + integrity sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ== dependencies: - find-up "^5.0.0" - find-yarn-workspace-root2 "1.2.16" - path-exists "^4.0.0" - which-pm "2.0.0" + detect-libc "^2.0.0" + expand-template "^2.0.3" + github-from-package "0.0.0" + minimist "^1.2.3" + mkdirp-classic "^0.5.3" + napi-build-utils "^1.0.1" + node-abi "^3.3.0" + pump "^3.0.0" + rc "^1.2.7" + simple-get "^4.0.0" + tar-fs "^2.0.0" + tunnel-agent "^0.6.0" prelude-ls@^1.2.1: version "1.2.1" @@ -8825,12 +9087,7 @@ prettier@2.3.2: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.2.tgz#ef280a05ec253712e486233db5c6f23441e7342d" integrity sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ== -pretty-bytes@^5.3.0: - version "5.6.0" - resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb" - integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg== - -pretty-format@^29.0.0, pretty-format@^29.3.1: +pretty-format@^29.3.1: version "29.3.1" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.3.1.tgz#1841cac822b02b4da8971dacb03e8a871b4722da" integrity sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg== @@ -8848,26 +9105,16 @@ pretty-format@^29.7.0: ansi-styles "^5.0.0" react-is "^18.0.0" -proc-log@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-1.0.0.tgz#0d927307401f69ed79341e83a0b2c9a13395eb77" - integrity sha512-aCk8AO51s+4JyuYGg3Q/a6gnrlDO09NpVWePtjp7xwphcoQ04x5WAfCyugcsbLooWcMJ87CLkD4+604IckEdhg== - proc-log@^2.0.0, proc-log@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-2.0.1.tgz#8f3f69a1f608de27878f91f5c688b225391cb685" integrity sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw== -process-nextick-args@^2.0.0, process-nextick-args@~2.0.0: +process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== -process@^0.11.10: - version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== - promise-all-reject-late@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz#f8ebf13483e5ca91ad809ccc2fcf25f26f8643c2" @@ -8951,11 +9198,6 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" -punycode@1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" - integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= - punycode@^1.3.2: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" @@ -8976,11 +9218,6 @@ q@^1.5.1: resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= -querystring@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" - integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= - queue-microtask@^1.2.2, queue-microtask@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" @@ -9021,7 +9258,7 @@ read-cmd-shim@^3.0.0: resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-3.0.1.tgz#868c235ec59d1de2db69e11aec885bc095aea087" integrity sha512-kEmDUoYf/CDy8yZbLTmhB1X9kkjf9Q80PCNsDMb7ufrGd6zZSQA1+UyjrO+pZm5K/S4OXCWJeiIt1JA8kAsa6g== -read-package-json-fast@^2.0.1, read-package-json-fast@^2.0.2, read-package-json-fast@^2.0.3: +read-package-json-fast@^2.0.2, read-package-json-fast@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz#323ca529630da82cb34b36cc0b996693c98c2b83" integrity sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ== @@ -9091,7 +9328,7 @@ readable-stream@3, readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stre string_decoder "^1.1.1" util-deprecate "^1.0.1" -readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.3.5, readable-stream@~2.3.6: +readable-stream@^2.0.6, readable-stream@~2.3.6: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -9104,17 +9341,6 @@ readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.3.5, readable string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^4.3.0: - version "4.5.2" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-4.5.2.tgz#9e7fc4c45099baeed934bff6eb97ba6cf2729e09" - integrity sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g== - dependencies: - abort-controller "^3.0.0" - buffer "^6.0.3" - events "^3.3.0" - process "^0.11.10" - string_decoder "^1.3.0" - readdir-scoped-modules@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz#8d45407b4f870a0dcaebc0e28670d18e74514309" @@ -9125,13 +9351,6 @@ readdir-scoped-modules@^1.1.0: graceful-fs "^4.1.2" once "^1.3.0" -rechoir@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" - integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= - dependencies: - resolve "^1.1.6" - redent@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" @@ -9140,34 +9359,17 @@ redent@^3.0.0: indent-string "^4.0.0" strip-indent "^3.0.0" -redeyed@~2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/redeyed/-/redeyed-2.1.1.tgz#8984b5815d99cb220469c99eeeffe38913e6cc0b" - integrity sha1-iYS1gV2ZyyIEacme7v/jiRPmzAs= - dependencies: - esprima "~4.0.0" - regenerator-runtime@^0.14.0: version "0.14.0" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz#5e19d68eb12d486f797e15a3c6a918f7cec5eb45" integrity sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA== -remove-trailing-separator@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= - -replace-ext@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.1.tgz#2d6d996d04a15855d967443631dd5f77825b016a" - integrity sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw== - require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= -resolve-alpn@^1.0.0: +resolve-alpn@^1.2.0: version "1.2.1" resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9" integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g== @@ -9194,7 +9396,7 @@ resolve.exports@^2.0.0: resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== -resolve@^1.1.6, resolve@^1.10.0, resolve@^1.20.0: +resolve@^1.10.0, resolve@^1.20.0: version "1.20.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== @@ -9202,12 +9404,12 @@ resolve@^1.1.6, resolve@^1.10.0, resolve@^1.20.0: is-core-module "^2.2.0" path-parse "^1.0.6" -responselike@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.1.tgz#9a0bc8fdc252f3fb1cca68b016591059ba1422bc" - integrity sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw== +responselike@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-3.0.0.tgz#20decb6c298aff0dbee1c355ca95461d42823626" + integrity sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg== dependencies: - lowercase-keys "^2.0.0" + lowercase-keys "^3.0.0" restore-cursor@^3.1.0: version "3.1.0" @@ -9217,6 +9419,11 @@ restore-cursor@^3.1.0: onetime "^5.1.0" signal-exit "^3.0.2" +retry@0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" + integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== + retry@^0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" @@ -9259,7 +9466,7 @@ rollup@^4.14.1: "@rollup/rollup-win32-x64-msvc" "4.17.2" fsevents "~2.3.2" -run-async@^2.0.0, run-async@^2.4.0: +run-async@^2.4.0: version "2.4.1" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== @@ -9271,13 +9478,6 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -rxjs@^7.0.0: - version "7.8.1" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" - integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== - dependencies: - tslib "^2.1.0" - rxjs@^7.5.5: version "7.5.5" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.5.tgz#2ebad89af0f560f460ad5cc4213219e1f7dd4e9f" @@ -9285,6 +9485,13 @@ rxjs@^7.5.5: dependencies: tslib "^2.1.0" +rxjs@^7.8.1: + version "7.8.1" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" + integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== + dependencies: + tslib "^2.1.0" + safe-buffer@^5.0.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" @@ -9300,22 +9507,7 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sax@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" - integrity sha1-e45lYZCyKOgaZq6nSEgNgozS03o= - -sax@>=0.6.0: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== - -scoped-regex@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/scoped-regex/-/scoped-regex-2.1.0.tgz#7b9be845d81fd9d21d1ec97c61a0b7cf86d2015f" - integrity sha512-g3WxHrqSWCZHGHlSrF51VXFdjImhwvH8ZO/pryFH56Qi0cDsZfylQa/t0jCzVQFNbNvM00HfHjkDPEuarKDSWQ== - -"semver@2 || 3 || 4 || 5", "semver@>= 5 < 6", semver@^5.5.0, semver@^5.6.0: +"semver@2 || 3 || 4 || 5", "semver@>= 5 < 6", semver@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -9344,18 +9536,13 @@ semver@^7.0.0, semver@^7.3.7: dependencies: lru-cache "^6.0.0" -semver@^7.1.1, semver@^7.1.3, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5: +semver@^7.1.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5: version "7.3.5" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== dependencies: lru-cache "^6.0.0" -semver@^7.3.8: - version "7.6.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13" - integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== - semver@^7.5.3: version "7.5.3" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.3.tgz#161ce8c2c6b4b3bdca6caadc9fa3317a4c4fe88e" @@ -9370,23 +9557,25 @@ semver@^7.5.4: dependencies: lru-cache "^6.0.0" +semver@^7.6.0, semver@^7.6.2: + version "7.6.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13" + integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== + +sentence-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/sentence-case/-/sentence-case-3.0.4.tgz#3645a7b8c117c787fde8702056225bb62a45131f" + integrity sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + upper-case-first "^2.0.2" + set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= -set-function-length@^1.2.1: - version "1.2.2" - resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" - integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== - dependencies: - define-data-property "^1.1.4" - es-errors "^1.3.0" - function-bind "^1.1.2" - get-intrinsic "^1.2.4" - gopd "^1.0.1" - has-property-descriptors "^1.0.2" - shallow-clone@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" @@ -9394,13 +9583,6 @@ shallow-clone@^3.0.0: dependencies: kind-of "^6.0.2" -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= - dependencies: - shebang-regex "^1.0.0" - shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -9408,30 +9590,11 @@ shebang-command@^2.0.0: dependencies: shebang-regex "^3.0.0" -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= - shebang-regex@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -shell-quote@^1.7.3: - version "1.8.1" - resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680" - integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== - -shelljs@^0.8.5: - version "0.8.5" - resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.5.tgz#de055408d8361bed66c669d2f000538ced8ee20c" - integrity sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow== - dependencies: - glob "^7.0.0" - interpret "^1.0.0" - rechoir "^0.6.2" - shellwords@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" @@ -9456,6 +9619,11 @@ signal-exit@^3.0.7: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== +signal-exit@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + simple-concat@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" @@ -9470,13 +9638,6 @@ simple-get@^4.0.0: once "^1.3.1" simple-concat "^1.0.0" -simple-swizzle@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" - integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg== - dependencies: - is-arrayish "^0.3.1" - sisteransi@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" @@ -9487,20 +9648,24 @@ slash@^3.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== -slice-ansi@^4.0.0: +slash@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" - integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== - dependencies: - ansi-styles "^4.0.0" - astral-regex "^2.0.0" - is-fullwidth-code-point "^3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-4.0.0.tgz#2422372176c4c6c5addb5e2ada885af984b396a7" + integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew== smart-buffer@^4.1.0, smart-buffer@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== +snake-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-3.0.4.tgz#4f2bbd568e9935abdfd593f34c691dadb49c452c" + integrity sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg== + dependencies: + dot-case "^3.0.4" + tslib "^2.0.3" + socks-proxy-agent@^6.0.0: version "6.1.0" resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-6.1.0.tgz#869cf2d7bd10fea96c7ad3111e81726855e285c3" @@ -9510,15 +9675,6 @@ socks-proxy-agent@^6.0.0: debug "^4.3.1" socks "^2.6.1" -socks-proxy-agent@^6.1.1: - version "6.1.1" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-6.1.1.tgz#e664e8f1aaf4e1fb3df945f09e3d94f911137f87" - integrity sha512-t8J0kG3csjA4g6FTbsMOWws+7R7vuRC8aQ/wy3/1OWmsgwA68zs/+cExQ0koSitUDXqhufF/YJr9wtNMZHw5Ew== - dependencies: - agent-base "^6.0.2" - debug "^4.3.1" - socks "^2.6.1" - socks-proxy-agent@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz#dc069ecf34436621acb41e3efa66ca1b5fed15b6" @@ -9551,13 +9707,32 @@ sort-keys@^2.0.0: dependencies: is-plain-obj "^1.0.0" -sort-keys@^4.0.0, sort-keys@^4.2.0: +sort-keys@^4.0.0: version "4.2.0" resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-4.2.0.tgz#6b7638cee42c506fff8c1cecde7376d21315be18" integrity sha512-aUYIEU/UviqPgc8mHR6IW1EGxkAXpeRETYcrzg8cLAvUPZcpAlleSXHV2mY7G12GphSH6Gzv+4MMVSSkbdteHg== dependencies: is-plain-obj "^2.0.0" +sort-object-keys@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/sort-object-keys/-/sort-object-keys-1.1.3.tgz#bff833fe85cab147b34742e45863453c1e190b45" + integrity sha512-855pvK+VkU7PaKYPc+Jjnmt4EzejQHyhhF33q31qG8x7maDzkeFhAAThdCYay11CISO+qAMwjOBP+fPZe0IPyg== + +sort-package-json@^2.10.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/sort-package-json/-/sort-package-json-2.10.0.tgz#6be07424bf3b7db9fbb1bdd69e7945f301026d8a" + integrity sha512-MYecfvObMwJjjJskhxYfuOADkXp1ZMMnCFC8yhp+9HDsk7HhR336hd7eiBs96lTXfiqmUNI+WQCeCMRBhl251g== + dependencies: + detect-indent "^7.0.1" + detect-newline "^4.0.0" + get-stdin "^9.0.0" + git-hooks-list "^3.0.0" + globby "^13.1.2" + is-plain-obj "^4.1.0" + semver "^7.6.0" + sort-object-keys "^1.1.3" + source-map-support@0.5.13: version "0.5.13" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" @@ -9571,11 +9746,6 @@ source-map@^0.6.0, source-map@^0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -spawn-command@^0.0.2-1: - version "0.0.2-1" - resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2-1.tgz#62f5e9466981c1b796dc5929937e11c9c6921bd0" - integrity sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A= - spdx-correct@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" @@ -9665,14 +9835,6 @@ stack-utils@^2.0.3: dependencies: escape-string-regexp "^2.0.0" -stdout-stderr@^0.1.9: - version "0.1.13" - resolved "https://registry.yarnpkg.com/stdout-stderr/-/stdout-stderr-0.1.13.tgz#54e3450f3d4c54086a49c0c7f8786a44d1844b6f" - integrity sha512-Xnt9/HHHYfjZ7NeQLvuQDyL1LnbsbddgMFKCuaQKwGCdJm8LnstZIXop+uOY36UR1UXXoHXfMbC1KlVdVd2JLA== - dependencies: - debug "^4.1.1" - strip-ansi "^6.0.0" - stream-combiner@~0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14" @@ -9700,16 +9862,7 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" -string-width@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - -"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +string-width@4.2.3, "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -9718,13 +9871,14 @@ string-width@^1.0.1: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string-width@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" string.prototype.trimend@^1.0.4: version "1.0.4" @@ -9742,7 +9896,7 @@ string.prototype.trimstart@^1.0.4: call-bind "^1.0.2" define-properties "^1.1.3" -string_decoder@^1.1.1, string_decoder@^1.3.0: +string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== @@ -9763,13 +9917,6 @@ strip-ansi@^3.0.0, strip-ansi@^3.0.1: dependencies: ansi-regex "^2.0.0" -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= - dependencies: - ansi-regex "^3.0.0" - strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" @@ -9777,28 +9924,6 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" -strip-bom-buf@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-bom-buf/-/strip-bom-buf-1.0.0.tgz#1cb45aaf57530f4caf86c7f75179d2c9a51dd572" - integrity sha1-HLRar1dTD0yvhsf3UXnSyaUd1XI= - dependencies: - is-utf8 "^0.2.1" - -strip-bom-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-bom-stream/-/strip-bom-stream-2.0.0.tgz#f87db5ef2613f6968aa545abfe1ec728b6a829ca" - integrity sha1-+H217yYT9paKpUWr/h7HKLaoKco= - dependencies: - first-chunk-stream "^2.0.0" - strip-bom "^2.0.0" - -strip-bom@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" - integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= - dependencies: - is-utf8 "^0.2.0" - strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" @@ -9831,6 +9956,11 @@ strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= +strnum@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/strnum/-/strnum-1.0.5.tgz#5c4e829fe15ad4ff0d20c3db5ac97b73c9b072db" + integrity sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA== + strong-log-transformer@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz#0f5ed78d325e0421ac6f90f7f10e691d6ae3ae10" @@ -9845,11 +9975,6 @@ stubs@^3.0.0: resolved "https://registry.yarnpkg.com/stubs/-/stubs-3.0.0.tgz#e8d2ba1fa9c90570303c030b6900f7d5f89abe5b" integrity sha1-6NK6H6nJBXAwPAMLaQD31fiavls= -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= - supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -9864,14 +9989,14 @@ supports-color@^7.0.0, supports-color@^7.1.0: dependencies: has-flag "^4.0.0" -supports-color@^8.0.0, supports-color@^8.1.0, supports-color@^8.1.1: +supports-color@^8, supports-color@^8.0.0: version "8.1.1" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== dependencies: has-flag "^4.0.0" -supports-hyperlinks@2.2.0, supports-hyperlinks@^2.2.0: +supports-hyperlinks@2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" integrity sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ== @@ -9884,14 +10009,6 @@ synchronous-promise@^2.0.13: resolved "https://registry.yarnpkg.com/synchronous-promise/-/synchronous-promise-2.0.15.tgz#07ca1822b9de0001f5ff73595f3d08c4f720eb8e" integrity sha512-k8uzYIkIVwmT+TcglpdN50pS2y1BDcUnBPK9iJeGu0Pl1lOI8pD6wtzgw91Pjpe+RxtTncw32tLxs/R0yNL2Mg== -taketalk@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/taketalk/-/taketalk-1.0.0.tgz#b4d4f0deed206ae7df775b129ea2ca6de52f26dd" - integrity sha1-tNTw3u0gauffd1sSnqLKbeUvJt0= - dependencies: - get-stdin "^4.0.1" - minimist "^1.1.0" - tar-fs@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" @@ -9960,11 +10077,6 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= -textextensions@^5.12.0, textextensions@^5.13.0: - version "5.14.0" - resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-5.14.0.tgz#a6ff6aee5faaa751e6157d422c722a2bfd59eedf" - integrity sha512-4cAYwNFNYlIAHBUo7p6zw8POUvWbZor+/R0Tanv+rIhsauEyV9QSrEXL40pI+GfTQxKX8k6Tyw6CmdSDSmASrg== - through2@^2.0.0: version "2.0.5" resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" @@ -9985,6 +10097,11 @@ through@2, "through@>=2.2.7 <3", through@^2.3.4, through@^2.3.6, through@~2.3, t resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= +tiny-jsonc@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tiny-jsonc/-/tiny-jsonc-1.0.1.tgz#71de47c9d812b411e87a9f3ab4a5fe42cd8d8f9c" + integrity sha512-ik6BCxzva9DoiEfDX/li0L2cWKPPENYvixUprFdl3YPi4bZZUhDnNI9YUkacrv+uIG90dnxR5mNqaoD6UhD6Bw== + tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -10026,16 +10143,6 @@ tr46@~0.0.3: resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= -tree-kill@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" - integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== - -treeverse@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/treeverse/-/treeverse-1.0.4.tgz#a6b0ebf98a1bca6846ddc7ecbc900df08cb9cd5f" - integrity sha512-whw60l7r+8ZU8Tu/Uc2yxtc4ZTZbR/PF3u1IPNKGQ6p8EICLb3Z2lAgoqw9bqYd8IkgnsaOcLzYHFckjqNsf0g== - treeverse@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/treeverse/-/treeverse-2.0.0.tgz#036dcef04bc3fd79a9b79a68d4da03e882d8a9ca" @@ -10065,7 +10172,7 @@ ts-jest@29.1.1: semver "^7.5.3" yargs-parser "^21.0.1" -ts-node@10.9.1, ts-node@^10.9.1: +ts-node@10.9.1: version "10.9.1" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== @@ -10119,7 +10226,12 @@ tslib@^1.8.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2, tslib@^2.1.0, tslib@^2.3.1: +tslib@^2.0.3, tslib@^2.6.2: + version "2.6.3" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0" + integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ== + +tslib@^2.1.0, tslib@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== @@ -10134,16 +10246,6 @@ tslib@^2.4.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== -tslib@^2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e" - integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA== - -tslib@^2.5.0: - version "2.5.3" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.3.tgz#24944ba2d990940e6e982c4bea147aba80209913" - integrity "sha1-JJRLotmQlA5umCxL6hR6uoAgmRM= sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==" - tsutils@^3.21.0: version "3.21.0" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" @@ -10242,6 +10344,11 @@ unbox-primitive@^1.0.1: resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.6.tgz#04786a1f589dc6c09f761fc5f45b89e935136441" integrity sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A== +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + unique-filename@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" @@ -10285,11 +10392,6 @@ universalify@^2.0.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== -untildify@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" - integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== - upath@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/upath/-/upath-2.0.1.tgz#50c73dea68d6f6b990f51d279ce6081665d61a8b" @@ -10303,6 +10405,20 @@ update-browserslist-db@^1.0.13: escalade "^3.1.1" picocolors "^1.0.0" +upper-case-first@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/upper-case-first/-/upper-case-first-2.0.2.tgz#992c3273f882abd19d1e02894cc147117f844324" + integrity sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg== + dependencies: + tslib "^2.0.3" + +upper-case@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-2.0.2.tgz#d89810823faab1df1549b7d97a76f8662bae6f7a" + integrity sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg== + dependencies: + tslib "^2.0.3" + uri-js@^4.2.2: version "4.4.1" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" @@ -10310,14 +10426,6 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -url@0.10.3: - version "0.10.3" - resolved "https://registry.yarnpkg.com/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" - integrity sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ= - dependencies: - punycode "1.3.2" - querystring "0.2.0" - urlgrey@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/urlgrey/-/urlgrey-1.0.0.tgz#72d2f904482d0b602e3c7fa599343d699bbe1017" @@ -10325,32 +10433,30 @@ urlgrey@1.0.0: dependencies: fast-url-parser "^1.1.3" +usb@2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/usb/-/usb-2.9.0.tgz#8ae3b175f93bee559400bff33491eee63406b6a2" + integrity sha512-G0I/fPgfHUzWH8xo2KkDxTTFruUWfppgSFJ+bQxz/kVY2x15EQ/XDB7dqD1G432G4gBG4jYQuF3U7j/orSs5nw== + dependencies: + "@types/w3c-web-usb" "^1.0.6" + node-addon-api "^6.0.0" + node-gyp-build "^4.5.0" + util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= -util@^0.12.4: - version "0.12.5" - resolved "https://registry.yarnpkg.com/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc" - integrity sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA== - dependencies: - inherits "^2.0.3" - is-arguments "^1.0.4" - is-generator-function "^1.0.7" - is-typed-array "^1.1.3" - which-typed-array "^1.1.2" - -uuid@8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.0.0.tgz#bc6ccf91b5ff0ac07bbcdbf1c7c4e150db4dbb6c" - integrity sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw== - uuid@8.3.2, uuid@^8.0.0, uuid@^8.3.0, uuid@^8.3.2: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== +uuid@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== + v8-compile-cache-lib@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" @@ -10392,28 +10498,10 @@ validate-npm-package-name@^4.0.0: dependencies: builtins "^5.0.0" -vinyl-file@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/vinyl-file/-/vinyl-file-3.0.0.tgz#b104d9e4409ffa325faadd520642d0a3b488b365" - integrity sha1-sQTZ5ECf+jJfqt1SBkLQo7SIs2U= - dependencies: - graceful-fs "^4.1.2" - pify "^2.3.0" - strip-bom-buf "^1.0.0" - strip-bom-stream "^2.0.0" - vinyl "^2.0.1" - -vinyl@^2.0.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.2.1.tgz#23cfb8bbab5ece3803aa2c0a1eb28af7cbba1974" - integrity sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw== - dependencies: - clone "^2.1.1" - clone-buffer "^1.0.0" - clone-stats "^1.0.0" - cloneable-readable "^1.0.0" - remove-trailing-separator "^1.0.1" - replace-ext "^1.0.0" +validate-npm-package-name@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz#a316573e9b49f3ccd90dbb6eb52b3f06c6d604e8" + integrity sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ== walk-up-path@^1.0.0: version "1.0.0" @@ -10458,32 +10546,6 @@ which-boxed-primitive@^1.0.2: is-string "^1.0.5" is-symbol "^1.0.3" -which-pm@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/which-pm/-/which-pm-2.0.0.tgz#8245609ecfe64bf751d0eef2f376d83bf1ddb7ae" - integrity sha512-Lhs9Pmyph0p5n5Z3mVnN0yWcbQYUAD7rbQUiMsQxOJ3T57k7RFe35SUwWMf7dsbDZks1uOmw4AecB/JMDj3v/w== - dependencies: - load-yaml-file "^0.2.0" - path-exists "^4.0.0" - -which-typed-array@^1.1.14, which-typed-array@^1.1.2: - version "1.1.15" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" - integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA== - dependencies: - available-typed-arrays "^1.0.7" - call-bind "^1.0.7" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.2" - -which@^1.2.9: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - which@^2.0.1, which@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" @@ -10510,13 +10572,14 @@ wordwrap@^1.0.0: resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= -wrap-ansi@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" - integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= +wrap-ansi@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" + integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" wrap-ansi@^7.0.0: version "7.0.0" @@ -10605,19 +10668,6 @@ ws@8.12.1: resolved "https://registry.yarnpkg.com/ws/-/ws-8.12.1.tgz#c51e583d79140b5e42e39be48c934131942d4a8f" integrity sha512-1qo+M9Ba+xNhPB+YTWUlK6M17brTut5EXbcBaMRN5pH5dFrXz7lzz1ChFSUq3bOUl8yEvSenhHmYUNJxFzdJew== -xml2js@0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.6.2.tgz#dd0b630083aa09c161e25a4d0901e2b2a929b499" - integrity sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA== - dependencies: - sax ">=0.6.0" - xmlbuilder "~11.0.0" - -xmlbuilder@~11.0.0: - version "11.0.1" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" - integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== - xtend@^4.0.2, xtend@~4.0.0, xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" @@ -10689,68 +10739,6 @@ yarn@^1.22.10: resolved "https://registry.yarnpkg.com/yarn/-/yarn-1.22.17.tgz#bf910747d22497b573131f7341c0e1d15c74036c" integrity sha512-H0p241BXaH0UN9IeH//RT82tl5PfNraVpSpEoW+ET7lmopNC61eZ+A+IDvU8FM6Go5vx162SncDL8J1ZjRBriQ== -yeoman-environment@^3.11.1: - version "3.19.3" - resolved "https://registry.yarnpkg.com/yeoman-environment/-/yeoman-environment-3.19.3.tgz#49c2339805fdf695fac42c88334a1daa94ee8b6c" - integrity sha512-/+ODrTUHtlDPRH9qIC0JREH8+7nsRcjDl3Bxn2Xo/rvAaVvixH5275jHwg0C85g4QsF4P6M2ojfScPPAl+pLAg== - dependencies: - "@npmcli/arborist" "^4.0.4" - are-we-there-yet "^2.0.0" - arrify "^2.0.1" - binaryextensions "^4.15.0" - chalk "^4.1.0" - cli-table "^0.3.1" - commander "7.1.0" - dateformat "^4.5.0" - debug "^4.1.1" - diff "^5.0.0" - error "^10.4.0" - escape-string-regexp "^4.0.0" - execa "^5.0.0" - find-up "^5.0.0" - globby "^11.0.1" - grouped-queue "^2.0.0" - inquirer "^8.0.0" - is-scoped "^2.1.0" - isbinaryfile "^4.0.10" - lodash "^4.17.10" - log-symbols "^4.0.0" - mem-fs "^1.2.0 || ^2.0.0" - mem-fs-editor "^8.1.2 || ^9.0.0" - minimatch "^3.0.4" - npmlog "^5.0.1" - p-queue "^6.6.2" - p-transform "^1.3.0" - pacote "^12.0.2" - preferred-pm "^3.0.3" - pretty-bytes "^5.3.0" - readable-stream "^4.3.0" - semver "^7.1.3" - slash "^3.0.0" - strip-ansi "^6.0.0" - text-table "^0.2.0" - textextensions "^5.12.0" - untildify "^4.0.0" - -yeoman-generator@^5.6.1: - version "5.6.1" - resolved "https://registry.yarnpkg.com/yeoman-generator/-/yeoman-generator-5.6.1.tgz#850fd266a5ab26d9d1cb9c46ad646f06eade4a1d" - integrity sha512-XllgFvmDEwoPMq2rKtL4/N52WlINJW6a3I3XtlCrMb3/dqO5dW0nPNgR0L3IIUIdf9y1EHb1ZFMs2Qp3ZEEFxg== - dependencies: - chalk "^4.1.0" - dargs "^7.0.0" - debug "^4.1.1" - execa "^4.1.0" - github-username "^6.0.0" - lodash "^4.17.11" - minimist "^1.2.5" - read-pkg-up "^7.0.1" - run-async "^2.0.0" - semver "^7.2.1" - shelljs "^0.8.5" - sort-keys "^4.2.0" - text-table "^0.2.0" - yn@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" @@ -10761,20 +10749,10 @@ yocto-queue@^0.1.0: resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== -yosay@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/yosay/-/yosay-2.0.2.tgz#a7017e764cd88d64a1ae64812201de5b157adf6d" - integrity sha512-avX6nz2esp7IMXGag4gu6OyQBsMh/SEn+ZybGu3yKPlOTE6z9qJrzG/0X5vCq/e0rPFy0CUYCze0G5hL310ibA== - dependencies: - ansi-regex "^2.0.0" - ansi-styles "^3.0.0" - chalk "^1.0.0" - cli-boxes "^1.0.0" - pad-component "0.0.1" - string-width "^2.0.0" - strip-ansi "^3.0.0" - taketalk "^1.0.0" - wrap-ansi "^2.0.0" +yoctocolors-cjs@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz#f4b905a840a37506813a7acaa28febe97767a242" + integrity sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA== yup@0.29.3: version "0.29.3"