@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.js
CHANGED
|
@@ -732,7 +732,8 @@ var ChipiClient = class {
|
|
|
732
732
|
throw new shared.ChipiApiError(
|
|
733
733
|
errorData.message,
|
|
734
734
|
errorData.code || `HTTP_${response.status}`,
|
|
735
|
-
response.status
|
|
735
|
+
response.status,
|
|
736
|
+
data
|
|
736
737
|
);
|
|
737
738
|
}
|
|
738
739
|
return data;
|
|
@@ -743,14 +744,15 @@ var ChipiClient = class {
|
|
|
743
744
|
async post({
|
|
744
745
|
endpoint,
|
|
745
746
|
bearerToken,
|
|
746
|
-
body
|
|
747
|
+
body,
|
|
748
|
+
headers
|
|
747
749
|
}) {
|
|
748
750
|
try {
|
|
749
751
|
const url = new URL(`${this.baseUrl}${endpoint}`);
|
|
750
752
|
this.addVersionParams(url);
|
|
751
753
|
const response = await fetch(url.toString(), {
|
|
752
754
|
method: "POST",
|
|
753
|
-
headers: this.getHeaders(bearerToken),
|
|
755
|
+
headers: { ...headers, ...this.getHeaders(bearerToken) },
|
|
754
756
|
body: body ? JSON.stringify(body) : void 0
|
|
755
757
|
});
|
|
756
758
|
const data = await response.json();
|
|
@@ -759,7 +761,8 @@ var ChipiClient = class {
|
|
|
759
761
|
throw new shared.ChipiApiError(
|
|
760
762
|
errorData.message,
|
|
761
763
|
errorData.code || `HTTP_${response.status}`,
|
|
762
|
-
response.status
|
|
764
|
+
response.status,
|
|
765
|
+
data
|
|
763
766
|
);
|
|
764
767
|
}
|
|
765
768
|
return data;
|
|
@@ -786,7 +789,8 @@ var ChipiClient = class {
|
|
|
786
789
|
throw new shared.ChipiApiError(
|
|
787
790
|
errorData.message,
|
|
788
791
|
errorData.code || `HTTP_${response.status}`,
|
|
789
|
-
response.status
|
|
792
|
+
response.status,
|
|
793
|
+
data
|
|
790
794
|
);
|
|
791
795
|
}
|
|
792
796
|
return data;
|
|
@@ -813,7 +817,8 @@ var ChipiClient = class {
|
|
|
813
817
|
throw new shared.ChipiApiError(
|
|
814
818
|
errorData.message,
|
|
815
819
|
errorData.code || `HTTP_${response.status}`,
|
|
816
|
-
response.status
|
|
820
|
+
response.status,
|
|
821
|
+
data
|
|
817
822
|
);
|
|
818
823
|
}
|
|
819
824
|
return data;
|
|
@@ -838,7 +843,8 @@ var ChipiClient = class {
|
|
|
838
843
|
throw new shared.ChipiApiError(
|
|
839
844
|
errorData.message,
|
|
840
845
|
errorData.code || `HTTP_${response.status}`,
|
|
841
|
-
response.status
|
|
846
|
+
response.status,
|
|
847
|
+
data
|
|
842
848
|
);
|
|
843
849
|
}
|
|
844
850
|
return data;
|
|
@@ -1952,14 +1958,14 @@ var ChipiTransactions = class {
|
|
|
1952
1958
|
/**
|
|
1953
1959
|
* Get on-chain transaction status
|
|
1954
1960
|
*/
|
|
1955
|
-
async getTransactionStatus(
|
|
1961
|
+
async getTransactionStatus(hash11, bearerToken) {
|
|
1956
1962
|
return this.client.get({
|
|
1957
|
-
endpoint: `${shared.API_ENDPOINTS.TRANSACTIONS}/${
|
|
1963
|
+
endpoint: `${shared.API_ENDPOINTS.TRANSACTIONS}/${hash11}/status`,
|
|
1958
1964
|
bearerToken
|
|
1959
1965
|
});
|
|
1960
1966
|
}
|
|
1961
1967
|
/**
|
|
1962
|
-
* Sync on-chain transfers
|
|
1968
|
+
* Sync on-chain transfers (Starknet Transfer events) into the DB (read-through cache).
|
|
1963
1969
|
* Discovers transactions not made through the SDK (e.g., external USDC receives).
|
|
1964
1970
|
* After sync, getTransactionList returns the newly discovered transactions.
|
|
1965
1971
|
*/
|
|
@@ -2158,6 +2164,108 @@ function decodeSessionData(result, nowSeconds) {
|
|
|
2158
2164
|
const isActive = validUntil !== 0 && nowSeconds <= validUntil && remainingCalls > 0;
|
|
2159
2165
|
return { isActive, validUntil, remainingCalls, allowedEntrypoints: [] };
|
|
2160
2166
|
}
|
|
2167
|
+
var U128_MASK = (1n << 128n) - 1n;
|
|
2168
|
+
var U256_MAX = (1n << 256n) - 1n;
|
|
2169
|
+
var U64_MAX = (1n << 64n) - 1n;
|
|
2170
|
+
function splitU256(value) {
|
|
2171
|
+
return [starknet.num.toHex(value & U128_MASK), starknet.num.toHex(value >> 128n)];
|
|
2172
|
+
}
|
|
2173
|
+
function buildAddSessionKeyCall(walletAddress, sessionConfig) {
|
|
2174
|
+
const allowedEntrypoints = normalizeEntrypoints(sessionConfig.allowedEntrypoints);
|
|
2175
|
+
return {
|
|
2176
|
+
contractAddress: walletAddress,
|
|
2177
|
+
entrypoint: shared.SESSION_ENTRYPOINTS.ADD_OR_UPDATE,
|
|
2178
|
+
calldata: [
|
|
2179
|
+
sessionConfig.sessionPublicKey,
|
|
2180
|
+
starknet.num.toHex(sessionConfig.validUntil),
|
|
2181
|
+
starknet.num.toHex(sessionConfig.maxCalls),
|
|
2182
|
+
starknet.num.toHex(allowedEntrypoints.length),
|
|
2183
|
+
...allowedEntrypoints
|
|
2184
|
+
]
|
|
2185
|
+
};
|
|
2186
|
+
}
|
|
2187
|
+
function buildRevokeSessionKeyCall(walletAddress, sessionPublicKey) {
|
|
2188
|
+
return {
|
|
2189
|
+
contractAddress: walletAddress,
|
|
2190
|
+
entrypoint: shared.SESSION_ENTRYPOINTS.REVOKE,
|
|
2191
|
+
calldata: [sessionPublicKey]
|
|
2192
|
+
};
|
|
2193
|
+
}
|
|
2194
|
+
function validateSpendingPolicyConfig(config) {
|
|
2195
|
+
const { token, maxPerCall, maxPerWindow, windowSeconds } = config;
|
|
2196
|
+
if (!token || token.trim().length === 0) {
|
|
2197
|
+
throw new shared.ChipiSessionError(
|
|
2198
|
+
`Invalid token address for spending policy: "${token}"`,
|
|
2199
|
+
shared.SESSION_ERRORS.INVALID_SPENDING_POLICY
|
|
2200
|
+
);
|
|
2201
|
+
}
|
|
2202
|
+
if (typeof windowSeconds !== "number" || !Number.isFinite(windowSeconds) || !Number.isInteger(windowSeconds) || windowSeconds <= 0 || BigInt(windowSeconds) > U64_MAX) {
|
|
2203
|
+
throw new shared.ChipiSessionError(
|
|
2204
|
+
`Invalid window duration: ${windowSeconds}. Must be a positive integer within u64 range.`,
|
|
2205
|
+
shared.SESSION_ERRORS.INVALID_SPENDING_POLICY
|
|
2206
|
+
);
|
|
2207
|
+
}
|
|
2208
|
+
if (maxPerCall < 0n || maxPerCall > U256_MAX) {
|
|
2209
|
+
throw new shared.ChipiSessionError(
|
|
2210
|
+
`Invalid maxPerCall: must be >= 0 and <= 2^256 - 1`,
|
|
2211
|
+
shared.SESSION_ERRORS.INVALID_SPENDING_POLICY
|
|
2212
|
+
);
|
|
2213
|
+
}
|
|
2214
|
+
if (maxPerWindow < 0n || maxPerWindow > U256_MAX) {
|
|
2215
|
+
throw new shared.ChipiSessionError(
|
|
2216
|
+
`Invalid maxPerWindow: must be >= 0 and <= 2^256 - 1`,
|
|
2217
|
+
shared.SESSION_ERRORS.INVALID_SPENDING_POLICY
|
|
2218
|
+
);
|
|
2219
|
+
}
|
|
2220
|
+
if (maxPerWindow > 0n && maxPerCall > maxPerWindow) {
|
|
2221
|
+
throw new shared.ChipiSessionError(
|
|
2222
|
+
`Invalid spending policy: maxPerCall (${maxPerCall}) cannot exceed maxPerWindow (${maxPerWindow})`,
|
|
2223
|
+
shared.SESSION_ERRORS.INVALID_SPENDING_POLICY
|
|
2224
|
+
);
|
|
2225
|
+
}
|
|
2226
|
+
}
|
|
2227
|
+
function buildSetSpendingPolicyCall(walletAddress, config) {
|
|
2228
|
+
validateSpendingPolicyConfig(config);
|
|
2229
|
+
const [maxPerCallLow, maxPerCallHigh] = splitU256(config.maxPerCall);
|
|
2230
|
+
const [maxPerWindowLow, maxPerWindowHigh] = splitU256(config.maxPerWindow);
|
|
2231
|
+
return {
|
|
2232
|
+
contractAddress: walletAddress,
|
|
2233
|
+
entrypoint: shared.SESSION_ENTRYPOINTS.SET_SPENDING_POLICY,
|
|
2234
|
+
calldata: [
|
|
2235
|
+
config.sessionPublicKey,
|
|
2236
|
+
config.token,
|
|
2237
|
+
maxPerCallLow,
|
|
2238
|
+
maxPerCallHigh,
|
|
2239
|
+
maxPerWindowLow,
|
|
2240
|
+
maxPerWindowHigh,
|
|
2241
|
+
starknet.num.toHex(config.windowSeconds)
|
|
2242
|
+
]
|
|
2243
|
+
};
|
|
2244
|
+
}
|
|
2245
|
+
function buildRemoveSpendingPolicyCall(walletAddress, sessionPublicKey, token) {
|
|
2246
|
+
if (!token || token.trim().length === 0) {
|
|
2247
|
+
throw new shared.ChipiSessionError(
|
|
2248
|
+
`Invalid token address for spending policy removal: "${token}"`,
|
|
2249
|
+
shared.SESSION_ERRORS.INVALID_SPENDING_POLICY
|
|
2250
|
+
);
|
|
2251
|
+
}
|
|
2252
|
+
return {
|
|
2253
|
+
contractAddress: walletAddress,
|
|
2254
|
+
entrypoint: shared.SESSION_ENTRYPOINTS.REMOVE_SPENDING_POLICY,
|
|
2255
|
+
calldata: [sessionPublicKey, token]
|
|
2256
|
+
};
|
|
2257
|
+
}
|
|
2258
|
+
function buildSessionSetupCalls(walletAddress, sessionConfig, spendingPolicies = []) {
|
|
2259
|
+
return [
|
|
2260
|
+
buildAddSessionKeyCall(walletAddress, sessionConfig),
|
|
2261
|
+
...spendingPolicies.map(
|
|
2262
|
+
(policy) => buildSetSpendingPolicyCall(walletAddress, {
|
|
2263
|
+
...policy,
|
|
2264
|
+
sessionPublicKey: sessionConfig.sessionPublicKey
|
|
2265
|
+
})
|
|
2266
|
+
)
|
|
2267
|
+
];
|
|
2268
|
+
}
|
|
2161
2269
|
|
|
2162
2270
|
// src/sessions.ts
|
|
2163
2271
|
var ChipiSessions = class {
|
|
@@ -2299,26 +2407,12 @@ var ChipiSessions = class {
|
|
|
2299
2407
|
maxCalls: sessionConfig.maxCalls,
|
|
2300
2408
|
allowedEntrypoints: sessionConfig.allowedEntrypoints.length
|
|
2301
2409
|
});
|
|
2302
|
-
const
|
|
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
|
-
];
|
|
2410
|
+
const addCall = buildAddSessionKeyCall(wallet.publicKey, sessionConfig);
|
|
2311
2411
|
const txHash = await executePaymasterTransaction({
|
|
2312
2412
|
params: {
|
|
2313
2413
|
encryptKey,
|
|
2314
2414
|
wallet,
|
|
2315
|
-
calls: [
|
|
2316
|
-
{
|
|
2317
|
-
contractAddress: wallet.publicKey,
|
|
2318
|
-
entrypoint: shared.SESSION_ENTRYPOINTS.ADD_OR_UPDATE,
|
|
2319
|
-
calldata
|
|
2320
|
-
}
|
|
2321
|
-
],
|
|
2415
|
+
calls: [addCall],
|
|
2322
2416
|
saveToDatabase: false
|
|
2323
2417
|
// Don't record session management txs
|
|
2324
2418
|
},
|
|
@@ -2342,6 +2436,54 @@ var ChipiSessions = class {
|
|
|
2342
2436
|
throw error;
|
|
2343
2437
|
}
|
|
2344
2438
|
}
|
|
2439
|
+
/**
|
|
2440
|
+
* Register a session and its spending policies in ONE owner-signed transaction.
|
|
2441
|
+
*
|
|
2442
|
+
* Equivalent to `addSessionKeyToContract` followed by one `setSpendingPolicy`
|
|
2443
|
+
* per token, but the owner signs once (one passkey prompt) and the session
|
|
2444
|
+
* never exists on-chain without its caps.
|
|
2445
|
+
*
|
|
2446
|
+
* @example
|
|
2447
|
+
* ```typescript
|
|
2448
|
+
* const txHash = await sdk.sessions.setupSession({
|
|
2449
|
+
* encryptKey,
|
|
2450
|
+
* wallet,
|
|
2451
|
+
* sessionConfig: {
|
|
2452
|
+
* sessionPublicKey: session.publicKey,
|
|
2453
|
+
* validUntil: session.validUntil,
|
|
2454
|
+
* maxCalls: 500,
|
|
2455
|
+
* allowedEntrypoints: ["transfer", "approve"],
|
|
2456
|
+
* },
|
|
2457
|
+
* spendingPolicies: [
|
|
2458
|
+
* { token: USDC, maxPerCall: 5_000_000n, maxPerWindow: 20_000_000n, windowSeconds: 86400 },
|
|
2459
|
+
* ],
|
|
2460
|
+
* }, bearerToken);
|
|
2461
|
+
* ```
|
|
2462
|
+
*/
|
|
2463
|
+
async setupSession(params, bearerToken) {
|
|
2464
|
+
const { encryptKey, wallet, sessionConfig, spendingPolicies = [] } = params;
|
|
2465
|
+
this.validateWalletSupportsSessions(wallet.walletType, "Setup", wallet.publicKey);
|
|
2466
|
+
const calls = buildSessionSetupCalls(wallet.publicKey, sessionConfig, spendingPolicies);
|
|
2467
|
+
console.log("[ChipiSDK:Session:Setup] Registering session with spending policies", {
|
|
2468
|
+
walletAddress: wallet.publicKey.slice(0, 15) + "...",
|
|
2469
|
+
sessionPubKey: sessionConfig.sessionPublicKey.slice(0, 15) + "...",
|
|
2470
|
+
validUntil: new Date(sessionConfig.validUntil * 1e3).toISOString(),
|
|
2471
|
+
maxCalls: sessionConfig.maxCalls,
|
|
2472
|
+
allowedEntrypoints: sessionConfig.allowedEntrypoints.length,
|
|
2473
|
+
spendingPolicies: spendingPolicies.length
|
|
2474
|
+
});
|
|
2475
|
+
return executePaymasterTransaction({
|
|
2476
|
+
params: {
|
|
2477
|
+
encryptKey,
|
|
2478
|
+
wallet,
|
|
2479
|
+
calls,
|
|
2480
|
+
saveToDatabase: false
|
|
2481
|
+
// Don't record session management txs
|
|
2482
|
+
},
|
|
2483
|
+
bearerToken,
|
|
2484
|
+
client: this.client
|
|
2485
|
+
});
|
|
2486
|
+
}
|
|
2345
2487
|
/**
|
|
2346
2488
|
* Revoke a session key from the smart contract.
|
|
2347
2489
|
*
|
|
@@ -2375,13 +2517,7 @@ var ChipiSessions = class {
|
|
|
2375
2517
|
params: {
|
|
2376
2518
|
encryptKey,
|
|
2377
2519
|
wallet,
|
|
2378
|
-
calls: [
|
|
2379
|
-
{
|
|
2380
|
-
contractAddress: wallet.publicKey,
|
|
2381
|
-
entrypoint: shared.SESSION_ENTRYPOINTS.REVOKE,
|
|
2382
|
-
calldata: [sessionPublicKey]
|
|
2383
|
-
}
|
|
2384
|
-
],
|
|
2520
|
+
calls: [buildRevokeSessionKeyCall(wallet.publicKey, sessionPublicKey)],
|
|
2385
2521
|
saveToDatabase: false
|
|
2386
2522
|
// Don't record session management txs
|
|
2387
2523
|
},
|
|
@@ -2571,13 +2707,6 @@ var ChipiSessions = class {
|
|
|
2571
2707
|
// Wraps ISessionSpendingPolicy contract interface.
|
|
2572
2708
|
// Spending policies enforce per-token limits on ERC-20 operations
|
|
2573
2709
|
// (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
2710
|
/**
|
|
2582
2711
|
* Reconstruct a bigint from Cairo u256 (low, high) hex strings.
|
|
2583
2712
|
*/
|
|
@@ -2622,38 +2751,7 @@ var ChipiSessions = class {
|
|
|
2622
2751
|
shared.SESSION_ERRORS.INVALID_WALLET_TYPE_FOR_SESSION
|
|
2623
2752
|
);
|
|
2624
2753
|
}
|
|
2625
|
-
|
|
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
|
-
}
|
|
2754
|
+
validateSpendingPolicyConfig(spendingPolicyConfig);
|
|
2657
2755
|
try {
|
|
2658
2756
|
console.log("[ChipiSDK:Session:SetSpendingPolicy] Setting spending policy", {
|
|
2659
2757
|
walletAddress: wallet.publicKey.slice(0, 15) + "...",
|
|
@@ -2663,28 +2761,12 @@ var ChipiSessions = class {
|
|
|
2663
2761
|
maxPerWindow: maxPerWindow.toString(),
|
|
2664
2762
|
windowSeconds
|
|
2665
2763
|
});
|
|
2666
|
-
const
|
|
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
|
-
];
|
|
2764
|
+
const setPolicyCall = buildSetSpendingPolicyCall(wallet.publicKey, spendingPolicyConfig);
|
|
2677
2765
|
const txHash = await executePaymasterTransaction({
|
|
2678
2766
|
params: {
|
|
2679
2767
|
encryptKey,
|
|
2680
2768
|
wallet,
|
|
2681
|
-
calls: [
|
|
2682
|
-
{
|
|
2683
|
-
contractAddress: wallet.publicKey,
|
|
2684
|
-
entrypoint: shared.SESSION_ENTRYPOINTS.SET_SPENDING_POLICY,
|
|
2685
|
-
calldata
|
|
2686
|
-
}
|
|
2687
|
-
],
|
|
2769
|
+
calls: [setPolicyCall],
|
|
2688
2770
|
saveToDatabase: false
|
|
2689
2771
|
},
|
|
2690
2772
|
bearerToken,
|
|
@@ -2851,18 +2933,12 @@ var ChipiSessions = class {
|
|
|
2851
2933
|
sessionPubKey: sessionPublicKey.slice(0, 15) + "...",
|
|
2852
2934
|
token: token.slice(0, 15) + "..."
|
|
2853
2935
|
});
|
|
2854
|
-
const
|
|
2936
|
+
const removeCall = buildRemoveSpendingPolicyCall(wallet.publicKey, sessionPublicKey, token);
|
|
2855
2937
|
const txHash = await executePaymasterTransaction({
|
|
2856
2938
|
params: {
|
|
2857
2939
|
encryptKey,
|
|
2858
2940
|
wallet,
|
|
2859
|
-
calls: [
|
|
2860
|
-
{
|
|
2861
|
-
contractAddress: wallet.publicKey,
|
|
2862
|
-
entrypoint: shared.SESSION_ENTRYPOINTS.REMOVE_SPENDING_POLICY,
|
|
2863
|
-
calldata
|
|
2864
|
-
}
|
|
2865
|
-
],
|
|
2941
|
+
calls: [removeCall],
|
|
2866
2942
|
saveToDatabase: false
|
|
2867
2943
|
},
|
|
2868
2944
|
bearerToken,
|
|
@@ -3043,6 +3119,409 @@ var ChipiTreasury = class {
|
|
|
3043
3119
|
};
|
|
3044
3120
|
}
|
|
3045
3121
|
};
|
|
3122
|
+
var DEFAULT_RETRY_INTERVAL_MS = 3e3;
|
|
3123
|
+
var DEFAULT_TIMEOUT_MS = 3e5;
|
|
3124
|
+
function isPending(finalityStatus) {
|
|
3125
|
+
return finalityStatus === void 0 || finalityStatus === "RECEIVED" || finalityStatus === "PENDING" || finalityStatus === "PRE_CONFIRMED";
|
|
3126
|
+
}
|
|
3127
|
+
async function waitForTransaction(transactionHash, options = {}) {
|
|
3128
|
+
const {
|
|
3129
|
+
nodeUrl = shared.WALLET_RPC_ENDPOINTS.CHIPI,
|
|
3130
|
+
retryIntervalMs = DEFAULT_RETRY_INTERVAL_MS,
|
|
3131
|
+
timeoutMs = DEFAULT_TIMEOUT_MS
|
|
3132
|
+
} = options;
|
|
3133
|
+
const deadline = Date.now() + timeoutMs;
|
|
3134
|
+
let lastError;
|
|
3135
|
+
for (; ; ) {
|
|
3136
|
+
try {
|
|
3137
|
+
const receipt = await shared.withRpcFallback(
|
|
3138
|
+
(provider) => provider.getTransactionReceipt(transactionHash),
|
|
3139
|
+
{ fallbackUrl: nodeUrl }
|
|
3140
|
+
);
|
|
3141
|
+
if (!isPending(receipt?.finality_status)) {
|
|
3142
|
+
const reverted = receipt.execution_status === "REVERTED";
|
|
3143
|
+
return {
|
|
3144
|
+
transactionHash,
|
|
3145
|
+
success: !reverted,
|
|
3146
|
+
executionStatus: receipt.execution_status,
|
|
3147
|
+
finalityStatus: receipt.finality_status,
|
|
3148
|
+
...reverted ? { revertReason: receipt.revert_reason ?? "reverted on chain" } : {},
|
|
3149
|
+
events: receipt.events ?? [],
|
|
3150
|
+
...receipt.block_number !== void 0 ? { blockNumber: receipt.block_number } : {}
|
|
3151
|
+
};
|
|
3152
|
+
}
|
|
3153
|
+
} catch (err) {
|
|
3154
|
+
lastError = err;
|
|
3155
|
+
}
|
|
3156
|
+
if (Date.now() + retryIntervalMs >= deadline) {
|
|
3157
|
+
const detail = lastError instanceof Error ? `: ${lastError.message}` : "";
|
|
3158
|
+
throw new Error(
|
|
3159
|
+
`Timed out after ${timeoutMs}ms waiting for ${transactionHash}${detail}. The transaction may still land; re-check before treating it as failed.`
|
|
3160
|
+
);
|
|
3161
|
+
}
|
|
3162
|
+
await new Promise((resolve) => setTimeout(resolve, retryIntervalMs));
|
|
3163
|
+
}
|
|
3164
|
+
}
|
|
3165
|
+
var InMemoryTxHashStore = class {
|
|
3166
|
+
constructor() {
|
|
3167
|
+
this.used = /* @__PURE__ */ new Set();
|
|
3168
|
+
}
|
|
3169
|
+
consume(transactionHash) {
|
|
3170
|
+
if (this.used.has(transactionHash)) return false;
|
|
3171
|
+
this.used.add(transactionHash);
|
|
3172
|
+
return true;
|
|
3173
|
+
}
|
|
3174
|
+
};
|
|
3175
|
+
var TRANSFER_SELECTOR = BigInt(starknet.hash.getSelectorFromName("Transfer"));
|
|
3176
|
+
function toBigInt2(value) {
|
|
3177
|
+
if (value === void 0) return void 0;
|
|
3178
|
+
try {
|
|
3179
|
+
return BigInt(value);
|
|
3180
|
+
} catch {
|
|
3181
|
+
return void 0;
|
|
3182
|
+
}
|
|
3183
|
+
}
|
|
3184
|
+
function decodeTransfer(event) {
|
|
3185
|
+
if (toBigInt2(event.keys[0]) !== TRANSFER_SELECTOR) return void 0;
|
|
3186
|
+
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]];
|
|
3187
|
+
const values = [from, to, low, high].map(toBigInt2);
|
|
3188
|
+
if (values.some((v) => v === void 0)) return void 0;
|
|
3189
|
+
const [f, t, l, h] = values;
|
|
3190
|
+
return { from: f, to: t, amount: l + (h << 128n) };
|
|
3191
|
+
}
|
|
3192
|
+
var SessionTxVerifier = class {
|
|
3193
|
+
constructor(config = {}) {
|
|
3194
|
+
const { txHashStore, getReceipt, ...receiptOptions } = config;
|
|
3195
|
+
this.store = txHashStore ?? new InMemoryTxHashStore();
|
|
3196
|
+
this.getReceipt = getReceipt ?? waitForTransaction;
|
|
3197
|
+
this.receiptOptions = receiptOptions;
|
|
3198
|
+
}
|
|
3199
|
+
async verifyTransfer(params) {
|
|
3200
|
+
const { transactionHash, token, from, to, minAmount } = params;
|
|
3201
|
+
const receipt = await this.getReceipt(transactionHash, this.receiptOptions);
|
|
3202
|
+
if (!receipt.success) {
|
|
3203
|
+
return { valid: false, transactionHash, reason: "REVERTED", detail: receipt.revertReason };
|
|
3204
|
+
}
|
|
3205
|
+
const tokenAddress = BigInt(token);
|
|
3206
|
+
const fromAddress = BigInt(from);
|
|
3207
|
+
const toAddress = BigInt(to);
|
|
3208
|
+
let best;
|
|
3209
|
+
for (const event of receipt.events) {
|
|
3210
|
+
if (toBigInt2(event.from_address) !== tokenAddress) continue;
|
|
3211
|
+
const transfer = decodeTransfer(event);
|
|
3212
|
+
if (!transfer || transfer.from !== fromAddress || transfer.to !== toAddress) continue;
|
|
3213
|
+
if (best === void 0 || transfer.amount > best) best = transfer.amount;
|
|
3214
|
+
}
|
|
3215
|
+
if (best === void 0) {
|
|
3216
|
+
return { valid: false, transactionHash, reason: "TRANSFER_NOT_FOUND" };
|
|
3217
|
+
}
|
|
3218
|
+
if (best < minAmount) {
|
|
3219
|
+
return {
|
|
3220
|
+
valid: false,
|
|
3221
|
+
transactionHash,
|
|
3222
|
+
reason: "AMOUNT_TOO_LOW",
|
|
3223
|
+
detail: `paid ${best}, expected at least ${minAmount}`
|
|
3224
|
+
};
|
|
3225
|
+
}
|
|
3226
|
+
const key = "0x" + BigInt(transactionHash).toString(16);
|
|
3227
|
+
if (!await this.store.consume(key)) {
|
|
3228
|
+
return { valid: false, transactionHash, reason: "ALREADY_USED" };
|
|
3229
|
+
}
|
|
3230
|
+
return {
|
|
3231
|
+
valid: true,
|
|
3232
|
+
transactionHash,
|
|
3233
|
+
amount: best,
|
|
3234
|
+
...receipt.blockNumber !== void 0 ? { blockNumber: receipt.blockNumber } : {}
|
|
3235
|
+
};
|
|
3236
|
+
}
|
|
3237
|
+
};
|
|
3238
|
+
|
|
3239
|
+
// src/ai.ts
|
|
3240
|
+
var AI_BASE = "/ai";
|
|
3241
|
+
var THINK_ACTIONS = /* @__PURE__ */ new Set(["swap", "supply", "withdraw", "hold"]);
|
|
3242
|
+
var PAID_MAX_ATTEMPTS = 3;
|
|
3243
|
+
var PAID_RETRY_DELAY_MS = 5e3;
|
|
3244
|
+
var padFelt = (value) => "0x" + BigInt(value).toString(16).padStart(64, "0");
|
|
3245
|
+
function sameFelt(a, b) {
|
|
3246
|
+
try {
|
|
3247
|
+
return BigInt(a) === BigInt(b);
|
|
3248
|
+
} catch {
|
|
3249
|
+
return false;
|
|
3250
|
+
}
|
|
3251
|
+
}
|
|
3252
|
+
function sessionTransferOffer(err) {
|
|
3253
|
+
if (!(err instanceof shared.ChipiApiError) || err.status !== 402) return void 0;
|
|
3254
|
+
const details = err.details;
|
|
3255
|
+
return details?.x402?.accepts?.find(
|
|
3256
|
+
(r) => r.scheme === "exact" && r.network === "starknet-mainnet" && r.extra?.paymentMethod === "session-transfer" && sameFelt(r.asset, shared.CONTRACT_ADDRESSES.USDC_MAINNET)
|
|
3257
|
+
);
|
|
3258
|
+
}
|
|
3259
|
+
function thinkInputBytes(params) {
|
|
3260
|
+
const bytes = (text) => new TextEncoder().encode(text).length;
|
|
3261
|
+
const chain = params.chain ?? "starknet";
|
|
3262
|
+
return bytes(JSON.stringify(params.portfolio, null, 2)) + (params.history?.recentDecisions ? bytes(String(params.history.recentDecisions)) : 0) + 2 * bytes(chain);
|
|
3263
|
+
}
|
|
3264
|
+
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
3265
|
+
function isThinkDecision(decision) {
|
|
3266
|
+
if (!decision || typeof decision !== "object") return false;
|
|
3267
|
+
const d = decision;
|
|
3268
|
+
if (typeof d.action !== "string" || !THINK_ACTIONS.has(d.action)) return false;
|
|
3269
|
+
if (typeof d.reason !== "string") return false;
|
|
3270
|
+
if (d.amount !== void 0 && (typeof d.amount !== "number" || !Number.isFinite(d.amount)))
|
|
3271
|
+
return false;
|
|
3272
|
+
if (d.confidence !== void 0 && typeof d.confidence !== "number") return false;
|
|
3273
|
+
if (d.from !== void 0 && typeof d.from !== "string") return false;
|
|
3274
|
+
if (d.to !== void 0 && typeof d.to !== "string") return false;
|
|
3275
|
+
return true;
|
|
3276
|
+
}
|
|
3277
|
+
var ChipiAi = class {
|
|
3278
|
+
constructor(client, apiSecretKey, sessions) {
|
|
3279
|
+
this.client = client;
|
|
3280
|
+
this.apiSecretKey = apiSecretKey;
|
|
3281
|
+
this.sessions = sessions;
|
|
3282
|
+
}
|
|
3283
|
+
secret() {
|
|
3284
|
+
const key = this.apiSecretKey;
|
|
3285
|
+
if (!key || !key.startsWith("sk_")) {
|
|
3286
|
+
throw new shared.ChipiAuthError(
|
|
3287
|
+
"sdk.ai needs a secret key (sk_): configure the SDK with apiSecretKey and call it from a server, never the browser."
|
|
3288
|
+
);
|
|
3289
|
+
}
|
|
3290
|
+
return key;
|
|
3291
|
+
}
|
|
3292
|
+
/**
|
|
3293
|
+
* `GET /v1/ai/signals`: technical signals per token, market sentiment and
|
|
3294
|
+
* DeFi yields. Free up to a monthly quota per organization, then billed per call.
|
|
3295
|
+
*/
|
|
3296
|
+
async signals(params = {}) {
|
|
3297
|
+
const query = {};
|
|
3298
|
+
if (params.tokens?.length) query.tokens = params.tokens.join(",");
|
|
3299
|
+
if (params.chain) query.chain = params.chain;
|
|
3300
|
+
return this.client.get({
|
|
3301
|
+
endpoint: `${AI_BASE}/signals`,
|
|
3302
|
+
params: query,
|
|
3303
|
+
bearerToken: this.secret()
|
|
3304
|
+
});
|
|
3305
|
+
}
|
|
3306
|
+
/**
|
|
3307
|
+
* `POST /v1/ai/think`: one DeFi decision for a portfolio, with the latest
|
|
3308
|
+
* signals and your risk parameters injected into the prompt.
|
|
3309
|
+
*
|
|
3310
|
+
* The decision is advice, not an order: check it with `isThinkDecision` and
|
|
3311
|
+
* enforce your own limits before executing anything.
|
|
3312
|
+
*
|
|
3313
|
+
* **Paying per call (x402).** With `payWithSession`, a 402 that carries a
|
|
3314
|
+
* session-transfer offer (credits short, x402 on) is paid with the agent's
|
|
3315
|
+
* session key: a USDC `transfer` to the offer's `payTo`, then the same call
|
|
3316
|
+
* again with `X-PAYMENT`. The price must be at most `maxAmount`, `model`
|
|
3317
|
+
* must be payable and the input within `maxPromptBytes`, all checked before
|
|
3318
|
+
* paying. The session must whitelist `transfer` and cap USDC. A payment
|
|
3319
|
+
* that was made but not served is reported in `error.details.xPayment`;
|
|
3320
|
+
* pass it back as `options.xPayment` to retry without paying again.
|
|
3321
|
+
*
|
|
3322
|
+
* @example
|
|
3323
|
+
* ```typescript
|
|
3324
|
+
* const res = await sdk.ai.think(
|
|
3325
|
+
* { portfolio, model: "haiku" },
|
|
3326
|
+
* { payWithSession: { encryptKey, wallet, session, maxAmount: 20_000n } } // $0.02 at most
|
|
3327
|
+
* );
|
|
3328
|
+
* res.x402Payment; // set when the call was paid over x402
|
|
3329
|
+
* ```
|
|
3330
|
+
*/
|
|
3331
|
+
async think(params, options = {}) {
|
|
3332
|
+
try {
|
|
3333
|
+
return await this.postThink(params, options.xPayment);
|
|
3334
|
+
} catch (err) {
|
|
3335
|
+
const offer = options.payWithSession ? sessionTransferOffer(err) : void 0;
|
|
3336
|
+
if (!offer || !options.payWithSession) throw err;
|
|
3337
|
+
return this.payAndThink(params, offer, options.payWithSession);
|
|
3338
|
+
}
|
|
3339
|
+
}
|
|
3340
|
+
postThink(params, xPayment) {
|
|
3341
|
+
return this.client.post({
|
|
3342
|
+
endpoint: `${AI_BASE}/think`,
|
|
3343
|
+
bearerToken: this.secret(),
|
|
3344
|
+
body: params,
|
|
3345
|
+
...xPayment ? { headers: { "X-PAYMENT": xPayment } } : {}
|
|
3346
|
+
});
|
|
3347
|
+
}
|
|
3348
|
+
/**
|
|
3349
|
+
* Pay one think call with a session-key USDC transfer, then send it again
|
|
3350
|
+
* with `X-PAYMENT`. Every check that can refuse the call runs before the
|
|
3351
|
+
* transfer; the transfer counts only once its receipt shows the USDC moved.
|
|
3352
|
+
*/
|
|
3353
|
+
async payAndThink(params, offer, pay) {
|
|
3354
|
+
if (!this.sessions) {
|
|
3355
|
+
throw new shared.ChipiApiError(
|
|
3356
|
+
"payWithSession needs the SDK's session client",
|
|
3357
|
+
"X402_NOT_CONFIGURED",
|
|
3358
|
+
402
|
|
3359
|
+
);
|
|
3360
|
+
}
|
|
3361
|
+
let maxAmount;
|
|
3362
|
+
try {
|
|
3363
|
+
maxAmount = BigInt(pay.maxAmount);
|
|
3364
|
+
} catch {
|
|
3365
|
+
throw new shared.ChipiApiError(
|
|
3366
|
+
`maxAmount must be an integer of USDC base units (6 decimals), got ${String(pay.maxAmount)}; nothing was paid`,
|
|
3367
|
+
"X402_INVALID_MAX_AMOUNT",
|
|
3368
|
+
400
|
|
3369
|
+
);
|
|
3370
|
+
}
|
|
3371
|
+
const amount = BigInt(offer.maxAmountRequired);
|
|
3372
|
+
if (amount > maxAmount) {
|
|
3373
|
+
throw new shared.ChipiApiError(
|
|
3374
|
+
`The x402 price (${amount} USDC base units) is above maxAmount (${pay.maxAmount}); nothing was paid`,
|
|
3375
|
+
"X402_PRICE_ABOVE_MAX",
|
|
3376
|
+
402,
|
|
3377
|
+
{ x402: { accepts: [offer] } }
|
|
3378
|
+
);
|
|
3379
|
+
}
|
|
3380
|
+
const payable = offer.extra?.payableModels;
|
|
3381
|
+
if (params.model && Array.isArray(payable) && !payable.includes(params.model)) {
|
|
3382
|
+
throw new shared.ChipiApiError(
|
|
3383
|
+
`Model ${params.model} cannot be paid with x402 (payable: ${payable.join(", ")}); nothing was paid`,
|
|
3384
|
+
"X402_MODEL_NOT_PAYABLE",
|
|
3385
|
+
402,
|
|
3386
|
+
{ x402: { accepts: [offer] } }
|
|
3387
|
+
);
|
|
3388
|
+
}
|
|
3389
|
+
const maxBytes = offer.extra?.maxPromptBytes;
|
|
3390
|
+
if (typeof maxBytes === "number" && thinkInputBytes(params) > maxBytes) {
|
|
3391
|
+
throw new shared.ChipiApiError(
|
|
3392
|
+
`Paid calls accept at most ${maxBytes} bytes of portfolio, history and chain; nothing was paid`,
|
|
3393
|
+
"X402_PAYLOAD_TOO_LARGE",
|
|
3394
|
+
402,
|
|
3395
|
+
{ x402: { accepts: [offer] } }
|
|
3396
|
+
);
|
|
3397
|
+
}
|
|
3398
|
+
const payer = pay.wallet.publicKey;
|
|
3399
|
+
const mask = (1n << 128n) - 1n;
|
|
3400
|
+
const transactionHash = await this.sessions.executeTransactionWithSession(
|
|
3401
|
+
{
|
|
3402
|
+
encryptKey: pay.encryptKey,
|
|
3403
|
+
wallet: pay.wallet,
|
|
3404
|
+
session: pay.session,
|
|
3405
|
+
calls: [
|
|
3406
|
+
{
|
|
3407
|
+
contractAddress: offer.asset,
|
|
3408
|
+
entrypoint: "transfer",
|
|
3409
|
+
calldata: [offer.payTo, (amount & mask).toString(), (amount >> 128n).toString()]
|
|
3410
|
+
}
|
|
3411
|
+
]
|
|
3412
|
+
},
|
|
3413
|
+
this.secret()
|
|
3414
|
+
);
|
|
3415
|
+
const header = {
|
|
3416
|
+
x402Version: 1,
|
|
3417
|
+
scheme: "exact",
|
|
3418
|
+
network: "starknet-mainnet",
|
|
3419
|
+
payload: {
|
|
3420
|
+
signature: { r: padFelt(transactionHash), s: "session" },
|
|
3421
|
+
fromAddress: padFelt(payer),
|
|
3422
|
+
toAddress: padFelt(offer.payTo),
|
|
3423
|
+
amount: amount.toString(),
|
|
3424
|
+
asset: offer.asset,
|
|
3425
|
+
validUntil: Math.floor(Date.now() / 1e3) + offer.maxTimeoutSeconds,
|
|
3426
|
+
nonce: padFelt(transactionHash)
|
|
3427
|
+
}
|
|
3428
|
+
};
|
|
3429
|
+
const xPayment = JSON.stringify(header);
|
|
3430
|
+
const paidError = (message, code, extra = {}) => new shared.ChipiApiError(message, code, 402, {
|
|
3431
|
+
x402: { accepts: [offer] },
|
|
3432
|
+
x402PaymentHash: transactionHash,
|
|
3433
|
+
...extra
|
|
3434
|
+
});
|
|
3435
|
+
let receipt;
|
|
3436
|
+
try {
|
|
3437
|
+
receipt = await waitForTransaction(transactionHash, { timeoutMs: 12e4 });
|
|
3438
|
+
} catch (err) {
|
|
3439
|
+
throw paidError(
|
|
3440
|
+
`No receipt yet for the x402 payment ${transactionHash}: ${err instanceof Error ? err.message : String(err)}`,
|
|
3441
|
+
"X402_PAYMENT_PENDING",
|
|
3442
|
+
{ xPayment }
|
|
3443
|
+
);
|
|
3444
|
+
}
|
|
3445
|
+
const paid = await new SessionTxVerifier({
|
|
3446
|
+
txHashStore: { consume: () => true },
|
|
3447
|
+
getReceipt: async () => receipt
|
|
3448
|
+
}).verifyTransfer({
|
|
3449
|
+
transactionHash,
|
|
3450
|
+
token: offer.asset,
|
|
3451
|
+
from: payer,
|
|
3452
|
+
to: offer.payTo,
|
|
3453
|
+
minAmount: amount
|
|
3454
|
+
});
|
|
3455
|
+
if (!paid.valid) {
|
|
3456
|
+
throw paidError(
|
|
3457
|
+
`The x402 payment did not move ${amount} USDC base units to payTo (${paid.reason}). Check the session's whitelist (transfer) and its USDC cap.`,
|
|
3458
|
+
"X402_PAYMENT_FAILED",
|
|
3459
|
+
{ reason: paid.reason }
|
|
3460
|
+
);
|
|
3461
|
+
}
|
|
3462
|
+
for (let attempt = 1; ; attempt++) {
|
|
3463
|
+
try {
|
|
3464
|
+
return await this.postThink(params, xPayment);
|
|
3465
|
+
} catch (err) {
|
|
3466
|
+
const retryable = err instanceof shared.ChipiApiError && (err.status === 409 || err.status === 503 && err.details?.retryable === true);
|
|
3467
|
+
if (retryable && attempt < PAID_MAX_ATTEMPTS) {
|
|
3468
|
+
await sleep(PAID_RETRY_DELAY_MS);
|
|
3469
|
+
continue;
|
|
3470
|
+
}
|
|
3471
|
+
if (err instanceof shared.ChipiApiError) {
|
|
3472
|
+
throw new shared.ChipiApiError(err.message, err.code, err.status ?? 402, {
|
|
3473
|
+
...typeof err.details === "object" && err.details !== null ? err.details : {},
|
|
3474
|
+
x402PaymentHash: transactionHash,
|
|
3475
|
+
xPayment
|
|
3476
|
+
});
|
|
3477
|
+
}
|
|
3478
|
+
throw err;
|
|
3479
|
+
}
|
|
3480
|
+
}
|
|
3481
|
+
}
|
|
3482
|
+
/**
|
|
3483
|
+
* `POST /v1/ai/execute`: unsigned AVNU swap calls (approve + swap) for
|
|
3484
|
+
* `walletAddress`. Nothing is submitted; sign the calls with a session key
|
|
3485
|
+
* or the owner's key.
|
|
3486
|
+
*/
|
|
3487
|
+
async execute(params) {
|
|
3488
|
+
return this.client.post({
|
|
3489
|
+
endpoint: `${AI_BASE}/execute`,
|
|
3490
|
+
bearerToken: this.secret(),
|
|
3491
|
+
body: params
|
|
3492
|
+
});
|
|
3493
|
+
}
|
|
3494
|
+
/** `POST /v1/ai/chat`: general-purpose chat, billed per token. */
|
|
3495
|
+
async chat(params) {
|
|
3496
|
+
return this.client.post({
|
|
3497
|
+
endpoint: `${AI_BASE}/chat`,
|
|
3498
|
+
bearerToken: this.secret(),
|
|
3499
|
+
body: params
|
|
3500
|
+
});
|
|
3501
|
+
}
|
|
3502
|
+
/**
|
|
3503
|
+
* `GET /v1/ai/prices`: USD prices and 1h / 24h / 7d changes, refreshed about
|
|
3504
|
+
* every 30 seconds. No credits are charged, but like every `sdk.ai` method it
|
|
3505
|
+
* needs the SDK's secret key (`sk_`).
|
|
3506
|
+
*/
|
|
3507
|
+
async prices(params = {}) {
|
|
3508
|
+
const query = {};
|
|
3509
|
+
if (params.tokens?.length) query.tokens = params.tokens.join(",");
|
|
3510
|
+
if (params.chain) query.chain = params.chain;
|
|
3511
|
+
return this.client.get({
|
|
3512
|
+
endpoint: `${AI_BASE}/prices`,
|
|
3513
|
+
params: query,
|
|
3514
|
+
bearerToken: this.secret()
|
|
3515
|
+
});
|
|
3516
|
+
}
|
|
3517
|
+
/** `GET /v1/ai/models`: available models, prices and limits. */
|
|
3518
|
+
async models() {
|
|
3519
|
+
return this.client.get({
|
|
3520
|
+
endpoint: `${AI_BASE}/models`,
|
|
3521
|
+
bearerToken: this.secret()
|
|
3522
|
+
});
|
|
3523
|
+
}
|
|
3524
|
+
};
|
|
3046
3525
|
var InMemoryNonceStore = class {
|
|
3047
3526
|
constructor() {
|
|
3048
3527
|
this.used = /* @__PURE__ */ new Set();
|
|
@@ -3360,6 +3839,7 @@ var ChipiSDK = class {
|
|
|
3360
3839
|
this.sessions = new ChipiSessions(this.client);
|
|
3361
3840
|
this.exchanges = new ChipiExchanges(this.client);
|
|
3362
3841
|
this.treasury = new ChipiTreasury(this.client, config.apiSecretKey);
|
|
3842
|
+
this.ai = new ChipiAi(this.client, config.apiSecretKey, this.sessions);
|
|
3363
3843
|
this.executeTransaction = this.executeTransaction.bind(this);
|
|
3364
3844
|
this.executeTransactionWithSession = this.executeTransactionWithSession.bind(this);
|
|
3365
3845
|
this.transfer = this.transfer.bind(this);
|
|
@@ -3623,8 +4103,8 @@ var ChipiSDK = class {
|
|
|
3623
4103
|
/**
|
|
3624
4104
|
* Get on-chain transaction status (supports polling for confirmation)
|
|
3625
4105
|
*/
|
|
3626
|
-
async getTransactionStatus(
|
|
3627
|
-
return this.transactions.getTransactionStatus(
|
|
4106
|
+
async getTransactionStatus(hash11, bearerToken) {
|
|
4107
|
+
return this.transactions.getTransactionStatus(hash11, this.resolveBearerToken(bearerToken));
|
|
3628
4108
|
}
|
|
3629
4109
|
/**
|
|
3630
4110
|
* Prepare a wallet upgrade (e.g., READY → CHIPI or CHIPI v29 → v33).
|
|
@@ -3672,49 +4152,6 @@ var ChipiBrowserSDK = class extends ChipiSDK {
|
|
|
3672
4152
|
// All methods are inherited from ChipiSDK
|
|
3673
4153
|
// bearerToken parameter is required for each authenticated request
|
|
3674
4154
|
};
|
|
3675
|
-
var DEFAULT_RETRY_INTERVAL_MS = 3e3;
|
|
3676
|
-
var DEFAULT_TIMEOUT_MS = 3e5;
|
|
3677
|
-
function isPending(finalityStatus) {
|
|
3678
|
-
return finalityStatus === void 0 || finalityStatus === "RECEIVED" || finalityStatus === "PENDING" || finalityStatus === "PRE_CONFIRMED";
|
|
3679
|
-
}
|
|
3680
|
-
async function waitForTransaction(transactionHash, options = {}) {
|
|
3681
|
-
const {
|
|
3682
|
-
nodeUrl = shared.WALLET_RPC_ENDPOINTS.CHIPI,
|
|
3683
|
-
retryIntervalMs = DEFAULT_RETRY_INTERVAL_MS,
|
|
3684
|
-
timeoutMs = DEFAULT_TIMEOUT_MS
|
|
3685
|
-
} = options;
|
|
3686
|
-
const deadline = Date.now() + timeoutMs;
|
|
3687
|
-
let lastError;
|
|
3688
|
-
for (; ; ) {
|
|
3689
|
-
try {
|
|
3690
|
-
const receipt = await shared.withRpcFallback(
|
|
3691
|
-
(provider) => provider.getTransactionReceipt(transactionHash),
|
|
3692
|
-
{ fallbackUrl: nodeUrl }
|
|
3693
|
-
);
|
|
3694
|
-
if (!isPending(receipt?.finality_status)) {
|
|
3695
|
-
const reverted = receipt.execution_status === "REVERTED";
|
|
3696
|
-
return {
|
|
3697
|
-
transactionHash,
|
|
3698
|
-
success: !reverted,
|
|
3699
|
-
executionStatus: receipt.execution_status,
|
|
3700
|
-
finalityStatus: receipt.finality_status,
|
|
3701
|
-
...reverted ? { revertReason: receipt.revert_reason ?? "reverted on chain" } : {},
|
|
3702
|
-
events: receipt.events ?? [],
|
|
3703
|
-
...receipt.block_number !== void 0 ? { blockNumber: receipt.block_number } : {}
|
|
3704
|
-
};
|
|
3705
|
-
}
|
|
3706
|
-
} catch (err) {
|
|
3707
|
-
lastError = err;
|
|
3708
|
-
}
|
|
3709
|
-
if (Date.now() + retryIntervalMs >= deadline) {
|
|
3710
|
-
const detail = lastError instanceof Error ? `: ${lastError.message}` : "";
|
|
3711
|
-
throw new Error(
|
|
3712
|
-
`Timed out after ${timeoutMs}ms waiting for ${transactionHash}${detail}. The transaction may still land; re-check before treating it as failed.`
|
|
3713
|
-
);
|
|
3714
|
-
}
|
|
3715
|
-
await new Promise((resolve) => setTimeout(resolve, retryIntervalMs));
|
|
3716
|
-
}
|
|
3717
|
-
}
|
|
3718
4155
|
|
|
3719
4156
|
// src/index.ts
|
|
3720
4157
|
init_encryption2();
|
|
@@ -4444,7 +4881,7 @@ var JWT_APPLE_SUB_KIND_TAG = "JWT_ES256_APPLE_SUB";
|
|
|
4444
4881
|
var JWT_APPLE_SUB_KIND_TAG_FELT = BigInt(starknet.shortString.encodeShortString(JWT_APPLE_SUB_KIND_TAG));
|
|
4445
4882
|
var APPLE_ISSUER = "https://appleid.apple.com";
|
|
4446
4883
|
var NONCE_B64URL_LEN = 43;
|
|
4447
|
-
var
|
|
4884
|
+
var U128_MASK2 = (1n << 128n) - 1n;
|
|
4448
4885
|
function assertBytes3(name, b, len) {
|
|
4449
4886
|
if (b.length !== len) {
|
|
4450
4887
|
throw new Error(`${name} must be exactly ${len} bytes; got ${b.length}.`);
|
|
@@ -4454,7 +4891,7 @@ function bytesBeToU2563(b) {
|
|
|
4454
4891
|
assertBytes3("secp256r1 32B value", b, 32);
|
|
4455
4892
|
let x = 0n;
|
|
4456
4893
|
for (let i = 0; i < b.length; i++) x = x << 8n | BigInt(b[i]);
|
|
4457
|
-
return { low: x &
|
|
4894
|
+
return { low: x & U128_MASK2, high: x >> 128n };
|
|
4458
4895
|
}
|
|
4459
4896
|
function jwtAppleSubHash(sub) {
|
|
4460
4897
|
const bytes = new TextEncoder().encode(sub);
|
|
@@ -4589,9 +5026,9 @@ function buildEnvelopePayload(fields) {
|
|
|
4589
5026
|
BigInt(fields.issOffset),
|
|
4590
5027
|
BigInt(fields.subOffset),
|
|
4591
5028
|
BigInt(fields.subLen),
|
|
4592
|
-
fields.r &
|
|
5029
|
+
fields.r & U128_MASK2,
|
|
4593
5030
|
fields.r >> 128n,
|
|
4594
|
-
fields.s &
|
|
5031
|
+
fields.s & U128_MASK2,
|
|
4595
5032
|
fields.s >> 128n,
|
|
4596
5033
|
BigInt(fields.yParity)
|
|
4597
5034
|
];
|
|
@@ -4951,6 +5388,7 @@ Object.defineProperty(exports, "Currency", {
|
|
|
4951
5388
|
});
|
|
4952
5389
|
exports.APPLE_ISSUER = APPLE_ISSUER;
|
|
4953
5390
|
exports.BOOTSTRAP_DOMAIN_SEPARATOR = BOOTSTRAP_DOMAIN_SEPARATOR;
|
|
5391
|
+
exports.ChipiAi = ChipiAi;
|
|
4954
5392
|
exports.ChipiBrowserSDK = ChipiBrowserSDK;
|
|
4955
5393
|
exports.ChipiClient = ChipiClient;
|
|
4956
5394
|
exports.ChipiPaymasterAdapter = ChipiPaymasterAdapter;
|
|
@@ -4969,12 +5407,14 @@ exports.OP_ROTATE_OWNER = OP_ROTATE_OWNER;
|
|
|
4969
5407
|
exports.OP_SET_THRESHOLD = OP_SET_THRESHOLD;
|
|
4970
5408
|
exports.ROLE_GUARDIAN = ROLE_GUARDIAN;
|
|
4971
5409
|
exports.ROLE_OWNER = ROLE_OWNER;
|
|
5410
|
+
exports.SessionTxVerifier = SessionTxVerifier;
|
|
4972
5411
|
exports.ShhhAccount = ShhhAccount;
|
|
4973
5412
|
exports.TIMELOCK_SECONDS = TIMELOCK_SECONDS;
|
|
4974
5413
|
exports.VIEW_SELECTORS = VIEW_SELECTORS;
|
|
4975
5414
|
exports.X402Facilitator = X402Facilitator;
|
|
4976
5415
|
exports.X402ShhhClient = X402ShhhClient;
|
|
4977
5416
|
exports.assertValidV2Snip12Envelope = assertValidV2Snip12Envelope;
|
|
5417
|
+
exports.buildAddSessionKeyCall = buildAddSessionKeyCall;
|
|
4978
5418
|
exports.buildBootstrapSignedCall = buildBootstrapSignedCall;
|
|
4979
5419
|
exports.buildCancelPendingOpCall = buildCancelPendingOpCall;
|
|
4980
5420
|
exports.buildCancelRecoveryCall = buildCancelRecoveryCall;
|
|
@@ -4996,6 +5436,10 @@ exports.buildProposeAddOwnerCall = buildProposeAddOwnerCall;
|
|
|
4996
5436
|
exports.buildProposeRemoveOwnerCall = buildProposeRemoveOwnerCall;
|
|
4997
5437
|
exports.buildProposeRotateOwnerCall = buildProposeRotateOwnerCall;
|
|
4998
5438
|
exports.buildProposeSetThresholdCall = buildProposeSetThresholdCall;
|
|
5439
|
+
exports.buildRemoveSpendingPolicyCall = buildRemoveSpendingPolicyCall;
|
|
5440
|
+
exports.buildRevokeSessionKeyCall = buildRevokeSessionKeyCall;
|
|
5441
|
+
exports.buildSessionSetupCalls = buildSessionSetupCalls;
|
|
5442
|
+
exports.buildSetSpendingPolicyCall = buildSetSpendingPolicyCall;
|
|
4999
5443
|
exports.buildStarkEnvelope = buildStarkEnvelope;
|
|
5000
5444
|
exports.buildThresholdEnvelope = buildThresholdEnvelope;
|
|
5001
5445
|
exports.buildWebAuthnEnvelopeFromAssertion = buildWebAuthnEnvelopeFromAssertion;
|
|
@@ -5021,6 +5465,7 @@ exports.hashCalls = hashCalls;
|
|
|
5021
5465
|
exports.hashOutsideExecutionStruct = hashOutsideExecutionStruct;
|
|
5022
5466
|
exports.hashStarknetDomain = hashStarknetDomain;
|
|
5023
5467
|
exports.isReadyToExecute = isReadyToExecute;
|
|
5468
|
+
exports.isThinkDecision = isThinkDecision;
|
|
5024
5469
|
exports.jwtAppleSubHash = jwtAppleSubHash;
|
|
5025
5470
|
exports.jwtAppleSubOwnerId = jwtAppleSubOwnerId;
|
|
5026
5471
|
exports.jwtAppleSubPubkeyFelts = jwtAppleSubPubkeyFelts;
|
|
@@ -5028,6 +5473,7 @@ exports.labelToFelt = labelToFelt;
|
|
|
5028
5473
|
exports.locateSubClaim = locateSubClaim;
|
|
5029
5474
|
exports.messageHashToNonceB64url = messageHashToNonceB64url;
|
|
5030
5475
|
exports.migrateChipiWalletToShhh = migrateChipiWalletToShhh;
|
|
5476
|
+
exports.normalizeEntrypoints = normalizeEntrypoints;
|
|
5031
5477
|
exports.ownerCommitment = ownerCommitment;
|
|
5032
5478
|
exports.parseAppleIdToken = parseAppleIdToken;
|
|
5033
5479
|
exports.parseDerEcdsaSignature = parseDerEcdsaSignature;
|
|
@@ -5043,6 +5489,7 @@ exports.snip12HashToHexAsciiBytes = snip12HashToHexAsciiBytes;
|
|
|
5043
5489
|
exports.starkOwnerId = starkOwnerId;
|
|
5044
5490
|
exports.starkPubkeyFelts = starkPubkeyFelts;
|
|
5045
5491
|
exports.submitViaAccount = submitViaAccount;
|
|
5492
|
+
exports.validateSpendingPolicyConfig = validateSpendingPolicyConfig;
|
|
5046
5493
|
exports.waitForTransaction = waitForTransaction;
|
|
5047
5494
|
exports.webauthnOwnerId = webauthnOwnerId;
|
|
5048
5495
|
exports.webauthnOwnerPubkeyParam = webauthnOwnerPubkeyParam;
|