@chipi-stack/backend 14.14.0 → 14.15.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/dist/index.mjs CHANGED
@@ -727,7 +727,8 @@ var ChipiClient = class {
727
727
  throw new ChipiApiError(
728
728
  errorData.message,
729
729
  errorData.code || `HTTP_${response.status}`,
730
- response.status
730
+ response.status,
731
+ data
731
732
  );
732
733
  }
733
734
  return data;
@@ -738,14 +739,15 @@ var ChipiClient = class {
738
739
  async post({
739
740
  endpoint,
740
741
  bearerToken,
741
- body
742
+ body,
743
+ headers
742
744
  }) {
743
745
  try {
744
746
  const url = new URL(`${this.baseUrl}${endpoint}`);
745
747
  this.addVersionParams(url);
746
748
  const response = await fetch(url.toString(), {
747
749
  method: "POST",
748
- headers: this.getHeaders(bearerToken),
750
+ headers: { ...headers, ...this.getHeaders(bearerToken) },
749
751
  body: body ? JSON.stringify(body) : void 0
750
752
  });
751
753
  const data = await response.json();
@@ -754,7 +756,8 @@ var ChipiClient = class {
754
756
  throw new ChipiApiError(
755
757
  errorData.message,
756
758
  errorData.code || `HTTP_${response.status}`,
757
- response.status
759
+ response.status,
760
+ data
758
761
  );
759
762
  }
760
763
  return data;
@@ -781,7 +784,8 @@ var ChipiClient = class {
781
784
  throw new ChipiApiError(
782
785
  errorData.message,
783
786
  errorData.code || `HTTP_${response.status}`,
784
- response.status
787
+ response.status,
788
+ data
785
789
  );
786
790
  }
787
791
  return data;
@@ -808,7 +812,8 @@ var ChipiClient = class {
808
812
  throw new ChipiApiError(
809
813
  errorData.message,
810
814
  errorData.code || `HTTP_${response.status}`,
811
- response.status
815
+ response.status,
816
+ data
812
817
  );
813
818
  }
814
819
  return data;
@@ -833,7 +838,8 @@ var ChipiClient = class {
833
838
  throw new ChipiApiError(
834
839
  errorData.message,
835
840
  errorData.code || `HTTP_${response.status}`,
836
- response.status
841
+ response.status,
842
+ data
837
843
  );
838
844
  }
839
845
  return data;
@@ -3108,8 +3114,149 @@ var ChipiTreasury = class {
3108
3114
  };
3109
3115
  }
3110
3116
  };
3117
+ var DEFAULT_RETRY_INTERVAL_MS = 3e3;
3118
+ var DEFAULT_TIMEOUT_MS = 3e5;
3119
+ function isPending(finalityStatus) {
3120
+ return finalityStatus === void 0 || finalityStatus === "RECEIVED" || finalityStatus === "PENDING" || finalityStatus === "PRE_CONFIRMED";
3121
+ }
3122
+ async function waitForTransaction(transactionHash, options = {}) {
3123
+ const {
3124
+ nodeUrl = WALLET_RPC_ENDPOINTS.CHIPI,
3125
+ retryIntervalMs = DEFAULT_RETRY_INTERVAL_MS,
3126
+ timeoutMs = DEFAULT_TIMEOUT_MS
3127
+ } = options;
3128
+ const deadline = Date.now() + timeoutMs;
3129
+ let lastError;
3130
+ for (; ; ) {
3131
+ try {
3132
+ const receipt = await withRpcFallback(
3133
+ (provider) => provider.getTransactionReceipt(transactionHash),
3134
+ { fallbackUrl: nodeUrl }
3135
+ );
3136
+ if (!isPending(receipt?.finality_status)) {
3137
+ const reverted = receipt.execution_status === "REVERTED";
3138
+ return {
3139
+ transactionHash,
3140
+ success: !reverted,
3141
+ executionStatus: receipt.execution_status,
3142
+ finalityStatus: receipt.finality_status,
3143
+ ...reverted ? { revertReason: receipt.revert_reason ?? "reverted on chain" } : {},
3144
+ events: receipt.events ?? [],
3145
+ ...receipt.block_number !== void 0 ? { blockNumber: receipt.block_number } : {}
3146
+ };
3147
+ }
3148
+ } catch (err) {
3149
+ lastError = err;
3150
+ }
3151
+ if (Date.now() + retryIntervalMs >= deadline) {
3152
+ const detail = lastError instanceof Error ? `: ${lastError.message}` : "";
3153
+ throw new Error(
3154
+ `Timed out after ${timeoutMs}ms waiting for ${transactionHash}${detail}. The transaction may still land; re-check before treating it as failed.`
3155
+ );
3156
+ }
3157
+ await new Promise((resolve) => setTimeout(resolve, retryIntervalMs));
3158
+ }
3159
+ }
3160
+ var InMemoryTxHashStore = class {
3161
+ constructor() {
3162
+ this.used = /* @__PURE__ */ new Set();
3163
+ }
3164
+ consume(transactionHash) {
3165
+ if (this.used.has(transactionHash)) return false;
3166
+ this.used.add(transactionHash);
3167
+ return true;
3168
+ }
3169
+ };
3170
+ var TRANSFER_SELECTOR = BigInt(hash.getSelectorFromName("Transfer"));
3171
+ function toBigInt2(value) {
3172
+ if (value === void 0) return void 0;
3173
+ try {
3174
+ return BigInt(value);
3175
+ } catch {
3176
+ return void 0;
3177
+ }
3178
+ }
3179
+ function decodeTransfer(event) {
3180
+ if (toBigInt2(event.keys[0]) !== TRANSFER_SELECTOR) return void 0;
3181
+ const [from, to, low, high] = event.keys.length >= 3 ? [event.keys[1], event.keys[2], event.data[0], event.data[1]] : [event.data[0], event.data[1], event.data[2], event.data[3]];
3182
+ const values = [from, to, low, high].map(toBigInt2);
3183
+ if (values.some((v) => v === void 0)) return void 0;
3184
+ const [f, t, l, h] = values;
3185
+ return { from: f, to: t, amount: l + (h << 128n) };
3186
+ }
3187
+ var SessionTxVerifier = class {
3188
+ constructor(config = {}) {
3189
+ const { txHashStore, getReceipt, ...receiptOptions } = config;
3190
+ this.store = txHashStore ?? new InMemoryTxHashStore();
3191
+ this.getReceipt = getReceipt ?? waitForTransaction;
3192
+ this.receiptOptions = receiptOptions;
3193
+ }
3194
+ async verifyTransfer(params) {
3195
+ const { transactionHash, token, from, to, minAmount } = params;
3196
+ const receipt = await this.getReceipt(transactionHash, this.receiptOptions);
3197
+ if (!receipt.success) {
3198
+ return { valid: false, transactionHash, reason: "REVERTED", detail: receipt.revertReason };
3199
+ }
3200
+ const tokenAddress = BigInt(token);
3201
+ const fromAddress = BigInt(from);
3202
+ const toAddress = BigInt(to);
3203
+ let best;
3204
+ for (const event of receipt.events) {
3205
+ if (toBigInt2(event.from_address) !== tokenAddress) continue;
3206
+ const transfer = decodeTransfer(event);
3207
+ if (!transfer || transfer.from !== fromAddress || transfer.to !== toAddress) continue;
3208
+ if (best === void 0 || transfer.amount > best) best = transfer.amount;
3209
+ }
3210
+ if (best === void 0) {
3211
+ return { valid: false, transactionHash, reason: "TRANSFER_NOT_FOUND" };
3212
+ }
3213
+ if (best < minAmount) {
3214
+ return {
3215
+ valid: false,
3216
+ transactionHash,
3217
+ reason: "AMOUNT_TOO_LOW",
3218
+ detail: `paid ${best}, expected at least ${minAmount}`
3219
+ };
3220
+ }
3221
+ const key = "0x" + BigInt(transactionHash).toString(16);
3222
+ if (!await this.store.consume(key)) {
3223
+ return { valid: false, transactionHash, reason: "ALREADY_USED" };
3224
+ }
3225
+ return {
3226
+ valid: true,
3227
+ transactionHash,
3228
+ amount: best,
3229
+ ...receipt.blockNumber !== void 0 ? { blockNumber: receipt.blockNumber } : {}
3230
+ };
3231
+ }
3232
+ };
3233
+
3234
+ // src/ai.ts
3111
3235
  var AI_BASE = "/ai";
3112
3236
  var THINK_ACTIONS = /* @__PURE__ */ new Set(["swap", "supply", "withdraw", "hold"]);
3237
+ var PAID_MAX_ATTEMPTS = 3;
3238
+ var PAID_RETRY_DELAY_MS = 5e3;
3239
+ var padFelt = (value) => "0x" + BigInt(value).toString(16).padStart(64, "0");
3240
+ function sameFelt(a, b) {
3241
+ try {
3242
+ return BigInt(a) === BigInt(b);
3243
+ } catch {
3244
+ return false;
3245
+ }
3246
+ }
3247
+ function sessionTransferOffer(err) {
3248
+ if (!(err instanceof ChipiApiError) || err.status !== 402) return void 0;
3249
+ const details = err.details;
3250
+ return details?.x402?.accepts?.find(
3251
+ (r) => r.scheme === "exact" && r.network === "starknet-mainnet" && r.extra?.paymentMethod === "session-transfer" && sameFelt(r.asset, CONTRACT_ADDRESSES.USDC_MAINNET)
3252
+ );
3253
+ }
3254
+ function thinkInputBytes(params) {
3255
+ const bytes = (text) => new TextEncoder().encode(text).length;
3256
+ const chain = params.chain ?? "starknet";
3257
+ return bytes(JSON.stringify(params.portfolio, null, 2)) + (params.history?.recentDecisions ? bytes(String(params.history.recentDecisions)) : 0) + 2 * bytes(chain);
3258
+ }
3259
+ var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
3113
3260
  function isThinkDecision(decision) {
3114
3261
  if (!decision || typeof decision !== "object") return false;
3115
3262
  const d = decision;
@@ -3123,9 +3270,10 @@ function isThinkDecision(decision) {
3123
3270
  return true;
3124
3271
  }
3125
3272
  var ChipiAi = class {
3126
- constructor(client, apiSecretKey) {
3273
+ constructor(client, apiSecretKey, sessions) {
3127
3274
  this.client = client;
3128
3275
  this.apiSecretKey = apiSecretKey;
3276
+ this.sessions = sessions;
3129
3277
  }
3130
3278
  secret() {
3131
3279
  const key = this.apiSecretKey;
@@ -3156,13 +3304,175 @@ var ChipiAi = class {
3156
3304
  *
3157
3305
  * The decision is advice, not an order: check it with `isThinkDecision` and
3158
3306
  * enforce your own limits before executing anything.
3307
+ *
3308
+ * **Paying per call (x402).** With `payWithSession`, a 402 that carries a
3309
+ * session-transfer offer (credits short, x402 on) is paid with the agent's
3310
+ * session key: a USDC `transfer` to the offer's `payTo`, then the same call
3311
+ * again with `X-PAYMENT`. The price must be at most `maxAmount`, `model`
3312
+ * must be payable and the input within `maxPromptBytes`, all checked before
3313
+ * paying. The session must whitelist `transfer` and cap USDC. A payment
3314
+ * that was made but not served is reported in `error.details.xPayment`;
3315
+ * pass it back as `options.xPayment` to retry without paying again.
3316
+ *
3317
+ * @example
3318
+ * ```typescript
3319
+ * const res = await sdk.ai.think(
3320
+ * { portfolio, model: "haiku" },
3321
+ * { payWithSession: { encryptKey, wallet, session, maxAmount: 20_000n } } // $0.02 at most
3322
+ * );
3323
+ * res.x402Payment; // set when the call was paid over x402
3324
+ * ```
3159
3325
  */
3160
- async think(params) {
3326
+ async think(params, options = {}) {
3327
+ try {
3328
+ return await this.postThink(params, options.xPayment);
3329
+ } catch (err) {
3330
+ const offer = options.payWithSession ? sessionTransferOffer(err) : void 0;
3331
+ if (!offer || !options.payWithSession) throw err;
3332
+ return this.payAndThink(params, offer, options.payWithSession);
3333
+ }
3334
+ }
3335
+ postThink(params, xPayment) {
3161
3336
  return this.client.post({
3162
3337
  endpoint: `${AI_BASE}/think`,
3163
3338
  bearerToken: this.secret(),
3164
- body: params
3339
+ body: params,
3340
+ ...xPayment ? { headers: { "X-PAYMENT": xPayment } } : {}
3341
+ });
3342
+ }
3343
+ /**
3344
+ * Pay one think call with a session-key USDC transfer, then send it again
3345
+ * with `X-PAYMENT`. Every check that can refuse the call runs before the
3346
+ * transfer; the transfer counts only once its receipt shows the USDC moved.
3347
+ */
3348
+ async payAndThink(params, offer, pay) {
3349
+ if (!this.sessions) {
3350
+ throw new ChipiApiError(
3351
+ "payWithSession needs the SDK's session client",
3352
+ "X402_NOT_CONFIGURED",
3353
+ 402
3354
+ );
3355
+ }
3356
+ let maxAmount;
3357
+ try {
3358
+ maxAmount = BigInt(pay.maxAmount);
3359
+ } catch {
3360
+ throw new ChipiApiError(
3361
+ `maxAmount must be an integer of USDC base units (6 decimals), got ${String(pay.maxAmount)}; nothing was paid`,
3362
+ "X402_INVALID_MAX_AMOUNT",
3363
+ 400
3364
+ );
3365
+ }
3366
+ const amount = BigInt(offer.maxAmountRequired);
3367
+ if (amount > maxAmount) {
3368
+ throw new ChipiApiError(
3369
+ `The x402 price (${amount} USDC base units) is above maxAmount (${pay.maxAmount}); nothing was paid`,
3370
+ "X402_PRICE_ABOVE_MAX",
3371
+ 402,
3372
+ { x402: { accepts: [offer] } }
3373
+ );
3374
+ }
3375
+ const payable = offer.extra?.payableModels;
3376
+ if (params.model && Array.isArray(payable) && !payable.includes(params.model)) {
3377
+ throw new ChipiApiError(
3378
+ `Model ${params.model} cannot be paid with x402 (payable: ${payable.join(", ")}); nothing was paid`,
3379
+ "X402_MODEL_NOT_PAYABLE",
3380
+ 402,
3381
+ { x402: { accepts: [offer] } }
3382
+ );
3383
+ }
3384
+ const maxBytes = offer.extra?.maxPromptBytes;
3385
+ if (typeof maxBytes === "number" && thinkInputBytes(params) > maxBytes) {
3386
+ throw new ChipiApiError(
3387
+ `Paid calls accept at most ${maxBytes} bytes of portfolio, history and chain; nothing was paid`,
3388
+ "X402_PAYLOAD_TOO_LARGE",
3389
+ 402,
3390
+ { x402: { accepts: [offer] } }
3391
+ );
3392
+ }
3393
+ const payer = pay.wallet.publicKey;
3394
+ const mask = (1n << 128n) - 1n;
3395
+ const transactionHash = await this.sessions.executeTransactionWithSession(
3396
+ {
3397
+ encryptKey: pay.encryptKey,
3398
+ wallet: pay.wallet,
3399
+ session: pay.session,
3400
+ calls: [
3401
+ {
3402
+ contractAddress: offer.asset,
3403
+ entrypoint: "transfer",
3404
+ calldata: [offer.payTo, (amount & mask).toString(), (amount >> 128n).toString()]
3405
+ }
3406
+ ]
3407
+ },
3408
+ this.secret()
3409
+ );
3410
+ const header = {
3411
+ x402Version: 1,
3412
+ scheme: "exact",
3413
+ network: "starknet-mainnet",
3414
+ payload: {
3415
+ signature: { r: padFelt(transactionHash), s: "session" },
3416
+ fromAddress: padFelt(payer),
3417
+ toAddress: padFelt(offer.payTo),
3418
+ amount: amount.toString(),
3419
+ asset: offer.asset,
3420
+ validUntil: Math.floor(Date.now() / 1e3) + offer.maxTimeoutSeconds,
3421
+ nonce: padFelt(transactionHash)
3422
+ }
3423
+ };
3424
+ const xPayment = JSON.stringify(header);
3425
+ const paidError = (message, code, extra = {}) => new ChipiApiError(message, code, 402, {
3426
+ x402: { accepts: [offer] },
3427
+ x402PaymentHash: transactionHash,
3428
+ ...extra
3165
3429
  });
3430
+ let receipt;
3431
+ try {
3432
+ receipt = await waitForTransaction(transactionHash, { timeoutMs: 12e4 });
3433
+ } catch (err) {
3434
+ throw paidError(
3435
+ `No receipt yet for the x402 payment ${transactionHash}: ${err instanceof Error ? err.message : String(err)}`,
3436
+ "X402_PAYMENT_PENDING",
3437
+ { xPayment }
3438
+ );
3439
+ }
3440
+ const paid = await new SessionTxVerifier({
3441
+ txHashStore: { consume: () => true },
3442
+ getReceipt: async () => receipt
3443
+ }).verifyTransfer({
3444
+ transactionHash,
3445
+ token: offer.asset,
3446
+ from: payer,
3447
+ to: offer.payTo,
3448
+ minAmount: amount
3449
+ });
3450
+ if (!paid.valid) {
3451
+ throw paidError(
3452
+ `The x402 payment did not move ${amount} USDC base units to payTo (${paid.reason}). Check the session's whitelist (transfer) and its USDC cap.`,
3453
+ "X402_PAYMENT_FAILED",
3454
+ { reason: paid.reason }
3455
+ );
3456
+ }
3457
+ for (let attempt = 1; ; attempt++) {
3458
+ try {
3459
+ return await this.postThink(params, xPayment);
3460
+ } catch (err) {
3461
+ const retryable = err instanceof ChipiApiError && (err.status === 409 || err.status === 503 && err.details?.retryable === true);
3462
+ if (retryable && attempt < PAID_MAX_ATTEMPTS) {
3463
+ await sleep(PAID_RETRY_DELAY_MS);
3464
+ continue;
3465
+ }
3466
+ if (err instanceof ChipiApiError) {
3467
+ throw new ChipiApiError(err.message, err.code, err.status ?? 402, {
3468
+ ...typeof err.details === "object" && err.details !== null ? err.details : {},
3469
+ x402PaymentHash: transactionHash,
3470
+ xPayment
3471
+ });
3472
+ }
3473
+ throw err;
3474
+ }
3475
+ }
3166
3476
  }
3167
3477
  /**
3168
3478
  * `POST /v1/ai/execute`: unsigned AVNU swap calls (approve + swap) for
@@ -3524,7 +3834,7 @@ var ChipiSDK = class {
3524
3834
  this.sessions = new ChipiSessions(this.client);
3525
3835
  this.exchanges = new ChipiExchanges(this.client);
3526
3836
  this.treasury = new ChipiTreasury(this.client, config.apiSecretKey);
3527
- this.ai = new ChipiAi(this.client, config.apiSecretKey);
3837
+ this.ai = new ChipiAi(this.client, config.apiSecretKey, this.sessions);
3528
3838
  this.executeTransaction = this.executeTransaction.bind(this);
3529
3839
  this.executeTransactionWithSession = this.executeTransactionWithSession.bind(this);
3530
3840
  this.transfer = this.transfer.bind(this);
@@ -3837,49 +4147,6 @@ var ChipiBrowserSDK = class extends ChipiSDK {
3837
4147
  // All methods are inherited from ChipiSDK
3838
4148
  // bearerToken parameter is required for each authenticated request
3839
4149
  };
3840
- var DEFAULT_RETRY_INTERVAL_MS = 3e3;
3841
- var DEFAULT_TIMEOUT_MS = 3e5;
3842
- function isPending(finalityStatus) {
3843
- return finalityStatus === void 0 || finalityStatus === "RECEIVED" || finalityStatus === "PENDING" || finalityStatus === "PRE_CONFIRMED";
3844
- }
3845
- async function waitForTransaction(transactionHash, options = {}) {
3846
- const {
3847
- nodeUrl = WALLET_RPC_ENDPOINTS.CHIPI,
3848
- retryIntervalMs = DEFAULT_RETRY_INTERVAL_MS,
3849
- timeoutMs = DEFAULT_TIMEOUT_MS
3850
- } = options;
3851
- const deadline = Date.now() + timeoutMs;
3852
- let lastError;
3853
- for (; ; ) {
3854
- try {
3855
- const receipt = await withRpcFallback(
3856
- (provider) => provider.getTransactionReceipt(transactionHash),
3857
- { fallbackUrl: nodeUrl }
3858
- );
3859
- if (!isPending(receipt?.finality_status)) {
3860
- const reverted = receipt.execution_status === "REVERTED";
3861
- return {
3862
- transactionHash,
3863
- success: !reverted,
3864
- executionStatus: receipt.execution_status,
3865
- finalityStatus: receipt.finality_status,
3866
- ...reverted ? { revertReason: receipt.revert_reason ?? "reverted on chain" } : {},
3867
- events: receipt.events ?? [],
3868
- ...receipt.block_number !== void 0 ? { blockNumber: receipt.block_number } : {}
3869
- };
3870
- }
3871
- } catch (err) {
3872
- lastError = err;
3873
- }
3874
- if (Date.now() + retryIntervalMs >= deadline) {
3875
- const detail = lastError instanceof Error ? `: ${lastError.message}` : "";
3876
- throw new Error(
3877
- `Timed out after ${timeoutMs}ms waiting for ${transactionHash}${detail}. The transaction may still land; re-check before treating it as failed.`
3878
- );
3879
- }
3880
- await new Promise((resolve) => setTimeout(resolve, retryIntervalMs));
3881
- }
3882
- }
3883
4150
 
3884
4151
  // src/index.ts
3885
4152
  init_encryption2();
@@ -4204,79 +4471,6 @@ function x402Middleware(config) {
4204
4471
  next();
4205
4472
  };
4206
4473
  }
4207
- var InMemoryTxHashStore = class {
4208
- constructor() {
4209
- this.used = /* @__PURE__ */ new Set();
4210
- }
4211
- consume(transactionHash) {
4212
- if (this.used.has(transactionHash)) return false;
4213
- this.used.add(transactionHash);
4214
- return true;
4215
- }
4216
- };
4217
- var TRANSFER_SELECTOR = BigInt(hash.getSelectorFromName("Transfer"));
4218
- function toBigInt2(value) {
4219
- if (value === void 0) return void 0;
4220
- try {
4221
- return BigInt(value);
4222
- } catch {
4223
- return void 0;
4224
- }
4225
- }
4226
- function decodeTransfer(event) {
4227
- if (toBigInt2(event.keys[0]) !== TRANSFER_SELECTOR) return void 0;
4228
- const [from, to, low, high] = event.keys.length >= 3 ? [event.keys[1], event.keys[2], event.data[0], event.data[1]] : [event.data[0], event.data[1], event.data[2], event.data[3]];
4229
- const values = [from, to, low, high].map(toBigInt2);
4230
- if (values.some((v) => v === void 0)) return void 0;
4231
- const [f, t, l, h] = values;
4232
- return { from: f, to: t, amount: l + (h << 128n) };
4233
- }
4234
- var SessionTxVerifier = class {
4235
- constructor(config = {}) {
4236
- const { txHashStore, getReceipt, ...receiptOptions } = config;
4237
- this.store = txHashStore ?? new InMemoryTxHashStore();
4238
- this.getReceipt = getReceipt ?? waitForTransaction;
4239
- this.receiptOptions = receiptOptions;
4240
- }
4241
- async verifyTransfer(params) {
4242
- const { transactionHash, token, from, to, minAmount } = params;
4243
- const receipt = await this.getReceipt(transactionHash, this.receiptOptions);
4244
- if (!receipt.success) {
4245
- return { valid: false, transactionHash, reason: "REVERTED", detail: receipt.revertReason };
4246
- }
4247
- const tokenAddress = BigInt(token);
4248
- const fromAddress = BigInt(from);
4249
- const toAddress = BigInt(to);
4250
- let best;
4251
- for (const event of receipt.events) {
4252
- if (toBigInt2(event.from_address) !== tokenAddress) continue;
4253
- const transfer = decodeTransfer(event);
4254
- if (!transfer || transfer.from !== fromAddress || transfer.to !== toAddress) continue;
4255
- if (best === void 0 || transfer.amount > best) best = transfer.amount;
4256
- }
4257
- if (best === void 0) {
4258
- return { valid: false, transactionHash, reason: "TRANSFER_NOT_FOUND" };
4259
- }
4260
- if (best < minAmount) {
4261
- return {
4262
- valid: false,
4263
- transactionHash,
4264
- reason: "AMOUNT_TOO_LOW",
4265
- detail: `paid ${best}, expected at least ${minAmount}`
4266
- };
4267
- }
4268
- const key = "0x" + BigInt(transactionHash).toString(16);
4269
- if (!await this.store.consume(key)) {
4270
- return { valid: false, transactionHash, reason: "ALREADY_USED" };
4271
- }
4272
- return {
4273
- valid: true,
4274
- transactionHash,
4275
- amount: best,
4276
- ...receipt.blockNumber !== void 0 ? { blockNumber: receipt.blockNumber } : {}
4277
- };
4278
- }
4279
- };
4280
4474
 
4281
4475
  // src/shhh/index.ts
4282
4476
  init_snip12_hash();