@invisi-labs/primitives 0.0.0-stage → 1.2.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/README.md +4 -2
- package/dist/address.cjs +263 -0
- package/dist/address.cjs.map +1 -0
- package/dist/address.d.cts +35 -0
- package/dist/address.d.ts +35 -0
- package/dist/address.js +10 -0
- package/dist/address.js.map +1 -0
- package/dist/chunk-3SEC7POH.js +168 -0
- package/dist/chunk-3SEC7POH.js.map +1 -0
- package/dist/chunk-PRUUPDVD.js +1149 -0
- package/dist/chunk-PRUUPDVD.js.map +1 -0
- package/dist/chunk-Q3NNEKKR.js +147 -0
- package/dist/chunk-Q3NNEKKR.js.map +1 -0
- package/dist/chunk-TJYV6KTQ.js +21 -0
- package/dist/chunk-TJYV6KTQ.js.map +1 -0
- package/dist/credit.cjs +1113 -0
- package/dist/credit.cjs.map +1 -0
- package/dist/credit.d.cts +68 -0
- package/dist/credit.d.ts +68 -0
- package/dist/credit.js +42 -0
- package/dist/credit.js.map +1 -0
- package/dist/encryption-0HQXc3tT.d.cts +33 -0
- package/dist/encryption-D06YBTW0.d.ts +33 -0
- package/dist/index.cjs +2759 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +492 -0
- package/dist/index.d.ts +492 -0
- package/dist/index.js +1311 -0
- package/dist/index.js.map +1 -0
- package/dist/note.cjs +875 -0
- package/dist/note.cjs.map +1 -0
- package/dist/note.d.cts +12 -0
- package/dist/note.d.ts +12 -0
- package/dist/note.js +18 -0
- package/dist/note.js.map +1 -0
- package/dist/types-CEAuh35C.d.cts +80 -0
- package/dist/types-CEAuh35C.d.ts +80 -0
- package/package.json +52 -3
package/dist/index.js
ADDED
|
@@ -0,0 +1,1311 @@
|
|
|
1
|
+
import {
|
|
2
|
+
computeNoteNullifier
|
|
3
|
+
} from "./chunk-TJYV6KTQ.js";
|
|
4
|
+
import {
|
|
5
|
+
CREDIT_POLICY_FIELDS,
|
|
6
|
+
CREDIT_USAGE_FIELDS,
|
|
7
|
+
D_CNULL,
|
|
8
|
+
D_CREDIT,
|
|
9
|
+
D_CREDIT_KEY_HASH,
|
|
10
|
+
D_CREDIT_RECOVERY,
|
|
11
|
+
D_CREDIT_STATE_NONCE,
|
|
12
|
+
D_IDENT,
|
|
13
|
+
D_NOTE,
|
|
14
|
+
D_NULL,
|
|
15
|
+
FIELD_MODULUS,
|
|
16
|
+
MAX_CIPHERTEXT_BYTES,
|
|
17
|
+
TREE_DEPTH,
|
|
18
|
+
applyCreditDrawUsage,
|
|
19
|
+
computeCreditCommitment,
|
|
20
|
+
computeCreditNullifier,
|
|
21
|
+
computeCreditRecoveryPad,
|
|
22
|
+
computeCreditSharedKeyHash,
|
|
23
|
+
computeNoteCommitment,
|
|
24
|
+
computeNoteIdentity,
|
|
25
|
+
creditCommitment,
|
|
26
|
+
creditPeriods,
|
|
27
|
+
decodeDeliveryHeader,
|
|
28
|
+
decryptCreditPayload,
|
|
29
|
+
decryptCreditState,
|
|
30
|
+
decryptNotePayload,
|
|
31
|
+
decryptPrivateTransferNote,
|
|
32
|
+
deliveryCodec,
|
|
33
|
+
deliveryHeader,
|
|
34
|
+
deriveCreditState,
|
|
35
|
+
deriveCreditStateNonce,
|
|
36
|
+
deriveCreditUpdate,
|
|
37
|
+
encryptCreditState,
|
|
38
|
+
encryptPrivateTransferNote,
|
|
39
|
+
exportPayloadKey,
|
|
40
|
+
generateCreditSharedKey,
|
|
41
|
+
generateNonce,
|
|
42
|
+
normalizeCreditDeliveryState,
|
|
43
|
+
normalizeCreditPolicy,
|
|
44
|
+
normalizeCreditState,
|
|
45
|
+
normalizeCreditUsage,
|
|
46
|
+
noteCommitment,
|
|
47
|
+
poseidonHash,
|
|
48
|
+
recoverCreditState,
|
|
49
|
+
validateContext,
|
|
50
|
+
validateDeliveryCiphertext,
|
|
51
|
+
viewingPublicKey
|
|
52
|
+
} from "./chunk-PRUUPDVD.js";
|
|
53
|
+
import {
|
|
54
|
+
MissingCapabilityError,
|
|
55
|
+
ReceivingAddress,
|
|
56
|
+
decodeAddress
|
|
57
|
+
} from "./chunk-3SEC7POH.js";
|
|
58
|
+
import {
|
|
59
|
+
createClue,
|
|
60
|
+
createClueFromSeed,
|
|
61
|
+
deriveClueKey,
|
|
62
|
+
validateClueKey
|
|
63
|
+
} from "./chunk-Q3NNEKKR.js";
|
|
64
|
+
|
|
65
|
+
// src/disclosure/disclosure.ts
|
|
66
|
+
import { bytesToHex } from "@noble/hashes/utils";
|
|
67
|
+
var NOTE_FIELDS = ["ownerAddress", "amount", "nonce"];
|
|
68
|
+
var CREDIT_FIELDS = [
|
|
69
|
+
"spenderWalletIdentity",
|
|
70
|
+
"ownerWalletIdentity",
|
|
71
|
+
"revocationShard",
|
|
72
|
+
"revocationSlot",
|
|
73
|
+
"nonce",
|
|
74
|
+
"expiry",
|
|
75
|
+
"creditSharedKeyHash",
|
|
76
|
+
"singleLimit",
|
|
77
|
+
"dailyLimit",
|
|
78
|
+
"monthlyLimit",
|
|
79
|
+
"availableCredit",
|
|
80
|
+
"unlimited",
|
|
81
|
+
"lastDay",
|
|
82
|
+
"dailySpent",
|
|
83
|
+
"lastMonth",
|
|
84
|
+
"monthlySpent",
|
|
85
|
+
"totalSpent"
|
|
86
|
+
];
|
|
87
|
+
function record(value, fields) {
|
|
88
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
89
|
+
throw new Error("invalid disclosure object");
|
|
90
|
+
const keys = Object.keys(value);
|
|
91
|
+
if (keys.length !== fields.length || keys.some((key) => !fields.includes(key)))
|
|
92
|
+
throw new Error("unexpected disclosure fields");
|
|
93
|
+
return value;
|
|
94
|
+
}
|
|
95
|
+
function number(value, bits, label) {
|
|
96
|
+
if (typeof value !== "bigint" || value < 0n || value >= 1n << BigInt(bits))
|
|
97
|
+
throw new Error(`invalid disclosure ${label}`);
|
|
98
|
+
return value;
|
|
99
|
+
}
|
|
100
|
+
function decimal(value, bits, label) {
|
|
101
|
+
if (typeof value !== "string" || !/^(0|[1-9][0-9]*)$/.test(value) || value.length > 78)
|
|
102
|
+
throw new Error(`invalid disclosure ${label}`);
|
|
103
|
+
return number(BigInt(value), bits, label);
|
|
104
|
+
}
|
|
105
|
+
function hash(value, label, field = true) {
|
|
106
|
+
if (typeof value !== "string" || !/^0x[0-9a-fA-F]{64}$/.test(value))
|
|
107
|
+
throw new Error(`invalid disclosure ${label}`);
|
|
108
|
+
if (field && BigInt(value) >= FIELD_MODULUS) throw new Error(`invalid disclosure ${label}`);
|
|
109
|
+
return value.toLowerCase();
|
|
110
|
+
}
|
|
111
|
+
function owner(value, label) {
|
|
112
|
+
if (typeof value !== "string" || !/^0x[0-9a-fA-F]{40}$/.test(value) || BigInt(value) === 0n)
|
|
113
|
+
throw new Error(`invalid disclosure ${label}`);
|
|
114
|
+
return value.toLowerCase();
|
|
115
|
+
}
|
|
116
|
+
function nonce(value) {
|
|
117
|
+
if (value < 0n || value >= FIELD_MODULUS) throw new Error("invalid disclosure nonce");
|
|
118
|
+
return value;
|
|
119
|
+
}
|
|
120
|
+
function context(value) {
|
|
121
|
+
const result = {
|
|
122
|
+
chainId: number(value.chainId, 64, "chainId"),
|
|
123
|
+
protocolAddress: number(value.protocolAddress, 160, "protocolAddress"),
|
|
124
|
+
tokenAddress: number(value.tokenAddress, 160, "tokenAddress")
|
|
125
|
+
};
|
|
126
|
+
if (result.protocolAddress === 0n || result.tokenAddress === 0n)
|
|
127
|
+
throw new Error("disclosure addresses must be nonzero");
|
|
128
|
+
return result;
|
|
129
|
+
}
|
|
130
|
+
function encode(values) {
|
|
131
|
+
return Object.fromEntries(
|
|
132
|
+
Object.entries(values).map(([key, value]) => [key, value.toString()])
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
async function creditOpening(note) {
|
|
136
|
+
const copied = { ...note };
|
|
137
|
+
return {
|
|
138
|
+
...context(copied),
|
|
139
|
+
...normalizeCreditPolicy(copied),
|
|
140
|
+
...normalizeCreditUsage(copied),
|
|
141
|
+
availableCredit: number(copied.availableCredit, 128, "availableCredit"),
|
|
142
|
+
unlimited: copied.unlimited,
|
|
143
|
+
spenderWalletIdentity: owner(copied.spenderWalletIdentity, "spender identity"),
|
|
144
|
+
ownerWalletIdentity: owner(copied.ownerWalletIdentity, "owner identity"),
|
|
145
|
+
revocationShard: number(copied.revocationShard, 64, "revocation shard"),
|
|
146
|
+
revocationSlot: number(copied.revocationSlot, 16, "revocation slot"),
|
|
147
|
+
nonce: nonce(copied.nonce),
|
|
148
|
+
expiry: number(copied.expiry, 64, "expiry"),
|
|
149
|
+
creditSharedKeyHash: await computeCreditSharedKeyHash(copied.creditSharedKey)
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
async function commitment(note) {
|
|
153
|
+
if ("creditSharedKeyHash" in note) {
|
|
154
|
+
return computeCreditCommitment({ ...note, creditSharedKey: 0n }, note.creditSharedKeyHash);
|
|
155
|
+
}
|
|
156
|
+
return computeNoteCommitment(
|
|
157
|
+
note.chainId,
|
|
158
|
+
BigInt(note.protocolAddress),
|
|
159
|
+
await computeNoteIdentity(BigInt(note.ownerAddress), note.nonce),
|
|
160
|
+
note.tokenAddress,
|
|
161
|
+
note.amount
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
var Disclosure = class _Disclosure {
|
|
165
|
+
#material;
|
|
166
|
+
constructor(material) {
|
|
167
|
+
this.#material = {
|
|
168
|
+
...material,
|
|
169
|
+
context: Object.freeze({ ...material.context }),
|
|
170
|
+
data: Object.freeze({ ...material.data })
|
|
171
|
+
};
|
|
172
|
+
Object.freeze(this.#material);
|
|
173
|
+
Object.freeze(this);
|
|
174
|
+
}
|
|
175
|
+
static async fromNote(value) {
|
|
176
|
+
const copied = { ...value };
|
|
177
|
+
const note = {
|
|
178
|
+
...context(copied),
|
|
179
|
+
ownerAddress: owner(copied.ownerAddress, "owner address"),
|
|
180
|
+
amount: number(copied.amount, 128, "amount"),
|
|
181
|
+
nonce: nonce(copied.nonce)
|
|
182
|
+
};
|
|
183
|
+
return new _Disclosure({
|
|
184
|
+
version: 1,
|
|
185
|
+
kind: "note",
|
|
186
|
+
method: "opening",
|
|
187
|
+
context: {
|
|
188
|
+
...encode(context(note)),
|
|
189
|
+
outputCommitment: await commitment(note)
|
|
190
|
+
},
|
|
191
|
+
data: encode({
|
|
192
|
+
ownerAddress: note.ownerAddress,
|
|
193
|
+
amount: note.amount,
|
|
194
|
+
nonce: note.nonce
|
|
195
|
+
})
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
static async fromCredit(value) {
|
|
199
|
+
const note = await creditOpening(value);
|
|
200
|
+
const data = Object.fromEntries(
|
|
201
|
+
CREDIT_FIELDS.map((key) => [
|
|
202
|
+
key,
|
|
203
|
+
key === "unlimited" ? note.unlimited ? "1" : "0" : note[key].toString()
|
|
204
|
+
])
|
|
205
|
+
);
|
|
206
|
+
return new _Disclosure({
|
|
207
|
+
version: 1,
|
|
208
|
+
kind: "credit",
|
|
209
|
+
method: "opening",
|
|
210
|
+
context: {
|
|
211
|
+
...encode(context(note)),
|
|
212
|
+
outputCommitment: await commitment(note)
|
|
213
|
+
},
|
|
214
|
+
data
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
/** Low-level factory; normally use wallet.getViewer().discloseNote(). */
|
|
218
|
+
static async fromEncryptedNote(key, envelope, value) {
|
|
219
|
+
const scoped = { ...value };
|
|
220
|
+
const copied = typeof envelope === "string" ? envelope : Uint8Array.from(envelope);
|
|
221
|
+
const localKey = typeof key === "string" ? key : Uint8Array.from(key);
|
|
222
|
+
try {
|
|
223
|
+
await decryptPrivateTransferNote(localKey, copied, scoped);
|
|
224
|
+
return await _Disclosure.fromEnvelope(localKey, copied, scoped, "funds");
|
|
225
|
+
} finally {
|
|
226
|
+
if (localKey instanceof Uint8Array) localKey.fill(0);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
/** Exposes the full selected Credit envelope, including its shared key and receiving snapshots. */
|
|
230
|
+
static async fromEncryptedCredit(key, envelope, value) {
|
|
231
|
+
const scoped = { ...value };
|
|
232
|
+
const copied = typeof envelope === "string" ? envelope : Uint8Array.from(envelope);
|
|
233
|
+
const localKey = typeof key === "string" ? key : Uint8Array.from(key);
|
|
234
|
+
try {
|
|
235
|
+
await decryptCreditState(localKey, copied, scoped);
|
|
236
|
+
return await _Disclosure.fromEnvelope(localKey, copied, scoped, scoped.role);
|
|
237
|
+
} finally {
|
|
238
|
+
if (localKey instanceof Uint8Array) localKey.fill(0);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
static async fromEnvelope(key, envelope, scoped, role) {
|
|
242
|
+
const payloadKey = await exportPayloadKey(key, envelope, role !== "funds");
|
|
243
|
+
try {
|
|
244
|
+
return new _Disclosure({
|
|
245
|
+
version: 1,
|
|
246
|
+
kind: role === "funds" ? "note" : "credit",
|
|
247
|
+
method: "payload-key",
|
|
248
|
+
context: {
|
|
249
|
+
...encode(context(scoped)),
|
|
250
|
+
outputCommitment: hash(scoped.outputCommitment, "commitment")
|
|
251
|
+
},
|
|
252
|
+
data: {
|
|
253
|
+
payloadKey: `0x${bytesToHex(payloadKey)}`,
|
|
254
|
+
ownerAddress: owner(scoped.ownerAddress, "owner address"),
|
|
255
|
+
role
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
} finally {
|
|
259
|
+
payloadKey.fill(0);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
/** Parse untrusted JSON material; verification against an independent output is still required. */
|
|
263
|
+
static async fromExport(value) {
|
|
264
|
+
const root = record(value, ["version", "kind", "method", "context", "data"]);
|
|
265
|
+
if (root.version !== 1 || root.kind !== "note" && root.kind !== "credit" || root.method !== "opening" && root.method !== "payload-key")
|
|
266
|
+
throw new Error("unsupported disclosure format");
|
|
267
|
+
const rawContext = record(root.context, [
|
|
268
|
+
"chainId",
|
|
269
|
+
"protocolAddress",
|
|
270
|
+
"tokenAddress",
|
|
271
|
+
"outputCommitment"
|
|
272
|
+
]);
|
|
273
|
+
const scoped = context({
|
|
274
|
+
chainId: decimal(rawContext.chainId, 64, "chainId"),
|
|
275
|
+
protocolAddress: decimal(rawContext.protocolAddress, 160, "protocolAddress"),
|
|
276
|
+
tokenAddress: decimal(rawContext.tokenAddress, 160, "tokenAddress")
|
|
277
|
+
});
|
|
278
|
+
const outputCommitment = hash(rawContext.outputCommitment, "commitment");
|
|
279
|
+
const fields = root.method === "payload-key" ? ["payloadKey", "ownerAddress", "role"] : root.kind === "note" ? NOTE_FIELDS : CREDIT_FIELDS;
|
|
280
|
+
const raw = record(root.data, fields);
|
|
281
|
+
const data = {};
|
|
282
|
+
for (const key of fields) {
|
|
283
|
+
if (key === "role") {
|
|
284
|
+
if (root.kind === "note" ? raw[key] !== "funds" : raw[key] !== "owner" && raw[key] !== "spender")
|
|
285
|
+
throw new Error("invalid disclosure role");
|
|
286
|
+
data[key] = raw[key];
|
|
287
|
+
} else if (key === "payloadKey" || key.endsWith("Identity") || key === "ownerAddress" || key === "creditSharedKeyHash") {
|
|
288
|
+
data[key] = key.endsWith("Identity") || key === "ownerAddress" ? owner(raw[key], key) : hash(raw[key], key, key !== "payloadKey");
|
|
289
|
+
} else if (key === "unlimited") {
|
|
290
|
+
if (raw[key] !== "0" && raw[key] !== "1")
|
|
291
|
+
throw Error("invalid disclosure unlimited");
|
|
292
|
+
data[key] = raw[key];
|
|
293
|
+
} else {
|
|
294
|
+
const bits = key === "availableCredit" ? 128 : key.endsWith("Payout") ? 160 : key === "expiry" ? 64 : key === "amount" ? root.kind === "note" ? 128 : 126 : 254;
|
|
295
|
+
const parsed = decimal(raw[key], bits, key);
|
|
296
|
+
if (key === "nonce") nonce(parsed);
|
|
297
|
+
data[key] = parsed.toString();
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
const material = {
|
|
301
|
+
version: 1,
|
|
302
|
+
kind: root.kind,
|
|
303
|
+
method: root.method,
|
|
304
|
+
context: { ...encode(scoped), outputCommitment },
|
|
305
|
+
data
|
|
306
|
+
};
|
|
307
|
+
const result = new _Disclosure(material);
|
|
308
|
+
if (material.method === "opening")
|
|
309
|
+
await result.verify({
|
|
310
|
+
...scoped,
|
|
311
|
+
outputCommitment,
|
|
312
|
+
role: material.kind === "note" ? "funds" : "owner"
|
|
313
|
+
});
|
|
314
|
+
return result;
|
|
315
|
+
}
|
|
316
|
+
getScope() {
|
|
317
|
+
const { version, kind, method } = this.#material;
|
|
318
|
+
return {
|
|
319
|
+
version,
|
|
320
|
+
kind,
|
|
321
|
+
method,
|
|
322
|
+
permitsOwnerSweep: kind === "note",
|
|
323
|
+
revealsNoteConsumption: kind === "note",
|
|
324
|
+
revealsCreditSharedKey: kind === "credit" && method === "payload-key",
|
|
325
|
+
revealsReceivingKeys: kind === "credit" && method === "payload-key",
|
|
326
|
+
revealsMemo: method === "payload-key",
|
|
327
|
+
revealsPayload: method === "payload-key"
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
/** Explicitly export sensitive, JSON-compatible material for a chosen recipient. */
|
|
331
|
+
export() {
|
|
332
|
+
return {
|
|
333
|
+
...this.#material,
|
|
334
|
+
context: { ...this.#material.context },
|
|
335
|
+
data: { ...this.#material.data }
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
async verify(value) {
|
|
339
|
+
const output = {
|
|
340
|
+
...value,
|
|
341
|
+
ciphertext: value.ciphertext instanceof Uint8Array ? Uint8Array.from(value.ciphertext) : value.ciphertext
|
|
342
|
+
};
|
|
343
|
+
const scoped = context(output);
|
|
344
|
+
const material = this.#material;
|
|
345
|
+
for (const field of ["chainId", "protocolAddress", "tokenAddress"]) {
|
|
346
|
+
if (scoped[field].toString() !== material.context[field])
|
|
347
|
+
throw new Error("disclosure deployment context mismatch");
|
|
348
|
+
}
|
|
349
|
+
if (hash(output.outputCommitment, "commitment") !== material.context.outputCommitment)
|
|
350
|
+
throw new Error("disclosure output commitment mismatch");
|
|
351
|
+
if (material.kind === "note" ? output.role !== "funds" : output.role !== "owner" && output.role !== "spender")
|
|
352
|
+
throw new Error("disclosure output role mismatch");
|
|
353
|
+
const data = material.data;
|
|
354
|
+
if (material.method === "payload-key") {
|
|
355
|
+
if (output.role !== data.role || output.ciphertext === void 0)
|
|
356
|
+
throw new Error("disclosure requires the selected role envelope");
|
|
357
|
+
const decryption = {
|
|
358
|
+
...scoped,
|
|
359
|
+
outputCommitment: output.outputCommitment,
|
|
360
|
+
ownerAddress: data.ownerAddress
|
|
361
|
+
};
|
|
362
|
+
if (material.kind === "note")
|
|
363
|
+
return {
|
|
364
|
+
kind: "note",
|
|
365
|
+
note: Object.freeze(
|
|
366
|
+
await decryptNotePayload(
|
|
367
|
+
data.payloadKey,
|
|
368
|
+
output.ciphertext,
|
|
369
|
+
decryption
|
|
370
|
+
)
|
|
371
|
+
)
|
|
372
|
+
};
|
|
373
|
+
const state = await decryptCreditPayload(
|
|
374
|
+
data.payloadKey,
|
|
375
|
+
output.ciphertext,
|
|
376
|
+
{ ...decryption, role: output.role }
|
|
377
|
+
);
|
|
378
|
+
return {
|
|
379
|
+
kind: "credit",
|
|
380
|
+
note: Object.freeze({
|
|
381
|
+
...await creditOpening(state.note),
|
|
382
|
+
...state.note.payload === void 0 ? {} : { payload: structuredClone(state.note.payload) }
|
|
383
|
+
})
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
if (material.kind === "note") {
|
|
387
|
+
const note2 = {
|
|
388
|
+
...scoped,
|
|
389
|
+
ownerAddress: data.ownerAddress,
|
|
390
|
+
amount: BigInt(data.amount),
|
|
391
|
+
nonce: BigInt(data.nonce)
|
|
392
|
+
};
|
|
393
|
+
if (await commitment(note2) !== material.context.outputCommitment)
|
|
394
|
+
throw new Error("disclosure opening commitment mismatch");
|
|
395
|
+
return { kind: "note", note: Object.freeze(note2) };
|
|
396
|
+
}
|
|
397
|
+
const note = {
|
|
398
|
+
...scoped,
|
|
399
|
+
spenderWalletIdentity: data.spenderWalletIdentity,
|
|
400
|
+
ownerWalletIdentity: data.ownerWalletIdentity,
|
|
401
|
+
revocationShard: BigInt(data.revocationShard),
|
|
402
|
+
revocationSlot: BigInt(data.revocationSlot),
|
|
403
|
+
nonce: BigInt(data.nonce),
|
|
404
|
+
expiry: BigInt(data.expiry),
|
|
405
|
+
...normalizeCreditPolicy(
|
|
406
|
+
Object.fromEntries(
|
|
407
|
+
["singleLimit", "dailyLimit", "monthlyLimit"].map((k) => [k, BigInt(data[k])])
|
|
408
|
+
)
|
|
409
|
+
),
|
|
410
|
+
...normalizeCreditUsage(
|
|
411
|
+
Object.fromEntries(
|
|
412
|
+
["lastDay", "dailySpent", "lastMonth", "monthlySpent", "totalSpent"].map(
|
|
413
|
+
(k) => [k, BigInt(data[k])]
|
|
414
|
+
)
|
|
415
|
+
)
|
|
416
|
+
),
|
|
417
|
+
availableCredit: BigInt(data.availableCredit),
|
|
418
|
+
unlimited: data.unlimited === "1",
|
|
419
|
+
creditSharedKeyHash: data.creditSharedKeyHash
|
|
420
|
+
};
|
|
421
|
+
if (await commitment(note) !== material.context.outputCommitment)
|
|
422
|
+
throw new Error("disclosure opening commitment mismatch");
|
|
423
|
+
return { kind: "credit", note: Object.freeze(note) };
|
|
424
|
+
}
|
|
425
|
+
toJSON() {
|
|
426
|
+
return { capability: "disclosure", ...this.getScope() };
|
|
427
|
+
}
|
|
428
|
+
[/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")]() {
|
|
429
|
+
return this.toJSON();
|
|
430
|
+
}
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
// src/wallet/capabilities.ts
|
|
434
|
+
import { secp256k1 as secp256k12 } from "@noble/curves/secp256k1";
|
|
435
|
+
import { bytesToHex as bytesToHex3, hexToBytes as hexToBytes2 } from "@noble/hashes/utils";
|
|
436
|
+
|
|
437
|
+
// src/wallet/wallet.ts
|
|
438
|
+
import { secp256k1 } from "@noble/curves/secp256k1";
|
|
439
|
+
import { hkdf } from "@noble/hashes/hkdf";
|
|
440
|
+
import { sha256 } from "@noble/hashes/sha256";
|
|
441
|
+
import { keccak_256 } from "@noble/hashes/sha3";
|
|
442
|
+
import { bytesToHex as bytesToHex2, concatBytes, hexToBytes, utf8ToBytes } from "@noble/hashes/utils";
|
|
443
|
+
var OPERATIONS = {
|
|
444
|
+
transact: "Transact",
|
|
445
|
+
"create-credit": "CreateCredit",
|
|
446
|
+
"credit-draw": "CreditDraw",
|
|
447
|
+
"update-credit": "UpdateCredit"
|
|
448
|
+
};
|
|
449
|
+
var WALLET_AUTHORIZATION_TYPES = {
|
|
450
|
+
WalletAuthorization: [
|
|
451
|
+
{ name: "operation", type: "bytes32" },
|
|
452
|
+
{ name: "statementHash", type: "bytes32" }
|
|
453
|
+
]
|
|
454
|
+
};
|
|
455
|
+
var hex = (value) => `0x${bytesToHex2(value)}`;
|
|
456
|
+
function bytes(value, length) {
|
|
457
|
+
if (typeof value === "string" && !/^0x(?:[0-9a-fA-F]{2})*$/.test(value))
|
|
458
|
+
throw new Error("invalid hexadecimal bytes");
|
|
459
|
+
if (typeof value !== "string" && !(value instanceof Uint8Array))
|
|
460
|
+
throw new TypeError("expected bytes");
|
|
461
|
+
const result = typeof value === "string" ? hexToBytes(value.slice(2)) : Uint8Array.from(value);
|
|
462
|
+
if (length !== void 0 && result.length !== length)
|
|
463
|
+
throw new Error(`expected ${length} bytes`);
|
|
464
|
+
return result;
|
|
465
|
+
}
|
|
466
|
+
function word(value) {
|
|
467
|
+
if (value < 0n || value >= 1n << 256n) throw new RangeError("value exceeds uint256");
|
|
468
|
+
return hexToBytes(value.toString(16).padStart(64, "0"));
|
|
469
|
+
}
|
|
470
|
+
async function computeOwnerAddress(publicKey) {
|
|
471
|
+
const point = secp256k1.ProjectivePoint.fromHex(bytes(publicKey));
|
|
472
|
+
point.assertValidity();
|
|
473
|
+
return hex(keccak_256(point.toRawBytes(false).slice(1)).slice(12));
|
|
474
|
+
}
|
|
475
|
+
function walletAuthorizationTypedData(request) {
|
|
476
|
+
const { context: context2, operation, capacity, words } = request;
|
|
477
|
+
if (!Object.hasOwn(OPERATIONS, operation)) throw new Error("unsupported wallet operation");
|
|
478
|
+
const allowed = operation === "transact" ? [
|
|
479
|
+
1,
|
|
480
|
+
2,
|
|
481
|
+
3,
|
|
482
|
+
4,
|
|
483
|
+
5,
|
|
484
|
+
6,
|
|
485
|
+
7,
|
|
486
|
+
8,
|
|
487
|
+
9,
|
|
488
|
+
10,
|
|
489
|
+
20,
|
|
490
|
+
30,
|
|
491
|
+
40,
|
|
492
|
+
50,
|
|
493
|
+
60,
|
|
494
|
+
70,
|
|
495
|
+
80,
|
|
496
|
+
90,
|
|
497
|
+
100,
|
|
498
|
+
110,
|
|
499
|
+
120,
|
|
500
|
+
130,
|
|
501
|
+
140,
|
|
502
|
+
150,
|
|
503
|
+
160,
|
|
504
|
+
170,
|
|
505
|
+
180,
|
|
506
|
+
190
|
|
507
|
+
] : operation === "credit-draw" ? [1, 2, 3, 4, 5, 10, 20, 30, 40, 50, 60, 70, 80] : [1];
|
|
508
|
+
if (!allowed.includes(capacity)) throw new Error("invalid operation capacity");
|
|
509
|
+
if (!Array.isArray(words) || words.length < 2) throw new Error("public words required");
|
|
510
|
+
for (const value of words)
|
|
511
|
+
if (typeof value !== "bigint" || value < 0n || value >= FIELD_MODULUS)
|
|
512
|
+
throw new RangeError("noncanonical public field");
|
|
513
|
+
const { chainId, protocolAddress } = context2;
|
|
514
|
+
if (typeof chainId !== "bigint" || chainId < 0n || chainId >= 1n << 64n)
|
|
515
|
+
throw new RangeError("invalid chain id");
|
|
516
|
+
if (typeof protocolAddress !== "bigint" || protocolAddress <= 0n || protocolAddress >= 1n << 160n)
|
|
517
|
+
throw new RangeError("invalid protocol address");
|
|
518
|
+
if (words[0] !== chainId) throw new Error("statement chain mismatch");
|
|
519
|
+
if (words[1] !== protocolAddress) throw new Error("statement instance mismatch");
|
|
520
|
+
const statement = concatBytes(
|
|
521
|
+
word(BigInt(capacity)),
|
|
522
|
+
word(64n),
|
|
523
|
+
word(BigInt(words.length)),
|
|
524
|
+
...words.map(word)
|
|
525
|
+
);
|
|
526
|
+
return {
|
|
527
|
+
domain: {
|
|
528
|
+
name: "InvisibleProtocol",
|
|
529
|
+
version: "1",
|
|
530
|
+
chainId,
|
|
531
|
+
verifyingContract: `0x${protocolAddress.toString(16).padStart(40, "0")}`
|
|
532
|
+
},
|
|
533
|
+
types: WALLET_AUTHORIZATION_TYPES,
|
|
534
|
+
primaryType: "WalletAuthorization",
|
|
535
|
+
message: {
|
|
536
|
+
operation: hex(
|
|
537
|
+
keccak_256(
|
|
538
|
+
utf8ToBytes(
|
|
539
|
+
`Invisi.${OPERATIONS[operation]}.${operation === "transact" ? "v1" : "v4"}`
|
|
540
|
+
)
|
|
541
|
+
)
|
|
542
|
+
),
|
|
543
|
+
statementHash: hex(keccak_256(statement))
|
|
544
|
+
}
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
function computeWalletAuthorizationDigest(request) {
|
|
548
|
+
const data = walletAuthorizationTypedData(request), hashText = (text) => keccak_256(utf8ToBytes(text));
|
|
549
|
+
const domain = keccak_256(
|
|
550
|
+
concatBytes(
|
|
551
|
+
hashText(
|
|
552
|
+
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
|
|
553
|
+
),
|
|
554
|
+
hashText(data.domain.name),
|
|
555
|
+
hashText(data.domain.version),
|
|
556
|
+
word(data.domain.chainId),
|
|
557
|
+
word(BigInt(data.domain.verifyingContract))
|
|
558
|
+
)
|
|
559
|
+
);
|
|
560
|
+
const structure = keccak_256(
|
|
561
|
+
concatBytes(
|
|
562
|
+
hashText("WalletAuthorization(bytes32 operation,bytes32 statementHash)"),
|
|
563
|
+
bytes(data.message.operation),
|
|
564
|
+
bytes(data.message.statementHash)
|
|
565
|
+
)
|
|
566
|
+
);
|
|
567
|
+
return hex(keccak_256(concatBytes(new Uint8Array([25, 1]), domain, structure)));
|
|
568
|
+
}
|
|
569
|
+
function signWalletAuthorization(privateKey, request) {
|
|
570
|
+
return hex(
|
|
571
|
+
secp256k1.sign(bytes(computeWalletAuthorizationDigest(request)), bytes(privateKey, 32), {
|
|
572
|
+
lowS: true
|
|
573
|
+
}).toCompactRawBytes()
|
|
574
|
+
);
|
|
575
|
+
}
|
|
576
|
+
async function verifyWalletAuthorization(expectedIdentity, publicKey, signature, request) {
|
|
577
|
+
const raw = bytes(signature, 64), digest = bytes(computeWalletAuthorizationDigest(request));
|
|
578
|
+
if (await computeOwnerAddress(publicKey) !== expectedIdentity) return false;
|
|
579
|
+
return secp256k1.verify(raw, digest, bytes(publicKey), { lowS: true });
|
|
580
|
+
}
|
|
581
|
+
async function buildWalletAuthorizationWitness(wallet, request) {
|
|
582
|
+
const publicKey = secp256k1.ProjectivePoint.fromHex(bytes(wallet.spendingPublicKey)).toRawBytes(
|
|
583
|
+
false
|
|
584
|
+
);
|
|
585
|
+
const privateKey = bytes(wallet.spendingPrivateKey, 32), identity2 = wallet.ownerAddress;
|
|
586
|
+
const statement = { ...request, context: { ...request.context }, words: [...request.words] };
|
|
587
|
+
try {
|
|
588
|
+
const derived = secp256k1.getPublicKey(privateKey, false);
|
|
589
|
+
if (!derived.every((value, i) => value === publicKey[i]))
|
|
590
|
+
throw new Error("spending key pair mismatch");
|
|
591
|
+
if (BigInt(await computeOwnerAddress(publicKey)) !== BigInt(identity2))
|
|
592
|
+
throw new Error("owner address mismatch");
|
|
593
|
+
return {
|
|
594
|
+
public_key_x: Array.from(publicKey.slice(1, 33)),
|
|
595
|
+
public_key_y: Array.from(publicKey.slice(33)),
|
|
596
|
+
signature: Array.from(bytes(signWalletAuthorization(privateKey, statement), 64))
|
|
597
|
+
};
|
|
598
|
+
} finally {
|
|
599
|
+
privateKey.fill(0);
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
// src/wallet/capabilities.ts
|
|
604
|
+
var copyWitness = (witness) => ({
|
|
605
|
+
public_key_x: [...witness.public_key_x],
|
|
606
|
+
public_key_y: [...witness.public_key_y],
|
|
607
|
+
signature: [...witness.signature]
|
|
608
|
+
});
|
|
609
|
+
var inspect = /* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom");
|
|
610
|
+
function copyBytes(value) {
|
|
611
|
+
if (typeof value === "string" && !/^0x(?:[0-9a-fA-F]{2})+$/.test(value)) {
|
|
612
|
+
throw new Error("invalid hexadecimal bytes");
|
|
613
|
+
}
|
|
614
|
+
return typeof value === "string" ? hexToBytes2(value.slice(2)) : Uint8Array.from(value);
|
|
615
|
+
}
|
|
616
|
+
function identity(value) {
|
|
617
|
+
return ReceivingAddress.fromIdentity(value).ownerAddress;
|
|
618
|
+
}
|
|
619
|
+
var ViewingCapability = class {
|
|
620
|
+
#key;
|
|
621
|
+
ownerAddress;
|
|
622
|
+
constructor(ownerAddress, privateKey, expectedPublicKey) {
|
|
623
|
+
this.ownerAddress = identity(ownerAddress);
|
|
624
|
+
this.#key = copyBytes(privateKey);
|
|
625
|
+
const publicKey = viewingPublicKey(this.#key);
|
|
626
|
+
if (expectedPublicKey && bytesToHex3(publicKey) !== bytesToHex3(expectedPublicKey)) {
|
|
627
|
+
throw new Error("viewing key pair mismatch");
|
|
628
|
+
}
|
|
629
|
+
Object.freeze(this);
|
|
630
|
+
}
|
|
631
|
+
decryptNote(envelope, context2) {
|
|
632
|
+
return decryptPrivateTransferNote(this.#key, envelope, {
|
|
633
|
+
...context2,
|
|
634
|
+
ownerAddress: this.ownerAddress
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
decryptCredit(envelope, context2) {
|
|
638
|
+
return decryptCreditState(this.#key, envelope, {
|
|
639
|
+
...context2,
|
|
640
|
+
ownerAddress: this.ownerAddress
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
getPublicKey() {
|
|
644
|
+
return viewingPublicKey(this.#key);
|
|
645
|
+
}
|
|
646
|
+
/** Disclose this authenticated output's payload key, without exporting the wallet viewing key. */
|
|
647
|
+
discloseNote(envelope, context2) {
|
|
648
|
+
return Disclosure.fromEncryptedNote(this.#key, envelope, {
|
|
649
|
+
...context2,
|
|
650
|
+
ownerAddress: this.ownerAddress
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
/** Exposes the entire Credit envelope; prefer Disclosure.fromCredit() for hash-only opening. */
|
|
654
|
+
discloseCredit(envelope, context2) {
|
|
655
|
+
return Disclosure.fromEncryptedCredit(this.#key, envelope, {
|
|
656
|
+
...context2,
|
|
657
|
+
ownerAddress: this.ownerAddress
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
/** Explicit sensitive export for delegating viewing. It grants note recovery and owner-only sweep permission. */
|
|
661
|
+
exportKey() {
|
|
662
|
+
return Uint8Array.from(this.#key);
|
|
663
|
+
}
|
|
664
|
+
toJSON() {
|
|
665
|
+
return { capability: "viewing", ownerAddress: this.ownerAddress };
|
|
666
|
+
}
|
|
667
|
+
[inspect]() {
|
|
668
|
+
return this.toJSON();
|
|
669
|
+
}
|
|
670
|
+
};
|
|
671
|
+
var Detector = class {
|
|
672
|
+
#key;
|
|
673
|
+
#clueKey;
|
|
674
|
+
constructor(key) {
|
|
675
|
+
this.#key = Uint8Array.from(key);
|
|
676
|
+
this.#clueKey = deriveClueKey(this.#key);
|
|
677
|
+
Object.freeze(this);
|
|
678
|
+
}
|
|
679
|
+
getClueKey() {
|
|
680
|
+
return Uint8Array.from(this.#clueKey);
|
|
681
|
+
}
|
|
682
|
+
/** Full detection delegation; the receiver chooses the checked prefix length. */
|
|
683
|
+
exportKey() {
|
|
684
|
+
return Uint8Array.from(this.#key);
|
|
685
|
+
}
|
|
686
|
+
toJSON() {
|
|
687
|
+
return { capability: "detection" };
|
|
688
|
+
}
|
|
689
|
+
[inspect]() {
|
|
690
|
+
return this.toJSON();
|
|
691
|
+
}
|
|
692
|
+
};
|
|
693
|
+
var NullifierCapability = class _NullifierCapability {
|
|
694
|
+
ownerAddress;
|
|
695
|
+
constructor(ownerAddress) {
|
|
696
|
+
this.ownerAddress = identity(ownerAddress);
|
|
697
|
+
Object.freeze(this);
|
|
698
|
+
}
|
|
699
|
+
static fromIdentity(ownerAddress) {
|
|
700
|
+
return new _NullifierCapability(ownerAddress);
|
|
701
|
+
}
|
|
702
|
+
compute(chainId, protocolAddress, commitment2, nonce2) {
|
|
703
|
+
return computeNoteNullifier(chainId, protocolAddress, nonce2, commitment2);
|
|
704
|
+
}
|
|
705
|
+
toJSON() {
|
|
706
|
+
return { capability: "nullifier", ownerAddress: this.ownerAddress };
|
|
707
|
+
}
|
|
708
|
+
[inspect]() {
|
|
709
|
+
return this.toJSON();
|
|
710
|
+
}
|
|
711
|
+
};
|
|
712
|
+
var AuthorizedStatement = class {
|
|
713
|
+
#witness;
|
|
714
|
+
digest;
|
|
715
|
+
ownerAddress;
|
|
716
|
+
constructor(ownerAddress, digest, witness) {
|
|
717
|
+
this.ownerAddress = ownerAddress;
|
|
718
|
+
this.digest = digest;
|
|
719
|
+
this.#witness = copyWitness(witness);
|
|
720
|
+
Object.freeze(this);
|
|
721
|
+
}
|
|
722
|
+
withWitness(assemble) {
|
|
723
|
+
return assemble(copyWitness(this.#witness));
|
|
724
|
+
}
|
|
725
|
+
toJSON() {
|
|
726
|
+
return { ownerAddress: this.ownerAddress, digest: this.digest };
|
|
727
|
+
}
|
|
728
|
+
[inspect]() {
|
|
729
|
+
return this.toJSON();
|
|
730
|
+
}
|
|
731
|
+
};
|
|
732
|
+
var WalletAuthorization = class _WalletAuthorization {
|
|
733
|
+
#privateKey;
|
|
734
|
+
#publicKey;
|
|
735
|
+
ownerAddress;
|
|
736
|
+
constructor(ownerAddress, privateKey, publicKey) {
|
|
737
|
+
this.ownerAddress = ownerAddress;
|
|
738
|
+
this.#privateKey = privateKey;
|
|
739
|
+
this.#publicKey = publicKey;
|
|
740
|
+
Object.freeze(this);
|
|
741
|
+
}
|
|
742
|
+
static async fromMaterial(ownerAddress, privateKey) {
|
|
743
|
+
const privateBytes = copyBytes(privateKey);
|
|
744
|
+
const publicBytes = secp256k12.getPublicKey(privateBytes, false);
|
|
745
|
+
if (await computeOwnerAddress(publicBytes) !== identity(ownerAddress)) {
|
|
746
|
+
throw new Error("owner address mismatch");
|
|
747
|
+
}
|
|
748
|
+
return new _WalletAuthorization(identity(ownerAddress), privateBytes, publicBytes);
|
|
749
|
+
}
|
|
750
|
+
getPublicKey() {
|
|
751
|
+
return Uint8Array.from(this.#publicKey);
|
|
752
|
+
}
|
|
753
|
+
async authorize(request) {
|
|
754
|
+
const frozen = { ...request, context: { ...request.context }, words: [...request.words] };
|
|
755
|
+
const digest = computeWalletAuthorizationDigest(frozen);
|
|
756
|
+
const witness = await buildWalletAuthorizationWitness(
|
|
757
|
+
{
|
|
758
|
+
ownerAddress: this.ownerAddress,
|
|
759
|
+
spendingPrivateKey: this.#privateKey,
|
|
760
|
+
spendingPublicKey: this.#publicKey
|
|
761
|
+
},
|
|
762
|
+
frozen
|
|
763
|
+
);
|
|
764
|
+
return new AuthorizedStatement(this.ownerAddress, digest, witness);
|
|
765
|
+
}
|
|
766
|
+
toJSON() {
|
|
767
|
+
return { capability: "wallet-authorization", ownerAddress: this.ownerAddress };
|
|
768
|
+
}
|
|
769
|
+
[inspect]() {
|
|
770
|
+
return this.toJSON();
|
|
771
|
+
}
|
|
772
|
+
};
|
|
773
|
+
|
|
774
|
+
// src/wallet/wallet-object.ts
|
|
775
|
+
var WalletAddress = class {
|
|
776
|
+
#address;
|
|
777
|
+
constructor(address) {
|
|
778
|
+
this.#address = address;
|
|
779
|
+
}
|
|
780
|
+
get ownerAddress() {
|
|
781
|
+
return this.#address.ownerAddress;
|
|
782
|
+
}
|
|
783
|
+
get viewingPublicKey() {
|
|
784
|
+
return this.#address.viewingPublicKey;
|
|
785
|
+
}
|
|
786
|
+
get clueKey() {
|
|
787
|
+
return this.#address.clueKey;
|
|
788
|
+
}
|
|
789
|
+
/** Complete 0i receiving address. Owner-only wallets must first resolve their receiving keys. */
|
|
790
|
+
getAddress() {
|
|
791
|
+
if (this.#address.kind !== "long") {
|
|
792
|
+
throw new MissingCapabilityError("resolved receiving keys");
|
|
793
|
+
}
|
|
794
|
+
return this.#address.toString();
|
|
795
|
+
}
|
|
796
|
+
getReceivingAddress() {
|
|
797
|
+
return this.#address;
|
|
798
|
+
}
|
|
799
|
+
/** Nullifiers derive from public identity and do not grant spending authority. */
|
|
800
|
+
exportNullifier() {
|
|
801
|
+
return NullifierCapability.fromIdentity(this.ownerAddress);
|
|
802
|
+
}
|
|
803
|
+
toJSON() {
|
|
804
|
+
return { ownerAddress: this.ownerAddress, address: this.#address.toString() };
|
|
805
|
+
}
|
|
806
|
+
[/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")]() {
|
|
807
|
+
return this.toJSON();
|
|
808
|
+
}
|
|
809
|
+
};
|
|
810
|
+
var Wallet = class _Wallet extends WalletAddress {
|
|
811
|
+
constructor(address) {
|
|
812
|
+
super(address);
|
|
813
|
+
Object.freeze(this);
|
|
814
|
+
}
|
|
815
|
+
/** Parse a complete 0i address or an EVM owner address without network access. */
|
|
816
|
+
static fromAddress(address) {
|
|
817
|
+
if (typeof address !== "string" && !(address instanceof ReceivingAddress)) {
|
|
818
|
+
throw new TypeError("expected a validated receiving address");
|
|
819
|
+
}
|
|
820
|
+
return new _Wallet(typeof address === "string" ? ReceivingAddress.parse(address) : address);
|
|
821
|
+
}
|
|
822
|
+
};
|
|
823
|
+
|
|
824
|
+
// src/delivery/memo.ts
|
|
825
|
+
var MAX_MEMO_BYTES = 256;
|
|
826
|
+
function encodeMemo(memo) {
|
|
827
|
+
if (memo === void 0) return new Uint8Array();
|
|
828
|
+
let encoded;
|
|
829
|
+
if (typeof memo === "string") {
|
|
830
|
+
for (let i = 0; i < memo.length; i++) {
|
|
831
|
+
const unit = memo.charCodeAt(i);
|
|
832
|
+
if (unit >= 55296 && unit <= 56319) {
|
|
833
|
+
const next = memo.charCodeAt(++i);
|
|
834
|
+
if (!(next >= 56320 && next <= 57343))
|
|
835
|
+
throw new Error("memo contains an invalid surrogate");
|
|
836
|
+
} else if (unit >= 56320 && unit <= 57343)
|
|
837
|
+
throw new Error("memo contains an invalid surrogate");
|
|
838
|
+
}
|
|
839
|
+
encoded = new TextEncoder().encode(memo);
|
|
840
|
+
} else if (memo instanceof Uint8Array) encoded = Uint8Array.from(memo);
|
|
841
|
+
else throw new TypeError("memo must be text or Uint8Array");
|
|
842
|
+
if (encoded.length > MAX_MEMO_BYTES) throw new RangeError("memo exceeds 256 bytes");
|
|
843
|
+
return encoded;
|
|
844
|
+
}
|
|
845
|
+
function decodeMemoText(memo) {
|
|
846
|
+
return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(memo);
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
// src/wallet/signing-request.ts
|
|
850
|
+
import { TypedDataEncoder } from "ethers";
|
|
851
|
+
function createSigningRequest(data) {
|
|
852
|
+
const types = Object.fromEntries(
|
|
853
|
+
Object.entries(data.types).map(([name, fields]) => [name, [...fields]])
|
|
854
|
+
);
|
|
855
|
+
const payload = TypedDataEncoder.getPayload(data.domain, types, data.message);
|
|
856
|
+
if (payload.primaryType !== data.primaryType) {
|
|
857
|
+
throw new Error("signing request primary type mismatch");
|
|
858
|
+
}
|
|
859
|
+
delete payload.types.EIP712Domain;
|
|
860
|
+
return structuredClone(payload);
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
// src/delivery/payload.ts
|
|
864
|
+
function encodeData(data) {
|
|
865
|
+
if (!data || typeof data !== "object" || Array.isArray(data)) {
|
|
866
|
+
throw new TypeError("v1 payload data must be an object");
|
|
867
|
+
}
|
|
868
|
+
for (const key of Object.keys(data)) {
|
|
869
|
+
if (key !== "memo") throw new Error(`unsupported v1 payload field ${key}`);
|
|
870
|
+
}
|
|
871
|
+
const memo = encodeMemo(data.memo);
|
|
872
|
+
return new Uint8Array([1, ...memo]);
|
|
873
|
+
}
|
|
874
|
+
function readData(value) {
|
|
875
|
+
if (!(value instanceof Uint8Array) || value.length < 1) {
|
|
876
|
+
throw new Error("payload version required");
|
|
877
|
+
}
|
|
878
|
+
if (value[0] !== 1) throw new Error("unsupported payload version");
|
|
879
|
+
const memo = Uint8Array.from(value.subarray(1));
|
|
880
|
+
if (memo.length > 256) throw new Error("invalid memo length");
|
|
881
|
+
return memo.length === 0 ? {} : { memo };
|
|
882
|
+
}
|
|
883
|
+
var fundsV1 = Object.freeze({
|
|
884
|
+
encode(data = {}) {
|
|
885
|
+
return encodeData(data);
|
|
886
|
+
},
|
|
887
|
+
decode(value) {
|
|
888
|
+
return readData(value);
|
|
889
|
+
}
|
|
890
|
+
});
|
|
891
|
+
var creditV1 = Object.freeze({
|
|
892
|
+
encode(data = {}) {
|
|
893
|
+
return encodeData(data);
|
|
894
|
+
},
|
|
895
|
+
decode(value) {
|
|
896
|
+
return readData(value);
|
|
897
|
+
}
|
|
898
|
+
});
|
|
899
|
+
|
|
900
|
+
// src/delivery/decryptor.ts
|
|
901
|
+
import { bytesToHex as bytesToHex4 } from "@noble/hashes/utils";
|
|
902
|
+
var DeliveryDecryptionError = class extends Error {
|
|
903
|
+
constructor(cause) {
|
|
904
|
+
super(cause instanceof Error ? cause.message : "delivery decryption failed", { cause });
|
|
905
|
+
this.name = "DeliveryDecryptionError";
|
|
906
|
+
}
|
|
907
|
+
};
|
|
908
|
+
function checkedPlaintext(plaintext, codec) {
|
|
909
|
+
if (!(plaintext instanceof Uint8Array)) throw new Error("invalid decrypted plaintext");
|
|
910
|
+
if (plaintext.length + 78 < codec.minimum || plaintext.length + 78 > codec.maximum)
|
|
911
|
+
throw new Error("invalid plaintext length");
|
|
912
|
+
return plaintext.slice();
|
|
913
|
+
}
|
|
914
|
+
function authenticatedDecryptor(wallet, decryptor) {
|
|
915
|
+
const ownerAddress = wallet.ownerAddress;
|
|
916
|
+
return {
|
|
917
|
+
ownerAddress,
|
|
918
|
+
async decryptNote(envelope, context2) {
|
|
919
|
+
context2 = { ...context2 };
|
|
920
|
+
try {
|
|
921
|
+
const bytes2 = validateDeliveryCiphertext(envelope, "funds");
|
|
922
|
+
const full = { ...context2, ownerAddress };
|
|
923
|
+
const plaintext = await decryptor.decryptNote(bytes2.slice(), { ...full });
|
|
924
|
+
if (plaintext === null) return null;
|
|
925
|
+
const codec = deliveryCodec(bytes2[0]);
|
|
926
|
+
if (codec.kind !== "funds") throw new Error("unexpected envelope kind");
|
|
927
|
+
const note = codec.decode(checkedPlaintext(plaintext, codec), full);
|
|
928
|
+
if (BigInt(note.ownerAddress) !== BigInt(ownerAddress) || note.tokenAddress !== context2.tokenAddress)
|
|
929
|
+
throw new Error("decrypted note context mismatch");
|
|
930
|
+
await noteCommitment(full, note);
|
|
931
|
+
return note;
|
|
932
|
+
} catch (cause) {
|
|
933
|
+
throw new DeliveryDecryptionError(cause);
|
|
934
|
+
}
|
|
935
|
+
},
|
|
936
|
+
async decryptCredit(envelope, context2) {
|
|
937
|
+
context2 = { ...context2 };
|
|
938
|
+
try {
|
|
939
|
+
const bytes2 = validateDeliveryCiphertext(envelope, "credit");
|
|
940
|
+
const full = { ...context2, ownerAddress };
|
|
941
|
+
const plaintext = await decryptor.decryptCredit(bytes2.slice(), { ...full });
|
|
942
|
+
if (plaintext === null) return null;
|
|
943
|
+
const codec = deliveryCodec(bytes2[0]);
|
|
944
|
+
if (codec.kind !== "credit") throw new Error("unexpected envelope kind");
|
|
945
|
+
const state = codec.decode(checkedPlaintext(plaintext, codec), full);
|
|
946
|
+
const identity2 = context2.role === "owner" ? state.note.ownerWalletIdentity : state.note.spenderWalletIdentity;
|
|
947
|
+
if (BigInt(identity2) !== BigInt(ownerAddress) || state.note.tokenAddress !== context2.tokenAddress)
|
|
948
|
+
throw new Error("decrypted credit context mismatch");
|
|
949
|
+
if (wallet.getReceivingAddress().kind === "long") {
|
|
950
|
+
const keys = context2.role === "owner" ? state.ownerReceivingKeys : state.spenderReceivingKeys;
|
|
951
|
+
if (bytesToHex4(keys.viewingPublicKey) !== bytesToHex4(wallet.viewingPublicKey))
|
|
952
|
+
throw new Error("decrypted credit receiving key mismatch");
|
|
953
|
+
}
|
|
954
|
+
await creditCommitment(full, state.note);
|
|
955
|
+
return state;
|
|
956
|
+
} catch (cause) {
|
|
957
|
+
throw new DeliveryDecryptionError(cause);
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
};
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
// src/wallet/wallet-wire.ts
|
|
964
|
+
import { bytesToHex as bytesToHex5, hexToBytes as hexToBytes3 } from "@noble/hashes/utils";
|
|
965
|
+
var walletHex = (bytes2) => `0x${bytesToHex5(bytes2)}`;
|
|
966
|
+
function walletBytes(value, length) {
|
|
967
|
+
if (typeof value !== "string" || !/^0x(?:[0-9a-f]{2})*$/.test(value))
|
|
968
|
+
throw new Error("invalid canonical hex bytes");
|
|
969
|
+
const bytes2 = hexToBytes3(value.slice(2));
|
|
970
|
+
if (length !== void 0 && bytes2.length !== length) throw new Error("invalid byte length");
|
|
971
|
+
return bytes2;
|
|
972
|
+
}
|
|
973
|
+
function walletInteger(value) {
|
|
974
|
+
if (typeof value !== "string" || !/^(0|[1-9][0-9]*)$/.test(value) || value.length > 78)
|
|
975
|
+
throw new Error("invalid canonical integer");
|
|
976
|
+
return BigInt(value);
|
|
977
|
+
}
|
|
978
|
+
function walletAuthorizationParams(params) {
|
|
979
|
+
return {
|
|
980
|
+
...params,
|
|
981
|
+
words: params.words.map(walletInteger),
|
|
982
|
+
context: {
|
|
983
|
+
chainId: walletInteger(params.context.chainId),
|
|
984
|
+
protocolAddress: walletInteger(params.context.protocolAddress)
|
|
985
|
+
}
|
|
986
|
+
};
|
|
987
|
+
}
|
|
988
|
+
function walletDecryptionContext(request) {
|
|
989
|
+
const context2 = request.params.context;
|
|
990
|
+
return {
|
|
991
|
+
chainId: walletInteger(context2.chainId),
|
|
992
|
+
protocolAddress: walletInteger(context2.protocolAddress),
|
|
993
|
+
tokenAddress: walletInteger(context2.tokenAddress),
|
|
994
|
+
outputCommitment: context2.outputCommitment,
|
|
995
|
+
ownerAddress: request.ownerAddress,
|
|
996
|
+
...context2.role ? { role: context2.role } : {}
|
|
997
|
+
};
|
|
998
|
+
}
|
|
999
|
+
function freeze(value) {
|
|
1000
|
+
if (value && typeof value === "object") {
|
|
1001
|
+
Object.values(value).forEach(freeze);
|
|
1002
|
+
Object.freeze(value);
|
|
1003
|
+
}
|
|
1004
|
+
return value;
|
|
1005
|
+
}
|
|
1006
|
+
function exactKeys(value, keys) {
|
|
1007
|
+
if (!value || typeof value !== "object" || Array.isArray(value) || Object.keys(value).some((key) => !keys.includes(key)) || keys.some((key) => !Object.hasOwn(value, key)))
|
|
1008
|
+
throw new Error("unexpected wallet fields");
|
|
1009
|
+
}
|
|
1010
|
+
function validateWalletRequest(request) {
|
|
1011
|
+
exactKeys(request, ["version", "id", "ownerAddress", "method", "params"]);
|
|
1012
|
+
if (request.version !== 1 || typeof request.id !== "string" || !/^[\x21-\x7e]{1,128}$/.test(request.id))
|
|
1013
|
+
throw new Error("invalid wallet request envelope");
|
|
1014
|
+
walletBytes(request.ownerAddress, 20);
|
|
1015
|
+
ReceivingAddress.fromIdentity(request.ownerAddress);
|
|
1016
|
+
switch (request.method) {
|
|
1017
|
+
case "wallet.public":
|
|
1018
|
+
exactKeys(request.params, []);
|
|
1019
|
+
break;
|
|
1020
|
+
case "wallet.detect": {
|
|
1021
|
+
exactKeys(request.params, ["clues"]);
|
|
1022
|
+
const { clues } = request.params;
|
|
1023
|
+
if (!Array.isArray(clues) || clues.length > 1024) throw new Error("invalid clues");
|
|
1024
|
+
clues.forEach((clue) => walletBytes(clue, 68));
|
|
1025
|
+
break;
|
|
1026
|
+
}
|
|
1027
|
+
case "wallet.authorize": {
|
|
1028
|
+
exactKeys(request.params, ["operation", "capacity", "words", "context"]);
|
|
1029
|
+
const params = request.params;
|
|
1030
|
+
exactKeys(params.context, ["chainId", "protocolAddress"]);
|
|
1031
|
+
if (!Array.isArray(params.words) || params.words.length > 8192)
|
|
1032
|
+
throw new Error("invalid authorization words");
|
|
1033
|
+
computeWalletAuthorizationDigest(walletAuthorizationParams(params));
|
|
1034
|
+
break;
|
|
1035
|
+
}
|
|
1036
|
+
case "wallet.decryptNote":
|
|
1037
|
+
case "wallet.decryptCredit": {
|
|
1038
|
+
const typed = request;
|
|
1039
|
+
exactKeys(typed.params, ["envelope", "context"]);
|
|
1040
|
+
exactKeys(typed.params.context, [
|
|
1041
|
+
"chainId",
|
|
1042
|
+
"protocolAddress",
|
|
1043
|
+
"tokenAddress",
|
|
1044
|
+
"outputCommitment",
|
|
1045
|
+
...request.method === "wallet.decryptCredit" ? ["role"] : []
|
|
1046
|
+
]);
|
|
1047
|
+
const context2 = walletDecryptionContext(typed);
|
|
1048
|
+
walletBytes(context2.outputCommitment, 32);
|
|
1049
|
+
validateContext(context2, context2.tokenAddress);
|
|
1050
|
+
if (request.method === "wallet.decryptCredit" && context2.role !== "owner" && context2.role !== "spender")
|
|
1051
|
+
throw new Error("invalid credit role");
|
|
1052
|
+
if (request.method === "wallet.decryptNote" && context2.role !== void 0)
|
|
1053
|
+
throw new Error("unexpected note role");
|
|
1054
|
+
walletBytes(typed.params.envelope);
|
|
1055
|
+
validateDeliveryCiphertext(
|
|
1056
|
+
typed.params.envelope,
|
|
1057
|
+
request.method === "wallet.decryptCredit" ? "credit" : "funds"
|
|
1058
|
+
);
|
|
1059
|
+
break;
|
|
1060
|
+
}
|
|
1061
|
+
default:
|
|
1062
|
+
throw new Error("unsupported wallet method");
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
var retainedWallets = /* @__PURE__ */ new WeakMap();
|
|
1066
|
+
function prepareWalletRequest(wallet, id, method, params) {
|
|
1067
|
+
if (!(wallet instanceof Wallet)) throw new TypeError("public Wallet required");
|
|
1068
|
+
const request = structuredClone({
|
|
1069
|
+
version: 1,
|
|
1070
|
+
id,
|
|
1071
|
+
ownerAddress: wallet.ownerAddress.toLowerCase(),
|
|
1072
|
+
method,
|
|
1073
|
+
params
|
|
1074
|
+
});
|
|
1075
|
+
validateWalletRequest(request);
|
|
1076
|
+
const prepared = freeze({ request });
|
|
1077
|
+
retainedWallets.set(prepared, wallet);
|
|
1078
|
+
return prepared;
|
|
1079
|
+
}
|
|
1080
|
+
async function acceptWalletResponse(prepared, response) {
|
|
1081
|
+
return acceptResponse(prepared, response);
|
|
1082
|
+
}
|
|
1083
|
+
async function acceptResponse(prepared, response) {
|
|
1084
|
+
const wallet = retainedWallets.get(prepared);
|
|
1085
|
+
if (!wallet) throw new Error("wallet request was not prepared by this SDK instance");
|
|
1086
|
+
const request = prepared.request;
|
|
1087
|
+
validateWalletRequest(request);
|
|
1088
|
+
const safe = structuredClone(response);
|
|
1089
|
+
if (safe.version !== request.version || safe.id !== request.id || safe.ownerAddress !== request.ownerAddress || safe.method !== request.method)
|
|
1090
|
+
throw new Error("wallet response envelope mismatch");
|
|
1091
|
+
validateWalletResponses([request], [safe]);
|
|
1092
|
+
if ("error" in safe) throw new NativeWalletError(safe.error.code);
|
|
1093
|
+
const result = safe.result;
|
|
1094
|
+
exactKeys(
|
|
1095
|
+
result,
|
|
1096
|
+
request.method === "wallet.public" ? ["viewingPublicKey", "spendingPublicKey", "clueKey"] : request.method === "wallet.authorize" ? ["spendingPublicKey", "signature", "digest"] : request.method === "wallet.detect" ? ["matches"] : ["plaintext"]
|
|
1097
|
+
);
|
|
1098
|
+
if (request.method === "wallet.public") {
|
|
1099
|
+
walletBytes(result.spendingPublicKey, 65);
|
|
1100
|
+
walletBytes(result.viewingPublicKey, 33);
|
|
1101
|
+
walletBytes(result.clueKey, 32);
|
|
1102
|
+
if (await computeOwnerAddress(result.spendingPublicKey) !== request.ownerAddress)
|
|
1103
|
+
throw new Error("wallet public identity mismatch");
|
|
1104
|
+
if (wallet.getReceivingAddress().kind === "long" && (walletHex(wallet.viewingPublicKey) !== result.viewingPublicKey || walletHex(wallet.clueKey) !== result.clueKey))
|
|
1105
|
+
throw new Error("wallet receiving key mismatch");
|
|
1106
|
+
ReceivingAddress.from({
|
|
1107
|
+
ownerAddress: request.ownerAddress,
|
|
1108
|
+
viewingPublicKey: walletBytes(result.viewingPublicKey),
|
|
1109
|
+
clueKey: walletBytes(result.clueKey)
|
|
1110
|
+
});
|
|
1111
|
+
} else if (request.method === "wallet.authorize") {
|
|
1112
|
+
const auth = walletAuthorizationParams(request.params);
|
|
1113
|
+
if (result.digest !== computeWalletAuthorizationDigest(auth) || !await verifyWalletAuthorization(
|
|
1114
|
+
request.ownerAddress,
|
|
1115
|
+
result.spendingPublicKey,
|
|
1116
|
+
result.signature,
|
|
1117
|
+
auth
|
|
1118
|
+
))
|
|
1119
|
+
throw new Error("invalid wallet authorization response");
|
|
1120
|
+
const publicKey = walletBytes(result.spendingPublicKey, 65);
|
|
1121
|
+
return new AuthorizedStatement(request.ownerAddress, result.digest, {
|
|
1122
|
+
public_key_x: Array.from(publicKey.slice(1, 33)),
|
|
1123
|
+
public_key_y: Array.from(publicKey.slice(33)),
|
|
1124
|
+
signature: Array.from(walletBytes(result.signature, 64))
|
|
1125
|
+
});
|
|
1126
|
+
} else if (request.method === "wallet.detect") {
|
|
1127
|
+
if (!Array.isArray(result.matches) || result.matches.length !== request.params.clues.length || result.matches.some((v) => typeof v !== "boolean"))
|
|
1128
|
+
throw new Error("invalid detection response");
|
|
1129
|
+
} else {
|
|
1130
|
+
const typed = request;
|
|
1131
|
+
const context2 = walletDecryptionContext(typed);
|
|
1132
|
+
const plaintext = walletBytes(result.plaintext);
|
|
1133
|
+
const viewing = authenticatedDecryptor(wallet, {
|
|
1134
|
+
decryptNote: async () => plaintext,
|
|
1135
|
+
decryptCredit: async () => plaintext
|
|
1136
|
+
});
|
|
1137
|
+
return typed.method === "wallet.decryptNote" ? viewing.decryptNote(typed.params.envelope, context2) : viewing.decryptCredit(typed.params.envelope, context2);
|
|
1138
|
+
}
|
|
1139
|
+
return result;
|
|
1140
|
+
}
|
|
1141
|
+
var NativeWalletError = class extends Error {
|
|
1142
|
+
constructor(code) {
|
|
1143
|
+
super(code);
|
|
1144
|
+
this.code = code;
|
|
1145
|
+
this.name = "NativeWalletError";
|
|
1146
|
+
}
|
|
1147
|
+
};
|
|
1148
|
+
var MAX_WALLET_BATCH_BYTES = 16 * 1024 * 1024;
|
|
1149
|
+
function boundedJson(value) {
|
|
1150
|
+
const json = JSON.stringify(value);
|
|
1151
|
+
if (typeof json !== "string" || new TextEncoder().encode(json).length > MAX_WALLET_BATCH_BYTES)
|
|
1152
|
+
throw new Error("wallet batch exceeds encoded size limit");
|
|
1153
|
+
}
|
|
1154
|
+
function validateWalletBatch(requests) {
|
|
1155
|
+
if (!Array.isArray(requests) || requests.length > 1024) throw new Error("invalid wallet batch");
|
|
1156
|
+
boundedJson(requests);
|
|
1157
|
+
const ids = /* @__PURE__ */ new Set();
|
|
1158
|
+
for (const request of requests) {
|
|
1159
|
+
validateWalletRequest(request);
|
|
1160
|
+
if (ids.has(request.id)) throw new Error("duplicate wallet request id");
|
|
1161
|
+
if (request.ownerAddress !== requests[0].ownerAddress)
|
|
1162
|
+
throw new Error("mixed wallet batch owners");
|
|
1163
|
+
ids.add(request.id);
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
function validateWalletResponses(requests, responses) {
|
|
1167
|
+
validateWalletBatch(requests);
|
|
1168
|
+
if (!Array.isArray(responses) || responses.length !== requests.length)
|
|
1169
|
+
throw new Error("wallet response batch length mismatch");
|
|
1170
|
+
boundedJson(responses);
|
|
1171
|
+
const expected = new Map(requests.map((request) => [request.id, request]));
|
|
1172
|
+
const found = /* @__PURE__ */ new Map();
|
|
1173
|
+
for (const response of responses) {
|
|
1174
|
+
if (!response || typeof response !== "object") throw new Error("invalid wallet response");
|
|
1175
|
+
const request = expected.get(response.id);
|
|
1176
|
+
if (!request || found.has(response.id) || response.version !== 1 || response.method !== request.method || response.ownerAddress !== request.ownerAddress)
|
|
1177
|
+
throw new Error("wallet response envelope mismatch");
|
|
1178
|
+
if (Object.hasOwn(response, "error")) {
|
|
1179
|
+
exactKeys(response, ["version", "id", "ownerAddress", "method", "error"]);
|
|
1180
|
+
exactKeys(response.error, ["code"]);
|
|
1181
|
+
if (typeof response.error?.code !== "string" || !/^[A-Z][A-Z0-9_]{0,127}$/.test(response.error.code))
|
|
1182
|
+
throw new Error("invalid native wallet error");
|
|
1183
|
+
} else {
|
|
1184
|
+
exactKeys(response, ["version", "id", "ownerAddress", "method", "result"]);
|
|
1185
|
+
if (!response.result || typeof response.result !== "object" || Array.isArray(response.result))
|
|
1186
|
+
throw new Error("invalid wallet result");
|
|
1187
|
+
const result = response.result;
|
|
1188
|
+
exactKeys(
|
|
1189
|
+
result,
|
|
1190
|
+
request.method === "wallet.public" ? ["viewingPublicKey", "spendingPublicKey", "clueKey"] : request.method === "wallet.authorize" ? ["spendingPublicKey", "signature", "digest"] : request.method === "wallet.detect" ? ["matches"] : ["plaintext"]
|
|
1191
|
+
);
|
|
1192
|
+
if (request.method === "wallet.public") {
|
|
1193
|
+
walletBytes(result.viewingPublicKey, 33);
|
|
1194
|
+
walletBytes(result.spendingPublicKey, 65);
|
|
1195
|
+
walletBytes(result.clueKey, 32);
|
|
1196
|
+
} else if (request.method === "wallet.authorize") {
|
|
1197
|
+
walletBytes(result.spendingPublicKey, 65);
|
|
1198
|
+
walletBytes(result.signature, 64);
|
|
1199
|
+
walletBytes(result.digest, 32);
|
|
1200
|
+
} else if (request.method === "wallet.detect") {
|
|
1201
|
+
if (!Array.isArray(result.matches) || result.matches.length !== request.params.clues.length || result.matches.some((value) => typeof value !== "boolean"))
|
|
1202
|
+
throw new Error("invalid detection response");
|
|
1203
|
+
} else {
|
|
1204
|
+
walletBytes(result.plaintext);
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
found.set(response.id, response);
|
|
1208
|
+
}
|
|
1209
|
+
return requests.map((request) => found.get(request.id));
|
|
1210
|
+
}
|
|
1211
|
+
async function acceptWalletResponses(prepared, responses) {
|
|
1212
|
+
for (const item of prepared) {
|
|
1213
|
+
if (!retainedWallets.has(item))
|
|
1214
|
+
throw new Error("wallet request was not prepared by this SDK instance");
|
|
1215
|
+
}
|
|
1216
|
+
const ordered = validateWalletResponses(
|
|
1217
|
+
prepared.map((item) => item.request),
|
|
1218
|
+
structuredClone(responses)
|
|
1219
|
+
);
|
|
1220
|
+
return Promise.all(prepared.map((item, index) => acceptWalletResponse(item, ordered[index])));
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
// src/provenance/intent-hash.ts
|
|
1224
|
+
import { AbiCoder, keccak256, toBeHex } from "ethers";
|
|
1225
|
+
function provenanceIntentHash(originalRequestHash) {
|
|
1226
|
+
return keccak256(
|
|
1227
|
+
AbiCoder.defaultAbiCoder().encode(
|
|
1228
|
+
["string", "bytes32"],
|
|
1229
|
+
["InvisiBroadcasterProvenanceIntentV1", toBeHex(BigInt(originalRequestHash), 32)]
|
|
1230
|
+
)
|
|
1231
|
+
);
|
|
1232
|
+
}
|
|
1233
|
+
export {
|
|
1234
|
+
AuthorizedStatement,
|
|
1235
|
+
CREDIT_POLICY_FIELDS,
|
|
1236
|
+
CREDIT_USAGE_FIELDS,
|
|
1237
|
+
D_CNULL,
|
|
1238
|
+
D_CREDIT,
|
|
1239
|
+
D_CREDIT_KEY_HASH,
|
|
1240
|
+
D_CREDIT_RECOVERY,
|
|
1241
|
+
D_CREDIT_STATE_NONCE,
|
|
1242
|
+
D_IDENT,
|
|
1243
|
+
D_NOTE,
|
|
1244
|
+
D_NULL,
|
|
1245
|
+
DeliveryDecryptionError,
|
|
1246
|
+
Detector,
|
|
1247
|
+
Disclosure,
|
|
1248
|
+
FIELD_MODULUS,
|
|
1249
|
+
MAX_CIPHERTEXT_BYTES,
|
|
1250
|
+
MAX_MEMO_BYTES,
|
|
1251
|
+
MAX_WALLET_BATCH_BYTES,
|
|
1252
|
+
MissingCapabilityError,
|
|
1253
|
+
NativeWalletError,
|
|
1254
|
+
NullifierCapability,
|
|
1255
|
+
ReceivingAddress,
|
|
1256
|
+
TREE_DEPTH,
|
|
1257
|
+
ViewingCapability,
|
|
1258
|
+
WALLET_AUTHORIZATION_TYPES,
|
|
1259
|
+
Wallet,
|
|
1260
|
+
acceptWalletResponse,
|
|
1261
|
+
acceptWalletResponses,
|
|
1262
|
+
applyCreditDrawUsage,
|
|
1263
|
+
authenticatedDecryptor,
|
|
1264
|
+
computeCreditCommitment,
|
|
1265
|
+
computeCreditNullifier,
|
|
1266
|
+
computeCreditRecoveryPad,
|
|
1267
|
+
computeCreditSharedKeyHash,
|
|
1268
|
+
computeNoteCommitment,
|
|
1269
|
+
computeNoteIdentity,
|
|
1270
|
+
computeNoteNullifier,
|
|
1271
|
+
computeOwnerAddress,
|
|
1272
|
+
computeWalletAuthorizationDigest,
|
|
1273
|
+
createClue,
|
|
1274
|
+
createClueFromSeed,
|
|
1275
|
+
createSigningRequest,
|
|
1276
|
+
creditPeriods,
|
|
1277
|
+
creditV1,
|
|
1278
|
+
decodeAddress,
|
|
1279
|
+
decodeDeliveryHeader,
|
|
1280
|
+
decodeMemoText,
|
|
1281
|
+
decryptCreditState,
|
|
1282
|
+
decryptPrivateTransferNote,
|
|
1283
|
+
deliveryCodec,
|
|
1284
|
+
deliveryHeader,
|
|
1285
|
+
deriveClueKey,
|
|
1286
|
+
deriveCreditState,
|
|
1287
|
+
deriveCreditStateNonce,
|
|
1288
|
+
deriveCreditUpdate,
|
|
1289
|
+
encodeMemo,
|
|
1290
|
+
encryptCreditState,
|
|
1291
|
+
encryptPrivateTransferNote,
|
|
1292
|
+
fundsV1,
|
|
1293
|
+
generateCreditSharedKey,
|
|
1294
|
+
generateNonce,
|
|
1295
|
+
normalizeCreditDeliveryState,
|
|
1296
|
+
normalizeCreditPolicy,
|
|
1297
|
+
normalizeCreditState,
|
|
1298
|
+
normalizeCreditUsage,
|
|
1299
|
+
poseidonHash,
|
|
1300
|
+
prepareWalletRequest,
|
|
1301
|
+
provenanceIntentHash,
|
|
1302
|
+
recoverCreditState,
|
|
1303
|
+
validateClueKey,
|
|
1304
|
+
validateDeliveryCiphertext,
|
|
1305
|
+
validateWalletBatch,
|
|
1306
|
+
validateWalletResponses,
|
|
1307
|
+
verifyWalletAuthorization,
|
|
1308
|
+
viewingPublicKey,
|
|
1309
|
+
walletAuthorizationTypedData
|
|
1310
|
+
};
|
|
1311
|
+
//# sourceMappingURL=index.js.map
|