@chipi-stack/backend 14.13.1 → 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/{client-CqD_yGH0.d.mts → client-D6SDBu5p.d.mts} +3 -1
- package/dist/{client-CqD_yGH0.d.ts → client-D6SDBu5p.d.ts} +3 -1
- package/dist/index.d.mts +277 -9
- package/dist/index.d.ts +277 -9
- package/dist/index.js +594 -147
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +586 -149
- package/dist/index.mjs.map +1 -1
- package/dist/skuPurchases.d.mts +1 -1
- package/dist/skuPurchases.d.ts +1 -1
- package/dist/skuPurchases.js +1 -1
- package/dist/skuPurchases.js.map +1 -1
- package/dist/skuPurchases.mjs +1 -1
- package/dist/skuPurchases.mjs.map +1 -1
- package/dist/skus.d.mts +1 -1
- package/dist/skus.d.ts +1 -1
- package/dist/transactions.d.mts +2 -2
- package/dist/transactions.d.ts +2 -2
- package/dist/transactions.js +1 -1
- package/dist/transactions.js.map +1 -1
- package/dist/transactions.mjs +1 -1
- package/dist/transactions.mjs.map +1 -1
- package/dist/{wallets-DxKnh21Q.d.ts → wallets-C541u9mn.d.ts} +1 -1
- package/dist/{wallets-CYCLyyXY.d.mts → wallets-CX42j3eN.d.mts} +1 -1
- package/dist/wallets.d.mts +2 -2
- package/dist/wallets.d.ts +2 -2
- package/package.json +3 -3
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,
|
|
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';
|
|
@@ -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;
|
|
@@ -1947,14 +1953,14 @@ var ChipiTransactions = class {
|
|
|
1947
1953
|
/**
|
|
1948
1954
|
* Get on-chain transaction status
|
|
1949
1955
|
*/
|
|
1950
|
-
async getTransactionStatus(
|
|
1956
|
+
async getTransactionStatus(hash11, bearerToken) {
|
|
1951
1957
|
return this.client.get({
|
|
1952
|
-
endpoint: `${API_ENDPOINTS.TRANSACTIONS}/${
|
|
1958
|
+
endpoint: `${API_ENDPOINTS.TRANSACTIONS}/${hash11}/status`,
|
|
1953
1959
|
bearerToken
|
|
1954
1960
|
});
|
|
1955
1961
|
}
|
|
1956
1962
|
/**
|
|
1957
|
-
* Sync on-chain transfers
|
|
1963
|
+
* Sync on-chain transfers (Starknet Transfer events) into the DB (read-through cache).
|
|
1958
1964
|
* Discovers transactions not made through the SDK (e.g., external USDC receives).
|
|
1959
1965
|
* After sync, getTransactionList returns the newly discovered transactions.
|
|
1960
1966
|
*/
|
|
@@ -2153,6 +2159,108 @@ function decodeSessionData(result, nowSeconds) {
|
|
|
2153
2159
|
const isActive = validUntil !== 0 && nowSeconds <= validUntil && remainingCalls > 0;
|
|
2154
2160
|
return { isActive, validUntil, remainingCalls, allowedEntrypoints: [] };
|
|
2155
2161
|
}
|
|
2162
|
+
var U128_MASK = (1n << 128n) - 1n;
|
|
2163
|
+
var U256_MAX = (1n << 256n) - 1n;
|
|
2164
|
+
var U64_MAX = (1n << 64n) - 1n;
|
|
2165
|
+
function splitU256(value) {
|
|
2166
|
+
return [num.toHex(value & U128_MASK), num.toHex(value >> 128n)];
|
|
2167
|
+
}
|
|
2168
|
+
function buildAddSessionKeyCall(walletAddress, sessionConfig) {
|
|
2169
|
+
const allowedEntrypoints = normalizeEntrypoints(sessionConfig.allowedEntrypoints);
|
|
2170
|
+
return {
|
|
2171
|
+
contractAddress: walletAddress,
|
|
2172
|
+
entrypoint: SESSION_ENTRYPOINTS.ADD_OR_UPDATE,
|
|
2173
|
+
calldata: [
|
|
2174
|
+
sessionConfig.sessionPublicKey,
|
|
2175
|
+
num.toHex(sessionConfig.validUntil),
|
|
2176
|
+
num.toHex(sessionConfig.maxCalls),
|
|
2177
|
+
num.toHex(allowedEntrypoints.length),
|
|
2178
|
+
...allowedEntrypoints
|
|
2179
|
+
]
|
|
2180
|
+
};
|
|
2181
|
+
}
|
|
2182
|
+
function buildRevokeSessionKeyCall(walletAddress, sessionPublicKey) {
|
|
2183
|
+
return {
|
|
2184
|
+
contractAddress: walletAddress,
|
|
2185
|
+
entrypoint: SESSION_ENTRYPOINTS.REVOKE,
|
|
2186
|
+
calldata: [sessionPublicKey]
|
|
2187
|
+
};
|
|
2188
|
+
}
|
|
2189
|
+
function validateSpendingPolicyConfig(config) {
|
|
2190
|
+
const { token, maxPerCall, maxPerWindow, windowSeconds } = config;
|
|
2191
|
+
if (!token || token.trim().length === 0) {
|
|
2192
|
+
throw new ChipiSessionError(
|
|
2193
|
+
`Invalid token address for spending policy: "${token}"`,
|
|
2194
|
+
SESSION_ERRORS.INVALID_SPENDING_POLICY
|
|
2195
|
+
);
|
|
2196
|
+
}
|
|
2197
|
+
if (typeof windowSeconds !== "number" || !Number.isFinite(windowSeconds) || !Number.isInteger(windowSeconds) || windowSeconds <= 0 || BigInt(windowSeconds) > U64_MAX) {
|
|
2198
|
+
throw new ChipiSessionError(
|
|
2199
|
+
`Invalid window duration: ${windowSeconds}. Must be a positive integer within u64 range.`,
|
|
2200
|
+
SESSION_ERRORS.INVALID_SPENDING_POLICY
|
|
2201
|
+
);
|
|
2202
|
+
}
|
|
2203
|
+
if (maxPerCall < 0n || maxPerCall > U256_MAX) {
|
|
2204
|
+
throw new ChipiSessionError(
|
|
2205
|
+
`Invalid maxPerCall: must be >= 0 and <= 2^256 - 1`,
|
|
2206
|
+
SESSION_ERRORS.INVALID_SPENDING_POLICY
|
|
2207
|
+
);
|
|
2208
|
+
}
|
|
2209
|
+
if (maxPerWindow < 0n || maxPerWindow > U256_MAX) {
|
|
2210
|
+
throw new ChipiSessionError(
|
|
2211
|
+
`Invalid maxPerWindow: must be >= 0 and <= 2^256 - 1`,
|
|
2212
|
+
SESSION_ERRORS.INVALID_SPENDING_POLICY
|
|
2213
|
+
);
|
|
2214
|
+
}
|
|
2215
|
+
if (maxPerWindow > 0n && maxPerCall > maxPerWindow) {
|
|
2216
|
+
throw new ChipiSessionError(
|
|
2217
|
+
`Invalid spending policy: maxPerCall (${maxPerCall}) cannot exceed maxPerWindow (${maxPerWindow})`,
|
|
2218
|
+
SESSION_ERRORS.INVALID_SPENDING_POLICY
|
|
2219
|
+
);
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
2222
|
+
function buildSetSpendingPolicyCall(walletAddress, config) {
|
|
2223
|
+
validateSpendingPolicyConfig(config);
|
|
2224
|
+
const [maxPerCallLow, maxPerCallHigh] = splitU256(config.maxPerCall);
|
|
2225
|
+
const [maxPerWindowLow, maxPerWindowHigh] = splitU256(config.maxPerWindow);
|
|
2226
|
+
return {
|
|
2227
|
+
contractAddress: walletAddress,
|
|
2228
|
+
entrypoint: SESSION_ENTRYPOINTS.SET_SPENDING_POLICY,
|
|
2229
|
+
calldata: [
|
|
2230
|
+
config.sessionPublicKey,
|
|
2231
|
+
config.token,
|
|
2232
|
+
maxPerCallLow,
|
|
2233
|
+
maxPerCallHigh,
|
|
2234
|
+
maxPerWindowLow,
|
|
2235
|
+
maxPerWindowHigh,
|
|
2236
|
+
num.toHex(config.windowSeconds)
|
|
2237
|
+
]
|
|
2238
|
+
};
|
|
2239
|
+
}
|
|
2240
|
+
function buildRemoveSpendingPolicyCall(walletAddress, sessionPublicKey, token) {
|
|
2241
|
+
if (!token || token.trim().length === 0) {
|
|
2242
|
+
throw new ChipiSessionError(
|
|
2243
|
+
`Invalid token address for spending policy removal: "${token}"`,
|
|
2244
|
+
SESSION_ERRORS.INVALID_SPENDING_POLICY
|
|
2245
|
+
);
|
|
2246
|
+
}
|
|
2247
|
+
return {
|
|
2248
|
+
contractAddress: walletAddress,
|
|
2249
|
+
entrypoint: SESSION_ENTRYPOINTS.REMOVE_SPENDING_POLICY,
|
|
2250
|
+
calldata: [sessionPublicKey, token]
|
|
2251
|
+
};
|
|
2252
|
+
}
|
|
2253
|
+
function buildSessionSetupCalls(walletAddress, sessionConfig, spendingPolicies = []) {
|
|
2254
|
+
return [
|
|
2255
|
+
buildAddSessionKeyCall(walletAddress, sessionConfig),
|
|
2256
|
+
...spendingPolicies.map(
|
|
2257
|
+
(policy) => buildSetSpendingPolicyCall(walletAddress, {
|
|
2258
|
+
...policy,
|
|
2259
|
+
sessionPublicKey: sessionConfig.sessionPublicKey
|
|
2260
|
+
})
|
|
2261
|
+
)
|
|
2262
|
+
];
|
|
2263
|
+
}
|
|
2156
2264
|
|
|
2157
2265
|
// src/sessions.ts
|
|
2158
2266
|
var ChipiSessions = class {
|
|
@@ -2294,26 +2402,12 @@ var ChipiSessions = class {
|
|
|
2294
2402
|
maxCalls: sessionConfig.maxCalls,
|
|
2295
2403
|
allowedEntrypoints: sessionConfig.allowedEntrypoints.length
|
|
2296
2404
|
});
|
|
2297
|
-
const
|
|
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
|
-
];
|
|
2405
|
+
const addCall = buildAddSessionKeyCall(wallet.publicKey, sessionConfig);
|
|
2306
2406
|
const txHash = await executePaymasterTransaction({
|
|
2307
2407
|
params: {
|
|
2308
2408
|
encryptKey,
|
|
2309
2409
|
wallet,
|
|
2310
|
-
calls: [
|
|
2311
|
-
{
|
|
2312
|
-
contractAddress: wallet.publicKey,
|
|
2313
|
-
entrypoint: SESSION_ENTRYPOINTS.ADD_OR_UPDATE,
|
|
2314
|
-
calldata
|
|
2315
|
-
}
|
|
2316
|
-
],
|
|
2410
|
+
calls: [addCall],
|
|
2317
2411
|
saveToDatabase: false
|
|
2318
2412
|
// Don't record session management txs
|
|
2319
2413
|
},
|
|
@@ -2337,6 +2431,54 @@ var ChipiSessions = class {
|
|
|
2337
2431
|
throw error;
|
|
2338
2432
|
}
|
|
2339
2433
|
}
|
|
2434
|
+
/**
|
|
2435
|
+
* Register a session and its spending policies in ONE owner-signed transaction.
|
|
2436
|
+
*
|
|
2437
|
+
* Equivalent to `addSessionKeyToContract` followed by one `setSpendingPolicy`
|
|
2438
|
+
* per token, but the owner signs once (one passkey prompt) and the session
|
|
2439
|
+
* never exists on-chain without its caps.
|
|
2440
|
+
*
|
|
2441
|
+
* @example
|
|
2442
|
+
* ```typescript
|
|
2443
|
+
* const txHash = await sdk.sessions.setupSession({
|
|
2444
|
+
* encryptKey,
|
|
2445
|
+
* wallet,
|
|
2446
|
+
* sessionConfig: {
|
|
2447
|
+
* sessionPublicKey: session.publicKey,
|
|
2448
|
+
* validUntil: session.validUntil,
|
|
2449
|
+
* maxCalls: 500,
|
|
2450
|
+
* allowedEntrypoints: ["transfer", "approve"],
|
|
2451
|
+
* },
|
|
2452
|
+
* spendingPolicies: [
|
|
2453
|
+
* { token: USDC, maxPerCall: 5_000_000n, maxPerWindow: 20_000_000n, windowSeconds: 86400 },
|
|
2454
|
+
* ],
|
|
2455
|
+
* }, bearerToken);
|
|
2456
|
+
* ```
|
|
2457
|
+
*/
|
|
2458
|
+
async setupSession(params, bearerToken) {
|
|
2459
|
+
const { encryptKey, wallet, sessionConfig, spendingPolicies = [] } = params;
|
|
2460
|
+
this.validateWalletSupportsSessions(wallet.walletType, "Setup", wallet.publicKey);
|
|
2461
|
+
const calls = buildSessionSetupCalls(wallet.publicKey, sessionConfig, spendingPolicies);
|
|
2462
|
+
console.log("[ChipiSDK:Session:Setup] Registering session with spending policies", {
|
|
2463
|
+
walletAddress: wallet.publicKey.slice(0, 15) + "...",
|
|
2464
|
+
sessionPubKey: sessionConfig.sessionPublicKey.slice(0, 15) + "...",
|
|
2465
|
+
validUntil: new Date(sessionConfig.validUntil * 1e3).toISOString(),
|
|
2466
|
+
maxCalls: sessionConfig.maxCalls,
|
|
2467
|
+
allowedEntrypoints: sessionConfig.allowedEntrypoints.length,
|
|
2468
|
+
spendingPolicies: spendingPolicies.length
|
|
2469
|
+
});
|
|
2470
|
+
return executePaymasterTransaction({
|
|
2471
|
+
params: {
|
|
2472
|
+
encryptKey,
|
|
2473
|
+
wallet,
|
|
2474
|
+
calls,
|
|
2475
|
+
saveToDatabase: false
|
|
2476
|
+
// Don't record session management txs
|
|
2477
|
+
},
|
|
2478
|
+
bearerToken,
|
|
2479
|
+
client: this.client
|
|
2480
|
+
});
|
|
2481
|
+
}
|
|
2340
2482
|
/**
|
|
2341
2483
|
* Revoke a session key from the smart contract.
|
|
2342
2484
|
*
|
|
@@ -2370,13 +2512,7 @@ var ChipiSessions = class {
|
|
|
2370
2512
|
params: {
|
|
2371
2513
|
encryptKey,
|
|
2372
2514
|
wallet,
|
|
2373
|
-
calls: [
|
|
2374
|
-
{
|
|
2375
|
-
contractAddress: wallet.publicKey,
|
|
2376
|
-
entrypoint: SESSION_ENTRYPOINTS.REVOKE,
|
|
2377
|
-
calldata: [sessionPublicKey]
|
|
2378
|
-
}
|
|
2379
|
-
],
|
|
2515
|
+
calls: [buildRevokeSessionKeyCall(wallet.publicKey, sessionPublicKey)],
|
|
2380
2516
|
saveToDatabase: false
|
|
2381
2517
|
// Don't record session management txs
|
|
2382
2518
|
},
|
|
@@ -2566,13 +2702,6 @@ var ChipiSessions = class {
|
|
|
2566
2702
|
// Wraps ISessionSpendingPolicy contract interface.
|
|
2567
2703
|
// Spending policies enforce per-token limits on ERC-20 operations
|
|
2568
2704
|
// (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
2705
|
/**
|
|
2577
2706
|
* Reconstruct a bigint from Cairo u256 (low, high) hex strings.
|
|
2578
2707
|
*/
|
|
@@ -2617,38 +2746,7 @@ var ChipiSessions = class {
|
|
|
2617
2746
|
SESSION_ERRORS.INVALID_WALLET_TYPE_FOR_SESSION
|
|
2618
2747
|
);
|
|
2619
2748
|
}
|
|
2620
|
-
|
|
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
|
-
}
|
|
2749
|
+
validateSpendingPolicyConfig(spendingPolicyConfig);
|
|
2652
2750
|
try {
|
|
2653
2751
|
console.log("[ChipiSDK:Session:SetSpendingPolicy] Setting spending policy", {
|
|
2654
2752
|
walletAddress: wallet.publicKey.slice(0, 15) + "...",
|
|
@@ -2658,28 +2756,12 @@ var ChipiSessions = class {
|
|
|
2658
2756
|
maxPerWindow: maxPerWindow.toString(),
|
|
2659
2757
|
windowSeconds
|
|
2660
2758
|
});
|
|
2661
|
-
const
|
|
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
|
-
];
|
|
2759
|
+
const setPolicyCall = buildSetSpendingPolicyCall(wallet.publicKey, spendingPolicyConfig);
|
|
2672
2760
|
const txHash = await executePaymasterTransaction({
|
|
2673
2761
|
params: {
|
|
2674
2762
|
encryptKey,
|
|
2675
2763
|
wallet,
|
|
2676
|
-
calls: [
|
|
2677
|
-
{
|
|
2678
|
-
contractAddress: wallet.publicKey,
|
|
2679
|
-
entrypoint: SESSION_ENTRYPOINTS.SET_SPENDING_POLICY,
|
|
2680
|
-
calldata
|
|
2681
|
-
}
|
|
2682
|
-
],
|
|
2764
|
+
calls: [setPolicyCall],
|
|
2683
2765
|
saveToDatabase: false
|
|
2684
2766
|
},
|
|
2685
2767
|
bearerToken,
|
|
@@ -2846,18 +2928,12 @@ var ChipiSessions = class {
|
|
|
2846
2928
|
sessionPubKey: sessionPublicKey.slice(0, 15) + "...",
|
|
2847
2929
|
token: token.slice(0, 15) + "..."
|
|
2848
2930
|
});
|
|
2849
|
-
const
|
|
2931
|
+
const removeCall = buildRemoveSpendingPolicyCall(wallet.publicKey, sessionPublicKey, token);
|
|
2850
2932
|
const txHash = await executePaymasterTransaction({
|
|
2851
2933
|
params: {
|
|
2852
2934
|
encryptKey,
|
|
2853
2935
|
wallet,
|
|
2854
|
-
calls: [
|
|
2855
|
-
{
|
|
2856
|
-
contractAddress: wallet.publicKey,
|
|
2857
|
-
entrypoint: SESSION_ENTRYPOINTS.REMOVE_SPENDING_POLICY,
|
|
2858
|
-
calldata
|
|
2859
|
-
}
|
|
2860
|
-
],
|
|
2936
|
+
calls: [removeCall],
|
|
2861
2937
|
saveToDatabase: false
|
|
2862
2938
|
},
|
|
2863
2939
|
bearerToken,
|
|
@@ -3038,6 +3114,409 @@ var ChipiTreasury = class {
|
|
|
3038
3114
|
};
|
|
3039
3115
|
}
|
|
3040
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
|
|
3235
|
+
var AI_BASE = "/ai";
|
|
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));
|
|
3260
|
+
function isThinkDecision(decision) {
|
|
3261
|
+
if (!decision || typeof decision !== "object") return false;
|
|
3262
|
+
const d = decision;
|
|
3263
|
+
if (typeof d.action !== "string" || !THINK_ACTIONS.has(d.action)) return false;
|
|
3264
|
+
if (typeof d.reason !== "string") return false;
|
|
3265
|
+
if (d.amount !== void 0 && (typeof d.amount !== "number" || !Number.isFinite(d.amount)))
|
|
3266
|
+
return false;
|
|
3267
|
+
if (d.confidence !== void 0 && typeof d.confidence !== "number") return false;
|
|
3268
|
+
if (d.from !== void 0 && typeof d.from !== "string") return false;
|
|
3269
|
+
if (d.to !== void 0 && typeof d.to !== "string") return false;
|
|
3270
|
+
return true;
|
|
3271
|
+
}
|
|
3272
|
+
var ChipiAi = class {
|
|
3273
|
+
constructor(client, apiSecretKey, sessions) {
|
|
3274
|
+
this.client = client;
|
|
3275
|
+
this.apiSecretKey = apiSecretKey;
|
|
3276
|
+
this.sessions = sessions;
|
|
3277
|
+
}
|
|
3278
|
+
secret() {
|
|
3279
|
+
const key = this.apiSecretKey;
|
|
3280
|
+
if (!key || !key.startsWith("sk_")) {
|
|
3281
|
+
throw new ChipiAuthError(
|
|
3282
|
+
"sdk.ai needs a secret key (sk_): configure the SDK with apiSecretKey and call it from a server, never the browser."
|
|
3283
|
+
);
|
|
3284
|
+
}
|
|
3285
|
+
return key;
|
|
3286
|
+
}
|
|
3287
|
+
/**
|
|
3288
|
+
* `GET /v1/ai/signals`: technical signals per token, market sentiment and
|
|
3289
|
+
* DeFi yields. Free up to a monthly quota per organization, then billed per call.
|
|
3290
|
+
*/
|
|
3291
|
+
async signals(params = {}) {
|
|
3292
|
+
const query = {};
|
|
3293
|
+
if (params.tokens?.length) query.tokens = params.tokens.join(",");
|
|
3294
|
+
if (params.chain) query.chain = params.chain;
|
|
3295
|
+
return this.client.get({
|
|
3296
|
+
endpoint: `${AI_BASE}/signals`,
|
|
3297
|
+
params: query,
|
|
3298
|
+
bearerToken: this.secret()
|
|
3299
|
+
});
|
|
3300
|
+
}
|
|
3301
|
+
/**
|
|
3302
|
+
* `POST /v1/ai/think`: one DeFi decision for a portfolio, with the latest
|
|
3303
|
+
* signals and your risk parameters injected into the prompt.
|
|
3304
|
+
*
|
|
3305
|
+
* The decision is advice, not an order: check it with `isThinkDecision` and
|
|
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
|
+
* ```
|
|
3325
|
+
*/
|
|
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) {
|
|
3336
|
+
return this.client.post({
|
|
3337
|
+
endpoint: `${AI_BASE}/think`,
|
|
3338
|
+
bearerToken: this.secret(),
|
|
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
|
|
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
|
+
}
|
|
3476
|
+
}
|
|
3477
|
+
/**
|
|
3478
|
+
* `POST /v1/ai/execute`: unsigned AVNU swap calls (approve + swap) for
|
|
3479
|
+
* `walletAddress`. Nothing is submitted; sign the calls with a session key
|
|
3480
|
+
* or the owner's key.
|
|
3481
|
+
*/
|
|
3482
|
+
async execute(params) {
|
|
3483
|
+
return this.client.post({
|
|
3484
|
+
endpoint: `${AI_BASE}/execute`,
|
|
3485
|
+
bearerToken: this.secret(),
|
|
3486
|
+
body: params
|
|
3487
|
+
});
|
|
3488
|
+
}
|
|
3489
|
+
/** `POST /v1/ai/chat`: general-purpose chat, billed per token. */
|
|
3490
|
+
async chat(params) {
|
|
3491
|
+
return this.client.post({
|
|
3492
|
+
endpoint: `${AI_BASE}/chat`,
|
|
3493
|
+
bearerToken: this.secret(),
|
|
3494
|
+
body: params
|
|
3495
|
+
});
|
|
3496
|
+
}
|
|
3497
|
+
/**
|
|
3498
|
+
* `GET /v1/ai/prices`: USD prices and 1h / 24h / 7d changes, refreshed about
|
|
3499
|
+
* every 30 seconds. No credits are charged, but like every `sdk.ai` method it
|
|
3500
|
+
* needs the SDK's secret key (`sk_`).
|
|
3501
|
+
*/
|
|
3502
|
+
async prices(params = {}) {
|
|
3503
|
+
const query = {};
|
|
3504
|
+
if (params.tokens?.length) query.tokens = params.tokens.join(",");
|
|
3505
|
+
if (params.chain) query.chain = params.chain;
|
|
3506
|
+
return this.client.get({
|
|
3507
|
+
endpoint: `${AI_BASE}/prices`,
|
|
3508
|
+
params: query,
|
|
3509
|
+
bearerToken: this.secret()
|
|
3510
|
+
});
|
|
3511
|
+
}
|
|
3512
|
+
/** `GET /v1/ai/models`: available models, prices and limits. */
|
|
3513
|
+
async models() {
|
|
3514
|
+
return this.client.get({
|
|
3515
|
+
endpoint: `${AI_BASE}/models`,
|
|
3516
|
+
bearerToken: this.secret()
|
|
3517
|
+
});
|
|
3518
|
+
}
|
|
3519
|
+
};
|
|
3041
3520
|
var InMemoryNonceStore = class {
|
|
3042
3521
|
constructor() {
|
|
3043
3522
|
this.used = /* @__PURE__ */ new Set();
|
|
@@ -3355,6 +3834,7 @@ var ChipiSDK = class {
|
|
|
3355
3834
|
this.sessions = new ChipiSessions(this.client);
|
|
3356
3835
|
this.exchanges = new ChipiExchanges(this.client);
|
|
3357
3836
|
this.treasury = new ChipiTreasury(this.client, config.apiSecretKey);
|
|
3837
|
+
this.ai = new ChipiAi(this.client, config.apiSecretKey, this.sessions);
|
|
3358
3838
|
this.executeTransaction = this.executeTransaction.bind(this);
|
|
3359
3839
|
this.executeTransactionWithSession = this.executeTransactionWithSession.bind(this);
|
|
3360
3840
|
this.transfer = this.transfer.bind(this);
|
|
@@ -3618,8 +4098,8 @@ var ChipiSDK = class {
|
|
|
3618
4098
|
/**
|
|
3619
4099
|
* Get on-chain transaction status (supports polling for confirmation)
|
|
3620
4100
|
*/
|
|
3621
|
-
async getTransactionStatus(
|
|
3622
|
-
return this.transactions.getTransactionStatus(
|
|
4101
|
+
async getTransactionStatus(hash11, bearerToken) {
|
|
4102
|
+
return this.transactions.getTransactionStatus(hash11, this.resolveBearerToken(bearerToken));
|
|
3623
4103
|
}
|
|
3624
4104
|
/**
|
|
3625
4105
|
* Prepare a wallet upgrade (e.g., READY → CHIPI or CHIPI v29 → v33).
|
|
@@ -3667,49 +4147,6 @@ var ChipiBrowserSDK = class extends ChipiSDK {
|
|
|
3667
4147
|
// All methods are inherited from ChipiSDK
|
|
3668
4148
|
// bearerToken parameter is required for each authenticated request
|
|
3669
4149
|
};
|
|
3670
|
-
var DEFAULT_RETRY_INTERVAL_MS = 3e3;
|
|
3671
|
-
var DEFAULT_TIMEOUT_MS = 3e5;
|
|
3672
|
-
function isPending(finalityStatus) {
|
|
3673
|
-
return finalityStatus === void 0 || finalityStatus === "RECEIVED" || finalityStatus === "PENDING" || finalityStatus === "PRE_CONFIRMED";
|
|
3674
|
-
}
|
|
3675
|
-
async function waitForTransaction(transactionHash, options = {}) {
|
|
3676
|
-
const {
|
|
3677
|
-
nodeUrl = WALLET_RPC_ENDPOINTS.CHIPI,
|
|
3678
|
-
retryIntervalMs = DEFAULT_RETRY_INTERVAL_MS,
|
|
3679
|
-
timeoutMs = DEFAULT_TIMEOUT_MS
|
|
3680
|
-
} = options;
|
|
3681
|
-
const deadline = Date.now() + timeoutMs;
|
|
3682
|
-
let lastError;
|
|
3683
|
-
for (; ; ) {
|
|
3684
|
-
try {
|
|
3685
|
-
const receipt = await withRpcFallback(
|
|
3686
|
-
(provider) => provider.getTransactionReceipt(transactionHash),
|
|
3687
|
-
{ fallbackUrl: nodeUrl }
|
|
3688
|
-
);
|
|
3689
|
-
if (!isPending(receipt?.finality_status)) {
|
|
3690
|
-
const reverted = receipt.execution_status === "REVERTED";
|
|
3691
|
-
return {
|
|
3692
|
-
transactionHash,
|
|
3693
|
-
success: !reverted,
|
|
3694
|
-
executionStatus: receipt.execution_status,
|
|
3695
|
-
finalityStatus: receipt.finality_status,
|
|
3696
|
-
...reverted ? { revertReason: receipt.revert_reason ?? "reverted on chain" } : {},
|
|
3697
|
-
events: receipt.events ?? [],
|
|
3698
|
-
...receipt.block_number !== void 0 ? { blockNumber: receipt.block_number } : {}
|
|
3699
|
-
};
|
|
3700
|
-
}
|
|
3701
|
-
} catch (err) {
|
|
3702
|
-
lastError = err;
|
|
3703
|
-
}
|
|
3704
|
-
if (Date.now() + retryIntervalMs >= deadline) {
|
|
3705
|
-
const detail = lastError instanceof Error ? `: ${lastError.message}` : "";
|
|
3706
|
-
throw new Error(
|
|
3707
|
-
`Timed out after ${timeoutMs}ms waiting for ${transactionHash}${detail}. The transaction may still land; re-check before treating it as failed.`
|
|
3708
|
-
);
|
|
3709
|
-
}
|
|
3710
|
-
await new Promise((resolve) => setTimeout(resolve, retryIntervalMs));
|
|
3711
|
-
}
|
|
3712
|
-
}
|
|
3713
4150
|
|
|
3714
4151
|
// src/index.ts
|
|
3715
4152
|
init_encryption2();
|
|
@@ -4439,7 +4876,7 @@ var JWT_APPLE_SUB_KIND_TAG = "JWT_ES256_APPLE_SUB";
|
|
|
4439
4876
|
var JWT_APPLE_SUB_KIND_TAG_FELT = BigInt(shortString.encodeShortString(JWT_APPLE_SUB_KIND_TAG));
|
|
4440
4877
|
var APPLE_ISSUER = "https://appleid.apple.com";
|
|
4441
4878
|
var NONCE_B64URL_LEN = 43;
|
|
4442
|
-
var
|
|
4879
|
+
var U128_MASK2 = (1n << 128n) - 1n;
|
|
4443
4880
|
function assertBytes3(name, b, len) {
|
|
4444
4881
|
if (b.length !== len) {
|
|
4445
4882
|
throw new Error(`${name} must be exactly ${len} bytes; got ${b.length}.`);
|
|
@@ -4449,7 +4886,7 @@ function bytesBeToU2563(b) {
|
|
|
4449
4886
|
assertBytes3("secp256r1 32B value", b, 32);
|
|
4450
4887
|
let x = 0n;
|
|
4451
4888
|
for (let i = 0; i < b.length; i++) x = x << 8n | BigInt(b[i]);
|
|
4452
|
-
return { low: x &
|
|
4889
|
+
return { low: x & U128_MASK2, high: x >> 128n };
|
|
4453
4890
|
}
|
|
4454
4891
|
function jwtAppleSubHash(sub) {
|
|
4455
4892
|
const bytes = new TextEncoder().encode(sub);
|
|
@@ -4584,9 +5021,9 @@ function buildEnvelopePayload(fields) {
|
|
|
4584
5021
|
BigInt(fields.issOffset),
|
|
4585
5022
|
BigInt(fields.subOffset),
|
|
4586
5023
|
BigInt(fields.subLen),
|
|
4587
|
-
fields.r &
|
|
5024
|
+
fields.r & U128_MASK2,
|
|
4588
5025
|
fields.r >> 128n,
|
|
4589
|
-
fields.s &
|
|
5026
|
+
fields.s & U128_MASK2,
|
|
4590
5027
|
fields.s >> 128n,
|
|
4591
5028
|
BigInt(fields.yParity)
|
|
4592
5029
|
];
|
|
@@ -4932,6 +5369,6 @@ function submitViaAccount(funded) {
|
|
|
4932
5369
|
};
|
|
4933
5370
|
}
|
|
4934
5371
|
|
|
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 };
|
|
5372
|
+
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
5373
|
//# sourceMappingURL=index.mjs.map
|
|
4937
5374
|
//# sourceMappingURL=index.mjs.map
|