n3-sdk 0.2.13 → 0.2.14
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/dist/lib/utils/pureSigner.d.ts +1 -3
- package/dist/lib/utils/pureSigner.d.ts.map +1 -1
- package/dist/lib/utils/pureSigner.js +46 -51
- package/dist/notes/receiver.d.ts +0 -4
- package/dist/notes/receiver.d.ts.map +1 -1
- package/dist/notes/receiver.js +4 -14
- package/dist/notes/store.d.ts +10 -0
- package/dist/notes/store.d.ts.map +1 -1
- package/dist/notes/store.js +26 -3
- package/package.json +1 -1
|
@@ -15,9 +15,7 @@ export declare function verifyPoseidonCompat(Ax: string | bigint, Ay: string | b
|
|
|
15
15
|
R8y: string;
|
|
16
16
|
S: string;
|
|
17
17
|
}): boolean;
|
|
18
|
-
export declare function permitSwapMsg(DOMAIN: bigint, domainB: bigint,
|
|
19
|
-
domainA: bigint, // pool-dec
|
|
20
|
-
commit: bigint, oldRoot: bigint, giveAmount: bigint, outRecv: {
|
|
18
|
+
export declare function permitSwapMsg(DOMAIN: bigint, domainB: bigint, domainA: bigint, commit: bigint, oldRoot: bigint, giveAmount: bigint, outRecv: {
|
|
21
19
|
assetId: bigint;
|
|
22
20
|
amount: bigint;
|
|
23
21
|
pubkey: bigint;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pureSigner.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/pureSigner.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pureSigner.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/pureSigner.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,29 +1,52 @@
|
|
|
1
1
|
// src/lib/utils/pureSigner.ts
|
|
2
2
|
// Pure-JS BabyJub EdDSA(Poseidon) helpers using circomlibjs builder API.
|
|
3
|
-
import { buildBabyjub, buildEddsa, buildPoseidonReference } from "circomlibjs";
|
|
4
|
-
try {
|
|
5
|
-
globalThis.ffjsconfig = { wasm: "disable" };
|
|
6
|
-
if (typeof process !== "undefined" && process?.env) {
|
|
7
|
-
process.env.FFJS_FORCE_NO_WASM = "1";
|
|
8
|
-
process.env.FFJSCONFIG = '{"wasm":"disable"}';
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
catch { }
|
|
12
3
|
let _ctxPromise = null;
|
|
13
4
|
let _ctx = null;
|
|
5
|
+
function setFfjsNoWasmConfig() {
|
|
6
|
+
try {
|
|
7
|
+
// Must be set BEFORE importing circomlibjs/ffjavascript
|
|
8
|
+
globalThis.ffjsconfig = { wasm: "disable" };
|
|
9
|
+
// In the browser, process.env is usually undefined; keep this guarded.
|
|
10
|
+
if (typeof process !== "undefined" && process?.env) {
|
|
11
|
+
process.env.FFJS_FORCE_NO_WASM = "1";
|
|
12
|
+
process.env.FFJSCONFIG = '{"wasm":"disable"}';
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
// ignore
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
async function loadCircomlibBuilders() {
|
|
20
|
+
setFfjsNoWasmConfig();
|
|
21
|
+
// Dynamic import ensures the config above is applied BEFORE module init runs.
|
|
22
|
+
const mod = await import("circomlibjs");
|
|
23
|
+
return {
|
|
24
|
+
buildBabyjub: mod.buildBabyjub,
|
|
25
|
+
buildEddsa: mod.buildEddsa,
|
|
26
|
+
buildPoseidonReference: mod.buildPoseidonReference,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
14
29
|
async function buildCtx() {
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
30
|
+
const { buildBabyjub, buildEddsa, buildPoseidonReference } = await loadCircomlibBuilders();
|
|
31
|
+
// SEQUENTIAL init to avoid peak memory spikes
|
|
32
|
+
const babyJub = await buildBabyjub();
|
|
33
|
+
const eddsa = await buildEddsa();
|
|
34
|
+
const poseidonRef = await buildPoseidonReference();
|
|
20
35
|
return { babyJub, eddsa, poseidonRef, Fr: babyJub.F };
|
|
21
36
|
}
|
|
22
37
|
async function ensureCtx() {
|
|
23
38
|
if (_ctx)
|
|
24
39
|
return _ctx;
|
|
25
|
-
if (!_ctxPromise)
|
|
26
|
-
_ctxPromise = buildCtx()
|
|
40
|
+
if (!_ctxPromise) {
|
|
41
|
+
_ctxPromise = buildCtx()
|
|
42
|
+
.then((c) => (_ctx = c))
|
|
43
|
+
.catch((e) => {
|
|
44
|
+
// allow retry after a failure
|
|
45
|
+
_ctxPromise = null;
|
|
46
|
+
_ctx = null;
|
|
47
|
+
throw e;
|
|
48
|
+
});
|
|
49
|
+
}
|
|
27
50
|
return _ctxPromise;
|
|
28
51
|
}
|
|
29
52
|
function ctxOrThrow() {
|
|
@@ -76,17 +99,9 @@ export function noteCommit(assetId, amount, pubkey, blinding) {
|
|
|
76
99
|
const h2 = (x, y) => H2(x, y);
|
|
77
100
|
return h2(h2(assetId, amount), h2(pubkey, blinding));
|
|
78
101
|
}
|
|
79
|
-
// PermitCheck / SpendInternal / SpendWithdraw:
|
|
80
|
-
// M = Poseidon(DOMAIN, domainB /*chainId*/, domainA /*poolAddr*/, commit, oldRoot)
|
|
81
102
|
export function msgHash(DOMAIN, chainDec, poolDec, c_in, oldRoot) {
|
|
82
103
|
const { poseidonRef, Fr } = ctxOrThrow();
|
|
83
|
-
return Fr.toObject(poseidonRef([
|
|
84
|
-
Fr.e(DOMAIN),
|
|
85
|
-
Fr.e(chainDec),
|
|
86
|
-
Fr.e(poolDec),
|
|
87
|
-
Fr.e(c_in),
|
|
88
|
-
Fr.e(oldRoot),
|
|
89
|
-
]));
|
|
104
|
+
return Fr.toObject(poseidonRef([Fr.e(DOMAIN), Fr.e(chainDec), Fr.e(poolDec), Fr.e(c_in), Fr.e(oldRoot)]));
|
|
90
105
|
}
|
|
91
106
|
export function poseidonAxAy(Ax, Ay) {
|
|
92
107
|
const { poseidonRef, Fr } = ctxOrThrow();
|
|
@@ -125,19 +140,8 @@ export function verifyPoseidonCompat(Ax, Ay, M, sig) {
|
|
|
125
140
|
const S = toBI(sig.S);
|
|
126
141
|
return eddsa.verifyPoseidon(M, { R8, S }, A);
|
|
127
142
|
}
|
|
128
|
-
// ---------- PermitSwap
|
|
129
|
-
|
|
130
|
-
// hD = Poseidon(DOMAIN, domainB, domainA)
|
|
131
|
-
// hC = Poseidon(commit, oldRoot)
|
|
132
|
-
// hG = Poseidon(giveAmount, outRecvAssetId)
|
|
133
|
-
// hR1 = Poseidon(outRecvAmount, outRecvPubkey, outRecvBlinding)
|
|
134
|
-
// hR = Poseidon(hG, hR1)
|
|
135
|
-
// hC1 = Poseidon(outChAssetId, outChAmount, outChPubkey)
|
|
136
|
-
// hC2 = Poseidon(hC1, outChBlinding)
|
|
137
|
-
// M = Poseidon(hD, hC, hR, hC2)
|
|
138
|
-
export function permitSwapMsg(DOMAIN, domainB, // chainId-dec
|
|
139
|
-
domainA, // pool-dec
|
|
140
|
-
commit, oldRoot, giveAmount, outRecv, outCh) {
|
|
143
|
+
// ---------- PermitSwap ----------
|
|
144
|
+
export function permitSwapMsg(DOMAIN, domainB, domainA, commit, oldRoot, giveAmount, outRecv, outCh) {
|
|
141
145
|
const hD = H3(DOMAIN, domainB, domainA);
|
|
142
146
|
const hC = H2(commit, oldRoot);
|
|
143
147
|
const hG = H2(giveAmount, outRecv.assetId);
|
|
@@ -149,9 +153,8 @@ commit, oldRoot, giveAmount, outRecv, outCh) {
|
|
|
149
153
|
}
|
|
150
154
|
export function signPermitSwapCompat(prvSeed, Ax, Ay, M) {
|
|
151
155
|
const sig = signPoseidonCompat(prvSeed, M, String(Ax), String(Ay));
|
|
152
|
-
if (!verifyPoseidonCompat(Ax, Ay, M, sig))
|
|
156
|
+
if (!verifyPoseidonCompat(Ax, Ay, M, sig))
|
|
153
157
|
throw new Error("PermitSwap verify failed (local).");
|
|
154
|
-
}
|
|
155
158
|
return sig;
|
|
156
159
|
}
|
|
157
160
|
export function dbgPermitSwapParts(side, { DOMAIN, chainDec, poolDec, commit, oldRoot, giveAmount, recv, ch, }) {
|
|
@@ -174,8 +177,6 @@ export function dbgPermitSwapParts(side, { DOMAIN, chainDec, poolDec, commit, ol
|
|
|
174
177
|
});
|
|
175
178
|
}
|
|
176
179
|
// ---------- OrderPermit (maker) ----------
|
|
177
|
-
// Mirrors OrderPermitHash.circom exactly.
|
|
178
|
-
// NOTE: bandOff is an input to the circuit but not actually used in the hash there.
|
|
179
180
|
export function orderPermitHash(DOMAIN, domainA, domainB, side, assetIn, assetOut, minNum, minDen, maxNum, maxDen, _bandOff, priceNum, priceDen, maxQty, expiry, orderId) {
|
|
180
181
|
const hDA = H2(domainA, domainB);
|
|
181
182
|
const hD = H2(DOMAIN, hDA);
|
|
@@ -194,24 +195,18 @@ export function orderPermitHash(DOMAIN, domainA, domainB, side, assetIn, assetOu
|
|
|
194
195
|
}
|
|
195
196
|
export function signOrderPermitCompat(prvSeed, Ax, Ay, orderHash) {
|
|
196
197
|
const sig = signPoseidonCompat(prvSeed, orderHash, String(Ax), String(Ay));
|
|
197
|
-
if (!verifyPoseidonCompat(Ax, Ay, orderHash, sig))
|
|
198
|
+
if (!verifyPoseidonCompat(Ax, Ay, orderHash, sig))
|
|
198
199
|
throw new Error("OrderPermit verify failed (local).");
|
|
199
|
-
}
|
|
200
200
|
return sig;
|
|
201
201
|
}
|
|
202
202
|
export function deriveBabyJubFromSeed(prvSeed) {
|
|
203
203
|
const { eddsa, Fr } = ctxOrThrow();
|
|
204
204
|
const raw = prvSeed.startsWith("0x") ? hexToBytes(prvSeed) : be32FromDec(prvSeed);
|
|
205
|
-
if (raw.length !== 32)
|
|
205
|
+
if (raw.length !== 32)
|
|
206
206
|
throw new Error(`deriveBabyJubFromSeed: prvSeed must be 32 bytes, got ${raw.length}`);
|
|
207
|
-
}
|
|
208
207
|
const A = eddsa.prv2pub(raw);
|
|
209
208
|
const Ax = Fr.toObject(A[0]);
|
|
210
209
|
const Ay = Fr.toObject(A[1]);
|
|
211
210
|
const notePubkey = poseidonAxAy(Ax, Ay);
|
|
212
|
-
return {
|
|
213
|
-
Ax: Ax.toString(),
|
|
214
|
-
Ay: Ay.toString(),
|
|
215
|
-
notePubkey: notePubkey.toString(),
|
|
216
|
-
};
|
|
211
|
+
return { Ax: Ax.toString(), Ay: Ay.toString(), notePubkey: notePubkey.toString() };
|
|
217
212
|
}
|
package/dist/notes/receiver.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { NoteStore } from './store.js';
|
|
2
|
-
import type { NoteV1 } from '../types/NoteStoreTypes.js';
|
|
3
2
|
type Chain = {
|
|
4
3
|
getEvents: (fromBlock?: number) => Promise<{
|
|
5
4
|
newRoots: {
|
|
@@ -28,9 +27,6 @@ export declare class Receiver {
|
|
|
28
27
|
private store;
|
|
29
28
|
private chain;
|
|
30
29
|
constructor(store: NoteStore, chain: Chain);
|
|
31
|
-
stageDepositNote(note: NoteV1): Promise<void>;
|
|
32
|
-
stageItOutNotes(notes: NoteV1[]): Promise<void>;
|
|
33
|
-
/** One-shot reconcile. Call from a small loop for “always-on”. */
|
|
34
30
|
reconcile(fromBlock?: number): Promise<void>;
|
|
35
31
|
}
|
|
36
32
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"receiver.d.ts","sourceRoot":"","sources":["../../src/notes/receiver.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"receiver.d.ts","sourceRoot":"","sources":["../../src/notes/receiver.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAG5C,KAAK,KAAK,GAAG;IACX,SAAS,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;QACzC,QAAQ,EAAE;YAAE,IAAI,EAAE,KAAK,MAAM,EAAE,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC;QACnD,MAAM,EAAI;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,KAAK,MAAM,EAAE,EAAE,CAAC;YAAC,KAAK,EAAE,MAAM,CAAC;YAAC,SAAS,CAAC,EAAE,KAAK,MAAM,EAAE,CAAA;SAAE,EAAE,CAAC;QACjG,MAAM,EAAI;YAAE,EAAE,EAAE,KAAK,MAAM,EAAE,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC;KAClD,CAAC,CAAC;IACH,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,MAAM,EAAE,KAAK,OAAO,CAAC;QAAE,IAAI,EAAE,KAAK,MAAM,EAAE,EAAE,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IACvG,UAAU,EAAE,CAAC,UAAU,EAAE,KAAK,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC;IAC1H,WAAW,EAAE,CAAC,IAAI,EAAE,KAAK,MAAM,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACxD,CAAC;AAGF,qBAAa,QAAQ;IACP,OAAO,CAAC,KAAK;IAAa,OAAO,CAAC,KAAK;gBAA/B,KAAK,EAAE,SAAS,EAAU,KAAK,EAAE,KAAK;IAEpD,SAAS,CAAC,SAAS,CAAC,EAAE,MAAM;CAsDnC"}
|
package/dist/notes/receiver.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// src/notes/receiver.ts
|
|
1
2
|
export class Receiver {
|
|
2
3
|
store;
|
|
3
4
|
chain;
|
|
@@ -5,20 +6,11 @@ export class Receiver {
|
|
|
5
6
|
this.store = store;
|
|
6
7
|
this.chain = chain;
|
|
7
8
|
}
|
|
8
|
-
async stageDepositNote(note) {
|
|
9
|
-
await this.store.addStagedNotes([{ ...note, status: 'STAGED' }]);
|
|
10
|
-
}
|
|
11
|
-
async stageItOutNotes(notes) {
|
|
12
|
-
await this.store.addStagedNotes(notes.map(n => ({ ...n, status: 'STAGED' })));
|
|
13
|
-
}
|
|
14
|
-
/** One-shot reconcile. Call from a small loop for “always-on”. */
|
|
15
9
|
async reconcile(fromBlock) {
|
|
16
10
|
const ev = await this.chain.getEvents(fromBlock);
|
|
17
|
-
// 1) record spents
|
|
18
11
|
if (ev.spents.length) {
|
|
19
12
|
await this.store.recordSpents(ev.spents.map(s => ({ nf: s.nf, blockNumber: s.block, at: Date.now() })));
|
|
20
13
|
}
|
|
21
|
-
// 2) inclusion for staged notes → SPENDABLE
|
|
22
14
|
const staged = await this.store.listStagedNotes();
|
|
23
15
|
const includedNow = new Set();
|
|
24
16
|
if (staged.length) {
|
|
@@ -31,18 +23,17 @@ export class Receiver {
|
|
|
31
23
|
continue;
|
|
32
24
|
for (let i = 0; i < batch.leaves.length; i++) {
|
|
33
25
|
const c = batch.leaves[i];
|
|
34
|
-
|
|
26
|
+
const st = stagedByCommit.get(c);
|
|
27
|
+
if (!st)
|
|
35
28
|
continue;
|
|
36
29
|
const index = batch.start + i;
|
|
37
|
-
//
|
|
38
|
-
// No need to recompute paths here.
|
|
30
|
+
// ✅ also persist the root/index only if staged note exists (you already do)
|
|
39
31
|
await this.store.markSpendable(c, index, root);
|
|
40
32
|
includedNow.add(c);
|
|
41
33
|
stagedByCommit.delete(c);
|
|
42
34
|
}
|
|
43
35
|
}
|
|
44
36
|
}
|
|
45
|
-
// 3) if an intent’s all outputs landed, clear it
|
|
46
37
|
const b = this.store['body'];
|
|
47
38
|
if (b?.outByIntent) {
|
|
48
39
|
for (const [intentId, expected] of Object.entries(b.outByIntent)) {
|
|
@@ -51,7 +42,6 @@ export class Receiver {
|
|
|
51
42
|
}
|
|
52
43
|
}
|
|
53
44
|
}
|
|
54
|
-
// 4) advance cursor to the latest block we saw
|
|
55
45
|
const maxBlock = Math.max(0, ...ev.newRoots.map(x => x.block), ...ev.leaves.map(x => x.block), ...ev.spents.map(x => x.block));
|
|
56
46
|
if (maxBlock > 0)
|
|
57
47
|
await this.store.setLastProcessedBlock(maxBlock);
|
package/dist/notes/store.d.ts
CHANGED
|
@@ -1,18 +1,28 @@
|
|
|
1
1
|
import type { NoteV1, VaultBlobV1, SpentRecord } from '../types/NoteStoreTypes.js';
|
|
2
|
+
export type NoteStoreSyncFn = (fromBlock?: number) => Promise<void>;
|
|
2
3
|
export declare class NoteStore {
|
|
3
4
|
private persist;
|
|
4
5
|
private header;
|
|
5
6
|
private body;
|
|
6
7
|
private key;
|
|
8
|
+
private _syncFn;
|
|
7
9
|
constructor(persist: {
|
|
8
10
|
readBlob: () => Promise<VaultBlobV1 | null>;
|
|
9
11
|
writeBlob: (blob: VaultBlobV1) => Promise<void>;
|
|
10
12
|
});
|
|
13
|
+
/** App/provider wires this to Receiver.reconcile(). */
|
|
14
|
+
setSync(fn: NoteStoreSyncFn | null): void;
|
|
15
|
+
/** Best-effort; no-op if not wired. */
|
|
16
|
+
sync(fromBlock?: number): Promise<void>;
|
|
17
|
+
/** Alias for your vocabulary. */
|
|
18
|
+
reconcile(fromBlock?: number): Promise<void>;
|
|
11
19
|
unlock(passphrase: string): Promise<void>;
|
|
12
20
|
private save;
|
|
13
21
|
private getBody;
|
|
14
22
|
listSpendable(filter?: {
|
|
15
23
|
assetId?: bigint;
|
|
24
|
+
chainId?: number;
|
|
25
|
+
pool?: `0x${string}`;
|
|
16
26
|
}): NoteV1[];
|
|
17
27
|
getByCommitment(c: `0x${string}`): NoteV1 | undefined;
|
|
18
28
|
/** Link an input NF to the input note we’re spending, for auto-SPENT later. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/notes/store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,MAAM,EACN,WAAW,EAGX,WAAW,EACZ,MAAM,4BAA4B,CAAC;AAIpC,qBAAa,SAAS;
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/notes/store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,MAAM,EACN,WAAW,EAGX,WAAW,EACZ,MAAM,4BAA4B,CAAC;AAIpC,MAAM,MAAM,eAAe,GAAG,CAAC,SAAS,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAGpE,qBAAa,SAAS;IAQlB,OAAO,CAAC,OAAO;IAPjB,OAAO,CAAC,MAAM,CAA8B;IAC5C,OAAO,CAAC,IAAI,CAA4B;IACxC,OAAO,CAAC,GAAG,CAA2B;IAEtC,OAAO,CAAC,OAAO,CAAgC;gBAGrC,OAAO,EAAE;QACf,QAAQ,EAAE,MAAM,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;QAC5C,SAAS,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KACjD;IAGH,uDAAuD;IACvD,OAAO,CAAC,EAAE,EAAE,eAAe,GAAG,IAAI;IAIlC,uCAAuC;IACjC,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM;IAI7B,iCAAiC;IAC3B,SAAS,CAAC,SAAS,CAAC,EAAE,MAAM;IAI5B,MAAM,CAAC,UAAU,EAAE,MAAM;YA2CjB,IAAI;IAQlB,OAAO,CAAC,OAAO;IAKf,aAAa,CAAC,MAAM,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,KAAK,MAAM,EAAE,CAAA;KAAE;IAiBnF,eAAe,CAAC,CAAC,EAAE,KAAK,MAAM,EAAE;IAOhC,+EAA+E;IACzE,gBAAgB,CAAC,MAAM,EAAE;QAC7B,EAAE,EAAE,KAAK,MAAM,EAAE,CAAC;QAClB,UAAU,CAAC,EAAE,KAAK,MAAM,EAAE,CAAC;QAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,IAAI,CAAC,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,CAAC;KAC7B;IAYD,kFAAkF;IAC5E,uBAAuB,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,MAAM,EAAE,EAAE;IAQtE,oBAAoB,CAAC,QAAQ,EAAE,MAAM;IAQ3C,+DAA+D;IACzD,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE;IAyB9B,eAAe,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAK1C,yDAAyD;IACnD,aAAa,CAAC,UAAU,EAAE,KAAK,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,MAAM,EAAE;IAcjF,YAAY,IAAI,MAAM,EAAE;IAKxB,yEAAyE;IACnE,YAAY,CAAC,MAAM,EAAE,WAAW,EAAE;IAyBlC,WAAW,CAAC,EAAE,EAAE,KAAK,MAAM,EAAE;IAK7B,SAAS,CAAC,UAAU,EAAE,KAAK,MAAM,EAAE,EAAE,EAAE,EAAE,KAAK,MAAM,EAAE,EAAE,WAAW,CAAC,EAAE,MAAM;IAe5E,qBAAqB,CAAC,KAAK,EAAE,MAAM;IAKzC,qBAAqB,IAAI,MAAM,GAAG,SAAS;IAKrC,eAAe,IAAI,OAAO,CAAC,WAAW,CAAC;IAKvC,eAAe,CAAC,IAAI,EAAE,WAAW;IAOvC,MAAM;IAmBN,mCAAmC;YACrB,OAAO;CAKtB"}
|
package/dist/notes/store.js
CHANGED
|
@@ -5,9 +5,22 @@ export class NoteStore {
|
|
|
5
5
|
header = null;
|
|
6
6
|
body = null;
|
|
7
7
|
key = null;
|
|
8
|
+
_syncFn = null;
|
|
8
9
|
constructor(persist) {
|
|
9
10
|
this.persist = persist;
|
|
10
11
|
}
|
|
12
|
+
/** App/provider wires this to Receiver.reconcile(). */
|
|
13
|
+
setSync(fn) {
|
|
14
|
+
this._syncFn = fn;
|
|
15
|
+
}
|
|
16
|
+
/** Best-effort; no-op if not wired. */
|
|
17
|
+
async sync(fromBlock) {
|
|
18
|
+
await this._syncFn?.(fromBlock);
|
|
19
|
+
}
|
|
20
|
+
/** Alias for your vocabulary. */
|
|
21
|
+
async reconcile(fromBlock) {
|
|
22
|
+
await this.sync(fromBlock);
|
|
23
|
+
}
|
|
11
24
|
async unlock(passphrase) {
|
|
12
25
|
const blob = await this.persist.readBlob();
|
|
13
26
|
if (!blob) {
|
|
@@ -42,7 +55,6 @@ export class NoteStore {
|
|
|
42
55
|
m, t, p, dkLen: 32,
|
|
43
56
|
});
|
|
44
57
|
const body = decryptBlob(key, blob);
|
|
45
|
-
// ensure new fields exist
|
|
46
58
|
if (!body.pendingLinks)
|
|
47
59
|
body.pendingLinks = [];
|
|
48
60
|
if (!body.outByIntent)
|
|
@@ -65,8 +77,19 @@ export class NoteStore {
|
|
|
65
77
|
return this.body;
|
|
66
78
|
}
|
|
67
79
|
listSpendable(filter) {
|
|
68
|
-
const
|
|
69
|
-
|
|
80
|
+
const b = this.getBody();
|
|
81
|
+
let notes = b.notes.filter((n) => n.status === 'SPENDABLE');
|
|
82
|
+
if (typeof filter?.chainId === 'number') {
|
|
83
|
+
notes = notes.filter((n) => n.chainId === filter.chainId);
|
|
84
|
+
}
|
|
85
|
+
if (filter?.pool) {
|
|
86
|
+
notes = notes.filter((n) => n.pool === filter.pool);
|
|
87
|
+
}
|
|
88
|
+
if (filter?.assetId != null) {
|
|
89
|
+
const want = BigInt(filter.assetId);
|
|
90
|
+
notes = notes.filter((n) => BigInt(n.assetId) === want);
|
|
91
|
+
}
|
|
92
|
+
return notes;
|
|
70
93
|
}
|
|
71
94
|
getByCommitment(c) {
|
|
72
95
|
return this.getBody().notes.find((n) => n.commitment === c);
|