diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 50214b0bb..e9ac31b86 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -40,6 +40,7 @@ jobs: --workspace sdk/definitions \ --workspace evm/ts \ --workspace solana \ + --workspace stacks \ --workspace sui \ --workspace sdk/route # OIDC authentication is used automatically by npm CLI 11.5.1+ diff --git a/Dockerfile.cli b/Dockerfile.cli index adf8b65c4..b457e08c0 100644 --- a/Dockerfile.cli +++ b/Dockerfile.cli @@ -48,6 +48,7 @@ COPY solana/package.json solana/package.json COPY solana/ts solana/ts COPY evm/ts evm/ts COPY solana/tsconfig.*.json solana/ +COPY stacks/ts stacks/ts COPY sui/ts sui/ts COPY cli/package.json cli/package.json COPY cli/package-lock.json cli/package-lock.json diff --git a/cli/install.sh b/cli/install.sh index f2597ef41..3764d63f4 100755 --- a/cli/install.sh +++ b/cli/install.sh @@ -143,10 +143,14 @@ function install_cli { export PATH="$tmpdir:$PATH" - # swallow the output of the first build - # TODO: figure out why it fails the first time. - bun --bun run --filter '*' build > /dev/null 2>&1 || true - bun --bun run --filter '*' build + # Build in dependency order: + # 1. definitions has no internal deps + # 2. platform-specific packages depend on definitions + # 3. route depends on platform-specific packages + # 4. cli depends on route + bun --bun run --filter '@wormhole-foundation/sdk-definitions-ntt' build + bun --bun run --filter '@wormhole-foundation/sdk-evm-ntt' --filter '@wormhole-foundation/sdk-solana-ntt' --filter '@wormhole-foundation/sdk-stacks-ntt' --filter '@wormhole-foundation/sdk-sui-ntt' build + bun --bun run --filter '@wormhole-foundation/sdk-route-ntt' build # remove the temporary directory diff --git a/cli/package.json b/cli/package.json index 2da840da5..79af17ff7 100644 --- a/cli/package.json +++ b/cli/package.json @@ -40,6 +40,12 @@ "@wormhole-foundation/sdk-solana": "^4.7.0", "@wormhole-foundation/sdk-solana-core": "^4.7.0" }, + "@wormhole-foundation/sdk-stacks-ntt": { + "@wormhole-foundation/sdk-base": "^4.7.0", + "@wormhole-foundation/sdk-definitions": "^4.7.0", + "@wormhole-foundation/sdk-stacks": "^4.7.0", + "@wormhole-foundation/sdk-stacks-core": "^4.7.0" + }, "@wormhole-foundation/sdk-sui-ntt": { "@wormhole-foundation/sdk-base": "^4.7.0", "@wormhole-foundation/sdk-definitions": "^4.7.0", diff --git a/evm/ts/README.md b/evm/ts/README.md index bce99d064..6fc94c4f7 100644 --- a/evm/ts/README.md +++ b/evm/ts/README.md @@ -1,5 +1,7 @@ ## Evm Ntt Implementation +> **Note:** These are low-level protocol classes. If you are trying to perform a transfer, use the higher-level Route abstractions such as [`NttExecutorRoute`](../../sdk/route/src/executor/executor.ts) instead. + # Building Make sure the Evm contracts are build with `npm run build:deps` and the bindings are generated with `npm run generate` diff --git a/evm/ts/src/ntt.ts b/evm/ts/src/ntt.ts index 6540b3f60..25086c39c 100644 --- a/evm/ts/src/ntt.ts +++ b/evm/ts/src/ntt.ts @@ -563,7 +563,11 @@ export class EvmNtt } // TODO: should this be some map of idx to transceiver? - async *redeem(attestations: Ntt.Attestation[]) { + async *redeem( + attestations: Ntt.Attestation[], + payer: AccountAddress, + recipient?: AccountAddress + ) { if (attestations.length !== this.xcvrs.length) throw new Error( "Not enough attestations for the registered Transceivers" @@ -648,7 +652,7 @@ export class EvmNtt async *completeInboundQueuedTransfer( fromChain: Chain, transceiverMessage: Ntt.Message, - payer?: AccountAddress + payer: AccountAddress ) { const tx = await this.manager.completeInboundQueuedTransfer.populateTransaction( diff --git a/package-lock.json b/package-lock.json index fa26cf2d9..4c3b0d5ce 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "sdk/definitions", "evm/ts", "solana", + "stacks/ts", "sui/ts", "sdk/route", "sdk/examples", @@ -27,6 +28,7 @@ "@wormhole-foundation/sdk": "^4.7.0", "@wormhole-foundation/wormchain-sdk": "^0.0.1", "ethers": "^6.5.1", + "jest": "^30.2.0", "prettier": "3.6.2", "ts-jest": "^29.1.2", "tsx": "^4.7.2", @@ -506,6 +508,8 @@ }, "node_modules/@babel/plugin-syntax-jsx": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", + "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", "dev": true, "license": "MIT", "dependencies": { @@ -2787,6 +2791,8 @@ }, "node_modules/@isaacs/cliui": { "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, "license": "ISC", "dependencies": { @@ -2833,15 +2839,17 @@ } }, "node_modules/@jest/console": { - "version": "30.1.2", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.2.0.tgz", + "integrity": "sha512-+O1ifRjkvYIkBqASKWgLxrpEhQAAE7hY77ALLUufSk5717KfOShg6IbqLmdsLMPdUiFvA2kTs0R7YZy+l0IzZQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", - "jest-message-util": "30.1.0", - "jest-util": "30.0.5", + "jest-message-util": "30.2.0", + "jest-util": "30.2.0", "slash": "^3.0.0" }, "engines": { @@ -2850,6 +2858,8 @@ }, "node_modules/@jest/console/node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { @@ -2864,6 +2874,8 @@ }, "node_modules/@jest/console/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", "dependencies": { @@ -2878,17 +2890,19 @@ } }, "node_modules/@jest/console/node_modules/jest-message-util": { - "version": "30.1.0", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", + "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/stack-utils": "^2.0.3", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "micromatch": "^4.0.8", - "pretty-format": "30.0.5", + "pretty-format": "30.2.0", "slash": "^3.0.0", "stack-utils": "^2.0.6" }, @@ -2897,11 +2911,13 @@ } }, "node_modules/@jest/console/node_modules/jest-util": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", + "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", @@ -2914,6 +2930,8 @@ }, "node_modules/@jest/console/node_modules/picomatch": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { @@ -2924,7 +2942,9 @@ } }, "node_modules/@jest/console/node_modules/pretty-format": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", + "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", "dev": true, "license": "MIT", "dependencies": { @@ -2938,6 +2958,8 @@ }, "node_modules/@jest/console/node_modules/pretty-format/node_modules/ansi-styles": { "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", "engines": { @@ -2948,37 +2970,39 @@ } }, "node_modules/@jest/core": { - "version": "30.1.3", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.2.0.tgz", + "integrity": "sha512-03W6IhuhjqTlpzh/ojut/pDB2LPRygyWX8ExpgHtQA8H/3K7+1vKmcINx5UzeOX1se6YEsBsOHQ1CRzf3fOwTQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/console": "30.1.2", + "@jest/console": "30.2.0", "@jest/pattern": "30.0.1", - "@jest/reporters": "30.1.3", - "@jest/test-result": "30.1.3", - "@jest/transform": "30.1.2", - "@jest/types": "30.0.5", + "@jest/reporters": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", "@types/node": "*", "ansi-escapes": "^4.3.2", "chalk": "^4.1.2", "ci-info": "^4.2.0", "exit-x": "^0.2.2", "graceful-fs": "^4.2.11", - "jest-changed-files": "30.0.5", - "jest-config": "30.1.3", - "jest-haste-map": "30.1.0", - "jest-message-util": "30.1.0", + "jest-changed-files": "30.2.0", + "jest-config": "30.2.0", + "jest-haste-map": "30.2.0", + "jest-message-util": "30.2.0", "jest-regex-util": "30.0.1", - "jest-resolve": "30.1.3", - "jest-resolve-dependencies": "30.1.3", - "jest-runner": "30.1.3", - "jest-runtime": "30.1.3", - "jest-snapshot": "30.1.2", - "jest-util": "30.0.5", - "jest-validate": "30.1.0", - "jest-watcher": "30.1.3", + "jest-resolve": "30.2.0", + "jest-resolve-dependencies": "30.2.0", + "jest-runner": "30.2.0", + "jest-runtime": "30.2.0", + "jest-snapshot": "30.2.0", + "jest-util": "30.2.0", + "jest-validate": "30.2.0", + "jest-watcher": "30.2.0", "micromatch": "^4.0.8", - "pretty-format": "30.0.5", + "pretty-format": "30.2.0", "slash": "^3.0.0" }, "engines": { @@ -2995,6 +3019,8 @@ }, "node_modules/@jest/core/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", "dependencies": { @@ -3010,6 +3036,8 @@ }, "node_modules/@jest/core/node_modules/chalk/node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { @@ -3023,17 +3051,19 @@ } }, "node_modules/@jest/core/node_modules/jest-message-util": { - "version": "30.1.0", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", + "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/stack-utils": "^2.0.3", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "micromatch": "^4.0.8", - "pretty-format": "30.0.5", + "pretty-format": "30.2.0", "slash": "^3.0.0", "stack-utils": "^2.0.6" }, @@ -3042,11 +3072,13 @@ } }, "node_modules/@jest/core/node_modules/jest-util": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", + "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", @@ -3059,6 +3091,8 @@ }, "node_modules/@jest/core/node_modules/picomatch": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { @@ -3069,7 +3103,9 @@ } }, "node_modules/@jest/core/node_modules/pretty-format": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", + "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", "dev": true, "license": "MIT", "dependencies": { @@ -3083,6 +3119,8 @@ }, "node_modules/@jest/diff-sequences": { "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz", + "integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==", "dev": true, "license": "MIT", "engines": { @@ -3090,26 +3128,30 @@ } }, "node_modules/@jest/environment": { - "version": "30.1.2", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.2.0.tgz", + "integrity": "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g==", "dev": true, "license": "MIT", "dependencies": { - "@jest/fake-timers": "30.1.2", - "@jest/types": "30.0.5", + "@jest/fake-timers": "30.2.0", + "@jest/types": "30.2.0", "@types/node": "*", - "jest-mock": "30.0.5" + "jest-mock": "30.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/expect": { - "version": "30.1.2", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.2.0.tgz", + "integrity": "sha512-V9yxQK5erfzx99Sf+7LbhBwNWEZ9eZay8qQ9+JSC0TrMR1pMDHLMY+BnVPacWU6Jamrh252/IKo4F1Xn/zfiqA==", "dev": true, "license": "MIT", "dependencies": { - "expect": "30.1.2", - "jest-snapshot": "30.1.2" + "expect": "30.2.0", + "jest-snapshot": "30.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -3127,7 +3169,9 @@ } }, "node_modules/@jest/expect/node_modules/@jest/expect-utils": { - "version": "30.1.2", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.2.0.tgz", + "integrity": "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==", "dev": true, "license": "MIT", "dependencies": { @@ -3139,6 +3183,8 @@ }, "node_modules/@jest/expect/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", "dependencies": { @@ -3154,6 +3200,8 @@ }, "node_modules/@jest/expect/node_modules/chalk/node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { @@ -3167,61 +3215,69 @@ } }, "node_modules/@jest/expect/node_modules/expect": { - "version": "30.1.2", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.2.0.tgz", + "integrity": "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/expect-utils": "30.1.2", + "@jest/expect-utils": "30.2.0", "@jest/get-type": "30.1.0", - "jest-matcher-utils": "30.1.2", - "jest-message-util": "30.1.0", - "jest-mock": "30.0.5", - "jest-util": "30.0.5" + "jest-matcher-utils": "30.2.0", + "jest-message-util": "30.2.0", + "jest-mock": "30.2.0", + "jest-util": "30.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/expect/node_modules/jest-diff": { - "version": "30.1.2", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", + "integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==", "dev": true, "license": "MIT", "dependencies": { "@jest/diff-sequences": "30.0.1", "@jest/get-type": "30.1.0", "chalk": "^4.1.2", - "pretty-format": "30.0.5" + "pretty-format": "30.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/expect/node_modules/jest-matcher-utils": { - "version": "30.1.2", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz", + "integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==", "dev": true, "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0", "chalk": "^4.1.2", - "jest-diff": "30.1.2", - "pretty-format": "30.0.5" + "jest-diff": "30.2.0", + "pretty-format": "30.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/@jest/expect/node_modules/jest-message-util": { - "version": "30.1.0", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", + "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/stack-utils": "^2.0.3", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "micromatch": "^4.0.8", - "pretty-format": "30.0.5", + "pretty-format": "30.2.0", "slash": "^3.0.0", "stack-utils": "^2.0.6" }, @@ -3230,11 +3286,13 @@ } }, "node_modules/@jest/expect/node_modules/jest-util": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", + "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", @@ -3247,6 +3305,8 @@ }, "node_modules/@jest/expect/node_modules/picomatch": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { @@ -3257,7 +3317,9 @@ } }, "node_modules/@jest/expect/node_modules/pretty-format": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", + "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", "dev": true, "license": "MIT", "dependencies": { @@ -3270,16 +3332,18 @@ } }, "node_modules/@jest/fake-timers": { - "version": "30.1.2", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.2.0.tgz", + "integrity": "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@sinonjs/fake-timers": "^13.0.0", "@types/node": "*", - "jest-message-util": "30.1.0", - "jest-mock": "30.0.5", - "jest-util": "30.0.5" + "jest-message-util": "30.2.0", + "jest-mock": "30.2.0", + "jest-util": "30.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -3287,6 +3351,8 @@ }, "node_modules/@jest/fake-timers/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", "dependencies": { @@ -3302,6 +3368,8 @@ }, "node_modules/@jest/fake-timers/node_modules/chalk/node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { @@ -3315,17 +3383,19 @@ } }, "node_modules/@jest/fake-timers/node_modules/jest-message-util": { - "version": "30.1.0", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", + "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/stack-utils": "^2.0.3", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "micromatch": "^4.0.8", - "pretty-format": "30.0.5", + "pretty-format": "30.2.0", "slash": "^3.0.0", "stack-utils": "^2.0.6" }, @@ -3334,11 +3404,13 @@ } }, "node_modules/@jest/fake-timers/node_modules/jest-util": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", + "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", @@ -3351,6 +3423,8 @@ }, "node_modules/@jest/fake-timers/node_modules/picomatch": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { @@ -3361,7 +3435,9 @@ } }, "node_modules/@jest/fake-timers/node_modules/pretty-format": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", + "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", "dev": true, "license": "MIT", "dependencies": { @@ -3382,14 +3458,16 @@ } }, "node_modules/@jest/globals": { - "version": "30.1.2", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.2.0.tgz", + "integrity": "sha512-b63wmnKPaK+6ZZfpYhz9K61oybvbI1aMcIs80++JI1O1rR1vaxHUCNqo3ITu6NU0d4V34yZFoHMn/uoKr/Rwfw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/environment": "30.1.2", - "@jest/expect": "30.1.2", - "@jest/types": "30.0.5", - "jest-mock": "30.0.5" + "@jest/environment": "30.2.0", + "@jest/expect": "30.2.0", + "@jest/types": "30.2.0", + "jest-mock": "30.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -3408,15 +3486,17 @@ } }, "node_modules/@jest/reporters": { - "version": "30.1.3", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.2.0.tgz", + "integrity": "sha512-DRyW6baWPqKMa9CzeiBjHwjd8XeAyco2Vt8XbcLFjiwCOEKOvy82GJ8QQnJE9ofsxCMPjH4MfH8fCWIHHDKpAQ==", "dev": true, "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "30.1.2", - "@jest/test-result": "30.1.3", - "@jest/transform": "30.1.2", - "@jest/types": "30.0.5", + "@jest/console": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", "@jridgewell/trace-mapping": "^0.3.25", "@types/node": "*", "chalk": "^4.1.2", @@ -3429,9 +3509,9 @@ "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^5.0.0", "istanbul-reports": "^3.1.3", - "jest-message-util": "30.1.0", - "jest-util": "30.0.5", - "jest-worker": "30.1.0", + "jest-message-util": "30.2.0", + "jest-util": "30.2.0", + "jest-worker": "30.2.0", "slash": "^3.0.0", "string-length": "^4.0.2", "v8-to-istanbul": "^9.0.1" @@ -3450,6 +3530,8 @@ }, "node_modules/@jest/reporters/node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { @@ -3464,6 +3546,8 @@ }, "node_modules/@jest/reporters/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", "dependencies": { @@ -3478,17 +3562,19 @@ } }, "node_modules/@jest/reporters/node_modules/jest-message-util": { - "version": "30.1.0", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", + "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/stack-utils": "^2.0.3", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "micromatch": "^4.0.8", - "pretty-format": "30.0.5", + "pretty-format": "30.2.0", "slash": "^3.0.0", "stack-utils": "^2.0.6" }, @@ -3497,11 +3583,13 @@ } }, "node_modules/@jest/reporters/node_modules/jest-util": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", + "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", @@ -3514,6 +3602,8 @@ }, "node_modules/@jest/reporters/node_modules/picomatch": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { @@ -3524,7 +3614,9 @@ } }, "node_modules/@jest/reporters/node_modules/pretty-format": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", + "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", "dev": true, "license": "MIT", "dependencies": { @@ -3538,6 +3630,8 @@ }, "node_modules/@jest/reporters/node_modules/pretty-format/node_modules/ansi-styles": { "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", "engines": { @@ -3559,11 +3653,13 @@ } }, "node_modules/@jest/snapshot-utils": { - "version": "30.1.2", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.2.0.tgz", + "integrity": "sha512-0aVxM3RH6DaiLcjj/b0KrIBZhSX1373Xci4l3cW5xiUWPctZ59zQ7jj4rqcJQ/Z8JuN/4wX3FpJSa3RssVvCug==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "natural-compare": "^1.4.0" @@ -3574,6 +3670,8 @@ }, "node_modules/@jest/snapshot-utils/node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { @@ -3588,6 +3686,8 @@ }, "node_modules/@jest/snapshot-utils/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", "dependencies": { @@ -3603,6 +3703,8 @@ }, "node_modules/@jest/source-map": { "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-30.0.1.tgz", + "integrity": "sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==", "dev": true, "license": "MIT", "dependencies": { @@ -3615,12 +3717,14 @@ } }, "node_modules/@jest/test-result": { - "version": "30.1.3", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.2.0.tgz", + "integrity": "sha512-RF+Z+0CCHkARz5HT9mcQCBulb1wgCP3FBvl9VFokMX27acKphwyQsNuWH3c+ojd1LeWBLoTYoxF0zm6S/66mjg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/console": "30.1.2", - "@jest/types": "30.0.5", + "@jest/console": "30.2.0", + "@jest/types": "30.2.0", "@types/istanbul-lib-coverage": "^2.0.6", "collect-v8-coverage": "^1.0.2" }, @@ -3629,13 +3733,15 @@ } }, "node_modules/@jest/test-sequencer": { - "version": "30.1.3", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.2.0.tgz", + "integrity": "sha512-wXKgU/lk8fKXMu/l5Hog1R61bL4q5GCdT6OJvdAFz1P+QrpoFuLU68eoKuVc4RbrTtNnTL5FByhWdLgOPSph+Q==", "dev": true, "license": "MIT", "dependencies": { - "@jest/test-result": "30.1.3", + "@jest/test-result": "30.2.0", "graceful-fs": "^4.2.11", - "jest-haste-map": "30.1.0", + "jest-haste-map": "30.2.0", "slash": "^3.0.0" }, "engines": { @@ -3643,21 +3749,23 @@ } }, "node_modules/@jest/transform": { - "version": "30.1.2", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.2.0.tgz", + "integrity": "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==", "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.27.4", - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@jridgewell/trace-mapping": "^0.3.25", - "babel-plugin-istanbul": "^7.0.0", + "babel-plugin-istanbul": "^7.0.1", "chalk": "^4.1.2", "convert-source-map": "^2.0.0", "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.11", - "jest-haste-map": "30.1.0", + "jest-haste-map": "30.2.0", "jest-regex-util": "30.0.1", - "jest-util": "30.0.5", + "jest-util": "30.2.0", "micromatch": "^4.0.8", "pirates": "^4.0.7", "slash": "^3.0.0", @@ -3669,6 +3777,8 @@ }, "node_modules/@jest/transform/node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { @@ -3683,6 +3793,8 @@ }, "node_modules/@jest/transform/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", "dependencies": { @@ -3697,11 +3809,13 @@ } }, "node_modules/@jest/transform/node_modules/jest-util": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", + "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", @@ -3714,6 +3828,8 @@ }, "node_modules/@jest/transform/node_modules/picomatch": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { @@ -3724,7 +3840,9 @@ } }, "node_modules/@jest/types": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", + "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", "dev": true, "license": "MIT", "dependencies": { @@ -3907,6 +4025,8 @@ }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, "license": "MIT", "optional": true, @@ -3916,6 +4036,8 @@ }, "node_modules/@pkgr/core": { "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", "dev": true, "license": "MIT", "engines": { @@ -4018,6 +4140,8 @@ }, "node_modules/@sinonjs/commons": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -4026,6 +4150,8 @@ }, "node_modules/@sinonjs/fake-timers": { "version": "13.0.5", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz", + "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -5348,6 +5474,7 @@ "resolved": "https://registry.npmjs.org/@wormhole-foundation/sdk-stacks/-/sdk-stacks-4.7.1.tgz", "integrity": "sha512-mGnXgo4PHGVW/lNRNWNTfAH6MLxP0byCgKlEoAxGa5rhsWiRaXjD9rk6oVKLuO/q4vGAcX1n/DrMn9T2RqHyrA==", "license": "Apache-2.0", + "peer": true, "dependencies": { "@stacks/network": "^7.0.2", "@stacks/transactions": "^7.1.0", @@ -5362,6 +5489,7 @@ "resolved": "https://registry.npmjs.org/@wormhole-foundation/sdk-stacks-core/-/sdk-stacks-core-4.7.1.tgz", "integrity": "sha512-/1od+AgQSaulAzN/dliPkOVz99Za18i79JQMA8btKvYGH2SWlD25VSa1090c1WLY5/SU6T/jSdP4uuA6J02EmA==", "license": "Apache-2.0", + "peer": true, "dependencies": { "@wormhole-foundation/sdk-connect": "4.7.1", "@wormhole-foundation/sdk-stacks": "4.7.1" @@ -5370,6 +5498,10 @@ "node": ">=16" } }, + "node_modules/@wormhole-foundation/sdk-stacks-ntt": { + "resolved": "stacks/ts", + "link": true + }, "node_modules/@wormhole-foundation/sdk-sui": { "version": "4.7.1", "resolved": "https://registry.npmjs.org/@wormhole-foundation/sdk-sui/-/sdk-sui-4.7.1.tgz", @@ -7233,14 +7365,16 @@ } }, "node_modules/babel-jest": { - "version": "30.1.2", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.2.0.tgz", + "integrity": "sha512-0YiBEOxWqKkSQWL9nNGGEgndoeL0ZpWrbLMNL5u/Kaxrli3Eaxlt3ZtIDktEvXt4L/R9r3ODr2zKwGM/2BjxVw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/transform": "30.1.2", + "@jest/transform": "30.2.0", "@types/babel__core": "^7.20.5", - "babel-plugin-istanbul": "^7.0.0", - "babel-preset-jest": "30.0.1", + "babel-plugin-istanbul": "^7.0.1", + "babel-preset-jest": "30.2.0", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "slash": "^3.0.0" @@ -7249,7 +7383,7 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" }, "peerDependencies": { - "@babel/core": "^7.11.0" + "@babel/core": "^7.11.0 || ^8.0.0-0" } }, "node_modules/babel-jest/node_modules/ansi-styles": { @@ -7300,12 +7434,12 @@ } }, "node_modules/babel-plugin-jest-hoist": { - "version": "30.0.1", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.2.0.tgz", + "integrity": "sha512-ftzhzSGMUnOzcCXd6WHdBGMyuwy15Wnn0iyyWGKgBDLxf9/s5ABuraCSpBX2uG0jUg4rqJnxsLc5+oYBqoxVaA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.27.3", "@types/babel__core": "^7.20.5" }, "engines": { @@ -7338,18 +7472,20 @@ } }, "node_modules/babel-preset-jest": { - "version": "30.0.1", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.2.0.tgz", + "integrity": "sha512-US4Z3NOieAQumwFnYdUWKvUKh8+YSnS/gB3t6YBiz0bskpu7Pine8pPCheNxlPEW4wnUkma2a94YuW2q3guvCQ==", "dev": true, "license": "MIT", "dependencies": { - "babel-plugin-jest-hoist": "30.0.1", - "babel-preset-current-node-syntax": "^1.1.0" + "babel-plugin-jest-hoist": "30.2.0", + "babel-preset-current-node-syntax": "^1.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" }, "peerDependencies": { - "@babel/core": "^7.11.0" + "@babel/core": "^7.11.0 || ^8.0.0-beta.1" } }, "node_modules/balanced-match": { @@ -7468,6 +7604,8 @@ }, "node_modules/brace-expansion": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "license": "MIT", "dependencies": { @@ -7803,12 +7941,16 @@ } }, "node_modules/cjs-module-lexer": { - "version": "2.1.0", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.1.1.tgz", + "integrity": "sha512-+CmxIZ/L2vNcEfvNtLdU0ZQ6mbq3FZnwAP2PPTiKP+1QOoKwlKlPgb8UKV0Dds7QVaMnHm+FwSft2VB0s/SLjQ==", "dev": true, "license": "MIT" }, "node_modules/cliui": { "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "license": "ISC", "dependencies": { @@ -7822,6 +7964,8 @@ }, "node_modules/cliui/node_modules/ansi-regex": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", "engines": { @@ -7830,6 +7974,8 @@ }, "node_modules/cliui/node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { @@ -7844,11 +7990,15 @@ }, "node_modules/cliui/node_modules/emoji-regex": { "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, "license": "MIT" }, "node_modules/cliui/node_modules/string-width": { "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", "dependencies": { @@ -7862,6 +8012,8 @@ }, "node_modules/cliui/node_modules/strip-ansi": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", "dependencies": { @@ -7873,6 +8025,8 @@ }, "node_modules/cliui/node_modules/wrap-ansi": { "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "license": "MIT", "dependencies": { @@ -8161,11 +8315,6 @@ "dev": true, "license": "MIT" }, - "node_modules/csstype": { - "version": "3.1.3", - "license": "MIT", - "optional": true - }, "node_modules/data-urls": { "version": "2.0.0", "dev": true, @@ -8261,6 +8410,8 @@ }, "node_modules/dedent": { "version": "1.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz", + "integrity": "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==", "dev": true, "license": "MIT", "peerDependencies": { @@ -8417,6 +8568,8 @@ }, "node_modules/eastasianwidth": { "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true, "license": "MIT" }, @@ -8444,6 +8597,8 @@ }, "node_modules/emittery": { "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", "dev": true, "license": "MIT", "engines": { @@ -8455,6 +8610,8 @@ }, "node_modules/emoji-regex": { "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true, "license": "MIT" }, @@ -8754,6 +8911,8 @@ }, "node_modules/exit-x": { "version": "0.2.2", + "resolved": "https://registry.npmjs.org/exit-x/-/exit-x-0.2.2.tgz", + "integrity": "sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==", "dev": true, "license": "MIT", "engines": { @@ -8880,6 +9039,8 @@ }, "node_modules/foreground-child": { "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", "dev": true, "license": "ISC", "dependencies": { @@ -9044,7 +9205,9 @@ } }, "node_modules/glob": { - "version": "10.4.5", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", "dev": true, "license": "ISC", "dependencies": { @@ -9635,6 +9798,8 @@ }, "node_modules/istanbul-lib-source-maps": { "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -9660,6 +9825,8 @@ }, "node_modules/jackspeak": { "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -9705,15 +9872,17 @@ "license": "MIT" }, "node_modules/jest": { - "version": "30.1.3", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-30.2.0.tgz", + "integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "@jest/core": "30.1.3", - "@jest/types": "30.0.5", + "@jest/core": "30.2.0", + "@jest/types": "30.2.0", "import-local": "^3.2.0", - "jest-cli": "30.1.3" + "jest-cli": "30.2.0" }, "bin": { "jest": "bin/jest.js" @@ -9731,12 +9900,14 @@ } }, "node_modules/jest-changed-files": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.2.0.tgz", + "integrity": "sha512-L8lR1ChrRnSdfeOvTrwZMlnWV8G/LLjQ0nG9MBclwWZidA2N5FviRki0Bvh20WRMOX31/JYvzdqTJrk5oBdydQ==", "dev": true, "license": "MIT", "dependencies": { "execa": "^5.1.1", - "jest-util": "30.0.5", + "jest-util": "30.2.0", "p-limit": "^3.1.0" }, "engines": { @@ -9745,6 +9916,8 @@ }, "node_modules/jest-changed-files/node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { @@ -9759,6 +9932,8 @@ }, "node_modules/jest-changed-files/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", "dependencies": { @@ -9773,11 +9948,13 @@ } }, "node_modules/jest-changed-files/node_modules/jest-util": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", + "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", @@ -9790,6 +9967,8 @@ }, "node_modules/jest-changed-files/node_modules/picomatch": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { @@ -9800,27 +9979,29 @@ } }, "node_modules/jest-circus": { - "version": "30.1.3", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.2.0.tgz", + "integrity": "sha512-Fh0096NC3ZkFx05EP2OXCxJAREVxj1BcW/i6EWqqymcgYKWjyyDpral3fMxVcHXg6oZM7iULer9wGRFvfpl+Tg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/environment": "30.1.2", - "@jest/expect": "30.1.2", - "@jest/test-result": "30.1.3", - "@jest/types": "30.0.5", + "@jest/environment": "30.2.0", + "@jest/expect": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "co": "^4.6.0", "dedent": "^1.6.0", "is-generator-fn": "^2.1.0", - "jest-each": "30.1.0", - "jest-matcher-utils": "30.1.2", - "jest-message-util": "30.1.0", - "jest-runtime": "30.1.3", - "jest-snapshot": "30.1.2", - "jest-util": "30.0.5", + "jest-each": "30.2.0", + "jest-matcher-utils": "30.2.0", + "jest-message-util": "30.2.0", + "jest-runtime": "30.2.0", + "jest-snapshot": "30.2.0", + "jest-util": "30.2.0", "p-limit": "^3.1.0", - "pretty-format": "30.0.5", + "pretty-format": "30.2.0", "pure-rand": "^7.0.0", "slash": "^3.0.0", "stack-utils": "^2.0.6" @@ -9831,6 +10012,8 @@ }, "node_modules/jest-circus/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", "dependencies": { @@ -9846,6 +10029,8 @@ }, "node_modules/jest-circus/node_modules/chalk/node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { @@ -9859,45 +10044,51 @@ } }, "node_modules/jest-circus/node_modules/jest-diff": { - "version": "30.1.2", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", + "integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==", "dev": true, "license": "MIT", "dependencies": { "@jest/diff-sequences": "30.0.1", "@jest/get-type": "30.1.0", "chalk": "^4.1.2", - "pretty-format": "30.0.5" + "pretty-format": "30.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-circus/node_modules/jest-matcher-utils": { - "version": "30.1.2", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz", + "integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==", "dev": true, "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0", "chalk": "^4.1.2", - "jest-diff": "30.1.2", - "pretty-format": "30.0.5" + "jest-diff": "30.2.0", + "pretty-format": "30.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-circus/node_modules/jest-message-util": { - "version": "30.1.0", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", + "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/stack-utils": "^2.0.3", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "micromatch": "^4.0.8", - "pretty-format": "30.0.5", + "pretty-format": "30.2.0", "slash": "^3.0.0", "stack-utils": "^2.0.6" }, @@ -9906,11 +10097,13 @@ } }, "node_modules/jest-circus/node_modules/jest-util": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", + "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", @@ -9923,6 +10116,8 @@ }, "node_modules/jest-circus/node_modules/picomatch": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { @@ -9933,7 +10128,9 @@ } }, "node_modules/jest-circus/node_modules/pretty-format": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", + "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", "dev": true, "license": "MIT", "dependencies": { @@ -9946,19 +10143,21 @@ } }, "node_modules/jest-cli": { - "version": "30.1.3", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.2.0.tgz", + "integrity": "sha512-Os9ukIvADX/A9sLt6Zse3+nmHtHaE6hqOsjQtNiugFTbKRHYIYtZXNGNK9NChseXy7djFPjndX1tL0sCTlfpAA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/core": "30.1.3", - "@jest/test-result": "30.1.3", - "@jest/types": "30.0.5", + "@jest/core": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/types": "30.2.0", "chalk": "^4.1.2", "exit-x": "^0.2.2", "import-local": "^3.2.0", - "jest-config": "30.1.3", - "jest-util": "30.0.5", - "jest-validate": "30.1.0", + "jest-config": "30.2.0", + "jest-util": "30.2.0", + "jest-validate": "30.2.0", "yargs": "^17.7.2" }, "bin": { @@ -9978,6 +10177,8 @@ }, "node_modules/jest-cli/node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { @@ -9992,6 +10193,8 @@ }, "node_modules/jest-cli/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", "dependencies": { @@ -10006,11 +10209,13 @@ } }, "node_modules/jest-cli/node_modules/jest-util": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", + "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", @@ -10023,6 +10228,8 @@ }, "node_modules/jest-cli/node_modules/picomatch": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { @@ -10033,32 +10240,34 @@ } }, "node_modules/jest-config": { - "version": "30.1.3", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.2.0.tgz", + "integrity": "sha512-g4WkyzFQVWHtu6uqGmQR4CQxz/CH3yDSlhzXMWzNjDx843gYjReZnMRanjRCq5XZFuQrGDxgUaiYWE8BRfVckA==", "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.27.4", "@jest/get-type": "30.1.0", "@jest/pattern": "30.0.1", - "@jest/test-sequencer": "30.1.3", - "@jest/types": "30.0.5", - "babel-jest": "30.1.2", + "@jest/test-sequencer": "30.2.0", + "@jest/types": "30.2.0", + "babel-jest": "30.2.0", "chalk": "^4.1.2", "ci-info": "^4.2.0", "deepmerge": "^4.3.1", "glob": "^10.3.10", "graceful-fs": "^4.2.11", - "jest-circus": "30.1.3", - "jest-docblock": "30.0.1", - "jest-environment-node": "30.1.2", + "jest-circus": "30.2.0", + "jest-docblock": "30.2.0", + "jest-environment-node": "30.2.0", "jest-regex-util": "30.0.1", - "jest-resolve": "30.1.3", - "jest-runner": "30.1.3", - "jest-util": "30.0.5", - "jest-validate": "30.1.0", + "jest-resolve": "30.2.0", + "jest-runner": "30.2.0", + "jest-util": "30.2.0", + "jest-validate": "30.2.0", "micromatch": "^4.0.8", "parse-json": "^5.2.0", - "pretty-format": "30.0.5", + "pretty-format": "30.2.0", "slash": "^3.0.0", "strip-json-comments": "^3.1.1" }, @@ -10084,6 +10293,8 @@ }, "node_modules/jest-config/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", "dependencies": { @@ -10099,6 +10310,8 @@ }, "node_modules/jest-config/node_modules/chalk/node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { @@ -10112,11 +10325,13 @@ } }, "node_modules/jest-config/node_modules/jest-util": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", + "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", @@ -10129,6 +10344,8 @@ }, "node_modules/jest-config/node_modules/picomatch": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { @@ -10139,7 +10356,9 @@ } }, "node_modules/jest-config/node_modules/pretty-format": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", + "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", "dev": true, "license": "MIT", "dependencies": { @@ -10195,7 +10414,9 @@ } }, "node_modules/jest-docblock": { - "version": "30.0.1", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.2.0.tgz", + "integrity": "sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==", "dev": true, "license": "MIT", "dependencies": { @@ -10206,15 +10427,17 @@ } }, "node_modules/jest-each": { - "version": "30.1.0", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.2.0.tgz", + "integrity": "sha512-lpWlJlM7bCUf1mfmuqTA8+j2lNURW9eNafOy99knBM01i5CQeY5UH1vZjgT9071nDJac1M4XsbyI44oNOdhlDQ==", "dev": true, "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0", - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "chalk": "^4.1.2", - "jest-util": "30.0.5", - "pretty-format": "30.0.5" + "jest-util": "30.2.0", + "pretty-format": "30.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -10222,6 +10445,8 @@ }, "node_modules/jest-each/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", "dependencies": { @@ -10237,6 +10462,8 @@ }, "node_modules/jest-each/node_modules/chalk/node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { @@ -10250,11 +10477,13 @@ } }, "node_modules/jest-each/node_modules/jest-util": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", + "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", @@ -10267,6 +10496,8 @@ }, "node_modules/jest-each/node_modules/picomatch": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { @@ -10277,7 +10508,9 @@ } }, "node_modules/jest-each/node_modules/pretty-format": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", + "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", "dev": true, "license": "MIT", "dependencies": { @@ -10503,17 +10736,19 @@ "license": "MIT" }, "node_modules/jest-environment-node": { - "version": "30.1.2", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.2.0.tgz", + "integrity": "sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/environment": "30.1.2", - "@jest/fake-timers": "30.1.2", - "@jest/types": "30.0.5", + "@jest/environment": "30.2.0", + "@jest/fake-timers": "30.2.0", + "@jest/types": "30.2.0", "@types/node": "*", - "jest-mock": "30.0.5", - "jest-util": "30.0.5", - "jest-validate": "30.1.0" + "jest-mock": "30.2.0", + "jest-util": "30.2.0", + "jest-validate": "30.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -10521,6 +10756,8 @@ }, "node_modules/jest-environment-node/node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { @@ -10535,6 +10772,8 @@ }, "node_modules/jest-environment-node/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", "dependencies": { @@ -10549,11 +10788,13 @@ } }, "node_modules/jest-environment-node/node_modules/jest-util": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", + "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", @@ -10566,6 +10807,8 @@ }, "node_modules/jest-environment-node/node_modules/picomatch": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { @@ -10584,18 +10827,20 @@ } }, "node_modules/jest-haste-map": { - "version": "30.1.0", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.2.0.tgz", + "integrity": "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/node": "*", "anymatch": "^3.1.3", "fb-watchman": "^2.0.2", "graceful-fs": "^4.2.11", "jest-regex-util": "30.0.1", - "jest-util": "30.0.5", - "jest-worker": "30.1.0", + "jest-util": "30.2.0", + "jest-worker": "30.2.0", "micromatch": "^4.0.8", "walker": "^1.0.8" }, @@ -10608,6 +10853,8 @@ }, "node_modules/jest-haste-map/node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { @@ -10622,6 +10869,8 @@ }, "node_modules/jest-haste-map/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", "dependencies": { @@ -10636,11 +10885,13 @@ } }, "node_modules/jest-haste-map/node_modules/jest-util": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", + "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", @@ -10653,6 +10904,8 @@ }, "node_modules/jest-haste-map/node_modules/picomatch": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { @@ -11292,19 +11545,23 @@ } }, "node_modules/jest-leak-detector": { - "version": "30.1.0", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.2.0.tgz", + "integrity": "sha512-M6jKAjyzjHG0SrQgwhgZGy9hFazcudwCNovY/9HPIicmNSBuockPSedAP9vlPK6ONFJ1zfyH/M2/YYJxOz5cdQ==", "dev": true, "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0", - "pretty-format": "30.0.5" + "pretty-format": "30.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-leak-detector/node_modules/pretty-format": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", + "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", "dev": true, "license": "MIT", "dependencies": { @@ -11440,13 +11697,15 @@ } }, "node_modules/jest-mock": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.2.0.tgz", + "integrity": "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/node": "*", - "jest-util": "30.0.5" + "jest-util": "30.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -11454,6 +11713,8 @@ }, "node_modules/jest-mock/node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { @@ -11468,6 +11729,8 @@ }, "node_modules/jest-mock/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", "dependencies": { @@ -11482,11 +11745,13 @@ } }, "node_modules/jest-mock/node_modules/jest-util": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", + "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", @@ -11499,6 +11764,8 @@ }, "node_modules/jest-mock/node_modules/picomatch": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { @@ -11533,16 +11800,18 @@ } }, "node_modules/jest-resolve": { - "version": "30.1.3", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.2.0.tgz", + "integrity": "sha512-TCrHSxPlx3tBY3hWNtRQKbtgLhsXa1WmbJEqBlTBrGafd5fiQFByy2GNCEoGR+Tns8d15GaL9cxEzKOO3GEb2A==", "dev": true, "license": "MIT", "dependencies": { "chalk": "^4.1.2", "graceful-fs": "^4.2.11", - "jest-haste-map": "30.1.0", + "jest-haste-map": "30.2.0", "jest-pnp-resolver": "^1.2.3", - "jest-util": "30.0.5", - "jest-validate": "30.1.0", + "jest-util": "30.2.0", + "jest-validate": "30.2.0", "slash": "^3.0.0", "unrs-resolver": "^1.7.11" }, @@ -11551,12 +11820,14 @@ } }, "node_modules/jest-resolve-dependencies": { - "version": "30.1.3", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.2.0.tgz", + "integrity": "sha512-xTOIGug/0RmIe3mmCqCT95yO0vj6JURrn1TKWlNbhiAefJRWINNPgwVkrVgt/YaerPzY3iItufd80v3lOrFJ2w==", "dev": true, "license": "MIT", "dependencies": { "jest-regex-util": "30.0.1", - "jest-snapshot": "30.1.2" + "jest-snapshot": "30.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -11564,6 +11835,8 @@ }, "node_modules/jest-resolve/node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { @@ -11578,6 +11851,8 @@ }, "node_modules/jest-resolve/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", "dependencies": { @@ -11592,11 +11867,13 @@ } }, "node_modules/jest-resolve/node_modules/jest-util": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", + "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", @@ -11609,6 +11886,8 @@ }, "node_modules/jest-resolve/node_modules/picomatch": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { @@ -11619,30 +11898,32 @@ } }, "node_modules/jest-runner": { - "version": "30.1.3", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.2.0.tgz", + "integrity": "sha512-PqvZ2B2XEyPEbclp+gV6KO/F1FIFSbIwewRgmROCMBo/aZ6J1w8Qypoj2pEOcg3G2HzLlaP6VUtvwCI8dM3oqQ==", "dev": true, "license": "MIT", "dependencies": { - "@jest/console": "30.1.2", - "@jest/environment": "30.1.2", - "@jest/test-result": "30.1.3", - "@jest/transform": "30.1.2", - "@jest/types": "30.0.5", + "@jest/console": "30.2.0", + "@jest/environment": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "emittery": "^0.13.1", "exit-x": "^0.2.2", "graceful-fs": "^4.2.11", - "jest-docblock": "30.0.1", - "jest-environment-node": "30.1.2", - "jest-haste-map": "30.1.0", - "jest-leak-detector": "30.1.0", - "jest-message-util": "30.1.0", - "jest-resolve": "30.1.3", - "jest-runtime": "30.1.3", - "jest-util": "30.0.5", - "jest-watcher": "30.1.3", - "jest-worker": "30.1.0", + "jest-docblock": "30.2.0", + "jest-environment-node": "30.2.0", + "jest-haste-map": "30.2.0", + "jest-leak-detector": "30.2.0", + "jest-message-util": "30.2.0", + "jest-resolve": "30.2.0", + "jest-runtime": "30.2.0", + "jest-util": "30.2.0", + "jest-watcher": "30.2.0", + "jest-worker": "30.2.0", "p-limit": "^3.1.0", "source-map-support": "0.5.13" }, @@ -11652,6 +11933,8 @@ }, "node_modules/jest-runner/node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { @@ -11666,6 +11949,8 @@ }, "node_modules/jest-runner/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", "dependencies": { @@ -11680,17 +11965,19 @@ } }, "node_modules/jest-runner/node_modules/jest-message-util": { - "version": "30.1.0", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", + "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/stack-utils": "^2.0.3", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "micromatch": "^4.0.8", - "pretty-format": "30.0.5", + "pretty-format": "30.2.0", "slash": "^3.0.0", "stack-utils": "^2.0.6" }, @@ -11699,11 +11986,13 @@ } }, "node_modules/jest-runner/node_modules/jest-util": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", + "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", @@ -11716,6 +12005,8 @@ }, "node_modules/jest-runner/node_modules/picomatch": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { @@ -11726,7 +12017,9 @@ } }, "node_modules/jest-runner/node_modules/pretty-format": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", + "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", "dev": true, "license": "MIT", "dependencies": { @@ -11740,6 +12033,8 @@ }, "node_modules/jest-runner/node_modules/pretty-format/node_modules/ansi-styles": { "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", "engines": { @@ -11750,30 +12045,32 @@ } }, "node_modules/jest-runtime": { - "version": "30.1.3", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.2.0.tgz", + "integrity": "sha512-p1+GVX/PJqTucvsmERPMgCPvQJpFt4hFbM+VN3n8TMo47decMUcJbt+rgzwrEme0MQUA/R+1de2axftTHkKckg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/environment": "30.1.2", - "@jest/fake-timers": "30.1.2", - "@jest/globals": "30.1.2", + "@jest/environment": "30.2.0", + "@jest/fake-timers": "30.2.0", + "@jest/globals": "30.2.0", "@jest/source-map": "30.0.1", - "@jest/test-result": "30.1.3", - "@jest/transform": "30.1.2", - "@jest/types": "30.0.5", + "@jest/test-result": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "cjs-module-lexer": "^2.1.0", "collect-v8-coverage": "^1.0.2", "glob": "^10.3.10", "graceful-fs": "^4.2.11", - "jest-haste-map": "30.1.0", - "jest-message-util": "30.1.0", - "jest-mock": "30.0.5", + "jest-haste-map": "30.2.0", + "jest-message-util": "30.2.0", + "jest-mock": "30.2.0", "jest-regex-util": "30.0.1", - "jest-resolve": "30.1.3", - "jest-snapshot": "30.1.2", - "jest-util": "30.0.5", + "jest-resolve": "30.2.0", + "jest-snapshot": "30.2.0", + "jest-util": "30.2.0", "slash": "^3.0.0", "strip-bom": "^4.0.0" }, @@ -11783,6 +12080,8 @@ }, "node_modules/jest-runtime/node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { @@ -11797,6 +12096,8 @@ }, "node_modules/jest-runtime/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", "dependencies": { @@ -11811,17 +12112,19 @@ } }, "node_modules/jest-runtime/node_modules/jest-message-util": { - "version": "30.1.0", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", + "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/stack-utils": "^2.0.3", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "micromatch": "^4.0.8", - "pretty-format": "30.0.5", + "pretty-format": "30.2.0", "slash": "^3.0.0", "stack-utils": "^2.0.6" }, @@ -11830,11 +12133,13 @@ } }, "node_modules/jest-runtime/node_modules/jest-util": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", + "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", @@ -11847,6 +12152,8 @@ }, "node_modules/jest-runtime/node_modules/picomatch": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { @@ -11857,7 +12164,9 @@ } }, "node_modules/jest-runtime/node_modules/pretty-format": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", + "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", "dev": true, "license": "MIT", "dependencies": { @@ -11871,6 +12180,8 @@ }, "node_modules/jest-runtime/node_modules/pretty-format/node_modules/ansi-styles": { "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", "engines": { @@ -11893,7 +12204,9 @@ } }, "node_modules/jest-snapshot": { - "version": "30.1.2", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.2.0.tgz", + "integrity": "sha512-5WEtTy2jXPFypadKNpbNkZ72puZCa6UjSr/7djeecHWOu7iYhSXSnHScT8wBz3Rn8Ena5d5RYRcsyKIeqG1IyA==", "dev": true, "license": "MIT", "dependencies": { @@ -11902,20 +12215,20 @@ "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1", "@babel/types": "^7.27.3", - "@jest/expect-utils": "30.1.2", + "@jest/expect-utils": "30.2.0", "@jest/get-type": "30.1.0", - "@jest/snapshot-utils": "30.1.2", - "@jest/transform": "30.1.2", - "@jest/types": "30.0.5", - "babel-preset-current-node-syntax": "^1.1.0", + "@jest/snapshot-utils": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", + "babel-preset-current-node-syntax": "^1.2.0", "chalk": "^4.1.2", - "expect": "30.1.2", + "expect": "30.2.0", "graceful-fs": "^4.2.11", - "jest-diff": "30.1.2", - "jest-matcher-utils": "30.1.2", - "jest-message-util": "30.1.0", - "jest-util": "30.0.5", - "pretty-format": "30.0.5", + "jest-diff": "30.2.0", + "jest-matcher-utils": "30.2.0", + "jest-message-util": "30.2.0", + "jest-util": "30.2.0", + "pretty-format": "30.2.0", "semver": "^7.7.2", "synckit": "^0.11.8" }, @@ -11924,7 +12237,9 @@ } }, "node_modules/jest-snapshot/node_modules/@jest/expect-utils": { - "version": "30.1.2", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.2.0.tgz", + "integrity": "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==", "dev": true, "license": "MIT", "dependencies": { @@ -11936,6 +12251,8 @@ }, "node_modules/jest-snapshot/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", "dependencies": { @@ -11951,6 +12268,8 @@ }, "node_modules/jest-snapshot/node_modules/chalk/node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { @@ -11964,61 +12283,69 @@ } }, "node_modules/jest-snapshot/node_modules/expect": { - "version": "30.1.2", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.2.0.tgz", + "integrity": "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==", "dev": true, "license": "MIT", "dependencies": { - "@jest/expect-utils": "30.1.2", + "@jest/expect-utils": "30.2.0", "@jest/get-type": "30.1.0", - "jest-matcher-utils": "30.1.2", - "jest-message-util": "30.1.0", - "jest-mock": "30.0.5", - "jest-util": "30.0.5" + "jest-matcher-utils": "30.2.0", + "jest-message-util": "30.2.0", + "jest-mock": "30.2.0", + "jest-util": "30.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-snapshot/node_modules/jest-diff": { - "version": "30.1.2", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", + "integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==", "dev": true, "license": "MIT", "dependencies": { "@jest/diff-sequences": "30.0.1", "@jest/get-type": "30.1.0", "chalk": "^4.1.2", - "pretty-format": "30.0.5" + "pretty-format": "30.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-snapshot/node_modules/jest-matcher-utils": { - "version": "30.1.2", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz", + "integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==", "dev": true, "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0", "chalk": "^4.1.2", - "jest-diff": "30.1.2", - "pretty-format": "30.0.5" + "jest-diff": "30.2.0", + "pretty-format": "30.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, "node_modules/jest-snapshot/node_modules/jest-message-util": { - "version": "30.1.0", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", + "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/stack-utils": "^2.0.3", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "micromatch": "^4.0.8", - "pretty-format": "30.0.5", + "pretty-format": "30.2.0", "slash": "^3.0.0", "stack-utils": "^2.0.6" }, @@ -12027,11 +12354,13 @@ } }, "node_modules/jest-snapshot/node_modules/jest-util": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", + "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", @@ -12044,6 +12373,8 @@ }, "node_modules/jest-snapshot/node_modules/picomatch": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { @@ -12054,7 +12385,9 @@ } }, "node_modules/jest-snapshot/node_modules/pretty-format": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", + "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", "dev": true, "license": "MIT", "dependencies": { @@ -12158,16 +12491,18 @@ } }, "node_modules/jest-validate": { - "version": "30.1.0", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.2.0.tgz", + "integrity": "sha512-FBGWi7dP2hpdi8nBoWxSsLvBFewKAg0+uSQwBaof4Y4DPgBabXgpSYC5/lR7VmnIlSpASmCi/ntRWPbv7089Pw==", "dev": true, "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0", - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "camelcase": "^6.3.0", "chalk": "^4.1.2", "leven": "^3.1.0", - "pretty-format": "30.0.5" + "pretty-format": "30.2.0" }, "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -12175,6 +12510,8 @@ }, "node_modules/jest-validate/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", "dependencies": { @@ -12190,6 +12527,8 @@ }, "node_modules/jest-validate/node_modules/chalk/node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { @@ -12203,7 +12542,9 @@ } }, "node_modules/jest-validate/node_modules/pretty-format": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", + "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", "dev": true, "license": "MIT", "dependencies": { @@ -12216,17 +12557,19 @@ } }, "node_modules/jest-watcher": { - "version": "30.1.3", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.2.0.tgz", + "integrity": "sha512-PYxa28dxJ9g777pGm/7PrbnMeA0Jr7osHP9bS7eJy9DuAjMgdGtxgf0uKMyoIsTWAkIbUW5hSDdJ3urmgXBqxg==", "dev": true, "license": "MIT", "dependencies": { - "@jest/test-result": "30.1.3", - "@jest/types": "30.0.5", + "@jest/test-result": "30.2.0", + "@jest/types": "30.2.0", "@types/node": "*", "ansi-escapes": "^4.3.2", "chalk": "^4.1.2", "emittery": "^0.13.1", - "jest-util": "30.0.5", + "jest-util": "30.2.0", "string-length": "^4.0.2" }, "engines": { @@ -12235,6 +12578,8 @@ }, "node_modules/jest-watcher/node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { @@ -12249,6 +12594,8 @@ }, "node_modules/jest-watcher/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", "dependencies": { @@ -12263,11 +12610,13 @@ } }, "node_modules/jest-watcher/node_modules/jest-util": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", + "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", @@ -12280,6 +12629,8 @@ }, "node_modules/jest-watcher/node_modules/picomatch": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { @@ -12290,13 +12641,15 @@ } }, "node_modules/jest-worker": { - "version": "30.1.0", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.2.0.tgz", + "integrity": "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g==", "dev": true, "license": "MIT", "dependencies": { "@types/node": "*", "@ungap/structured-clone": "^1.3.0", - "jest-util": "30.0.5", + "jest-util": "30.2.0", "merge-stream": "^2.0.0", "supports-color": "^8.1.1" }, @@ -12306,6 +12659,8 @@ }, "node_modules/jest-worker/node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { @@ -12320,6 +12675,8 @@ }, "node_modules/jest-worker/node_modules/chalk": { "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", "dependencies": { @@ -12335,6 +12692,8 @@ }, "node_modules/jest-worker/node_modules/chalk/node_modules/supports-color": { "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "license": "MIT", "dependencies": { @@ -12345,11 +12704,13 @@ } }, "node_modules/jest-worker/node_modules/jest-util": { - "version": "30.0.5", + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", + "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", "dev": true, "license": "MIT", "dependencies": { - "@jest/types": "30.0.5", + "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", @@ -12362,6 +12723,8 @@ }, "node_modules/jest-worker/node_modules/picomatch": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { @@ -12373,6 +12736,8 @@ }, "node_modules/jest-worker/node_modules/supports-color": { "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "license": "MIT", "dependencies": { @@ -12849,6 +13214,8 @@ }, "node_modules/minimatch": { "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "license": "ISC", "dependencies": { @@ -12870,6 +13237,8 @@ }, "node_modules/minipass": { "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true, "license": "ISC", "engines": { @@ -13136,6 +13505,8 @@ }, "node_modules/p-limit": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "license": "MIT", "dependencies": { @@ -13183,6 +13554,8 @@ }, "node_modules/package-json-from-dist": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", "dev": true, "license": "BlueOak-1.0.0" }, @@ -13241,6 +13614,8 @@ }, "node_modules/path-scurry": { "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -13256,6 +13631,8 @@ }, "node_modules/path-scurry/node_modules/lru-cache": { "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "dev": true, "license": "ISC" }, @@ -13450,6 +13827,8 @@ }, "node_modules/pure-rand": { "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", + "integrity": "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==", "dev": true, "funding": [ { @@ -14091,6 +14470,8 @@ }, "node_modules/string-width": { "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, "license": "MIT", "dependencies": { @@ -14108,6 +14489,8 @@ "node_modules/string-width-cjs": { "name": "string-width", "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", "dependencies": { @@ -14121,6 +14504,8 @@ }, "node_modules/string-width-cjs/node_modules/ansi-regex": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", "engines": { @@ -14129,11 +14514,15 @@ }, "node_modules/string-width-cjs/node_modules/emoji-regex": { "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, "license": "MIT" }, "node_modules/string-width-cjs/node_modules/strip-ansi": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", "dependencies": { @@ -14159,6 +14548,8 @@ "node_modules/strip-ansi-cjs": { "name": "strip-ansi", "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", "dependencies": { @@ -14170,6 +14561,8 @@ }, "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", "engines": { @@ -14257,6 +14650,8 @@ }, "node_modules/synckit": { "version": "0.11.11", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", + "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==", "dev": true, "license": "MIT", "dependencies": { @@ -15093,6 +15488,8 @@ }, "node_modules/v8-to-istanbul": { "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", "dev": true, "license": "ISC", "dependencies": { @@ -15299,6 +15696,8 @@ }, "node_modules/wrap-ansi": { "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, "license": "MIT", "dependencies": { @@ -15316,6 +15715,8 @@ "node_modules/wrap-ansi-cjs": { "name": "wrap-ansi", "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "license": "MIT", "dependencies": { @@ -15332,6 +15733,8 @@ }, "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", "engines": { @@ -15340,6 +15743,8 @@ }, "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { @@ -15354,11 +15759,15 @@ }, "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, "license": "MIT" }, "node_modules/wrap-ansi-cjs/node_modules/string-width": { "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", "dependencies": { @@ -15372,6 +15781,8 @@ }, "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", "dependencies": { @@ -15383,6 +15794,8 @@ }, "node_modules/wrap-ansi/node_modules/ansi-styles": { "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "dev": true, "license": "MIT", "engines": { @@ -15460,6 +15873,8 @@ }, "node_modules/yargs": { "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, "license": "MIT", "dependencies": { @@ -15485,6 +15900,8 @@ }, "node_modules/yargs/node_modules/ansi-regex": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", "engines": { @@ -15493,11 +15910,15 @@ }, "node_modules/yargs/node_modules/emoji-regex": { "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, "license": "MIT" }, "node_modules/yargs/node_modules/string-width": { "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", "dependencies": { @@ -15511,6 +15932,8 @@ }, "node_modules/yargs/node_modules/strip-ansi": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", "dependencies": { @@ -15530,6 +15953,8 @@ }, "node_modules/yocto-queue": { "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, "license": "MIT", "engines": { @@ -15602,7 +16027,8 @@ "dependencies": { "@wormhole-foundation/sdk-definitions-ntt": "1.0.0", "@wormhole-foundation/sdk-evm-ntt": "1.0.0", - "@wormhole-foundation/sdk-solana-ntt": "1.0.0" + "@wormhole-foundation/sdk-solana-ntt": "1.0.0", + "@wormhole-foundation/sdk-stacks-ntt": "1.0.0" }, "devDependencies": { "nock": "^13.3.3", @@ -15666,6 +16092,28 @@ "version": "5.2.1", "license": "MIT" }, + "stacks/ts": { + "name": "@wormhole-foundation/sdk-stacks-ntt", + "version": "1.0.0", + "license": "Apache-2.0", + "dependencies": { + "@stacks/network": "^7.2.0", + "@stacks/transactions": "^7.2.0", + "@wormhole-foundation/sdk-definitions-ntt": "1.0.0" + }, + "devDependencies": { + "tsx": "^4.7.2" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "@wormhole-foundation/sdk-base": "^4.7.0", + "@wormhole-foundation/sdk-definitions": "^4.7.0", + "@wormhole-foundation/sdk-stacks": "^4.7.0", + "@wormhole-foundation/sdk-stacks-core": "^4.7.0" + } + }, "sui/ts": { "name": "@wormhole-foundation/sdk-sui-ntt", "version": "0.5.0", diff --git a/package.json b/package.json index 802cb49e7..85eb30d35 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "build:solana": "npm run build --workspace=sdk/definitions --workspace=solana", "build:evm": "npm run build --workspace=sdk/definitions --workspace=sdk/evm", "build:sui": "npm run build --workspace=sdk/definitions --workspace=sui/ts", + "build:stacks": "npm run build --workspace=sdk/definitions --workspace=stacks/ts", "typecheck:cli": "npm run typecheck --workspace=cli", "generate": "npm run generate --workspaces --if-present", "test": "npm run test --workspaces --if-present", @@ -30,6 +31,7 @@ "@wormhole-foundation/sdk": "^4.7.0", "@wormhole-foundation/wormchain-sdk": "^0.0.1", "ethers": "^6.5.1", + "jest": "^30.2.0", "prettier": "3.6.2", "ts-jest": "^29.1.2", "tsx": "^4.7.2", @@ -39,6 +41,7 @@ "sdk/definitions", "evm/ts", "solana", + "stacks/ts", "sui/ts", "sdk/route", "sdk/examples", diff --git a/sdk/definitions/src/ntt.ts b/sdk/definitions/src/ntt.ts index 13111d15b..4bccbed7a 100644 --- a/sdk/definitions/src/ntt.ts +++ b/sdk/definitions/src/ntt.ts @@ -263,12 +263,15 @@ export interface Ntt { /** * redeem redeems a set of Attestations to the corresponding transceivers on the destination chain * @param attestations The attestations to redeem, the length should be equal to the number of transceivers + * @param payer The account that will pay for the transaction + * @param recipient The recipient address * * TODO: replace with Map */ redeem( attestations: Ntt.Attestation[], - payer?: AccountAddress + payer: AccountAddress, + recipient?: AccountAddress ): AsyncGenerator>; /** Get the address for the account that custodies locked tokens */ @@ -370,7 +373,7 @@ export interface Ntt { completeInboundQueuedTransfer( fromChain: Chain, transceiverMessage: Ntt.Message, - payer?: AccountAddress + payer: AccountAddress ): AsyncGenerator>; /** diff --git a/sdk/route/package.json b/sdk/route/package.json index 01fe158cc..e4a225e53 100644 --- a/sdk/route/package.json +++ b/sdk/route/package.json @@ -48,7 +48,8 @@ "dependencies": { "@wormhole-foundation/sdk-definitions-ntt": "1.0.0", "@wormhole-foundation/sdk-evm-ntt": "1.0.0", - "@wormhole-foundation/sdk-solana-ntt": "1.0.0" + "@wormhole-foundation/sdk-solana-ntt": "1.0.0", + "@wormhole-foundation/sdk-stacks-ntt": "1.0.0" }, "peerDependencies": { "@wormhole-foundation/sdk-connect": "^4.7.0", diff --git a/sdk/route/src/automatic.ts b/sdk/route/src/automatic.ts index 8e7d69a0b..ec7691041 100644 --- a/sdk/route/src/automatic.ts +++ b/sdk/route/src/automatic.ts @@ -283,7 +283,7 @@ export class NttAutomaticRoute address: vaa.emitterAddress, }); - const dstInfo = NttRoute.resolveDestinationNttContracts( + const { dstContracts: dstInfo } = NttRoute.resolveDestinationNttContracts( this.staticConfig, { chain: vaa.emitterChain, diff --git a/sdk/route/src/executor/consts.ts b/sdk/route/src/executor/consts.ts index 23ad6fabe..1e9152302 100644 --- a/sdk/route/src/executor/consts.ts +++ b/sdk/route/src/executor/consts.ts @@ -21,6 +21,8 @@ export const getDefaultReferrerAddress = (chain: Chain): ChainAddress => { } else if (chainToPlatform(chain) === "Sui") { address = "0xbfa1240e48c622d97881473953be730091161b7931d89bd6afe667841cf69ef4"; + } else if (chainToPlatform(chain) === "Stacks") { + address = "ST117FG1AKZ7724AXYMMABVPE4G2MNQ453SNS0S3"; // TODO: update to actual referrer address } else { throw new Error(`No referrer address for chain ${chain}`); } diff --git a/sdk/route/src/executor/executor.ts b/sdk/route/src/executor/executor.ts index c6becc543..b1d53ae32 100644 --- a/sdk/route/src/executor/executor.ts +++ b/sdk/route/src/executor/executor.ts @@ -42,9 +42,11 @@ import { fetchCapabilities, fetchSignedQuote, fetchStatus, + getNativeRecipientAddress, isRelayStatusFailed, } from "./utils.js"; import { Ntt, NttWithExecutor } from "@wormhole-foundation/sdk-definitions-ntt"; +import { StacksNttWithExecutor } from "@wormhole-foundation/sdk-stacks-ntt"; import { isNative, relayInstructionsLayout, @@ -278,8 +280,10 @@ export class NttExecutorRoute toChain.config.nativeTokenDecimals ), eta: - finality.estimateFinalityTime(request.fromChain.chain) + - guardians.guardianAttestationEta * 1000, + request.fromChain.chain === "Stacks" + ? 10000 + : finality.estimateFinalityTime(request.fromChain.chain) + + guardians.guardianAttestationEta * 1000, expires, details: executorQuote, }; @@ -388,34 +392,55 @@ export class NttExecutorRoute } } - const relayRequests = []; + let relayInstructions: Uint8Array; - // Add the gas instruction - relayRequests.push({ - request: { - type: "GasInstruction" as const, - gasLimit, - msgValue, - }, - }); + const relayRequests = []; - // Add the gas drop-off instruction if applicable - if (dropOff > 0n) { + if (toChain.chain === "Stacks") { + // When transferring to Stacks, we use the StacksNttReceiveInstruction, which includes + // the pre-hashed recipient address (Stacks "universal" addresses are keccak256 hashes). + // The pre-hashed recipient address is used by executor to register the recipient + // with the Stacks addr32 contract if it is not already registered. relayRequests.push({ request: { - type: "GasDropOffInstruction" as const, - dropOff, - // If the recipient is undefined (e.g. the user hasn’t connected their wallet yet), - // we temporarily use a dummy address to fetch a quote. - // The recipient address is validated later in the `initiate` method, which will throw if it's still missing. + type: "StacksNttReceiveInstruction" as const, + nttManager: Buffer.from( + params.normalizedParams.destinationContracts.manager + ), recipient: recipient - ? recipient.address.toUniversalAddress() - : new UniversalAddress(new Uint8Array(32)), + ? recipient.address.toUint8Array() + : new Uint8Array(new Uint8Array(32)), + gasDropOff: dropOff, + }, + }); + } else { + // Add the gas instruction + relayRequests.push({ + request: { + type: "GasInstruction" as const, + gasLimit, + msgValue, }, }); + + // Add the gas drop-off instruction if applicable + if (dropOff > 0n) { + relayRequests.push({ + request: { + type: "GasDropOffInstruction" as const, + dropOff, + // If the recipient is undefined (e.g. the user hasn't connected their wallet yet), + // we temporarily use a dummy address to fetch a quote. + // The recipient address is validated later in the `initiate` method, which will throw if it's still missing. + recipient: recipient + ? recipient.address.toUniversalAddress() + : new UniversalAddress(new Uint8Array(32)), + }, + }); + } } - const relayInstructions = serializeLayout(relayInstructionsLayout, { + relayInstructions = serializeLayout(relayInstructionsLayout, { requests: relayRequests, }); @@ -473,6 +498,12 @@ export class NttExecutorRoute ) { throw new Error("Gas drop-off recipient does not match"); } + if ( + request.type === "StacksNttReceiveInstruction" && + !encoding.bytes.equals(request.recipient, to.address.toUint8Array()) + ) { + throw new Error("Stacks recipient does not match"); + } }); const { fromChain } = request; @@ -548,11 +579,21 @@ export class NttExecutorRoute } const toChain = this.wh.getChain(receipt.to); + + const recipientAddress = await getNativeRecipientAddress( + this.wh.network, + receipt + ); + const ntt = await toChain.getProtocol("Ntt", { ntt: receipt.params.normalizedParams.destinationContracts, }); const sender = Wormhole.parseAddress(signer.chain(), signer.address()); - const completeXfer = ntt.redeem([receipt.attestation.attestation], sender); + const completeXfer = ntt.redeem( + [receipt.attestation.attestation], + sender, + recipientAddress + ); const txids = await signSendWait(toChain, completeXfer, signer); return { @@ -576,30 +617,26 @@ export class NttExecutorRoute const { recipientChain, trimmedAmount } = vaa.payload["nttManagerPayload"].payload; - const token = canonicalAddress({ - chain: vaa.emitterChain, - address: vaa.payload["nttManagerPayload"].payload.sourceToken, - }); - const manager = canonicalAddress({ - chain: vaa.emitterChain, - address: vaa.payload["sourceNttManager"], - }); - const whTransceiver = - chainToPlatform(vaa.emitterChain) === "Solana" - ? manager - : canonicalAddress({ - chain: vaa.emitterChain, - address: vaa.emitterAddress, - }); - - const dstInfo = NttRoute.resolveDestinationNttContracts( - this.staticConfig.ntt, - { + const srcManagerAddress = await (async () => { + if (chainToPlatform(tx.chain) === "Stacks") { + // We can't use the manager address from the VAA payload for Stacks + // since it's the hashed address. Instead, we need to fetch it from the transaction. + const stacks = this.wh.getChain("Stacks"); + const rpc = await stacks.getRpc(); + return StacksNttWithExecutor.getManagerAddressFromTx(rpc, tx.txid); + } + return { chain: vaa.emitterChain, address: vaa.payload["sourceNttManager"], - }, - recipientChain - ); + }; + })(); + + const { srcContracts, dstContracts } = + NttRoute.resolveDestinationNttContracts( + this.staticConfig.ntt, + srcManagerAddress, + recipientChain + ); const amt = amount.fromBaseUnits( trimmedAmount.amount, @@ -620,20 +657,8 @@ export class NttExecutorRoute options: {}, normalizedParams: { amount: amt, - sourceContracts: { - token, - manager, - transceiver: { - wormhole: whTransceiver, - }, - }, - destinationContracts: { - token: dstInfo.token, - manager: dstInfo.manager, - transceiver: { - wormhole: dstInfo.transceiver["wormhole"]!, - }, - }, + sourceContracts: srcContracts, + destinationContracts: dstContracts, referrerFeeDbps: 0n, }, }, diff --git a/sdk/route/src/executor/utils.ts b/sdk/route/src/executor/utils.ts index ad70b0e32..53d444afb 100644 --- a/sdk/route/src/executor/utils.ts +++ b/sdk/route/src/executor/utils.ts @@ -3,11 +3,19 @@ import { Network, toChainId, amount as sdkAmount, + encoding, + deserializeLayout, } from "@wormhole-foundation/sdk-base"; -import { SignedQuote } from "@wormhole-foundation/sdk-definitions"; +import { + NativeAddress, + SignedQuote, + relayInstructionsLayout, +} from "@wormhole-foundation/sdk-definitions"; +import { isAttested, Wormhole } from "@wormhole-foundation/sdk-connect"; import axios from "axios"; import { apiBaseUrl } from "./consts.js"; import { NttRoute } from "../types.js"; +import { NttExecutorRoute } from "./executor.js"; export enum RelayStatus { Pending = "pending", @@ -110,6 +118,7 @@ export async function fetchSignedQuote( export interface StatusResponse extends RelayData { signedQuote: SignedQuote; estimatedCost: string; + requestForExecution: RequestForExecution; } // Fetch Status @@ -163,3 +172,63 @@ export function calculateReferrerFee( } return { referrerFee, remainingAmount, referrerFeeDbps: dBps }; } + +export async function getNativeRecipientAddress( + network: Network, + receipt: NttExecutorRoute.TransferReceipt +): Promise> { + if (!isAttested(receipt)) { + throw new Error( + "Cannot extract recipient address from unattested transfer" + ); + } + + // For Stacks, we need to extract from the transaction's relay instructions + // which will contain the pre-hashed recipient address + if (receipt.to === "Stacks") { + const [txStatus] = await fetchStatus( + network, + receipt.originTxs.at(-1)!.txid, + receipt.to + ); + + if (!txStatus) { + throw new Error("Failed to fetch transaction status"); + } + + const { relayInstructionsBytes } = txStatus.requestForExecution; + + const relayInstructionsDecoded = encoding.hex.decode( + relayInstructionsBytes + ); + + const relayInstructions = deserializeLayout( + relayInstructionsLayout, + relayInstructionsDecoded + ); + + const stacksInstruction = relayInstructions.requests.find( + ({ request }) => request.type === "StacksNttReceiveInstruction" + ); + + if ( + !stacksInstruction || + stacksInstruction.request.type !== "StacksNttReceiveInstruction" + ) { + throw new Error( + "No StacksNttReceiveInstruction found in relay instructions" + ); + } + + const recipientBytes = stacksInstruction.request.recipient; + const recipientAddressString = encoding.bytes.decode(recipientBytes); + return Wormhole.parseAddress("Stacks", recipientAddressString); + } + + // For other chains, we can extract directly from the VAA payload + const vaa = receipt.attestation.attestation; + return Wormhole.parseAddress( + receipt.to, + vaa.payload.nttManagerPayload.payload.recipientAddress.toString() + ); +} diff --git a/sdk/route/src/manual.ts b/sdk/route/src/manual.ts index cdaa4cf9a..377cff8f7 100644 --- a/sdk/route/src/manual.ts +++ b/sdk/route/src/manual.ts @@ -264,7 +264,7 @@ export class NttManualRoute address: vaa.emitterAddress, }); - const dstInfo = NttRoute.resolveDestinationNttContracts( + const { dstContracts: dstInfo } = NttRoute.resolveDestinationNttContracts( this.staticConfig, { chain: vaa.emitterChain, diff --git a/sdk/route/src/types.ts b/sdk/route/src/types.ts index b6dcd1caa..55a3f8ce4 100644 --- a/sdk/route/src/types.ts +++ b/sdk/route/src/types.ts @@ -239,7 +239,7 @@ export namespace NttRoute { config: Config, srcManager: ChainAddress, dstChain: Chain - ): Ntt.Contracts { + ): { srcContracts: Ntt.Contracts; dstContracts: Ntt.Contracts } { const cfg = Object.values(config.tokens); const address = canonicalAddress(srcManager); for (const tokens of cfg) { @@ -255,7 +255,19 @@ export namespace NttRoute { `Cannot find destination Ntt contracts in config for: ${address}` ); } - return { + + const srcContracts = { + token: found.token, + manager: found.manager, + transceiver: { + wormhole: found.transceiver.find((v) => v.type === "wormhole")! + .address, + }, + quoter: found.quoter, + svmShims: found.svmShims, + }; + + const dstContracts = { token: remote.unwrapsOnRedeem ? "native" : remote.token, manager: remote.manager, transceiver: { @@ -265,6 +277,8 @@ export namespace NttRoute { quoter: remote.quoter, svmShims: remote.svmShims, }; + + return { srcContracts, dstContracts }; } } throw new Error("Cannot find Ntt contracts in config for: " + address); diff --git a/solana/ts/README.md b/solana/ts/README.md new file mode 100644 index 000000000..14d1d4df0 --- /dev/null +++ b/solana/ts/README.md @@ -0,0 +1,3 @@ +## Solana Ntt Implementation + +> **Note:** These are low-level protocol classes. If you are trying to perform a transfer, use the higher-level Route abstractions such as [`NttExecutorRoute`](../../sdk/route/src/executor/executor.ts) instead. diff --git a/solana/ts/sdk/ntt.ts b/solana/ts/sdk/ntt.ts index 99fcc04b0..b8894c887 100644 --- a/solana/ts/sdk/ntt.ts +++ b/solana/ts/sdk/ntt.ts @@ -1249,7 +1249,11 @@ export class SolanaNtt } } - async *redeem(attestations: Ntt.Attestation[], payer: AccountAddress) { + async *redeem( + attestations: Ntt.Attestation[], + payer: AccountAddress, + recipient?: AccountAddress + ) { const config = await this.getConfig(); if (config.paused) throw new Error("Contract is paused"); diff --git a/stacks/ts/.gitignore b/stacks/ts/.gitignore new file mode 100644 index 000000000..34112f8f2 --- /dev/null +++ b/stacks/ts/.gitignore @@ -0,0 +1,2 @@ +dist/* +node_modules/ diff --git a/stacks/ts/README.md b/stacks/ts/README.md new file mode 100644 index 000000000..5505d4f39 --- /dev/null +++ b/stacks/ts/README.md @@ -0,0 +1,3 @@ +## Stacks Ntt Implementation + +> **Note:** These are low-level protocol classes. If you are trying to perform a transfer, use the higher-level Route abstractions such as [`NttExecutorRoute`](../../sdk/route/src/executor/executor.ts) instead. diff --git a/stacks/ts/jest.config.ts b/stacks/ts/jest.config.ts new file mode 100644 index 000000000..23159500c --- /dev/null +++ b/stacks/ts/jest.config.ts @@ -0,0 +1,18 @@ +import type { JestConfigWithTsJest } from "ts-jest"; + +const jestConfig: JestConfigWithTsJest = { + verbose: true, + testTimeout: 10000000, + roots: ["./__tests__"], + testMatch: ["**/*.test.ts"], + modulePathIgnorePatterns: ["mocks"], + preset: "ts-jest", + moduleNameMapper: { + "^(\\.{1,2}/.*)\\.js$": "$1", + }, + transform: { + "^.+\\.tsx?$": ["ts-jest", { tsconfig: "tsconfig.test.json" }], + }, +}; + +export default jestConfig; diff --git a/stacks/ts/package.json b/stacks/ts/package.json new file mode 100644 index 000000000..d94fff151 --- /dev/null +++ b/stacks/ts/package.json @@ -0,0 +1,69 @@ +{ + "name": "@wormhole-foundation/sdk-stacks-ntt", + "version": "1.0.0", + "repository": { + "type": "git", + "url": "git+https://github.com/wormhole-foundation/native-token-transfers.git" + }, + "bugs": { + "url": "https://github.com/wormhole-foundation/native-token-transfers" + }, + "directories": { + "test": "__tests__" + }, + "license": "Apache-2.0", + "main": "./dist/cjs/index.js", + "types": "./dist/cjs/index.d.ts", + "module": "./dist/esm/index.js", + "description": "NTT SDK for Stacks chain", + "files": [ + "dist/esm", + "dist/cjs" + ], + "keywords": [ + "wormhole", + "sdk", + "typescript", + "ntt", + "stacks" + ], + "engines": { + "node": ">=16" + }, + "sideEffects": true, + "scripts": { + "build:cjs": "tsc -p ./tsconfig.cjs.json && echo '{\"type\":\"commonjs\"}' > dist/cjs/package.json", + "build:esm": "tsc -p ./tsconfig.esm.json", + "build": "npm run build:esm && npm run build:cjs", + "rebuild": "npm run clean && npm run build", + "clean": "rm -rf ./dist", + "build:contracts": "cd ../.. && make build" + }, + "dependencies": { + "@stacks/network": "^7.2.0", + "@stacks/transactions": "^7.2.0", + "@wormhole-foundation/sdk-definitions-ntt": "1.0.0" + }, + "devDependencies": { + "tsx": "^4.7.2" + }, + "type": "module", + "exports": { + ".": { + "import": { + "types": "./dist/esm/index.d.ts", + "default": "./dist/esm/index.js" + }, + "require": { + "types": "./dist/cjs/index.d.ts", + "default": "./dist/cjs/index.js" + } + } + }, + "peerDependencies": { + "@wormhole-foundation/sdk-base": "^4.7.0", + "@wormhole-foundation/sdk-definitions": "^4.7.0", + "@wormhole-foundation/sdk-stacks": "^4.7.0", + "@wormhole-foundation/sdk-stacks-core": "^4.7.0" + } +} diff --git a/stacks/ts/src/constants.ts b/stacks/ts/src/constants.ts new file mode 100644 index 000000000..8a29965aa --- /dev/null +++ b/stacks/ts/src/constants.ts @@ -0,0 +1,15 @@ +import { Network } from "@wormhole-foundation/sdk-base"; + +export const NTT_MANAGER_STATE_CONTRACT_NAME = "ntt-manager-state"; +export const NTT_MANAGER_CONTRACT_NAME = "ntt-manager-v1"; +export const NTT_TOKEN_OWNER_CONTRACT_NAME = "token-manager"; +export const WORMHOLE_TRANSCEIVER_STATE_CONTRACT_NAME = + "wormhole-transceiver-state"; + +export const WORMHOLE_PROTOCOL_ID = 1; + +export const DEFAULT_NTT_VERSION = "1.0.0"; + +export const ADDR32_CONTRACT: Partial> = { + Testnet: "ST2W4SFFKXMGFJW7K7NZFK3AH52ZTXDB74HKV9MRA.addr32", +}; diff --git a/stacks/ts/src/index.ts b/stacks/ts/src/index.ts new file mode 100644 index 000000000..ea2de956a --- /dev/null +++ b/stacks/ts/src/index.ts @@ -0,0 +1,12 @@ +import { registerProtocol } from "@wormhole-foundation/sdk-definitions"; +import { _platform } from "@wormhole-foundation/sdk-stacks"; +import { StacksNtt } from "./ntt.js"; +import { StacksNttWithExecutor } from "./nttWithExecutor.js"; +import "@wormhole-foundation/sdk-definitions-ntt"; +import "@wormhole-foundation/sdk-stacks-core"; + +registerProtocol(_platform, "Ntt", StacksNtt); +registerProtocol(_platform, "NttWithExecutor", StacksNttWithExecutor); + +export * from "./ntt.js"; +export * from "./nttWithExecutor.js"; diff --git a/stacks/ts/src/ntt.ts b/stacks/ts/src/ntt.ts new file mode 100644 index 000000000..7fdd30bb7 --- /dev/null +++ b/stacks/ts/src/ntt.ts @@ -0,0 +1,861 @@ +import { + Chain, + encoding, + Network, + toChainId, +} from "@wormhole-foundation/sdk-base"; +import { + AccountAddress, + ChainAddress, + ChainsConfig, + Contracts, + serialize, + toNative, + UniversalAddress, +} from "@wormhole-foundation/sdk-definitions"; +import { Ntt, NttTransceiver } from "@wormhole-foundation/sdk-definitions-ntt"; +import { + StacksChains, + StacksPlatform, + StacksPlatformType, + StacksUnsignedTransaction, + StacksZeroAddress, +} from "@wormhole-foundation/sdk-stacks"; +import { StacksNetwork } from "@stacks/network"; +import { + BufferCV, + Cl, + cvToValue, + fetchCallReadOnlyFunction, + PostConditionMode, +} from "@stacks/transactions"; +import { + ADDR32_CONTRACT, + DEFAULT_NTT_VERSION, + NTT_MANAGER_CONTRACT_NAME, + NTT_MANAGER_STATE_CONTRACT_NAME, + NTT_TOKEN_OWNER_CONTRACT_NAME, + WORMHOLE_PROTOCOL_ID, + WORMHOLE_TRANSCEIVER_STATE_CONTRACT_NAME, +} from "./constants.js"; + +export class StacksNttWormholeTransceiver< + N extends Network, + C extends StacksChains, +> implements NttTransceiver +{ + private readonly contractName: string; + private readonly deployer: string; + + constructor( + readonly manager: StacksNtt, + readonly tokenAddress: string, + readonly address: string + ) { + const addressSplit = address.split("."); + this.contractName = addressSplit[1]!; + this.deployer = addressSplit[0]!; + } + + async getTransceiverType(): Promise { + return "wormhole"; + } + + async getAddress(): Promise> { + return { + chain: this.manager.chain, + address: toNative(this.manager.chain, this.address), + }; + } + + async *setPeer( + peer: ChainAddress, + payer?: AccountAddress | undefined + ): AsyncGenerator> { + const tx = { + contractName: this.contractName, + contractAddress: this.deployer, + functionName: "add-peer", + functionArgs: [ + StacksNtt.chainToClBuffer(peer.chain), + Cl.buffer(new UniversalAddress(peer.address.toString()).toUint8Array()), + ], + postConditionMode: PostConditionMode.Allow, + }; + + yield { + transaction: tx, + network: this.manager.network, + chain: this.manager.chain, + description: "Ntt.setTransceiverPeer", + parallelizable: false, + }; + } + + async getPeer(chain: C): Promise | null> { + const res = await this.readonly( + "peers-get", + [StacksNtt.chainToClBuffer(chain)], + WORMHOLE_TRANSCEIVER_STATE_CONTRACT_NAME, + this.deployer + ); + const resValue = cvToValue(res); + if (!resValue) { + return null; + } + const address = new UniversalAddress(resValue.value); + return { + address, + chain, + }; + } + + async *setPauser( + newPauser: AccountAddress, + payer?: AccountAddress | undefined + ): AsyncGenerator> { + const tx = { + contractName: this.contractName, + contractAddress: this.deployer, + functionName: "transfer-pause-capability", + functionArgs: [Cl.address(newPauser.toString())], + postConditionMode: PostConditionMode.Allow, + }; + yield { + transaction: tx, + network: this.manager.network, + chain: this.manager.chain, + description: "Ntt.setTransceiverPauser", + parallelizable: false, + }; + } + + async getPauser(): Promise | null> { + const res = await this.transceiverReadOnly("get-pauser", []); + return cvToValue(res); + } + + async *receive( + attestation: Ntt.Attestation, + sender?: AccountAddress | undefined + ): AsyncGenerator> { + const tx = { + contractName: this.contractName, + contractAddress: this.deployer, + functionName: "receive-token-transfer", + functionArgs: [ + Cl.address(await this.manager.getFullAddress()), + Cl.address(this.tokenAddress), + Cl.buffer(serialize(attestation)), + ], + postConditionMode: PostConditionMode.Allow, + }; + yield { + transaction: tx, + network: this.manager.network, + chain: this.manager.chain, + description: "NttWormholeTransceiver.receive", + parallelizable: false, + }; + } + + private async transceiverReadOnly( + functionName: string, + functionArgs: any[] + ): Promise { + return this.readonly( + functionName, + functionArgs, + this.contractName, + this.deployer + ); + } + + private readonly( + functionName: string, + functionArgs: any[], + contractName: string, + contractAddress: string + ): Promise { + return fetchCallReadOnlyFunction({ + contractName: contractName, + contractAddress: contractAddress, + functionName, + functionArgs, + client: { + baseUrl: this.manager.connection.client.baseUrl, + }, + senderAddress: StacksZeroAddress, + }); + } +} + +export type StacksNttContracts = Ntt.Contracts & { + state: string; + tokenOwner: string; + transceiverState: { + [type: string]: string; + }; +}; + +export class StacksNtt + implements Ntt +{ + private readonly nttManagerDeployer: string; + private readonly nttStateContractName: string; + private readonly tokenOwnerContractName: string; + private readonly tokenAddress: string; + + constructor( + readonly network: N, + readonly chain: C, + readonly connection: StacksNetwork, + readonly contracts: Contracts & { ntt?: StacksNttContracts }, + readonly version: string = DEFAULT_NTT_VERSION + ) { + if (!contracts.ntt) { + throw new Error("NTT Contracts not found"); + } + + const manager = contracts.ntt.manager; + this.nttStateContractName = contracts?.ntt?.state; + this.tokenOwnerContractName = contracts?.ntt?.tokenOwner; + this.tokenAddress = contracts.ntt.token; + + if (manager?.startsWith("0x")) { + const utf8Manager = Buffer.from(manager.slice(2), "hex").toString( + "utf-8" + ); + const [deployer, managerName] = utf8Manager.split("."); + if (!deployer || !managerName) { + throw new Error("Invalid manager address format"); + } + this.nttManagerDeployer = deployer; + } else if (contracts.ntt.manager) { + const [deployer] = contracts.ntt.manager.split("."); + this.nttManagerDeployer = deployer || ""; + } else if (contracts.ntt.state) { + const [deployer] = contracts.ntt.state.split("."); + this.nttManagerDeployer = deployer || ""; + } else { + this.nttManagerDeployer = ""; + } + } + + async getMode(): Promise { + const res = await this.managerReadOnly("get-mode", []); + const modeValue = cvToValue(res); + return modeValue.value === "0x00" ? "locking" : "burning"; + } + + async getFullAddress(): Promise { + return (await this.getActiveNttManager()).full; + } + + async isPaused(): Promise { + const res = await this.managerReadOnly("is-paused", []); + return cvToValue(res); + } + + async *pause( + payer?: AccountAddress | undefined + ): AsyncGenerator> { + const activeNttManager = await this.getActiveNttManager(); + const tx = { + contractName: activeNttManager.contractName, + contractAddress: activeNttManager.address, + functionName: "pause", + functionArgs: [], + postConditionMode: PostConditionMode.Allow, + }; + yield { + transaction: tx, + network: this.network, + chain: this.chain, + description: "Ntt.pause", + parallelizable: false, + }; + } + + async *unpause( + payer?: AccountAddress | undefined + ): AsyncGenerator> { + const activeNttManager = await this.getActiveNttManager(); + const tx = { + contractName: activeNttManager.contractName, + contractAddress: activeNttManager.address, + functionName: "unpause", + functionArgs: [], + postConditionMode: PostConditionMode.Allow, + }; + yield { + transaction: tx, + network: this.network, + chain: this.chain, + description: "Ntt.unpause", + parallelizable: false, + }; + } + + /** + * We do noy have a `get-admin` or `get-owner` function. + * We'll optimistically assume that the deployer is the owner + * or throw an error if it's not. + */ + async getOwner(): Promise> { + const deployerNative = toNative(this.chain, this.nttManagerDeployer); + const isDeployerOwner = await this.isOwner(deployerNative); + if (isDeployerOwner) { + return deployerNative; + } + throw new Error("Method not implemented. Use isOwner instead"); + } + + async isOwner(account: AccountAddress): Promise { + const res = await this.managerReadOnly("is-admin", [ + Cl.address(account.toString()), + ]); + return cvToValue(res); + } + + async getPauser(): Promise | null> { + const res = await this.managerReadOnly("get-pauser", []); + return cvToValue(res); + } + + async *setOwner( + newOwner: AccountAddress, + payer?: AccountAddress | undefined + ): AsyncGenerator> { + const activeNttManager = await this.getActiveNttManager(); + const tx = { + contractName: activeNttManager.contractName, + contractAddress: activeNttManager.address, + functionName: "add-admin", + functionArgs: [Cl.address(newOwner.toString())], + postConditionMode: PostConditionMode.Allow, + }; + yield { + transaction: tx, + network: this.network, + chain: this.chain, + description: "Ntt.setOwner", + parallelizable: false, + }; + } + + async *removeOwner( + owner: AccountAddress, + payer?: AccountAddress | undefined + ): AsyncGenerator> { + const activeNttManager = await this.getActiveNttManager(); + const tx = { + contractName: activeNttManager.contractName, + contractAddress: activeNttManager.address, + functionName: "remove-admin", + functionArgs: [Cl.address(owner.toString())], + postConditionMode: PostConditionMode.Allow, + }; + yield { + transaction: tx, + network: this.network, + chain: this.chain, + description: "Ntt.removeOwner", + parallelizable: false, + }; + } + + setPauser( + newOwner: AccountAddress, + payer?: AccountAddress | undefined + ): AsyncGenerator> { + throw new Error("Method not implemented."); + } + + async getThreshold(): Promise { + return 1; + } + + async *setThreshold( + threshold: number, + payer?: AccountAddress + ): AsyncGenerator> { + throw new Error("Method not implemented."); + } + + async *setPeer( + peer: ChainAddress, + tokenDecimals: number, + inboundLimit: bigint, + payer?: AccountAddress | undefined + ): AsyncGenerator> { + const activeNttManager = await this.getActiveNttManager(); + const tx = { + contractName: activeNttManager.contractName, + contractAddress: activeNttManager.address, + functionName: "add-peer", + functionArgs: [ + StacksNtt.chainToClBuffer(peer.chain), + Cl.buffer(new UniversalAddress(peer.address.toString()).toUint8Array()), + ], + postConditionMode: PostConditionMode.Allow, + }; + + yield { + transaction: tx, + network: this.network, + chain: this.chain, + description: "Ntt.setPeer", + parallelizable: false, + }; + } + + async *setTransceiverPeer( + ix: number, + peer: ChainAddress, + payer?: AccountAddress | undefined + ): AsyncGenerator> { + const transceiver = await this.getTransceiver(0); + if (!transceiver) { + throw new Error("Transceiver for protocol 1 (Wormhole) not found"); + } + yield* transceiver.setPeer(peer); + } + + isRelayingAvailable(destination: Chain): Promise { + throw new Error("Method not implemented."); + } + + quoteDeliveryPrice( + destination: Chain, + options: Ntt.TransferOptions + ): Promise { + throw new Error("Method not implemented."); + } + + async *transfer( + sender: AccountAddress, + amount: bigint, + destination: ChainAddress, + options: Ntt.TransferOptions + ): AsyncGenerator> { + const transceiver = await this.getTransceiver(0); + if (!transceiver) { + throw new Error("Transceiver for protocol 1 (Wormhole) not found"); + } + const transceiverAddress = ( + await transceiver.getAddress() + ).address.toString(); + const activeNttManager = await this.getActiveNttManager(); + const tx = { + contractName: activeNttManager.contractName, + contractAddress: activeNttManager.address, + functionName: "send-token-transfer", + functionArgs: [ + Cl.address(this.tokenAddress), + Cl.address(transceiverAddress), + Cl.uint(amount), + StacksNtt.chainToClBuffer(destination.chain), + Cl.buffer( + new UniversalAddress(destination.address.toString()).toUint8Array() + ), + ], + postConditionMode: PostConditionMode.Allow, + }; + yield { + transaction: tx, + network: this.network, + chain: this.chain, + description: "Ntt.transfer", + parallelizable: false, + }; + } + + async *addr32RegisterPrincipal( + principal: string + ): AsyncGenerator> | boolean { + const addr32Address = ADDR32_CONTRACT[this.network]; + if (!addr32Address) { + throw new Error( + `Stacks NTT registerPrincipal for network ${this.network} not found` + ); + } + const [contractAddress, contractName] = addr32Address.split("."); + if (!contractAddress || !contractName) { + throw new Error( + `Stacks NTT registerPrincipal for network ${this.network} not found` + ); + } + const res = await this.readonly( + "reverse-lookup", + [Cl.principal(principal)], + contractName, + contractAddress + ); + + const resValue = cvToValue(res); + if (resValue.registered) { + return true; + } + + const tx = { + contractName, + contractAddress, + functionName: "register", + functionArgs: [Cl.principal(principal)], + postConditionMode: PostConditionMode.Allow, + }; + yield { + transaction: tx, + network: this.network, + chain: this.chain, + description: "Addr32.registerPrincipal", + parallelizable: false, + }; + } + + async addr32Lookup(hash: Uint8Array): Promise { + const addr32Address = ADDR32_CONTRACT[this.network]; + if (!addr32Address) { + throw new Error( + `Stacks NTT registerPrincipal for network ${this.network} not found` + ); + } + const [contractAddress, contractName] = addr32Address.split("."); + if (!contractAddress || !contractName) { + throw new Error( + `Stacks NTT registerPrincipal for network ${this.network} not found` + ); + } + + const res = await this.readonly( + "lookup", + [Cl.buffer(hash)], + contractName, + contractAddress + ); + + const resValue = cvToValue(res); + return resValue.value; + } + + async *redeem( + attestations: Ntt.Attestation[], + payer: AccountAddress, + recipient?: AccountAddress | undefined + ): AsyncGenerator> { + if (!recipient) { + throw new Error("Recipient address is required for Stacks redeem"); + } + + const transceiver = await this.getTransceiver(0); + if (!transceiver) { + throw new Error("Transceiver for protocol Wormhole not found"); + } + + // Register the recipient with the addr32 contract if not already registered + const recipientPrincipal = recipient.toString(); + const registrationResult = + await this.addr32RegisterPrincipal(recipientPrincipal); + + if (typeof registrationResult !== "boolean") { + yield* registrationResult; + } + + return yield* transceiver.receive(attestations[0]!); + } + + async getCustodyAddress(): Promise { + return this.getTokenOwnerContractAddress(); + } + + async getTokenDecimals(): Promise { + let tokenToQuery: string; + if (!this.tokenAddress) { + const token = await this.managerReadOnly("get-token-contract", []); + const tokenValue = cvToValue(token); + tokenToQuery = tokenValue.value; + } else { + tokenToQuery = this.tokenAddress; + } + const decimals = await StacksPlatform.getDecimals( + this.network, + this.chain, + this.connection, + toNative(this.chain, tokenToQuery) + ); + return decimals; + } + + async getPeer(chain: C): Promise | null> { + const res = await this.readonly( + "peers-get", + [StacksNtt.chainToClBuffer(chain)], + this.getStateContractName(), + this.nttManagerDeployer + ); + + const resValue = cvToValue(res); + if (!resValue) { + return null; + } + const address = new UniversalAddress(resValue.value); + return { + address: { + chain, + address, + }, + tokenDecimals: 0, + inboundLimit: 0n, + }; + } + + /** + * The current Stacks implementation has a single transceiver. + * Queried by protocol ID. Wormhole protocol ID is u1. Index is ignored. + */ + async getTransceiver( + index: number + ): Promise | null> { + const activeNttManager = await this.getActiveNttManager(); + const whProtocol = WORMHOLE_PROTOCOL_ID; + const res = await this.readonly( + "protocols-get", + [Cl.uint(whProtocol)], + this.getStateContractName(), + activeNttManager.address + ); + const resValue = cvToValue(res); + return new StacksNttWormholeTransceiver( + this, + this.tokenAddress, + resValue.value + ); + } + + async getActiveNttManager(): Promise<{ + full: string; + address: string; + contractName: string; + }> { + const res = await this.readonly( + "get-active-ntt-manager", + [], + this.getStateContractName(), + this.nttManagerDeployer + ); + const resValue = cvToValue(res); + const address = resValue.split(".")[0]!; + const contractName = resValue.split(".")[1]!; + return { + full: resValue, + address, + contractName, + }; + } + + getStateContractName(): string { + return ( + this.nttStateContractName?.split(".")[1] ?? + NTT_MANAGER_STATE_CONTRACT_NAME + ); + } + + getTokenOwnerContractAddress(): string { + return ( + this.tokenOwnerContractName ?? + `${this.nttManagerDeployer}.${NTT_TOKEN_OWNER_CONTRACT_NAME}` + ); + } + + // NOTE: v1 contract does not implement rate limiting + + getCurrentOutboundCapacity(): Promise { + throw new Error("Method not implemented."); + } + async getOutboundLimit(): Promise { + return 0n; + } + setOutboundLimit( + limit: bigint, + payer?: AccountAddress | undefined + ): AsyncGenerator> { + throw new Error("Method not implemented."); + } + getCurrentInboundCapacity(fromChain: Chain): Promise { + throw new Error("Method not implemented."); + } + async getRateLimitDuration(): Promise { + return 0n; + } + getInboundLimit(fromChain: Chain): Promise { + throw new Error("Method not implemented."); + } + setInboundLimit( + fromChain: Chain, + limit: bigint, + payer?: AccountAddress | undefined + ): AsyncGenerator> { + throw new Error("Method not implemented."); + } + getIsApproved(attestation: Ntt.Attestation): Promise { + return this.getIsExecuted(attestation); + } + + async getIsExecuted(attestation: Ntt.Attestation): Promise { + const payload = + attestation.payloadName === "WormholeTransfer" + ? attestation.payload + : attestation.payload["payload"]; + + const hash = Ntt.messageDigest( + attestation.emitterChain, + payload["nttManagerPayload"] + ); + const res = await this.readonly( + "consumed-messages-get", + [Cl.buffer(hash)], + this.getStateContractName(), + this.nttManagerDeployer + ); + const resValue = cvToValue(res); + return !!resValue; + } + + getIsTransferInboundQueued(attestation: Ntt.Attestation): Promise { + throw new Error("Method not implemented."); + } + async getInboundQueuedTransfer( + fromChain: Chain, + transceiverMessage: Ntt.Message + ): Promise | null> { + return null; + } + completeInboundQueuedTransfer( + fromChain: Chain, + transceiverMessage: Ntt.Message, + payer: AccountAddress + ): AsyncGenerator> { + throw new Error("Method not implemented."); + } + async verifyAddresses(): Promise | null> { + try { + const local: Partial = { + manager: this.contracts.ntt!.manager, + token: this.contracts.ntt!.token, + transceiver: this.contracts.ntt!.transceiver || {}, + }; + + const deployerAddress = this.nttManagerDeployer; + + const remoteStateAddress = `${deployerAddress}.${NTT_MANAGER_STATE_CONTRACT_NAME}`; + const remote: Partial = { + manager: this.contracts.ntt!.manager, + token: cvToValue( + await this.managerReadOnly( + "get-token-contract", + [], + `${deployerAddress}.${NTT_MANAGER_CONTRACT_NAME}` + ) + ).value, + transceiver: { + wormhole: cvToValue( + await this.readonly( + "protocols-get", + [Cl.uint(WORMHOLE_PROTOCOL_ID)], + NTT_MANAGER_STATE_CONTRACT_NAME, + deployerAddress + ) + ).value, + }, + state: remoteStateAddress, + }; + + const deleteMatching = (a: any, b: any): void => { + for (const k in a) { + if ( + typeof a[k] === "object" && + a[k] !== null && + typeof b[k] === "object" && + b[k] !== null + ) { + deleteMatching(a[k], b[k]); + if (Object.keys(a[k]).length === 0) delete a[k]; + } else if (a[k] === b[k]) { + delete a[k]; + } + } + }; + + deleteMatching(remote, local); + + return Object.keys(remote).length > 0 ? remote : null; + } catch (e) { + return null; + } + } + + static async getVersion(): Promise { + return DEFAULT_NTT_VERSION; + } + + static async fromRpc( + connection: StacksNetwork, + config: ChainsConfig + ): Promise> { + const [network, chain] = await StacksPlatform.chainFromRpc(connection); + const version = await StacksNtt.getVersion(); + const chainConfig = config[chain]; + if (!chainConfig) { + throw new Error(`Missing ChainsConfig for chain ${chain} on Stacks`); + } + return new StacksNtt( + network as N, + chain, + connection, + chainConfig.contracts, + version + ); + } + + static chainToClBuffer(chain: Chain): BufferCV { + return Cl.buffer(encoding.bignum.toBytes(toChainId(chain), 2)); + } + + private async managerReadOnly( + functionName: string, + functionArgs: any[], + manager?: string + ): Promise { + const activeNttManager = !!manager + ? { + contractName: manager.split(".")[1]!, + address: manager.split(".")[0]!, + } + : await this.getActiveNttManager(); + return this.readonly( + functionName, + functionArgs, + activeNttManager.contractName, + activeNttManager.address + ); + } + + private readonly( + functionName: string, + functionArgs: any[], + contractName: string, + contractAddress: string + ): Promise { + return fetchCallReadOnlyFunction({ + contractName: contractName, + contractAddress: contractAddress, + functionName, + functionArgs, + client: { + baseUrl: this.connection.client.baseUrl, + }, + senderAddress: StacksZeroAddress, + }); + } +} diff --git a/stacks/ts/src/nttWithExecutor.ts b/stacks/ts/src/nttWithExecutor.ts new file mode 100644 index 000000000..2f163b189 --- /dev/null +++ b/stacks/ts/src/nttWithExecutor.ts @@ -0,0 +1,189 @@ +import type { Network } from "@wormhole-foundation/sdk-base"; +import { chainToChainId } from "@wormhole-foundation/sdk-base"; +import { + Contracts, + UniversalAddress, + type AccountAddress, + type ChainAddress, + type ChainsConfig, +} from "@wormhole-foundation/sdk-definitions"; +import { NttWithExecutor } from "@wormhole-foundation/sdk-definitions-ntt"; +import { + StacksAddress, + StacksChains, + StacksPlatform, + StacksUnsignedTransaction, + type StacksPlatformType, +} from "@wormhole-foundation/sdk-stacks"; +import { StacksNetwork } from "@stacks/network"; +import { + bufferCV, + ContractCallOptions, + contractPrincipalCV, + PostConditionMode, + standardPrincipalCV, + uintCV, +} from "@stacks/transactions"; +import axios from "axios"; +import { StacksNtt, StacksNttContracts } from "./ntt.js"; +import { amount } from "@wormhole-foundation/sdk-base"; + +const nttManagerWithExecutorAddresses: Partial< + Record>> +> = { + Mainnet: { + // TODO: Add mainnet executor address + }, + Testnet: { + Stacks: + "ST36CY4MQNM6KM52EV9KN56KJXQCPXT5B8RH6B0J5.ntt-manager-with-executor-v7", + }, +}; + +export class StacksNttWithExecutor + implements NttWithExecutor +{ + readonly executorAddress: string; + + constructor( + readonly network: N, + readonly chain: C, + readonly connection: StacksNetwork, + readonly contracts: Contracts & { ntt?: StacksNttContracts } + ) { + const executorAddress = + nttManagerWithExecutorAddresses[this.network]?.[this.chain]; + if (!executorAddress) { + throw new Error(`Executor address not found for chain ${this.chain}`); + } + this.executorAddress = executorAddress; + } + + static async fromRpc( + connection: StacksNetwork, + config: ChainsConfig + ): Promise> { + const [network, chain] = await StacksPlatform.chainFromRpc(connection); + const conf = config[chain]!; + if (conf.network !== network) { + throw new Error(`Network mismatch: ${conf.network} != ${network}`); + } + + return new StacksNttWithExecutor( + network as N, + chain, + connection, + conf.contracts + ); + } + + async *transfer( + sender: AccountAddress, + destination: ChainAddress, + amount: bigint, + quote: NttWithExecutor.Quote, + ntt: StacksNtt, + _wrapNative: boolean = false + ): AsyncGenerator> { + const destinationChainId = chainToChainId(destination.chain); + + const executorAddressSplit = this.executorAddress.split("."); + const executorDeployer = executorAddressSplit[0]!; + const executorContractName = executorAddressSplit[1]!; + + const managerFullAddress = await ntt.getFullAddress(); + const managerSplit = managerFullAddress.split("."); + const managerDeployer = managerSplit[0]!; + const managerContractName = managerSplit[1]!; + + const tokenAddress = this.contracts.ntt!.token; + const tokenSplit = tokenAddress.split("."); + const tokenDeployer = tokenSplit[0]!; + const tokenContractName = tokenSplit[1]!; + + const transceiver = await ntt.getTransceiver(0); + if (!transceiver) { + throw new Error("Transceiver not found"); + } + const transceiverAddress = ( + await transceiver.getAddress() + ).address.toString(); + const transceiverSplit = transceiverAddress.split("."); + const transceiverDeployer = transceiverSplit[0]!; + const transceiverContractName = transceiverSplit[1]!; + + const recipientBytes32 = new UniversalAddress( + destination.address.toString() + ).toUint8Array(); + + const referrerAddress = quote.referrer.address.toString(); + + const tx: ContractCallOptions = { + contractName: executorContractName, + contractAddress: executorDeployer, + functionName: "transfer", + functionArgs: [ + contractPrincipalCV(managerDeployer, managerContractName), + contractPrincipalCV(tokenDeployer, tokenContractName), + contractPrincipalCV(transceiverDeployer, transceiverContractName), + uintCV(amount.toString()), + uintCV(destinationChainId), + bufferCV(recipientBytes32), + uintCV(quote.estimatedCost.toString()), + standardPrincipalCV(sender.toString()), // executor-refund-address + bufferCV(Buffer.from(quote.signedQuote)), + bufferCV(Buffer.from(quote.relayInstructions)), + uintCV(quote.referrerFeeDbps.toString()), + standardPrincipalCV(referrerAddress), + ], + postConditionMode: PostConditionMode.Allow, + }; + + yield { + transaction: tx, + network: this.network, + chain: this.chain, + description: "NttWithExecutor.transfer", + parallelizable: false, + }; + } + + async estimateMsgValueAndGasLimit( + _recipient: ChainAddress | undefined + ): Promise<{ msgValue: bigint; gasLimit: bigint }> { + const msgValue = 0n; + + // TODO: tweak this value for mainnet if needed + const gasLimit = amount.units(amount.parse("0.1", 6)); // 0.1 STX + + return { msgValue, gasLimit }; + } + + static async getManagerAddressFromTx( + connection: StacksNetwork, + txHash: string + ): Promise> { + const url = `${connection.client.baseUrl}/extended/v1/tx/${txHash}`; + + const response = await axios.get(url); + const data = response.data; + + if (!data.contract_call?.function_args) { + throw new Error("No contract call function args found in transaction"); + } + + const functionArgs = data.contract_call.function_args; + const nttManagerArg = functionArgs.find( + (arg: any) => arg.name === "ntt-manager" + ); + + if (!nttManagerArg) { + throw new Error("No ntt-manager argument found in transaction"); + } + + // The value comes with a leading quote, because it's a trait_reference type + const managerAddress = nttManagerArg.repr.replace(/^'/, ""); + + return { chain: "Stacks", address: new StacksAddress(managerAddress) }; + } +} diff --git a/stacks/ts/tsconfig.cjs.json b/stacks/ts/tsconfig.cjs.json new file mode 100644 index 000000000..411c4c5b7 --- /dev/null +++ b/stacks/ts/tsconfig.cjs.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.cjs.json", + "include": ["src"], + "exclude": ["src/transferTest.ts"], + "compilerOptions": { + "outDir": "dist/cjs", + "rootDir": "src" + } +} diff --git a/stacks/ts/tsconfig.esm.json b/stacks/ts/tsconfig.esm.json new file mode 100644 index 000000000..d877364d7 --- /dev/null +++ b/stacks/ts/tsconfig.esm.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.esm.json", + "include": ["src"], + "exclude": ["src/transferTest.ts"], + "compilerOptions": { + "outDir": "dist/esm", + "rootDir": "src" + } +} diff --git a/stacks/ts/tsconfig.test.json b/stacks/ts/tsconfig.test.json new file mode 100644 index 000000000..55b1793db --- /dev/null +++ b/stacks/ts/tsconfig.test.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src/**/*.ts"], + "compilerOptions": { + "module": "NodeNext", + "moduleResolution": "NodeNext", + "allowUnreachableCode": true, + "allowUnusedLabels": true, + "noUnusedLocals": false + } +} diff --git a/sui/ts/README.md b/sui/ts/README.md new file mode 100644 index 000000000..df75b46a6 --- /dev/null +++ b/sui/ts/README.md @@ -0,0 +1,3 @@ +## Sui Ntt Implementation + +> **Note:** These are low-level protocol classes. If you are trying to perform a transfer, use the higher-level Route abstractions such as [`NttExecutorRoute`](../../sdk/route/src/executor/executor.ts) instead. diff --git a/sui/ts/src/ntt.ts b/sui/ts/src/ntt.ts index cd6fd87c5..bb59c66ef 100644 --- a/sui/ts/src/ntt.ts +++ b/sui/ts/src/ntt.ts @@ -889,7 +889,8 @@ export class SuiNtt async *redeem( attestations: Ntt.Attestation[], - payer?: AccountAddress + payer: AccountAddress, + recipient?: AccountAddress ): AsyncGenerator> { // Check if paused const isPaused = await this.isPaused(); @@ -1300,7 +1301,7 @@ export class SuiNtt async *completeInboundQueuedTransfer( fromChain: PC, transceiverMessage: Ntt.Message, - payer?: AccountAddress + payer: AccountAddress ): AsyncGenerator> { // Check if paused const isPaused = await this.isPaused();