@owney/sdk 0.7.6 → 0.7.7-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +77 -38
- package/dist/index.d.cts +23 -12
- package/dist/index.d.ts +23 -12
- package/dist/index.js +77 -38
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1912,9 +1912,12 @@ async function postSponsorTransferAuth(input) {
|
|
|
1912
1912
|
{
|
|
1913
1913
|
statusCode: res.status,
|
|
1914
1914
|
responseBody: text.slice(0, 500),
|
|
1915
|
-
//
|
|
1916
|
-
//
|
|
1917
|
-
|
|
1915
|
+
// A 4xx is an explicit refusal before execution (DTO validation,
|
|
1916
|
+
// signature rejection, simulation) — nothing was broadcast, so a
|
|
1917
|
+
// user-paid retry cannot double-spend. 503 SPONSOR_UNAVAILABLE means
|
|
1918
|
+
// the relayer was out of gas, also pre-broadcast. Any other 5xx stays
|
|
1919
|
+
// ambiguous: the transfer may already be in flight.
|
|
1920
|
+
safeToFallback: res.status >= 400 && res.status < 500 || res.status === 503
|
|
1918
1921
|
}
|
|
1919
1922
|
);
|
|
1920
1923
|
}
|
|
@@ -2186,9 +2189,9 @@ function makeSponsoredDepositCallback(deps) {
|
|
|
2186
2189
|
};
|
|
2187
2190
|
}
|
|
2188
2191
|
|
|
2189
|
-
// src/lib/sponsored-
|
|
2192
|
+
// src/lib/sponsored-permit2-deposit.ts
|
|
2190
2193
|
var PERMIT_WINDOW_SECONDS = 15 * 60;
|
|
2191
|
-
function
|
|
2194
|
+
function makeSponsoredPermit2Callback(deps) {
|
|
2192
2195
|
const get = deps.httpGet ?? getSponsorRelayerAddress;
|
|
2193
2196
|
const post = deps.httpPost ?? postSponsorPermit2Transfer;
|
|
2194
2197
|
return async (smartWallet, chainId, amount) => {
|
|
@@ -2197,7 +2200,7 @@ function makeSponsoredWethCallback(deps) {
|
|
|
2197
2200
|
if (!token) {
|
|
2198
2201
|
throw new OwneyError(
|
|
2199
2202
|
"CHAIN_UNSUPPORTED",
|
|
2200
|
-
`No sponsored
|
|
2203
|
+
`No sponsored ${deps.assetLabel} configured for chain ${chainId}`
|
|
2201
2204
|
);
|
|
2202
2205
|
}
|
|
2203
2206
|
const amountWei = BigInt(amount);
|
|
@@ -2209,14 +2212,14 @@ function makeSponsoredWethCallback(deps) {
|
|
|
2209
2212
|
if (balance < amountWei) {
|
|
2210
2213
|
throw new OwneyError(
|
|
2211
2214
|
"DEPOSIT_INSUFFICIENT_BALANCE",
|
|
2212
|
-
|
|
2215
|
+
`Insufficient ${deps.assetLabel} balance for this deposit.`,
|
|
2213
2216
|
{ token, chainId: cid, balance: balance.toString(), amount }
|
|
2214
2217
|
);
|
|
2215
2218
|
}
|
|
2216
2219
|
} catch (err) {
|
|
2217
2220
|
if (err instanceof OwneyError) throw err;
|
|
2218
2221
|
console.warn(
|
|
2219
|
-
|
|
2222
|
+
`[owney-sdk] ${deps.assetLabel} balance pre-check failed (non-fatal):`,
|
|
2220
2223
|
err instanceof Error ? err.message : String(err)
|
|
2221
2224
|
);
|
|
2222
2225
|
}
|
|
@@ -2224,7 +2227,7 @@ function makeSponsoredWethCallback(deps) {
|
|
|
2224
2227
|
if (allowance < amountWei) {
|
|
2225
2228
|
throw new OwneyError(
|
|
2226
2229
|
"PERMIT2_APPROVAL_REQUIRED",
|
|
2227
|
-
|
|
2230
|
+
`${deps.assetLabel} gasless deposits need a one-time Permit2 approval; call approvePermit2("${deps.assetLabel}") first`,
|
|
2228
2231
|
{ token, chainId: cid, allowance: allowance.toString(), amount }
|
|
2229
2232
|
);
|
|
2230
2233
|
}
|
|
@@ -2329,7 +2332,7 @@ var OwneySDK = class {
|
|
|
2329
2332
|
routingApiBaseUrl;
|
|
2330
2333
|
referralSource;
|
|
2331
2334
|
cachedSponsoredCallback = null;
|
|
2332
|
-
|
|
2335
|
+
cachedPermit2Callbacks = /* @__PURE__ */ new Map();
|
|
2333
2336
|
initializingAgentsPromise = null;
|
|
2334
2337
|
constructor(config) {
|
|
2335
2338
|
this.apiKey = config.apiKey;
|
|
@@ -2357,7 +2360,7 @@ var OwneySDK = class {
|
|
|
2357
2360
|
}
|
|
2358
2361
|
this.state = { provider, walletAddress, chainId: null };
|
|
2359
2362
|
this.cachedSponsoredCallback = null;
|
|
2360
|
-
this.
|
|
2363
|
+
this.cachedPermit2Callbacks.clear();
|
|
2361
2364
|
}
|
|
2362
2365
|
/**
|
|
2363
2366
|
* Disconnect from all agents and clear connection state.
|
|
@@ -2371,7 +2374,7 @@ var OwneySDK = class {
|
|
|
2371
2374
|
this.disabledAgents.clear();
|
|
2372
2375
|
this.state = null;
|
|
2373
2376
|
this.cachedSponsoredCallback = null;
|
|
2374
|
-
this.
|
|
2377
|
+
this.cachedPermit2Callbacks.clear();
|
|
2375
2378
|
}
|
|
2376
2379
|
isAgentDisabled(agentId) {
|
|
2377
2380
|
return this.disabledAgents.has(agentId);
|
|
@@ -2448,25 +2451,23 @@ var OwneySDK = class {
|
|
|
2448
2451
|
return callback;
|
|
2449
2452
|
}
|
|
2450
2453
|
/**
|
|
2451
|
-
* Lazily builds (and caches) the
|
|
2452
|
-
*
|
|
2453
|
-
*
|
|
2454
|
-
*
|
|
2454
|
+
* Lazily builds (and caches) the Permit2 sponsored callback for one asset.
|
|
2455
|
+
* Used for WETH always, and for USDC when the connected owner is a smart
|
|
2456
|
+
* account — EIP-3009 verifies with ecrecover inside USDC and cannot accept a
|
|
2457
|
+
* contract signature, while Permit2 supports ERC-1271.
|
|
2455
2458
|
*/
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
+
getDefaultPermit2Callback(asset, onApproved) {
|
|
2460
|
+
const cached = this.cachedPermit2Callbacks.get(asset);
|
|
2461
|
+
if (!onApproved && cached) return cached;
|
|
2459
2462
|
const provider = this.requireConnectedProvider();
|
|
2460
2463
|
const owner = this.state.walletAddress;
|
|
2461
|
-
const callback =
|
|
2464
|
+
const callback = makeSponsoredPermit2Callback({
|
|
2462
2465
|
apiKey: this.apiKey,
|
|
2463
2466
|
baseUrl: this.routingApiBaseUrl,
|
|
2464
2467
|
ownerAddress: owner,
|
|
2468
|
+
assetLabel: asset,
|
|
2465
2469
|
onApproved,
|
|
2466
|
-
tokenAddressByChain: SPONSORED_WETH_BY_CHAIN,
|
|
2467
|
-
// Casts work around viem's chain-narrowed Client vs the generic
|
|
2468
|
-
// PublicClient/WalletClient param types — structurally identical at
|
|
2469
|
-
// runtime, but the two share a name TS treats as unrelated.
|
|
2470
|
+
tokenAddressByChain: asset === "USDC" ? SPONSORED_USDC_BY_CHAIN : SPONSORED_WETH_BY_CHAIN,
|
|
2470
2471
|
getPublicClient: (cid) => (0, import_viem5.createPublicClient)({
|
|
2471
2472
|
chain: VIEM_CHAIN2[cid],
|
|
2472
2473
|
transport: (0, import_viem5.custom)(provider)
|
|
@@ -2477,9 +2478,34 @@ var OwneySDK = class {
|
|
|
2477
2478
|
transport: (0, import_viem5.custom)(provider)
|
|
2478
2479
|
})
|
|
2479
2480
|
});
|
|
2480
|
-
if (!onApproved) this.
|
|
2481
|
+
if (!onApproved) this.cachedPermit2Callbacks.set(asset, callback);
|
|
2481
2482
|
return callback;
|
|
2482
2483
|
}
|
|
2484
|
+
/**
|
|
2485
|
+
* True when the connected owner has bytecode — a deployed smart wallet, or an
|
|
2486
|
+
* EOA carrying an EIP-7702 delegation (the Base app's "Upgrade your wallet").
|
|
2487
|
+
* Such wallets sign via ERC-1271, which EIP-3009 cannot verify.
|
|
2488
|
+
*
|
|
2489
|
+
* Fails OPEN: an unreadable code check returns false so a working EOA deposit
|
|
2490
|
+
* is never blocked by a flaky provider.
|
|
2491
|
+
*/
|
|
2492
|
+
async ownerHasCode() {
|
|
2493
|
+
try {
|
|
2494
|
+
const provider = this.requireConnectedProvider();
|
|
2495
|
+
const code = await provider.request({
|
|
2496
|
+
method: "eth_getCode",
|
|
2497
|
+
params: [this.state.walletAddress, "latest"]
|
|
2498
|
+
});
|
|
2499
|
+
return Boolean(code) && code !== "0x";
|
|
2500
|
+
} catch (error) {
|
|
2501
|
+
debugLog(
|
|
2502
|
+
"deposit",
|
|
2503
|
+
"owner code check failed; assuming EOA",
|
|
2504
|
+
error instanceof Error ? error.message : String(error)
|
|
2505
|
+
);
|
|
2506
|
+
return false;
|
|
2507
|
+
}
|
|
2508
|
+
}
|
|
2483
2509
|
getAgent(agentId) {
|
|
2484
2510
|
const agent = this.agents.get(agentId);
|
|
2485
2511
|
if (!agent) {
|
|
@@ -2675,7 +2701,11 @@ var OwneySDK = class {
|
|
|
2675
2701
|
}
|
|
2676
2702
|
const state = this.requireState();
|
|
2677
2703
|
const chainId = this.requireChainId();
|
|
2678
|
-
const
|
|
2704
|
+
const ownerIsSmartAccount = depositCallback === void 0 && asset !== "WETH" ? await this.ownerHasCode() : false;
|
|
2705
|
+
const effectiveCallback = depositCallback ?? (asset === "WETH" || ownerIsSmartAccount ? this.getDefaultPermit2Callback(
|
|
2706
|
+
asset === "WETH" ? "WETH" : "USDC",
|
|
2707
|
+
onApproved
|
|
2708
|
+
) : this.getDefaultSponsoredCallback(onApproved));
|
|
2679
2709
|
if (agentId) {
|
|
2680
2710
|
if (this.isAgentDisabled(agentId)) {
|
|
2681
2711
|
throw new OwneyError(
|
|
@@ -2779,12 +2809,12 @@ var OwneySDK = class {
|
|
|
2779
2809
|
try {
|
|
2780
2810
|
return await attempt(effectiveCallback);
|
|
2781
2811
|
} catch (error) {
|
|
2782
|
-
if (!approvalAttempted && appCallback === void 0 && asset === "WETH" && error instanceof OwneyError && error.code === "PERMIT2_APPROVAL_REQUIRED") {
|
|
2812
|
+
if (!approvalAttempted && appCallback === void 0 && (asset === "WETH" || asset === "USDC") && error instanceof OwneyError && error.code === "PERMIT2_APPROVAL_REQUIRED") {
|
|
2783
2813
|
approvalAttempted = true;
|
|
2784
2814
|
console.warn(
|
|
2785
|
-
|
|
2815
|
+
`[owney-sdk] First ${asset} gasless deposit: sending one-time Permit2 approval...`
|
|
2786
2816
|
);
|
|
2787
|
-
await this.approvePermit2();
|
|
2817
|
+
await this.approvePermit2(asset);
|
|
2788
2818
|
continue;
|
|
2789
2819
|
}
|
|
2790
2820
|
if (!shouldFallbackToUserPaid(error, asset, appCallback)) throw error;
|
|
@@ -3298,23 +3328,32 @@ var OwneySDK = class {
|
|
|
3298
3328
|
return agent.ensureAutoSelectProtocols(state, chainId, asset);
|
|
3299
3329
|
}
|
|
3300
3330
|
/**
|
|
3301
|
-
* One-time, user-paid approval of Permit2 on the sponsored
|
|
3302
|
-
* the active chain. Required once per wallet per chain before
|
|
3303
|
-
*
|
|
3304
|
-
*
|
|
3305
|
-
*
|
|
3331
|
+
* One-time, user-paid approval of Permit2 on the given sponsored token for
|
|
3332
|
+
* the active chain. Required once per wallet per chain per token before a
|
|
3333
|
+
* gasless deposit of that asset over Permit2; afterwards deposit() is
|
|
3334
|
+
* signature-only for it. This call itself is a real transaction the user
|
|
3335
|
+
* pays gas for. Resolves only after the approval transaction is mined (1
|
|
3336
|
+
* confirmation), so a subsequent deposit() will see the new allowance;
|
|
3337
|
+
* throws if the transaction reverted.
|
|
3306
3338
|
* @returns the approval transaction hash.
|
|
3307
3339
|
*/
|
|
3308
3340
|
async approvePermit2(asset = "WETH") {
|
|
3309
|
-
void asset;
|
|
3310
3341
|
const state = this.requireState();
|
|
3311
3342
|
const chainId = this.requireChainId();
|
|
3312
|
-
this.
|
|
3313
|
-
|
|
3343
|
+
let guard = this.agents.get("zyfai");
|
|
3344
|
+
if (!guard) {
|
|
3345
|
+
try {
|
|
3346
|
+
guard = this.getEligibleAgents(chainId, asset)[0];
|
|
3347
|
+
} catch {
|
|
3348
|
+
guard = void 0;
|
|
3349
|
+
}
|
|
3350
|
+
}
|
|
3351
|
+
if (guard) this.validateAssetSupport(guard, chainId, asset);
|
|
3352
|
+
const token = asset === "USDC" ? SPONSORED_USDC_BY_CHAIN[chainId] : SPONSORED_WETH_BY_CHAIN[chainId];
|
|
3314
3353
|
if (!token) {
|
|
3315
3354
|
throw new OwneyError(
|
|
3316
3355
|
"CHAIN_UNSUPPORTED",
|
|
3317
|
-
`No sponsored
|
|
3356
|
+
`No sponsored ${asset} on chain ${chainId}`
|
|
3318
3357
|
);
|
|
3319
3358
|
}
|
|
3320
3359
|
const provider = this.requireConnectedProvider();
|
package/dist/index.d.cts
CHANGED
|
@@ -392,7 +392,7 @@ declare class OwneySDK {
|
|
|
392
392
|
private routingApiBaseUrl?;
|
|
393
393
|
private referralSource?;
|
|
394
394
|
private cachedSponsoredCallback;
|
|
395
|
-
private
|
|
395
|
+
private cachedPermit2Callbacks;
|
|
396
396
|
private initializingAgentsPromise;
|
|
397
397
|
constructor(config: OwneySDKConfig);
|
|
398
398
|
/**
|
|
@@ -428,12 +428,21 @@ declare class OwneySDK {
|
|
|
428
428
|
*/
|
|
429
429
|
private getDefaultSponsoredCallback;
|
|
430
430
|
/**
|
|
431
|
-
* Lazily builds (and caches) the
|
|
432
|
-
*
|
|
433
|
-
*
|
|
434
|
-
*
|
|
431
|
+
* Lazily builds (and caches) the Permit2 sponsored callback for one asset.
|
|
432
|
+
* Used for WETH always, and for USDC when the connected owner is a smart
|
|
433
|
+
* account — EIP-3009 verifies with ecrecover inside USDC and cannot accept a
|
|
434
|
+
* contract signature, while Permit2 supports ERC-1271.
|
|
435
435
|
*/
|
|
436
|
-
private
|
|
436
|
+
private getDefaultPermit2Callback;
|
|
437
|
+
/**
|
|
438
|
+
* True when the connected owner has bytecode — a deployed smart wallet, or an
|
|
439
|
+
* EOA carrying an EIP-7702 delegation (the Base app's "Upgrade your wallet").
|
|
440
|
+
* Such wallets sign via ERC-1271, which EIP-3009 cannot verify.
|
|
441
|
+
*
|
|
442
|
+
* Fails OPEN: an unreadable code check returns false so a working EOA deposit
|
|
443
|
+
* is never blocked by a flaky provider.
|
|
444
|
+
*/
|
|
445
|
+
private ownerHasCode;
|
|
437
446
|
private getAgent;
|
|
438
447
|
private getActiveAgents;
|
|
439
448
|
/**
|
|
@@ -578,14 +587,16 @@ declare class OwneySDK {
|
|
|
578
587
|
*/
|
|
579
588
|
ensureAutoSelectProtocols(asset: "USDC" | "WETH", agentId?: AgentId): Promise<boolean>;
|
|
580
589
|
/**
|
|
581
|
-
* One-time, user-paid approval of Permit2 on the sponsored
|
|
582
|
-
* the active chain. Required once per wallet per chain before
|
|
583
|
-
*
|
|
584
|
-
*
|
|
585
|
-
*
|
|
590
|
+
* One-time, user-paid approval of Permit2 on the given sponsored token for
|
|
591
|
+
* the active chain. Required once per wallet per chain per token before a
|
|
592
|
+
* gasless deposit of that asset over Permit2; afterwards deposit() is
|
|
593
|
+
* signature-only for it. This call itself is a real transaction the user
|
|
594
|
+
* pays gas for. Resolves only after the approval transaction is mined (1
|
|
595
|
+
* confirmation), so a subsequent deposit() will see the new allowance;
|
|
596
|
+
* throws if the transaction reverted.
|
|
586
597
|
* @returns the approval transaction hash.
|
|
587
598
|
*/
|
|
588
|
-
approvePermit2(asset?: "WETH"): Promise<`0x${string}`>;
|
|
599
|
+
approvePermit2(asset?: "WETH" | "USDC"): Promise<`0x${string}`>;
|
|
589
600
|
/**
|
|
590
601
|
* Get the agent's average APY performance over a time period. Does not require a wallet connection.
|
|
591
602
|
* @param options - Contains agentId (optional) and days ("7D", "14D", or "30D")
|
package/dist/index.d.ts
CHANGED
|
@@ -392,7 +392,7 @@ declare class OwneySDK {
|
|
|
392
392
|
private routingApiBaseUrl?;
|
|
393
393
|
private referralSource?;
|
|
394
394
|
private cachedSponsoredCallback;
|
|
395
|
-
private
|
|
395
|
+
private cachedPermit2Callbacks;
|
|
396
396
|
private initializingAgentsPromise;
|
|
397
397
|
constructor(config: OwneySDKConfig);
|
|
398
398
|
/**
|
|
@@ -428,12 +428,21 @@ declare class OwneySDK {
|
|
|
428
428
|
*/
|
|
429
429
|
private getDefaultSponsoredCallback;
|
|
430
430
|
/**
|
|
431
|
-
* Lazily builds (and caches) the
|
|
432
|
-
*
|
|
433
|
-
*
|
|
434
|
-
*
|
|
431
|
+
* Lazily builds (and caches) the Permit2 sponsored callback for one asset.
|
|
432
|
+
* Used for WETH always, and for USDC when the connected owner is a smart
|
|
433
|
+
* account — EIP-3009 verifies with ecrecover inside USDC and cannot accept a
|
|
434
|
+
* contract signature, while Permit2 supports ERC-1271.
|
|
435
435
|
*/
|
|
436
|
-
private
|
|
436
|
+
private getDefaultPermit2Callback;
|
|
437
|
+
/**
|
|
438
|
+
* True when the connected owner has bytecode — a deployed smart wallet, or an
|
|
439
|
+
* EOA carrying an EIP-7702 delegation (the Base app's "Upgrade your wallet").
|
|
440
|
+
* Such wallets sign via ERC-1271, which EIP-3009 cannot verify.
|
|
441
|
+
*
|
|
442
|
+
* Fails OPEN: an unreadable code check returns false so a working EOA deposit
|
|
443
|
+
* is never blocked by a flaky provider.
|
|
444
|
+
*/
|
|
445
|
+
private ownerHasCode;
|
|
437
446
|
private getAgent;
|
|
438
447
|
private getActiveAgents;
|
|
439
448
|
/**
|
|
@@ -578,14 +587,16 @@ declare class OwneySDK {
|
|
|
578
587
|
*/
|
|
579
588
|
ensureAutoSelectProtocols(asset: "USDC" | "WETH", agentId?: AgentId): Promise<boolean>;
|
|
580
589
|
/**
|
|
581
|
-
* One-time, user-paid approval of Permit2 on the sponsored
|
|
582
|
-
* the active chain. Required once per wallet per chain before
|
|
583
|
-
*
|
|
584
|
-
*
|
|
585
|
-
*
|
|
590
|
+
* One-time, user-paid approval of Permit2 on the given sponsored token for
|
|
591
|
+
* the active chain. Required once per wallet per chain per token before a
|
|
592
|
+
* gasless deposit of that asset over Permit2; afterwards deposit() is
|
|
593
|
+
* signature-only for it. This call itself is a real transaction the user
|
|
594
|
+
* pays gas for. Resolves only after the approval transaction is mined (1
|
|
595
|
+
* confirmation), so a subsequent deposit() will see the new allowance;
|
|
596
|
+
* throws if the transaction reverted.
|
|
586
597
|
* @returns the approval transaction hash.
|
|
587
598
|
*/
|
|
588
|
-
approvePermit2(asset?: "WETH"): Promise<`0x${string}`>;
|
|
599
|
+
approvePermit2(asset?: "WETH" | "USDC"): Promise<`0x${string}`>;
|
|
589
600
|
/**
|
|
590
601
|
* Get the agent's average APY performance over a time period. Does not require a wallet connection.
|
|
591
602
|
* @param options - Contains agentId (optional) and days ("7D", "14D", or "30D")
|
package/dist/index.js
CHANGED
|
@@ -1883,9 +1883,12 @@ async function postSponsorTransferAuth(input) {
|
|
|
1883
1883
|
{
|
|
1884
1884
|
statusCode: res.status,
|
|
1885
1885
|
responseBody: text.slice(0, 500),
|
|
1886
|
-
//
|
|
1887
|
-
//
|
|
1888
|
-
|
|
1886
|
+
// A 4xx is an explicit refusal before execution (DTO validation,
|
|
1887
|
+
// signature rejection, simulation) — nothing was broadcast, so a
|
|
1888
|
+
// user-paid retry cannot double-spend. 503 SPONSOR_UNAVAILABLE means
|
|
1889
|
+
// the relayer was out of gas, also pre-broadcast. Any other 5xx stays
|
|
1890
|
+
// ambiguous: the transfer may already be in flight.
|
|
1891
|
+
safeToFallback: res.status >= 400 && res.status < 500 || res.status === 503
|
|
1889
1892
|
}
|
|
1890
1893
|
);
|
|
1891
1894
|
}
|
|
@@ -2157,9 +2160,9 @@ function makeSponsoredDepositCallback(deps) {
|
|
|
2157
2160
|
};
|
|
2158
2161
|
}
|
|
2159
2162
|
|
|
2160
|
-
// src/lib/sponsored-
|
|
2163
|
+
// src/lib/sponsored-permit2-deposit.ts
|
|
2161
2164
|
var PERMIT_WINDOW_SECONDS = 15 * 60;
|
|
2162
|
-
function
|
|
2165
|
+
function makeSponsoredPermit2Callback(deps) {
|
|
2163
2166
|
const get = deps.httpGet ?? getSponsorRelayerAddress;
|
|
2164
2167
|
const post = deps.httpPost ?? postSponsorPermit2Transfer;
|
|
2165
2168
|
return async (smartWallet, chainId, amount) => {
|
|
@@ -2168,7 +2171,7 @@ function makeSponsoredWethCallback(deps) {
|
|
|
2168
2171
|
if (!token) {
|
|
2169
2172
|
throw new OwneyError(
|
|
2170
2173
|
"CHAIN_UNSUPPORTED",
|
|
2171
|
-
`No sponsored
|
|
2174
|
+
`No sponsored ${deps.assetLabel} configured for chain ${chainId}`
|
|
2172
2175
|
);
|
|
2173
2176
|
}
|
|
2174
2177
|
const amountWei = BigInt(amount);
|
|
@@ -2180,14 +2183,14 @@ function makeSponsoredWethCallback(deps) {
|
|
|
2180
2183
|
if (balance < amountWei) {
|
|
2181
2184
|
throw new OwneyError(
|
|
2182
2185
|
"DEPOSIT_INSUFFICIENT_BALANCE",
|
|
2183
|
-
|
|
2186
|
+
`Insufficient ${deps.assetLabel} balance for this deposit.`,
|
|
2184
2187
|
{ token, chainId: cid, balance: balance.toString(), amount }
|
|
2185
2188
|
);
|
|
2186
2189
|
}
|
|
2187
2190
|
} catch (err) {
|
|
2188
2191
|
if (err instanceof OwneyError) throw err;
|
|
2189
2192
|
console.warn(
|
|
2190
|
-
|
|
2193
|
+
`[owney-sdk] ${deps.assetLabel} balance pre-check failed (non-fatal):`,
|
|
2191
2194
|
err instanceof Error ? err.message : String(err)
|
|
2192
2195
|
);
|
|
2193
2196
|
}
|
|
@@ -2195,7 +2198,7 @@ function makeSponsoredWethCallback(deps) {
|
|
|
2195
2198
|
if (allowance < amountWei) {
|
|
2196
2199
|
throw new OwneyError(
|
|
2197
2200
|
"PERMIT2_APPROVAL_REQUIRED",
|
|
2198
|
-
|
|
2201
|
+
`${deps.assetLabel} gasless deposits need a one-time Permit2 approval; call approvePermit2("${deps.assetLabel}") first`,
|
|
2199
2202
|
{ token, chainId: cid, allowance: allowance.toString(), amount }
|
|
2200
2203
|
);
|
|
2201
2204
|
}
|
|
@@ -2300,7 +2303,7 @@ var OwneySDK = class {
|
|
|
2300
2303
|
routingApiBaseUrl;
|
|
2301
2304
|
referralSource;
|
|
2302
2305
|
cachedSponsoredCallback = null;
|
|
2303
|
-
|
|
2306
|
+
cachedPermit2Callbacks = /* @__PURE__ */ new Map();
|
|
2304
2307
|
initializingAgentsPromise = null;
|
|
2305
2308
|
constructor(config) {
|
|
2306
2309
|
this.apiKey = config.apiKey;
|
|
@@ -2328,7 +2331,7 @@ var OwneySDK = class {
|
|
|
2328
2331
|
}
|
|
2329
2332
|
this.state = { provider, walletAddress, chainId: null };
|
|
2330
2333
|
this.cachedSponsoredCallback = null;
|
|
2331
|
-
this.
|
|
2334
|
+
this.cachedPermit2Callbacks.clear();
|
|
2332
2335
|
}
|
|
2333
2336
|
/**
|
|
2334
2337
|
* Disconnect from all agents and clear connection state.
|
|
@@ -2342,7 +2345,7 @@ var OwneySDK = class {
|
|
|
2342
2345
|
this.disabledAgents.clear();
|
|
2343
2346
|
this.state = null;
|
|
2344
2347
|
this.cachedSponsoredCallback = null;
|
|
2345
|
-
this.
|
|
2348
|
+
this.cachedPermit2Callbacks.clear();
|
|
2346
2349
|
}
|
|
2347
2350
|
isAgentDisabled(agentId) {
|
|
2348
2351
|
return this.disabledAgents.has(agentId);
|
|
@@ -2419,25 +2422,23 @@ var OwneySDK = class {
|
|
|
2419
2422
|
return callback;
|
|
2420
2423
|
}
|
|
2421
2424
|
/**
|
|
2422
|
-
* Lazily builds (and caches) the
|
|
2423
|
-
*
|
|
2424
|
-
*
|
|
2425
|
-
*
|
|
2425
|
+
* Lazily builds (and caches) the Permit2 sponsored callback for one asset.
|
|
2426
|
+
* Used for WETH always, and for USDC when the connected owner is a smart
|
|
2427
|
+
* account — EIP-3009 verifies with ecrecover inside USDC and cannot accept a
|
|
2428
|
+
* contract signature, while Permit2 supports ERC-1271.
|
|
2426
2429
|
*/
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
+
getDefaultPermit2Callback(asset, onApproved) {
|
|
2431
|
+
const cached = this.cachedPermit2Callbacks.get(asset);
|
|
2432
|
+
if (!onApproved && cached) return cached;
|
|
2430
2433
|
const provider = this.requireConnectedProvider();
|
|
2431
2434
|
const owner = this.state.walletAddress;
|
|
2432
|
-
const callback =
|
|
2435
|
+
const callback = makeSponsoredPermit2Callback({
|
|
2433
2436
|
apiKey: this.apiKey,
|
|
2434
2437
|
baseUrl: this.routingApiBaseUrl,
|
|
2435
2438
|
ownerAddress: owner,
|
|
2439
|
+
assetLabel: asset,
|
|
2436
2440
|
onApproved,
|
|
2437
|
-
tokenAddressByChain: SPONSORED_WETH_BY_CHAIN,
|
|
2438
|
-
// Casts work around viem's chain-narrowed Client vs the generic
|
|
2439
|
-
// PublicClient/WalletClient param types — structurally identical at
|
|
2440
|
-
// runtime, but the two share a name TS treats as unrelated.
|
|
2441
|
+
tokenAddressByChain: asset === "USDC" ? SPONSORED_USDC_BY_CHAIN : SPONSORED_WETH_BY_CHAIN,
|
|
2441
2442
|
getPublicClient: (cid) => createPublicClient2({
|
|
2442
2443
|
chain: VIEM_CHAIN2[cid],
|
|
2443
2444
|
transport: custom(provider)
|
|
@@ -2448,9 +2449,34 @@ var OwneySDK = class {
|
|
|
2448
2449
|
transport: custom(provider)
|
|
2449
2450
|
})
|
|
2450
2451
|
});
|
|
2451
|
-
if (!onApproved) this.
|
|
2452
|
+
if (!onApproved) this.cachedPermit2Callbacks.set(asset, callback);
|
|
2452
2453
|
return callback;
|
|
2453
2454
|
}
|
|
2455
|
+
/**
|
|
2456
|
+
* True when the connected owner has bytecode — a deployed smart wallet, or an
|
|
2457
|
+
* EOA carrying an EIP-7702 delegation (the Base app's "Upgrade your wallet").
|
|
2458
|
+
* Such wallets sign via ERC-1271, which EIP-3009 cannot verify.
|
|
2459
|
+
*
|
|
2460
|
+
* Fails OPEN: an unreadable code check returns false so a working EOA deposit
|
|
2461
|
+
* is never blocked by a flaky provider.
|
|
2462
|
+
*/
|
|
2463
|
+
async ownerHasCode() {
|
|
2464
|
+
try {
|
|
2465
|
+
const provider = this.requireConnectedProvider();
|
|
2466
|
+
const code = await provider.request({
|
|
2467
|
+
method: "eth_getCode",
|
|
2468
|
+
params: [this.state.walletAddress, "latest"]
|
|
2469
|
+
});
|
|
2470
|
+
return Boolean(code) && code !== "0x";
|
|
2471
|
+
} catch (error) {
|
|
2472
|
+
debugLog(
|
|
2473
|
+
"deposit",
|
|
2474
|
+
"owner code check failed; assuming EOA",
|
|
2475
|
+
error instanceof Error ? error.message : String(error)
|
|
2476
|
+
);
|
|
2477
|
+
return false;
|
|
2478
|
+
}
|
|
2479
|
+
}
|
|
2454
2480
|
getAgent(agentId) {
|
|
2455
2481
|
const agent = this.agents.get(agentId);
|
|
2456
2482
|
if (!agent) {
|
|
@@ -2646,7 +2672,11 @@ var OwneySDK = class {
|
|
|
2646
2672
|
}
|
|
2647
2673
|
const state = this.requireState();
|
|
2648
2674
|
const chainId = this.requireChainId();
|
|
2649
|
-
const
|
|
2675
|
+
const ownerIsSmartAccount = depositCallback === void 0 && asset !== "WETH" ? await this.ownerHasCode() : false;
|
|
2676
|
+
const effectiveCallback = depositCallback ?? (asset === "WETH" || ownerIsSmartAccount ? this.getDefaultPermit2Callback(
|
|
2677
|
+
asset === "WETH" ? "WETH" : "USDC",
|
|
2678
|
+
onApproved
|
|
2679
|
+
) : this.getDefaultSponsoredCallback(onApproved));
|
|
2650
2680
|
if (agentId) {
|
|
2651
2681
|
if (this.isAgentDisabled(agentId)) {
|
|
2652
2682
|
throw new OwneyError(
|
|
@@ -2750,12 +2780,12 @@ var OwneySDK = class {
|
|
|
2750
2780
|
try {
|
|
2751
2781
|
return await attempt(effectiveCallback);
|
|
2752
2782
|
} catch (error) {
|
|
2753
|
-
if (!approvalAttempted && appCallback === void 0 && asset === "WETH" && error instanceof OwneyError && error.code === "PERMIT2_APPROVAL_REQUIRED") {
|
|
2783
|
+
if (!approvalAttempted && appCallback === void 0 && (asset === "WETH" || asset === "USDC") && error instanceof OwneyError && error.code === "PERMIT2_APPROVAL_REQUIRED") {
|
|
2754
2784
|
approvalAttempted = true;
|
|
2755
2785
|
console.warn(
|
|
2756
|
-
|
|
2786
|
+
`[owney-sdk] First ${asset} gasless deposit: sending one-time Permit2 approval...`
|
|
2757
2787
|
);
|
|
2758
|
-
await this.approvePermit2();
|
|
2788
|
+
await this.approvePermit2(asset);
|
|
2759
2789
|
continue;
|
|
2760
2790
|
}
|
|
2761
2791
|
if (!shouldFallbackToUserPaid(error, asset, appCallback)) throw error;
|
|
@@ -3269,23 +3299,32 @@ var OwneySDK = class {
|
|
|
3269
3299
|
return agent.ensureAutoSelectProtocols(state, chainId, asset);
|
|
3270
3300
|
}
|
|
3271
3301
|
/**
|
|
3272
|
-
* One-time, user-paid approval of Permit2 on the sponsored
|
|
3273
|
-
* the active chain. Required once per wallet per chain before
|
|
3274
|
-
*
|
|
3275
|
-
*
|
|
3276
|
-
*
|
|
3302
|
+
* One-time, user-paid approval of Permit2 on the given sponsored token for
|
|
3303
|
+
* the active chain. Required once per wallet per chain per token before a
|
|
3304
|
+
* gasless deposit of that asset over Permit2; afterwards deposit() is
|
|
3305
|
+
* signature-only for it. This call itself is a real transaction the user
|
|
3306
|
+
* pays gas for. Resolves only after the approval transaction is mined (1
|
|
3307
|
+
* confirmation), so a subsequent deposit() will see the new allowance;
|
|
3308
|
+
* throws if the transaction reverted.
|
|
3277
3309
|
* @returns the approval transaction hash.
|
|
3278
3310
|
*/
|
|
3279
3311
|
async approvePermit2(asset = "WETH") {
|
|
3280
|
-
void asset;
|
|
3281
3312
|
const state = this.requireState();
|
|
3282
3313
|
const chainId = this.requireChainId();
|
|
3283
|
-
this.
|
|
3284
|
-
|
|
3314
|
+
let guard = this.agents.get("zyfai");
|
|
3315
|
+
if (!guard) {
|
|
3316
|
+
try {
|
|
3317
|
+
guard = this.getEligibleAgents(chainId, asset)[0];
|
|
3318
|
+
} catch {
|
|
3319
|
+
guard = void 0;
|
|
3320
|
+
}
|
|
3321
|
+
}
|
|
3322
|
+
if (guard) this.validateAssetSupport(guard, chainId, asset);
|
|
3323
|
+
const token = asset === "USDC" ? SPONSORED_USDC_BY_CHAIN[chainId] : SPONSORED_WETH_BY_CHAIN[chainId];
|
|
3285
3324
|
if (!token) {
|
|
3286
3325
|
throw new OwneyError(
|
|
3287
3326
|
"CHAIN_UNSUPPORTED",
|
|
3288
|
-
`No sponsored
|
|
3327
|
+
`No sponsored ${asset} on chain ${chainId}`
|
|
3289
3328
|
);
|
|
3290
3329
|
}
|
|
3291
3330
|
const provider = this.requireConnectedProvider();
|