@zerc20/storage-sdk 0.0.0-stage → 0.1.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.
@@ -0,0 +1,238 @@
1
+ // What every blob holds, and the ids and keys of the slots that hold them.
2
+ //
3
+ // A plaintext is `type(1) ‖ body ‖ zeros`, padded to the one length its blob has: every blob is `BLOB_LEN` bytes, so
4
+ // its kind does not show. Each type has one fixed body. A reader takes the body and ignores what follows it, so a
5
+ // later version can append a field that an older reader passes over; a record an older reader must not misread takes
6
+ // a new type, which that reader drops.
7
+ import { bech32m } from '@scure/base';
8
+ import { compare, concat, kdf, readU32, readU64, taggedHash, u32be, u64be, unhex } from './crypto.js';
9
+ import { BLOB_LEN } from './wire.js';
10
+ /** A sealed slot's plaintext: the blob less the nonce and the tag. */
11
+ export const SLOT_PLAIN = BLOB_LEN - 12 - 16;
12
+ /** An inbox announcement's plaintext: also less the ephemeral key. */
13
+ export const ANNOUNCE_PLAIN = BLOB_LEN - 32 - 12 - 16;
14
+ /** The most salts a burn block holds. */
15
+ export const BURN_BLOCK = 6;
16
+ /** The BN254 scalar field modulus `Fr`, big-endian. */
17
+ export const FR_BE = unhex('30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001');
18
+ /** Record types, the first byte of every plaintext. */
19
+ export const NOTE = 0x01;
20
+ export const CODE_NOTE = 0x02;
21
+ export const SELF_NOTE = 0x03;
22
+ export const DEPOSIT = 0x04;
23
+ export const BURN_BLOCK_RECORD = 0x05;
24
+ export const RETURNED = 0x06;
25
+ export const DEPOSIT_ADDRESS = 0x07;
26
+ export const POS_LANE = 0x08;
27
+ export const SENT_TO_ADDRESS = 0x10;
28
+ export const SENT_TO_CODE = 0x11;
29
+ export const CHANNEL = 0x20;
30
+ export const RECEIVE_CODE = 0x40;
31
+ // ---- ids and keys ----
32
+ /** The inbox announcements of channels to `address` go to, under its registration's notify key: another
33
+ * registration, another inbox, so payers then open fresh channels. */
34
+ export const addressInbox = (address, notifyKey) => taggedHash('zerc20/storage/inbox/v1', [address, notifyKey]);
35
+ /** The payer's seed for its channel to `inbox`, recomputable from the payer's view key alone. */
36
+ export const channelSeed = (seed, payer, inbox) => kdf(seed, 'channel', [payer, inbox]);
37
+ /** A channel's lane key. Binding the inbox and the claimed payer means a seed learned from one channel opens
38
+ * nothing when replayed into another inbox or under another name. */
39
+ export const channelKey = (channelSeed, inbox, payer) => kdf(channelSeed, 'channel-key', [inbox, payer]);
40
+ /** The lane key of receive code `index` (burn index `index` of `tokenId` on `chainId`). Every payer of the code
41
+ * writes its notes to this one lane, and the owner finds them through the log: no inbox, no announcement. */
42
+ export const codeKey = (seed, chainId, tokenId, index) => kdf(seed, 'code', [u64be(chainId), u32be(tokenId), u32be(index)]);
43
+ /** The owner's own lane key: notes to self (merge outputs and change) and burn blocks, which only the owner's
44
+ * devices write and read. */
45
+ export const ownKey = (seed) => kdf(seed, 'own');
46
+ /** The lane key of the owner's point of sale `n`, handed to that point of sale alone: it records there the burn
47
+ * addresses it makes for the owner, ahead of handing them out. */
48
+ export const posKey = (seed, n) => kdf(seed, 'pos', [u32be(n)]);
49
+ /** The slot of record `slotIndex` on `chainId` in the lane of `laneKey`. */
50
+ export const slotId = (laneKey, chainId, slotIndex) => kdf(laneKey, 'slot', [u64be(chainId), u32be(slotIndex)]);
51
+ export const sealKey = (laneKey) => kdf(laneKey, 'seal');
52
+ export const outgoingId = (seed, index) => kdf(seed, 'outgoing-id', [u32be(index)]);
53
+ export const outgoingKey = (seed) => kdf(seed, 'outgoing');
54
+ /** The lanes each record type belongs in. A code's notes name their payer, and only the own lane's say what they are
55
+ * the change or the output of. */
56
+ const LANES = {
57
+ [NOTE]: ['channel'],
58
+ [CODE_NOTE]: ['code'],
59
+ [SELF_NOTE]: ['own'],
60
+ [DEPOSIT]: ['channel'],
61
+ [BURN_BLOCK_RECORD]: ['own', 'pos'],
62
+ [RETURNED]: ['own'],
63
+ [DEPOSIT_ADDRESS]: ['own'],
64
+ [POS_LANE]: ['own'],
65
+ };
66
+ /** `type ‖ body`, zero-padded to `size`. */
67
+ function record(type, body, size = SLOT_PLAIN) {
68
+ const out = new Uint8Array(size);
69
+ out[0] = type;
70
+ out.set(body, 1);
71
+ return out;
72
+ }
73
+ /** A value's 31 bytes on the wire, or `null` if it is not below 2^248. */
74
+ function valueBytes(value) {
75
+ return value.length === 32 && value[0] === 0 ? value.subarray(1) : null;
76
+ }
77
+ const isField = (x) => x.length === 32 && compare(x, FR_BE) < 0;
78
+ const RECEIPTS = ['sent', 'sent-to-code', 'withdrawn', 'unwrapped', 'merged'];
79
+ /** A value back from its 31 bytes on the wire. */
80
+ const wideValue = (b) => concat(Uint8Array.of(0), b);
81
+ /** `kind(1) ‖ amount(31) ‖ fee(31) ‖ counterparty(20)`, or `null` if a field is out of range. */
82
+ function receiptBytes(r) {
83
+ const [amount, fee] = [valueBytes(r.amount), valueBytes(r.fee)];
84
+ if (!amount || !fee || !RECEIPTS.includes(r.kind) || r.counterparty.length !== 20)
85
+ return null;
86
+ return concat(Uint8Array.of(RECEIPTS.indexOf(r.kind) + 1), amount, fee, r.counterparty);
87
+ }
88
+ /** The receipt in `b`, or `undefined` for a kind this version does not know: the note, which may be spendable change,
89
+ * is kept all the same. */
90
+ function readReceipt(b) {
91
+ const kind = RECEIPTS[b[0] - 1];
92
+ return (kind && {
93
+ kind,
94
+ amount: wideValue(b.subarray(1, 32)),
95
+ fee: wideValue(b.subarray(32, 63)),
96
+ counterparty: b.slice(63, 83),
97
+ });
98
+ }
99
+ /** A note's plaintext, `token_id(4) ‖ value(31) ‖ note_salt(32)`, or `null` if a field is out of the circuit's range
100
+ * (an out-of-range field can hash like a different value). With `payer` it is a note to a receive code, naming its
101
+ * payer; with `receipt`, a note to self, saying what it is the change or the output of. */
102
+ export function notePlaintext(opening, extra = null) {
103
+ const value = valueBytes(opening.value);
104
+ if (!value || !isField(opening.noteSalt))
105
+ return null;
106
+ const body = concat(u32be(opening.tokenId), value, opening.noteSalt);
107
+ if (!extra)
108
+ return record(NOTE, body);
109
+ if ('payer' in extra)
110
+ return extra.payer.length === 20 ? record(CODE_NOTE, concat(body, extra.payer)) : null;
111
+ const receipt = receiptBytes(extra.receipt);
112
+ return receipt && record(SELF_NOTE, concat(body, receipt));
113
+ }
114
+ /** A deposit's announcement, `token_id(4) ‖ value(31) ‖ burn_salt(32) ‖ burn_address(20)`, or `null` if the value or
115
+ * the salt is out of range. */
116
+ export function depositPlaintext(tokenId, value, burnSalt, burnAddress) {
117
+ const v = valueBytes(value);
118
+ if (!v || !isField(burnSalt) || burnAddress.length !== 20)
119
+ return null;
120
+ return record(DEPOSIT, concat(u32be(tokenId), v, burnSalt, burnAddress));
121
+ }
122
+ /** `token_id(4) ‖ burn_address(20) ‖` then a return's `index(8) ‖ recipient(20) ‖ amount(31) ‖ tx_hash(32)`, or a
123
+ * deposit address's `deposit_address(20)`. */
124
+ export function ownReceiptPlaintext(r) {
125
+ const amount = r.kind === 'returned' && valueBytes(r.amount);
126
+ const rest = r.kind === 'returned'
127
+ ? amount &&
128
+ r.recipient.length === 20 &&
129
+ r.txHash.length === 32 &&
130
+ concat(u64be(BigInt(r.index)), r.recipient, amount, r.txHash)
131
+ : r.depositAddress.length === 20 && r.depositAddress;
132
+ if (!rest || r.burnAddress.length !== 20)
133
+ throw new Error('an own receipt holds 20-byte addresses, a 32-byte hash and a value below 2^248');
134
+ return record(r.kind === 'returned' ? RETURNED : DEPOSIT_ADDRESS, concat(u32be(r.tokenId), r.burnAddress, rest));
135
+ }
136
+ /** `token_id(4) ‖ first(4) ‖ count(1) ‖ salt(32) × count`. */
137
+ export function burnBlockPlaintext(b) {
138
+ if (b.salts.length === 0 || b.salts.length > BURN_BLOCK || b.salts.some((s) => s.length !== 32)) {
139
+ throw new Error(`a burn block holds 1 to ${BURN_BLOCK} salts of 32 bytes`);
140
+ }
141
+ return record(BURN_BLOCK_RECORD, concat(u32be(b.tokenId), u32be(b.first), Uint8Array.of(b.salts.length), ...b.salts));
142
+ }
143
+ /** `n(4)`. */
144
+ export function posLanePlaintext(n) {
145
+ return record(POS_LANE, u32be(n));
146
+ }
147
+ /** The record a slot of a `lane` lane on `chainId` held, or `null` if it is malformed or not one such a lane holds. */
148
+ export function readLaneRecord(lane, chainId, slotIndex, atNs, plain) {
149
+ const type = plain[0];
150
+ if (plain.length !== SLOT_PLAIN || !LANES[type]?.includes(lane))
151
+ return null;
152
+ const stamp = { slotIndex, atNs };
153
+ const tokenId = readU32(plain, 1);
154
+ if (type === BURN_BLOCK_RECORD) {
155
+ const count = plain[9];
156
+ if (count === 0 || count > BURN_BLOCK)
157
+ return null;
158
+ const salts = Array.from({ length: count }, (_, i) => plain.slice(10 + 32 * i, 42 + 32 * i));
159
+ return { kind: 'burn-block', ...stamp, chainId, tokenId, first: readU32(plain, 5), salts };
160
+ }
161
+ if (type === POS_LANE)
162
+ return { kind: 'pos-lane', ...stamp, n: readU32(plain, 1) };
163
+ if (type === RETURNED || type === DEPOSIT_ADDRESS) {
164
+ const head = { ...stamp, chainId, tokenId, burnAddress: plain.slice(5, 25) };
165
+ if (type === DEPOSIT_ADDRESS)
166
+ return { ...head, kind: 'deposit-address', depositAddress: plain.slice(25, 45) };
167
+ const [recipient, amount, txHash] = [plain.slice(33, 53), wideValue(plain.subarray(53, 84)), plain.slice(84, 116)];
168
+ return { ...head, kind: 'returned', index: Number(readU64(plain, 25)), recipient, amount, txHash };
169
+ }
170
+ // a note or a deposit
171
+ const value = wideValue(plain.subarray(5, 36));
172
+ const salt = plain.slice(36, 68);
173
+ if (!isField(salt))
174
+ return null;
175
+ if (type === DEPOSIT)
176
+ return { kind: 'deposit', ...stamp, chainId, tokenId, value, burnSalt: salt, burnAddress: plain.slice(68, 88) };
177
+ const note = { kind: 'note', ...stamp, opening: { chainId, tokenId, value, noteSalt: salt } };
178
+ if (type === CODE_NOTE)
179
+ note.payer = plain.slice(68, 88);
180
+ const receipt = type === SELF_NOTE && readReceipt(plain.subarray(68, 151));
181
+ if (receipt)
182
+ note.receipt = receipt;
183
+ return note;
184
+ }
185
+ const codeBody = (c) => {
186
+ if (c.burnAddress.length !== 20 || c.publicKey.length !== 32 || c.key.length !== 32)
187
+ throw new Error('not a receive code');
188
+ return concat(u64be(c.chainId), u32be(c.tokenId), c.burnAddress, c.publicKey, c.key);
189
+ };
190
+ const readCodeBody = (b) => ({
191
+ chainId: readU64(b, 0),
192
+ tokenId: readU32(b, 8),
193
+ burnAddress: b.slice(12, 32),
194
+ publicKey: b.slice(32, 64),
195
+ key: b.slice(64, 96),
196
+ });
197
+ const CODE_PREFIX = 'zerc20';
198
+ /** A receive code as text: bech32m of `RECEIVE_CODE ‖ chain_id(8) ‖ token_id(4) ‖ burn_address(20) ‖ public_key(32) ‖
199
+ * key(32)`, so a mistyped one fails its checksum instead of paying someone else. */
200
+ export function encodeCode(c) {
201
+ return bech32m.encode(CODE_PREFIX, bech32m.toWords(concat(Uint8Array.of(RECEIVE_CODE), codeBody(c))), false);
202
+ }
203
+ /** The receive code `text` holds, or `null` for anything else. */
204
+ export function decodeCode(text) {
205
+ try {
206
+ const { prefix, bytes } = bech32m.decodeToBytes(text.trim(), false);
207
+ if (prefix !== CODE_PREFIX || bytes.length !== 97 || bytes[0] !== RECEIVE_CODE)
208
+ return null;
209
+ return readCodeBody(bytes.subarray(1));
210
+ }
211
+ catch {
212
+ return null;
213
+ }
214
+ }
215
+ /** `address(20) ‖ notify_key(32)`, or the code's body. */
216
+ export function targetPlaintext(t) {
217
+ return 'address' in t ? record(SENT_TO_ADDRESS, concat(t.address, t.notifyKey)) : record(SENT_TO_CODE, codeBody(t));
218
+ }
219
+ export function readTarget(plain) {
220
+ if (plain.length !== SLOT_PLAIN)
221
+ return null;
222
+ if (plain[0] === SENT_TO_ADDRESS)
223
+ return { address: plain.slice(1, 21), notifyKey: plain.slice(21, 53) };
224
+ if (plain[0] === SENT_TO_CODE)
225
+ return readCodeBody(plain.subarray(1, 97));
226
+ return null;
227
+ }
228
+ /** A channel's announcement, `payer(20) ‖ channel_seed(32)`: who claims to open it, and the seed its lane key derives
229
+ * from. */
230
+ export function channelPlaintext(payer, seed) {
231
+ return record(CHANNEL, concat(payer, seed), ANNOUNCE_PLAIN);
232
+ }
233
+ export function readChannel(plain) {
234
+ if (plain.length !== ANNOUNCE_PLAIN || plain[0] !== CHANNEL)
235
+ return null;
236
+ return { payer: plain.slice(1, 21), seed: plain.slice(21, 53) };
237
+ }
238
+ //# sourceMappingURL=formats.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formats.js","sourceRoot":"","sources":["../src/formats.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export type { Action, AuditRecord, AuditRequest, CanisterError, Kind, Registration, Service, Slot } from './candid.js';
2
+ export { idlFactory } from './candid.js';
3
+ export { CanisterClient, StorageError } from './canister.js';
4
+ export { BURN_BLOCK, FR_BE, addressInbox, codeKey, decodeCode, encodeCode, posKey, type BurnBlock, type Deposit, type LaneRecord, type Note, type NoteOpening, type OwnReceipt, type PosLane, type Receipt, type ReceiveCode, type Via, } from './formats.js';
5
+ export { commit, nextPosLane, planBurnBlock, planDeposit, planPayCode, planPosLane, planReceipt, planSelf, planSend, writePosBlock, } from './send.js';
6
+ export { type ChainLane, type NewRecord, type StoredLane, type SyncState, emptyState, exportState, importState, refresh, } from './sync.js';
7
+ export { type Recipient, type Signer, type ViewKey, eip191Signer, lookupRecipient, notifyKey, notifySecret, openEscrow, registeredViewKey, register, verifyRegistration, viewKey, } from './viewKey.js';
8
+ export { REGISTER_POW_BITS, actionsDigest, auditMessage, powOk, registerDigest, registerMessage, requiredPowBits, solvePow, vetkdInput, } from './wire.js';
package/dist/index.js ADDED
@@ -0,0 +1,24 @@
1
+ // zerc20-storage SDK: private note delivery for zERC20 on the Internet Computer.
2
+ //
3
+ // - View keys (`registeredViewKey`): an address's key, derived from its zERC20 root seed. Everything only the owner can
4
+ // compute derives from it. Registering (one wallet signature) publishes what payers need: the address's zERC20
5
+ // public key and the key announcements are encrypted to, which payers look up with `lookupRecipient`. It also
6
+ // escrows the view key to the auditor.
7
+ // - History (`refresh`): both sides recover their channels and records from the view key alone, and each refresh
8
+ // reads only what is new. Keep the state with `exportState`.
9
+ // - Payments (`planSend`, `planDeposit`, `planPayCode`, and `planSelf` for merge outputs and change, with what each
10
+ // was), submitted with `commit`; `planReceipt` for what leaves no note to self.
11
+ // - Burn blocks (`planBurnBlock`): which burn addresses the owner's devices hand out. Each of a wallet's own is also
12
+ // a receive code (`encodeCode`), paid by a deposit or by a note, any amount, any number of times.
13
+ // - Points of sale (`planPosLane`): a lane whose key (`posKey`) the owner hands to one point of sale, which records
14
+ // there the burn addresses it hands out (`writePosBlock`), for every device of the owner to find.
15
+ //
16
+ // Payers are not verified: a record's `peer` is only what was claimed.
17
+ export { idlFactory } from './candid.js';
18
+ export { CanisterClient, StorageError } from './canister.js';
19
+ export { BURN_BLOCK, FR_BE, addressInbox, codeKey, decodeCode, encodeCode, posKey, } from './formats.js';
20
+ export { commit, nextPosLane, planBurnBlock, planDeposit, planPayCode, planPosLane, planReceipt, planSelf, planSend, writePosBlock, } from './send.js';
21
+ export { emptyState, exportState, importState, refresh, } from './sync.js';
22
+ export { eip191Signer, lookupRecipient, notifyKey, notifySecret, openEscrow, registeredViewKey, register, verifyRegistration, viewKey, } from './viewKey.js';
23
+ export { REGISTER_POW_BITS, actionsDigest, auditMessage, powOk, registerDigest, registerMessage, requiredPowBits, solvePow, vetkdInput, } from './wire.js';
24
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,EAAE;AACF,wHAAwH;AACxH,iHAAiH;AACjH,gHAAgH;AAChH,yCAAyC;AACzC,iHAAiH;AACjH,+DAA+D;AAC/D,oHAAoH;AACpH,kFAAkF;AAClF,qHAAqH;AACrH,oGAAoG;AACpG,oHAAoH;AACpH,oGAAoG;AACpG,EAAE;AACF,uEAAuE;AAGvE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,EACL,UAAU,EACV,KAAK,EACL,YAAY,EACZ,OAAO,EACP,UAAU,EACV,UAAU,EACV,MAAM,GAWP,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,MAAM,EACN,WAAW,EACX,aAAa,EACb,WAAW,EACX,WAAW,EACX,WAAW,EACX,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,aAAa,GACd,MAAM,WAAW,CAAC;AACnB,OAAO,EAKL,UAAU,EACV,WAAW,EACX,WAAW,EACX,OAAO,GACR,MAAM,WAAW,CAAC;AACnB,OAAO,EAIL,YAAY,EACZ,eAAe,EACf,SAAS,EACT,YAAY,EACZ,UAAU,EACV,iBAAiB,EACjB,QAAQ,EACR,kBAAkB,EAClB,OAAO,GACR,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,iBAAiB,EACjB,aAAa,EACb,YAAY,EACZ,KAAK,EACL,cAAc,EACd,eAAe,EACf,eAAe,EACf,QAAQ,EACR,UAAU,GACX,MAAM,WAAW,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ // solvePow's search, in a Web Worker: off the page's thread, it never needs to yield.
2
+ import { findNonce } from './wire.js';
3
+ onmessage = async ({ data }) => postMessage(await findNonce(data.digest, data.bits, Infinity));
4
+ //# sourceMappingURL=powWorker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"powWorker.js","sourceRoot":"","sources":["../src/powWorker.ts"],"names":[],"mappings":"AAAA,sFAAsF;AAEtF,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,SAAS,GAAG,KAAK,EAAE,EAAE,IAAI,EAAsD,EAAE,EAAE,CACjF,WAAW,CAAC,MAAM,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC"}
package/dist/send.d.ts ADDED
@@ -0,0 +1,51 @@
1
+ import type { Action } from './candid.js';
2
+ import { type CanisterClient } from './canister.js';
3
+ import { type BurnBlock, type NoteOpening, type OwnReceipt, type Receipt, type ReceiveCode } from './formats.js';
4
+ import { type NewRecord, type SyncState } from './sync.js';
5
+ import type { Recipient, ViewKey } from './viewKey.js';
6
+ /** A note with `opening` (what the on-chain note commits to) for `recipient`, as `lookupRecipient` found it. The
7
+ * on-chain note must be owned by `recipient.publicKey`. */
8
+ export declare function planSend(view: ViewKey, state: SyncState, recipient: Recipient, opening: NoteOpening): Action[];
9
+ /** Tells `recipient` of a deposit of `value` of `tokenId` on `chainId` into its burn address of `burnSalt`, under
10
+ * `recipient.publicKey`, which the payer then pays by a plain transfer. */
11
+ export declare function planDeposit(view: ViewKey, state: SyncState, recipient: Recipient, deposit: {
12
+ chainId: bigint;
13
+ tokenId: number;
14
+ value: Uint8Array;
15
+ burnSalt: Uint8Array;
16
+ burnAddress: Uint8Array;
17
+ }): Action[];
18
+ /** A note with `opening` paying `code`; the on-chain note must be owned by `code.publicKey`. Every payer of the code
19
+ * writes to its one lane, naming itself: the first payment records the code for the payer's history and looks for
20
+ * the lane's end, later ones take it from `state`. Another payer writing first makes the submit `Occupied`, which
21
+ * `commit` plans again. */
22
+ export declare function planPayCode(client: CanisterClient, view: ViewKey, state: SyncState, code: ReceiveCode, opening: NoteOpening): Promise<Action[]>;
23
+ /** A note to self in the own lane, which only the owner reads: the output of a merge, or the change of a payment.
24
+ * Put a payment's change in the payment's batch, so both are written or neither:
25
+ * `[...planSend(..), ...planSelf(..)]`. `receipt` says what the payment or merge was, for the owner's other devices; a
26
+ * zero-value change is unspendable, and worth writing only to carry it. */
27
+ export declare function planSelf(view: ViewKey, state: SyncState, opening: NoteOpening, receipt: Receipt): Action[];
28
+ /** What the owner did that leaves no note to self (a rage exit, a deposit address registered), in the own lane. */
29
+ export declare function planReceipt(view: ViewKey, state: SyncState, receipt: OwnReceipt): Action[];
30
+ /** The record of `block` in the own lane, to submit before handing out any of its burn addresses, so that every
31
+ * device of the owner watches them. Record blocks ahead of need, not as an address is handed out: the time of the
32
+ * write would otherwise mark the first payment to it. */
33
+ export declare function planBurnBlock(view: ViewKey, state: SyncState, block: BurnBlock): Action[];
34
+ /** The number the owner's next point of sale takes: one past the highest the own lane records. */
35
+ export declare const nextPosLane: (state: SyncState) => number;
36
+ /** The record of point of sale `n` in the own lane, so that every device of the owner reads its lane (`posKey`). Plan
37
+ * it with `n = nextPosLane(state)` inside `commit`'s plan: after `Occupied`, another device took that number. */
38
+ export declare function planPosLane(view: ViewKey, state: SyncState, chainId: bigint, n: number): Action[];
39
+ /** Writes `block` to the lane of `laneKey`, as the point of sale that alone holds the key, at the lane's first empty
40
+ * slot from `from` on; returns the slot after it. A slot someone else took first is passed over, and the same salts
41
+ * written twice are found once. */
42
+ export declare function writePosBlock(client: CanisterClient, laneKey: Uint8Array, block: BurnBlock, from?: number): Promise<number>;
43
+ /** Submits the actions `plan` builds from `state`, then refreshes; continue from the returned state,
44
+ * or the next plan reuses a slot that is taken. After `Occupied` (another device wrote there first)
45
+ * it refreshes and plans once more. Calls that fail without an answer are retried with the same
46
+ * actions, which is safe: writes are write-once and batches atomic. */
47
+ export declare function commit<T extends Action[]>(client: CanisterClient, view: ViewKey, state: SyncState, plan: (state: SyncState) => T | Promise<T>): Promise<{
48
+ planned: T;
49
+ state: SyncState;
50
+ added: NewRecord[];
51
+ }>;
package/dist/send.js ADDED
@@ -0,0 +1,162 @@
1
+ // Planning payments, deposits, notes to self, burn blocks and points of sale from a synced state, and submitting them.
2
+ // A point of sale writes its own lane with its key alone (`writePosBlock`).
3
+ //
4
+ // Write the note here first, then create the on-chain note with the same opening: a note that exists
5
+ // only on chain cannot be found. Receivers match notes one-to-one to on-chain leaves (by
6
+ // `commitment_index`) and treat the unmatched as pending.
7
+ import { StorageError } from './canister.js';
8
+ import { equal, seal, sealTo } from './crypto.js';
9
+ import { burnBlockPlaintext, channelKey, channelPlaintext, channelSeed, depositPlaintext, notePlaintext, outgoingId, outgoingKey, ownKey, ownReceiptPlaintext, posLanePlaintext, sealKey, slotId, targetPlaintext, } from './formats.js';
10
+ import { checkState, refresh, sequenceEnd } from './sync.js';
11
+ /** The record at `slotIndex` of the lane of `laneKey` on `chainId`. */
12
+ function put(laneKey, chainId, slotIndex, plaintext) {
13
+ const id = slotId(laneKey, chainId, slotIndex);
14
+ return { Put: { kind: { Lane: null }, id, data: seal(sealKey(laneKey), id, plaintext) } };
15
+ }
16
+ /** The next free slot of a lane `state` has read, which must be on a watched chain. */
17
+ function nextSlotIndex(state, chains, chainId) {
18
+ if (!state.chains.includes(chainId))
19
+ throw new Error(`watch chain ${chainId} and refresh first`);
20
+ return chains?.find((c) => c.chainId === chainId)?.nextSlotIndex ?? 0;
21
+ }
22
+ function plaintextOf(plain) {
23
+ if (!plain)
24
+ throw new Error('out of range: value ≥ 2^248 or salt ≥ Fr');
25
+ return plain;
26
+ }
27
+ /** A record for `recipient` on `chainId`, through the channel to it, which is opened first if there is none yet. */
28
+ function toAddress(view, state, recipient, chainId, plaintext) {
29
+ checkState(view, state);
30
+ const actions = [];
31
+ const { inbox } = recipient;
32
+ const channel = state.outgoing.lanes.find((c) => c.inbox && equal(c.inbox, inbox));
33
+ let key = channel?.key;
34
+ if (!key) {
35
+ // first contact: announce `payer ‖ seed` to the receiver, and record the channel for the payer
36
+ const c = channelSeed(view.seed, view.address, inbox);
37
+ const enc_announcement = sealTo(recipient.notifyKey, 'announce', inbox, channelPlaintext(view.address, c));
38
+ if (!enc_announcement)
39
+ throw new Error('low-order notify key');
40
+ const outgoing_id = outgoingId(view.seed, state.outgoing.next);
41
+ const target = { address: recipient.address, notifyKey: recipient.notifyKey };
42
+ const enc_outgoing = seal(outgoingKey(view.seed), outgoing_id, targetPlaintext(target));
43
+ actions.push({ OpenChannel: { inbox, enc_announcement, outgoing_id, enc_outgoing } });
44
+ key = channelKey(c, inbox, view.address);
45
+ }
46
+ actions.push(put(key, chainId, nextSlotIndex(state, channel?.chains, chainId), plaintext));
47
+ return actions;
48
+ }
49
+ /** A note with `opening` (what the on-chain note commits to) for `recipient`, as `lookupRecipient` found it. The
50
+ * on-chain note must be owned by `recipient.publicKey`. */
51
+ export function planSend(view, state, recipient, opening) {
52
+ return toAddress(view, state, recipient, opening.chainId, plaintextOf(notePlaintext(opening)));
53
+ }
54
+ /** Tells `recipient` of a deposit of `value` of `tokenId` on `chainId` into its burn address of `burnSalt`, under
55
+ * `recipient.publicKey`, which the payer then pays by a plain transfer. */
56
+ export function planDeposit(view, state, recipient, deposit) {
57
+ const plaintext = plaintextOf(depositPlaintext(deposit.tokenId, deposit.value, deposit.burnSalt, deposit.burnAddress));
58
+ return toAddress(view, state, recipient, deposit.chainId, plaintext);
59
+ }
60
+ /** A note with `opening` paying `code`; the on-chain note must be owned by `code.publicKey`. Every payer of the code
61
+ * writes to its one lane, naming itself: the first payment records the code for the payer's history and looks for
62
+ * the lane's end, later ones take it from `state`. Another payer writing first makes the submit `Occupied`, which
63
+ * `commit` plans again. */
64
+ export async function planPayCode(client, view, state, code, opening) {
65
+ if (opening.chainId !== code.chainId || opening.tokenId !== code.tokenId)
66
+ throw new Error("the note is not for the code's chain and token");
67
+ const plaintext = plaintextOf(notePlaintext(opening, { payer: view.address }));
68
+ checkState(view, state);
69
+ const { chainId, key } = code;
70
+ const lane = state.outgoing.lanes.find((c) => equal(c.key, key));
71
+ if (lane)
72
+ return [put(key, chainId, nextSlotIndex(state, lane.chains, chainId), plaintext)];
73
+ nextSlotIndex(state, undefined, chainId); // a watched chain
74
+ const id = outgoingId(view.seed, state.outgoing.next);
75
+ const record = seal(outgoingKey(view.seed), id, targetPlaintext(code));
76
+ const end = await sequenceEnd(client, (i) => slotId(key, chainId, i));
77
+ return [{ Put: { kind: { Outgoing: null }, id, data: record } }, put(key, chainId, end, plaintext)];
78
+ }
79
+ /** A note to self in the own lane, which only the owner reads: the output of a merge, or the change of a payment.
80
+ * Put a payment's change in the payment's batch, so both are written or neither:
81
+ * `[...planSend(..), ...planSelf(..)]`. `receipt` says what the payment or merge was, for the owner's other devices; a
82
+ * zero-value change is unspendable, and worth writing only to carry it. */
83
+ export function planSelf(view, state, opening, receipt) {
84
+ checkState(view, state);
85
+ const plaintext = plaintextOf(notePlaintext(opening, { receipt }));
86
+ return [put(ownKey(view.seed), opening.chainId, nextSlotIndex(state, state.own, opening.chainId), plaintext)];
87
+ }
88
+ /** What the owner did that leaves no note to self (a rage exit, a deposit address registered), in the own lane. */
89
+ export function planReceipt(view, state, receipt) {
90
+ checkState(view, state);
91
+ return [
92
+ put(ownKey(view.seed), receipt.chainId, nextSlotIndex(state, state.own, receipt.chainId), ownReceiptPlaintext(receipt)),
93
+ ];
94
+ }
95
+ /** The record of `block` in the own lane, to submit before handing out any of its burn addresses, so that every
96
+ * device of the owner watches them. Record blocks ahead of need, not as an address is handed out: the time of the
97
+ * write would otherwise mark the first payment to it. */
98
+ export function planBurnBlock(view, state, block) {
99
+ checkState(view, state);
100
+ return [
101
+ put(ownKey(view.seed), block.chainId, nextSlotIndex(state, state.own, block.chainId), burnBlockPlaintext(block)),
102
+ ];
103
+ }
104
+ /** The number the owner's next point of sale takes: one past the highest the own lane records. */
105
+ export const nextPosLane = (state) => 1 + Math.max(-1, ...state.incoming.map((c) => (c.via.type === 'pos' ? c.via.n : -1)));
106
+ /** The record of point of sale `n` in the own lane, so that every device of the owner reads its lane (`posKey`). Plan
107
+ * it with `n = nextPosLane(state)` inside `commit`'s plan: after `Occupied`, another device took that number. */
108
+ export function planPosLane(view, state, chainId, n) {
109
+ checkState(view, state);
110
+ return [put(ownKey(view.seed), chainId, nextSlotIndex(state, state.own, chainId), posLanePlaintext(n))];
111
+ }
112
+ /** Writes `block` to the lane of `laneKey`, as the point of sale that alone holds the key, at the lane's first empty
113
+ * slot from `from` on; returns the slot after it. A slot someone else took first is passed over, and the same salts
114
+ * written twice are found once. */
115
+ export async function writePosBlock(client, laneKey, block, from = 0) {
116
+ const plaintext = burnBlockPlaintext(block);
117
+ for (;;) {
118
+ const at = await sequenceEnd(client, (i) => slotId(laneKey, block.chainId, i), from);
119
+ try {
120
+ await submit(client, [put(laneKey, block.chainId, at, plaintext)]);
121
+ return at + 1;
122
+ }
123
+ catch (e) {
124
+ if (!(e instanceof StorageError && e.occupied))
125
+ throw e;
126
+ from = at + 1;
127
+ }
128
+ }
129
+ }
130
+ /** Submits the actions `plan` builds from `state`, then refreshes; continue from the returned state,
131
+ * or the next plan reuses a slot that is taken. After `Occupied` (another device wrote there first)
132
+ * it refreshes and plans once more. Calls that fail without an answer are retried with the same
133
+ * actions, which is safe: writes are write-once and batches atomic. */
134
+ export async function commit(client, view, state, plan) {
135
+ let planned = await plan(state);
136
+ // a record is announced by one refresh only: keep what the one between the attempts announced too
137
+ let added = [];
138
+ try {
139
+ await submit(client, planned);
140
+ }
141
+ catch (e) {
142
+ if (!(e instanceof StorageError && e.occupied))
143
+ throw e;
144
+ ({ state, added } = await refresh(client, view, state));
145
+ planned = await plan(state);
146
+ await submit(client, planned);
147
+ }
148
+ const last = await refresh(client, view, state);
149
+ return { planned, state: last.state, added: [...added, ...last.added] };
150
+ }
151
+ async function submit(client, actions) {
152
+ for (let attempt = 1;; attempt++) {
153
+ try {
154
+ return await client.submit(actions);
155
+ }
156
+ catch (e) {
157
+ if (e instanceof StorageError || attempt === 3)
158
+ throw e;
159
+ }
160
+ }
161
+ }
162
+ //# sourceMappingURL=send.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"send.js","sourceRoot":"","sources":["../src/send.ts"],"names":[],"mappings":"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"}
package/dist/sync.d.ts ADDED
@@ -0,0 +1,82 @@
1
+ import type { CanisterClient } from './canister.js';
2
+ import { type LaneRecord, type Via } from './formats.js';
3
+ import { type ViewKey } from './viewKey.js';
4
+ /** One lane on one chain. */
5
+ export interface ChainLane {
6
+ chainId: bigint;
7
+ /** Where the next record goes: the first empty slot index (slots that do not open count too). */
8
+ nextSlotIndex: number;
9
+ /** What it held, in slot order. An app that keeps records of its own may empty this. */
10
+ records: LaneRecord[];
11
+ }
12
+ /** A lane other than the own lane: one payer → receiver channel, a receive code's lane, which every payer of the code
13
+ * writes to, or the lane of one of the owner's points of sale. */
14
+ export interface StoredLane {
15
+ /** Outgoing: the receiver, or `null` for a code (which never names its receiver). Incoming: the payer as claimed
16
+ * by whoever opened the channel, or `null` for a code, whose notes each claim their own, and for a point of sale;
17
+ * it is NOT verified. */
18
+ peer: Uint8Array | null;
19
+ via: Via;
20
+ /** The channel seed and its inbox; `null` for a code and a point of sale, which have neither. */
21
+ seed: Uint8Array | null;
22
+ inbox: Uint8Array | null;
23
+ /** The lane key. */
24
+ key: Uint8Array;
25
+ /** One entry per watched chain. */
26
+ chains: ChainLane[];
27
+ }
28
+ /** Everything one view key has seen so far. Plain data: keep it with `exportState`, and treat it as read-only. */
29
+ export interface SyncState {
30
+ address: Uint8Array;
31
+ /** The chains whose lanes are read. Add one and the next refresh reads it from slot 0. */
32
+ chains: bigint[];
33
+ addressInboxRead: number;
34
+ /** Channels to the address, the address's own receive codes (one for each burn index in its burn blocks), and the
35
+ * lanes of its points of sale (one for each the own lane records). */
36
+ incoming: StoredLane[];
37
+ outgoing: {
38
+ next: number;
39
+ lanes: StoredLane[];
40
+ };
41
+ /** The own lane (notes to self, burn blocks and points of sale), one entry per watched chain. */
42
+ own: ChainLane[];
43
+ /** How far the canister's lane log has been read; `null` until the first full read. */
44
+ log: number | null;
45
+ }
46
+ /** A record a refresh found. */
47
+ export interface NewRecord {
48
+ direction: 'incoming' | 'outgoing' | 'own';
49
+ /** `null` in the own lane. */
50
+ lane: StoredLane | null;
51
+ /** Who is on the other side, as claimed and unverified: an incoming channel's payer, an outgoing one's receiver,
52
+ * a note's payer in one of the owner's codes. `null` in the own lane and a point of sale's, and for a payment to a
53
+ * code. */
54
+ peer: Uint8Array | null;
55
+ record: LaneRecord;
56
+ }
57
+ export declare const emptyState: (view: ViewKey, chains: bigint[]) => SyncState;
58
+ export declare function checkState(view: ViewKey, state: SyncState): void;
59
+ /** Reads what is new since `state` and returns the extended state, plus the records it found. `state` itself is
60
+ * left untouched, so a failed refresh loses nothing. A first sync is a refresh of `emptyState`.
61
+ *
62
+ * Queries only spot news: whatever is kept is read again as update calls, so a single lying replica
63
+ * can neither plant entries nor make a cursor skip one. With nothing new it costs queries only: one
64
+ * for outgoing records, one for the address inbox, and one for the lane log.
65
+ *
66
+ * A replica can still leave log entries out, which only delays those records: `full` reads every
67
+ * lane instead (one query per 256 of them: every channel, point of sale and the own lane on every
68
+ * watched chain, every code on its own), as the first refresh of a state does. Do that now and then, say hourly. */
69
+ export declare function refresh(client: CanisterClient, view: ViewKey, state: SyncState, opts?: {
70
+ full?: boolean;
71
+ }): Promise<{
72
+ state: SyncState;
73
+ added: NewRecord[];
74
+ }>;
75
+ /** The first empty slot of a lane's sequence from slot `from` on: where a code's first payment goes, or a point of
76
+ * sale's next block. */
77
+ export declare function sequenceEnd(client: CanisterClient, idAt: (index: number) => Uint8Array, from?: number): Promise<number>;
78
+ /** `state`, encrypted under a key only `view` derives, for the app to store anywhere. */
79
+ export declare function exportState(view: ViewKey, state: SyncState): Uint8Array;
80
+ /** The state `exportState` encrypted, or `null` if `bytes` is not one for `view` (start over from
81
+ * `emptyState` then). */
82
+ export declare function importState(view: ViewKey, bytes: Uint8Array): SyncState | null;