@matrix-privacy/wallet 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +73 -0
- package/.prettierrc.js +21 -0
- package/LICENSE +21 -0
- package/README.md +7 -0
- package/dist/__tests__/index.test.d.ts +1 -0
- package/dist/__tests__/index.test.js +13 -0
- package/dist/__tests__/index.test.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/services/artifacts/__tests__/artifact-downloader.test.d.ts +1 -0
- package/dist/services/artifacts/__tests__/artifact-downloader.test.js +172 -0
- package/dist/services/artifacts/__tests__/artifact-downloader.test.js.map +1 -0
- package/dist/services/artifacts/artifact-downloader.d.ts +13 -0
- package/dist/services/artifacts/artifact-downloader.js +142 -0
- package/dist/services/artifacts/artifact-downloader.js.map +1 -0
- package/dist/services/artifacts/artifact-hash.d.ts +3 -0
- package/dist/services/artifacts/artifact-hash.js +53 -0
- package/dist/services/artifacts/artifact-hash.js.map +1 -0
- package/dist/services/artifacts/artifact-store.d.ts +11 -0
- package/dist/services/artifacts/artifact-store.js +15 -0
- package/dist/services/artifacts/artifact-store.js.map +1 -0
- package/dist/services/artifacts/artifact-util.d.ts +7 -0
- package/dist/services/artifacts/artifact-util.js +64 -0
- package/dist/services/artifacts/artifact-util.js.map +1 -0
- package/dist/services/artifacts/index.d.ts +2 -0
- package/dist/services/artifacts/index.js +19 -0
- package/dist/services/artifacts/index.js.map +1 -0
- package/dist/services/artifacts/json/artifact-v2-hashes.json +467 -0
- package/dist/services/ethers/__tests__/ethers-util.test.d.ts +1 -0
- package/dist/services/ethers/__tests__/ethers-util.test.js +19 -0
- package/dist/services/ethers/__tests__/ethers-util.test.js.map +1 -0
- package/dist/services/ethers/ethers-util.d.ts +1 -0
- package/dist/services/ethers/ethers-util.js +9 -0
- package/dist/services/ethers/ethers-util.js.map +1 -0
- package/dist/services/ethers/index.d.ts +1 -0
- package/dist/services/ethers/index.js +18 -0
- package/dist/services/ethers/index.js.map +1 -0
- package/dist/services/index.d.ts +4 -0
- package/dist/services/index.js +21 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/matrix/core/__tests__/engine.test.d.ts +1 -0
- package/dist/services/matrix/core/__tests__/engine.test.js +30 -0
- package/dist/services/matrix/core/__tests__/engine.test.js.map +1 -0
- package/dist/services/matrix/core/__tests__/providers.test.d.ts +1 -0
- package/dist/services/matrix/core/__tests__/providers.test.js +54 -0
- package/dist/services/matrix/core/__tests__/providers.test.js.map +1 -0
- package/dist/services/matrix/core/artifacts.d.ts +10 -0
- package/dist/services/matrix/core/artifacts.js +70 -0
- package/dist/services/matrix/core/artifacts.js.map +1 -0
- package/dist/services/matrix/core/engine.d.ts +4 -0
- package/dist/services/matrix/core/engine.js +21 -0
- package/dist/services/matrix/core/engine.js.map +1 -0
- package/dist/services/matrix/core/index.d.ts +8 -0
- package/dist/services/matrix/core/index.js +25 -0
- package/dist/services/matrix/core/index.js.map +1 -0
- package/dist/services/matrix/core/init.d.ts +21 -0
- package/dist/services/matrix/core/init.js +79 -0
- package/dist/services/matrix/core/init.js.map +1 -0
- package/dist/services/matrix/core/load-provider.d.ts +9 -0
- package/dist/services/matrix/core/load-provider.js +100 -0
- package/dist/services/matrix/core/load-provider.js.map +1 -0
- package/dist/services/matrix/core/merkletree.d.ts +5 -0
- package/dist/services/matrix/core/merkletree.js +40 -0
- package/dist/services/matrix/core/merkletree.js.map +1 -0
- package/dist/services/matrix/core/prover.d.ts +3 -0
- package/dist/services/matrix/core/prover.js +14 -0
- package/dist/services/matrix/core/prover.js.map +1 -0
- package/dist/services/matrix/core/providers.d.ts +9 -0
- package/dist/services/matrix/core/providers.js +31 -0
- package/dist/services/matrix/core/providers.js.map +1 -0
- package/dist/services/matrix/core/shields.d.ts +11 -0
- package/dist/services/matrix/core/shields.js +24 -0
- package/dist/services/matrix/core/shields.js.map +1 -0
- package/dist/services/matrix/history/__tests__/transaction-history.test.d.ts +1 -0
- package/dist/services/matrix/history/__tests__/transaction-history.test.js +249 -0
- package/dist/services/matrix/history/__tests__/transaction-history.test.js.map +1 -0
- package/dist/services/matrix/history/transaction-history.d.ts +4 -0
- package/dist/services/matrix/history/transaction-history.js +182 -0
- package/dist/services/matrix/history/transaction-history.js.map +1 -0
- package/dist/services/matrix/index.d.ts +4 -0
- package/dist/services/matrix/index.js +21 -0
- package/dist/services/matrix/index.js.map +1 -0
- package/dist/services/matrix/process/extract-transaction-data.d.ts +3 -0
- package/dist/services/matrix/process/extract-transaction-data.js +19 -0
- package/dist/services/matrix/process/extract-transaction-data.js.map +1 -0
- package/dist/services/matrix/process/index.d.ts +1 -0
- package/dist/services/matrix/process/index.js +18 -0
- package/dist/services/matrix/process/index.js.map +1 -0
- package/dist/services/matrix/quick-sync/V3/__tests__/quick-sync-events-graph-v3.test.d.ts +1 -0
- package/dist/services/matrix/quick-sync/V3/__tests__/quick-sync-events-graph-v3.test.js +56 -0
- package/dist/services/matrix/quick-sync/V3/__tests__/quick-sync-events-graph-v3.test.js.map +1 -0
- package/dist/services/matrix/quick-sync/V3/graph-type-formatters-v3.d.ts +8 -0
- package/dist/services/matrix/quick-sync/V3/graph-type-formatters-v3.js +103 -0
- package/dist/services/matrix/quick-sync/V3/graph-type-formatters-v3.js.map +1 -0
- package/dist/services/matrix/quick-sync/V3/graphql/.graphclient/sources/mumbai/introspectionSchema.d.ts +2 -0
- package/dist/services/matrix/quick-sync/V3/graphql/.graphclient/sources/mumbai/introspectionSchema.js +19861 -0
- package/dist/services/matrix/quick-sync/V3/graphql/.graphclient/sources/mumbai/introspectionSchema.js.map +1 -0
- package/dist/services/matrix/quick-sync/V3/graphql/.graphclient/sources/mumbai/types.d.ts +1352 -0
- package/dist/services/matrix/quick-sync/V3/graphql/.graphclient/sources/mumbai/types.js +4 -0
- package/dist/services/matrix/quick-sync/V3/graphql/.graphclient/sources/mumbai/types.js.map +1 -0
- package/dist/services/matrix/quick-sync/V3/graphql/index.d.ts +1680 -0
- package/dist/services/matrix/quick-sync/V3/graphql/index.js +348 -0
- package/dist/services/matrix/quick-sync/V3/graphql/index.js.map +1 -0
- package/dist/services/matrix/quick-sync/V3/quick-sync-events-graph-v3.d.ts +2 -0
- package/dist/services/matrix/quick-sync/V3/quick-sync-events-graph-v3.js +99 -0
- package/dist/services/matrix/quick-sync/V3/quick-sync-events-graph-v3.js.map +1 -0
- package/dist/services/matrix/quick-sync/graph-query.d.ts +5 -0
- package/dist/services/matrix/quick-sync/graph-query.js +26 -0
- package/dist/services/matrix/quick-sync/graph-query.js.map +1 -0
- package/dist/services/matrix/quick-sync/quick-sync-events.d.ts +2 -0
- package/dist/services/matrix/quick-sync/quick-sync-events.js +9 -0
- package/dist/services/matrix/quick-sync/quick-sync-events.js.map +1 -0
- package/dist/services/matrix/quick-sync/shared-formatters.d.ts +8 -0
- package/dist/services/matrix/quick-sync/shared-formatters.js +36 -0
- package/dist/services/matrix/quick-sync/shared-formatters.js.map +1 -0
- package/dist/services/matrix/util/__tests__/bytes-util.test.d.ts +1 -0
- package/dist/services/matrix/util/__tests__/bytes-util.test.js +23 -0
- package/dist/services/matrix/util/__tests__/bytes-util.test.js.map +1 -0
- package/dist/services/matrix/util/__tests__/crypto-util.test.d.ts +1 -0
- package/dist/services/matrix/util/__tests__/crypto-util.test.js +62 -0
- package/dist/services/matrix/util/__tests__/crypto-util.test.js.map +1 -0
- package/dist/services/matrix/util/bytes.d.ts +5 -0
- package/dist/services/matrix/util/bytes.js +22 -0
- package/dist/services/matrix/util/bytes.js.map +1 -0
- package/dist/services/matrix/util/crypto.d.ts +14 -0
- package/dist/services/matrix/util/crypto.js +80 -0
- package/dist/services/matrix/util/crypto.js.map +1 -0
- package/dist/services/matrix/util/graph-util.d.ts +3 -0
- package/dist/services/matrix/util/graph-util.js +13 -0
- package/dist/services/matrix/util/graph-util.js.map +1 -0
- package/dist/services/matrix/util/index.d.ts +2 -0
- package/dist/services/matrix/util/index.js +19 -0
- package/dist/services/matrix/util/index.js.map +1 -0
- package/dist/services/matrix/util/runtime.d.ts +2 -0
- package/dist/services/matrix/util/runtime.js +8 -0
- package/dist/services/matrix/util/runtime.js.map +1 -0
- package/dist/services/matrix/wallets/__tests__/balances-live.test.d.ts +1 -0
- package/dist/services/matrix/wallets/__tests__/balances-live.test.js +48 -0
- package/dist/services/matrix/wallets/__tests__/balances-live.test.js.map +1 -0
- package/dist/services/matrix/wallets/__tests__/balances-update.test.d.ts +1 -0
- package/dist/services/matrix/wallets/__tests__/balances-update.test.js +85 -0
- package/dist/services/matrix/wallets/__tests__/balances-update.test.js.map +1 -0
- package/dist/services/matrix/wallets/__tests__/balances.test.d.ts +1 -0
- package/dist/services/matrix/wallets/__tests__/balances.test.js +59 -0
- package/dist/services/matrix/wallets/__tests__/balances.test.js.map +1 -0
- package/dist/services/matrix/wallets/__tests__/wallets.test.d.ts +1 -0
- package/dist/services/matrix/wallets/__tests__/wallets.test.js +80 -0
- package/dist/services/matrix/wallets/__tests__/wallets.test.js.map +1 -0
- package/dist/services/matrix/wallets/balance-update.d.ts +10 -0
- package/dist/services/matrix/wallets/balance-update.js +126 -0
- package/dist/services/matrix/wallets/balance-update.js.map +1 -0
- package/dist/services/matrix/wallets/balances.d.ts +3 -0
- package/dist/services/matrix/wallets/balances.js +32 -0
- package/dist/services/matrix/wallets/balances.js.map +1 -0
- package/dist/services/matrix/wallets/index.d.ts +4 -0
- package/dist/services/matrix/wallets/index.js +21 -0
- package/dist/services/matrix/wallets/index.js.map +1 -0
- package/dist/services/matrix/wallets/wallets.d.ts +22 -0
- package/dist/services/matrix/wallets/wallets.js +252 -0
- package/dist/services/matrix/wallets/wallets.js.map +1 -0
- package/dist/services/transactions/__tests__/json/formatted-relay-adapt-error-logs.json +216 -0
- package/dist/services/transactions/__tests__/proof-cache.test.d.ts +1 -0
- package/dist/services/transactions/__tests__/proof-cache.test.js +114 -0
- package/dist/services/transactions/__tests__/proof-cache.test.js.map +1 -0
- package/dist/services/transactions/__tests__/tx-cross-contract-calls.test.d.ts +1 -0
- package/dist/services/transactions/__tests__/tx-cross-contract-calls.test.js +376 -0
- package/dist/services/transactions/__tests__/tx-cross-contract-calls.test.js.map +1 -0
- package/dist/services/transactions/__tests__/tx-gas-details.test.d.ts +1 -0
- package/dist/services/transactions/__tests__/tx-gas-details.test.js +109 -0
- package/dist/services/transactions/__tests__/tx-gas-details.test.js.map +1 -0
- package/dist/services/transactions/__tests__/tx-notes.test.d.ts +1 -0
- package/dist/services/transactions/__tests__/tx-notes.test.js +193 -0
- package/dist/services/transactions/__tests__/tx-notes.test.js.map +1 -0
- package/dist/services/transactions/__tests__/tx-shield-base-token.test.d.ts +1 -0
- package/dist/services/transactions/__tests__/tx-shield-base-token.test.js +99 -0
- package/dist/services/transactions/__tests__/tx-shield-base-token.test.js.map +1 -0
- package/dist/services/transactions/__tests__/tx-shield.test.d.ts +1 -0
- package/dist/services/transactions/__tests__/tx-shield.test.js +146 -0
- package/dist/services/transactions/__tests__/tx-shield.test.js.map +1 -0
- package/dist/services/transactions/__tests__/tx-transfer.test.d.ts +1 -0
- package/dist/services/transactions/__tests__/tx-transfer.test.js +263 -0
- package/dist/services/transactions/__tests__/tx-transfer.test.js.map +1 -0
- package/dist/services/transactions/__tests__/tx-unshield.test.d.ts +1 -0
- package/dist/services/transactions/__tests__/tx-unshield.test.js +759 -0
- package/dist/services/transactions/__tests__/tx-unshield.test.js.map +1 -0
- package/dist/services/transactions/index.d.ts +13 -0
- package/dist/services/transactions/index.js +30 -0
- package/dist/services/transactions/index.js.map +1 -0
- package/dist/services/transactions/proof-cache.d.ts +27 -0
- package/dist/services/transactions/proof-cache.js +130 -0
- package/dist/services/transactions/proof-cache.js.map +1 -0
- package/dist/services/transactions/tx-cross-contract-calls.d.ts +12 -0
- package/dist/services/transactions/tx-cross-contract-calls.js +210 -0
- package/dist/services/transactions/tx-cross-contract-calls.js.map +1 -0
- package/dist/services/transactions/tx-gas-broadcaster-fee-estimator.d.ts +5 -0
- package/dist/services/transactions/tx-gas-broadcaster-fee-estimator.js +110 -0
- package/dist/services/transactions/tx-gas-broadcaster-fee-estimator.js.map +1 -0
- package/dist/services/transactions/tx-gas-details.d.ts +5 -0
- package/dist/services/transactions/tx-gas-details.js +101 -0
- package/dist/services/transactions/tx-gas-details.js.map +1 -0
- package/dist/services/transactions/tx-generator.d.ts +13 -0
- package/dist/services/transactions/tx-generator.js +168 -0
- package/dist/services/transactions/tx-generator.js.map +1 -0
- package/dist/services/transactions/tx-notes.d.ts +11 -0
- package/dist/services/transactions/tx-notes.js +153 -0
- package/dist/services/transactions/tx-notes.js.map +1 -0
- package/dist/services/transactions/tx-nullifiers.d.ts +2 -0
- package/dist/services/transactions/tx-nullifiers.js +17 -0
- package/dist/services/transactions/tx-nullifiers.js.map +1 -0
- package/dist/services/transactions/tx-proof-transfer.d.ts +3 -0
- package/dist/services/transactions/tx-proof-transfer.js +39 -0
- package/dist/services/transactions/tx-proof-transfer.js.map +1 -0
- package/dist/services/transactions/tx-proof-unshield.d.ts +5 -0
- package/dist/services/transactions/tx-proof-unshield.js +132 -0
- package/dist/services/transactions/tx-proof-unshield.js.map +1 -0
- package/dist/services/transactions/tx-shield-base-token.d.ts +3 -0
- package/dist/services/transactions/tx-shield-base-token.js +55 -0
- package/dist/services/transactions/tx-shield-base-token.js.map +1 -0
- package/dist/services/transactions/tx-shield.d.ts +6 -0
- package/dist/services/transactions/tx-shield.js +77 -0
- package/dist/services/transactions/tx-shield.js.map +1 -0
- package/dist/services/transactions/tx-transfer.d.ts +3 -0
- package/dist/services/transactions/tx-transfer.js +39 -0
- package/dist/services/transactions/tx-transfer.js.map +1 -0
- package/dist/services/transactions/tx-unshield.d.ts +11 -0
- package/dist/services/transactions/tx-unshield.js +224 -0
- package/dist/services/transactions/tx-unshield.js.map +1 -0
- package/dist/tests/local-e2e.d.ts +13 -0
- package/dist/tests/local-e2e.js +487 -0
- package/dist/tests/local-e2e.js.map +1 -0
- package/dist/tests/mocks.test.d.ts +40 -0
- package/dist/tests/mocks.test.js +171 -0
- package/dist/tests/mocks.test.js.map +1 -0
- package/dist/tests/setup.test.d.ts +7 -0
- package/dist/tests/setup.test.js +88 -0
- package/dist/tests/setup.test.js.map +1 -0
- package/dist/tests/stubs/engine-stubs.test.d.ts +7 -0
- package/dist/tests/stubs/engine-stubs.test.js +72 -0
- package/dist/tests/stubs/engine-stubs.test.js.map +1 -0
- package/dist/utils/__tests__/blocked-address.test.d.ts +1 -0
- package/dist/utils/__tests__/blocked-address.test.js +23 -0
- package/dist/utils/__tests__/blocked-address.test.js.map +1 -0
- package/dist/utils/__tests__/logger.test.d.ts +1 -0
- package/dist/utils/__tests__/logger.test.js +28 -0
- package/dist/utils/__tests__/logger.test.js.map +1 -0
- package/dist/utils/__tests__/utils.test.d.ts +1 -0
- package/dist/utils/__tests__/utils.test.js +21 -0
- package/dist/utils/__tests__/utils.test.js.map +1 -0
- package/dist/utils/blocked-address.d.ts +2 -0
- package/dist/utils/blocked-address.js +17 -0
- package/dist/utils/blocked-address.js.map +1 -0
- package/dist/utils/error.d.ts +1 -0
- package/dist/utils/error.js +20 -0
- package/dist/utils/error.js.map +1 -0
- package/dist/utils/gas-price.d.ts +6 -0
- package/dist/utils/gas-price.js +19 -0
- package/dist/utils/gas-price.js.map +1 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.js +19 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +3 -0
- package/dist/utils/logger.js +21 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/utils.d.ts +4 -0
- package/dist/utils/utils.js +54 -0
- package/dist/utils/utils.js.map +1 -0
- package/package.json +94 -0
- package/postinstall.js +52 -0
- package/react-native-shims.js +42 -0
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/// <reference types="../types/global" />
|
|
3
|
+
/* eslint-disable no-plusplus, no-await-in-loop, @typescript-eslint/no-floating-promises, @typescript-eslint/restrict-template-expressions, @typescript-eslint/strict-boolean-expressions, import/no-extraneous-dependencies */
|
|
4
|
+
/**
|
|
5
|
+
* Local E2E test for Matrix wallet against a local Ganache/Hardhat node.
|
|
6
|
+
*
|
|
7
|
+
* Prerequisites:
|
|
8
|
+
* 1. Start local node: ./ganache.sh (or: npx hardhat node)
|
|
9
|
+
* 2. Deploy contracts: cd matrix-contracts && yarn hardhat deploy:full --network localhost
|
|
10
|
+
* 3. Fill in deployed addresses in wallet/local-deploy.json.example
|
|
11
|
+
* (also set "mnemonic" and "userPrivateKey" matching your local node)
|
|
12
|
+
*
|
|
13
|
+
* Run:
|
|
14
|
+
* cd wallet && npx ts-node -P tsconfig.test.json src/tests/local-e2e.ts
|
|
15
|
+
*/
|
|
16
|
+
/* eslint-disable no-console */
|
|
17
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
18
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
const fs_1 = __importDefault(require("fs"));
|
|
22
|
+
const path_1 = __importDefault(require("path"));
|
|
23
|
+
const leveldown_1 = __importDefault(require("leveldown"));
|
|
24
|
+
const ethers_1 = require("ethers");
|
|
25
|
+
const snarkjs_1 = require("snarkjs");
|
|
26
|
+
const shared_models_1 = require("@matrix-privacy/shared-models");
|
|
27
|
+
const engine_1 = require("@matrix-privacy/engine");
|
|
28
|
+
const core_1 = require("../services/matrix/core");
|
|
29
|
+
const wallets_1 = require("../services/matrix/wallets/wallets");
|
|
30
|
+
const balance_update_1 = require("../services/matrix/wallets/balance-update");
|
|
31
|
+
const tx_shield_1 = require("../services/transactions/tx-shield");
|
|
32
|
+
const tx_proof_transfer_1 = require("../services/transactions/tx-proof-transfer");
|
|
33
|
+
const tx_transfer_1 = require("../services/transactions/tx-transfer");
|
|
34
|
+
const tx_proof_unshield_1 = require("../services/transactions/tx-proof-unshield");
|
|
35
|
+
const tx_unshield_1 = require("../services/transactions/tx-unshield");
|
|
36
|
+
const artifact_store_1 = require("../services/artifacts/artifact-store");
|
|
37
|
+
const utils_1 = require("../utils");
|
|
38
|
+
// ============================================================
|
|
39
|
+
// Configuration
|
|
40
|
+
// ============================================================
|
|
41
|
+
const WALLET_ROOT = path_1.default.resolve(__dirname, '../..');
|
|
42
|
+
const CONFIG_PATH = path_1.default.resolve(WALLET_ROOT, 'local-deploy.json');
|
|
43
|
+
const CONFIG_PATH_EXAMPLE = path_1.default.resolve(WALLET_ROOT, 'local-deploy.json.example');
|
|
44
|
+
const DB_PATH = path_1.default.resolve(WALLET_ROOT, 'local-e2e.db');
|
|
45
|
+
const ARTIFACTS_DIR = path_1.default.resolve(WALLET_ROOT, 'local-e2e-artifacts');
|
|
46
|
+
// Defaults (Ganache) — overridden by config file fields "userPrivateKey" / "mnemonic"
|
|
47
|
+
// Using account[2] — account[0] is deployer, account[1] is treasury
|
|
48
|
+
const DEFAULT_USER_PRIVATE_KEY = '0xb9bf8d5cedb05765c054f80b69ba7770721b858deb51fc78a8c6962daab4b316'; // Ganache account[2]
|
|
49
|
+
const DEFAULT_MNEMONIC = 'tube level toe forget impulse absorb travel during coach option round coyote';
|
|
50
|
+
const DB_ENCRYPTION_KEY = '0101010101010101010101010101010101010101010101010101010101010101';
|
|
51
|
+
const SHIELD_AMOUNT = ethers_1.ethers.parseEther('1.0'); // 1 WETH
|
|
52
|
+
const TRANSFER_AMOUNT = ethers_1.ethers.parseEther('0.4'); // private transfer amount
|
|
53
|
+
const UNSHIELD_AMOUNT = ethers_1.ethers.parseEther('0.1'); // unshield amount
|
|
54
|
+
// ============================================================
|
|
55
|
+
// Helpers
|
|
56
|
+
// ============================================================
|
|
57
|
+
const fileExists = (filePath) => fs_1.default.promises.access(filePath).then(() => true).catch(() => false);
|
|
58
|
+
const rmDirSafe = async (dir) => {
|
|
59
|
+
if (await fileExists(dir)) {
|
|
60
|
+
await fs_1.default.promises.rm(dir, { recursive: true });
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
const step = (n, msg) => console.log(`\n${'='.repeat(60)}\n Step ${n}: ${msg}\n${'='.repeat(60)}`);
|
|
64
|
+
const info = (msg) => console.log(` [INFO] ${msg}`);
|
|
65
|
+
const ok = (msg) => console.log(` [OK] ${msg}`);
|
|
66
|
+
const fail = (msg) => console.error(` [FAIL] ${msg}`);
|
|
67
|
+
// Minimal WETH9 ABI
|
|
68
|
+
const WETH9_ABI = [
|
|
69
|
+
'function deposit() payable',
|
|
70
|
+
'function approve(address spender, uint256 amount) returns (bool)',
|
|
71
|
+
'function balanceOf(address owner) view returns (uint256)',
|
|
72
|
+
];
|
|
73
|
+
/** Wait for a merkletree scan cycle to complete. */
|
|
74
|
+
const waitForScan = async (timeoutMs = 30000) => {
|
|
75
|
+
return new Promise((resolve) => {
|
|
76
|
+
let done = false;
|
|
77
|
+
const cb = (scanData) => {
|
|
78
|
+
if (scanData.scanStatus === shared_models_1.MerkletreeScanStatus.Complete && !done) {
|
|
79
|
+
done = true;
|
|
80
|
+
resolve(true);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
(0, core_1.setOnUTXOMerkletreeScanCallback)(cb);
|
|
84
|
+
setTimeout(() => { if (!done) {
|
|
85
|
+
done = true;
|
|
86
|
+
resolve(false);
|
|
87
|
+
} }, timeoutMs);
|
|
88
|
+
});
|
|
89
|
+
};
|
|
90
|
+
/** Get gas details for Ganache (EIP-1559). */
|
|
91
|
+
const getGasDetails = async (provider, gasEstimate = 4000000n) => {
|
|
92
|
+
const feeData = await provider.getFeeData();
|
|
93
|
+
return {
|
|
94
|
+
evmGasType: shared_models_1.EVMGasType.Type2,
|
|
95
|
+
gasEstimate,
|
|
96
|
+
maxFeePerGas: feeData.maxFeePerGas ?? 2000000000n,
|
|
97
|
+
maxPriorityFeePerGas: feeData.maxPriorityFeePerGas ?? 1000000000n,
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
// ============================================================
|
|
101
|
+
// Main
|
|
102
|
+
// ============================================================
|
|
103
|
+
async function main() {
|
|
104
|
+
console.log('\nMatrix Wallet — Local E2E Test\n');
|
|
105
|
+
// ── Step 0: Read deployment config ──────────────────────────
|
|
106
|
+
step(0, 'Read deployment config');
|
|
107
|
+
// Try local-deploy.json first, then local-deploy.json.example
|
|
108
|
+
let configFile;
|
|
109
|
+
if (await fileExists(CONFIG_PATH)) {
|
|
110
|
+
configFile = CONFIG_PATH;
|
|
111
|
+
}
|
|
112
|
+
else if (await fileExists(CONFIG_PATH_EXAMPLE)) {
|
|
113
|
+
configFile = CONFIG_PATH_EXAMPLE;
|
|
114
|
+
}
|
|
115
|
+
if (!configFile) {
|
|
116
|
+
fail(`Config file not found.`);
|
|
117
|
+
console.log(`\nLooked for:\n ${CONFIG_PATH}\n ${CONFIG_PATH_EXAMPLE}`);
|
|
118
|
+
console.log('\nCreate one with your deployed contract addresses.');
|
|
119
|
+
console.log('Required fields: rpc, chainId, weth, accumulatorProxy,');
|
|
120
|
+
console.log(' matrixProxy, verifierProxy, tokenVaultProxy, relayAdapt');
|
|
121
|
+
console.log('Optional: userPrivateKey, mnemonic\n');
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
info(`Reading config from: ${path_1.default.basename(configFile)}`);
|
|
125
|
+
const config = JSON.parse(await fs_1.default.promises.readFile(configFile, 'utf-8'));
|
|
126
|
+
// Validate all addresses are present
|
|
127
|
+
const requiredFields = [
|
|
128
|
+
'rpc', 'chainId', 'weth',
|
|
129
|
+
'accumulatorProxy', 'matrixProxy', 'verifierProxy',
|
|
130
|
+
'tokenVaultProxy', 'relayAdapt',
|
|
131
|
+
];
|
|
132
|
+
for (const field of requiredFields) {
|
|
133
|
+
if (!config[field]) {
|
|
134
|
+
fail(`Missing field "${field}" in local-deploy.json`);
|
|
135
|
+
process.exit(1);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
info(`RPC: ${config.rpc}`);
|
|
139
|
+
info(`Chain ID: ${config.chainId}`);
|
|
140
|
+
info(`WETH: ${config.weth}`);
|
|
141
|
+
info(`Accumulator: ${config.accumulatorProxy}`);
|
|
142
|
+
info(`Matrix: ${config.matrixProxy}`);
|
|
143
|
+
info(`Verifier: ${config.verifierProxy}`);
|
|
144
|
+
info(`TokenVault: ${config.tokenVaultProxy}`);
|
|
145
|
+
info(`RelayAdapt: ${config.relayAdapt}`);
|
|
146
|
+
ok('Config loaded');
|
|
147
|
+
// ── Step 1: Patch NETWORK_CONFIG ────────────────────────────
|
|
148
|
+
step(1, 'Patch NETWORK_CONFIG with deployed addresses');
|
|
149
|
+
const networkConfig = shared_models_1.NETWORK_CONFIG[shared_models_1.NetworkName.Hardhat];
|
|
150
|
+
networkConfig.chain.id = config.chainId;
|
|
151
|
+
networkConfig.matrixContract = config.matrixProxy;
|
|
152
|
+
networkConfig.accumulatorContract = config.accumulatorProxy;
|
|
153
|
+
// Engine's "verifier" is the Matrix contract (legacy naming from Railgun's
|
|
154
|
+
// PoseidonMerkleVerifier). It holds the execute() entry point.
|
|
155
|
+
networkConfig.verifierContract = config.matrixProxy;
|
|
156
|
+
networkConfig.tokenVaultContract = config.tokenVaultProxy;
|
|
157
|
+
networkConfig.relayAdaptContract = config.relayAdapt;
|
|
158
|
+
networkConfig.baseToken.wrappedAddress = config.weth;
|
|
159
|
+
networkConfig.deploymentBlock = 0;
|
|
160
|
+
ok('NETWORK_CONFIG patched');
|
|
161
|
+
// ── Step 2: Connect to local node ───────────────────────────
|
|
162
|
+
step(2, 'Connect to local node');
|
|
163
|
+
const userPrivateKey = config.userPrivateKey || DEFAULT_USER_PRIVATE_KEY;
|
|
164
|
+
const mnemonic = config.mnemonic || DEFAULT_MNEMONIC;
|
|
165
|
+
const jsonRpcProvider = new ethers_1.JsonRpcProvider(config.rpc, config.chainId);
|
|
166
|
+
const blockNumber = await jsonRpcProvider.getBlockNumber();
|
|
167
|
+
info(`Current block: ${blockNumber}`);
|
|
168
|
+
const userWallet = new ethers_1.Wallet(userPrivateKey, jsonRpcProvider);
|
|
169
|
+
const userAddress = await userWallet.getAddress();
|
|
170
|
+
const ethBalance = await jsonRpcProvider.getBalance(userAddress);
|
|
171
|
+
info(`User address: ${userAddress}`);
|
|
172
|
+
info(`ETH balance: ${ethers_1.ethers.formatEther(ethBalance)} ETH`);
|
|
173
|
+
if (ethBalance === 0n) {
|
|
174
|
+
fail('User account has 0 ETH — wrong private key or unfunded account?');
|
|
175
|
+
process.exit(1);
|
|
176
|
+
}
|
|
177
|
+
ok('Connected to local node');
|
|
178
|
+
// ── Step 3: Initialize Matrix Engine ────────────────────────
|
|
179
|
+
step(3, 'Initialize Matrix Engine');
|
|
180
|
+
await rmDirSafe(DB_PATH);
|
|
181
|
+
// Keep ARTIFACTS_DIR across runs so IPFS-downloaded circuit artifacts are cached.
|
|
182
|
+
const db = new leveldown_1.default(DB_PATH);
|
|
183
|
+
const artifactStore = new artifact_store_1.ArtifactStore((filePath) => fs_1.default.promises.readFile(path_1.default.resolve(ARTIFACTS_DIR, filePath)), async (dir, filePath, data) => {
|
|
184
|
+
const fullDir = path_1.default.resolve(ARTIFACTS_DIR, dir);
|
|
185
|
+
const fullPath = path_1.default.resolve(ARTIFACTS_DIR, filePath);
|
|
186
|
+
await fs_1.default.promises.mkdir(fullDir, { recursive: true });
|
|
187
|
+
await fs_1.default.promises.writeFile(fullPath, data);
|
|
188
|
+
}, async (filePath) => fileExists(path_1.default.resolve(ARTIFACTS_DIR, filePath)));
|
|
189
|
+
(0, utils_1.setLoggers)(console.log, console.error);
|
|
190
|
+
await (0, core_1.startMatrixEngine)('locale2etest', // walletSource (max 16 chars, lowercase, no hyphens)
|
|
191
|
+
db, // database
|
|
192
|
+
true, // shouldDebug
|
|
193
|
+
artifactStore, // artifactStore
|
|
194
|
+
false, // useNativeArtifacts (nodejs = false)
|
|
195
|
+
false, // skipMerkletreeScans
|
|
196
|
+
false);
|
|
197
|
+
(0, core_1.getEngine)().prover.setSnarkJSGroth16(snarkjs_1.groth16);
|
|
198
|
+
ok('Engine initialized');
|
|
199
|
+
// ── Step 4: Load network provider ──────────────────────────
|
|
200
|
+
step(4, 'Load network provider');
|
|
201
|
+
const fallbackProviderConfig = {
|
|
202
|
+
chainId: config.chainId,
|
|
203
|
+
providers: [
|
|
204
|
+
{
|
|
205
|
+
provider: config.rpc,
|
|
206
|
+
priority: 1,
|
|
207
|
+
weight: 2,
|
|
208
|
+
maxLogsPerBatch: 100,
|
|
209
|
+
stallTimeout: 5000,
|
|
210
|
+
},
|
|
211
|
+
],
|
|
212
|
+
};
|
|
213
|
+
const { feesSerialized } = await (0, core_1.loadProvider)(fallbackProviderConfig, shared_models_1.NetworkName.Hardhat, 5000);
|
|
214
|
+
info(`Shield fee: ${feesSerialized.shieldFee} bps`);
|
|
215
|
+
info(`Unshield fee: ${feesSerialized.unshieldFee} bps`);
|
|
216
|
+
ok('Provider loaded, network connected');
|
|
217
|
+
// ── Step 5: Create Matrix wallet ───────────────────────────
|
|
218
|
+
step(5, 'Create Matrix wallet');
|
|
219
|
+
const walletInfo = await (0, wallets_1.createMatrixWallet)(DB_ENCRYPTION_KEY, mnemonic, { [shared_models_1.NetworkName.Hardhat]: 0 }, 0);
|
|
220
|
+
info(`Wallet ID: ${walletInfo.id}`);
|
|
221
|
+
info(`Matrix address: ${walletInfo.matrixAddress}`);
|
|
222
|
+
ok('Wallet created');
|
|
223
|
+
// ── Step 6: Set up event listeners and scan ────────────────
|
|
224
|
+
step(6, 'Scan contract history');
|
|
225
|
+
let scanComplete = false;
|
|
226
|
+
const scanPromise = new Promise((resolve) => {
|
|
227
|
+
(0, core_1.setOnUTXOMerkletreeScanCallback)((scanData) => {
|
|
228
|
+
info(`Scan: status=${scanData.scanStatus}, progress=${(scanData.progress * 100).toFixed(1)}%`);
|
|
229
|
+
if (scanData.scanStatus === shared_models_1.MerkletreeScanStatus.Complete) {
|
|
230
|
+
scanComplete = true;
|
|
231
|
+
resolve();
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
let balanceUpdated = false;
|
|
236
|
+
(0, balance_update_1.setOnBalanceUpdateCallback)(() => {
|
|
237
|
+
balanceUpdated = true;
|
|
238
|
+
});
|
|
239
|
+
const { chain } = shared_models_1.NETWORK_CONFIG[shared_models_1.NetworkName.Hardhat];
|
|
240
|
+
(0, core_1.getEngine)().scanContractHistory(chain, undefined);
|
|
241
|
+
// Wait for initial scan (should be fast on empty chain)
|
|
242
|
+
const scanTimeout = setTimeout(() => {
|
|
243
|
+
if (!scanComplete) {
|
|
244
|
+
info('Scan taking long, continuing...');
|
|
245
|
+
}
|
|
246
|
+
}, 10000);
|
|
247
|
+
await Promise.race([
|
|
248
|
+
scanPromise,
|
|
249
|
+
new Promise(resolve => setTimeout(resolve, 15000)),
|
|
250
|
+
]);
|
|
251
|
+
clearTimeout(scanTimeout);
|
|
252
|
+
ok('Initial scan complete');
|
|
253
|
+
// ── Step 7: Wrap ETH → WETH ────────────────────────────────
|
|
254
|
+
step(7, 'Wrap ETH → WETH');
|
|
255
|
+
const weth = new ethers_1.Contract(config.weth, WETH9_ABI, userWallet);
|
|
256
|
+
// Ganache instamine + ethers v6 nonce caching = stale nonces.
|
|
257
|
+
// Fetch once, increment locally for each send.
|
|
258
|
+
let nonce = await jsonRpcProvider.getTransactionCount(userAddress, 'pending');
|
|
259
|
+
info(`Starting nonce: ${nonce}`);
|
|
260
|
+
info(`Depositing ${ethers_1.ethers.formatEther(SHIELD_AMOUNT)} ETH → WETH...`);
|
|
261
|
+
const depositTx = await weth.deposit({ value: SHIELD_AMOUNT, nonce: nonce++ });
|
|
262
|
+
await depositTx.wait();
|
|
263
|
+
const wethBalance = await weth.balanceOf(userAddress);
|
|
264
|
+
info(`WETH balance: ${ethers_1.ethers.formatEther(wethBalance)}`);
|
|
265
|
+
ok('ETH wrapped to WETH');
|
|
266
|
+
// ── Step 8: Approve TokenVault to spend WETH ───────────────
|
|
267
|
+
step(8, 'Approve TokenVault for WETH');
|
|
268
|
+
info(`Approving ${config.tokenVaultProxy} to spend WETH...`);
|
|
269
|
+
const approveTx = await weth.approve(config.tokenVaultProxy, SHIELD_AMOUNT, { nonce: nonce++ });
|
|
270
|
+
await approveTx.wait();
|
|
271
|
+
ok('TokenVault approved');
|
|
272
|
+
// ── Step 9: Shield WETH into Matrix wallet ─────────────────
|
|
273
|
+
step(9, 'Shield WETH');
|
|
274
|
+
// Generate a shield private key (random for testing)
|
|
275
|
+
const shieldPrivateKey = engine_1.ByteUtils.randomHex(32);
|
|
276
|
+
info(`Shield private key: ${shieldPrivateKey.slice(0, 18)}...`);
|
|
277
|
+
info(`Shield message: "${(0, tx_shield_1.getShieldPrivateKeySignatureMessage)()}"`);
|
|
278
|
+
const erc20AmountRecipients = [
|
|
279
|
+
{
|
|
280
|
+
tokenAddress: config.weth,
|
|
281
|
+
amount: SHIELD_AMOUNT,
|
|
282
|
+
recipientAddress: walletInfo.matrixAddress,
|
|
283
|
+
},
|
|
284
|
+
];
|
|
285
|
+
info('Populating shield transaction...');
|
|
286
|
+
const { transaction: shieldTx } = await (0, tx_shield_1.populateShield)(shared_models_1.NetworkName.Hardhat, shieldPrivateKey, erc20AmountRecipients, [], // nftAmountRecipients
|
|
287
|
+
undefined);
|
|
288
|
+
info(`Shield tx to: ${shieldTx.to}`);
|
|
289
|
+
info('Sending shield transaction...');
|
|
290
|
+
const sentTx = await userWallet.sendTransaction({ ...shieldTx, nonce: nonce++ });
|
|
291
|
+
info(`TX hash: ${sentTx.hash}`);
|
|
292
|
+
const receipt = await sentTx.wait();
|
|
293
|
+
info(`TX confirmed in block ${receipt?.blockNumber}, gas used: ${receipt?.gasUsed.toString()}`);
|
|
294
|
+
ok('Shield transaction confirmed');
|
|
295
|
+
// ── Step 10: Wait for balance update ───────────────────────
|
|
296
|
+
step(10, 'Wait for balance scan after shield');
|
|
297
|
+
info('Triggering rescan...');
|
|
298
|
+
balanceUpdated = false;
|
|
299
|
+
(0, core_1.getEngine)().scanContractHistory(chain, undefined);
|
|
300
|
+
// Wait for balance update
|
|
301
|
+
const balanceTimeout = 30000;
|
|
302
|
+
const startTime = Date.now();
|
|
303
|
+
while (!balanceUpdated && Date.now() - startTime < balanceTimeout) {
|
|
304
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
305
|
+
}
|
|
306
|
+
if (balanceUpdated) {
|
|
307
|
+
ok('Balance updated after shield');
|
|
308
|
+
}
|
|
309
|
+
else {
|
|
310
|
+
info('Balance update not received within timeout — check engine logs above');
|
|
311
|
+
}
|
|
312
|
+
// ── Step 11: Query private balance ───────────────────────
|
|
313
|
+
step(11, 'Query private balance after shield');
|
|
314
|
+
const wallet1 = (0, wallets_1.walletForID)(walletInfo.id);
|
|
315
|
+
const balances1 = await wallet1.getTokenBalances(chain, false);
|
|
316
|
+
const erc20Balances1 = (0, balance_update_1.getSerializedERC20Balances)(balances1);
|
|
317
|
+
const shieldedWeth = erc20Balances1.find(b => b.tokenAddress.toLowerCase() === config.weth.toLowerCase());
|
|
318
|
+
if (shieldedWeth) {
|
|
319
|
+
info(`Private WETH balance: ${ethers_1.ethers.formatEther(shieldedWeth.amount)}`);
|
|
320
|
+
}
|
|
321
|
+
else {
|
|
322
|
+
fail('No WETH found in private balance!');
|
|
323
|
+
process.exit(1);
|
|
324
|
+
}
|
|
325
|
+
ok('Private balance confirmed');
|
|
326
|
+
// ── Step 12: Create second wallet (recipient) ────────────
|
|
327
|
+
step(12, 'Create second Matrix wallet (recipient)');
|
|
328
|
+
const wallet2Info = await (0, wallets_1.createMatrixWallet)(DB_ENCRYPTION_KEY, mnemonic, { [shared_models_1.NetworkName.Hardhat]: 0 }, 1);
|
|
329
|
+
info(`Wallet 2 ID: ${wallet2Info.id}`);
|
|
330
|
+
info(`Wallet 2 address: ${wallet2Info.matrixAddress}`);
|
|
331
|
+
ok('Second wallet created');
|
|
332
|
+
// ── Step 13: Private transfer ────────────────────────────
|
|
333
|
+
step(13, 'Private transfer (ZK proof)');
|
|
334
|
+
info(`Transferring ${ethers_1.ethers.formatEther(TRANSFER_AMOUNT)} WETH to wallet 2...`);
|
|
335
|
+
info('Generating transfer proof (this may take ~30-60s)...');
|
|
336
|
+
const transferRecipients = [
|
|
337
|
+
{
|
|
338
|
+
tokenAddress: config.weth,
|
|
339
|
+
amount: TRANSFER_AMOUNT,
|
|
340
|
+
recipientAddress: wallet2Info.matrixAddress,
|
|
341
|
+
},
|
|
342
|
+
];
|
|
343
|
+
await (0, tx_proof_transfer_1.generateTransferProof)(shared_models_1.NetworkName.Hardhat, walletInfo.id, DB_ENCRYPTION_KEY, false, // showSenderAddressToRecipient
|
|
344
|
+
undefined, // memoText
|
|
345
|
+
transferRecipients, [], // nftAmountRecipients
|
|
346
|
+
undefined, // broadcasterFeeERC20AmountRecipient
|
|
347
|
+
true, // sendWithPublicWallet
|
|
348
|
+
undefined, // overallBatchMinGasPrice
|
|
349
|
+
(progress, status) => {
|
|
350
|
+
info(`Proof: ${status} (${(progress * 100).toFixed(1)}%)`);
|
|
351
|
+
});
|
|
352
|
+
ok('Transfer proof generated');
|
|
353
|
+
const transferGasDetails = await getGasDetails(jsonRpcProvider);
|
|
354
|
+
const { transaction: transferTx } = await (0, tx_transfer_1.populateProvedTransfer)(shared_models_1.NetworkName.Hardhat, walletInfo.id, false, // showSenderAddressToRecipient
|
|
355
|
+
undefined, // memoText
|
|
356
|
+
transferRecipients, [], // nftAmountRecipients
|
|
357
|
+
undefined, // broadcasterFeeERC20AmountRecipient
|
|
358
|
+
true, // sendWithPublicWallet
|
|
359
|
+
undefined, // overallBatchMinGasPrice
|
|
360
|
+
transferGasDetails);
|
|
361
|
+
info(`Transfer tx to: ${transferTx.to}`);
|
|
362
|
+
const sentTransferTx = await userWallet.sendTransaction({ ...transferTx, nonce: nonce++ });
|
|
363
|
+
info(`TX hash: ${sentTransferTx.hash}`);
|
|
364
|
+
const transferReceipt = await sentTransferTx.wait();
|
|
365
|
+
info(`TX confirmed in block ${transferReceipt?.blockNumber}, gas used: ${transferReceipt?.gasUsed.toString()}`);
|
|
366
|
+
ok('Private transfer confirmed on-chain');
|
|
367
|
+
// ── Step 14: Rescan + verify transfer balances ───────────
|
|
368
|
+
step(14, 'Rescan after transfer');
|
|
369
|
+
(0, core_1.getEngine)().scanContractHistory(chain, undefined);
|
|
370
|
+
const scanOk1 = await waitForScan();
|
|
371
|
+
if (scanOk1) {
|
|
372
|
+
ok('Scan complete');
|
|
373
|
+
}
|
|
374
|
+
else {
|
|
375
|
+
info('Scan timeout — continuing');
|
|
376
|
+
}
|
|
377
|
+
// Query both wallets (balance deserialization may fail for wallet 2 — investigate separately)
|
|
378
|
+
let w1Weth;
|
|
379
|
+
let w2Weth;
|
|
380
|
+
try {
|
|
381
|
+
const w1PostTransfer = await (0, wallets_1.walletForID)(walletInfo.id).getTokenBalances(chain, false);
|
|
382
|
+
const w1Erc20 = (0, balance_update_1.getSerializedERC20Balances)(w1PostTransfer);
|
|
383
|
+
w1Weth = w1Erc20.find(b => b.tokenAddress.toLowerCase() === config.weth.toLowerCase());
|
|
384
|
+
info(`Wallet 1 private WETH: ${w1Weth ? ethers_1.ethers.formatEther(w1Weth.amount) : '0'}`);
|
|
385
|
+
}
|
|
386
|
+
catch (err) {
|
|
387
|
+
info(`Wallet 1 balance query failed: ${err.message}`);
|
|
388
|
+
}
|
|
389
|
+
try {
|
|
390
|
+
const wallet2 = (0, wallets_1.walletForID)(wallet2Info.id);
|
|
391
|
+
const w2PostTransfer = await wallet2.getTokenBalances(chain, false);
|
|
392
|
+
const w2Erc20 = (0, balance_update_1.getSerializedERC20Balances)(w2PostTransfer);
|
|
393
|
+
w2Weth = w2Erc20.find(b => b.tokenAddress.toLowerCase() === config.weth.toLowerCase());
|
|
394
|
+
info(`Wallet 2 private WETH: ${w2Weth ? ethers_1.ethers.formatEther(w2Weth.amount) : '0'}`);
|
|
395
|
+
}
|
|
396
|
+
catch (err) {
|
|
397
|
+
info(`Wallet 2 balance query failed: ${err.message}`);
|
|
398
|
+
}
|
|
399
|
+
ok('Transfer balances checked');
|
|
400
|
+
// ── Step 15: Unshield from wallet 1 ──────────────────────
|
|
401
|
+
step(15, 'Unshield WETH (ZK proof)');
|
|
402
|
+
info(`Unshielding ${ethers_1.ethers.formatEther(UNSHIELD_AMOUNT)} WETH to ${userAddress}...`);
|
|
403
|
+
info('Generating unshield proof (this may take ~30-60s)...');
|
|
404
|
+
const unshieldRecipients = [
|
|
405
|
+
{
|
|
406
|
+
tokenAddress: config.weth,
|
|
407
|
+
amount: UNSHIELD_AMOUNT,
|
|
408
|
+
recipientAddress: userAddress, // public ETH address
|
|
409
|
+
},
|
|
410
|
+
];
|
|
411
|
+
await (0, tx_proof_unshield_1.generateUnshieldProof)(shared_models_1.NetworkName.Hardhat, walletInfo.id, DB_ENCRYPTION_KEY, unshieldRecipients, [], // nftAmountRecipients
|
|
412
|
+
undefined, // broadcasterFeeERC20AmountRecipient
|
|
413
|
+
true, // sendWithPublicWallet
|
|
414
|
+
undefined, // overallBatchMinGasPrice
|
|
415
|
+
(progress, status) => {
|
|
416
|
+
info(`Proof: ${status} (${(progress * 100).toFixed(1)}%)`);
|
|
417
|
+
});
|
|
418
|
+
ok('Unshield proof generated');
|
|
419
|
+
const unshieldGasDetails = await getGasDetails(jsonRpcProvider);
|
|
420
|
+
const { transaction: unshieldTx } = await (0, tx_unshield_1.populateProvedUnshield)(shared_models_1.NetworkName.Hardhat, walletInfo.id, unshieldRecipients, [], // nftAmountRecipients
|
|
421
|
+
undefined, // broadcasterFeeERC20AmountRecipient
|
|
422
|
+
true, // sendWithPublicWallet
|
|
423
|
+
undefined, // overallBatchMinGasPrice
|
|
424
|
+
unshieldGasDetails);
|
|
425
|
+
info(`Unshield tx to: ${unshieldTx.to}`);
|
|
426
|
+
const sentUnshieldTx = await userWallet.sendTransaction({ ...unshieldTx, nonce: nonce++ });
|
|
427
|
+
info(`TX hash: ${sentUnshieldTx.hash}`);
|
|
428
|
+
const unshieldReceipt = await sentUnshieldTx.wait();
|
|
429
|
+
info(`TX confirmed in block ${unshieldReceipt?.blockNumber}, gas used: ${unshieldReceipt?.gasUsed.toString()}`);
|
|
430
|
+
ok('Unshield confirmed on-chain');
|
|
431
|
+
// ── Step 16: Rescan + verify unshield ────────────────────
|
|
432
|
+
step(16, 'Verify unshield');
|
|
433
|
+
(0, core_1.getEngine)().scanContractHistory(chain, undefined);
|
|
434
|
+
const scanOk2 = await waitForScan();
|
|
435
|
+
if (scanOk2) {
|
|
436
|
+
ok('Scan complete');
|
|
437
|
+
}
|
|
438
|
+
else {
|
|
439
|
+
info('Scan timeout — continuing');
|
|
440
|
+
}
|
|
441
|
+
const postUnshieldWeth = await weth.balanceOf(userAddress);
|
|
442
|
+
info(`Public WETH balance after unshield: ${ethers_1.ethers.formatEther(postUnshieldWeth)}`);
|
|
443
|
+
let w1FinalWeth;
|
|
444
|
+
try {
|
|
445
|
+
const w1Final = await (0, wallets_1.walletForID)(walletInfo.id).getTokenBalances(chain, false);
|
|
446
|
+
const w1FinalErc20 = (0, balance_update_1.getSerializedERC20Balances)(w1Final);
|
|
447
|
+
w1FinalWeth = w1FinalErc20.find(b => b.tokenAddress.toLowerCase() === config.weth.toLowerCase());
|
|
448
|
+
info(`Wallet 1 final private WETH: ${w1FinalWeth ? ethers_1.ethers.formatEther(w1FinalWeth.amount) : '0'}`);
|
|
449
|
+
}
|
|
450
|
+
catch (err) {
|
|
451
|
+
info(`Wallet 1 final balance query failed: ${err.message}`);
|
|
452
|
+
}
|
|
453
|
+
ok('Unshield verified');
|
|
454
|
+
// ── Step 17: Final summary ───────────────────────────────
|
|
455
|
+
step(17, 'Final Summary');
|
|
456
|
+
const finalEthBalance = await jsonRpcProvider.getBalance(userAddress);
|
|
457
|
+
const finalWethBalance = await weth.balanceOf(userAddress);
|
|
458
|
+
let w2FinalWeth;
|
|
459
|
+
try {
|
|
460
|
+
const w2Final = await (0, wallets_1.walletForID)(wallet2Info.id).getTokenBalances(chain, false);
|
|
461
|
+
const w2FinalErc20 = (0, balance_update_1.getSerializedERC20Balances)(w2Final);
|
|
462
|
+
w2FinalWeth = w2FinalErc20.find(b => b.tokenAddress.toLowerCase() === config.weth.toLowerCase());
|
|
463
|
+
}
|
|
464
|
+
catch (err) {
|
|
465
|
+
info(`Wallet 2 final balance query failed: ${err.message}`);
|
|
466
|
+
}
|
|
467
|
+
console.log('\n Public wallet:');
|
|
468
|
+
info(`ETH: ${ethers_1.ethers.formatEther(finalEthBalance)}`);
|
|
469
|
+
info(`WETH: ${ethers_1.ethers.formatEther(finalWethBalance)}`);
|
|
470
|
+
console.log('\n Private wallets:');
|
|
471
|
+
info(`Wallet 1: ${w1FinalWeth ? ethers_1.ethers.formatEther(w1FinalWeth.amount) : '0'} WETH`);
|
|
472
|
+
info(`Wallet 2: ${w2FinalWeth ? ethers_1.ethers.formatEther(w2FinalWeth.amount) : '0'} WETH`);
|
|
473
|
+
console.log('\n Operations completed:');
|
|
474
|
+
info(`Shield: ${ethers_1.ethers.formatEther(SHIELD_AMOUNT)} WETH (fee ${feesSerialized.shieldFee} bps)`);
|
|
475
|
+
info(`Transfer: ${ethers_1.ethers.formatEther(TRANSFER_AMOUNT)} WETH (wallet 1 -> wallet 2)`);
|
|
476
|
+
info(`Unshield: ${ethers_1.ethers.formatEther(UNSHIELD_AMOUNT)} WETH (fee ${feesSerialized.unshieldFee} bps)`);
|
|
477
|
+
console.log('');
|
|
478
|
+
// ── Cleanup ────────────────────────────────────────────────
|
|
479
|
+
await (0, core_1.stopMatrixEngine)();
|
|
480
|
+
ok('Engine stopped. Full E2E test complete.\n');
|
|
481
|
+
process.exit(0);
|
|
482
|
+
}
|
|
483
|
+
main().catch((err) => {
|
|
484
|
+
console.error('\n [FATAL]', err);
|
|
485
|
+
process.exit(1);
|
|
486
|
+
});
|
|
487
|
+
//# sourceMappingURL=local-e2e.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-e2e.js","sourceRoot":"","sources":["../../src/tests/local-e2e.ts"],"names":[],"mappings":";AAAA,yCAAyC;AACzC,+NAA+N;AAC/N;;;;;;;;;;;GAWG;AACH,+BAA+B;;;;;AAE/B,4CAAoB;AACpB,gDAAwB;AACxB,0DAAkC;AAClC,mCAAgG;AAChG,qCAAkC;AAClC,iEAQuC;AACvC,mDAIgC;AAChC,kDAMiC;AACjC,gEAG4C;AAC5C,8EAGmD;AACnD,kEAG4C;AAC5C,kFAAmF;AACnF,sEAA8E;AAC9E,kFAAmF;AACnF,sEAA8E;AAC9E,yEAAqE;AACrE,oCAAsC;AAEtC,+DAA+D;AAC/D,gBAAgB;AAChB,+DAA+D;AAE/D,MAAM,WAAW,GAAG,cAAI,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;AACrD,MAAM,WAAW,GAAG,cAAI,CAAC,OAAO,CAAC,WAAW,EAAE,mBAAmB,CAAC,CAAC;AACnE,MAAM,mBAAmB,GAAG,cAAI,CAAC,OAAO,CAAC,WAAW,EAAE,2BAA2B,CAAC,CAAC;AACnF,MAAM,OAAO,GAAG,cAAI,CAAC,OAAO,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;AAC1D,MAAM,aAAa,GAAG,cAAI,CAAC,OAAO,CAAC,WAAW,EAAE,qBAAqB,CAAC,CAAC;AAEvE,sFAAsF;AACtF,oEAAoE;AACpE,MAAM,wBAAwB,GAC5B,oEAAoE,CAAC,CAAC,qBAAqB;AAC7F,MAAM,gBAAgB,GACpB,8EAA8E,CAAC;AACjF,MAAM,iBAAiB,GACrB,kEAAkE,CAAC;AAErE,MAAM,aAAa,GAAG,eAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;AACzD,MAAM,eAAe,GAAG,eAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,0BAA0B;AAC5E,MAAM,eAAe,GAAG,eAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,kBAAkB;AAoBpE,+DAA+D;AAC/D,UAAU;AACV,+DAA+D;AAE/D,MAAM,UAAU,GAAG,CAAC,QAAgB,EAAoB,EAAE,CACxD,YAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC;AAEnE,MAAM,SAAS,GAAG,KAAK,EAAE,GAAW,EAAE,EAAE;IACtC,IAAI,MAAM,UAAU,CAAC,GAAG,CAAC,EAAE;QACzB,MAAM,YAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;KAChD;AACH,CAAC,CAAC;AAEF,MAAM,IAAI,GAAG,CAAC,CAAS,EAAE,GAAW,EAAE,EAAE,CACtC,OAAO,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,KAAK,GAAG,KAAK,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AAE7E,MAAM,IAAI,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,GAAG,EAAE,CAAC,CAAC;AAC7D,MAAM,EAAE,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,GAAG,EAAE,CAAC,CAAC;AAC3D,MAAM,IAAI,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,YAAY,GAAG,EAAE,CAAC,CAAC;AAE/D,oBAAoB;AACpB,MAAM,SAAS,GAAG;IAChB,4BAA4B;IAC5B,kEAAkE;IAClE,0DAA0D;CAC3D,CAAC;AAEF,oDAAoD;AACpD,MAAM,WAAW,GAAG,KAAK,EAAE,SAAS,GAAG,KAAK,EAAoB,EAAE;IAChE,OAAO,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,EAAE;QACtC,IAAI,IAAI,GAAG,KAAK,CAAC;QACjB,MAAM,EAAE,GAAG,CAAC,QAAmC,EAAE,EAAE;YACjD,IAAI,QAAQ,CAAC,UAAU,KAAK,oCAAoB,CAAC,QAAQ,IAAI,CAAC,IAAI,EAAE;gBAClE,IAAI,GAAG,IAAI,CAAC;gBACZ,OAAO,CAAC,IAAI,CAAC,CAAC;aACf;QACH,CAAC,CAAC;QACF,IAAA,sCAA+B,EAAC,EAAE,CAAC,CAAC;QACpC,UAAU,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE;YAAE,IAAI,GAAG,IAAI,CAAC;YAAC,OAAO,CAAC,KAAK,CAAC,CAAC;SAAE,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IAC/E,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,8CAA8C;AAC9C,MAAM,aAAa,GAAG,KAAK,EACzB,QAAyB,EACzB,WAAW,GAAG,QAAU,EACa,EAAE;IACvC,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,CAAC;IAC5C,OAAO;QACL,UAAU,EAAE,0BAAU,CAAC,KAAK;QAC5B,WAAW;QACX,YAAY,EAAE,OAAO,CAAC,YAAY,IAAI,WAAc;QACpD,oBAAoB,EAAE,OAAO,CAAC,oBAAoB,IAAI,WAAc;KACrE,CAAC;AACJ,CAAC,CAAC;AAEF,+DAA+D;AAC/D,OAAO;AACP,+DAA+D;AAE/D,KAAK,UAAU,IAAI;IACjB,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;IAElD,+DAA+D;IAC/D,IAAI,CAAC,CAAC,EAAE,wBAAwB,CAAC,CAAC;IAElC,8DAA8D;IAC9D,IAAI,UAA8B,CAAC;IACnC,IAAI,MAAM,UAAU,CAAC,WAAW,CAAC,EAAE;QACjC,UAAU,GAAG,WAAW,CAAC;KAC1B;SAAM,IAAI,MAAM,UAAU,CAAC,mBAAmB,CAAC,EAAE;QAChD,UAAU,GAAG,mBAAmB,CAAC;KAClC;IAED,IAAI,CAAC,UAAU,EAAE;QACf,IAAI,CAAC,wBAAwB,CAAC,CAAC;QAC/B,OAAO,CAAC,GAAG,CAAC,oBAAoB,WAAW,OAAO,mBAAmB,EAAE,CAAC,CAAC;QACzE,OAAO,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAC;QACnE,OAAO,CAAC,GAAG,CAAC,wDAAwD,CAAC,CAAC;QACtE,OAAO,CAAC,GAAG,CAAC,2DAA2D,CAAC,CAAC;QACzE,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC;QACpD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;KACjB;IAED,IAAI,CAAC,wBAAwB,cAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IAC1D,MAAM,MAAM,GAAiB,IAAI,CAAC,KAAK,CACrC,MAAM,YAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAChD,CAAC;IAEF,qCAAqC;IACrC,MAAM,cAAc,GAA2B;QAC7C,KAAK,EAAE,SAAS,EAAE,MAAM;QACxB,kBAAkB,EAAE,aAAa,EAAE,eAAe;QAClD,iBAAiB,EAAE,YAAY;KAChC,CAAC;IACF,KAAK,MAAM,KAAK,IAAI,cAAc,EAAE;QAClC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;YAClB,IAAI,CAAC,kBAAkB,KAAK,wBAAwB,CAAC,CAAC;YACtD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;SACjB;KACF;IAED,IAAI,CAAC,QAAQ,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;IAC3B,IAAI,CAAC,aAAa,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IACpC,IAAI,CAAC,SAAS,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IAC7B,IAAI,CAAC,gBAAgB,MAAM,CAAC,gBAAgB,EAAE,CAAC,CAAC;IAChD,IAAI,CAAC,WAAW,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;IACtC,IAAI,CAAC,aAAa,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC;IAC1C,IAAI,CAAC,eAAe,MAAM,CAAC,eAAe,EAAE,CAAC,CAAC;IAC9C,IAAI,CAAC,eAAe,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;IACzC,EAAE,CAAC,eAAe,CAAC,CAAC;IAEpB,+DAA+D;IAC/D,IAAI,CAAC,CAAC,EAAE,8CAA8C,CAAC,CAAC;IAExD,MAAM,aAAa,GAAG,8BAAc,CAAC,2BAAW,CAAC,OAAO,CAAC,CAAC;IAC1D,aAAa,CAAC,KAAK,CAAC,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC;IACxC,aAAa,CAAC,cAAc,GAAG,MAAM,CAAC,WAAW,CAAC;IAClD,aAAa,CAAC,mBAAmB,GAAG,MAAM,CAAC,gBAAgB,CAAC;IAC5D,2EAA2E;IAC3E,+DAA+D;IAC/D,aAAa,CAAC,gBAAgB,GAAG,MAAM,CAAC,WAAW,CAAC;IACpD,aAAa,CAAC,kBAAkB,GAAG,MAAM,CAAC,eAAe,CAAC;IAC1D,aAAa,CAAC,kBAAkB,GAAG,MAAM,CAAC,UAAU,CAAC;IACrD,aAAa,CAAC,SAAS,CAAC,cAAc,GAAG,MAAM,CAAC,IAAI,CAAC;IACrD,aAAa,CAAC,eAAe,GAAG,CAAC,CAAC;IAElC,EAAE,CAAC,wBAAwB,CAAC,CAAC;IAE7B,+DAA+D;IAC/D,IAAI,CAAC,CAAC,EAAE,uBAAuB,CAAC,CAAC;IAEjC,MAAM,cAAc,GAAG,MAAM,CAAC,cAAc,IAAI,wBAAwB,CAAC;IACzE,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,IAAI,gBAAgB,CAAC;IAErD,MAAM,eAAe,GAAG,IAAI,wBAAe,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACxE,MAAM,WAAW,GAAG,MAAM,eAAe,CAAC,cAAc,EAAE,CAAC;IAC3D,IAAI,CAAC,kBAAkB,WAAW,EAAE,CAAC,CAAC;IAEtC,MAAM,UAAU,GAAG,IAAI,eAAM,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC;IAC/D,MAAM,WAAW,GAAG,MAAM,UAAU,CAAC,UAAU,EAAE,CAAC;IAClD,MAAM,UAAU,GAAG,MAAM,eAAe,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;IACjE,IAAI,CAAC,iBAAiB,WAAW,EAAE,CAAC,CAAC;IACrC,IAAI,CAAC,gBAAgB,eAAM,CAAC,WAAW,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IAC3D,IAAI,UAAU,KAAK,EAAE,EAAE;QACrB,IAAI,CAAC,iEAAiE,CAAC,CAAC;QACxE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;KACjB;IACD,EAAE,CAAC,yBAAyB,CAAC,CAAC;IAE9B,+DAA+D;IAC/D,IAAI,CAAC,CAAC,EAAE,0BAA0B,CAAC,CAAC;IAEpC,MAAM,SAAS,CAAC,OAAO,CAAC,CAAC;IACzB,kFAAkF;IAElF,MAAM,EAAE,GAAG,IAAI,mBAAS,CAAC,OAAO,CAAC,CAAC;IAElC,MAAM,aAAa,GAAG,IAAI,8BAAa,CACrC,CAAC,QAAQ,EAAE,EAAE,CAAC,YAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,cAAI,CAAC,OAAO,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC,EACzE,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE;QAC5B,MAAM,OAAO,GAAG,cAAI,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;QACjD,MAAM,QAAQ,GAAG,cAAI,CAAC,OAAO,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;QACvD,MAAM,YAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtD,MAAM,YAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC9C,CAAC,EACD,KAAK,EAAE,QAAQ,EAAE,EAAE,CAAC,UAAU,CAAC,cAAI,CAAC,OAAO,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC,CACtE,CAAC;IAEF,IAAA,kBAAU,EAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAEvC,MAAM,IAAA,wBAAiB,EACrB,cAAc,EAAG,qDAAqD;IACtE,EAAE,EAAe,WAAW;IAC5B,IAAI,EAAa,cAAc;IAC/B,aAAa,EAAI,gBAAgB;IACjC,KAAK,EAAY,sCAAsC;IACvD,KAAK,EAAY,sBAAsB;IACvC,KAAK,CACN,CAAC;IAEF,IAAA,gBAAS,GAAE,CAAC,MAAM,CAAC,iBAAiB,CAAC,iBAAyB,CAAC,CAAC;IAEhE,EAAE,CAAC,oBAAoB,CAAC,CAAC;IAEzB,8DAA8D;IAC9D,IAAI,CAAC,CAAC,EAAE,uBAAuB,CAAC,CAAC;IAEjC,MAAM,sBAAsB,GAA+B;QACzD,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,SAAS,EAAE;YACT;gBACE,QAAQ,EAAE,MAAM,CAAC,GAAG;gBACpB,QAAQ,EAAE,CAAC;gBACX,MAAM,EAAE,CAAC;gBACT,eAAe,EAAE,GAAG;gBACpB,YAAY,EAAE,IAAI;aACnB;SACF;KACF,CAAC;IAEF,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,IAAA,mBAAY,EAC3C,sBAAsB,EACtB,2BAAW,CAAC,OAAO,EACnB,IAAI,CACL,CAAC;IAEF,IAAI,CAAC,eAAe,cAAc,CAAC,SAAS,MAAM,CAAC,CAAC;IACpD,IAAI,CAAC,iBAAiB,cAAc,CAAC,WAAW,MAAM,CAAC,CAAC;IACxD,EAAE,CAAC,oCAAoC,CAAC,CAAC;IAEzC,8DAA8D;IAC9D,IAAI,CAAC,CAAC,EAAE,sBAAsB,CAAC,CAAC;IAEhC,MAAM,UAAU,GAAG,MAAM,IAAA,4BAAkB,EACzC,iBAAiB,EACjB,QAAQ,EACR,EAAE,CAAC,2BAAW,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,EAC5B,CAAC,CACF,CAAC;IAEF,IAAI,CAAC,cAAc,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC;IACpC,IAAI,CAAC,mBAAmB,UAAU,CAAC,aAAa,EAAE,CAAC,CAAC;IACpD,EAAE,CAAC,gBAAgB,CAAC,CAAC;IAErB,8DAA8D;IAC9D,IAAI,CAAC,CAAC,EAAE,uBAAuB,CAAC,CAAC;IAEjC,IAAI,YAAY,GAAG,KAAK,CAAC;IACzB,MAAM,WAAW,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QAChD,IAAA,sCAA+B,EAAC,CAAC,QAAmC,EAAE,EAAE;YACtE,IAAI,CAAC,gBAAgB,QAAQ,CAAC,UAAU,cAAc,CAAC,QAAQ,CAAC,QAAQ,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YAC/F,IAAI,QAAQ,CAAC,UAAU,KAAK,oCAAoB,CAAC,QAAQ,EAAE;gBACzD,YAAY,GAAG,IAAI,CAAC;gBACpB,OAAO,EAAE,CAAC;aACX;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,IAAI,cAAc,GAAG,KAAK,CAAC;IAC3B,IAAA,2CAA0B,EAAC,GAAG,EAAE;QAC9B,cAAc,GAAG,IAAI,CAAC;IACxB,CAAC,CAAC,CAAC;IAEH,MAAM,EAAE,KAAK,EAAE,GAAG,8BAAc,CAAC,2BAAW,CAAC,OAAO,CAAC,CAAC;IACtD,IAAA,gBAAS,GAAE,CAAC,mBAAmB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IAElD,wDAAwD;IACxD,MAAM,WAAW,GAAG,UAAU,CAAC,GAAG,EAAE;QAClC,IAAI,CAAC,YAAY,EAAE;YACjB,IAAI,CAAC,iCAAiC,CAAC,CAAC;SACzC;IACH,CAAC,EAAE,KAAK,CAAC,CAAC;IAEV,MAAM,OAAO,CAAC,IAAI,CAAC;QACjB,WAAW;QACX,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;KACnD,CAAC,CAAC;IACH,YAAY,CAAC,WAAW,CAAC,CAAC;IAE1B,EAAE,CAAC,uBAAuB,CAAC,CAAC;IAE5B,8DAA8D;IAC9D,IAAI,CAAC,CAAC,EAAE,iBAAiB,CAAC,CAAC;IAE3B,MAAM,IAAI,GAAG,IAAI,iBAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IAE9D,8DAA8D;IAC9D,+CAA+C;IAC/C,IAAI,KAAK,GAAG,MAAM,eAAe,CAAC,mBAAmB,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IAC9E,IAAI,CAAC,mBAAmB,KAAK,EAAE,CAAC,CAAC;IAEjC,IAAI,CAAC,cAAc,eAAM,CAAC,WAAW,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;IACtE,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,CAAgC,CAAC;IAC9G,MAAM,SAAS,CAAC,IAAI,EAAE,CAAC;IAEvB,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IACtD,IAAI,CAAC,iBAAiB,eAAM,CAAC,WAAW,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;IACzD,EAAE,CAAC,qBAAqB,CAAC,CAAC;IAE1B,8DAA8D;IAC9D,IAAI,CAAC,CAAC,EAAE,6BAA6B,CAAC,CAAC;IAEvC,IAAI,CAAC,aAAa,MAAM,CAAC,eAAe,mBAAmB,CAAC,CAAC;IAC7D,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,OAAO,CAClC,MAAM,CAAC,eAAe,EACtB,aAAa,EACb,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,CACY,CAAC;IACjC,MAAM,SAAS,CAAC,IAAI,EAAE,CAAC;IAEvB,EAAE,CAAC,qBAAqB,CAAC,CAAC;IAE1B,8DAA8D;IAC9D,IAAI,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC;IAEvB,qDAAqD;IACrD,MAAM,gBAAgB,GAAG,kBAAS,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IACjD,IAAI,CAAC,uBAAuB,gBAAgB,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;IAChE,IAAI,CAAC,oBAAoB,IAAA,+CAAmC,GAAE,GAAG,CAAC,CAAC;IAEnE,MAAM,qBAAqB,GAAG;QAC5B;YACE,YAAY,EAAE,MAAM,CAAC,IAAI;YACzB,MAAM,EAAE,aAAa;YACrB,gBAAgB,EAAE,UAAU,CAAC,aAAa;SAC3C;KACF,CAAC;IAEF,IAAI,CAAC,kCAAkC,CAAC,CAAC;IACzC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,GAAG,MAAM,IAAA,0BAAc,EACpD,2BAAW,CAAC,OAAO,EACnB,gBAAgB,EAChB,qBAAqB,EACrB,EAAE,EAAE,sBAAsB;IAC1B,SAAS,CACV,CAAC;IAEF,IAAI,CAAC,iBAAiB,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC;IACrC,IAAI,CAAC,+BAA+B,CAAC,CAAC;IAEtC,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,eAAe,CAAC,EAAE,GAAG,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;IACjF,IAAI,CAAC,YAAY,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IAEhC,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;IACpC,IAAI,CAAC,yBAAyB,OAAO,EAAE,WAAW,eAAe,OAAO,EAAE,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAChG,EAAE,CAAC,8BAA8B,CAAC,CAAC;IAEnC,8DAA8D;IAC9D,IAAI,CAAC,EAAE,EAAE,oCAAoC,CAAC,CAAC;IAE/C,IAAI,CAAC,sBAAsB,CAAC,CAAC;IAC7B,cAAc,GAAG,KAAK,CAAC;IAEvB,IAAA,gBAAS,GAAE,CAAC,mBAAmB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IAElD,0BAA0B;IAC1B,MAAM,cAAc,GAAG,KAAK,CAAC;IAC7B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC7B,OAAO,CAAC,cAAc,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,GAAG,cAAc,EAAE;QACjE,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;KACxD;IAED,IAAI,cAAc,EAAE;QAClB,EAAE,CAAC,8BAA8B,CAAC,CAAC;KACpC;SAAM;QACL,IAAI,CAAC,sEAAsE,CAAC,CAAC;KAC9E;IAED,4DAA4D;IAC5D,IAAI,CAAC,EAAE,EAAE,oCAAoC,CAAC,CAAC;IAE/C,MAAM,OAAO,GAAG,IAAA,qBAAW,EAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IAC3C,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,gBAAgB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC/D,MAAM,cAAc,GAAG,IAAA,2CAA0B,EAAC,SAAS,CAAC,CAAC;IAC7D,MAAM,YAAY,GAAG,cAAc,CAAC,IAAI,CACtC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,CAChE,CAAC;IAEF,IAAI,YAAY,EAAE;QAChB,IAAI,CAAC,yBAAyB,eAAM,CAAC,WAAW,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;KAC1E;SAAM;QACL,IAAI,CAAC,mCAAmC,CAAC,CAAC;QAC1C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;KACjB;IACD,EAAE,CAAC,2BAA2B,CAAC,CAAC;IAEhC,4DAA4D;IAC5D,IAAI,CAAC,EAAE,EAAE,yCAAyC,CAAC,CAAC;IAEpD,MAAM,WAAW,GAAG,MAAM,IAAA,4BAAkB,EAC1C,iBAAiB,EACjB,QAAQ,EACR,EAAE,CAAC,2BAAW,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,EAC5B,CAAC,CACF,CAAC;IAEF,IAAI,CAAC,gBAAgB,WAAW,CAAC,EAAE,EAAE,CAAC,CAAC;IACvC,IAAI,CAAC,qBAAqB,WAAW,CAAC,aAAa,EAAE,CAAC,CAAC;IACvD,EAAE,CAAC,uBAAuB,CAAC,CAAC;IAE5B,4DAA4D;IAC5D,IAAI,CAAC,EAAE,EAAE,6BAA6B,CAAC,CAAC;IAExC,IAAI,CAAC,gBAAgB,eAAM,CAAC,WAAW,CAAC,eAAe,CAAC,sBAAsB,CAAC,CAAC;IAChF,IAAI,CAAC,sDAAsD,CAAC,CAAC;IAE7D,MAAM,kBAAkB,GAAG;QACzB;YACE,YAAY,EAAE,MAAM,CAAC,IAAI;YACzB,MAAM,EAAE,eAAe;YACvB,gBAAgB,EAAE,WAAW,CAAC,aAAa;SAC5C;KACF,CAAC;IAEF,MAAM,IAAA,yCAAqB,EACzB,2BAAW,CAAC,OAAO,EACnB,UAAU,CAAC,EAAE,EACb,iBAAiB,EACjB,KAAK,EAAM,+BAA+B;IAC1C,SAAS,EAAE,WAAW;IACtB,kBAAkB,EAClB,EAAE,EAAS,sBAAsB;IACjC,SAAS,EAAE,qCAAqC;IAChD,IAAI,EAAO,uBAAuB;IAClC,SAAS,EAAE,0BAA0B;IACrC,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE;QACnB,IAAI,CAAC,UAAU,MAAM,KAAK,CAAC,QAAQ,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAC7D,CAAC,CACF,CAAC;IACF,EAAE,CAAC,0BAA0B,CAAC,CAAC;IAE/B,MAAM,kBAAkB,GAAG,MAAM,aAAa,CAAC,eAAe,CAAC,CAAC;IAEhE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,GAAG,MAAM,IAAA,oCAAsB,EAC9D,2BAAW,CAAC,OAAO,EACnB,UAAU,CAAC,EAAE,EACb,KAAK,EAAM,+BAA+B;IAC1C,SAAS,EAAE,WAAW;IACtB,kBAAkB,EAClB,EAAE,EAAS,sBAAsB;IACjC,SAAS,EAAE,qCAAqC;IAChD,IAAI,EAAO,uBAAuB;IAClC,SAAS,EAAE,0BAA0B;IACrC,kBAAkB,CACnB,CAAC;IAEF,IAAI,CAAC,mBAAmB,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC;IACzC,MAAM,cAAc,GAAG,MAAM,UAAU,CAAC,eAAe,CAAC,EAAE,GAAG,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;IAC3F,IAAI,CAAC,YAAY,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC;IAExC,MAAM,eAAe,GAAG,MAAM,cAAc,CAAC,IAAI,EAAE,CAAC;IACpD,IAAI,CAAC,yBAAyB,eAAe,EAAE,WAAW,eAAe,eAAe,EAAE,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAChH,EAAE,CAAC,qCAAqC,CAAC,CAAC;IAE1C,4DAA4D;IAC5D,IAAI,CAAC,EAAE,EAAE,uBAAuB,CAAC,CAAC;IAElC,IAAA,gBAAS,GAAE,CAAC,mBAAmB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IAClD,MAAM,OAAO,GAAG,MAAM,WAAW,EAAE,CAAC;IACpC,IAAI,OAAO,EAAE;QACX,EAAE,CAAC,eAAe,CAAC,CAAC;KACrB;SAAM;QACL,IAAI,CAAC,2BAA2B,CAAC,CAAC;KACnC;IAED,8FAA8F;IAC9F,IAAI,MAA4D,CAAC;IACjE,IAAI,MAA4D,CAAC;IACjE,IAAI;QACF,MAAM,cAAc,GAAG,MAAM,IAAA,qBAAW,EAAC,UAAU,CAAC,EAAE,CAAC,CAAC,gBAAgB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QACvF,MAAM,OAAO,GAAG,IAAA,2CAA0B,EAAC,cAAc,CAAC,CAAC;QAC3D,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QACvF,IAAI,CAAC,0BAA0B,MAAM,CAAC,CAAC,CAAC,eAAM,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;KACpF;IAAC,OAAO,GAAG,EAAE;QACZ,IAAI,CAAC,kCAAmC,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;KAClE;IACD,IAAI;QACF,MAAM,OAAO,GAAG,IAAA,qBAAW,EAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QAC5C,MAAM,cAAc,GAAG,MAAM,OAAO,CAAC,gBAAgB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QACpE,MAAM,OAAO,GAAG,IAAA,2CAA0B,EAAC,cAAc,CAAC,CAAC;QAC3D,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QACvF,IAAI,CAAC,0BAA0B,MAAM,CAAC,CAAC,CAAC,eAAM,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;KACpF;IAAC,OAAO,GAAG,EAAE;QACZ,IAAI,CAAC,kCAAmC,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;KAClE;IACD,EAAE,CAAC,2BAA2B,CAAC,CAAC;IAEhC,4DAA4D;IAC5D,IAAI,CAAC,EAAE,EAAE,0BAA0B,CAAC,CAAC;IAErC,IAAI,CAAC,eAAe,eAAM,CAAC,WAAW,CAAC,eAAe,CAAC,YAAY,WAAW,KAAK,CAAC,CAAC;IACrF,IAAI,CAAC,sDAAsD,CAAC,CAAC;IAE7D,MAAM,kBAAkB,GAAG;QACzB;YACE,YAAY,EAAE,MAAM,CAAC,IAAI;YACzB,MAAM,EAAE,eAAe;YACvB,gBAAgB,EAAE,WAAW,EAAE,qBAAqB;SACrD;KACF,CAAC;IAEF,MAAM,IAAA,yCAAqB,EACzB,2BAAW,CAAC,OAAO,EACnB,UAAU,CAAC,EAAE,EACb,iBAAiB,EACjB,kBAAkB,EAClB,EAAE,EAAS,sBAAsB;IACjC,SAAS,EAAE,qCAAqC;IAChD,IAAI,EAAO,uBAAuB;IAClC,SAAS,EAAE,0BAA0B;IACrC,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE;QACnB,IAAI,CAAC,UAAU,MAAM,KAAK,CAAC,QAAQ,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAC7D,CAAC,CACF,CAAC;IACF,EAAE,CAAC,0BAA0B,CAAC,CAAC;IAE/B,MAAM,kBAAkB,GAAG,MAAM,aAAa,CAAC,eAAe,CAAC,CAAC;IAEhE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,GAAG,MAAM,IAAA,oCAAsB,EAC9D,2BAAW,CAAC,OAAO,EACnB,UAAU,CAAC,EAAE,EACb,kBAAkB,EAClB,EAAE,EAAS,sBAAsB;IACjC,SAAS,EAAE,qCAAqC;IAChD,IAAI,EAAO,uBAAuB;IAClC,SAAS,EAAE,0BAA0B;IACrC,kBAAkB,CACnB,CAAC;IAEF,IAAI,CAAC,mBAAmB,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC;IACzC,MAAM,cAAc,GAAG,MAAM,UAAU,CAAC,eAAe,CAAC,EAAE,GAAG,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;IAC3F,IAAI,CAAC,YAAY,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC;IAExC,MAAM,eAAe,GAAG,MAAM,cAAc,CAAC,IAAI,EAAE,CAAC;IACpD,IAAI,CAAC,yBAAyB,eAAe,EAAE,WAAW,eAAe,eAAe,EAAE,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAChH,EAAE,CAAC,6BAA6B,CAAC,CAAC;IAElC,4DAA4D;IAC5D,IAAI,CAAC,EAAE,EAAE,iBAAiB,CAAC,CAAC;IAE5B,IAAA,gBAAS,GAAE,CAAC,mBAAmB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IAClD,MAAM,OAAO,GAAG,MAAM,WAAW,EAAE,CAAC;IACpC,IAAI,OAAO,EAAE;QACX,EAAE,CAAC,eAAe,CAAC,CAAC;KACrB;SAAM;QACL,IAAI,CAAC,2BAA2B,CAAC,CAAC;KACnC;IAED,MAAM,gBAAgB,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IAC3D,IAAI,CAAC,uCAAuC,eAAM,CAAC,WAAW,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC;IAEpF,IAAI,WAAiE,CAAC;IACtE,IAAI;QACF,MAAM,OAAO,GAAG,MAAM,IAAA,qBAAW,EAAC,UAAU,CAAC,EAAE,CAAC,CAAC,gBAAgB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAChF,MAAM,YAAY,GAAG,IAAA,2CAA0B,EAAC,OAAO,CAAC,CAAC;QACzD,WAAW,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QACjG,IAAI,CAAC,gCAAgC,WAAW,CAAC,CAAC,CAAC,eAAM,CAAC,WAAW,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;KACpG;IAAC,OAAO,GAAG,EAAE;QACZ,IAAI,CAAC,wCAAyC,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;KACxE;IAED,EAAE,CAAC,mBAAmB,CAAC,CAAC;IAExB,4DAA4D;IAC5D,IAAI,CAAC,EAAE,EAAE,eAAe,CAAC,CAAC;IAE1B,MAAM,eAAe,GAAG,MAAM,eAAe,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;IACtE,MAAM,gBAAgB,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IAE3D,IAAI,WAAiE,CAAC;IACtE,IAAI;QACF,MAAM,OAAO,GAAG,MAAM,IAAA,qBAAW,EAAC,WAAW,CAAC,EAAE,CAAC,CAAC,gBAAgB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QACjF,MAAM,YAAY,GAAG,IAAA,2CAA0B,EAAC,OAAO,CAAC,CAAC;QACzD,WAAW,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;KAClG;IAAC,OAAO,GAAG,EAAE;QACZ,IAAI,CAAC,wCAAyC,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;KACxE;IAED,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;IAClC,IAAI,CAAC,SAAS,eAAM,CAAC,WAAW,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;IACrD,IAAI,CAAC,SAAS,eAAM,CAAC,WAAW,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC;IACtD,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;IACpC,IAAI,CAAC,aAAa,WAAW,CAAC,CAAC,CAAC,eAAM,CAAC,WAAW,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC;IACrF,IAAI,CAAC,aAAa,WAAW,CAAC,CAAC,CAAC,eAAM,CAAC,WAAW,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC;IACrF,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;IACzC,IAAI,CAAC,aAAa,eAAM,CAAC,WAAW,CAAC,aAAa,CAAC,cAAc,cAAc,CAAC,SAAS,OAAO,CAAC,CAAC;IAClG,IAAI,CAAC,aAAa,eAAM,CAAC,WAAW,CAAC,eAAe,CAAC,8BAA8B,CAAC,CAAC;IACrF,IAAI,CAAC,aAAa,eAAM,CAAC,WAAW,CAAC,eAAe,CAAC,cAAc,cAAc,CAAC,WAAW,OAAO,CAAC,CAAC;IACtG,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEhB,8DAA8D;IAC9D,MAAM,IAAA,uBAAgB,GAAE,CAAC;IACzB,EAAE,CAAC,2CAA2C,CAAC,CAAC;IAChD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;IAClC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC","sourcesContent":["/// <reference types=\"../types/global\" />\n/* eslint-disable no-plusplus, no-await-in-loop, @typescript-eslint/no-floating-promises, @typescript-eslint/restrict-template-expressions, @typescript-eslint/strict-boolean-expressions, import/no-extraneous-dependencies */\n/**\n * Local E2E test for Matrix wallet against a local Ganache/Hardhat node.\n *\n * Prerequisites:\n * 1. Start local node: ./ganache.sh (or: npx hardhat node)\n * 2. Deploy contracts: cd matrix-contracts && yarn hardhat deploy:full --network localhost\n * 3. Fill in deployed addresses in wallet/local-deploy.json.example\n * (also set \"mnemonic\" and \"userPrivateKey\" matching your local node)\n *\n * Run:\n * cd wallet && npx ts-node -P tsconfig.test.json src/tests/local-e2e.ts\n */\n/* eslint-disable no-console */\n\nimport fs from 'fs';\nimport path from 'path';\nimport LevelDOWN from 'leveldown';\nimport { ethers, Wallet, JsonRpcProvider, Contract, ContractTransactionResponse } from 'ethers';\nimport { groth16 } from 'snarkjs';\nimport {\n NETWORK_CONFIG,\n NetworkName,\n FallbackProviderJsonConfig,\n MerkletreeScanStatus,\n MerkletreeScanUpdateEvent,\n EVMGasType,\n type TransactionGasDetailsType2,\n} from '@matrix-privacy/shared-models';\nimport {\n SnarkJSGroth16,\n MatrixContracts,\n ByteUtils,\n} from '@matrix-privacy/engine';\nimport {\n startMatrixEngine,\n stopMatrixEngine,\n getEngine,\n loadProvider,\n setOnUTXOMerkletreeScanCallback,\n} from '../services/matrix/core';\nimport {\n createMatrixWallet,\n walletForID,\n} from '../services/matrix/wallets/wallets';\nimport {\n setOnBalanceUpdateCallback,\n getSerializedERC20Balances,\n} from '../services/matrix/wallets/balance-update';\nimport {\n populateShield,\n getShieldPrivateKeySignatureMessage,\n} from '../services/transactions/tx-shield';\nimport { generateTransferProof } from '../services/transactions/tx-proof-transfer';\nimport { populateProvedTransfer } from '../services/transactions/tx-transfer';\nimport { generateUnshieldProof } from '../services/transactions/tx-proof-unshield';\nimport { populateProvedUnshield } from '../services/transactions/tx-unshield';\nimport { ArtifactStore } from '../services/artifacts/artifact-store';\nimport { setLoggers } from '../utils';\n\n// ============================================================\n// Configuration\n// ============================================================\n\nconst WALLET_ROOT = path.resolve(__dirname, '../..');\nconst CONFIG_PATH = path.resolve(WALLET_ROOT, 'local-deploy.json');\nconst CONFIG_PATH_EXAMPLE = path.resolve(WALLET_ROOT, 'local-deploy.json.example');\nconst DB_PATH = path.resolve(WALLET_ROOT, 'local-e2e.db');\nconst ARTIFACTS_DIR = path.resolve(WALLET_ROOT, 'local-e2e-artifacts');\n\n// Defaults (Ganache) — overridden by config file fields \"userPrivateKey\" / \"mnemonic\"\n// Using account[2] — account[0] is deployer, account[1] is treasury\nconst DEFAULT_USER_PRIVATE_KEY =\n '0xb9bf8d5cedb05765c054f80b69ba7770721b858deb51fc78a8c6962daab4b316'; // Ganache account[2]\nconst DEFAULT_MNEMONIC =\n 'tube level toe forget impulse absorb travel during coach option round coyote';\nconst DB_ENCRYPTION_KEY =\n '0101010101010101010101010101010101010101010101010101010101010101';\n\nconst SHIELD_AMOUNT = ethers.parseEther('1.0'); // 1 WETH\nconst TRANSFER_AMOUNT = ethers.parseEther('0.4'); // private transfer amount\nconst UNSHIELD_AMOUNT = ethers.parseEther('0.1'); // unshield amount\n\n// ============================================================\n// Types\n// ============================================================\n\ninterface DeployConfig {\n rpc: string;\n chainId: number;\n weth: string;\n accumulatorProxy: string;\n matrixProxy: string;\n verifierProxy: string;\n tokenVaultProxy: string;\n relayAdapt: string;\n // Optional: override default user key / mnemonic\n userPrivateKey?: string;\n mnemonic?: string;\n}\n\n// ============================================================\n// Helpers\n// ============================================================\n\nconst fileExists = (filePath: string): Promise<boolean> =>\n fs.promises.access(filePath).then(() => true).catch(() => false);\n\nconst rmDirSafe = async (dir: string) => {\n if (await fileExists(dir)) {\n await fs.promises.rm(dir, { recursive: true });\n }\n};\n\nconst step = (n: number, msg: string) =>\n console.log(`\\n${'='.repeat(60)}\\n Step ${n}: ${msg}\\n${'='.repeat(60)}`);\n\nconst info = (msg: string) => console.log(` [INFO] ${msg}`);\nconst ok = (msg: string) => console.log(` [OK] ${msg}`);\nconst fail = (msg: string) => console.error(` [FAIL] ${msg}`);\n\n// Minimal WETH9 ABI\nconst WETH9_ABI = [\n 'function deposit() payable',\n 'function approve(address spender, uint256 amount) returns (bool)',\n 'function balanceOf(address owner) view returns (uint256)',\n];\n\n/** Wait for a merkletree scan cycle to complete. */\nconst waitForScan = async (timeoutMs = 30000): Promise<boolean> => {\n return new Promise<boolean>((resolve) => {\n let done = false;\n const cb = (scanData: MerkletreeScanUpdateEvent) => {\n if (scanData.scanStatus === MerkletreeScanStatus.Complete && !done) {\n done = true;\n resolve(true);\n }\n };\n setOnUTXOMerkletreeScanCallback(cb);\n setTimeout(() => { if (!done) { done = true; resolve(false); } }, timeoutMs);\n });\n};\n\n/** Get gas details for Ganache (EIP-1559). */\nconst getGasDetails = async (\n provider: JsonRpcProvider,\n gasEstimate = 4_000_000n,\n): Promise<TransactionGasDetailsType2> => {\n const feeData = await provider.getFeeData();\n return {\n evmGasType: EVMGasType.Type2,\n gasEstimate,\n maxFeePerGas: feeData.maxFeePerGas ?? 2_000_000_000n,\n maxPriorityFeePerGas: feeData.maxPriorityFeePerGas ?? 1_000_000_000n,\n };\n};\n\n// ============================================================\n// Main\n// ============================================================\n\nasync function main() {\n console.log('\\nMatrix Wallet — Local E2E Test\\n');\n\n // ── Step 0: Read deployment config ──────────────────────────\n step(0, 'Read deployment config');\n\n // Try local-deploy.json first, then local-deploy.json.example\n let configFile: string | undefined;\n if (await fileExists(CONFIG_PATH)) {\n configFile = CONFIG_PATH;\n } else if (await fileExists(CONFIG_PATH_EXAMPLE)) {\n configFile = CONFIG_PATH_EXAMPLE;\n }\n\n if (!configFile) {\n fail(`Config file not found.`);\n console.log(`\\nLooked for:\\n ${CONFIG_PATH}\\n ${CONFIG_PATH_EXAMPLE}`);\n console.log('\\nCreate one with your deployed contract addresses.');\n console.log('Required fields: rpc, chainId, weth, accumulatorProxy,');\n console.log(' matrixProxy, verifierProxy, tokenVaultProxy, relayAdapt');\n console.log('Optional: userPrivateKey, mnemonic\\n');\n process.exit(1);\n }\n\n info(`Reading config from: ${path.basename(configFile)}`);\n const config: DeployConfig = JSON.parse(\n await fs.promises.readFile(configFile, 'utf-8'),\n );\n\n // Validate all addresses are present\n const requiredFields: (keyof DeployConfig)[] = [\n 'rpc', 'chainId', 'weth',\n 'accumulatorProxy', 'matrixProxy', 'verifierProxy',\n 'tokenVaultProxy', 'relayAdapt',\n ];\n for (const field of requiredFields) {\n if (!config[field]) {\n fail(`Missing field \"${field}\" in local-deploy.json`);\n process.exit(1);\n }\n }\n\n info(`RPC: ${config.rpc}`);\n info(`Chain ID: ${config.chainId}`);\n info(`WETH: ${config.weth}`);\n info(`Accumulator: ${config.accumulatorProxy}`);\n info(`Matrix: ${config.matrixProxy}`);\n info(`Verifier: ${config.verifierProxy}`);\n info(`TokenVault: ${config.tokenVaultProxy}`);\n info(`RelayAdapt: ${config.relayAdapt}`);\n ok('Config loaded');\n\n // ── Step 1: Patch NETWORK_CONFIG ────────────────────────────\n step(1, 'Patch NETWORK_CONFIG with deployed addresses');\n\n const networkConfig = NETWORK_CONFIG[NetworkName.Hardhat];\n networkConfig.chain.id = config.chainId;\n networkConfig.matrixContract = config.matrixProxy;\n networkConfig.accumulatorContract = config.accumulatorProxy;\n // Engine's \"verifier\" is the Matrix contract (legacy naming from Railgun's\n // PoseidonMerkleVerifier). It holds the execute() entry point.\n networkConfig.verifierContract = config.matrixProxy;\n networkConfig.tokenVaultContract = config.tokenVaultProxy;\n networkConfig.relayAdaptContract = config.relayAdapt;\n networkConfig.baseToken.wrappedAddress = config.weth;\n networkConfig.deploymentBlock = 0;\n\n ok('NETWORK_CONFIG patched');\n\n // ── Step 2: Connect to local node ───────────────────────────\n step(2, 'Connect to local node');\n\n const userPrivateKey = config.userPrivateKey || DEFAULT_USER_PRIVATE_KEY;\n const mnemonic = config.mnemonic || DEFAULT_MNEMONIC;\n\n const jsonRpcProvider = new JsonRpcProvider(config.rpc, config.chainId);\n const blockNumber = await jsonRpcProvider.getBlockNumber();\n info(`Current block: ${blockNumber}`);\n\n const userWallet = new Wallet(userPrivateKey, jsonRpcProvider);\n const userAddress = await userWallet.getAddress();\n const ethBalance = await jsonRpcProvider.getBalance(userAddress);\n info(`User address: ${userAddress}`);\n info(`ETH balance: ${ethers.formatEther(ethBalance)} ETH`);\n if (ethBalance === 0n) {\n fail('User account has 0 ETH — wrong private key or unfunded account?');\n process.exit(1);\n }\n ok('Connected to local node');\n\n // ── Step 3: Initialize Matrix Engine ────────────────────────\n step(3, 'Initialize Matrix Engine');\n\n await rmDirSafe(DB_PATH);\n // Keep ARTIFACTS_DIR across runs so IPFS-downloaded circuit artifacts are cached.\n\n const db = new LevelDOWN(DB_PATH);\n\n const artifactStore = new ArtifactStore(\n (filePath) => fs.promises.readFile(path.resolve(ARTIFACTS_DIR, filePath)),\n async (dir, filePath, data) => {\n const fullDir = path.resolve(ARTIFACTS_DIR, dir);\n const fullPath = path.resolve(ARTIFACTS_DIR, filePath);\n await fs.promises.mkdir(fullDir, { recursive: true });\n await fs.promises.writeFile(fullPath, data);\n },\n async (filePath) => fileExists(path.resolve(ARTIFACTS_DIR, filePath)),\n );\n\n setLoggers(console.log, console.error);\n\n await startMatrixEngine(\n 'locale2etest', // walletSource (max 16 chars, lowercase, no hyphens)\n db, // database\n true, // shouldDebug\n artifactStore, // artifactStore\n false, // useNativeArtifacts (nodejs = false)\n false, // skipMerkletreeScans\n false, // verboseScanLogging\n );\n\n getEngine().prover.setSnarkJSGroth16(groth16 as SnarkJSGroth16);\n\n ok('Engine initialized');\n\n // ── Step 4: Load network provider ──────────────────────────\n step(4, 'Load network provider');\n\n const fallbackProviderConfig: FallbackProviderJsonConfig = {\n chainId: config.chainId,\n providers: [\n {\n provider: config.rpc,\n priority: 1,\n weight: 2,\n maxLogsPerBatch: 100,\n stallTimeout: 5000,\n },\n ],\n };\n\n const { feesSerialized } = await loadProvider(\n fallbackProviderConfig,\n NetworkName.Hardhat,\n 5000, // pollingInterval (5s for local)\n );\n\n info(`Shield fee: ${feesSerialized.shieldFee} bps`);\n info(`Unshield fee: ${feesSerialized.unshieldFee} bps`);\n ok('Provider loaded, network connected');\n\n // ── Step 5: Create Matrix wallet ───────────────────────────\n step(5, 'Create Matrix wallet');\n\n const walletInfo = await createMatrixWallet(\n DB_ENCRYPTION_KEY,\n mnemonic,\n { [NetworkName.Hardhat]: 0 },\n 0, // derivationIndex\n );\n\n info(`Wallet ID: ${walletInfo.id}`);\n info(`Matrix address: ${walletInfo.matrixAddress}`);\n ok('Wallet created');\n\n // ── Step 6: Set up event listeners and scan ────────────────\n step(6, 'Scan contract history');\n\n let scanComplete = false;\n const scanPromise = new Promise<void>((resolve) => {\n setOnUTXOMerkletreeScanCallback((scanData: MerkletreeScanUpdateEvent) => {\n info(`Scan: status=${scanData.scanStatus}, progress=${(scanData.progress * 100).toFixed(1)}%`);\n if (scanData.scanStatus === MerkletreeScanStatus.Complete) {\n scanComplete = true;\n resolve();\n }\n });\n });\n\n let balanceUpdated = false;\n setOnBalanceUpdateCallback(() => {\n balanceUpdated = true;\n });\n\n const { chain } = NETWORK_CONFIG[NetworkName.Hardhat];\n getEngine().scanContractHistory(chain, undefined);\n\n // Wait for initial scan (should be fast on empty chain)\n const scanTimeout = setTimeout(() => {\n if (!scanComplete) {\n info('Scan taking long, continuing...');\n }\n }, 10000);\n\n await Promise.race([\n scanPromise,\n new Promise(resolve => setTimeout(resolve, 15000)),\n ]);\n clearTimeout(scanTimeout);\n\n ok('Initial scan complete');\n\n // ── Step 7: Wrap ETH → WETH ────────────────────────────────\n step(7, 'Wrap ETH → WETH');\n\n const weth = new Contract(config.weth, WETH9_ABI, userWallet);\n\n // Ganache instamine + ethers v6 nonce caching = stale nonces.\n // Fetch once, increment locally for each send.\n let nonce = await jsonRpcProvider.getTransactionCount(userAddress, 'pending');\n info(`Starting nonce: ${nonce}`);\n\n info(`Depositing ${ethers.formatEther(SHIELD_AMOUNT)} ETH → WETH...`);\n const depositTx = await weth.deposit({ value: SHIELD_AMOUNT, nonce: nonce++ }) as ContractTransactionResponse;\n await depositTx.wait();\n\n const wethBalance = await weth.balanceOf(userAddress);\n info(`WETH balance: ${ethers.formatEther(wethBalance)}`);\n ok('ETH wrapped to WETH');\n\n // ── Step 8: Approve TokenVault to spend WETH ───────────────\n step(8, 'Approve TokenVault for WETH');\n\n info(`Approving ${config.tokenVaultProxy} to spend WETH...`);\n const approveTx = await weth.approve(\n config.tokenVaultProxy,\n SHIELD_AMOUNT,\n { nonce: nonce++ },\n ) as ContractTransactionResponse;\n await approveTx.wait();\n\n ok('TokenVault approved');\n\n // ── Step 9: Shield WETH into Matrix wallet ─────────────────\n step(9, 'Shield WETH');\n\n // Generate a shield private key (random for testing)\n const shieldPrivateKey = ByteUtils.randomHex(32);\n info(`Shield private key: ${shieldPrivateKey.slice(0, 18)}...`);\n info(`Shield message: \"${getShieldPrivateKeySignatureMessage()}\"`);\n\n const erc20AmountRecipients = [\n {\n tokenAddress: config.weth,\n amount: SHIELD_AMOUNT,\n recipientAddress: walletInfo.matrixAddress,\n },\n ];\n\n info('Populating shield transaction...');\n const { transaction: shieldTx } = await populateShield(\n NetworkName.Hardhat,\n shieldPrivateKey,\n erc20AmountRecipients,\n [], // nftAmountRecipients\n undefined, // gasDetails (let the node estimate)\n );\n\n info(`Shield tx to: ${shieldTx.to}`);\n info('Sending shield transaction...');\n\n const sentTx = await userWallet.sendTransaction({ ...shieldTx, nonce: nonce++ });\n info(`TX hash: ${sentTx.hash}`);\n\n const receipt = await sentTx.wait();\n info(`TX confirmed in block ${receipt?.blockNumber}, gas used: ${receipt?.gasUsed.toString()}`);\n ok('Shield transaction confirmed');\n\n // ── Step 10: Wait for balance update ───────────────────────\n step(10, 'Wait for balance scan after shield');\n\n info('Triggering rescan...');\n balanceUpdated = false;\n\n getEngine().scanContractHistory(chain, undefined);\n\n // Wait for balance update\n const balanceTimeout = 30000;\n const startTime = Date.now();\n while (!balanceUpdated && Date.now() - startTime < balanceTimeout) {\n await new Promise(resolve => setTimeout(resolve, 500));\n }\n\n if (balanceUpdated) {\n ok('Balance updated after shield');\n } else {\n info('Balance update not received within timeout — check engine logs above');\n }\n\n // ── Step 11: Query private balance ───────────────────────\n step(11, 'Query private balance after shield');\n\n const wallet1 = walletForID(walletInfo.id);\n const balances1 = await wallet1.getTokenBalances(chain, false);\n const erc20Balances1 = getSerializedERC20Balances(balances1);\n const shieldedWeth = erc20Balances1.find(\n b => b.tokenAddress.toLowerCase() === config.weth.toLowerCase(),\n );\n\n if (shieldedWeth) {\n info(`Private WETH balance: ${ethers.formatEther(shieldedWeth.amount)}`);\n } else {\n fail('No WETH found in private balance!');\n process.exit(1);\n }\n ok('Private balance confirmed');\n\n // ── Step 12: Create second wallet (recipient) ────────────\n step(12, 'Create second Matrix wallet (recipient)');\n\n const wallet2Info = await createMatrixWallet(\n DB_ENCRYPTION_KEY,\n mnemonic,\n { [NetworkName.Hardhat]: 0 },\n 1, // derivation index 1\n );\n\n info(`Wallet 2 ID: ${wallet2Info.id}`);\n info(`Wallet 2 address: ${wallet2Info.matrixAddress}`);\n ok('Second wallet created');\n\n // ── Step 13: Private transfer ────────────────────────────\n step(13, 'Private transfer (ZK proof)');\n\n info(`Transferring ${ethers.formatEther(TRANSFER_AMOUNT)} WETH to wallet 2...`);\n info('Generating transfer proof (this may take ~30-60s)...');\n\n const transferRecipients = [\n {\n tokenAddress: config.weth,\n amount: TRANSFER_AMOUNT,\n recipientAddress: wallet2Info.matrixAddress,\n },\n ];\n\n await generateTransferProof(\n NetworkName.Hardhat,\n walletInfo.id,\n DB_ENCRYPTION_KEY,\n false, // showSenderAddressToRecipient\n undefined, // memoText\n transferRecipients,\n [], // nftAmountRecipients\n undefined, // broadcasterFeeERC20AmountRecipient\n true, // sendWithPublicWallet\n undefined, // overallBatchMinGasPrice\n (progress, status) => {\n info(`Proof: ${status} (${(progress * 100).toFixed(1)}%)`);\n },\n );\n ok('Transfer proof generated');\n\n const transferGasDetails = await getGasDetails(jsonRpcProvider);\n\n const { transaction: transferTx } = await populateProvedTransfer(\n NetworkName.Hardhat,\n walletInfo.id,\n false, // showSenderAddressToRecipient\n undefined, // memoText\n transferRecipients,\n [], // nftAmountRecipients\n undefined, // broadcasterFeeERC20AmountRecipient\n true, // sendWithPublicWallet\n undefined, // overallBatchMinGasPrice\n transferGasDetails,\n );\n\n info(`Transfer tx to: ${transferTx.to}`);\n const sentTransferTx = await userWallet.sendTransaction({ ...transferTx, nonce: nonce++ });\n info(`TX hash: ${sentTransferTx.hash}`);\n\n const transferReceipt = await sentTransferTx.wait();\n info(`TX confirmed in block ${transferReceipt?.blockNumber}, gas used: ${transferReceipt?.gasUsed.toString()}`);\n ok('Private transfer confirmed on-chain');\n\n // ── Step 14: Rescan + verify transfer balances ───────────\n step(14, 'Rescan after transfer');\n\n getEngine().scanContractHistory(chain, undefined);\n const scanOk1 = await waitForScan();\n if (scanOk1) {\n ok('Scan complete');\n } else {\n info('Scan timeout — continuing');\n }\n\n // Query both wallets (balance deserialization may fail for wallet 2 — investigate separately)\n let w1Weth: { tokenAddress: string; amount: bigint } | undefined;\n let w2Weth: { tokenAddress: string; amount: bigint } | undefined;\n try {\n const w1PostTransfer = await walletForID(walletInfo.id).getTokenBalances(chain, false);\n const w1Erc20 = getSerializedERC20Balances(w1PostTransfer);\n w1Weth = w1Erc20.find(b => b.tokenAddress.toLowerCase() === config.weth.toLowerCase());\n info(`Wallet 1 private WETH: ${w1Weth ? ethers.formatEther(w1Weth.amount) : '0'}`);\n } catch (err) {\n info(`Wallet 1 balance query failed: ${(err as Error).message}`);\n }\n try {\n const wallet2 = walletForID(wallet2Info.id);\n const w2PostTransfer = await wallet2.getTokenBalances(chain, false);\n const w2Erc20 = getSerializedERC20Balances(w2PostTransfer);\n w2Weth = w2Erc20.find(b => b.tokenAddress.toLowerCase() === config.weth.toLowerCase());\n info(`Wallet 2 private WETH: ${w2Weth ? ethers.formatEther(w2Weth.amount) : '0'}`);\n } catch (err) {\n info(`Wallet 2 balance query failed: ${(err as Error).message}`);\n }\n ok('Transfer balances checked');\n\n // ── Step 15: Unshield from wallet 1 ──────────────────────\n step(15, 'Unshield WETH (ZK proof)');\n\n info(`Unshielding ${ethers.formatEther(UNSHIELD_AMOUNT)} WETH to ${userAddress}...`);\n info('Generating unshield proof (this may take ~30-60s)...');\n\n const unshieldRecipients = [\n {\n tokenAddress: config.weth,\n amount: UNSHIELD_AMOUNT,\n recipientAddress: userAddress, // public ETH address\n },\n ];\n\n await generateUnshieldProof(\n NetworkName.Hardhat,\n walletInfo.id,\n DB_ENCRYPTION_KEY,\n unshieldRecipients,\n [], // nftAmountRecipients\n undefined, // broadcasterFeeERC20AmountRecipient\n true, // sendWithPublicWallet\n undefined, // overallBatchMinGasPrice\n (progress, status) => {\n info(`Proof: ${status} (${(progress * 100).toFixed(1)}%)`);\n },\n );\n ok('Unshield proof generated');\n\n const unshieldGasDetails = await getGasDetails(jsonRpcProvider);\n\n const { transaction: unshieldTx } = await populateProvedUnshield(\n NetworkName.Hardhat,\n walletInfo.id,\n unshieldRecipients,\n [], // nftAmountRecipients\n undefined, // broadcasterFeeERC20AmountRecipient\n true, // sendWithPublicWallet\n undefined, // overallBatchMinGasPrice\n unshieldGasDetails,\n );\n\n info(`Unshield tx to: ${unshieldTx.to}`);\n const sentUnshieldTx = await userWallet.sendTransaction({ ...unshieldTx, nonce: nonce++ });\n info(`TX hash: ${sentUnshieldTx.hash}`);\n\n const unshieldReceipt = await sentUnshieldTx.wait();\n info(`TX confirmed in block ${unshieldReceipt?.blockNumber}, gas used: ${unshieldReceipt?.gasUsed.toString()}`);\n ok('Unshield confirmed on-chain');\n\n // ── Step 16: Rescan + verify unshield ────────────────────\n step(16, 'Verify unshield');\n\n getEngine().scanContractHistory(chain, undefined);\n const scanOk2 = await waitForScan();\n if (scanOk2) {\n ok('Scan complete');\n } else {\n info('Scan timeout — continuing');\n }\n\n const postUnshieldWeth = await weth.balanceOf(userAddress);\n info(`Public WETH balance after unshield: ${ethers.formatEther(postUnshieldWeth)}`);\n\n let w1FinalWeth: { tokenAddress: string; amount: bigint } | undefined;\n try {\n const w1Final = await walletForID(walletInfo.id).getTokenBalances(chain, false);\n const w1FinalErc20 = getSerializedERC20Balances(w1Final);\n w1FinalWeth = w1FinalErc20.find(b => b.tokenAddress.toLowerCase() === config.weth.toLowerCase());\n info(`Wallet 1 final private WETH: ${w1FinalWeth ? ethers.formatEther(w1FinalWeth.amount) : '0'}`);\n } catch (err) {\n info(`Wallet 1 final balance query failed: ${(err as Error).message}`);\n }\n\n ok('Unshield verified');\n\n // ── Step 17: Final summary ───────────────────────────────\n step(17, 'Final Summary');\n\n const finalEthBalance = await jsonRpcProvider.getBalance(userAddress);\n const finalWethBalance = await weth.balanceOf(userAddress);\n\n let w2FinalWeth: { tokenAddress: string; amount: bigint } | undefined;\n try {\n const w2Final = await walletForID(wallet2Info.id).getTokenBalances(chain, false);\n const w2FinalErc20 = getSerializedERC20Balances(w2Final);\n w2FinalWeth = w2FinalErc20.find(b => b.tokenAddress.toLowerCase() === config.weth.toLowerCase());\n } catch (err) {\n info(`Wallet 2 final balance query failed: ${(err as Error).message}`);\n }\n\n console.log('\\n Public wallet:');\n info(`ETH: ${ethers.formatEther(finalEthBalance)}`);\n info(`WETH: ${ethers.formatEther(finalWethBalance)}`);\n console.log('\\n Private wallets:');\n info(`Wallet 1: ${w1FinalWeth ? ethers.formatEther(w1FinalWeth.amount) : '0'} WETH`);\n info(`Wallet 2: ${w2FinalWeth ? ethers.formatEther(w2FinalWeth.amount) : '0'} WETH`);\n console.log('\\n Operations completed:');\n info(`Shield: ${ethers.formatEther(SHIELD_AMOUNT)} WETH (fee ${feesSerialized.shieldFee} bps)`);\n info(`Transfer: ${ethers.formatEther(TRANSFER_AMOUNT)} WETH (wallet 1 -> wallet 2)`);\n info(`Unshield: ${ethers.formatEther(UNSHIELD_AMOUNT)} WETH (fee ${feesSerialized.unshieldFee} bps)`);\n console.log('');\n\n // ── Cleanup ────────────────────────────────────────────────\n await stopMatrixEngine();\n ok('Engine stopped. Full E2E test complete.\\n');\n process.exit(0);\n}\n\nmain().catch((err) => {\n console.error('\\n [FATAL]', err);\n process.exit(1);\n});\n"]}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { FallbackProviderJsonConfig, FeeTokenDetails, MatrixERC20Amount, MatrixNFTAmountRecipient, MatrixNFTAmount, TransactionGasDetails, MatrixERC20Recipient } from '@matrix-privacy/shared-models';
|
|
2
|
+
import { BalancesUpdatedCallback } from '../services/matrix/wallets/balance-update';
|
|
3
|
+
import { CommitmentCiphertextV3 } from '@matrix-privacy/engine';
|
|
4
|
+
export declare const MOCK_MNEMONIC = "test test test test test test test test test test test junk";
|
|
5
|
+
export declare const MOCK_MNEMONIC_2 = "pause crystal tornado alcohol genre cement fade large song like bag where";
|
|
6
|
+
export declare const MOCK_DB_ENCRYPTION_KEY = "0101010101010101010101010101010101010101010101010101010101010101";
|
|
7
|
+
export declare const MOCK_MEMO = "A nice little mock memo, and how bout a little more for ya? \uD83E\uDD29";
|
|
8
|
+
export declare const MOCK_MATRIX_WALLET_ADDRESS = "0zk1q8hxknrs97q8pjxaagwthzc0df99rzmhl2xnlxmgv9akv32sua0kfrv7j6fe3z53llhxknrs97q8pjxaagwthzc0df99rzmhl2xnlxmgv9akv32sua0kg0zpzts";
|
|
9
|
+
export declare const MOCK_ETH_WALLET_ADDRESS = "0x9E9F988356f46744Ee0374A17a5Fa1a3A3cC3777";
|
|
10
|
+
export declare const MOCK_TOKEN_ADDRESS = "0x5FbDB2315678afecb367f032d93F642f64180aa3";
|
|
11
|
+
export declare const MOCK_TOKEN_ADDRESS_2 = "0xe76C6c83af64e4C60245D8C7dE953DF673a7A33D";
|
|
12
|
+
export declare const MOCK_NFT_ADDRESS = "0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d";
|
|
13
|
+
export declare const TEST_POLYGON_RPC = "https://polygon-rpc.com";
|
|
14
|
+
export declare const TEST_WALLET_SOURCE = "test engine";
|
|
15
|
+
export declare const MOCK_TOKEN_AMOUNTS_TOKEN_1_ONLY: MatrixERC20Amount[];
|
|
16
|
+
export declare const MOCK_TOKEN_AMOUNTS: MatrixERC20Amount[];
|
|
17
|
+
export declare const MOCK_ERC20_RECIPIENTS: MatrixERC20Recipient[];
|
|
18
|
+
export declare const MOCK_NFT_AMOUNTS: MatrixNFTAmount[];
|
|
19
|
+
export declare const MOCK_COMMITMENTS: string[];
|
|
20
|
+
export declare const MOCK_NULLIFIERS: string[];
|
|
21
|
+
export declare const MOCK_BOUND_PARAMS_V3: {
|
|
22
|
+
local: {
|
|
23
|
+
commitmentCiphertext: {
|
|
24
|
+
ciphertext: string;
|
|
25
|
+
blindedSenderViewingKey: string;
|
|
26
|
+
blindedReceiverViewingKey: string;
|
|
27
|
+
}[];
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
export declare const MOCK_COMMITMENT_HASH = "0x2b13bccd4974c797df42a89221ed6e19e50c32055058cdcc5a8ea836233e4cab";
|
|
31
|
+
export declare const MOCK_FORMATTED_BROADCASTER_FEE_COMMITMENT_CIPHERTEXT_V3: CommitmentCiphertextV3;
|
|
32
|
+
export declare const MOCK_NFT_AMOUNT_RECIPIENTS: MatrixNFTAmountRecipient[];
|
|
33
|
+
export declare const MOCK_NFT_AMOUNT_RECIPIENTS_UNSHIELD: MatrixNFTAmountRecipient[];
|
|
34
|
+
export declare const MOCK_TOKEN_FEE: MatrixERC20Amount;
|
|
35
|
+
export declare const MOCK_FEE_TOKEN_DETAILS: FeeTokenDetails;
|
|
36
|
+
export declare const MOCK_TRANSACTION_GAS_DETAILS_SERIALIZED_TYPE_2: TransactionGasDetails;
|
|
37
|
+
export declare const MOCK_BALANCES_UPDATE_CALLBACK: BalancesUpdatedCallback;
|
|
38
|
+
export declare const MOCK_FALLBACK_PROVIDER_JSON_CONFIG_POLYGON: FallbackProviderJsonConfig;
|
|
39
|
+
export declare const MOCK_FALLBACK_PROVIDER_JSON_CONFIG_SEPOLIA: FallbackProviderJsonConfig;
|
|
40
|
+
export declare const MOCK_FALLBACK_PROVIDER_JSON_CONFIG_ETHEREUM: FallbackProviderJsonConfig;
|