@zerc20/wallet-sdk 0.5.0 → 0.6.0
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/LICENSE +17 -20
- package/README.md +1 -1
- package/dist/chain.d.ts +6 -5
- package/dist/chain.js +8 -7
- package/dist/chain.js.map +1 -1
- package/dist/context.js +1 -1
- package/dist/context.js.map +1 -1
- package/dist/core.js +3 -2
- package/dist/core.js.map +1 -1
- package/dist/errors.d.ts +20 -3
- package/dist/errors.js +7 -1
- package/dist/errors.js.map +1 -1
- package/dist/network.d.ts +4 -2
- package/dist/network.js +3 -1
- package/dist/network.js.map +1 -1
- package/dist/pos.d.ts +3 -0
- package/dist/pos.js +6 -0
- package/dist/pos.js.map +1 -1
- package/dist/prove.d.ts +3 -0
- package/dist/prove.js +9 -0
- package/dist/prove.js.map +1 -1
- package/dist/servers.d.ts +3 -0
- package/dist/servers.js +1 -0
- package/dist/servers.js.map +1 -1
- package/dist/services.d.ts +3 -2
- package/dist/services.js +9 -7
- package/dist/services.js.map +1 -1
- package/dist/spend.d.ts +30 -9
- package/dist/spend.js +135 -58
- package/dist/spend.js.map +1 -1
- package/dist/wallet.d.ts +40 -7
- package/dist/wallet.js +153 -37
- package/dist/wallet.js.map +1 -1
- package/package.json +3 -3
- package/src/chain.ts +12 -6
- package/src/context.ts +1 -1
- package/src/core.ts +3 -2
- package/src/errors.ts +15 -2
- package/src/network.ts +6 -3
- package/src/pos.ts +7 -0
- package/src/prove.ts +10 -0
- package/src/servers.ts +5 -0
- package/src/services.ts +8 -7
- package/src/spend.ts +146 -68
- package/src/wallet.ts +192 -38
package/dist/services.d.ts
CHANGED
|
@@ -26,8 +26,9 @@ export interface Relayed {
|
|
|
26
26
|
noteIndex1: number | null;
|
|
27
27
|
noteIndex2: number | null;
|
|
28
28
|
}
|
|
29
|
-
/** What `relay` reports
|
|
30
|
-
|
|
29
|
+
/** What `relay` reports while the relayer is relaying a request with the same nullifiers: the request already there
|
|
30
|
+
* gets the answer, and one after it finds the transaction landed. */
|
|
31
|
+
export declare class Relaying extends WalletError {
|
|
31
32
|
}
|
|
32
33
|
/** Has the relayer submit `request`. A 400 means the call reverts, which includes "already landed". */
|
|
33
34
|
export declare const relay: (c: ChainConfig, request: object, feeNote?: {
|
package/dist/services.js
CHANGED
|
@@ -78,23 +78,25 @@ export async function relayerFees(c) {
|
|
|
78
78
|
const fees = new Map(Object.entries(r.body.fees).map(([t, f]) => [Number(t), { fee: BigInt(f.fee) }]));
|
|
79
79
|
return { relayer: r.body.relayer, publicKey: r.body.publicKey, fees };
|
|
80
80
|
}
|
|
81
|
-
/** What `relay` reports
|
|
82
|
-
|
|
81
|
+
/** What `relay` reports while the relayer is relaying a request with the same nullifiers: the request already there
|
|
82
|
+
* gets the answer, and one after it finds the transaction landed. */
|
|
83
|
+
export class Relaying extends WalletError {
|
|
83
84
|
}
|
|
84
85
|
/** Has the relayer submit `request`. A 400 means the call reverts, which includes "already landed". */
|
|
85
86
|
export const relay = (c, request, feeNote) => relayed(`${c.transactRelayer}/transact`, { request, feeNote });
|
|
86
87
|
/** Has the relayer submit a merge's `request`, as `relay` does a JoinSplit's. Answers the merged note's index. */
|
|
87
88
|
export const relayMerge = (c, request) => relayed(`${c.transactRelayer}/merge`, { request });
|
|
88
89
|
async function relayed(url, body) {
|
|
89
|
-
// the relayer answers once mined, after fee bumping if need be
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
});
|
|
90
|
+
// the relayer answers once mined, after fee bumping if need be. Without an answer it may have sent it all the same:
|
|
91
|
+
// the same request goes again next sync, and lands at most once
|
|
92
|
+
const r = await post(url, body, 15 * 60_000);
|
|
93
93
|
if (typeof r.body !== 'string')
|
|
94
94
|
return r.body;
|
|
95
95
|
if (r.status === 400)
|
|
96
96
|
return { reverted: r.body };
|
|
97
|
-
|
|
97
|
+
if (r.status === 409)
|
|
98
|
+
throw new Relaying('unavailable', `transact-relayer: ${r.body}`);
|
|
99
|
+
return fail('unavailable', `transact-relayer: HTTP ${r.status}: ${r.body}`);
|
|
98
100
|
}
|
|
99
101
|
/** Sends a merge's witness (JSON, of `inputs` inputs) sealed to the merge prover's enclave, to prove `statement` (the
|
|
100
102
|
* attester's `Merge`). Proving takes minutes: `proofOf` tells when it is done. */
|
package/dist/services.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"services.js","sourceRoot":"","sources":["../src/services.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"services.js","sourceRoot":"","sources":["../src/services.ts"],"names":[],"mappings":"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"}
|
package/dist/spend.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { type Recipient } from '@zerc20/storage-sdk';
|
|
|
2
2
|
import { type Address, type Hex } from 'viem';
|
|
3
3
|
import { type Ctx } from './context.js';
|
|
4
4
|
import type { Indexer } from './servers.js';
|
|
5
|
-
import { type OperationRecord, type Position, type SpendOperation } from './state.js';
|
|
5
|
+
import { type NoteRecord, type OperationRecord, type Position, type SpendOperation } from './state.js';
|
|
6
6
|
/** Something spendable. */
|
|
7
7
|
export interface Coin {
|
|
8
8
|
kind: 'note' | 'burn';
|
|
@@ -41,9 +41,14 @@ export interface Step {
|
|
|
41
41
|
attempts: number;
|
|
42
42
|
/** Once relayed: the block the relayer saw it mined in. */
|
|
43
43
|
relayedBlock?: number;
|
|
44
|
-
/** The indexer's nullifier count once it is past that block, or just after a relay that
|
|
45
|
-
*
|
|
44
|
+
/** The indexer's nullifier count once it is past that block, or just after a relay that reverted on an input spent
|
|
45
|
+
* already: that leaves the step `attested`, not relayed again until its change tells whose transaction spent it.
|
|
46
|
+
* Final nullifiers past it, and its inputs still not among them, means whatever spent them is gone: a reorg dropped
|
|
47
|
+
* it, or the relayer never sent it. */
|
|
46
48
|
relayedAt?: number;
|
|
49
|
+
/** The final commitment count once an input is seen spent. Final commitments past it, and the change still not among
|
|
50
|
+
* them, means another transaction spent the input, and this step can never land. */
|
|
51
|
+
spentAt?: number;
|
|
47
52
|
}
|
|
48
53
|
/** The most inputs one merge spends: the attester takes requests up to 2 MB, at 8 KiB of sealed witness per input
|
|
49
54
|
* sent as hex, and the prover folds them in one job. */
|
|
@@ -65,9 +70,13 @@ export interface MergeStep {
|
|
|
65
70
|
/** Refused by the prover, or reverting with no sign of it on chain: built again with the same output a few times,
|
|
66
71
|
* then failed. */
|
|
67
72
|
attempts: number;
|
|
68
|
-
/**
|
|
73
|
+
/** Built again after a relay of it reverted, which counts in `attempts` beside the prover's refusals: the request
|
|
74
|
+
* out may still land, so the step is not cancelled. */
|
|
75
|
+
sent?: true;
|
|
76
|
+
/** As a JoinSplit's, with `proved` where a JoinSplit is `attested`. */
|
|
69
77
|
relayedBlock?: number;
|
|
70
78
|
relayedAt?: number;
|
|
79
|
+
spentAt?: number;
|
|
71
80
|
}
|
|
72
81
|
/** Where a send or withdrawal goes; `self` merges the wallet's own notes and nothing leaves. */
|
|
73
82
|
export type Destination = {
|
|
@@ -157,10 +166,15 @@ export declare const codeOf: (code: string) => import("@zerc20/storage-sdk").Rec
|
|
|
157
166
|
/** What `step` paid besides `op`'s amount, the relayer's fee and the protocol's cut: what its inputs hold beyond the
|
|
158
167
|
* amount and the change. */
|
|
159
168
|
export declare const feeOf: (op: SpendOperation, step: Step) => bigint;
|
|
160
|
-
/** Where a relayed
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
|
|
169
|
+
/** Where a relayed step stands, by its `change` (a merge's note) and its `inputs` as sync last saw them:
|
|
170
|
+
* - `landed`: the change is final where this wallet expects it;
|
|
171
|
+
* - `taken`: an input is spent and the final commitments passed `spentAt` without the change, so another transaction
|
|
172
|
+
* spent it, and this step can never land;
|
|
173
|
+
* - `dropped`: no input is spent and the final nullifiers passed `relayedAt` without them: whatever was spending them
|
|
174
|
+
* is gone, a reorg dropped it or the relayer never sent it;
|
|
175
|
+
* - `mined`: the change is in a block, not final yet;
|
|
176
|
+
* - `waiting`: none of these yet. */
|
|
177
|
+
export declare function relayedState(change: Pick<NoteRecord, 'found' | 'watch'> | undefined, inputs: (Position | undefined)[], relayedAt: number | undefined, spentAt: number | undefined): 'landed' | 'taken' | 'dropped' | 'mined' | 'waiting';
|
|
164
178
|
/** The indexer's nullifier count once it is past `block`, so past the nullifiers of a transaction mined there unless a
|
|
165
179
|
* reorg moved them; `undefined` until then. The relayer answers once the block is mined, which may be before the
|
|
166
180
|
* indexer has read it. */
|
|
@@ -168,5 +182,12 @@ export declare function nullifiersPast(indexer: Pick<Indexer, 'status'>, block:
|
|
|
168
182
|
/** Whether `op`'s payment or withdrawal is on chain: done, or relayed, which the relayer answers once it is mined. Until
|
|
169
183
|
* it is final a reorg may still drop it, and the operation relays it again. */
|
|
170
184
|
export declare function landed(op: SpendOperation): boolean;
|
|
171
|
-
/**
|
|
185
|
+
/** Whether `op` can still be cancelled, having paid nothing: a payment, withdrawal or consolidation under way with no
|
|
186
|
+
* request out to the relayer, and no merge of it landed. A step at its relay stage has one out, as its request leaves
|
|
187
|
+
* the moment it gets there; so has one built again after a relay of it reverted, as that request may still land: a
|
|
188
|
+
* JoinSplit's `attempts` count only those, and a merge, whose `attempts` count its prover's refusals too, is `sent`. */
|
|
189
|
+
export declare function cancellable(op: OperationRecord): boolean;
|
|
190
|
+
/** Takes `op` as far as it can go now, saving before each step that leaves the device. One cancelled meanwhile
|
|
191
|
+
* (`cancel`) finishes the stage under way and starts no other: its status is looked at after each, and nothing it does
|
|
192
|
+
* later is kept, as it is out of the state. A relayer that is relaying its request already throws `Relaying`. */
|
|
172
193
|
export declare function advanceSpend(ctx: Ctx, op: SpendOperation): Promise<void>;
|
package/dist/spend.js
CHANGED
|
@@ -6,9 +6,12 @@
|
|
|
6
6
|
// and deposits into one note to self, proved by the merge prover (a wallet cannot: its key is 6.3 GB). More take
|
|
7
7
|
// another merge, once a root is over the first one's note.
|
|
8
8
|
//
|
|
9
|
-
// A relayed JoinSplit or merge is done once its
|
|
10
|
-
//
|
|
11
|
-
//
|
|
9
|
+
// A relayed JoinSplit or merge is done once its change (a merge's note) is final where this wallet expects it, as sync
|
|
10
|
+
// sees it: only its own transaction puts that note there, as its salt is fresh and the proof binds it to the inputs'
|
|
11
|
+
// nullifiers. The relayer's answer alone could be a lie, a reorg could drop the transaction, and a spent input alone
|
|
12
|
+
// could be another device's doing: each device of a wallet locks its inputs in its own state. Only one that cannot
|
|
13
|
+
// land fails, which frees its inputs: one that kept reverting with no input spent, or one whose input another
|
|
14
|
+
// transaction spent.
|
|
12
15
|
import { commit, decodeCode, planPayCode, planSelf, planSend } from '@zerc20/storage-sdk';
|
|
13
16
|
import { bytesToHex, decodeAbiParameters, hexToBytes, numberToHex, parseAbiParameters, } from 'viem';
|
|
14
17
|
import { UNWRAP_INTENT } from './chain.js';
|
|
@@ -17,7 +20,7 @@ import { core } from './core.js';
|
|
|
17
20
|
import { fail } from './errors.js';
|
|
18
21
|
import { prove } from './prove.js';
|
|
19
22
|
import { scan } from './scan.js';
|
|
20
|
-
import {
|
|
23
|
+
import { attest, proofOf, relay, relayMerge, relayerFees, requestProof } from './services.js';
|
|
21
24
|
import { unspent } from './state.js';
|
|
22
25
|
import { commitmentsAt, noteReceipt, storageState, takeRefresh, tokenIds } from './sync.js';
|
|
23
26
|
import { aspPath, aspPaths, commitmentPath, commitmentPaths } from './tree.js';
|
|
@@ -474,29 +477,65 @@ const positionsAt = (ctx, chainId, index) => [...ctx.state.notes, ...ctx.state.d
|
|
|
474
477
|
.flatMap((r) => r.found.filter((f) => f.index === index));
|
|
475
478
|
/** The final one of them: an input is final. */
|
|
476
479
|
const positionOf = (ctx, chainId, index) => positionsAt(ctx, chainId, index).find((f) => !f.tentative);
|
|
477
|
-
/** Whether the step's
|
|
478
|
-
* newer ones.
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
if (f?.spent)
|
|
480
|
+
/** Whether any of the step's inputs is spent on chain: among the final nullifiers (as sync last saw them), or among
|
|
481
|
+
* the newer ones. Reads the pages everyone polls, never asks about a nullifier. */
|
|
482
|
+
async function inputsSpent(ctx, op, step) {
|
|
483
|
+
const inputs = step.inputs.map((coin) => positionOf(ctx, op.chainId, coin.index));
|
|
484
|
+
if (inputs.some((f) => f?.spent))
|
|
483
485
|
return true;
|
|
484
|
-
|
|
486
|
+
// copies: sync alone moves the watches, over final entries
|
|
487
|
+
const watches = inputs.flatMap((f) => (f?.nullifier ? [{ ...f.nullifier }] : []));
|
|
488
|
+
if (watches.length === 0)
|
|
485
489
|
return false;
|
|
486
490
|
const c = chainCtx(ctx, op.chainId);
|
|
487
491
|
const { nullifiers } = await c.indexer.status();
|
|
488
|
-
|
|
489
|
-
const
|
|
490
|
-
const hits = await scan([watch], 8, (p) => c.indexer.page('nullifiers', p), watch.scannedTo, nullifiers);
|
|
492
|
+
const from = Math.min(...watches.map((w) => w.scannedTo));
|
|
493
|
+
const hits = await scan(watches, 8, (p) => c.indexer.page('nullifiers', p), from, nullifiers);
|
|
491
494
|
return hits.length > 0;
|
|
492
495
|
}
|
|
493
|
-
/** Where a relayed
|
|
494
|
-
*
|
|
495
|
-
*
|
|
496
|
-
|
|
497
|
-
|
|
496
|
+
/** Where a relayed step stands, by its `change` (a merge's note) and its `inputs` as sync last saw them:
|
|
497
|
+
* - `landed`: the change is final where this wallet expects it;
|
|
498
|
+
* - `taken`: an input is spent and the final commitments passed `spentAt` without the change, so another transaction
|
|
499
|
+
* spent it, and this step can never land;
|
|
500
|
+
* - `dropped`: no input is spent and the final nullifiers passed `relayedAt` without them: whatever was spending them
|
|
501
|
+
* is gone, a reorg dropped it or the relayer never sent it;
|
|
502
|
+
* - `mined`: the change is in a block, not final yet;
|
|
503
|
+
* - `waiting`: none of these yet. */
|
|
504
|
+
export function relayedState(change, inputs, relayedAt, spentAt) {
|
|
505
|
+
const seen = change?.found.filter((f) => f.confirmed) ?? [];
|
|
506
|
+
if (seen.some((f) => !f.tentative))
|
|
498
507
|
return 'landed';
|
|
499
|
-
|
|
508
|
+
if (inputs.some((f) => f?.spent)) {
|
|
509
|
+
// a final position not read yet may be the change
|
|
510
|
+
const missed = spentAt !== undefined &&
|
|
511
|
+
!!change?.watch &&
|
|
512
|
+
change.watch.scannedTo >= spentAt &&
|
|
513
|
+
!change.found.some((f) => !f.tentative);
|
|
514
|
+
if (missed)
|
|
515
|
+
return 'taken';
|
|
516
|
+
}
|
|
517
|
+
else {
|
|
518
|
+
const watches = inputs.flatMap((f) => (f?.nullifier ? [f.nullifier] : []));
|
|
519
|
+
if (relayedAt !== undefined && watches.length > 0 && watches.every((w) => w.scannedTo >= relayedAt))
|
|
520
|
+
return 'dropped';
|
|
521
|
+
}
|
|
522
|
+
return seen.length > 0 ? 'mined' : 'waiting';
|
|
523
|
+
}
|
|
524
|
+
/** `relayedState` of `step`, failing the operation once another transaction took an input. The first time an input
|
|
525
|
+
* is seen spent, short of the step landing, it notes the final commitment count: a later status counts no fewer, so
|
|
526
|
+
* once the change's watch passes it, it has looked wherever that transaction put its notes. */
|
|
527
|
+
async function standing(ctx, op, step) {
|
|
528
|
+
const inputs = step.inputs.map((coin) => positionOf(ctx, op.chainId, coin.index));
|
|
529
|
+
const salt = 'output' in step ? step.output.salt : step.outputs[1].salt;
|
|
530
|
+
const change = ctx.state.notes.find((n) => n.chainId === op.chainId && n.salt === salt);
|
|
531
|
+
const now = relayedState(change, inputs, step.relayedAt, step.spentAt);
|
|
532
|
+
if (now === 'taken')
|
|
533
|
+
fail('spent-elsewhere', 'another device of this wallet spent a note or deposit of it first: it paid nothing');
|
|
534
|
+
if (now !== 'landed' && step.spentAt === undefined && inputs.some((f) => f?.spent)) {
|
|
535
|
+
step.spentAt = (await chainCtx(ctx, op.chainId).indexer.status()).commitmentsFinal;
|
|
536
|
+
await ctx.save();
|
|
537
|
+
}
|
|
538
|
+
return now;
|
|
500
539
|
}
|
|
501
540
|
/** The indexer's nullifier count once it is past `block`, so past the nullifiers of a transaction mined there unless a
|
|
502
541
|
* reorg moved them; `undefined` until then. The relayer answers once the block is mined, which may be before the
|
|
@@ -512,6 +551,20 @@ export async function nullifiersPast(indexer, block) {
|
|
|
512
551
|
export function landed(op) {
|
|
513
552
|
return (op.status === 'done' || (op.status === 'pending' && op.kind !== 'consolidate' && op.data.step?.stage === 'relayed'));
|
|
514
553
|
}
|
|
554
|
+
/** Whether `op` can still be cancelled, having paid nothing: a payment, withdrawal or consolidation under way with no
|
|
555
|
+
* request out to the relayer, and no merge of it landed. A step at its relay stage has one out, as its request leaves
|
|
556
|
+
* the moment it gets there; so has one built again after a relay of it reverted, as that request may still land: a
|
|
557
|
+
* JoinSplit's `attempts` count only those, and a merge, whose `attempts` count its prover's refusals too, is `sent`. */
|
|
558
|
+
export function cancellable(op) {
|
|
559
|
+
if (op.status !== 'pending' || op.kind === 'deposit' || op.data.paid > 0n)
|
|
560
|
+
return false;
|
|
561
|
+
const step = op.data.step;
|
|
562
|
+
if (!step)
|
|
563
|
+
return true;
|
|
564
|
+
if ('output' in step)
|
|
565
|
+
return !step.sent && step.stage !== 'proved' && step.stage !== 'relayed';
|
|
566
|
+
return step.attempts === 0 && step.stage !== 'attested' && step.stage !== 'relayed';
|
|
567
|
+
}
|
|
515
568
|
function markSpent(ctx, op, step) {
|
|
516
569
|
for (const coin of step.inputs)
|
|
517
570
|
for (const f of positionsAt(ctx, op.chainId, coin.index))
|
|
@@ -524,14 +577,18 @@ function placeChange(ctx, op, salt, index) {
|
|
|
524
577
|
note.found.push({ index, tentative: true, spent: false });
|
|
525
578
|
}
|
|
526
579
|
}
|
|
527
|
-
/** Takes `op` as far as it can go now, saving before each step that leaves the device.
|
|
580
|
+
/** Takes `op` as far as it can go now, saving before each step that leaves the device. One cancelled meanwhile
|
|
581
|
+
* (`cancel`) finishes the stage under way and starts no other: its status is looked at after each, and nothing it does
|
|
582
|
+
* later is kept, as it is out of the state. A relayer that is relaying its request already throws `Relaying`. */
|
|
528
583
|
export async function advanceSpend(ctx, op) {
|
|
529
584
|
const data = op.data;
|
|
530
585
|
const c = chainCtx(ctx, op.chainId);
|
|
531
586
|
for (;;) {
|
|
587
|
+
if (op.status !== 'pending')
|
|
588
|
+
return;
|
|
532
589
|
if (!data.step) {
|
|
533
590
|
const step = await planStep(ctx, op);
|
|
534
|
-
if (!step)
|
|
591
|
+
if (!step || op.status !== 'pending')
|
|
535
592
|
return;
|
|
536
593
|
if (step === 'done') {
|
|
537
594
|
op.status = 'done';
|
|
@@ -552,6 +609,8 @@ export async function advanceSpend(ctx, op) {
|
|
|
552
609
|
step.stage = 'noted';
|
|
553
610
|
await ctx.save();
|
|
554
611
|
}
|
|
612
|
+
if (op.status !== 'pending')
|
|
613
|
+
return;
|
|
555
614
|
if (step.stage === 'noted') {
|
|
556
615
|
const built = await witnessOf(ctx, op, step);
|
|
557
616
|
if (!built)
|
|
@@ -596,6 +655,8 @@ export async function advanceSpend(ctx, op) {
|
|
|
596
655
|
step.stage = 'proved';
|
|
597
656
|
await ctx.save();
|
|
598
657
|
}
|
|
658
|
+
if (op.status !== 'pending')
|
|
659
|
+
return;
|
|
599
660
|
if (step.stage === 'proved') {
|
|
600
661
|
const attestation = await attest(c.config, step.statement, step.witness);
|
|
601
662
|
step.request = { ...step.request, attestation };
|
|
@@ -603,19 +664,25 @@ export async function advanceSpend(ctx, op) {
|
|
|
603
664
|
step.stage = 'attested';
|
|
604
665
|
await ctx.save();
|
|
605
666
|
}
|
|
667
|
+
if (op.status !== 'pending')
|
|
668
|
+
return;
|
|
669
|
+
if (step.stage === 'attested' && step.relayedAt !== undefined) {
|
|
670
|
+
// a relay of it reverted on an input spent already: an earlier relay of it landed, one whose answer was lost, or
|
|
671
|
+
// another transaction spent the input. Relaying it again would tell nothing more
|
|
672
|
+
const now = await standing(ctx, op, step);
|
|
673
|
+
if (now === 'waiting')
|
|
674
|
+
return;
|
|
675
|
+
if (now === 'dropped')
|
|
676
|
+
delete step.relayedAt;
|
|
677
|
+
else
|
|
678
|
+
step.stage = 'relayed';
|
|
679
|
+
await ctx.save();
|
|
680
|
+
}
|
|
606
681
|
if (step.stage === 'attested') {
|
|
607
682
|
const relayerOut = step.outputs.find((o) => o.role === 'relayer');
|
|
608
|
-
|
|
609
|
-
try {
|
|
610
|
-
result = await relay(c.config, step.request, relayerOut ? { value: relayerOut.value, salt: relayerOut.salt } : undefined);
|
|
611
|
-
}
|
|
612
|
-
catch (e) {
|
|
613
|
-
if (e instanceof RelayUnknown)
|
|
614
|
-
return; // try the same request again next time
|
|
615
|
-
throw e;
|
|
616
|
-
}
|
|
683
|
+
const result = await relay(c.config, step.request, relayerOut ? { value: relayerOut.value, salt: relayerOut.salt } : undefined);
|
|
617
684
|
if ('reverted' in result) {
|
|
618
|
-
if (!(await
|
|
685
|
+
if (!(await inputsSpent(ctx, op, step))) {
|
|
619
686
|
// stale roots, most likely: prove again with the same outputs, next sync. A JoinSplit that keeps reverting
|
|
620
687
|
// is not on chain and cannot land, so failing it frees its inputs.
|
|
621
688
|
if (++step.attempts > 3)
|
|
@@ -624,24 +691,24 @@ export async function advanceSpend(ctx, op) {
|
|
|
624
691
|
await ctx.save();
|
|
625
692
|
return;
|
|
626
693
|
}
|
|
627
|
-
//
|
|
694
|
+
// the indexer counts the nullifiers of whatever spent it already
|
|
628
695
|
step.relayedAt = (await c.indexer.status()).nullifiers;
|
|
696
|
+
await ctx.save();
|
|
697
|
+
return;
|
|
629
698
|
}
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
step.relayedBlock = result.block;
|
|
634
|
-
delete step.relayedAt;
|
|
635
|
-
}
|
|
699
|
+
placeChange(ctx, op, step.outputs[1].salt, result.noteIndex2);
|
|
700
|
+
data.txHashes = [...(data.txHashes ?? []), result.txHash];
|
|
701
|
+
step.relayedBlock = result.block;
|
|
636
702
|
step.stage = 'relayed';
|
|
637
703
|
await ctx.save();
|
|
638
704
|
}
|
|
639
705
|
if (step.stage === 'relayed') {
|
|
640
706
|
step.relayedAt ??= await nullifiersPast(c.indexer, step.relayedBlock);
|
|
641
|
-
const now =
|
|
707
|
+
const now = await standing(ctx, op, step);
|
|
642
708
|
if (now === 'dropped') {
|
|
643
709
|
// relay it again next sync; if it did land after all, that reverts and finds it
|
|
644
710
|
step.stage = 'attested';
|
|
711
|
+
delete step.relayedAt;
|
|
645
712
|
await ctx.save();
|
|
646
713
|
}
|
|
647
714
|
if (now !== 'landed')
|
|
@@ -674,6 +741,8 @@ async function advanceMerge(ctx, op, step) {
|
|
|
674
741
|
step.stage = 'noted';
|
|
675
742
|
await ctx.save();
|
|
676
743
|
}
|
|
744
|
+
if (op.status !== 'pending')
|
|
745
|
+
return false;
|
|
677
746
|
if (step.stage === 'noted') {
|
|
678
747
|
const built = await mergeWitnessOf(ctx, op, step);
|
|
679
748
|
if (!built)
|
|
@@ -708,6 +777,8 @@ async function advanceMerge(ctx, op, step) {
|
|
|
708
777
|
step.stage = 'attested';
|
|
709
778
|
await ctx.save();
|
|
710
779
|
}
|
|
780
|
+
if (op.status !== 'pending')
|
|
781
|
+
return false;
|
|
711
782
|
if (step.stage === 'attested') {
|
|
712
783
|
await requestProof(c.config, prover, step.statement, step.witness, step.inputs.length);
|
|
713
784
|
delete step.witness; // the prover has it: the inputs' openings need not stay saved here
|
|
@@ -731,37 +802,43 @@ async function advanceMerge(ctx, op, step) {
|
|
|
731
802
|
step.stage = 'proved';
|
|
732
803
|
await ctx.save();
|
|
733
804
|
}
|
|
805
|
+
if (op.status !== 'pending')
|
|
806
|
+
return false;
|
|
807
|
+
if (step.stage === 'proved' && step.relayedAt !== undefined) {
|
|
808
|
+
// as a JoinSplit's, told apart by its note
|
|
809
|
+
const now = await standing(ctx, op, step);
|
|
810
|
+
if (now === 'waiting')
|
|
811
|
+
return false;
|
|
812
|
+
if (now === 'dropped')
|
|
813
|
+
delete step.relayedAt;
|
|
814
|
+
else
|
|
815
|
+
step.stage = 'relayed';
|
|
816
|
+
await ctx.save();
|
|
817
|
+
}
|
|
734
818
|
if (step.stage === 'proved') {
|
|
735
|
-
|
|
736
|
-
try {
|
|
737
|
-
result = await relayMerge(c.config, step.request);
|
|
738
|
-
}
|
|
739
|
-
catch (e) {
|
|
740
|
-
if (e instanceof RelayUnknown)
|
|
741
|
-
return false; // try the same request again next time
|
|
742
|
-
throw e;
|
|
743
|
-
}
|
|
819
|
+
const result = await relayMerge(c.config, step.request);
|
|
744
820
|
if ('reverted' in result) {
|
|
745
821
|
// stale roots, most likely: built again with the same output, next sync
|
|
746
|
-
if (!(await
|
|
822
|
+
if (!(await inputsSpent(ctx, op, step))) {
|
|
823
|
+
step.sent = true;
|
|
747
824
|
return again(result.reverted);
|
|
748
|
-
|
|
825
|
+
}
|
|
749
826
|
step.relayedAt = (await c.indexer.status()).nullifiers;
|
|
827
|
+
await ctx.save();
|
|
828
|
+
return false;
|
|
750
829
|
}
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
step.relayedBlock = result.block;
|
|
755
|
-
delete step.relayedAt;
|
|
756
|
-
}
|
|
830
|
+
placeChange(ctx, op, step.output.salt, result.noteIndex);
|
|
831
|
+
data.txHashes = [...(data.txHashes ?? []), result.txHash];
|
|
832
|
+
step.relayedBlock = result.block;
|
|
757
833
|
step.stage = 'relayed';
|
|
758
834
|
await ctx.save();
|
|
759
835
|
}
|
|
760
836
|
step.relayedAt ??= await nullifiersPast(c.indexer, step.relayedBlock);
|
|
761
|
-
const now =
|
|
837
|
+
const now = await standing(ctx, op, step);
|
|
762
838
|
if (now === 'dropped') {
|
|
763
839
|
// relay it again next sync; if it did land after all, that reverts and finds it
|
|
764
840
|
step.stage = 'proved';
|
|
841
|
+
delete step.relayedAt;
|
|
765
842
|
await ctx.save();
|
|
766
843
|
}
|
|
767
844
|
if (now !== 'landed')
|