@chipi-stack/backend 14.13.1 → 14.14.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.js CHANGED
@@ -1952,14 +1952,14 @@ var ChipiTransactions = class {
1952
1952
  /**
1953
1953
  * Get on-chain transaction status
1954
1954
  */
1955
- async getTransactionStatus(hash10, bearerToken) {
1955
+ async getTransactionStatus(hash11, bearerToken) {
1956
1956
  return this.client.get({
1957
- endpoint: `${shared.API_ENDPOINTS.TRANSACTIONS}/${hash10}/status`,
1957
+ endpoint: `${shared.API_ENDPOINTS.TRANSACTIONS}/${hash11}/status`,
1958
1958
  bearerToken
1959
1959
  });
1960
1960
  }
1961
1961
  /**
1962
- * Sync on-chain transfers from Voyager into the DB (read-through cache).
1962
+ * Sync on-chain transfers (Starknet Transfer events) into the DB (read-through cache).
1963
1963
  * Discovers transactions not made through the SDK (e.g., external USDC receives).
1964
1964
  * After sync, getTransactionList returns the newly discovered transactions.
1965
1965
  */
@@ -2158,6 +2158,108 @@ function decodeSessionData(result, nowSeconds) {
2158
2158
  const isActive = validUntil !== 0 && nowSeconds <= validUntil && remainingCalls > 0;
2159
2159
  return { isActive, validUntil, remainingCalls, allowedEntrypoints: [] };
2160
2160
  }
2161
+ var U128_MASK = (1n << 128n) - 1n;
2162
+ var U256_MAX = (1n << 256n) - 1n;
2163
+ var U64_MAX = (1n << 64n) - 1n;
2164
+ function splitU256(value) {
2165
+ return [starknet.num.toHex(value & U128_MASK), starknet.num.toHex(value >> 128n)];
2166
+ }
2167
+ function buildAddSessionKeyCall(walletAddress, sessionConfig) {
2168
+ const allowedEntrypoints = normalizeEntrypoints(sessionConfig.allowedEntrypoints);
2169
+ return {
2170
+ contractAddress: walletAddress,
2171
+ entrypoint: shared.SESSION_ENTRYPOINTS.ADD_OR_UPDATE,
2172
+ calldata: [
2173
+ sessionConfig.sessionPublicKey,
2174
+ starknet.num.toHex(sessionConfig.validUntil),
2175
+ starknet.num.toHex(sessionConfig.maxCalls),
2176
+ starknet.num.toHex(allowedEntrypoints.length),
2177
+ ...allowedEntrypoints
2178
+ ]
2179
+ };
2180
+ }
2181
+ function buildRevokeSessionKeyCall(walletAddress, sessionPublicKey) {
2182
+ return {
2183
+ contractAddress: walletAddress,
2184
+ entrypoint: shared.SESSION_ENTRYPOINTS.REVOKE,
2185
+ calldata: [sessionPublicKey]
2186
+ };
2187
+ }
2188
+ function validateSpendingPolicyConfig(config) {
2189
+ const { token, maxPerCall, maxPerWindow, windowSeconds } = config;
2190
+ if (!token || token.trim().length === 0) {
2191
+ throw new shared.ChipiSessionError(
2192
+ `Invalid token address for spending policy: "${token}"`,
2193
+ shared.SESSION_ERRORS.INVALID_SPENDING_POLICY
2194
+ );
2195
+ }
2196
+ if (typeof windowSeconds !== "number" || !Number.isFinite(windowSeconds) || !Number.isInteger(windowSeconds) || windowSeconds <= 0 || BigInt(windowSeconds) > U64_MAX) {
2197
+ throw new shared.ChipiSessionError(
2198
+ `Invalid window duration: ${windowSeconds}. Must be a positive integer within u64 range.`,
2199
+ shared.SESSION_ERRORS.INVALID_SPENDING_POLICY
2200
+ );
2201
+ }
2202
+ if (maxPerCall < 0n || maxPerCall > U256_MAX) {
2203
+ throw new shared.ChipiSessionError(
2204
+ `Invalid maxPerCall: must be >= 0 and <= 2^256 - 1`,
2205
+ shared.SESSION_ERRORS.INVALID_SPENDING_POLICY
2206
+ );
2207
+ }
2208
+ if (maxPerWindow < 0n || maxPerWindow > U256_MAX) {
2209
+ throw new shared.ChipiSessionError(
2210
+ `Invalid maxPerWindow: must be >= 0 and <= 2^256 - 1`,
2211
+ shared.SESSION_ERRORS.INVALID_SPENDING_POLICY
2212
+ );
2213
+ }
2214
+ if (maxPerWindow > 0n && maxPerCall > maxPerWindow) {
2215
+ throw new shared.ChipiSessionError(
2216
+ `Invalid spending policy: maxPerCall (${maxPerCall}) cannot exceed maxPerWindow (${maxPerWindow})`,
2217
+ shared.SESSION_ERRORS.INVALID_SPENDING_POLICY
2218
+ );
2219
+ }
2220
+ }
2221
+ function buildSetSpendingPolicyCall(walletAddress, config) {
2222
+ validateSpendingPolicyConfig(config);
2223
+ const [maxPerCallLow, maxPerCallHigh] = splitU256(config.maxPerCall);
2224
+ const [maxPerWindowLow, maxPerWindowHigh] = splitU256(config.maxPerWindow);
2225
+ return {
2226
+ contractAddress: walletAddress,
2227
+ entrypoint: shared.SESSION_ENTRYPOINTS.SET_SPENDING_POLICY,
2228
+ calldata: [
2229
+ config.sessionPublicKey,
2230
+ config.token,
2231
+ maxPerCallLow,
2232
+ maxPerCallHigh,
2233
+ maxPerWindowLow,
2234
+ maxPerWindowHigh,
2235
+ starknet.num.toHex(config.windowSeconds)
2236
+ ]
2237
+ };
2238
+ }
2239
+ function buildRemoveSpendingPolicyCall(walletAddress, sessionPublicKey, token) {
2240
+ if (!token || token.trim().length === 0) {
2241
+ throw new shared.ChipiSessionError(
2242
+ `Invalid token address for spending policy removal: "${token}"`,
2243
+ shared.SESSION_ERRORS.INVALID_SPENDING_POLICY
2244
+ );
2245
+ }
2246
+ return {
2247
+ contractAddress: walletAddress,
2248
+ entrypoint: shared.SESSION_ENTRYPOINTS.REMOVE_SPENDING_POLICY,
2249
+ calldata: [sessionPublicKey, token]
2250
+ };
2251
+ }
2252
+ function buildSessionSetupCalls(walletAddress, sessionConfig, spendingPolicies = []) {
2253
+ return [
2254
+ buildAddSessionKeyCall(walletAddress, sessionConfig),
2255
+ ...spendingPolicies.map(
2256
+ (policy) => buildSetSpendingPolicyCall(walletAddress, {
2257
+ ...policy,
2258
+ sessionPublicKey: sessionConfig.sessionPublicKey
2259
+ })
2260
+ )
2261
+ ];
2262
+ }
2161
2263
 
2162
2264
  // src/sessions.ts
2163
2265
  var ChipiSessions = class {
@@ -2299,26 +2401,12 @@ var ChipiSessions = class {
2299
2401
  maxCalls: sessionConfig.maxCalls,
2300
2402
  allowedEntrypoints: sessionConfig.allowedEntrypoints.length
2301
2403
  });
2302
- const allowedEntrypoints = normalizeEntrypoints(sessionConfig.allowedEntrypoints);
2303
- const calldata = [
2304
- sessionConfig.sessionPublicKey,
2305
- starknet.num.toHex(sessionConfig.validUntil),
2306
- starknet.num.toHex(sessionConfig.maxCalls),
2307
- // Array: first element is length, then elements
2308
- starknet.num.toHex(allowedEntrypoints.length),
2309
- ...allowedEntrypoints
2310
- ];
2404
+ const addCall = buildAddSessionKeyCall(wallet.publicKey, sessionConfig);
2311
2405
  const txHash = await executePaymasterTransaction({
2312
2406
  params: {
2313
2407
  encryptKey,
2314
2408
  wallet,
2315
- calls: [
2316
- {
2317
- contractAddress: wallet.publicKey,
2318
- entrypoint: shared.SESSION_ENTRYPOINTS.ADD_OR_UPDATE,
2319
- calldata
2320
- }
2321
- ],
2409
+ calls: [addCall],
2322
2410
  saveToDatabase: false
2323
2411
  // Don't record session management txs
2324
2412
  },
@@ -2342,6 +2430,54 @@ var ChipiSessions = class {
2342
2430
  throw error;
2343
2431
  }
2344
2432
  }
2433
+ /**
2434
+ * Register a session and its spending policies in ONE owner-signed transaction.
2435
+ *
2436
+ * Equivalent to `addSessionKeyToContract` followed by one `setSpendingPolicy`
2437
+ * per token, but the owner signs once (one passkey prompt) and the session
2438
+ * never exists on-chain without its caps.
2439
+ *
2440
+ * @example
2441
+ * ```typescript
2442
+ * const txHash = await sdk.sessions.setupSession({
2443
+ * encryptKey,
2444
+ * wallet,
2445
+ * sessionConfig: {
2446
+ * sessionPublicKey: session.publicKey,
2447
+ * validUntil: session.validUntil,
2448
+ * maxCalls: 500,
2449
+ * allowedEntrypoints: ["transfer", "approve"],
2450
+ * },
2451
+ * spendingPolicies: [
2452
+ * { token: USDC, maxPerCall: 5_000_000n, maxPerWindow: 20_000_000n, windowSeconds: 86400 },
2453
+ * ],
2454
+ * }, bearerToken);
2455
+ * ```
2456
+ */
2457
+ async setupSession(params, bearerToken) {
2458
+ const { encryptKey, wallet, sessionConfig, spendingPolicies = [] } = params;
2459
+ this.validateWalletSupportsSessions(wallet.walletType, "Setup", wallet.publicKey);
2460
+ const calls = buildSessionSetupCalls(wallet.publicKey, sessionConfig, spendingPolicies);
2461
+ console.log("[ChipiSDK:Session:Setup] Registering session with spending policies", {
2462
+ walletAddress: wallet.publicKey.slice(0, 15) + "...",
2463
+ sessionPubKey: sessionConfig.sessionPublicKey.slice(0, 15) + "...",
2464
+ validUntil: new Date(sessionConfig.validUntil * 1e3).toISOString(),
2465
+ maxCalls: sessionConfig.maxCalls,
2466
+ allowedEntrypoints: sessionConfig.allowedEntrypoints.length,
2467
+ spendingPolicies: spendingPolicies.length
2468
+ });
2469
+ return executePaymasterTransaction({
2470
+ params: {
2471
+ encryptKey,
2472
+ wallet,
2473
+ calls,
2474
+ saveToDatabase: false
2475
+ // Don't record session management txs
2476
+ },
2477
+ bearerToken,
2478
+ client: this.client
2479
+ });
2480
+ }
2345
2481
  /**
2346
2482
  * Revoke a session key from the smart contract.
2347
2483
  *
@@ -2375,13 +2511,7 @@ var ChipiSessions = class {
2375
2511
  params: {
2376
2512
  encryptKey,
2377
2513
  wallet,
2378
- calls: [
2379
- {
2380
- contractAddress: wallet.publicKey,
2381
- entrypoint: shared.SESSION_ENTRYPOINTS.REVOKE,
2382
- calldata: [sessionPublicKey]
2383
- }
2384
- ],
2514
+ calls: [buildRevokeSessionKeyCall(wallet.publicKey, sessionPublicKey)],
2385
2515
  saveToDatabase: false
2386
2516
  // Don't record session management txs
2387
2517
  },
@@ -2571,13 +2701,6 @@ var ChipiSessions = class {
2571
2701
  // Wraps ISessionSpendingPolicy contract interface.
2572
2702
  // Spending policies enforce per-token limits on ERC-20 operations
2573
2703
  // (transfer, approve, increase_allowance) executed by session keys.
2574
- /**
2575
- * Split a bigint into Cairo u256 representation (low u128, high u128).
2576
- */
2577
- splitU256(value) {
2578
- const mask = (1n << 128n) - 1n;
2579
- return [starknet.num.toHex(value & mask), starknet.num.toHex(value >> 128n)];
2580
- }
2581
2704
  /**
2582
2705
  * Reconstruct a bigint from Cairo u256 (low, high) hex strings.
2583
2706
  */
@@ -2622,38 +2745,7 @@ var ChipiSessions = class {
2622
2745
  shared.SESSION_ERRORS.INVALID_WALLET_TYPE_FOR_SESSION
2623
2746
  );
2624
2747
  }
2625
- const U256_MAX = (1n << 256n) - 1n;
2626
- const U64_MAX = (1n << 64n) - 1n;
2627
- if (!token || token.trim().length === 0) {
2628
- throw new shared.ChipiSessionError(
2629
- `Invalid token address for spending policy: "${token}"`,
2630
- shared.SESSION_ERRORS.INVALID_SPENDING_POLICY
2631
- );
2632
- }
2633
- if (typeof windowSeconds !== "number" || !Number.isFinite(windowSeconds) || !Number.isInteger(windowSeconds) || windowSeconds <= 0 || BigInt(windowSeconds) > U64_MAX) {
2634
- throw new shared.ChipiSessionError(
2635
- `Invalid window duration: ${windowSeconds}. Must be a positive integer within u64 range.`,
2636
- shared.SESSION_ERRORS.INVALID_SPENDING_POLICY
2637
- );
2638
- }
2639
- if (maxPerCall < 0n || maxPerCall > U256_MAX) {
2640
- throw new shared.ChipiSessionError(
2641
- `Invalid maxPerCall: must be >= 0 and <= 2^256 - 1`,
2642
- shared.SESSION_ERRORS.INVALID_SPENDING_POLICY
2643
- );
2644
- }
2645
- if (maxPerWindow < 0n || maxPerWindow > U256_MAX) {
2646
- throw new shared.ChipiSessionError(
2647
- `Invalid maxPerWindow: must be >= 0 and <= 2^256 - 1`,
2648
- shared.SESSION_ERRORS.INVALID_SPENDING_POLICY
2649
- );
2650
- }
2651
- if (maxPerWindow > 0n && maxPerCall > maxPerWindow) {
2652
- throw new shared.ChipiSessionError(
2653
- `Invalid spending policy: maxPerCall (${maxPerCall}) cannot exceed maxPerWindow (${maxPerWindow})`,
2654
- shared.SESSION_ERRORS.INVALID_SPENDING_POLICY
2655
- );
2656
- }
2748
+ validateSpendingPolicyConfig(spendingPolicyConfig);
2657
2749
  try {
2658
2750
  console.log("[ChipiSDK:Session:SetSpendingPolicy] Setting spending policy", {
2659
2751
  walletAddress: wallet.publicKey.slice(0, 15) + "...",
@@ -2663,28 +2755,12 @@ var ChipiSessions = class {
2663
2755
  maxPerWindow: maxPerWindow.toString(),
2664
2756
  windowSeconds
2665
2757
  });
2666
- const [maxPerCallLow, maxPerCallHigh] = this.splitU256(maxPerCall);
2667
- const [maxPerWindowLow, maxPerWindowHigh] = this.splitU256(maxPerWindow);
2668
- const calldata = [
2669
- sessionPublicKey,
2670
- token,
2671
- maxPerCallLow,
2672
- maxPerCallHigh,
2673
- maxPerWindowLow,
2674
- maxPerWindowHigh,
2675
- starknet.num.toHex(windowSeconds)
2676
- ];
2758
+ const setPolicyCall = buildSetSpendingPolicyCall(wallet.publicKey, spendingPolicyConfig);
2677
2759
  const txHash = await executePaymasterTransaction({
2678
2760
  params: {
2679
2761
  encryptKey,
2680
2762
  wallet,
2681
- calls: [
2682
- {
2683
- contractAddress: wallet.publicKey,
2684
- entrypoint: shared.SESSION_ENTRYPOINTS.SET_SPENDING_POLICY,
2685
- calldata
2686
- }
2687
- ],
2763
+ calls: [setPolicyCall],
2688
2764
  saveToDatabase: false
2689
2765
  },
2690
2766
  bearerToken,
@@ -2851,18 +2927,12 @@ var ChipiSessions = class {
2851
2927
  sessionPubKey: sessionPublicKey.slice(0, 15) + "...",
2852
2928
  token: token.slice(0, 15) + "..."
2853
2929
  });
2854
- const calldata = [sessionPublicKey, token];
2930
+ const removeCall = buildRemoveSpendingPolicyCall(wallet.publicKey, sessionPublicKey, token);
2855
2931
  const txHash = await executePaymasterTransaction({
2856
2932
  params: {
2857
2933
  encryptKey,
2858
2934
  wallet,
2859
- calls: [
2860
- {
2861
- contractAddress: wallet.publicKey,
2862
- entrypoint: shared.SESSION_ENTRYPOINTS.REMOVE_SPENDING_POLICY,
2863
- calldata
2864
- }
2865
- ],
2935
+ calls: [removeCall],
2866
2936
  saveToDatabase: false
2867
2937
  },
2868
2938
  bearerToken,
@@ -3043,6 +3113,105 @@ var ChipiTreasury = class {
3043
3113
  };
3044
3114
  }
3045
3115
  };
3116
+ var AI_BASE = "/ai";
3117
+ var THINK_ACTIONS = /* @__PURE__ */ new Set(["swap", "supply", "withdraw", "hold"]);
3118
+ function isThinkDecision(decision) {
3119
+ if (!decision || typeof decision !== "object") return false;
3120
+ const d = decision;
3121
+ if (typeof d.action !== "string" || !THINK_ACTIONS.has(d.action)) return false;
3122
+ if (typeof d.reason !== "string") return false;
3123
+ if (d.amount !== void 0 && (typeof d.amount !== "number" || !Number.isFinite(d.amount)))
3124
+ return false;
3125
+ if (d.confidence !== void 0 && typeof d.confidence !== "number") return false;
3126
+ if (d.from !== void 0 && typeof d.from !== "string") return false;
3127
+ if (d.to !== void 0 && typeof d.to !== "string") return false;
3128
+ return true;
3129
+ }
3130
+ var ChipiAi = class {
3131
+ constructor(client, apiSecretKey) {
3132
+ this.client = client;
3133
+ this.apiSecretKey = apiSecretKey;
3134
+ }
3135
+ secret() {
3136
+ const key = this.apiSecretKey;
3137
+ if (!key || !key.startsWith("sk_")) {
3138
+ throw new shared.ChipiAuthError(
3139
+ "sdk.ai needs a secret key (sk_): configure the SDK with apiSecretKey and call it from a server, never the browser."
3140
+ );
3141
+ }
3142
+ return key;
3143
+ }
3144
+ /**
3145
+ * `GET /v1/ai/signals`: technical signals per token, market sentiment and
3146
+ * DeFi yields. Free up to a monthly quota per organization, then billed per call.
3147
+ */
3148
+ async signals(params = {}) {
3149
+ const query = {};
3150
+ if (params.tokens?.length) query.tokens = params.tokens.join(",");
3151
+ if (params.chain) query.chain = params.chain;
3152
+ return this.client.get({
3153
+ endpoint: `${AI_BASE}/signals`,
3154
+ params: query,
3155
+ bearerToken: this.secret()
3156
+ });
3157
+ }
3158
+ /**
3159
+ * `POST /v1/ai/think`: one DeFi decision for a portfolio, with the latest
3160
+ * signals and your risk parameters injected into the prompt.
3161
+ *
3162
+ * The decision is advice, not an order: check it with `isThinkDecision` and
3163
+ * enforce your own limits before executing anything.
3164
+ */
3165
+ async think(params) {
3166
+ return this.client.post({
3167
+ endpoint: `${AI_BASE}/think`,
3168
+ bearerToken: this.secret(),
3169
+ body: params
3170
+ });
3171
+ }
3172
+ /**
3173
+ * `POST /v1/ai/execute`: unsigned AVNU swap calls (approve + swap) for
3174
+ * `walletAddress`. Nothing is submitted; sign the calls with a session key
3175
+ * or the owner's key.
3176
+ */
3177
+ async execute(params) {
3178
+ return this.client.post({
3179
+ endpoint: `${AI_BASE}/execute`,
3180
+ bearerToken: this.secret(),
3181
+ body: params
3182
+ });
3183
+ }
3184
+ /** `POST /v1/ai/chat`: general-purpose chat, billed per token. */
3185
+ async chat(params) {
3186
+ return this.client.post({
3187
+ endpoint: `${AI_BASE}/chat`,
3188
+ bearerToken: this.secret(),
3189
+ body: params
3190
+ });
3191
+ }
3192
+ /**
3193
+ * `GET /v1/ai/prices`: USD prices and 1h / 24h / 7d changes, refreshed about
3194
+ * every 30 seconds. No credits are charged, but like every `sdk.ai` method it
3195
+ * needs the SDK's secret key (`sk_`).
3196
+ */
3197
+ async prices(params = {}) {
3198
+ const query = {};
3199
+ if (params.tokens?.length) query.tokens = params.tokens.join(",");
3200
+ if (params.chain) query.chain = params.chain;
3201
+ return this.client.get({
3202
+ endpoint: `${AI_BASE}/prices`,
3203
+ params: query,
3204
+ bearerToken: this.secret()
3205
+ });
3206
+ }
3207
+ /** `GET /v1/ai/models`: available models, prices and limits. */
3208
+ async models() {
3209
+ return this.client.get({
3210
+ endpoint: `${AI_BASE}/models`,
3211
+ bearerToken: this.secret()
3212
+ });
3213
+ }
3214
+ };
3046
3215
  var InMemoryNonceStore = class {
3047
3216
  constructor() {
3048
3217
  this.used = /* @__PURE__ */ new Set();
@@ -3360,6 +3529,7 @@ var ChipiSDK = class {
3360
3529
  this.sessions = new ChipiSessions(this.client);
3361
3530
  this.exchanges = new ChipiExchanges(this.client);
3362
3531
  this.treasury = new ChipiTreasury(this.client, config.apiSecretKey);
3532
+ this.ai = new ChipiAi(this.client, config.apiSecretKey);
3363
3533
  this.executeTransaction = this.executeTransaction.bind(this);
3364
3534
  this.executeTransactionWithSession = this.executeTransactionWithSession.bind(this);
3365
3535
  this.transfer = this.transfer.bind(this);
@@ -3623,8 +3793,8 @@ var ChipiSDK = class {
3623
3793
  /**
3624
3794
  * Get on-chain transaction status (supports polling for confirmation)
3625
3795
  */
3626
- async getTransactionStatus(hash10, bearerToken) {
3627
- return this.transactions.getTransactionStatus(hash10, this.resolveBearerToken(bearerToken));
3796
+ async getTransactionStatus(hash11, bearerToken) {
3797
+ return this.transactions.getTransactionStatus(hash11, this.resolveBearerToken(bearerToken));
3628
3798
  }
3629
3799
  /**
3630
3800
  * Prepare a wallet upgrade (e.g., READY → CHIPI or CHIPI v29 → v33).
@@ -4039,6 +4209,79 @@ function x402Middleware(config) {
4039
4209
  next();
4040
4210
  };
4041
4211
  }
4212
+ var InMemoryTxHashStore = class {
4213
+ constructor() {
4214
+ this.used = /* @__PURE__ */ new Set();
4215
+ }
4216
+ consume(transactionHash) {
4217
+ if (this.used.has(transactionHash)) return false;
4218
+ this.used.add(transactionHash);
4219
+ return true;
4220
+ }
4221
+ };
4222
+ var TRANSFER_SELECTOR = BigInt(starknet.hash.getSelectorFromName("Transfer"));
4223
+ function toBigInt2(value) {
4224
+ if (value === void 0) return void 0;
4225
+ try {
4226
+ return BigInt(value);
4227
+ } catch {
4228
+ return void 0;
4229
+ }
4230
+ }
4231
+ function decodeTransfer(event) {
4232
+ if (toBigInt2(event.keys[0]) !== TRANSFER_SELECTOR) return void 0;
4233
+ 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]];
4234
+ const values = [from, to, low, high].map(toBigInt2);
4235
+ if (values.some((v) => v === void 0)) return void 0;
4236
+ const [f, t, l, h] = values;
4237
+ return { from: f, to: t, amount: l + (h << 128n) };
4238
+ }
4239
+ var SessionTxVerifier = class {
4240
+ constructor(config = {}) {
4241
+ const { txHashStore, getReceipt, ...receiptOptions } = config;
4242
+ this.store = txHashStore ?? new InMemoryTxHashStore();
4243
+ this.getReceipt = getReceipt ?? waitForTransaction;
4244
+ this.receiptOptions = receiptOptions;
4245
+ }
4246
+ async verifyTransfer(params) {
4247
+ const { transactionHash, token, from, to, minAmount } = params;
4248
+ const receipt = await this.getReceipt(transactionHash, this.receiptOptions);
4249
+ if (!receipt.success) {
4250
+ return { valid: false, transactionHash, reason: "REVERTED", detail: receipt.revertReason };
4251
+ }
4252
+ const tokenAddress = BigInt(token);
4253
+ const fromAddress = BigInt(from);
4254
+ const toAddress = BigInt(to);
4255
+ let best;
4256
+ for (const event of receipt.events) {
4257
+ if (toBigInt2(event.from_address) !== tokenAddress) continue;
4258
+ const transfer = decodeTransfer(event);
4259
+ if (!transfer || transfer.from !== fromAddress || transfer.to !== toAddress) continue;
4260
+ if (best === void 0 || transfer.amount > best) best = transfer.amount;
4261
+ }
4262
+ if (best === void 0) {
4263
+ return { valid: false, transactionHash, reason: "TRANSFER_NOT_FOUND" };
4264
+ }
4265
+ if (best < minAmount) {
4266
+ return {
4267
+ valid: false,
4268
+ transactionHash,
4269
+ reason: "AMOUNT_TOO_LOW",
4270
+ detail: `paid ${best}, expected at least ${minAmount}`
4271
+ };
4272
+ }
4273
+ const key = "0x" + BigInt(transactionHash).toString(16);
4274
+ if (!await this.store.consume(key)) {
4275
+ return { valid: false, transactionHash, reason: "ALREADY_USED" };
4276
+ }
4277
+ return {
4278
+ valid: true,
4279
+ transactionHash,
4280
+ amount: best,
4281
+ ...receipt.blockNumber !== void 0 ? { blockNumber: receipt.blockNumber } : {}
4282
+ };
4283
+ }
4284
+ };
4042
4285
 
4043
4286
  // src/shhh/index.ts
4044
4287
  init_snip12_hash();
@@ -4444,7 +4687,7 @@ var JWT_APPLE_SUB_KIND_TAG = "JWT_ES256_APPLE_SUB";
4444
4687
  var JWT_APPLE_SUB_KIND_TAG_FELT = BigInt(starknet.shortString.encodeShortString(JWT_APPLE_SUB_KIND_TAG));
4445
4688
  var APPLE_ISSUER = "https://appleid.apple.com";
4446
4689
  var NONCE_B64URL_LEN = 43;
4447
- var U128_MASK = (1n << 128n) - 1n;
4690
+ var U128_MASK2 = (1n << 128n) - 1n;
4448
4691
  function assertBytes3(name, b, len) {
4449
4692
  if (b.length !== len) {
4450
4693
  throw new Error(`${name} must be exactly ${len} bytes; got ${b.length}.`);
@@ -4454,7 +4697,7 @@ function bytesBeToU2563(b) {
4454
4697
  assertBytes3("secp256r1 32B value", b, 32);
4455
4698
  let x = 0n;
4456
4699
  for (let i = 0; i < b.length; i++) x = x << 8n | BigInt(b[i]);
4457
- return { low: x & U128_MASK, high: x >> 128n };
4700
+ return { low: x & U128_MASK2, high: x >> 128n };
4458
4701
  }
4459
4702
  function jwtAppleSubHash(sub) {
4460
4703
  const bytes = new TextEncoder().encode(sub);
@@ -4589,9 +4832,9 @@ function buildEnvelopePayload(fields) {
4589
4832
  BigInt(fields.issOffset),
4590
4833
  BigInt(fields.subOffset),
4591
4834
  BigInt(fields.subLen),
4592
- fields.r & U128_MASK,
4835
+ fields.r & U128_MASK2,
4593
4836
  fields.r >> 128n,
4594
- fields.s & U128_MASK,
4837
+ fields.s & U128_MASK2,
4595
4838
  fields.s >> 128n,
4596
4839
  BigInt(fields.yParity)
4597
4840
  ];
@@ -4951,6 +5194,7 @@ Object.defineProperty(exports, "Currency", {
4951
5194
  });
4952
5195
  exports.APPLE_ISSUER = APPLE_ISSUER;
4953
5196
  exports.BOOTSTRAP_DOMAIN_SEPARATOR = BOOTSTRAP_DOMAIN_SEPARATOR;
5197
+ exports.ChipiAi = ChipiAi;
4954
5198
  exports.ChipiBrowserSDK = ChipiBrowserSDK;
4955
5199
  exports.ChipiClient = ChipiClient;
4956
5200
  exports.ChipiPaymasterAdapter = ChipiPaymasterAdapter;
@@ -4969,12 +5213,14 @@ exports.OP_ROTATE_OWNER = OP_ROTATE_OWNER;
4969
5213
  exports.OP_SET_THRESHOLD = OP_SET_THRESHOLD;
4970
5214
  exports.ROLE_GUARDIAN = ROLE_GUARDIAN;
4971
5215
  exports.ROLE_OWNER = ROLE_OWNER;
5216
+ exports.SessionTxVerifier = SessionTxVerifier;
4972
5217
  exports.ShhhAccount = ShhhAccount;
4973
5218
  exports.TIMELOCK_SECONDS = TIMELOCK_SECONDS;
4974
5219
  exports.VIEW_SELECTORS = VIEW_SELECTORS;
4975
5220
  exports.X402Facilitator = X402Facilitator;
4976
5221
  exports.X402ShhhClient = X402ShhhClient;
4977
5222
  exports.assertValidV2Snip12Envelope = assertValidV2Snip12Envelope;
5223
+ exports.buildAddSessionKeyCall = buildAddSessionKeyCall;
4978
5224
  exports.buildBootstrapSignedCall = buildBootstrapSignedCall;
4979
5225
  exports.buildCancelPendingOpCall = buildCancelPendingOpCall;
4980
5226
  exports.buildCancelRecoveryCall = buildCancelRecoveryCall;
@@ -4996,6 +5242,10 @@ exports.buildProposeAddOwnerCall = buildProposeAddOwnerCall;
4996
5242
  exports.buildProposeRemoveOwnerCall = buildProposeRemoveOwnerCall;
4997
5243
  exports.buildProposeRotateOwnerCall = buildProposeRotateOwnerCall;
4998
5244
  exports.buildProposeSetThresholdCall = buildProposeSetThresholdCall;
5245
+ exports.buildRemoveSpendingPolicyCall = buildRemoveSpendingPolicyCall;
5246
+ exports.buildRevokeSessionKeyCall = buildRevokeSessionKeyCall;
5247
+ exports.buildSessionSetupCalls = buildSessionSetupCalls;
5248
+ exports.buildSetSpendingPolicyCall = buildSetSpendingPolicyCall;
4999
5249
  exports.buildStarkEnvelope = buildStarkEnvelope;
5000
5250
  exports.buildThresholdEnvelope = buildThresholdEnvelope;
5001
5251
  exports.buildWebAuthnEnvelopeFromAssertion = buildWebAuthnEnvelopeFromAssertion;
@@ -5021,6 +5271,7 @@ exports.hashCalls = hashCalls;
5021
5271
  exports.hashOutsideExecutionStruct = hashOutsideExecutionStruct;
5022
5272
  exports.hashStarknetDomain = hashStarknetDomain;
5023
5273
  exports.isReadyToExecute = isReadyToExecute;
5274
+ exports.isThinkDecision = isThinkDecision;
5024
5275
  exports.jwtAppleSubHash = jwtAppleSubHash;
5025
5276
  exports.jwtAppleSubOwnerId = jwtAppleSubOwnerId;
5026
5277
  exports.jwtAppleSubPubkeyFelts = jwtAppleSubPubkeyFelts;
@@ -5028,6 +5279,7 @@ exports.labelToFelt = labelToFelt;
5028
5279
  exports.locateSubClaim = locateSubClaim;
5029
5280
  exports.messageHashToNonceB64url = messageHashToNonceB64url;
5030
5281
  exports.migrateChipiWalletToShhh = migrateChipiWalletToShhh;
5282
+ exports.normalizeEntrypoints = normalizeEntrypoints;
5031
5283
  exports.ownerCommitment = ownerCommitment;
5032
5284
  exports.parseAppleIdToken = parseAppleIdToken;
5033
5285
  exports.parseDerEcdsaSignature = parseDerEcdsaSignature;
@@ -5043,6 +5295,7 @@ exports.snip12HashToHexAsciiBytes = snip12HashToHexAsciiBytes;
5043
5295
  exports.starkOwnerId = starkOwnerId;
5044
5296
  exports.starkPubkeyFelts = starkPubkeyFelts;
5045
5297
  exports.submitViaAccount = submitViaAccount;
5298
+ exports.validateSpendingPolicyConfig = validateSpendingPolicyConfig;
5046
5299
  exports.waitForTransaction = waitForTransaction;
5047
5300
  exports.webauthnOwnerId = webauthnOwnerId;
5048
5301
  exports.webauthnOwnerPubkeyParam = webauthnOwnerPubkeyParam;