@unlink-xyz/core 0.1.3-canary.fd5dddf → 0.1.4
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/README.md +9 -0
- package/dist/account/account.d.ts +31 -2
- package/dist/account/account.d.ts.map +1 -1
- package/dist/account/accounts.d.ts +42 -0
- package/dist/account/accounts.d.ts.map +1 -0
- package/dist/account/seed.d.ts +45 -0
- package/dist/account/seed.d.ts.map +1 -0
- package/dist/account/serialization.d.ts +6 -0
- package/dist/account/serialization.d.ts.map +1 -0
- package/dist/browser/index.js +34424 -86406
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/wallet/index.js +55942 -0
- package/dist/browser/wallet/index.js.map +1 -0
- package/dist/clients/broadcaster.d.ts +1 -0
- package/dist/clients/broadcaster.d.ts.map +1 -1
- package/dist/clients/indexer.d.ts +5 -0
- package/dist/clients/indexer.d.ts.map +1 -1
- package/dist/config.d.ts +6 -4
- package/dist/config.d.ts.map +1 -1
- package/dist/core.d.ts.map +1 -1
- package/dist/crypto/adapters/index.d.ts +17 -0
- package/dist/crypto/adapters/index.d.ts.map +1 -0
- package/dist/crypto/adapters/polyfills.d.ts +5 -0
- package/dist/crypto/adapters/polyfills.d.ts.map +1 -0
- package/dist/crypto/encrypt.d.ts +33 -0
- package/dist/crypto/encrypt.d.ts.map +1 -0
- package/dist/crypto/secure-memory.d.ts.map +1 -0
- package/dist/errors.d.ts +8 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6721 -23
- package/dist/index.js.map +1 -0
- package/dist/keys/derive.d.ts +2 -2
- package/dist/keys/derive.d.ts.map +1 -1
- package/dist/keys/hex.d.ts +1 -4
- package/dist/keys/hex.d.ts.map +1 -1
- package/dist/keys/mnemonic.d.ts +0 -2
- package/dist/keys/mnemonic.d.ts.map +1 -1
- package/dist/keys.d.ts +1 -0
- package/dist/keys.d.ts.map +1 -1
- package/dist/prover/config.d.ts +54 -9
- package/dist/prover/config.d.ts.map +1 -1
- package/dist/prover/integrity.d.ts +20 -0
- package/dist/prover/integrity.d.ts.map +1 -0
- package/dist/prover/prover.d.ts +16 -31
- package/dist/prover/prover.d.ts.map +1 -1
- package/dist/state/merkle/hydrator.d.ts +21 -19
- package/dist/state/merkle/hydrator.d.ts.map +1 -1
- package/dist/state/merkle/index.d.ts +1 -1
- package/dist/state/merkle/index.d.ts.map +1 -1
- package/dist/state/store/ciphertext-store.d.ts +7 -0
- package/dist/state/store/ciphertext-store.d.ts.map +1 -1
- package/dist/state/store/index.d.ts +1 -1
- package/dist/state/store/index.d.ts.map +1 -1
- package/dist/state/store/job-store.d.ts.map +1 -1
- package/dist/state/store/jobs.d.ts +14 -16
- package/dist/state/store/jobs.d.ts.map +1 -1
- package/dist/state/store/leaf-store.d.ts +4 -0
- package/dist/state/store/leaf-store.d.ts.map +1 -1
- package/dist/state/store/nullifier-store.d.ts.map +1 -1
- package/dist/state/store/records.d.ts +8 -0
- package/dist/state/store/records.d.ts.map +1 -1
- package/dist/state/store/store.d.ts +18 -0
- package/dist/state/store/store.d.ts.map +1 -1
- package/dist/storage/indexeddb.d.ts.map +1 -1
- package/dist/storage/memory.d.ts.map +1 -1
- package/dist/transactions/adapter.d.ts +31 -0
- package/dist/transactions/adapter.d.ts.map +1 -0
- package/dist/transactions/deposit.d.ts +1 -1
- package/dist/transactions/deposit.d.ts.map +1 -1
- package/dist/transactions/index.d.ts +4 -2
- package/dist/transactions/index.d.ts.map +1 -1
- package/dist/transactions/note-sync.d.ts +3 -3
- package/dist/transactions/note-sync.d.ts.map +1 -1
- package/dist/transactions/reconcile.d.ts +1 -1
- package/dist/transactions/reconcile.d.ts.map +1 -1
- package/dist/transactions/transact.d.ts +21 -2
- package/dist/transactions/transact.d.ts.map +1 -1
- package/dist/transactions/transaction-planner.d.ts +1 -1
- package/dist/transactions/transaction-planner.d.ts.map +1 -1
- package/dist/transactions/transfer-planner.d.ts +2 -1
- package/dist/transactions/transfer-planner.d.ts.map +1 -1
- package/dist/transactions/types/deposit.d.ts +3 -3
- package/dist/transactions/types/deposit.d.ts.map +1 -1
- package/dist/transactions/types/domain.d.ts +3 -0
- package/dist/transactions/types/domain.d.ts.map +1 -1
- package/dist/transactions/types/options.d.ts +14 -5
- package/dist/transactions/types/options.d.ts.map +1 -1
- package/dist/transactions/types/planning.d.ts +2 -0
- package/dist/transactions/types/planning.d.ts.map +1 -1
- package/dist/transactions/types/state-stores.d.ts +53 -5
- package/dist/transactions/types/state-stores.d.ts.map +1 -1
- package/dist/transactions/types/transact.d.ts +10 -3
- package/dist/transactions/types/transact.d.ts.map +1 -1
- package/dist/transactions/withdrawal-planner.d.ts +1 -1
- package/dist/transactions/withdrawal-planner.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/tsup.config.d.ts +8 -0
- package/dist/tsup.config.d.ts.map +1 -0
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/amounts.d.ts +0 -13
- package/dist/utils/amounts.d.ts.map +1 -1
- package/dist/utils/async.js +37 -34
- package/dist/utils/async.js.map +1 -0
- package/dist/utils/bigint.d.ts +0 -2
- package/dist/utils/bigint.d.ts.map +1 -1
- package/dist/utils/random.d.ts +5 -0
- package/dist/utils/random.d.ts.map +1 -1
- package/dist/utils/validators.d.ts.map +1 -1
- package/dist/vitest.config.d.ts.map +1 -1
- package/dist/wallet/adapter.d.ts +21 -0
- package/dist/wallet/adapter.d.ts.map +1 -0
- package/dist/wallet/burner/service.d.ts +32 -0
- package/dist/wallet/burner/service.d.ts.map +1 -0
- package/dist/wallet/burner/types.d.ts +47 -0
- package/dist/wallet/burner/types.d.ts.map +1 -0
- package/dist/wallet/index.d.ts +20 -0
- package/dist/wallet/index.d.ts.map +1 -0
- package/dist/wallet/index.js +6462 -0
- package/dist/wallet/index.js.map +1 -0
- package/dist/wallet/sdk.d.ts +48 -0
- package/dist/wallet/sdk.d.ts.map +1 -0
- package/dist/wallet/types.d.ts +457 -0
- package/dist/wallet/types.d.ts.map +1 -0
- package/dist/wallet/unlink-wallet.d.ts +187 -0
- package/dist/wallet/unlink-wallet.d.ts.map +1 -0
- package/package.json +16 -6
- package/dist/account/account.js +0 -142
- package/dist/circuits.json +0 -74
- package/dist/clients/broadcaster.js +0 -30
- package/dist/clients/http.js +0 -72
- package/dist/clients/indexer.js +0 -94
- package/dist/config.js +0 -36
- package/dist/constants.js +0 -5
- package/dist/core.js +0 -15
- package/dist/crypto-adapters/auto-init.d.ts +0 -2
- package/dist/crypto-adapters/auto-init.d.ts.map +0 -1
- package/dist/crypto-adapters/auto-init.js +0 -7
- package/dist/crypto-adapters/index.d.ts +0 -22
- package/dist/crypto-adapters/index.d.ts.map +0 -1
- package/dist/crypto-adapters/index.js +0 -47
- package/dist/crypto-adapters/polyfills.d.ts +0 -5
- package/dist/crypto-adapters/polyfills.d.ts.map +0 -1
- package/dist/crypto-adapters/polyfills.js +0 -8
- package/dist/errors.js +0 -36
- package/dist/history/index.js +0 -2
- package/dist/history/service.js +0 -354
- package/dist/history/types.js +0 -1
- package/dist/keys/address.js +0 -55
- package/dist/keys/derive.js +0 -112
- package/dist/keys/hex.js +0 -66
- package/dist/keys/index.js +0 -4
- package/dist/keys/mnemonic.js +0 -23
- package/dist/keys.js +0 -45
- package/dist/prover/config.js +0 -70
- package/dist/prover/index.js +0 -1
- package/dist/prover/prover.js +0 -291
- package/dist/prover/registry.js +0 -18
- package/dist/schema.js +0 -14
- package/dist/state/index.js +0 -2
- package/dist/state/merkle/hydrator.js +0 -37
- package/dist/state/merkle/index.js +0 -2
- package/dist/state/merkle/merkle-tree.js +0 -113
- package/dist/state/store/ciphertext-store.js +0 -37
- package/dist/state/store/history-store.js +0 -53
- package/dist/state/store/index.js +0 -9
- package/dist/state/store/job-store.js +0 -144
- package/dist/state/store/jobs.js +0 -1
- package/dist/state/store/leaf-store.js +0 -32
- package/dist/state/store/note-store.js +0 -146
- package/dist/state/store/nullifier-store.js +0 -60
- package/dist/state/store/records.js +0 -1
- package/dist/state/store/root-store.js +0 -26
- package/dist/state/store/store.js +0 -113
- package/dist/storage/index.js +0 -2
- package/dist/storage/indexeddb.js +0 -205
- package/dist/storage/memory.js +0 -91
- package/dist/transactions/deposit.js +0 -220
- package/dist/transactions/index.js +0 -9
- package/dist/transactions/note-selection.js +0 -201
- package/dist/transactions/note-sync.js +0 -485
- package/dist/transactions/reconcile.js +0 -85
- package/dist/transactions/transact.js +0 -450
- package/dist/transactions/transaction-planner.js +0 -116
- package/dist/transactions/transfer-planner.js +0 -85
- package/dist/transactions/types/deposit.js +0 -1
- package/dist/transactions/types/domain.js +0 -4
- package/dist/transactions/types/index.js +0 -17
- package/dist/transactions/types/options.js +0 -1
- package/dist/transactions/types/planning.js +0 -1
- package/dist/transactions/types/state-stores.js +0 -1
- package/dist/transactions/types/transact.js +0 -1
- package/dist/transactions/withdrawal-planner.js +0 -128
- package/dist/tsup.browser.config.js +0 -34
- package/dist/types.js +0 -1
- package/dist/utils/amounts.js +0 -89
- package/dist/utils/bigint.js +0 -29
- package/dist/utils/crypto.d.ts +0 -18
- package/dist/utils/crypto.d.ts.map +0 -1
- package/dist/utils/crypto.js +0 -45
- package/dist/utils/format.js +0 -33
- package/dist/utils/json-codec.js +0 -25
- package/dist/utils/notes.js +0 -14
- package/dist/utils/polling.js +0 -11
- package/dist/utils/random.js +0 -27
- package/dist/utils/secure-memory.d.ts.map +0 -1
- package/dist/utils/secure-memory.js +0 -28
- package/dist/utils/signature.js +0 -14
- package/dist/utils/validators.js +0 -96
- package/dist/vitest.config.js +0 -13
- /package/dist/{utils → crypto}/secure-memory.d.ts +0 -0
package/dist/config.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Environment types for SDK configuration.
|
|
3
|
-
*/
|
|
4
|
-
import { InitializationError } from "./errors.js";
|
|
5
|
-
const CONFIG_URL = "https://api.unlink.xyz/config/networks.json";
|
|
6
|
-
/**
|
|
7
|
-
* Fetch environment configuration from the hosted network config file.
|
|
8
|
-
*
|
|
9
|
-
* @param env - The environment to fetch config for
|
|
10
|
-
* @returns Promise resolving to the environment configuration
|
|
11
|
-
* @throws If fetch fails or environment is not found
|
|
12
|
-
*/
|
|
13
|
-
export async function fetchEnvironmentConfig(env) {
|
|
14
|
-
const res = await fetch(CONFIG_URL);
|
|
15
|
-
if (!res.ok) {
|
|
16
|
-
throw new InitializationError(`Failed to fetch SDK config: ${res.status}`);
|
|
17
|
-
}
|
|
18
|
-
const config = (await res.json());
|
|
19
|
-
if (!config[env]) {
|
|
20
|
-
throw new InitializationError(`Unknown environment: ${env}`);
|
|
21
|
-
}
|
|
22
|
-
return config[env];
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Create service configuration from an RPC URL.
|
|
26
|
-
*
|
|
27
|
-
* @param rpcUrl - The base RPC URL
|
|
28
|
-
* @returns Service configuration with broadcaster and indexer URLs
|
|
29
|
-
*/
|
|
30
|
-
export function createServiceConfig(rpcUrl) {
|
|
31
|
-
const baseUrl = rpcUrl.replace(/\/+$/, "");
|
|
32
|
-
return {
|
|
33
|
-
broadcasterBaseUrl: baseUrl + "/broadcaster",
|
|
34
|
-
indexerBaseUrl: baseUrl + "/indexer",
|
|
35
|
-
};
|
|
36
|
-
}
|
package/dist/constants.js
DELETED
package/dist/core.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { initCrypto } from "./crypto-adapters/index.js";
|
|
2
|
-
import { InitializationError } from "./errors.js";
|
|
3
|
-
import { migrate } from "./schema.js";
|
|
4
|
-
export async function initCore(deps) {
|
|
5
|
-
if (!deps?.storage)
|
|
6
|
-
throw new InitializationError("storage dep required");
|
|
7
|
-
if (!deps?.rng)
|
|
8
|
-
throw new InitializationError("rng dep required");
|
|
9
|
-
await initCrypto();
|
|
10
|
-
await migrate(deps.storage);
|
|
11
|
-
return {
|
|
12
|
-
storage: deps.storage,
|
|
13
|
-
rng: deps.rng,
|
|
14
|
-
};
|
|
15
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"auto-init.d.ts","sourceRoot":"","sources":["../../crypto-adapters/auto-init.ts"],"names":[],"mappings":""}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Auto-initialization module for tests.
|
|
3
|
-
* Import this at the top of test files to automatically initialize crypto, not in production code.
|
|
4
|
-
*/
|
|
5
|
-
import { initCrypto } from "./index.js";
|
|
6
|
-
await initCrypto();
|
|
7
|
-
console.log("[crypto] Auto-initialized for tests");
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Crypto adapters for browser-compatible cryptographic operations.
|
|
3
|
-
*
|
|
4
|
-
* Exports:
|
|
5
|
-
* - poseidon: Poseidon hash from circomlibjs (iden3)
|
|
6
|
-
* - deriveSpendingPublicKey, signMessage, verifySignature: EdDSA from @zk-kit/eddsa-poseidon
|
|
7
|
-
* - initCrypto: Async function to initialize crypto primitives (must be called before using poseidon)
|
|
8
|
-
*/
|
|
9
|
-
import "./polyfills.js";
|
|
10
|
-
/**
|
|
11
|
-
* Initialize the crypto primitives (Poseidon hash function).
|
|
12
|
-
* This must be called before using the poseidon function.
|
|
13
|
-
* Safe to call multiple times - subsequent calls return the same promise.
|
|
14
|
-
*/
|
|
15
|
-
export declare function initCrypto(): Promise<void>;
|
|
16
|
-
/**
|
|
17
|
-
* Poseidon hash function compatible with circomlib circuits.
|
|
18
|
-
* Wraps circomlibjs buildPoseidon to return bigint directly.
|
|
19
|
-
*/
|
|
20
|
-
export declare const poseidon: (inputs: (bigint | number)[]) => bigint;
|
|
21
|
-
export { derivePublicKey as deriveSpendingPublicKey, signMessage, verifySignature, } from "@zk-kit/eddsa-poseidon";
|
|
22
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../crypto-adapters/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,gBAAgB,CAAC;AAWxB;;;;GAIG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAehD;AAED;;;GAGG;AACH,eAAO,MAAM,QAAQ,GAAI,QAAQ,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,KAAG,MAQtD,CAAC;AAEF,OAAO,EACL,eAAe,IAAI,uBAAuB,EAC1C,WAAW,EACX,eAAe,GAChB,MAAM,wBAAwB,CAAC"}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Crypto adapters for browser-compatible cryptographic operations.
|
|
3
|
-
*
|
|
4
|
-
* Exports:
|
|
5
|
-
* - poseidon: Poseidon hash from circomlibjs (iden3)
|
|
6
|
-
* - deriveSpendingPublicKey, signMessage, verifySignature: EdDSA from @zk-kit/eddsa-poseidon
|
|
7
|
-
* - initCrypto: Async function to initialize crypto primitives (must be called before using poseidon)
|
|
8
|
-
*/
|
|
9
|
-
// Polyfill must be the first import
|
|
10
|
-
import "./polyfills.js";
|
|
11
|
-
import { InitializationError } from "../errors.js";
|
|
12
|
-
let _poseidon = null;
|
|
13
|
-
let _initPromise = null;
|
|
14
|
-
/**
|
|
15
|
-
* Initialize the crypto primitives (Poseidon hash function).
|
|
16
|
-
* This must be called before using the poseidon function.
|
|
17
|
-
* Safe to call multiple times - subsequent calls return the same promise.
|
|
18
|
-
*/
|
|
19
|
-
export async function initCrypto() {
|
|
20
|
-
if (_poseidon)
|
|
21
|
-
return; // Already initialized
|
|
22
|
-
if (_initPromise)
|
|
23
|
-
return _initPromise; // Initialization in progress
|
|
24
|
-
_initPromise = (async () => {
|
|
25
|
-
try {
|
|
26
|
-
const { buildPoseidon } = await import("circomlibjs");
|
|
27
|
-
_poseidon = await buildPoseidon();
|
|
28
|
-
}
|
|
29
|
-
catch (error) {
|
|
30
|
-
_initPromise = null; // Reset to allow retry
|
|
31
|
-
throw error;
|
|
32
|
-
}
|
|
33
|
-
})();
|
|
34
|
-
return _initPromise;
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Poseidon hash function compatible with circomlib circuits.
|
|
38
|
-
* Wraps circomlibjs buildPoseidon to return bigint directly.
|
|
39
|
-
*/
|
|
40
|
-
export const poseidon = (inputs) => {
|
|
41
|
-
if (!_poseidon) {
|
|
42
|
-
throw new InitializationError("Crypto not initialized. Call initCrypto() before using poseidon().");
|
|
43
|
-
}
|
|
44
|
-
const hash = _poseidon(inputs);
|
|
45
|
-
return _poseidon.F.toObject(hash);
|
|
46
|
-
};
|
|
47
|
-
export { derivePublicKey as deriveSpendingPublicKey, signMessage, verifySignature, } from "@zk-kit/eddsa-poseidon";
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"polyfills.d.ts","sourceRoot":"","sources":["../../crypto-adapters/polyfills.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
package/dist/errors.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
export class CoreError extends Error {
|
|
2
|
-
constructor(message) {
|
|
3
|
-
super(message);
|
|
4
|
-
this.name = "CoreError";
|
|
5
|
-
}
|
|
6
|
-
}
|
|
7
|
-
export class KeyValidationError extends CoreError {
|
|
8
|
-
constructor(message) {
|
|
9
|
-
super(message);
|
|
10
|
-
this.name = "KeyValidationError";
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
export class SchemaMismatchError extends CoreError {
|
|
14
|
-
constructor(current, expected) {
|
|
15
|
-
super(`schema mismatch (current ${current}, expected ${expected})`);
|
|
16
|
-
this.name = "SchemaMismatchError";
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
export class ValidationError extends CoreError {
|
|
20
|
-
constructor(message) {
|
|
21
|
-
super(message);
|
|
22
|
-
this.name = "ValidationError";
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
export class ProofError extends CoreError {
|
|
26
|
-
constructor(message) {
|
|
27
|
-
super(message);
|
|
28
|
-
this.name = "ProofError";
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
export class InitializationError extends CoreError {
|
|
32
|
-
constructor(message) {
|
|
33
|
-
super(message);
|
|
34
|
-
this.name = "InitializationError";
|
|
35
|
-
}
|
|
36
|
-
}
|
package/dist/history/index.js
DELETED
package/dist/history/service.js
DELETED
|
@@ -1,354 +0,0 @@
|
|
|
1
|
-
import { ensureChainId, ensureMpk } from "../utils/validators.js";
|
|
2
|
-
function addByToken(totals, token, delta) {
|
|
3
|
-
totals.set(token, (totals.get(token) ?? 0n) + delta);
|
|
4
|
-
}
|
|
5
|
-
function maxTimestamp(notes, field) {
|
|
6
|
-
let max = 0;
|
|
7
|
-
for (const note of notes) {
|
|
8
|
-
const timestamp = note[field];
|
|
9
|
-
if (timestamp !== undefined)
|
|
10
|
-
max = Math.max(max, timestamp);
|
|
11
|
-
}
|
|
12
|
-
return max > 0 ? max : undefined;
|
|
13
|
-
}
|
|
14
|
-
const STATUS_PRIORITY = {
|
|
15
|
-
failed: 3,
|
|
16
|
-
pending: 2,
|
|
17
|
-
confirmed: 1,
|
|
18
|
-
};
|
|
19
|
-
function convertJobStatus(jobStatus) {
|
|
20
|
-
if (jobStatus === "failed" || jobStatus === "dead")
|
|
21
|
-
return "failed";
|
|
22
|
-
if (jobStatus === "pending" ||
|
|
23
|
-
jobStatus === "submitted" ||
|
|
24
|
-
jobStatus === "broadcasting")
|
|
25
|
-
return "pending";
|
|
26
|
-
return "confirmed";
|
|
27
|
-
}
|
|
28
|
-
function mergeStatus(prev, next) {
|
|
29
|
-
if (!prev)
|
|
30
|
-
return next;
|
|
31
|
-
return STATUS_PRIORITY[next] > STATUS_PRIORITY[prev] ? next : prev;
|
|
32
|
-
}
|
|
33
|
-
function computeEntryId(params) {
|
|
34
|
-
return `${params.chainId}:${params.mpk}:${params.txHash}:${params.kind}`;
|
|
35
|
-
}
|
|
36
|
-
function groupNotesByTransaction(notes) {
|
|
37
|
-
const byTx = new Map();
|
|
38
|
-
const ensureGroup = (txHash) => {
|
|
39
|
-
const existing = byTx.get(txHash);
|
|
40
|
-
if (existing)
|
|
41
|
-
return existing;
|
|
42
|
-
const next = {
|
|
43
|
-
created: [],
|
|
44
|
-
spent: [],
|
|
45
|
-
createdEventType: undefined,
|
|
46
|
-
};
|
|
47
|
-
byTx.set(txHash, next);
|
|
48
|
-
return next;
|
|
49
|
-
};
|
|
50
|
-
for (const note of notes) {
|
|
51
|
-
if (note.createdTxHash) {
|
|
52
|
-
const group = ensureGroup(note.createdTxHash);
|
|
53
|
-
group.created.push(note);
|
|
54
|
-
group.createdEventType ??= note.createdEventType;
|
|
55
|
-
}
|
|
56
|
-
if (note.spentTxHash) {
|
|
57
|
-
const group = ensureGroup(note.spentTxHash);
|
|
58
|
-
group.spent.push(note);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return byTx;
|
|
62
|
-
}
|
|
63
|
-
function resolveJobStatuses(jobs, chainId, mpk) {
|
|
64
|
-
const statusByTxHash = new Map();
|
|
65
|
-
for (const job of jobs) {
|
|
66
|
-
if (job.chainId !== chainId)
|
|
67
|
-
continue;
|
|
68
|
-
if (job.mpk && job.mpk !== mpk)
|
|
69
|
-
continue;
|
|
70
|
-
const txHash = job.txHash ?? undefined;
|
|
71
|
-
if (!txHash)
|
|
72
|
-
continue;
|
|
73
|
-
const status = convertJobStatus(job.status);
|
|
74
|
-
statusByTxHash.set(txHash, mergeStatus(statusByTxHash.get(txHash), status));
|
|
75
|
-
}
|
|
76
|
-
return statusByTxHash;
|
|
77
|
-
}
|
|
78
|
-
function aggregateAmounts(group) {
|
|
79
|
-
const createdTotals = new Map();
|
|
80
|
-
const spentTotals = new Map();
|
|
81
|
-
for (const note of group.created) {
|
|
82
|
-
addByToken(createdTotals, note.token, BigInt(note.value));
|
|
83
|
-
}
|
|
84
|
-
for (const note of group.spent) {
|
|
85
|
-
addByToken(spentTotals, note.token, BigInt(note.value));
|
|
86
|
-
}
|
|
87
|
-
const tokens = new Set([
|
|
88
|
-
...createdTotals.keys(),
|
|
89
|
-
...spentTotals.keys(),
|
|
90
|
-
]);
|
|
91
|
-
const netByToken = new Map();
|
|
92
|
-
let hasNetChange = false;
|
|
93
|
-
for (const token of tokens) {
|
|
94
|
-
const created = createdTotals.get(token) ?? 0n;
|
|
95
|
-
const spent = spentTotals.get(token) ?? 0n;
|
|
96
|
-
const net = created - spent;
|
|
97
|
-
netByToken.set(token, net);
|
|
98
|
-
if (net !== 0n)
|
|
99
|
-
hasNetChange = true;
|
|
100
|
-
}
|
|
101
|
-
return { createdTotals, spentTotals, netByToken, hasNetChange };
|
|
102
|
-
}
|
|
103
|
-
function classifyTransaction(group, amounts) {
|
|
104
|
-
const isSelfSend = group.spent.length > 0 && !amounts.hasNetChange;
|
|
105
|
-
if (isSelfSend) {
|
|
106
|
-
return "SelfSend";
|
|
107
|
-
}
|
|
108
|
-
else if (group.spent.length > 0) {
|
|
109
|
-
return "Send";
|
|
110
|
-
}
|
|
111
|
-
else if (group.created.length > 0) {
|
|
112
|
-
return group.createdEventType === "deposit" ? "Deposit" : "Receive";
|
|
113
|
-
}
|
|
114
|
-
return null;
|
|
115
|
-
}
|
|
116
|
-
function computeFinalAmounts(kind, amounts) {
|
|
117
|
-
const finalTotals = new Map();
|
|
118
|
-
const tokens = new Set([
|
|
119
|
-
...amounts.createdTotals.keys(),
|
|
120
|
-
...amounts.spentTotals.keys(),
|
|
121
|
-
]);
|
|
122
|
-
if (kind === "SelfSend") {
|
|
123
|
-
for (const token of tokens)
|
|
124
|
-
finalTotals.set(token, 0n);
|
|
125
|
-
}
|
|
126
|
-
else if (kind === "Send" || kind === "Withdraw") {
|
|
127
|
-
for (const [token, net] of amounts.netByToken.entries()) {
|
|
128
|
-
if (net < 0n)
|
|
129
|
-
finalTotals.set(token, net);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
else {
|
|
133
|
-
for (const [token, net] of amounts.netByToken.entries()) {
|
|
134
|
-
if (net > 0n)
|
|
135
|
-
finalTotals.set(token, net);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
return finalTotals;
|
|
139
|
-
}
|
|
140
|
-
function selectTimestamp(kind, group) {
|
|
141
|
-
if (kind === "Deposit" || kind === "Receive") {
|
|
142
|
-
return maxTimestamp(group.created, "createdAt");
|
|
143
|
-
}
|
|
144
|
-
else if (kind === "Send" || kind === "SelfSend" || kind === "Withdraw") {
|
|
145
|
-
return (maxTimestamp(group.spent, "spentAt") ??
|
|
146
|
-
maxTimestamp(group.created, "createdAt"));
|
|
147
|
-
}
|
|
148
|
-
return undefined;
|
|
149
|
-
}
|
|
150
|
-
function buildHistoryEntry(params) {
|
|
151
|
-
return {
|
|
152
|
-
id: computeEntryId({
|
|
153
|
-
chainId: params.chainId,
|
|
154
|
-
mpk: params.mpk,
|
|
155
|
-
txHash: params.txHash,
|
|
156
|
-
kind: params.kind,
|
|
157
|
-
}),
|
|
158
|
-
chainId: params.chainId,
|
|
159
|
-
mpk: params.mpk,
|
|
160
|
-
txHash: params.txHash,
|
|
161
|
-
kind: params.kind,
|
|
162
|
-
status: params.status,
|
|
163
|
-
timestamp: params.timestamp,
|
|
164
|
-
amounts: [...params.finalAmounts.entries()].map(([token, delta]) => ({
|
|
165
|
-
token,
|
|
166
|
-
delta: delta.toString(),
|
|
167
|
-
})),
|
|
168
|
-
details: {
|
|
169
|
-
createdNoteCount: params.group.created.length,
|
|
170
|
-
spentNoteCount: params.group.spent.length,
|
|
171
|
-
createdEventType: params.group.createdEventType ?? "unknown",
|
|
172
|
-
},
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
export function createHistoryService(stateStore) {
|
|
176
|
-
// Track pending rebuilds to prevent concurrent execution
|
|
177
|
-
const pendingRebuilds = new Map();
|
|
178
|
-
async function computeHistory(params) {
|
|
179
|
-
ensureChainId(params.chainId);
|
|
180
|
-
ensureMpk(params.mpk);
|
|
181
|
-
// Fetch data
|
|
182
|
-
const notes = await stateStore.listNotes({
|
|
183
|
-
chainId: params.chainId,
|
|
184
|
-
mpk: params.mpk,
|
|
185
|
-
includeSpent: true,
|
|
186
|
-
});
|
|
187
|
-
const jobs = await stateStore.listJobs({
|
|
188
|
-
statuses: [
|
|
189
|
-
"pending",
|
|
190
|
-
"submitted",
|
|
191
|
-
"broadcasting",
|
|
192
|
-
"failed",
|
|
193
|
-
"dead",
|
|
194
|
-
"succeeded",
|
|
195
|
-
],
|
|
196
|
-
});
|
|
197
|
-
// Group notes by transaction hash
|
|
198
|
-
const byTx = groupNotesByTransaction(notes);
|
|
199
|
-
// Resolve job statuses for each transaction
|
|
200
|
-
const statusByTxHash = resolveJobStatuses(jobs, params.chainId, params.mpk);
|
|
201
|
-
const entries = [];
|
|
202
|
-
const confirmedTxHashes = new Set();
|
|
203
|
-
// Process each transaction group
|
|
204
|
-
for (const [txHash, group] of byTx.entries()) {
|
|
205
|
-
if (group.created.length === 0 && group.spent.length === 0)
|
|
206
|
-
continue;
|
|
207
|
-
// Aggregate amounts and compute net deltas
|
|
208
|
-
const amounts = aggregateAmounts(group);
|
|
209
|
-
// Classify transaction type
|
|
210
|
-
const kind = classifyTransaction(group, amounts);
|
|
211
|
-
if (!kind)
|
|
212
|
-
continue;
|
|
213
|
-
// Compute final amounts to display
|
|
214
|
-
const finalAmounts = computeFinalAmounts(kind, amounts);
|
|
215
|
-
if (finalAmounts.size === 0)
|
|
216
|
-
continue;
|
|
217
|
-
// Select appropriate timestamp
|
|
218
|
-
const timestamp = selectTimestamp(kind, group);
|
|
219
|
-
// Build history entry
|
|
220
|
-
const entry = buildHistoryEntry({
|
|
221
|
-
chainId: params.chainId,
|
|
222
|
-
mpk: params.mpk,
|
|
223
|
-
txHash,
|
|
224
|
-
kind,
|
|
225
|
-
status: statusByTxHash.get(txHash) ?? "confirmed",
|
|
226
|
-
timestamp,
|
|
227
|
-
finalAmounts,
|
|
228
|
-
group,
|
|
229
|
-
});
|
|
230
|
-
confirmedTxHashes.add(txHash);
|
|
231
|
-
entries.push(entry);
|
|
232
|
-
}
|
|
233
|
-
// Add pending job entries for transactions not yet indexed
|
|
234
|
-
for (const job of jobs) {
|
|
235
|
-
if (job.chainId !== params.chainId)
|
|
236
|
-
continue;
|
|
237
|
-
if (job.mpk && job.mpk !== params.mpk)
|
|
238
|
-
continue;
|
|
239
|
-
const txHash = job.txHash ?? undefined;
|
|
240
|
-
if (!txHash)
|
|
241
|
-
continue;
|
|
242
|
-
if (confirmedTxHashes.has(txHash))
|
|
243
|
-
continue;
|
|
244
|
-
if (!job.historyPreview)
|
|
245
|
-
continue;
|
|
246
|
-
if (job.status === "succeeded")
|
|
247
|
-
continue;
|
|
248
|
-
const status = job.status === "failed" || job.status === "dead" ? "failed" : "pending";
|
|
249
|
-
entries.push({
|
|
250
|
-
id: computeEntryId({
|
|
251
|
-
chainId: params.chainId,
|
|
252
|
-
mpk: params.mpk,
|
|
253
|
-
txHash,
|
|
254
|
-
kind: job.historyPreview.kind,
|
|
255
|
-
}),
|
|
256
|
-
chainId: params.chainId,
|
|
257
|
-
mpk: params.mpk,
|
|
258
|
-
txHash,
|
|
259
|
-
kind: job.historyPreview.kind,
|
|
260
|
-
status,
|
|
261
|
-
timestamp: job.createdAt,
|
|
262
|
-
amounts: job.historyPreview.amounts,
|
|
263
|
-
details: {
|
|
264
|
-
source: "job",
|
|
265
|
-
jobKind: job.kind,
|
|
266
|
-
},
|
|
267
|
-
});
|
|
268
|
-
}
|
|
269
|
-
// Sort by timestamp descending
|
|
270
|
-
entries.sort((a, b) => {
|
|
271
|
-
const at = a.timestamp ?? 0;
|
|
272
|
-
const bt = b.timestamp ?? 0;
|
|
273
|
-
if (at !== bt)
|
|
274
|
-
return bt - at;
|
|
275
|
-
return b.txHash.localeCompare(a.txHash);
|
|
276
|
-
});
|
|
277
|
-
// Filter self-sends if needed (unified filtering point)
|
|
278
|
-
return params.includeSelfSends
|
|
279
|
-
? entries
|
|
280
|
-
: entries.filter((e) => e.kind !== "SelfSend");
|
|
281
|
-
}
|
|
282
|
-
async function computeAndPersist(params) {
|
|
283
|
-
// Always compute with self-sends included for complete storage
|
|
284
|
-
const allEntries = await computeHistory({
|
|
285
|
-
chainId: params.chainId,
|
|
286
|
-
mpk: params.mpk,
|
|
287
|
-
includeSelfSends: true,
|
|
288
|
-
});
|
|
289
|
-
await stateStore.clearHistoryEntries({
|
|
290
|
-
chainId: params.chainId,
|
|
291
|
-
mpk: params.mpk,
|
|
292
|
-
});
|
|
293
|
-
await Promise.all(allEntries.map((entry) => stateStore.putHistoryEntry(entry)));
|
|
294
|
-
await stateStore.commitHistorySnapshot({
|
|
295
|
-
chainId: params.chainId,
|
|
296
|
-
mpk: params.mpk,
|
|
297
|
-
});
|
|
298
|
-
}
|
|
299
|
-
return {
|
|
300
|
-
async rebuildHistory(params) {
|
|
301
|
-
const rebuildKey = `${params.chainId}:${params.mpk}`;
|
|
302
|
-
// If a rebuild is already in progress, wait for it instead of starting a new one
|
|
303
|
-
const existing = pendingRebuilds.get(rebuildKey);
|
|
304
|
-
if (existing) {
|
|
305
|
-
return existing;
|
|
306
|
-
}
|
|
307
|
-
// Start a new rebuild and track it
|
|
308
|
-
const rebuildPromise = computeAndPersist(params).finally(() => {
|
|
309
|
-
// Clean up when done
|
|
310
|
-
pendingRebuilds.delete(rebuildKey);
|
|
311
|
-
});
|
|
312
|
-
pendingRebuilds.set(rebuildKey, rebuildPromise);
|
|
313
|
-
return rebuildPromise;
|
|
314
|
-
},
|
|
315
|
-
async getHistory(params) {
|
|
316
|
-
ensureChainId(params.chainId);
|
|
317
|
-
ensureMpk(params.mpk);
|
|
318
|
-
// If rebuild in progress, wait for it
|
|
319
|
-
const rebuildKey = `${params.chainId}:${params.mpk}`;
|
|
320
|
-
const pendingRebuild = pendingRebuilds.get(rebuildKey);
|
|
321
|
-
if (pendingRebuild) {
|
|
322
|
-
await pendingRebuild;
|
|
323
|
-
}
|
|
324
|
-
if (params.force) {
|
|
325
|
-
await computeAndPersist({
|
|
326
|
-
chainId: params.chainId,
|
|
327
|
-
mpk: params.mpk,
|
|
328
|
-
});
|
|
329
|
-
}
|
|
330
|
-
else {
|
|
331
|
-
// Check if we have persisted history
|
|
332
|
-
const hasSnapshot = await stateStore.hasHistorySnapshot({
|
|
333
|
-
chainId: params.chainId,
|
|
334
|
-
mpk: params.mpk,
|
|
335
|
-
});
|
|
336
|
-
if (!hasSnapshot) {
|
|
337
|
-
// First time - compute and persist
|
|
338
|
-
await computeAndPersist({
|
|
339
|
-
chainId: params.chainId,
|
|
340
|
-
mpk: params.mpk,
|
|
341
|
-
});
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
// Always read from storage
|
|
345
|
-
const stored = await stateStore.listHistoryEntries({
|
|
346
|
-
chainId: params.chainId,
|
|
347
|
-
mpk: params.mpk,
|
|
348
|
-
});
|
|
349
|
-
return params.includeSelfSends
|
|
350
|
-
? stored
|
|
351
|
-
: stored.filter((e) => e.kind !== "SelfSend");
|
|
352
|
-
},
|
|
353
|
-
};
|
|
354
|
-
}
|
package/dist/history/types.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/keys/address.js
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { bech32m } from "@scure/base";
|
|
2
|
-
import { ValidationError } from "../errors.js";
|
|
3
|
-
import { FieldSize, Hex } from "./hex.js";
|
|
4
|
-
const VERSION = 1;
|
|
5
|
-
const LIMIT = 127;
|
|
6
|
-
const ALL_CHAINS = "ffffffffffffffff";
|
|
7
|
-
const PREFIX = "0zk";
|
|
8
|
-
const SALT = new TextEncoder().encode("unlink");
|
|
9
|
-
function xorWithSalt(hex) {
|
|
10
|
-
const bytes = Hex.toBytes(hex);
|
|
11
|
-
const result = new Uint8Array(bytes.length);
|
|
12
|
-
for (let i = 0; i < bytes.length; i++)
|
|
13
|
-
result[i] = bytes[i] ^ SALT[i % SALT.length];
|
|
14
|
-
return Hex.fromBytes(result);
|
|
15
|
-
}
|
|
16
|
-
function chainToHex(chain) {
|
|
17
|
-
if (!chain)
|
|
18
|
-
return ALL_CHAINS;
|
|
19
|
-
return ((chain.type & 0xff).toString(16).padStart(2, "0") +
|
|
20
|
-
BigInt(chain.id).toString(16).padStart(14, "0"));
|
|
21
|
-
}
|
|
22
|
-
function hexToChain(hex) {
|
|
23
|
-
if (hex === ALL_CHAINS)
|
|
24
|
-
return undefined;
|
|
25
|
-
return {
|
|
26
|
-
type: parseInt(hex.slice(0, 2), 16),
|
|
27
|
-
id: parseInt(hex.slice(2), 16),
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
export function encodeAddress(data) {
|
|
31
|
-
const ver = (data.version ?? VERSION).toString(16).padStart(2, "0");
|
|
32
|
-
const mpk = Hex.fromBigInt(data.masterPublicKey, FieldSize.SCALAR);
|
|
33
|
-
const vpk = Hex.padToSize(data.viewingPublicKey, FieldSize.SCALAR);
|
|
34
|
-
const net = xorWithSalt(chainToHex(data.chain));
|
|
35
|
-
return bech32m.encode(PREFIX, bech32m.toWords(Hex.toBytes(`${ver}${mpk}${net}${vpk}`)), LIMIT);
|
|
36
|
-
}
|
|
37
|
-
export function decodeAddress(address) {
|
|
38
|
-
if (!address)
|
|
39
|
-
throw new ValidationError("No address to decode");
|
|
40
|
-
const decoded = bech32m.decode(address, LIMIT);
|
|
41
|
-
if (decoded.prefix !== PREFIX)
|
|
42
|
-
throw new ValidationError("Invalid address prefix");
|
|
43
|
-
const hex = Hex.encode(bech32m.fromWords(decoded.words));
|
|
44
|
-
if (hex.length !== 146)
|
|
45
|
-
throw new ValidationError("Incorrect address payload length");
|
|
46
|
-
const version = parseInt(hex.slice(0, 2), 16);
|
|
47
|
-
if (version !== VERSION)
|
|
48
|
-
throw new ValidationError("Incorrect address version");
|
|
49
|
-
return {
|
|
50
|
-
version,
|
|
51
|
-
masterPublicKey: Hex.toBigInt(hex.slice(2, 66)),
|
|
52
|
-
viewingPublicKey: Hex.toBytes(hex.slice(82, 146)),
|
|
53
|
-
chain: hexToChain(xorWithSalt(hex.slice(66, 82))),
|
|
54
|
-
};
|
|
55
|
-
}
|