@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.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { shortString, hash, CallData, ec, RpcProvider, Account, num, CairoCustomEnum, CairoOption, CairoOptionVariant, cairo, typedData, uint256 } from 'starknet';
2
- import { SHHH_KIND_GAS_OVERHEAD, isValidApiKey, ChipiAuthError, STARKNET_NETWORKS, API_VERSIONING, validateErrorResponse, ChipiApiError, handleApiError, getWalletTypeFromClassHash, WALLET_CLASS_HASHES, WALLET_RPC_ENDPOINTS, SHHH_VERIFIER_CLASS_HASHES, API_ENDPOINTS, ChipiTransactionError, formatAmount, SKU_CONTRACTS, CARRIER_IDS, SERVICE_TYPES, ChipiSessionError, SESSION_ERRORS, SESSION_DEFAULTS, SESSION_ENTRYPOINTS, withRpcFallback, CONTRACT_ADDRESSES, TOKEN_DECIMALS } from '@chipi-stack/shared';
2
+ import { SHHH_KIND_GAS_OVERHEAD, isValidApiKey, ChipiAuthError, STARKNET_NETWORKS, API_VERSIONING, validateErrorResponse, ChipiApiError, handleApiError, getWalletTypeFromClassHash, WALLET_CLASS_HASHES, WALLET_RPC_ENDPOINTS, SHHH_VERIFIER_CLASS_HASHES, API_ENDPOINTS, ChipiTransactionError, formatAmount, SKU_CONTRACTS, CARRIER_IDS, SERVICE_TYPES, ChipiSessionError, SESSION_ERRORS, SESSION_ENTRYPOINTS, SESSION_DEFAULTS, withRpcFallback, CONTRACT_ADDRESSES, TOKEN_DECIMALS } from '@chipi-stack/shared';
3
3
  import CryptoES from 'crypto-es';
4
4
  import { randomBytes } from 'crypto';
5
5
  import { STARKNET_CONTRACTS, Chain } from '@chipi-stack/types';
