@chipi-stack/backend 14.14.0 → 14.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{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 +35 -6
- package/dist/index.d.ts +35 -6
- package/dist/index.js +321 -127
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +321 -127
- package/dist/index.mjs.map +1 -1
- package/dist/skuPurchases.d.mts +1 -1
- package/dist/skuPurchases.d.ts +1 -1
- package/dist/skus.d.mts +1 -1
- package/dist/skus.d.ts +1 -1
- package/dist/transactions.d.mts +1 -1
- package/dist/transactions.d.ts +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;
|
|
@@ -3113,8 +3119,149 @@ var ChipiTreasury = class {
|
|
|
3113
3119
|
};
|
|
3114
3120
|
}
|
|
3115
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
|
|
3116
3240
|
var AI_BASE = "/ai";
|
|
3117
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));
|
|
3118
3265
|
function isThinkDecision(decision) {
|
|
3119
3266
|
if (!decision || typeof decision !== "object") return false;
|
|
3120
3267
|
const d = decision;
|
|
@@ -3128,9 +3275,10 @@ function isThinkDecision(decision) {
|
|
|
3128
3275
|
return true;
|
|
3129
3276
|
}
|
|
3130
3277
|
var ChipiAi = class {
|
|
3131
|
-
constructor(client, apiSecretKey) {
|
|
3278
|
+
constructor(client, apiSecretKey, sessions) {
|
|
3132
3279
|
this.client = client;
|
|
3133
3280
|
this.apiSecretKey = apiSecretKey;
|
|
3281
|
+
this.sessions = sessions;
|
|
3134
3282
|
}
|
|
3135
3283
|
secret() {
|
|
3136
3284
|
const key = this.apiSecretKey;
|
|
@@ -3161,13 +3309,175 @@ var ChipiAi = class {
|
|
|
3161
3309
|
*
|
|
3162
3310
|
* The decision is advice, not an order: check it with `isThinkDecision` and
|
|
3163
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
|
+
* ```
|
|
3164
3330
|
*/
|
|
3165
|
-
async think(params) {
|
|
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) {
|
|
3166
3341
|
return this.client.post({
|
|
3167
3342
|
endpoint: `${AI_BASE}/think`,
|
|
3168
3343
|
bearerToken: this.secret(),
|
|
3169
|
-
body: params
|
|
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
|
|
3170
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
|
+
}
|
|
3171
3481
|
}
|
|
3172
3482
|
/**
|
|
3173
3483
|
* `POST /v1/ai/execute`: unsigned AVNU swap calls (approve + swap) for
|
|
@@ -3529,7 +3839,7 @@ var ChipiSDK = class {
|
|
|
3529
3839
|
this.sessions = new ChipiSessions(this.client);
|
|
3530
3840
|
this.exchanges = new ChipiExchanges(this.client);
|
|
3531
3841
|
this.treasury = new ChipiTreasury(this.client, config.apiSecretKey);
|
|
3532
|
-
this.ai = new ChipiAi(this.client, config.apiSecretKey);
|
|
3842
|
+
this.ai = new ChipiAi(this.client, config.apiSecretKey, this.sessions);
|
|
3533
3843
|
this.executeTransaction = this.executeTransaction.bind(this);
|
|
3534
3844
|
this.executeTransactionWithSession = this.executeTransactionWithSession.bind(this);
|
|
3535
3845
|
this.transfer = this.transfer.bind(this);
|
|
@@ -3842,49 +4152,6 @@ var ChipiBrowserSDK = class extends ChipiSDK {
|
|
|
3842
4152
|
// All methods are inherited from ChipiSDK
|
|
3843
4153
|
// bearerToken parameter is required for each authenticated request
|
|
3844
4154
|
};
|
|
3845
|
-
var DEFAULT_RETRY_INTERVAL_MS = 3e3;
|
|
3846
|
-
var DEFAULT_TIMEOUT_MS = 3e5;
|
|
3847
|
-
function isPending(finalityStatus) {
|
|
3848
|
-
return finalityStatus === void 0 || finalityStatus === "RECEIVED" || finalityStatus === "PENDING" || finalityStatus === "PRE_CONFIRMED";
|
|
3849
|
-
}
|
|
3850
|
-
async function waitForTransaction(transactionHash, options = {}) {
|
|
3851
|
-
const {
|
|
3852
|
-
nodeUrl = shared.WALLET_RPC_ENDPOINTS.CHIPI,
|
|
3853
|
-
retryIntervalMs = DEFAULT_RETRY_INTERVAL_MS,
|
|
3854
|
-
timeoutMs = DEFAULT_TIMEOUT_MS
|
|
3855
|
-
} = options;
|
|
3856
|
-
const deadline = Date.now() + timeoutMs;
|
|
3857
|
-
let lastError;
|
|
3858
|
-
for (; ; ) {
|
|
3859
|
-
try {
|
|
3860
|
-
const receipt = await shared.withRpcFallback(
|
|
3861
|
-
(provider) => provider.getTransactionReceipt(transactionHash),
|
|
3862
|
-
{ fallbackUrl: nodeUrl }
|
|
3863
|
-
);
|
|
3864
|
-
if (!isPending(receipt?.finality_status)) {
|
|
3865
|
-
const reverted = receipt.execution_status === "REVERTED";
|
|
3866
|
-
return {
|
|
3867
|
-
transactionHash,
|
|
3868
|
-
success: !reverted,
|
|
3869
|
-
executionStatus: receipt.execution_status,
|
|
3870
|
-
finalityStatus: receipt.finality_status,
|
|
3871
|
-
...reverted ? { revertReason: receipt.revert_reason ?? "reverted on chain" } : {},
|
|
3872
|
-
events: receipt.events ?? [],
|
|
3873
|
-
...receipt.block_number !== void 0 ? { blockNumber: receipt.block_number } : {}
|
|
3874
|
-
};
|
|
3875
|
-
}
|
|
3876
|
-
} catch (err) {
|
|
3877
|
-
lastError = err;
|
|
3878
|
-
}
|
|
3879
|
-
if (Date.now() + retryIntervalMs >= deadline) {
|
|
3880
|
-
const detail = lastError instanceof Error ? `: ${lastError.message}` : "";
|
|
3881
|
-
throw new Error(
|
|
3882
|
-
`Timed out after ${timeoutMs}ms waiting for ${transactionHash}${detail}. The transaction may still land; re-check before treating it as failed.`
|
|
3883
|
-
);
|
|
3884
|
-
}
|
|
3885
|
-
await new Promise((resolve) => setTimeout(resolve, retryIntervalMs));
|
|
3886
|
-
}
|
|
3887
|
-
}
|
|
3888
4155
|
|
|
3889
4156
|
// src/index.ts
|
|
3890
4157
|
init_encryption2();
|
|
@@ -4209,79 +4476,6 @@ function x402Middleware(config) {
|
|
|
4209
4476
|
next();
|
|
4210
4477
|
};
|
|
4211
4478
|
}
|
|
4212
|
-
var InMemoryTxHashStore = class {
|
|
4213
|
-
constructor() {
|
|
4214
|
-
this.used = /* @__PURE__ */ new Set();
|
|
4215
|
-
}
|
|
4216
|
-
consume(transactionHash) {
|
|
4217
|
-
if (this.used.has(transactionHash)) return false;
|
|
4218
|
-
this.used.add(transactionHash);
|
|
4219
|
-
return true;
|
|
4220
|
-
}
|
|
4221
|
-
};
|
|
4222
|
-
var TRANSFER_SELECTOR = BigInt(starknet.hash.getSelectorFromName("Transfer"));
|
|
4223
|
-
function toBigInt2(value) {
|
|
4224
|
-
if (value === void 0) return void 0;
|
|
4225
|
-
try {
|
|
4226
|
-
return BigInt(value);
|
|
4227
|
-
} catch {
|
|
4228
|
-
return void 0;
|
|
4229
|
-
}
|
|
4230
|
-
}
|
|
4231
|
-
function decodeTransfer(event) {
|
|
4232
|
-
if (toBigInt2(event.keys[0]) !== TRANSFER_SELECTOR) return void 0;
|
|
4233
|
-
const [from, to, low, high] = event.keys.length >= 3 ? [event.keys[1], event.keys[2], event.data[0], event.data[1]] : [event.data[0], event.data[1], event.data[2], event.data[3]];
|
|
4234
|
-
const values = [from, to, low, high].map(toBigInt2);
|
|
4235
|
-
if (values.some((v) => v === void 0)) return void 0;
|
|
4236
|
-
const [f, t, l, h] = values;
|
|
4237
|
-
return { from: f, to: t, amount: l + (h << 128n) };
|
|
4238
|
-
}
|
|
4239
|
-
var SessionTxVerifier = class {
|
|
4240
|
-
constructor(config = {}) {
|
|
4241
|
-
const { txHashStore, getReceipt, ...receiptOptions } = config;
|
|
4242
|
-
this.store = txHashStore ?? new InMemoryTxHashStore();
|
|
4243
|
-
this.getReceipt = getReceipt ?? waitForTransaction;
|
|
4244
|
-
this.receiptOptions = receiptOptions;
|
|
4245
|
-
}
|
|
4246
|
-
async verifyTransfer(params) {
|
|
4247
|
-
const { transactionHash, token, from, to, minAmount } = params;
|
|
4248
|
-
const receipt = await this.getReceipt(transactionHash, this.receiptOptions);
|
|
4249
|
-
if (!receipt.success) {
|
|
4250
|
-
return { valid: false, transactionHash, reason: "REVERTED", detail: receipt.revertReason };
|
|
4251
|
-
}
|
|
4252
|
-
const tokenAddress = BigInt(token);
|
|
4253
|
-
const fromAddress = BigInt(from);
|
|
4254
|
-
const toAddress = BigInt(to);
|
|
4255
|
-
let best;
|
|
4256
|
-
for (const event of receipt.events) {
|
|
4257
|
-
if (toBigInt2(event.from_address) !== tokenAddress) continue;
|
|
4258
|
-
const transfer = decodeTransfer(event);
|
|
4259
|
-
if (!transfer || transfer.from !== fromAddress || transfer.to !== toAddress) continue;
|
|
4260
|
-
if (best === void 0 || transfer.amount > best) best = transfer.amount;
|
|
4261
|
-
}
|
|
4262
|
-
if (best === void 0) {
|
|
4263
|
-
return { valid: false, transactionHash, reason: "TRANSFER_NOT_FOUND" };
|
|
4264
|
-
}
|
|
4265
|
-
if (best < minAmount) {
|
|
4266
|
-
return {
|
|
4267
|
-
valid: false,
|
|
4268
|
-
transactionHash,
|
|
4269
|
-
reason: "AMOUNT_TOO_LOW",
|
|
4270
|
-
detail: `paid ${best}, expected at least ${minAmount}`
|
|
4271
|
-
};
|
|
4272
|
-
}
|
|
4273
|
-
const key = "0x" + BigInt(transactionHash).toString(16);
|
|
4274
|
-
if (!await this.store.consume(key)) {
|
|
4275
|
-
return { valid: false, transactionHash, reason: "ALREADY_USED" };
|
|
4276
|
-
}
|
|
4277
|
-
return {
|
|
4278
|
-
valid: true,
|
|
4279
|
-
transactionHash,
|
|
4280
|
-
amount: best,
|
|
4281
|
-
...receipt.blockNumber !== void 0 ? { blockNumber: receipt.blockNumber } : {}
|
|
4282
|
-
};
|
|
4283
|
-
}
|
|
4284
|
-
};
|
|
4285
4479
|
|
|
4286
4480
|
// src/shhh/index.ts
|
|
4287
4481
|
init_snip12_hash();
|