@opaquecash/stellar 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,3 @@
1
+ export { E as EncryptedPayload, J as JobAdvert, b as PoolWithdrawPayload, r as RELAY_CHAIN_STELLAR, s as RELAY_PAYLOAD_DOMAIN, c as RelayerBid, u as RelayerGateway, a as RelayerJobDraft, d as RelayerJobStatus, v as RelayerMessage, y as SerializablePoolWithdrawPayload, V as VerifiedBid, X as X25519Keypair, K as bidSigningDigest, M as buildRelayedWithdrawPayload, Q as buildRelayerJobDraft, Z as decodePoolWithdrawPayload, _ as encodePoolWithdrawPayload, a0 as generateX25519Keypair, a1 as hashPoolWithdrawPayload, a2 as hashPoolWithdrawPayloadHex, a4 as makeAdvert, a5 as makeBid, a7 as openBox, a8 as parsePoolWithdrawPayload, a9 as pickStakeWeightedBid, aa as poolWithdrawPayloadPreimage, ac as randomJobId, ae as sealBox, ag as serializePoolWithdrawPayload, aj as validateAdvert, ak as validateBid, al as verifyBid } from '../index-Dqr8RiOd.js';
2
+ import '@stellar/stellar-sdk';
3
+ import '../notes-CTR_oi8Y.js';
@@ -0,0 +1,431 @@
1
+ import { Keypair, Address, xdr } from '@stellar/stellar-sdk';
2
+ import { keccak_256 } from '@noble/hashes/sha3';
3
+
4
+ // src/relayer-protocol/payload.ts
5
+
6
+ // src/relayer-protocol/bytes.ts
7
+ function hexToBytes(hex) {
8
+ const clean = hex.replace(/^0x/, "");
9
+ if (!/^[0-9a-f]*$/i.test(clean) || clean.length % 2 !== 0) {
10
+ throw new Error("Invalid hex string.");
11
+ }
12
+ const out = new Uint8Array(clean.length / 2);
13
+ for (let i = 0; i < out.length; i += 1) {
14
+ out[i] = Number.parseInt(clean.slice(i * 2, i * 2 + 2), 16);
15
+ }
16
+ return out;
17
+ }
18
+ function bytesToHex(bytes) {
19
+ return `0x${Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("")}`;
20
+ }
21
+ function base64ToBytes(value) {
22
+ if (typeof atob === "function") {
23
+ const bin = atob(value);
24
+ return Uint8Array.from(bin, (c) => c.charCodeAt(0));
25
+ }
26
+ const buffer = globalThis.Buffer;
27
+ if (!buffer) throw new Error("No base64 decoder available.");
28
+ return Uint8Array.from(buffer.from(value, "base64"));
29
+ }
30
+ function bytesToBase64(bytes) {
31
+ if (typeof btoa === "function") {
32
+ let bin = "";
33
+ for (const b of bytes) bin += String.fromCharCode(b);
34
+ return btoa(bin);
35
+ }
36
+ const buffer = globalThis.Buffer;
37
+ if (!buffer) throw new Error("No base64 encoder available.");
38
+ return buffer.from(bytes).toString("base64");
39
+ }
40
+ function concatBytes(...chunks) {
41
+ const len = chunks.reduce((n, c) => n + c.length, 0);
42
+ const out = new Uint8Array(len);
43
+ let offset = 0;
44
+ for (const chunk of chunks) {
45
+ out.set(chunk, offset);
46
+ offset += chunk.length;
47
+ }
48
+ return out;
49
+ }
50
+ function assertLength(bytes, len, label) {
51
+ if (bytes.length !== len) {
52
+ throw new Error(`${label} must be ${len} bytes, got ${bytes.length}.`);
53
+ }
54
+ return bytes;
55
+ }
56
+ function i128ToBytes(value) {
57
+ const min = -(1n << 127n);
58
+ const max = (1n << 127n) - 1n;
59
+ if (value < min || value > max) throw new Error("i128 out of range.");
60
+ let unsigned = value;
61
+ if (value < 0) unsigned = (1n << 128n) + value;
62
+ const out = new Uint8Array(16);
63
+ for (let i = 15; i >= 0; i -= 1) {
64
+ out[i] = Number(unsigned & 0xffn);
65
+ unsigned >>= 8n;
66
+ }
67
+ return out;
68
+ }
69
+
70
+ // src/relayer-protocol/payload.ts
71
+ var RELAY_PAYLOAD_DOMAIN = "opaque-stellar-relay-v1";
72
+ var RELAY_CHAIN_STELLAR = 3e3;
73
+ function utf8(value) {
74
+ return new TextEncoder().encode(value);
75
+ }
76
+ function addressXdr(address) {
77
+ return new Uint8Array(new Address(address).toScVal().toXDR());
78
+ }
79
+ function symbolXdr(symbol) {
80
+ return new Uint8Array(xdr.ScVal.scvSymbol(symbol).toXDR());
81
+ }
82
+ function poolWithdrawPayloadPreimage(payload) {
83
+ return concatBytes(
84
+ utf8(RELAY_PAYLOAD_DOMAIN),
85
+ addressXdr(payload.poolId),
86
+ symbolXdr("withdraw"),
87
+ assertLength(payload.proofA, 64, "proofA"),
88
+ assertLength(payload.proofB, 128, "proofB"),
89
+ assertLength(payload.proofC, 64, "proofC"),
90
+ i128ToBytes(payload.withdrawnValue),
91
+ assertLength(payload.stateRoot, 32, "stateRoot"),
92
+ assertLength(payload.aspRoot, 32, "aspRoot"),
93
+ assertLength(payload.nullifierHash, 32, "nullifierHash"),
94
+ assertLength(payload.newCommitment, 32, "newCommitment"),
95
+ addressXdr(payload.recipient),
96
+ i128ToBytes(payload.poolFee),
97
+ addressXdr(payload.poolRelayer)
98
+ );
99
+ }
100
+ function hashPoolWithdrawPayload(payload) {
101
+ return keccak_256(poolWithdrawPayloadPreimage(payload));
102
+ }
103
+ function hashPoolWithdrawPayloadHex(payload) {
104
+ return bytesToHex(hashPoolWithdrawPayload(payload));
105
+ }
106
+ function serializePoolWithdrawPayload(payload) {
107
+ return {
108
+ poolId: payload.poolId,
109
+ proofA: bytesToHex(payload.proofA),
110
+ proofB: bytesToHex(payload.proofB),
111
+ proofC: bytesToHex(payload.proofC),
112
+ withdrawnValue: payload.withdrawnValue.toString(),
113
+ stateRoot: bytesToHex(payload.stateRoot),
114
+ aspRoot: bytesToHex(payload.aspRoot),
115
+ nullifierHash: bytesToHex(payload.nullifierHash),
116
+ newCommitment: bytesToHex(payload.newCommitment),
117
+ recipient: payload.recipient,
118
+ poolFee: payload.poolFee.toString(),
119
+ poolRelayer: payload.poolRelayer
120
+ };
121
+ }
122
+ function parsePoolWithdrawPayload(payload) {
123
+ return {
124
+ poolId: payload.poolId,
125
+ proofA: assertLength(hexToBytes(payload.proofA), 64, "proofA"),
126
+ proofB: assertLength(hexToBytes(payload.proofB), 128, "proofB"),
127
+ proofC: assertLength(hexToBytes(payload.proofC), 64, "proofC"),
128
+ withdrawnValue: BigInt(payload.withdrawnValue),
129
+ stateRoot: assertLength(hexToBytes(payload.stateRoot), 32, "stateRoot"),
130
+ aspRoot: assertLength(hexToBytes(payload.aspRoot), 32, "aspRoot"),
131
+ nullifierHash: assertLength(hexToBytes(payload.nullifierHash), 32, "nullifierHash"),
132
+ newCommitment: assertLength(hexToBytes(payload.newCommitment), 32, "newCommitment"),
133
+ recipient: payload.recipient,
134
+ poolFee: BigInt(payload.poolFee),
135
+ poolRelayer: payload.poolRelayer
136
+ };
137
+ }
138
+ function encodePoolWithdrawPayload(payload) {
139
+ return utf8(
140
+ JSON.stringify({ t: "pool-withdraw", v: 1, payload: serializePoolWithdrawPayload(payload) })
141
+ );
142
+ }
143
+ function decodePoolWithdrawPayload(bytes) {
144
+ const decoded = JSON.parse(new TextDecoder().decode(bytes));
145
+ if (decoded.t !== "pool-withdraw" || decoded.v !== 1 || !decoded.payload) {
146
+ throw new Error("Unsupported relayer payload.");
147
+ }
148
+ return parsePoolWithdrawPayload(decoded.payload);
149
+ }
150
+
151
+ // src/relayer-protocol/box.ts
152
+ var PUBLIC_KEY_BYTES = 32;
153
+ var SECRET_KEY_BYTES = 32;
154
+ var NONCE_BYTES = 24;
155
+ function randomBytes(len) {
156
+ const out = new Uint8Array(len);
157
+ globalThis.crypto.getRandomValues(out);
158
+ return out;
159
+ }
160
+ async function getNacl() {
161
+ try {
162
+ return (await import('tweetnacl')).default;
163
+ } catch (cause) {
164
+ throw new Error(
165
+ "tweetnacl is required for relayer payload encryption; install it as a peer dependency.",
166
+ { cause }
167
+ );
168
+ }
169
+ }
170
+ async function generateX25519Keypair(seed) {
171
+ const nacl = await getNacl();
172
+ if (seed) {
173
+ const secretKey = assertLength(seed, SECRET_KEY_BYTES, "x25519 seed");
174
+ const pair2 = nacl.box.keyPair.fromSecretKey(secretKey);
175
+ return { publicKey: pair2.publicKey, secretKey: pair2.secretKey };
176
+ }
177
+ const pair = nacl.box.keyPair();
178
+ return { publicKey: pair.publicKey, secretKey: pair.secretKey };
179
+ }
180
+ async function sealBox(plaintext, recipientPublicKey) {
181
+ const nacl = await getNacl();
182
+ const to = assertLength(recipientPublicKey, PUBLIC_KEY_BYTES, "recipient x25519 public key");
183
+ const eph = nacl.box.keyPair();
184
+ const nonce = randomBytes(NONCE_BYTES);
185
+ const ciphertext = nacl.box(plaintext, nonce, to, eph.secretKey);
186
+ return bytesToBase64(concatBytes(eph.publicKey, nonce, ciphertext));
187
+ }
188
+ async function openBox(box, recipientSecretKey) {
189
+ const nacl = await getNacl();
190
+ const secret = assertLength(recipientSecretKey, SECRET_KEY_BYTES, "recipient x25519 secret key");
191
+ const raw = base64ToBytes(box);
192
+ if (raw.length < PUBLIC_KEY_BYTES + NONCE_BYTES + nacl.box.overheadLength) {
193
+ throw new Error("Encrypted payload is too short.");
194
+ }
195
+ const epk = raw.slice(0, PUBLIC_KEY_BYTES);
196
+ const nonce = raw.slice(PUBLIC_KEY_BYTES, PUBLIC_KEY_BYTES + NONCE_BYTES);
197
+ const ciphertext = raw.slice(PUBLIC_KEY_BYTES + NONCE_BYTES);
198
+ const opened = nacl.box.open(ciphertext, nonce, epk, secret);
199
+ if (!opened) throw new Error("Could not decrypt relayer payload.");
200
+ return opened;
201
+ }
202
+ var BID_DOMAIN = new TextEncoder().encode("opaque-relayer-bid-v1");
203
+ function makeAdvert(args) {
204
+ return {
205
+ t: "advert",
206
+ v: 1,
207
+ jobId: bytesToHex(assertLength(args.jobId, 32, "jobId")),
208
+ chain: args.chain ?? RELAY_CHAIN_STELLAR,
209
+ fee: args.fee.toString(),
210
+ deadline: args.deadline,
211
+ payloadHash: bytesToHex(assertLength(args.payloadHash, 32, "payloadHash"))
212
+ };
213
+ }
214
+ function bidSigningDigest(jobId, x25519Pk) {
215
+ return keccak_256(
216
+ concatBytes(
217
+ BID_DOMAIN,
218
+ assertLength(jobId, 32, "jobId"),
219
+ assertLength(x25519Pk, 32, "x25519Pk")
220
+ )
221
+ );
222
+ }
223
+ function makeBid(args) {
224
+ const x25519Pk = assertLength(args.x25519Pk, 32, "x25519Pk");
225
+ const digest = bidSigningDigest(hexToBytes(args.advert.jobId), x25519Pk);
226
+ return {
227
+ t: "bid",
228
+ v: 1,
229
+ jobId: args.advert.jobId,
230
+ chain: args.advert.chain,
231
+ operator: args.operator.publicKey(),
232
+ x25519Pk: bytesToHex(x25519Pk),
233
+ sig: bytesToBase64(args.operator.sign(Buffer.from(digest))),
234
+ endpoint: args.endpoint,
235
+ freeStake: args.freeStake?.toString()
236
+ };
237
+ }
238
+ function verifyBid(bid) {
239
+ try {
240
+ const digest = bidSigningDigest(hexToBytes(bid.jobId), hexToBytes(bid.x25519Pk));
241
+ return Keypair.fromPublicKey(bid.operator).verify(
242
+ Buffer.from(digest),
243
+ Buffer.from(base64ToBytes(bid.sig))
244
+ );
245
+ } catch {
246
+ return false;
247
+ }
248
+ }
249
+ function validateAdvert(value) {
250
+ const v = value;
251
+ if (v?.t !== "advert" || v.v !== 1 || typeof v.jobId !== "string" || typeof v.payloadHash !== "string" || typeof v.fee !== "string" || typeof v.deadline !== "number") {
252
+ throw new Error("Invalid relayer advert.");
253
+ }
254
+ assertLength(hexToBytes(v.jobId), 32, "jobId");
255
+ assertLength(hexToBytes(v.payloadHash), 32, "payloadHash");
256
+ return { ...v, chain: v.chain ?? RELAY_CHAIN_STELLAR };
257
+ }
258
+ function validateBid(value) {
259
+ const v = value;
260
+ if (v?.t !== "bid" || v.v !== 1 || typeof v.jobId !== "string" || typeof v.operator !== "string" || typeof v.x25519Pk !== "string" || typeof v.sig !== "string") {
261
+ throw new Error("Invalid relayer bid.");
262
+ }
263
+ assertLength(hexToBytes(v.jobId), 32, "jobId");
264
+ assertLength(hexToBytes(v.x25519Pk), 32, "x25519Pk");
265
+ return { ...v, chain: v.chain ?? RELAY_CHAIN_STELLAR };
266
+ }
267
+ function addressToScVal(addr) {
268
+ return new Address(addr).toScVal();
269
+ }
270
+ function bytesToScVal(bytes) {
271
+ return xdr.ScVal.scvBytes(Buffer.from(bytes));
272
+ }
273
+
274
+ // src/relayer-protocol/gateway.ts
275
+ var REGISTRY_JOB_STATUS = {
276
+ 0: "open",
277
+ 1: "accepted",
278
+ 2: "submitted",
279
+ 3: "slashed",
280
+ 4: "canceled"
281
+ };
282
+ function randomJobId() {
283
+ const out = new Uint8Array(32);
284
+ globalThis.crypto.getRandomValues(out);
285
+ return out;
286
+ }
287
+ function buildRelayedWithdrawPayload(args) {
288
+ return {
289
+ poolId: args.poolId,
290
+ proofA: args.proof.proofA,
291
+ proofB: args.proof.proofB,
292
+ proofC: args.proof.proofC,
293
+ withdrawnValue: args.proof.withdrawnValue,
294
+ stateRoot: args.proof.stateRoot,
295
+ aspRoot: args.proof.aspRoot,
296
+ nullifierHash: args.proof.nullifierHash,
297
+ newCommitment: args.proof.newCommitment,
298
+ recipient: args.recipient,
299
+ poolFee: 0n,
300
+ poolRelayer: args.registryId
301
+ };
302
+ }
303
+ function buildRelayerJobDraft(args) {
304
+ const jobId = assertLength(args.jobId ?? randomJobId(), 32, "jobId");
305
+ const payloadHash = hashPoolWithdrawPayload(args.payload);
306
+ return {
307
+ jobId,
308
+ jobIdHex: bytesToHex(jobId),
309
+ payload: args.payload,
310
+ payloadHash,
311
+ payloadHashHex: bytesToHex(payloadHash),
312
+ advert: makeAdvert({ jobId, fee: args.fee, deadline: args.deadlineLedger, payloadHash }),
313
+ deadlineLedger: args.deadlineLedger,
314
+ fee: args.fee
315
+ };
316
+ }
317
+ function pickStakeWeightedBid(bids) {
318
+ if (bids.length === 0) return null;
319
+ const total = bids.reduce((sum, bid) => sum + bid.freeStakeValue, 0n);
320
+ if (total <= 0n) return bids[0];
321
+ const rand = new Uint32Array(2);
322
+ globalThis.crypto.getRandomValues(rand);
323
+ let target = ((BigInt(rand[0]) << 32n) + BigInt(rand[1])) % total;
324
+ for (const bid of bids) {
325
+ if (target < bid.freeStakeValue) return bid;
326
+ target -= bid.freeStakeValue;
327
+ }
328
+ return bids[bids.length - 1];
329
+ }
330
+ var RelayerGateway = class {
331
+ gatewayUrls;
332
+ registryId;
333
+ invoker;
334
+ constructor(opts) {
335
+ if (opts.gatewayUrls.length === 0) {
336
+ throw new Error("RelayerGateway requires at least one gateway URL.");
337
+ }
338
+ this.gatewayUrls = opts.gatewayUrls;
339
+ this.registryId = opts.registryId;
340
+ this.invoker = opts.invoker;
341
+ }
342
+ url(path, base = this.gatewayUrls[0]) {
343
+ return new URL(path, base.endsWith("/") ? base : `${base}/`).toString();
344
+ }
345
+ /** A deadline `ledgers` ahead of the current ledger. */
346
+ async deadlineLedger(ledgers = 720) {
347
+ return await this.invoker.getLatestLedger() + ledgers;
348
+ }
349
+ async publishAdvert(advert, gateway = this.gatewayUrls[0]) {
350
+ const res = await fetch(this.url("v1/jobs", gateway), {
351
+ method: "POST",
352
+ headers: { "content-type": "application/json" },
353
+ body: JSON.stringify(advert)
354
+ });
355
+ if (!res.ok) throw new Error(`Relayer gateway rejected advert (${res.status}).`);
356
+ }
357
+ async fetchBids(jobIdHex, gateway = this.gatewayUrls[0]) {
358
+ const res = await fetch(this.url(`v1/jobs/${encodeURIComponent(jobIdHex)}/bids`, gateway));
359
+ if (!res.ok) throw new Error(`Could not fetch relayer bids (${res.status}).`);
360
+ const body = await res.json();
361
+ const signed = (body.bids ?? []).map((raw) => validateBid(raw)).filter((bid) => verifyBid(bid)).filter((bid) => bid.jobId.toLowerCase() === jobIdHex.toLowerCase()).filter((bid) => bid.chain === RELAY_CHAIN_STELLAR);
362
+ const checked = await Promise.all(signed.map((bid) => this.verifyBidRegistryState(jobIdHex, bid)));
363
+ return checked.filter((bid) => bid !== null);
364
+ }
365
+ async deliverPayload(args) {
366
+ const box = await sealBox(
367
+ encodePoolWithdrawPayload(args.draft.payload),
368
+ hexToBytes(args.bid.x25519Pk)
369
+ );
370
+ const res = await fetch(
371
+ this.url(`v1/jobs/${encodeURIComponent(args.draft.jobIdHex)}/payload`, args.gateway ?? this.gatewayUrls[0]),
372
+ {
373
+ method: "POST",
374
+ headers: { "content-type": "application/json" },
375
+ body: JSON.stringify({ t: "payload", v: 1, jobId: args.draft.jobIdHex, to: args.bid.x25519Pk, box })
376
+ }
377
+ );
378
+ if (!res.ok) throw new Error(`Relayer gateway rejected payload (${res.status}).`);
379
+ const body = await res.json();
380
+ return body.result ?? null;
381
+ }
382
+ async jobStatus(jobIdHex, source) {
383
+ const job = await this.registryView(source, "get_job", [
384
+ bytesToScVal(hexToBytes(jobIdHex))
385
+ ]);
386
+ if (!job) return "unknown";
387
+ return REGISTRY_JOB_STATUS[Number(job.status)] ?? "unknown";
388
+ }
389
+ async verifyBidRegistryState(jobIdHex, bid) {
390
+ try {
391
+ const [job, relayer] = await Promise.all([
392
+ this.registryView(bid.operator, "get_job", [
393
+ bytesToScVal(hexToBytes(jobIdHex))
394
+ ]),
395
+ this.registryView(bid.operator, "get_relayer", [
396
+ addressToScVal(bid.operator)
397
+ ])
398
+ ]);
399
+ if (!job || !relayer) return null;
400
+ const fee = BigInt(job.fee);
401
+ const freeStakeValue = BigInt(relayer.free_stake);
402
+ if (Number(job.status) !== 0 || freeStakeValue < fee) return null;
403
+ const registeredPk = bytesToHex(Uint8Array.from(relayer.x25519_pubkey));
404
+ if (registeredPk.toLowerCase() !== bid.x25519Pk.toLowerCase()) return null;
405
+ return {
406
+ ...bid,
407
+ endpoint: relayer.endpoint?.trim() || bid.endpoint,
408
+ freeStake: freeStakeValue.toString(),
409
+ freeStakeValue
410
+ };
411
+ } catch {
412
+ return null;
413
+ }
414
+ }
415
+ async registryView(source, method, args) {
416
+ try {
417
+ return await this.invoker.readNative({
418
+ source,
419
+ contractId: this.registryId,
420
+ method,
421
+ args
422
+ });
423
+ } catch {
424
+ return null;
425
+ }
426
+ }
427
+ };
428
+
429
+ export { RELAY_CHAIN_STELLAR, RELAY_PAYLOAD_DOMAIN, RelayerGateway, bidSigningDigest, buildRelayedWithdrawPayload, buildRelayerJobDraft, decodePoolWithdrawPayload, encodePoolWithdrawPayload, generateX25519Keypair, hashPoolWithdrawPayload, hashPoolWithdrawPayloadHex, makeAdvert, makeBid, openBox, parsePoolWithdrawPayload, pickStakeWeightedBid, poolWithdrawPayloadPreimage, randomJobId, sealBox, serializePoolWithdrawPayload, validateAdvert, validateBid, verifyBid };
430
+ //# sourceMappingURL=index.js.map
431
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/relayer-protocol/bytes.ts","../../src/relayer-protocol/payload.ts","../../src/relayer-protocol/box.ts","../../src/relayer-protocol/messages.ts","../../src/rpc/scval.ts","../../src/relayer-protocol/gateway.ts"],"names":["pair","keccak_256","Address","xdr"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Internal byte helpers for the relayer protocol. Kept separate from\n * `crypto/bytes` because the wire format here uses 0x-prefixed hex and exact\n * i128/length encodings that must byte-match the relayer node and the\n * relayer-registry contract.\n */\n\nexport function hexToBytes(hex: string): Uint8Array {\n const clean = hex.replace(/^0x/, \"\");\n if (!/^[0-9a-f]*$/i.test(clean) || clean.length % 2 !== 0) {\n throw new Error(\"Invalid hex string.\");\n }\n const out = new Uint8Array(clean.length / 2);\n for (let i = 0; i < out.length; i += 1) {\n out[i] = Number.parseInt(clean.slice(i * 2, i * 2 + 2), 16);\n }\n return out;\n}\n\nexport function bytesToHex(bytes: Uint8Array): string {\n return `0x${Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\")}`;\n}\n\nexport function base64ToBytes(value: string): Uint8Array {\n if (typeof atob === \"function\") {\n const bin = atob(value);\n return Uint8Array.from(bin, (c) => c.charCodeAt(0));\n }\n const buffer = (globalThis as unknown as { Buffer?: { from(v: string, enc: \"base64\"): Uint8Array } }).Buffer;\n if (!buffer) throw new Error(\"No base64 decoder available.\");\n return Uint8Array.from(buffer.from(value, \"base64\"));\n}\n\nexport function bytesToBase64(bytes: Uint8Array): string {\n if (typeof btoa === \"function\") {\n let bin = \"\";\n for (const b of bytes) bin += String.fromCharCode(b);\n return btoa(bin);\n }\n const buffer = (globalThis as unknown as { Buffer?: { from(v: Uint8Array): { toString(enc: \"base64\"): string } } }).Buffer;\n if (!buffer) throw new Error(\"No base64 encoder available.\");\n return buffer.from(bytes).toString(\"base64\");\n}\n\nexport function concatBytes(...chunks: Uint8Array[]): Uint8Array {\n const len = chunks.reduce((n, c) => n + c.length, 0);\n const out = new Uint8Array(len);\n let offset = 0;\n for (const chunk of chunks) {\n out.set(chunk, offset);\n offset += chunk.length;\n }\n return out;\n}\n\nexport function assertLength(bytes: Uint8Array, len: number, label: string): Uint8Array {\n if (bytes.length !== len) {\n throw new Error(`${label} must be ${len} bytes, got ${bytes.length}.`);\n }\n return bytes;\n}\n\nexport function i128ToBytes(value: bigint): Uint8Array {\n const min = -(1n << 127n);\n const max = (1n << 127n) - 1n;\n if (value < min || value > max) throw new Error(\"i128 out of range.\");\n let unsigned = value;\n if (value < 0) unsigned = (1n << 128n) + value;\n const out = new Uint8Array(16);\n for (let i = 15; i >= 0; i -= 1) {\n out[i] = Number(unsigned & 0xffn);\n unsigned >>= 8n;\n }\n return out;\n}\n","/**\n * Canonical pool-withdrawal payload + hash. The preimage and keccak256 hash\n * byte-match the relayer-registry contract and the relayer node, so a payload\n * hash computed here is the same one the contract recomputes on submission.\n */\nimport { Address, xdr } from \"@stellar/stellar-sdk\";\nimport { keccak_256 } from \"@noble/hashes/sha3\";\nimport { assertLength, bytesToHex, concatBytes, hexToBytes, i128ToBytes } from \"./bytes\";\n\nexport const RELAY_PAYLOAD_DOMAIN = \"opaque-stellar-relay-v1\";\nexport const RELAY_CHAIN_STELLAR = 3000;\n\nexport type PoolWithdrawPayload = {\n poolId: string;\n proofA: Uint8Array;\n proofB: Uint8Array;\n proofC: Uint8Array;\n withdrawnValue: bigint;\n stateRoot: Uint8Array;\n aspRoot: Uint8Array;\n nullifierHash: Uint8Array;\n newCommitment: Uint8Array;\n recipient: string;\n poolFee: bigint;\n poolRelayer: string;\n};\n\nexport type SerializablePoolWithdrawPayload = {\n poolId: string;\n proofA: string;\n proofB: string;\n proofC: string;\n withdrawnValue: string;\n stateRoot: string;\n aspRoot: string;\n nullifierHash: string;\n newCommitment: string;\n recipient: string;\n poolFee: string;\n poolRelayer: string;\n};\n\nfunction utf8(value: string): Uint8Array {\n return new TextEncoder().encode(value);\n}\n\nfunction addressXdr(address: string): Uint8Array {\n return new Uint8Array(new Address(address).toScVal().toXDR());\n}\n\nfunction symbolXdr(symbol: string): Uint8Array {\n return new Uint8Array(xdr.ScVal.scvSymbol(symbol).toXDR());\n}\n\nexport function poolWithdrawPayloadPreimage(payload: PoolWithdrawPayload): Uint8Array {\n return concatBytes(\n utf8(RELAY_PAYLOAD_DOMAIN),\n addressXdr(payload.poolId),\n symbolXdr(\"withdraw\"),\n assertLength(payload.proofA, 64, \"proofA\"),\n assertLength(payload.proofB, 128, \"proofB\"),\n assertLength(payload.proofC, 64, \"proofC\"),\n i128ToBytes(payload.withdrawnValue),\n assertLength(payload.stateRoot, 32, \"stateRoot\"),\n assertLength(payload.aspRoot, 32, \"aspRoot\"),\n assertLength(payload.nullifierHash, 32, \"nullifierHash\"),\n assertLength(payload.newCommitment, 32, \"newCommitment\"),\n addressXdr(payload.recipient),\n i128ToBytes(payload.poolFee),\n addressXdr(payload.poolRelayer),\n );\n}\n\nexport function hashPoolWithdrawPayload(payload: PoolWithdrawPayload): Uint8Array {\n return keccak_256(poolWithdrawPayloadPreimage(payload));\n}\n\nexport function hashPoolWithdrawPayloadHex(payload: PoolWithdrawPayload): string {\n return bytesToHex(hashPoolWithdrawPayload(payload));\n}\n\nexport function serializePoolWithdrawPayload(\n payload: PoolWithdrawPayload,\n): SerializablePoolWithdrawPayload {\n return {\n poolId: payload.poolId,\n proofA: bytesToHex(payload.proofA),\n proofB: bytesToHex(payload.proofB),\n proofC: bytesToHex(payload.proofC),\n withdrawnValue: payload.withdrawnValue.toString(),\n stateRoot: bytesToHex(payload.stateRoot),\n aspRoot: bytesToHex(payload.aspRoot),\n nullifierHash: bytesToHex(payload.nullifierHash),\n newCommitment: bytesToHex(payload.newCommitment),\n recipient: payload.recipient,\n poolFee: payload.poolFee.toString(),\n poolRelayer: payload.poolRelayer,\n };\n}\n\nexport function parsePoolWithdrawPayload(\n payload: SerializablePoolWithdrawPayload,\n): PoolWithdrawPayload {\n return {\n poolId: payload.poolId,\n proofA: assertLength(hexToBytes(payload.proofA), 64, \"proofA\"),\n proofB: assertLength(hexToBytes(payload.proofB), 128, \"proofB\"),\n proofC: assertLength(hexToBytes(payload.proofC), 64, \"proofC\"),\n withdrawnValue: BigInt(payload.withdrawnValue),\n stateRoot: assertLength(hexToBytes(payload.stateRoot), 32, \"stateRoot\"),\n aspRoot: assertLength(hexToBytes(payload.aspRoot), 32, \"aspRoot\"),\n nullifierHash: assertLength(hexToBytes(payload.nullifierHash), 32, \"nullifierHash\"),\n newCommitment: assertLength(hexToBytes(payload.newCommitment), 32, \"newCommitment\"),\n recipient: payload.recipient,\n poolFee: BigInt(payload.poolFee),\n poolRelayer: payload.poolRelayer,\n };\n}\n\nexport function encodePoolWithdrawPayload(payload: PoolWithdrawPayload): Uint8Array {\n return utf8(\n JSON.stringify({ t: \"pool-withdraw\", v: 1, payload: serializePoolWithdrawPayload(payload) }),\n );\n}\n\nexport function decodePoolWithdrawPayload(bytes: Uint8Array): PoolWithdrawPayload {\n const decoded = JSON.parse(new TextDecoder().decode(bytes)) as {\n t?: string;\n v?: number;\n payload?: SerializablePoolWithdrawPayload;\n };\n if (decoded.t !== \"pool-withdraw\" || decoded.v !== 1 || !decoded.payload) {\n throw new Error(\"Unsupported relayer payload.\");\n }\n return parsePoolWithdrawPayload(decoded.payload);\n}\n","/**\n * NaCl `crypto_box` sealing for relayer payloads. `tweetnacl` is an optional peer\n * dependency, loaded lazily so consumers that never touch the relayer market do\n * not need it installed.\n */\nimport { assertLength, base64ToBytes, bytesToBase64, concatBytes } from \"./bytes\";\n\nconst PUBLIC_KEY_BYTES = 32;\nconst SECRET_KEY_BYTES = 32;\nconst NONCE_BYTES = 24;\n\nfunction randomBytes(len: number): Uint8Array {\n const out = new Uint8Array(len);\n globalThis.crypto.getRandomValues(out);\n return out;\n}\n\ntype KeyPair = { publicKey: Uint8Array; secretKey: Uint8Array };\ninterface NaclBox {\n (msg: Uint8Array, nonce: Uint8Array, theirPk: Uint8Array, mySk: Uint8Array): Uint8Array;\n open(box: Uint8Array, nonce: Uint8Array, theirPk: Uint8Array, mySk: Uint8Array): Uint8Array | null;\n keyPair: { (): KeyPair; fromSecretKey(sk: Uint8Array): KeyPair };\n overheadLength: number;\n}\ninterface Nacl {\n box: NaclBox;\n}\n\nasync function getNacl(): Promise<Nacl> {\n try {\n return ((await import(\"tweetnacl\")) as unknown as { default: Nacl }).default;\n } catch (cause) {\n throw new Error(\n \"tweetnacl is required for relayer payload encryption; install it as a peer dependency.\",\n { cause },\n );\n }\n}\n\nexport type X25519Keypair = {\n publicKey: Uint8Array;\n secretKey: Uint8Array;\n};\n\nexport async function generateX25519Keypair(seed?: Uint8Array): Promise<X25519Keypair> {\n const nacl = await getNacl();\n if (seed) {\n const secretKey = assertLength(seed, SECRET_KEY_BYTES, \"x25519 seed\");\n const pair = nacl.box.keyPair.fromSecretKey(secretKey);\n return { publicKey: pair.publicKey, secretKey: pair.secretKey };\n }\n const pair = nacl.box.keyPair();\n return { publicKey: pair.publicKey, secretKey: pair.secretKey };\n}\n\nexport async function sealBox(\n plaintext: Uint8Array,\n recipientPublicKey: Uint8Array,\n): Promise<string> {\n const nacl = await getNacl();\n const to = assertLength(recipientPublicKey, PUBLIC_KEY_BYTES, \"recipient x25519 public key\");\n const eph = nacl.box.keyPair();\n const nonce = randomBytes(NONCE_BYTES);\n const ciphertext = nacl.box(plaintext, nonce, to, eph.secretKey);\n return bytesToBase64(concatBytes(eph.publicKey, nonce, ciphertext));\n}\n\nexport async function openBox(box: string, recipientSecretKey: Uint8Array): Promise<Uint8Array> {\n const nacl = await getNacl();\n const secret = assertLength(recipientSecretKey, SECRET_KEY_BYTES, \"recipient x25519 secret key\");\n const raw = base64ToBytes(box);\n if (raw.length < PUBLIC_KEY_BYTES + NONCE_BYTES + nacl.box.overheadLength) {\n throw new Error(\"Encrypted payload is too short.\");\n }\n const epk = raw.slice(0, PUBLIC_KEY_BYTES);\n const nonce = raw.slice(PUBLIC_KEY_BYTES, PUBLIC_KEY_BYTES + NONCE_BYTES);\n const ciphertext = raw.slice(PUBLIC_KEY_BYTES + NONCE_BYTES);\n const opened = nacl.box.open(ciphertext, nonce, epk, secret);\n if (!opened) throw new Error(\"Could not decrypt relayer payload.\");\n return opened;\n}\n","/**\n * `opaque/jobs/v1` wire messages: advert, bid, encrypted payload. Bids are\n * Ed25519-signed by the relayer operator over a domain-separated digest so the\n * SDK can verify them before trusting registry state.\n */\nimport { Keypair } from \"@stellar/stellar-sdk\";\nimport { keccak_256 } from \"@noble/hashes/sha3\";\nimport {\n assertLength,\n base64ToBytes,\n bytesToBase64,\n bytesToHex,\n concatBytes,\n hexToBytes,\n} from \"./bytes\";\nimport { RELAY_CHAIN_STELLAR } from \"./payload\";\n\nconst BID_DOMAIN = new TextEncoder().encode(\"opaque-relayer-bid-v1\");\n\nexport type JobAdvert = {\n t: \"advert\";\n v: 1;\n jobId: string;\n chain: number;\n fee: string;\n deadline: number;\n payloadHash: string;\n};\n\nexport type RelayerBid = {\n t: \"bid\";\n v: 1;\n jobId: string;\n chain: number;\n operator: string;\n x25519Pk: string;\n sig: string;\n endpoint?: string;\n freeStake?: string;\n};\n\nexport type EncryptedPayload = {\n t: \"payload\";\n v: 1;\n jobId: string;\n to: string;\n box: string;\n};\n\nexport type RelayerMessage = JobAdvert | RelayerBid | EncryptedPayload;\n\nexport function makeAdvert(args: {\n jobId: Uint8Array;\n fee: bigint;\n deadline: number;\n payloadHash: Uint8Array;\n chain?: number;\n}): JobAdvert {\n return {\n t: \"advert\",\n v: 1,\n jobId: bytesToHex(assertLength(args.jobId, 32, \"jobId\")),\n chain: args.chain ?? RELAY_CHAIN_STELLAR,\n fee: args.fee.toString(),\n deadline: args.deadline,\n payloadHash: bytesToHex(assertLength(args.payloadHash, 32, \"payloadHash\")),\n };\n}\n\nexport function bidSigningDigest(jobId: Uint8Array, x25519Pk: Uint8Array): Uint8Array {\n return keccak_256(\n concatBytes(\n BID_DOMAIN,\n assertLength(jobId, 32, \"jobId\"),\n assertLength(x25519Pk, 32, \"x25519Pk\"),\n ),\n );\n}\n\nexport function makeBid(args: {\n advert: JobAdvert;\n operator: Keypair;\n x25519Pk: Uint8Array;\n endpoint?: string;\n freeStake?: bigint;\n}): RelayerBid {\n const x25519Pk = assertLength(args.x25519Pk, 32, \"x25519Pk\");\n const digest = bidSigningDigest(hexToBytes(args.advert.jobId), x25519Pk);\n return {\n t: \"bid\",\n v: 1,\n jobId: args.advert.jobId,\n chain: args.advert.chain,\n operator: args.operator.publicKey(),\n x25519Pk: bytesToHex(x25519Pk),\n sig: bytesToBase64(args.operator.sign(Buffer.from(digest))),\n endpoint: args.endpoint,\n freeStake: args.freeStake?.toString(),\n };\n}\n\nexport function verifyBid(bid: RelayerBid): boolean {\n try {\n const digest = bidSigningDigest(hexToBytes(bid.jobId), hexToBytes(bid.x25519Pk));\n return Keypair.fromPublicKey(bid.operator).verify(\n Buffer.from(digest),\n Buffer.from(base64ToBytes(bid.sig)),\n );\n } catch {\n return false;\n }\n}\n\nexport function validateAdvert(value: unknown): JobAdvert {\n const v = value as Partial<JobAdvert>;\n if (\n v?.t !== \"advert\" ||\n v.v !== 1 ||\n typeof v.jobId !== \"string\" ||\n typeof v.payloadHash !== \"string\" ||\n typeof v.fee !== \"string\" ||\n typeof v.deadline !== \"number\"\n ) {\n throw new Error(\"Invalid relayer advert.\");\n }\n assertLength(hexToBytes(v.jobId), 32, \"jobId\");\n assertLength(hexToBytes(v.payloadHash), 32, \"payloadHash\");\n return { ...v, chain: v.chain ?? RELAY_CHAIN_STELLAR } as JobAdvert;\n}\n\nexport function validateBid(value: unknown): RelayerBid {\n const v = value as Partial<RelayerBid>;\n if (\n v?.t !== \"bid\" ||\n v.v !== 1 ||\n typeof v.jobId !== \"string\" ||\n typeof v.operator !== \"string\" ||\n typeof v.x25519Pk !== \"string\" ||\n typeof v.sig !== \"string\"\n ) {\n throw new Error(\"Invalid relayer bid.\");\n }\n assertLength(hexToBytes(v.jobId), 32, \"jobId\");\n assertLength(hexToBytes(v.x25519Pk), 32, \"x25519Pk\");\n return { ...v, chain: v.chain ?? RELAY_CHAIN_STELLAR } as RelayerBid;\n}\n","/**\n * ScVal conversion helpers for building Soroban contract-call arguments.\n * Thin, typed wrappers over `@stellar/stellar-sdk` so callers never hand-roll\n * `nativeToScVal` type tags.\n */\nimport { Address, nativeToScVal, scValToNative, xdr } from \"@stellar/stellar-sdk\";\n\n/** Stellar address (G/C-strkey) -> ScVal address. */\nexport function addressToScVal(addr: string): xdr.ScVal {\n return new Address(addr).toScVal();\n}\n\n/** Raw bytes -> ScVal bytes. */\nexport function bytesToScVal(bytes: Uint8Array): xdr.ScVal {\n return xdr.ScVal.scvBytes(Buffer.from(bytes));\n}\n\n/** Number/bigint -> ScVal u32. */\nexport function u32ToScVal(n: number): xdr.ScVal {\n return nativeToScVal(n, { type: \"u32\" });\n}\n\n/** Number/bigint -> ScVal u64. */\nexport function u64ToScVal(n: bigint | number): xdr.ScVal {\n return nativeToScVal(n, { type: \"u64\" });\n}\n\n/** Bigint -> ScVal i128 (Soroban's signed amount type). */\nexport function i128ToScVal(n: bigint): xdr.ScVal {\n return nativeToScVal(n, { type: \"i128\" });\n}\n\n/** Bigint -> ScVal u128. */\nexport function u128ToScVal(n: bigint): xdr.ScVal {\n return nativeToScVal(n, { type: \"u128\" });\n}\n\n/** String -> ScVal symbol. */\nexport function symbolToScVal(s: string): xdr.ScVal {\n return nativeToScVal(s, { type: \"symbol\" });\n}\n\n/** String -> ScVal string. */\nexport function stringToScVal(s: string): xdr.ScVal {\n return nativeToScVal(s, { type: \"string\" });\n}\n\n/** Boolean -> ScVal bool. */\nexport function boolToScVal(b: boolean): xdr.ScVal {\n return nativeToScVal(b, { type: \"bool\" });\n}\n\n/** Optional address -> ScVal address, or a void ScVal when null/undefined. */\nexport function optionAddressToScVal(addr: string | null | undefined): xdr.ScVal {\n return addr ? addressToScVal(addr) : nativeToScVal(null, { type: \"address\" });\n}\n\n/** Decode an ScVal into its native JS representation. */\nexport function fromScVal(v: xdr.ScVal): unknown {\n return scValToNative(v);\n}\n","/**\n * Relayer-market gateway client: build a blind withdrawal payload, advertise a\n * job, collect and verify bids (signature + on-chain registry state), pick a\n * relayer, and deliver the payload encrypted to its X25519 key. HTTP transport\n * is the `opaque/jobs/v1` gateway API.\n */\nimport type { ContractInvoker } from \"../rpc/client\";\nimport { addressToScVal, bytesToScVal } from \"../rpc/scval\";\nimport type { PoolWithdrawProof } from \"../prove/pool\";\nimport { sealBox } from \"./box\";\nimport {\n makeAdvert,\n validateBid,\n verifyBid,\n type JobAdvert,\n type RelayerBid,\n} from \"./messages\";\nimport { assertLength, bytesToHex, hexToBytes } from \"./bytes\";\nimport {\n encodePoolWithdrawPayload,\n hashPoolWithdrawPayload,\n RELAY_CHAIN_STELLAR,\n type PoolWithdrawPayload,\n} from \"./payload\";\n\nexport type VerifiedBid = RelayerBid & { freeStakeValue: bigint };\n\nexport type RelayerJobDraft = {\n jobId: Uint8Array;\n jobIdHex: string;\n payload: PoolWithdrawPayload;\n payloadHash: Uint8Array;\n payloadHashHex: string;\n advert: JobAdvert;\n deadlineLedger: number;\n fee: bigint;\n};\n\nexport type RelayerJobStatus =\n | \"open\"\n | \"accepted\"\n | \"submitted\"\n | \"slashed\"\n | \"canceled\"\n | \"unknown\";\n\nconst REGISTRY_JOB_STATUS: Record<number, RelayerJobStatus> = {\n 0: \"open\",\n 1: \"accepted\",\n 2: \"submitted\",\n 3: \"slashed\",\n 4: \"canceled\",\n};\n\ntype NativeRegistryJob = { status: number | bigint; fee: bigint | number | string };\ntype NativeRegistryRelayer = {\n endpoint?: string;\n free_stake: bigint | number | string;\n x25519_pubkey: Uint8Array | number[];\n};\n\n/** Cryptographically random 32-byte job id. */\nexport function randomJobId(): Uint8Array {\n const out = new Uint8Array(32);\n globalThis.crypto.getRandomValues(out);\n return out;\n}\n\n/**\n * Build the blind withdrawal payload. The pool fee is zero (the registry escrow\n * pays the relayer) and the proof binds the registry as the pool relayer, so the\n * payload hash is deterministic before a relayer is chosen.\n */\nexport function buildRelayedWithdrawPayload(args: {\n poolId: string;\n registryId: string;\n proof: PoolWithdrawProof;\n recipient: string;\n}): PoolWithdrawPayload {\n return {\n poolId: args.poolId,\n proofA: args.proof.proofA,\n proofB: args.proof.proofB,\n proofC: args.proof.proofC,\n withdrawnValue: args.proof.withdrawnValue,\n stateRoot: args.proof.stateRoot,\n aspRoot: args.proof.aspRoot,\n nullifierHash: args.proof.nullifierHash,\n newCommitment: args.proof.newCommitment,\n recipient: args.recipient,\n poolFee: 0n,\n poolRelayer: args.registryId,\n };\n}\n\nexport function buildRelayerJobDraft(args: {\n payload: PoolWithdrawPayload;\n fee: bigint;\n deadlineLedger: number;\n jobId?: Uint8Array;\n}): RelayerJobDraft {\n const jobId = assertLength(args.jobId ?? randomJobId(), 32, \"jobId\");\n const payloadHash = hashPoolWithdrawPayload(args.payload);\n return {\n jobId,\n jobIdHex: bytesToHex(jobId),\n payload: args.payload,\n payloadHash,\n payloadHashHex: bytesToHex(payloadHash),\n advert: makeAdvert({ jobId, fee: args.fee, deadline: args.deadlineLedger, payloadHash }),\n deadlineLedger: args.deadlineLedger,\n fee: args.fee,\n };\n}\n\n/** Stake-weighted random choice among verified bids. */\nexport function pickStakeWeightedBid(bids: VerifiedBid[]): VerifiedBid | null {\n if (bids.length === 0) return null;\n const total = bids.reduce((sum, bid) => sum + bid.freeStakeValue, 0n);\n if (total <= 0n) return bids[0];\n const rand = new Uint32Array(2);\n globalThis.crypto.getRandomValues(rand);\n let target = ((BigInt(rand[0]) << 32n) + BigInt(rand[1])) % total;\n for (const bid of bids) {\n if (target < bid.freeStakeValue) return bid;\n target -= bid.freeStakeValue;\n }\n return bids[bids.length - 1];\n}\n\nexport class RelayerGateway {\n private readonly gatewayUrls: string[];\n private readonly registryId: string;\n private readonly invoker: ContractInvoker;\n\n constructor(opts: { gatewayUrls: string[]; registryId: string; invoker: ContractInvoker }) {\n if (opts.gatewayUrls.length === 0) {\n throw new Error(\"RelayerGateway requires at least one gateway URL.\");\n }\n this.gatewayUrls = opts.gatewayUrls;\n this.registryId = opts.registryId;\n this.invoker = opts.invoker;\n }\n\n private url(path: string, base = this.gatewayUrls[0]): string {\n return new URL(path, base.endsWith(\"/\") ? base : `${base}/`).toString();\n }\n\n /** A deadline `ledgers` ahead of the current ledger. */\n async deadlineLedger(ledgers = 720): Promise<number> {\n return (await this.invoker.getLatestLedger()) + ledgers;\n }\n\n async publishAdvert(advert: JobAdvert, gateway = this.gatewayUrls[0]): Promise<void> {\n const res = await fetch(this.url(\"v1/jobs\", gateway), {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(advert),\n });\n if (!res.ok) throw new Error(`Relayer gateway rejected advert (${res.status}).`);\n }\n\n async fetchBids(jobIdHex: string, gateway = this.gatewayUrls[0]): Promise<VerifiedBid[]> {\n const res = await fetch(this.url(`v1/jobs/${encodeURIComponent(jobIdHex)}/bids`, gateway));\n if (!res.ok) throw new Error(`Could not fetch relayer bids (${res.status}).`);\n const body = (await res.json()) as { bids?: unknown[] };\n const signed = (body.bids ?? [])\n .map((raw) => validateBid(raw))\n .filter((bid) => verifyBid(bid))\n .filter((bid) => bid.jobId.toLowerCase() === jobIdHex.toLowerCase())\n .filter((bid) => bid.chain === RELAY_CHAIN_STELLAR);\n const checked = await Promise.all(signed.map((bid) => this.verifyBidRegistryState(jobIdHex, bid)));\n return checked.filter((bid): bid is VerifiedBid => bid !== null);\n }\n\n async deliverPayload(args: {\n draft: RelayerJobDraft;\n bid: RelayerBid;\n gateway?: string;\n }): Promise<{ acceptedTx?: string; submittedTx?: string } | null> {\n const box = await sealBox(\n encodePoolWithdrawPayload(args.draft.payload),\n hexToBytes(args.bid.x25519Pk),\n );\n const res = await fetch(\n this.url(`v1/jobs/${encodeURIComponent(args.draft.jobIdHex)}/payload`, args.gateway ?? this.gatewayUrls[0]),\n {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ t: \"payload\", v: 1, jobId: args.draft.jobIdHex, to: args.bid.x25519Pk, box }),\n },\n );\n if (!res.ok) throw new Error(`Relayer gateway rejected payload (${res.status}).`);\n const body = (await res.json()) as {\n result?: { acceptedTx?: string; submittedTx?: string } | null;\n };\n return body.result ?? null;\n }\n\n async jobStatus(jobIdHex: string, source: string): Promise<RelayerJobStatus> {\n const job = await this.registryView<NativeRegistryJob>(source, \"get_job\", [\n bytesToScVal(hexToBytes(jobIdHex)),\n ]);\n if (!job) return \"unknown\";\n return REGISTRY_JOB_STATUS[Number(job.status)] ?? \"unknown\";\n }\n\n private async verifyBidRegistryState(\n jobIdHex: string,\n bid: RelayerBid,\n ): Promise<VerifiedBid | null> {\n try {\n const [job, relayer] = await Promise.all([\n this.registryView<NativeRegistryJob>(bid.operator, \"get_job\", [\n bytesToScVal(hexToBytes(jobIdHex)),\n ]),\n this.registryView<NativeRegistryRelayer>(bid.operator, \"get_relayer\", [\n addressToScVal(bid.operator),\n ]),\n ]);\n if (!job || !relayer) return null;\n const fee = BigInt(job.fee);\n const freeStakeValue = BigInt(relayer.free_stake);\n if (Number(job.status) !== 0 || freeStakeValue < fee) return null;\n const registeredPk = bytesToHex(Uint8Array.from(relayer.x25519_pubkey));\n if (registeredPk.toLowerCase() !== bid.x25519Pk.toLowerCase()) return null;\n return {\n ...bid,\n endpoint: relayer.endpoint?.trim() || bid.endpoint,\n freeStake: freeStakeValue.toString(),\n freeStakeValue,\n };\n } catch {\n return null;\n }\n }\n\n private async registryView<T>(\n source: string,\n method: string,\n args: Parameters<ContractInvoker[\"readNative\"]>[0][\"args\"],\n ): Promise<T | null> {\n try {\n return await this.invoker.readNative<T>({\n source,\n contractId: this.registryId,\n method,\n args,\n });\n } catch {\n return null;\n }\n }\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,106 @@
1
+ {
2
+ "name": "@opaquecash/stellar",
3
+ "version": "0.1.0",
4
+ "description": "Stealth private payments, privacy pools, relayer-market submission, and on-chain ZK reputation for Stellar/Soroban.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "keywords": [
8
+ "stellar",
9
+ "soroban",
10
+ "zk",
11
+ "zero-knowledge",
12
+ "groth16",
13
+ "privacy",
14
+ "stealth-addresses",
15
+ "privacy-pool",
16
+ "reputation"
17
+ ],
18
+ "homepage": "https://github.com/opaquecash/stellar/tree/main/sdk#readme",
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/opaquecash/stellar.git",
22
+ "directory": "sdk"
23
+ },
24
+ "bugs": {
25
+ "url": "https://github.com/opaquecash/stellar/issues"
26
+ },
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
30
+ "engines": {
31
+ "node": ">=18"
32
+ },
33
+ "sideEffects": false,
34
+ "files": [
35
+ "dist",
36
+ "README.md"
37
+ ],
38
+ "main": "./dist/index.cjs",
39
+ "module": "./dist/index.js",
40
+ "types": "./dist/index.d.ts",
41
+ "exports": {
42
+ ".": {
43
+ "import": { "types": "./dist/index.d.ts", "default": "./dist/index.js" },
44
+ "require": { "types": "./dist/index.d.cts", "default": "./dist/index.cjs" }
45
+ },
46
+ "./crypto": {
47
+ "import": { "types": "./dist/crypto/index.d.ts", "default": "./dist/crypto/index.js" },
48
+ "require": { "types": "./dist/crypto/index.d.cts", "default": "./dist/crypto/index.cjs" }
49
+ },
50
+ "./relayer-protocol": {
51
+ "import": { "types": "./dist/relayer-protocol/index.d.ts", "default": "./dist/relayer-protocol/index.js" },
52
+ "require": { "types": "./dist/relayer-protocol/index.d.cts", "default": "./dist/relayer-protocol/index.cjs" }
53
+ }
54
+ },
55
+ "scripts": {
56
+ "build": "tsup",
57
+ "clean": "rm -rf dist",
58
+ "typecheck": "tsc --noEmit",
59
+ "test": "vitest run",
60
+ "test:watch": "vitest",
61
+ "test:e2e": "vitest run tests/e2e",
62
+ "lint": "eslint src tests",
63
+ "check:exports": "publint --strict && attw --pack . --profile node16",
64
+ "docs:dev": "vitepress dev docs",
65
+ "docs:build": "vitepress build docs",
66
+ "docs:preview": "vitepress preview docs",
67
+ "prepublishOnly": "npm run typecheck && npm run build"
68
+ },
69
+ "peerDependencies": {
70
+ "@noble/curves": "^1.9.7",
71
+ "@noble/hashes": "^1.8.0",
72
+ "@stellar/stellar-sdk": "^15.1.0",
73
+ "circomlibjs": "^0.1.7",
74
+ "snarkjs": "^0.7.6",
75
+ "tweetnacl": "^1.0.3"
76
+ },
77
+ "peerDependenciesMeta": {
78
+ "snarkjs": {
79
+ "optional": true
80
+ },
81
+ "circomlibjs": {
82
+ "optional": true
83
+ },
84
+ "tweetnacl": {
85
+ "optional": true
86
+ }
87
+ },
88
+ "devDependencies": {
89
+ "@arethetypeswrong/cli": "^0.18.3",
90
+ "@eslint/js": "^9.39.4",
91
+ "@noble/curves": "^1.9.7",
92
+ "@noble/hashes": "^1.8.0",
93
+ "@stellar/stellar-sdk": "^15.1.0",
94
+ "@types/node": "^22.15.0",
95
+ "circomlibjs": "^0.1.7",
96
+ "eslint": "^9.39.4",
97
+ "publint": "^0.3.21",
98
+ "snarkjs": "^0.7.6",
99
+ "tsup": "^8.3.5",
100
+ "tweetnacl": "^1.0.3",
101
+ "typescript": "^5.8.3",
102
+ "typescript-eslint": "^8.61.1",
103
+ "vitepress": "^1.6.4",
104
+ "vitest": "^4.1.7"
105
+ }
106
+ }