@ottocode/sdk 0.1.203 → 0.1.205
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/package.json +1 -1
- package/src/providers/src/setu-client.ts +86 -19
package/package.json
CHANGED
|
@@ -78,6 +78,7 @@ export type SetuProviderOptions = {
|
|
|
78
78
|
promptCacheKey?: string;
|
|
79
79
|
promptCacheRetention?: 'in_memory' | '24h';
|
|
80
80
|
topupApprovalMode?: 'auto' | 'approval';
|
|
81
|
+
autoPayThresholdUsd?: number;
|
|
81
82
|
};
|
|
82
83
|
|
|
83
84
|
export type SetuAuth = {
|
|
@@ -163,6 +164,7 @@ export function createSetuFetch(
|
|
|
163
164
|
const promptCacheKey = options.promptCacheKey;
|
|
164
165
|
const promptCacheRetention = options.promptCacheRetention;
|
|
165
166
|
const topupApprovalMode = options.topupApprovalMode ?? 'auto';
|
|
167
|
+
const autoPayThresholdUsd = options.autoPayThresholdUsd ?? 0;
|
|
166
168
|
|
|
167
169
|
const baseFetch = globalThis.fetch.bind(globalThis);
|
|
168
170
|
|
|
@@ -232,39 +234,62 @@ export function createSetuFetch(
|
|
|
232
234
|
const amountUsd =
|
|
233
235
|
parseInt(requirement.maxAmountRequired, 10) / 1_000_000;
|
|
234
236
|
|
|
235
|
-
|
|
237
|
+
let walletUsdcBalance = 0;
|
|
238
|
+
if (autoPayThresholdUsd > 0) {
|
|
239
|
+
walletUsdcBalance = await getWalletUsdcBalance(walletAddress, rpcURL);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const canAutoPay =
|
|
243
|
+
autoPayThresholdUsd > 0 && walletUsdcBalance >= autoPayThresholdUsd;
|
|
244
|
+
|
|
245
|
+
const requestApproval = async () => {
|
|
246
|
+
if (!callbacks.onPaymentApproval) return;
|
|
236
247
|
const approval = await callbacks.onPaymentApproval({
|
|
237
248
|
amountUsd,
|
|
238
|
-
currentBalance:
|
|
249
|
+
currentBalance: walletUsdcBalance,
|
|
239
250
|
});
|
|
240
|
-
|
|
241
251
|
if (approval === 'cancel') {
|
|
242
252
|
callbacks.onPaymentError?.('Payment cancelled by user');
|
|
243
253
|
throw new Error('Setu: payment cancelled by user');
|
|
244
254
|
}
|
|
245
|
-
|
|
246
255
|
if (approval === 'fiat') {
|
|
247
256
|
const err = new Error('Setu: fiat payment selected');
|
|
248
257
|
(err as Error & { code: string }).code = 'SETU_FIAT_SELECTED';
|
|
249
258
|
throw err;
|
|
250
259
|
}
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
if (!canAutoPay && topupApprovalMode === 'approval') {
|
|
263
|
+
await requestApproval();
|
|
251
264
|
}
|
|
252
265
|
|
|
253
|
-
callbacks.onPaymentRequired?.(amountUsd,
|
|
254
|
-
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
266
|
+
callbacks.onPaymentRequired?.(amountUsd, walletUsdcBalance);
|
|
267
|
+
|
|
268
|
+
const doPayment = async () => {
|
|
269
|
+
const outcome = await handlePayment({
|
|
270
|
+
requirement,
|
|
271
|
+
keypair,
|
|
272
|
+
rpcURL,
|
|
273
|
+
baseURL,
|
|
274
|
+
baseFetch,
|
|
275
|
+
buildWalletHeaders,
|
|
276
|
+
maxAttempts: remainingPayments,
|
|
277
|
+
callbacks,
|
|
278
|
+
});
|
|
279
|
+
const newTotal = currentAttempts + outcome.attemptsUsed;
|
|
280
|
+
globalPaymentAttempts.set(walletAddress, newTotal);
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
if (canAutoPay) {
|
|
284
|
+
try {
|
|
285
|
+
await doPayment();
|
|
286
|
+
} catch (_autoPayErr) {
|
|
287
|
+
await requestApproval();
|
|
288
|
+
await doPayment();
|
|
289
|
+
}
|
|
290
|
+
} else {
|
|
291
|
+
await doPayment();
|
|
292
|
+
}
|
|
268
293
|
} finally {
|
|
269
294
|
releaseLock();
|
|
270
295
|
}
|
|
@@ -638,6 +663,48 @@ export function getPublicKeyFromPrivate(privateKey: string): string | null {
|
|
|
638
663
|
}
|
|
639
664
|
}
|
|
640
665
|
|
|
666
|
+
async function getWalletUsdcBalance(
|
|
667
|
+
walletAddress: string,
|
|
668
|
+
rpcUrl: string,
|
|
669
|
+
): Promise<number> {
|
|
670
|
+
try {
|
|
671
|
+
const usdcMint = rpcUrl.includes('devnet')
|
|
672
|
+
? USDC_MINT_DEVNET
|
|
673
|
+
: USDC_MINT_MAINNET;
|
|
674
|
+
const response = await fetch(rpcUrl, {
|
|
675
|
+
method: 'POST',
|
|
676
|
+
headers: { 'Content-Type': 'application/json' },
|
|
677
|
+
body: JSON.stringify({
|
|
678
|
+
jsonrpc: '2.0',
|
|
679
|
+
id: 1,
|
|
680
|
+
method: 'getTokenAccountsByOwner',
|
|
681
|
+
params: [walletAddress, { mint: usdcMint }, { encoding: 'jsonParsed' }],
|
|
682
|
+
}),
|
|
683
|
+
});
|
|
684
|
+
if (!response.ok) return 0;
|
|
685
|
+
const data = (await response.json()) as {
|
|
686
|
+
result?: {
|
|
687
|
+
value?: Array<{
|
|
688
|
+
account: {
|
|
689
|
+
data: {
|
|
690
|
+
parsed: {
|
|
691
|
+
info: { tokenAmount: { uiAmount: number } };
|
|
692
|
+
};
|
|
693
|
+
};
|
|
694
|
+
};
|
|
695
|
+
}>;
|
|
696
|
+
};
|
|
697
|
+
};
|
|
698
|
+
let total = 0;
|
|
699
|
+
for (const acct of data.result?.value ?? []) {
|
|
700
|
+
total += acct.account.data.parsed.info.tokenAmount.uiAmount ?? 0;
|
|
701
|
+
}
|
|
702
|
+
return total;
|
|
703
|
+
} catch {
|
|
704
|
+
return 0;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
|
|
641
708
|
const USDC_MINT_MAINNET = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v';
|
|
642
709
|
const USDC_MINT_DEVNET = '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU';
|
|
643
710
|
|