@@ -1947,14 +1947,14 @@ var ChipiTransactions = class {
1947
1947
  /**
1948
1948
  * Get on-chain transaction status
1949
1949
  */
1950
- async getTransactionStatus(hash10, bearerToken) {
1950
+ async getTransactionStatus(hash11, bearerToken) {
1951
1951
  return this.client.get({
1952
- endpoint: `${API_ENDPOINTS.TRANSACTIONS}/${hash10}/status`,
1952
+ endpoint: `${API_ENDPOINTS.TRANSACTIONS}/${hash11}/status`,
1953
1953
  bearerToken
1954
1954
  });
1955
1955
  }
1956
1956
  /**
1957
- * Sync on-chain transfers from Voyager into the DB (read-through cache).
1957
+ * Sync on-chain transfers (Starknet Transfer events) into the DB (read-through cache).
1958
1958
  * Discovers transactions not made through the SDK (e.g., external USDC receives).
1959
1959
  * After sync, getTransactionList returns the newly discovered transactions.
1960
1960
  */
@@ -2153,6 +2153,108 @@ function decodeSessionData(result, nowSeconds) {
2153
2153
  const isActive = validUntil !== 0 && nowSeconds <= validUntil && remainingCalls > 0;
2154
2154
  return { isActive, validUntil, remainingCalls, allowedEntrypoints: [] };
2155
2155
  }
2156
+ var U128_MASK = (1n << 128n) - 1n;
2157
+ var U256_MAX = (1n << 256n) - 1n;
2158
+ var U64_MAX = (1n << 64n) - 1n;
2159
+ function splitU256(value) {
2160
+ return [num.toHex(value & U128_MASK), num.toHex(value >> 128n)];
2161
+ }
2162
+ function buildAddSessionKeyCall(walletAddress, sessionConfig) {
2163
+ const allowedEntrypoints = normalizeEntrypoints(sessionConfig.allowedEntrypoints);
2164
+ return {
2165
+ contractAddress: walletAddress,
2166
+ entrypoint: SESSION_ENTRYPOINTS.ADD_OR_UPDATE,
2167
+ calldata: [
2168
+ sessionConfig.sessionPublicKey,
2169
+ num.toHex(sessionConfig.validUntil),
2170
+ num.toHex(sessionConfig.maxCalls),
2171
+ num.toHex(allowedEntrypoints.length),
2172
+ ...allowedEntrypoints
2173
+ ]
2174
+ };
2175
+ }
2176
+ function buildRevokeSessionKeyCall(walletAddress, sessionPublicKey) {
2177
+ return {
2178
+ contractAddress: walletAddress,
2179
+ entrypoint: SESSION_ENTRYPOINTS.REVOKE,
2180
+ calldata: [sessionPublicKey]
2181
+ };
2182
+ }
2183
+ function validateSpendingPolicyConfig(config) {
2184
+ const { token, maxPerCall, maxPerWindow, windowSeconds } = config;
2185
+ if (!token || token.trim().length === 0) {
2186
+ throw new ChipiSessionError(
2187
+ `Invalid token address for spending policy: "${token}"`,
2188
+ SESSION_ERRORS.INVALID_SPENDING_POLICY
2189
+ );
2190
+ }
2191
+ if (typeof windowSeconds !== "number" || !Number.isFinite(windowSeconds) || !Number.isInteger(windowSeconds) || windowSeconds <= 0 || BigInt(windowSeconds) > U64_MAX) {
2192
+ throw new ChipiSessionError(
2193
+ `Invalid window duration: ${windowSeconds}. Must be a positive integer within u64 range.`,
2194
+ SESSION_ERRORS.INVALID_SPENDING_POLICY
2195
+ );
2196
+ }
2197
+ if (maxPerCall < 0n || maxPerCall > U256_MAX) {
2198
+ throw new ChipiSessionError(
2199
+ `Invalid maxPerCall: must be >= 0 and <= 2^256 - 1`,
2200
+ SESSION_ERRORS.INVALID_SPENDING_POLICY
2201
+ );
2202
+ }
2203
+ if (maxPerWindow < 0n || maxPerWindow > U256_MAX) {
2204
+ throw new ChipiSessionError(
2205
+ `Invalid maxPerWindow: must be >= 0 and <= 2^256 - 1`,
2206
+ SESSION_ERRORS.INVALID_SPENDING_POLICY
2207
+ );
2208
+ }
2209
+ if (maxPerWindow > 0n && maxPerCall > maxPerWindow) {
2210
+ throw new ChipiSessionError(
2211
+ `Invalid spending policy: maxPerCall (${maxPerCall}) cannot exceed maxPerWindow (${maxPerWindow})`,
2212
+ SESSION_ERRORS.INVALID_SPENDING_POLICY
2213
+ );
2214
+ }
2215
+ }
2216
+ function buildSetSpendingPolicyCall(walletAddress, config) {
2217
+ validateSpendingPolicyConfig(config);
2218
+ const [maxPerCallLow, maxPerCallHigh] = splitU256(config.maxPerCall);
2219
+ const [maxPerWindowLow, maxPerWindowHigh] = splitU256(config.maxPerWindow);
2220
+ return {
2221
+ contractAddress: walletAddress,
2222
+ entrypoint: SESSION_ENTRYPOINTS.SET_SPENDING_POLICY,
2223
+ calldata: [
2224
+ config.sessionPublicKey,
2225
+ config.token,
2226
+ maxPerCallLow,
2227
+ maxPerCallHigh,
2228
+ maxPerWindowLow,
2229
+ maxPerWindowHigh,
2230
+ num.toHex(config.windowSeconds)
2231
+ ]
2232
+ };
2233
+ }
2234
+ function buildRemoveSpendingPolicyCall(walletAddress, sessionPublicKey, token) {
2235
+ if (!token || token.trim().length === 0) {
2236
+ throw new ChipiSessionError(
2237
+ `Invalid token address for spending policy removal: "${token}"`,
2238
+ SESSION_ERRORS.INVALID_SPENDING_POLICY
2239
+ );
2240
+ }
2241
+ return {
2242
+ contractAddress: walletAddress,
2243
+ entrypoint: SESSION_ENTRYPOINTS.REMOVE_SPENDING_POLICY,
2244
+ calldata: [sessionPublicKey, token]
2245
+ };
2246
+ }
2247
+ function buildSessionSetupCalls(walletAddress, sessionConfig, spendingPolicies = []) {
2248
+ return [
2249
+ buildAddSessionKeyCall(walletAddress, sessionConfig),
2250
+ ...spendingPolicies.map(
2251
+ (policy) => buildSetSpendingPolicyCall(walletAddress, {
2252
+ ...policy,
2253
+ sessionPublicKey: sessionConfig.sessionPublicKey
2254
+ })
2255
+ )
2256
+ ];
2257
+ }
2156
2258
 
2157
2259
  // src/sessions.ts
2158
2260
  var ChipiSessions = class {
@@ -2294,26 +2396,12 @@ var ChipiSessions = class {
2294
2396
  maxCalls: sessionConfig.maxCalls,
2295
2397
  allowedEntrypoints: sessionConfig.allowedEntrypoints.length
2296
2398
  });
2297
- const allowedEntrypoints = normalizeEntrypoints(sessionConfig.allowedEntrypoints);
2298
- const calldata = [
2299
- sessionConfig.sessionPublicKey,
2300
- num.toHex(sessionConfig.validUntil),
2301
- num.toHex(sessionConfig.maxCalls),
2302
- // Array: first element is length, then elements
2303
- num.toHex(allowedEntrypoints.length),
2304
- ...allowedEntrypoints
2305
- ];
2399
+ const addCall = buildAddSessionKeyCall(wallet.publicKey, sessionConfig);
2306
2400
  const txHash = await executePaymasterTransaction({
2307
2401
  params: {
2308
2402
  encryptKey,
2309
2403
  wallet,
2310
- calls: [
2311
- {
2312
- contractAddress: wallet.publicKey,
2313
- entrypoint: SESSION_ENTRYPOINTS.ADD_OR_UPDATE,
2314
- calldata
2315
- }
2316
- ],
2404
+ calls: [addCall],
2317
2405
  saveToDatabase: false
2318
2406
  // Don't record session management txs
2319
2407
  },
@@ -2337,6 +2425,54 @@ var ChipiSessions = class {
2337
2425
  throw error;
2338
2426
  }
2339
2427
  }
2428
+ /**
2429
+ * Register a session and its spending policies in ONE owner-signed transaction.
2430
+ *
2431
+ * Equivalent to `addSessionKeyToContract` followed by one `setSpendingPolicy`
2432
+ * per token, but the owner signs once (one passkey prompt) and the session
2433
+ * never exists on-chain without its caps.
2434
+ *
2435
+ * @example
2436
+ * ```typescript
2437
+ * const txHash = await sdk.sessions.setupSession({
2438
+ * encryptKey,
2439
+ * wallet,
2440
+ * sessionConfig: {
2441
+ * sessionPublicKey: session.publicKey,
2442
+ * validUntil: session.validUntil,
2443
+ * maxCalls: 500,
2444
+ * allowedEntrypoints: ["transfer", "approve"],
2445
+ * },
2446
+ * spendingPolicies: [
2447
+ * { token: USDC, maxPerCall: 5_000_000n, maxPerWindow: 20_000_000n, windowSeconds: 86400 },
2448
+ * ],
2449
+ * }, bearerToken);
2450
+ * ```
2451
+ */
2452
+ async setupSession(params, bearerToken) {
2453
+ const { encryptKey, wallet, sessionConfig, spendingPolicies = [] } = params;
2454
+ this.validateWalletSupportsSessions(wallet.walletType, "Setup", wallet.publicKey);
2455
+ const calls = buildSessionSetupCalls(wallet.publicKey, sessionConfig, spendingPolicies);
2456
+ console.log("[ChipiSDK:Session:Setup] Registering session with spending policies", {
2457
+ walletAddress: wallet.publicKey.slice(0, 15) + "...",
2458
+ sessionPubKey: sessionConfig.sessionPublicKey.slice(0, 15) + "...",
2459
+ validUntil: new Date(sessionConfig.validUntil * 1e3).toISOString(),
2460
+ maxCalls: sessionConfig.maxCalls,
2461
+ allowedEntrypoints: sessionConfig.allowedEntrypoints.length,
2462
+ spendingPolicies: spendingPolicies.length
2463
+ });
2464
+ return executePaymasterTransaction({
2465
+ params: {
2466
+ encryptKey,
2467
+ wallet,
2468
+ calls,
2469
+ saveToDatabase: false
2470
+ // Don't record session management txs
2471
+ },
2472
+ bearerToken,
2473
+ client: this.client
2474
+ });
2475
+ }
2340
2476
  /**
2341
2477
  * Revoke a session key from the smart contract.
2342
2478
  *
@@ -2370,13 +2506,7 @@ var ChipiSessions = class {
2370
2506
  params: {
2371
2507
  encryptKey,
2372
2508
  wallet,
2373
- calls: [
2374
- {
2375
- contractAddress: wallet.publicKey,
2376
- entrypoint: SESSION_ENTRYPOINTS.REVOKE,
2377
- calldata: [sessionPublicKey]
2378
- }
2379
- ],
2509
+ calls: [buildRevokeSessionKeyCall(wallet.publicKey, sessionPublicKey)],
2380
2510
  saveToDatabase: false
2381
2511
  // Don't record session management txs
2382
2512
  },
@@ -2566,13 +2696,6 @@ var ChipiSessions = class {
2566
2696
  // Wraps ISessionSpendingPolicy contract interface.
2567
2697
  // Spending policies enforce per-token limits on ERC-20 operations
2568
2698
  // (transfer, approve, increase_allowance) executed by session keys.
2569
- /**
2570
- * Split a bigint into Cairo u256 representation (low u128, high u128).
2571
- */
2572
- splitU256(value) {
2573
- const mask = (1n << 128n) - 1n;
2574
- return [num.toHex(value & mask), num.toHex(value >> 128n)];
2575
- }
2576
2699
  /**
2577
2700
  * Reconstruct a bigint from Cairo u256 (low, high) hex strings.
2578
2701
  */
@@ -2617,38 +2740,7 @@ var ChipiSessions = class {
2617
2740
  SESSION_ERRORS.INVALID_WALLET_TYPE_FOR_SESSION
2618
2741
  );
2619
2742
  }
2620
- const U256_MAX = (1n << 256n) - 1n;
2621
- const U64_MAX = (1n << 64n) - 1n;
2622
- if (!token || token.trim().length === 0) {
2623
- throw new ChipiSessionError(
2624
- `Invalid token address for spending policy: "${token}"`,
2625
- SESSION_ERRORS.INVALID_SPENDING_POLICY
2626
- );
2627
- }
2628
- if (typeof windowSeconds !== "number" || !Number.isFinite(windowSeconds) || !Number.isInteger(windowSeconds) || windowSeconds <= 0 || BigInt(windowSeconds) > U64_MAX) {
2629
- throw new ChipiSessionError(
2630
- `Invalid window duration: ${windowSeconds}. Must be a positive integer within u64 range.`,
2631
- SESSION_ERRORS.INVALID_SPENDING_POLICY
2632
- );
2633
- }
2634
- if (maxPerCall < 0n || maxPerCall > U256_MAX) {
2635
- throw new ChipiSessionError(
2636
- `Invalid maxPerCall: must be >= 0 and <= 2^256 - 1`,
2637
- SESSION_ERRORS.INVALID_SPENDING_POLICY
2638
- );
2639
- }
2640
- if (maxPerWindow < 0n || maxPerWindow > U256_MAX) {
2641
- throw new ChipiSessionError(
2642
- `Invalid maxPerWindow: must be >= 0 and <= 2^256 - 1`,
2643
- SESSION_ERRORS.INVALID_SPENDING_POLICY
2644
- );
2645
- }
2646
- if (maxPerWindow > 0n && maxPerCall > maxPerWindow) {
2647
- throw new ChipiSessionError(
2648
- `Invalid spending policy: maxPerCall (${maxPerCall}) cannot exceed maxPerWindow (${maxPerWindow})`,
2649
- SESSION_ERRORS.INVALID_SPENDING_POLICY
2650
- );
2651
- }
2743
+ validateSpendingPolicyConfig(spendingPolicyConfig);
2652
2744
  try {
2653
2745
  console.log("[ChipiSDK:Session:SetSpendingPolicy] Setting spending policy", {
2654
2746
  walletAddress: wallet.publicKey.slice(0, 15) + "...",
@@ -2658,28 +2750,12 @@ var ChipiSessions = class {
2658
2750
  maxPerWindow: maxPerWindow.toString(),
2659
2751
  windowSeconds
2660
2752
  });
2661
- const [maxPerCallLow, maxPerCallHigh] = this.splitU256(maxPerCall);
2662
- const [maxPerWindowLow, maxPerWindowHigh] = this.splitU256(maxPerWindow);
2663
- const calldata = [
2664
- sessionPublicKey,
2665
- token,
2666
- maxPerCallLow,
2667
- maxPerCallHigh,
2668
- maxPerWindowLow,
2669
- maxPerWindowHigh,
2670
- num.toHex(windowSeconds)
2671
- ];
2753
+ const setPolicyCall = buildSetSpendingPolicyCall(wallet.publicKey, spendingPolicyConfig);
2672
2754
  const txHash = await executePaymasterTransaction({
2673
2755
  params: {
2674
2756
  encryptKey,
2675
2757
  wallet,
2676
- calls: [
2677
- {
2678
- contractAddress: wallet.publicKey,
2679
- entrypoint: SESSION_ENTRYPOINTS.SET_SPENDING_POLICY,
2680
- calldata
2681
- }
2682
- ],
2758
+ calls: [setPolicyCall],
2683
2759
  saveToDatabase: false
2684
2760
  },
2685
2761
  bearerToken,
@@ -2846,18 +2922,12 @@ var ChipiSessions = class {
2846
2922
  sessionPubKey: sessionPublicKey.slice(0, 15) + "...",
2847
2923
  token: token.slice(0, 15) + "..."
2848
2924
  });
2849
- const calldata = [sessionPublicKey, token];
2925
+ const removeCall = buildRemoveSpendingPolicyCall(wallet.publicKey, sessionPublicKey, token);
2850
2926
  const txHash = await executePaymasterTransaction({
2851
2927
  params: {
2852
2928
  encryptKey,
2853
2929
  wallet,
2854
- calls: [
2855
- {
2856
- contractAddress: wallet.publicKey,
2857
- entrypoint: SESSION_ENTRYPOINTS.REMOVE_SPENDING_POLICY,
2858
- calldata
2859
- }
2860
- ],
2930
+ calls: [removeCall],
2861
2931
  saveToDatabase: false
2862
2932
  },
2863
2933
  bearerToken,
@@ -3038,6 +3108,105 @@ var ChipiTreasury = class {
3038
3108
  };
3039
3109
  }
3040
3110
  };
3111
+ var AI_BASE = "/ai";
3112
+ var THINK_ACTIONS = /* @__PURE__ */ new Set(["swap", "supply", "withdraw", "hold"]);
3113
+ function isThinkDecision(decision) {
3114
+ if (!decision || typeof decision !== "object") return false;
3115
+ const d = decision;
3116
+ if (typeof d.action !== "string" || !THINK_ACTIONS.has(d.action)) return false;
3117
+ if (typeof d.reason !== "string") return false;
3118
+ if (d.amount !== void 0 && (typeof d.amount !== "number" || !Number.isFinite(d.amount)))
3119
+ return false;
3120
+ if (d.confidence !== void 0 && typeof d.confidence !== "number") return false;
3121
+ if (d.from !== void 0 && typeof d.from !== "string") return false;
3122
+ if (d.to !== void 0 && typeof d.to !== "string") return false;
3123
+ return true;
3124
+ }
3125
+ var ChipiAi = class {
3126
+ constructor(client, apiSecretKey) {
3127
+ this.client = client;
3128
+ this.apiSecretKey = apiSecretKey;
3129
+ }
3130
+ secret() {
3131
+ const key = this.apiSecretKey;
3132
+ if (!key || !key.startsWith("sk_")) {
3133
+ throw new ChipiAuthError(
3134
+ "sdk.ai needs a secret key (sk_): configure the SDK with apiSecretKey and call it from a server, never the browser."
3135
+ );
3136
+ }
3137
+ return key;
3138
+ }
3139
+ /**
3140
+ * `GET /v1/ai/signals`: technical signals per token, market sentiment and
3141
+ * DeFi yields. Free up to a monthly quota per organization, then billed per call.
3142
+ */
3143
+ async signals(params = {}) {
3144
+ const query = {};
3145
+ if (params.tokens?.length) query.tokens = params.tokens.join(",");
3146
+ if (params.chain) query.chain = params.chain;
3147
+ return this.client.get({
3148
+ endpoint: `${AI_BASE}/signals`,
3149
+ params: query,
3150
+ bearerToken: this.secret()
3151
+ });
3152
+ }
3153
+ /**
3154
+ * `POST /v1/ai/think`: one DeFi decision for a portfolio, with the latest
3155
+ * signals and your risk parameters injected into the prompt.
3156
+ *
3157
+ * The decision is advice, not an order: check it with `isThinkDecision` and
3158
+ * enforce your own limits before executing anything.
3159
+ */
3160
+ async think(params) {
3161
+ return this.client.post({
3162
+ endpoint: `${AI_BASE}/think`,
3163
+ bearerToken: this.secret(),
3164
+ body: params
3165
+ });
3166
+ }
3167
+ /**
3168
+ * `POST /v1/ai/execute`: unsigned AVNU swap calls (approve + swap) for
3169
+ * `walletAddress`. Nothing is submitted; sign the calls with a session key
3170
+ * or the owner's key.
3171
+ */
3172
+ async execute(params) {
3173
+ return this.client.post({
3174
+ endpoint: `${AI_BASE}/execute`,
3175
+ bearerToken: this.secret(),
3176
+ body: params
3177
+ });
3178
+ }
3179
+ /** `POST /v1/ai/chat`: general-purpose chat, billed per token. */
3180
+ async chat(params) {
3181
+ return this.client.post({
3182
+ endpoint: `${AI_BASE}/chat`,
3183
+ bearerToken: this.secret(),
3184
+ body: params
3185
+ });
3186
+ }
3187
+ /**
3188
+ * `GET /v1/ai/prices`: USD prices and 1h / 24h / 7d changes, refreshed about
3189
+ * every 30 seconds. No credits are charged, but like every `sdk.ai` method it
3190
+ * needs the SDK's secret key (`sk_`).
3191
+ */
3192
+ async prices(params = {}) {
3193
+ const query = {};
3194
+ if (params.tokens?.length) query.tokens = params.tokens.join(",");
3195
+ if (params.chain) query.chain = params.chain;
3196
+ return this.client.get({
3197
+ endpoint: `${AI_BASE}/prices`,
3198
+ params: query,
3199
+ bearerToken: this.secret()
3200
+ });
3201
+ }
3202
+ /** `GET /v1/ai/models`: available models, prices and limits. */
3203
+ async models() {
3204
+ return this.client.get({
3205
+ endpoint: `${AI_BASE}/models`,
3206
+ bearerToken: this.secret()
3207
+ });
3208
+ }
3209
+ };
3041
3210
  var InMemoryNonceStore = class {
3042
3211
  constructor() {
3043
3212
  this.used = /* @__PURE__ */ new Set();
@@ -3355,6 +3524,7 @@ var ChipiSDK = class {
3355
3524
  this.sessions = new ChipiSessions(this.client);
3356
3525
  this.exchanges = new ChipiExchanges(this.client);
3357
3526
  this.treasury = new ChipiTreasury(this.client, config.apiSecretKey);
3527
+ this.ai = new ChipiAi(this.client, config.apiSecretKey);
3358
3528
  this.executeTransaction = this.executeTransaction.bind(this);
3359
3529
  this.executeTransactionWithSession = this.executeTransactionWithSession.bind(this);
3360
3530
  this.transfer = this.transfer.bind(this);
@@ -3618,8 +3788,8 @@ var ChipiSDK = class {
3618
3788
  /**
3619
3789
  * Get on-chain transaction status (supports polling for confirmation)
3620
3790
  */
3621
- async getTransactionStatus(hash10, bearerToken) {
3622
- return this.transactions.getTransactionStatus(hash10, this.resolveBearerToken(bearerToken));
3791
+ async getTransactionStatus(hash11, bearerToken) {
3792
+ return this.transactions.getTransactionStatus(hash11, this.resolveBearerToken(bearerToken));
3623
3793
  }
3624
3794
  /**
3625
3795
  * Prepare a wallet upgrade (e.g., READY → CHIPI or CHIPI v29 → v33).
@@ -4034,6 +4204,79 @@ function x402Middleware(config) {
4034
4204
  next();
4035
4205
  };
4036
4206
  }
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
+ };
4037
4280
 
4038
4281
  // src/shhh/index.ts
4039
4282
  init_snip12_hash();
@@ -4439,7 +4682,7 @@ var JWT_APPLE_SUB_KIND_TAG = "JWT_ES256_APPLE_SUB";
4439
4682
  var JWT_APPLE_SUB_KIND_TAG_FELT = BigInt(shortString.encodeShortString(JWT_APPLE_SUB_KIND_TAG));
4440
4683
  var APPLE_ISSUER = "https://appleid.apple.com";
4441
4684
  var NONCE_B64URL_LEN = 43;
4442
- var U128_MASK = (1n << 128n) - 1n;
4685
+ var U128_MASK2 = (1n << 128n) - 1n;
4443
4686
  function assertBytes3(name, b, len) {
4444
4687
  if (b.length !== len) {
4445
4688
  throw new Error(`${name} must be exactly ${len} bytes; got ${b.length}.`);
@@ -4449,7 +4692,7 @@ function bytesBeToU2563(b) {
4449
4692
  assertBytes3("secp256r1 32B value", b, 32);
4450
4693
  let x = 0n;
4451
4694
  for (let i = 0; i < b.length; i++) x = x << 8n | BigInt(b[i]);
4452
- return { low: x & U128_MASK, high: x >> 128n };
4695
+ return { low: x & U128_MASK2, high: x >> 128n };
4453
4696
  }
4454
4697
  function jwtAppleSubHash(sub) {
4455
4698
  const bytes = new TextEncoder().encode(sub);
@@ -4584,9 +4827,9 @@ function buildEnvelopePayload(fields) {
4584
4827
  BigInt(fields.issOffset),
4585
4828
  BigInt(fields.subOffset),
4586
4829
  BigInt(fields.subLen),
4587
- fields.r & U128_MASK,
4830
+ fields.r & U128_MASK2,
4588
4831
  fields.r >> 128n,
4589
- fields.s & U128_MASK,
4832
+ fields.s & U128_MASK2,
4590
4833
  fields.s >> 128n,
4591
4834
  BigInt(fields.yParity)
4592
4835
  ];
@@ -4932,6 +5175,6 @@ function submitViaAccount(funded) {
4932
5175
  };
4933
5176
  }
4934
5177
 
4935
- export { ANY_CALLER_FELT, APPLE_ISSUER, BOOTSTRAP_DOMAIN_SEPARATOR, ChipiBrowserSDK, ChipiClient, ChipiPaymasterAdapter, ChipiSDK, ChipiServerSDK, ChipiSessions, ChipiSkuPurchases, ChipiSkus, ChipiTransactions, ChipiTreasury, ChipiWallets, DEFAULT_OP_EXPIRY_SECONDS, ISIGNER_CANONICAL_LABEL, ISIGNER_ID, ISRC9_V2_ID, MAX_OE_VALIDITY_WINDOW_SECONDS, MIN_THRESHOLD_OWNERS, OE_DOMAIN_NAME, OE_DOMAIN_REVISION, OE_DOMAIN_VERSION, OP_ADD_OWNER, OP_REMOVE_OWNER, OP_ROTATE_OWNER, OP_SET_THRESHOLD, ROLE_GUARDIAN, ROLE_OWNER, SIG_VERSION_V1_HEX_ASCII, SIG_VERSION_V2_SNIP12, SIG_VERSION_V2_THRESHOLD, STARKNET_MESSAGE_PREFIX, ShhhAccount, TIMELOCK_SECONDS, VIEW_SELECTORS, X402Facilitator, X402ShhhClient, assertValidV2Snip12Envelope, buildBootstrapSignedCall, buildCancelPendingOpCall, buildCancelRecoveryCall, buildEd25519Envelope, buildEd25519EnvelopeFromSignature, buildEip191EnvelopeFromPrivateKey, buildEip191EnvelopeFromSignature, buildExecuteAddOwnerCall, buildExecuteRemoveOwnerCall, buildExecuteRotateOwnerCall, buildExecuteSetThresholdCall, buildFinalizeRecoveryCall, buildInitiateRecoveryCall, buildJwtAppleSubEnvelopeFromTestKey, buildJwtAppleSubEnvelopeFromTokenResponse, buildMigrationCalls, buildOutsideExecution, buildProposeAddOwnerCall, buildProposeRemoveOwnerCall, buildProposeRotateOwnerCall, buildProposeSetThresholdCall, buildStarkEnvelope, buildThresholdEnvelope, buildWebAuthnEnvelopeFromAssertion, buildWebAuthnEnvelopeFromPrivateKey, byteArrayToFelts, computeAddressSalt, computeBootstrapMessage, computeISignerId, computeOeHash, computeShhhAddress, computeSnip12Hash, decryptPrivateKey, ed25519OwnerId, ed25519OwnerPubkeyParam, ed25519PubkeyFelts, ed25519SignedBytes, eip191OwnerId, eip191OwnerPubkeyParam, eip191PubkeyFelts, encryptPrivateKey, estimateThresholdGasOverhead, executeShhhSponsoredRaw, hashCall, hashCalls, hashOutsideExecutionStruct, hashStarknetDomain, isReadyToExecute, jwtAppleSubHash, jwtAppleSubOwnerId, jwtAppleSubPubkeyFelts, labelToFelt, locateSubClaim, messageHashToNonceB64url, migrateChipiWalletToShhh, ownerCommitment, parseAppleIdToken, parseDerEcdsaSignature, parseEip191Signature, parseThresholdEnvelope, resolveShhhChainId, secondsUntilExecutable, serializeExecuteFromOutsideV2Calldata, signBootstrapMessage, signTypedData, signTypedDataArray, snip12HashToHexAsciiBytes, starkOwnerId, starkPubkeyFelts, submitViaAccount, waitForTransaction, webauthnOwnerId, webauthnOwnerPubkeyParam, webauthnPubkeyFelts, wrapV2Snip12Envelope, wrapV2ThresholdEnvelope, x402Middleware };
5178
+ export { ANY_CALLER_FELT, APPLE_ISSUER, BOOTSTRAP_DOMAIN_SEPARATOR, ChipiAi, ChipiBrowserSDK, ChipiClient, ChipiPaymasterAdapter, ChipiSDK, ChipiServerSDK, ChipiSessions, ChipiSkuPurchases, ChipiSkus, ChipiTransactions, ChipiTreasury, ChipiWallets, DEFAULT_OP_EXPIRY_SECONDS, ISIGNER_CANONICAL_LABEL, ISIGNER_ID, ISRC9_V2_ID, MAX_OE_VALIDITY_WINDOW_SECONDS, MIN_THRESHOLD_OWNERS, OE_DOMAIN_NAME, OE_DOMAIN_REVISION, OE_DOMAIN_VERSION, OP_ADD_OWNER, OP_REMOVE_OWNER, OP_ROTATE_OWNER, OP_SET_THRESHOLD, ROLE_GUARDIAN, ROLE_OWNER, SIG_VERSION_V1_HEX_ASCII, SIG_VERSION_V2_SNIP12, SIG_VERSION_V2_THRESHOLD, STARKNET_MESSAGE_PREFIX, SessionTxVerifier, ShhhAccount, TIMELOCK_SECONDS, VIEW_SELECTORS, X402Facilitator, X402ShhhClient, assertValidV2Snip12Envelope, buildAddSessionKeyCall, buildBootstrapSignedCall, buildCancelPendingOpCall, buildCancelRecoveryCall, buildEd25519Envelope, buildEd25519EnvelopeFromSignature, buildEip191EnvelopeFromPrivateKey, buildEip191EnvelopeFromSignature, buildExecuteAddOwnerCall, buildExecuteRemoveOwnerCall, buildExecuteRotateOwnerCall, buildExecuteSetThresholdCall, buildFinalizeRecoveryCall, buildInitiateRecoveryCall, buildJwtAppleSubEnvelopeFromTestKey, buildJwtAppleSubEnvelopeFromTokenResponse, buildMigrationCalls, buildOutsideExecution, buildProposeAddOwnerCall, buildProposeRemoveOwnerCall, buildProposeRotateOwnerCall, buildProposeSetThresholdCall, buildRemoveSpendingPolicyCall, buildRevokeSessionKeyCall, buildSessionSetupCalls, buildSetSpendingPolicyCall, buildStarkEnvelope, buildThresholdEnvelope, buildWebAuthnEnvelopeFromAssertion, buildWebAuthnEnvelopeFromPrivateKey, byteArrayToFelts, computeAddressSalt, computeBootstrapMessage, computeISignerId, computeOeHash, computeShhhAddress, computeSnip12Hash, decryptPrivateKey, ed25519OwnerId, ed25519OwnerPubkeyParam, ed25519PubkeyFelts, ed25519SignedBytes, eip191OwnerId, eip191OwnerPubkeyParam, eip191PubkeyFelts, encryptPrivateKey, estimateThresholdGasOverhead, executeShhhSponsoredRaw, hashCall, hashCalls, hashOutsideExecutionStruct, hashStarknetDomain, isReadyToExecute, isThinkDecision, jwtAppleSubHash, jwtAppleSubOwnerId, jwtAppleSubPubkeyFelts, labelToFelt, locateSubClaim, messageHashToNonceB64url, migrateChipiWalletToShhh, normalizeEntrypoints, ownerCommitment, parseAppleIdToken, parseDerEcdsaSignature, parseEip191Signature, parseThresholdEnvelope, resolveShhhChainId, secondsUntilExecutable, serializeExecuteFromOutsideV2Calldata, signBootstrapMessage, signTypedData, signTypedDataArray, snip12HashToHexAsciiBytes, starkOwnerId, starkPubkeyFelts, submitViaAccount, validateSpendingPolicyConfig, waitForTransaction, webauthnOwnerId, webauthnOwnerPubkeyParam, webauthnPubkeyFelts, wrapV2Snip12Envelope, wrapV2ThresholdEnvelope, x402Middleware };
4936
5179
  //# sourceMappingURL=index.mjs.map
4937
5180
  //# sourceMappingURL=index.mjs.map