@owney/sdk 0.6.4-beta.0 → 0.6.5-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 +428 -22
- package/dist/index.d.cts +119 -61
- package/dist/index.d.ts +119 -61
- package/dist/index.js +421 -15
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -40,7 +40,7 @@ var P_SUPPORTED_CHAINS = {
|
|
|
40
40
|
chainIds: [8453, 42161],
|
|
41
41
|
chains: ["BASE", "ARBITRUM"]
|
|
42
42
|
};
|
|
43
|
-
var SUPPORTED_TOKENS = ["USDC", "USDT"];
|
|
43
|
+
var SUPPORTED_TOKENS = ["USDC", "USDT", "WETH"];
|
|
44
44
|
var SUPPORTED_CHAIN_IDS = P_SUPPORTED_CHAINS.chainIds;
|
|
45
45
|
var SUPPORTED_CHAINS = P_SUPPORTED_CHAINS.chains;
|
|
46
46
|
var SupportedAssets = [
|
|
@@ -61,6 +61,18 @@ var SupportedAssets = [
|
|
|
61
61
|
symbol: "USDT",
|
|
62
62
|
chainId: 42161,
|
|
63
63
|
decimals: 6
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
address: `0x4200000000000000000000000000000000000006`,
|
|
67
|
+
symbol: "WETH",
|
|
68
|
+
chainId: 8453,
|
|
69
|
+
decimals: 18
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
address: `0x82aF49447D8a07e3bd95BD0d56f35241523fBab1`,
|
|
73
|
+
symbol: "WETH",
|
|
74
|
+
chainId: 42161,
|
|
75
|
+
decimals: 18
|
|
64
76
|
}
|
|
65
77
|
];
|
|
66
78
|
|
|
@@ -545,11 +557,26 @@ var clearSession = (address, chainId) => {
|
|
|
545
557
|
}
|
|
546
558
|
};
|
|
547
559
|
|
|
560
|
+
// src/agents/zyfai/autoSelect.ts
|
|
561
|
+
function buildAutoSelectUpdate(current, asset) {
|
|
562
|
+
if (current.autoSelectProtocols === true)
|
|
563
|
+
return null;
|
|
564
|
+
return {
|
|
565
|
+
asset,
|
|
566
|
+
autoSelectProtocols: true,
|
|
567
|
+
...current.chains ? { chains: current.chains } : {}
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
|
|
548
571
|
// src/agents/zyfai/zyfai.agent.ts
|
|
549
572
|
var DEFAULT_ZYFAI_RPC_URLS = {
|
|
550
573
|
8453: "https://base-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V",
|
|
551
574
|
42161: "https://arb-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V"
|
|
552
575
|
};
|
|
576
|
+
var WETH_ADDRESS_BY_CHAIN = {
|
|
577
|
+
8453: "0x4200000000000000000000000000000000000006",
|
|
578
|
+
42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"
|
|
579
|
+
};
|
|
553
580
|
var VIEM_CHAIN = { 8453: import_chains.base, 42161: import_chains.arbitrum };
|
|
554
581
|
var ZyfaiAgent = class {
|
|
555
582
|
id = "zyfai";
|
|
@@ -558,12 +585,18 @@ var ZyfaiAgent = class {
|
|
|
558
585
|
{
|
|
559
586
|
chainId: 8453,
|
|
560
587
|
chain: "BASE",
|
|
561
|
-
assets: [
|
|
588
|
+
assets: [
|
|
589
|
+
{ symbol: "USDC", minDepositAmount: "1500000" },
|
|
590
|
+
{ symbol: "WETH", minDepositAmount: "500000000000000" }
|
|
591
|
+
]
|
|
562
592
|
},
|
|
563
593
|
{
|
|
564
594
|
chainId: 42161,
|
|
565
595
|
chain: "ARBITRUM",
|
|
566
|
-
assets: [
|
|
596
|
+
assets: [
|
|
597
|
+
{ symbol: "USDC", minDepositAmount: "1500000" },
|
|
598
|
+
{ symbol: "WETH", minDepositAmount: "500000000000000" }
|
|
599
|
+
]
|
|
567
600
|
}
|
|
568
601
|
];
|
|
569
602
|
sdk;
|
|
@@ -758,6 +791,22 @@ var ZyfaiAgent = class {
|
|
|
758
791
|
this.smartWalletCache.set(`${address}_${validChainId}`, wallet.address);
|
|
759
792
|
if (!wallet.isDeployed) {
|
|
760
793
|
await this.sdk.deploySafe(address, validChainId, "aggressive", true);
|
|
794
|
+
try {
|
|
795
|
+
if (validChainId === 42161) {
|
|
796
|
+
await this.sdk.updateUserProfile({
|
|
797
|
+
asset: "WETH",
|
|
798
|
+
chains: [validChainId],
|
|
799
|
+
protocols: ["c24a33fa-4a87-4376-b756-93bd3957d3ea"],
|
|
800
|
+
// AAVE protocol ID
|
|
801
|
+
autoSelectProtocols: false
|
|
802
|
+
});
|
|
803
|
+
}
|
|
804
|
+
} catch (err) {
|
|
805
|
+
console.warn(
|
|
806
|
+
"Failed to configure AAVE protocol after Safe deployment:",
|
|
807
|
+
err instanceof Error ? err.message : String(err)
|
|
808
|
+
);
|
|
809
|
+
}
|
|
761
810
|
}
|
|
762
811
|
const user = await this.sdk.getUserDetails();
|
|
763
812
|
if (!user.hasActiveSessionKey) {
|
|
@@ -799,7 +848,7 @@ var ZyfaiAgent = class {
|
|
|
799
848
|
throw error;
|
|
800
849
|
}
|
|
801
850
|
}
|
|
802
|
-
async deposit(state, chainId, amount, depositCallback) {
|
|
851
|
+
async deposit(state, chainId, amount, asset, depositCallback) {
|
|
803
852
|
try {
|
|
804
853
|
await this.connectFull(state, chainId);
|
|
805
854
|
const validChainId = isValidChainId(chainId);
|
|
@@ -813,13 +862,15 @@ var ZyfaiAgent = class {
|
|
|
813
862
|
validChainId,
|
|
814
863
|
amount
|
|
815
864
|
);
|
|
816
|
-
|
|
865
|
+
const tokenAddress = asset === "WETH" ? WETH_ADDRESS_BY_CHAIN[validChainId] : void 0;
|
|
866
|
+
await (tokenAddress ? this.sdk.logDeposit(validChainId, txHash, amount, tokenAddress) : this.sdk.logDeposit(validChainId, txHash, amount));
|
|
817
867
|
return { txHash, smartWallet: wallet.address, amount };
|
|
818
868
|
}
|
|
819
869
|
const raw = await this.sdk.depositFunds(
|
|
820
870
|
this.getAddress(),
|
|
821
871
|
validChainId,
|
|
822
|
-
amount
|
|
872
|
+
amount,
|
|
873
|
+
asset
|
|
823
874
|
);
|
|
824
875
|
return mapDeposit(raw);
|
|
825
876
|
} catch (error) {
|
|
@@ -915,6 +966,21 @@ var ZyfaiAgent = class {
|
|
|
915
966
|
}
|
|
916
967
|
return mapUserProfile(raw, this.connectedAddress);
|
|
917
968
|
}
|
|
969
|
+
async ensureAutoSelectProtocols(state, chainId, asset) {
|
|
970
|
+
await this.connectAuth(state, chainId);
|
|
971
|
+
const current = await this.sdk.getUserDetails(asset);
|
|
972
|
+
const update = buildAutoSelectUpdate(
|
|
973
|
+
{
|
|
974
|
+
autoSelectProtocols: current.autoSelectProtocols,
|
|
975
|
+
chains: current.chains
|
|
976
|
+
},
|
|
977
|
+
asset
|
|
978
|
+
);
|
|
979
|
+
if (!update)
|
|
980
|
+
return false;
|
|
981
|
+
await this.sdk.updateUserProfile(update);
|
|
982
|
+
return true;
|
|
983
|
+
}
|
|
918
984
|
// --- IAgent: Discovery (no wallet required) ---
|
|
919
985
|
async getAgentApy(days, options) {
|
|
920
986
|
const raw = await this.sdk.getAPYPerStrategy(
|
|
@@ -1118,7 +1184,7 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
|
|
|
1118
1184
|
}
|
|
1119
1185
|
|
|
1120
1186
|
// src/client.ts
|
|
1121
|
-
var
|
|
1187
|
+
var import_viem5 = require("viem");
|
|
1122
1188
|
var import_chains2 = require("viem/chains");
|
|
1123
1189
|
|
|
1124
1190
|
// src/lib/transfer-auth.ts
|
|
@@ -1190,6 +1256,70 @@ async function postSponsorTransferAuth(input) {
|
|
|
1190
1256
|
}
|
|
1191
1257
|
return parsed.data;
|
|
1192
1258
|
}
|
|
1259
|
+
async function postSponsorPermit2Transfer(input) {
|
|
1260
|
+
const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
1261
|
+
let res;
|
|
1262
|
+
try {
|
|
1263
|
+
res = await fetch(`${base3}/api/v1/sponsor/permit2-transfer`, {
|
|
1264
|
+
method: "POST",
|
|
1265
|
+
headers: { "content-type": "application/json", "x-owney-api-key": input.apiKey },
|
|
1266
|
+
body: JSON.stringify(input.body)
|
|
1267
|
+
});
|
|
1268
|
+
} catch (networkError) {
|
|
1269
|
+
throw new OwneyError(
|
|
1270
|
+
"SPONSOR_REQUEST_FAILED",
|
|
1271
|
+
`Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
|
|
1272
|
+
{ cause: String(networkError), safeToFallback: false }
|
|
1273
|
+
);
|
|
1274
|
+
}
|
|
1275
|
+
const text = await res.text();
|
|
1276
|
+
let parsed = null;
|
|
1277
|
+
try {
|
|
1278
|
+
parsed = JSON.parse(text);
|
|
1279
|
+
} catch {
|
|
1280
|
+
}
|
|
1281
|
+
if (!res.ok || !parsed?.success || !parsed.data) {
|
|
1282
|
+
throw new OwneyError(
|
|
1283
|
+
"SPONSOR_REQUEST_FAILED",
|
|
1284
|
+
`Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
|
|
1285
|
+
{
|
|
1286
|
+
statusCode: res.status,
|
|
1287
|
+
responseBody: text.slice(0, 500),
|
|
1288
|
+
safeToFallback: res.status >= 400 && res.status < 500
|
|
1289
|
+
}
|
|
1290
|
+
);
|
|
1291
|
+
}
|
|
1292
|
+
return parsed.data;
|
|
1293
|
+
}
|
|
1294
|
+
async function getSponsorRelayerAddress(input) {
|
|
1295
|
+
const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
1296
|
+
let res;
|
|
1297
|
+
try {
|
|
1298
|
+
res = await fetch(`${base3}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`, {
|
|
1299
|
+
headers: { "x-owney-api-key": input.apiKey }
|
|
1300
|
+
});
|
|
1301
|
+
} catch (networkError) {
|
|
1302
|
+
throw new OwneyError(
|
|
1303
|
+
"SPONSOR_REQUEST_FAILED",
|
|
1304
|
+
`Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
|
|
1305
|
+
{ cause: String(networkError), safeToFallback: true }
|
|
1306
|
+
);
|
|
1307
|
+
}
|
|
1308
|
+
const text = await res.text();
|
|
1309
|
+
let parsed = null;
|
|
1310
|
+
try {
|
|
1311
|
+
parsed = JSON.parse(text);
|
|
1312
|
+
} catch {
|
|
1313
|
+
}
|
|
1314
|
+
if (!res.ok || !parsed?.success || !parsed.data?.relayer) {
|
|
1315
|
+
throw new OwneyError(
|
|
1316
|
+
"SPONSOR_REQUEST_FAILED",
|
|
1317
|
+
`Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
|
|
1318
|
+
{ statusCode: res.status, responseBody: text.slice(0, 500), safeToFallback: true }
|
|
1319
|
+
);
|
|
1320
|
+
}
|
|
1321
|
+
return parsed.data.relayer;
|
|
1322
|
+
}
|
|
1193
1323
|
|
|
1194
1324
|
// src/lib/sponsored-deposit.ts
|
|
1195
1325
|
var AUTH_WINDOW_SECONDS = 15 * 60;
|
|
@@ -1241,6 +1371,114 @@ function makeSponsoredDepositCallback(deps) {
|
|
|
1241
1371
|
};
|
|
1242
1372
|
}
|
|
1243
1373
|
|
|
1374
|
+
// src/lib/permit2.ts
|
|
1375
|
+
var import_viem4 = require("viem");
|
|
1376
|
+
var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
1377
|
+
var MAX_UINT256 = 2n ** 256n - 1n;
|
|
1378
|
+
var ERC20_ALLOWANCE_ABI = [
|
|
1379
|
+
{
|
|
1380
|
+
type: "function",
|
|
1381
|
+
name: "allowance",
|
|
1382
|
+
stateMutability: "view",
|
|
1383
|
+
inputs: [{ name: "owner", type: "address" }, { name: "spender", type: "address" }],
|
|
1384
|
+
outputs: [{ name: "", type: "uint256" }]
|
|
1385
|
+
},
|
|
1386
|
+
{
|
|
1387
|
+
type: "function",
|
|
1388
|
+
name: "approve",
|
|
1389
|
+
stateMutability: "nonpayable",
|
|
1390
|
+
inputs: [{ name: "spender", type: "address" }, { name: "amount", type: "uint256" }],
|
|
1391
|
+
outputs: [{ name: "", type: "bool" }]
|
|
1392
|
+
}
|
|
1393
|
+
];
|
|
1394
|
+
function buildPermitTransferFromTypedData(input) {
|
|
1395
|
+
return {
|
|
1396
|
+
domain: { name: "Permit2", chainId: input.chainId, verifyingContract: PERMIT2_ADDRESS },
|
|
1397
|
+
types: {
|
|
1398
|
+
PermitTransferFrom: [
|
|
1399
|
+
{ name: "permitted", type: "TokenPermissions" },
|
|
1400
|
+
{ name: "spender", type: "address" },
|
|
1401
|
+
{ name: "nonce", type: "uint256" },
|
|
1402
|
+
{ name: "deadline", type: "uint256" }
|
|
1403
|
+
],
|
|
1404
|
+
TokenPermissions: [
|
|
1405
|
+
{ name: "token", type: "address" },
|
|
1406
|
+
{ name: "amount", type: "uint256" }
|
|
1407
|
+
]
|
|
1408
|
+
},
|
|
1409
|
+
primaryType: "PermitTransferFrom",
|
|
1410
|
+
message: input.message
|
|
1411
|
+
};
|
|
1412
|
+
}
|
|
1413
|
+
function randomPermit2Nonce() {
|
|
1414
|
+
const bytes = new Uint8Array(32);
|
|
1415
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
1416
|
+
return BigInt((0, import_viem4.bytesToHex)(bytes));
|
|
1417
|
+
}
|
|
1418
|
+
async function readPermit2Allowance(publicClient, token, owner) {
|
|
1419
|
+
return publicClient.readContract({
|
|
1420
|
+
address: token,
|
|
1421
|
+
abi: ERC20_ALLOWANCE_ABI,
|
|
1422
|
+
functionName: "allowance",
|
|
1423
|
+
args: [owner, PERMIT2_ADDRESS]
|
|
1424
|
+
});
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
// src/lib/sponsored-weth-deposit.ts
|
|
1428
|
+
var PERMIT_WINDOW_SECONDS = 15 * 60;
|
|
1429
|
+
function makeSponsoredWethCallback(deps) {
|
|
1430
|
+
const get = deps.httpGet ?? getSponsorRelayerAddress;
|
|
1431
|
+
const post = deps.httpPost ?? postSponsorPermit2Transfer;
|
|
1432
|
+
return async (smartWallet, chainId, amount) => {
|
|
1433
|
+
const cid = chainId;
|
|
1434
|
+
const token = deps.tokenAddressByChain[cid];
|
|
1435
|
+
if (!token) {
|
|
1436
|
+
throw new OwneyError("CHAIN_UNSUPPORTED", `No sponsored WETH configured for chain ${chainId}`);
|
|
1437
|
+
}
|
|
1438
|
+
const amountWei = BigInt(amount);
|
|
1439
|
+
const pub = deps.getPublicClient(cid);
|
|
1440
|
+
const allowance = await readPermit2Allowance(pub, token, deps.ownerAddress);
|
|
1441
|
+
if (allowance < amountWei) {
|
|
1442
|
+
throw new OwneyError(
|
|
1443
|
+
"PERMIT2_APPROVAL_REQUIRED",
|
|
1444
|
+
"WETH gasless deposits need a one-time Permit2 approval; call approvePermit2() first",
|
|
1445
|
+
{ token, chainId: cid, allowance: allowance.toString(), amount }
|
|
1446
|
+
);
|
|
1447
|
+
}
|
|
1448
|
+
const relayer = await get({ baseUrl: deps.baseUrl, apiKey: deps.apiKey, chainId: cid });
|
|
1449
|
+
const nonce = randomPermit2Nonce();
|
|
1450
|
+
const deadline = BigInt(Math.floor(Date.now() / 1e3) + PERMIT_WINDOW_SECONDS);
|
|
1451
|
+
const typedData = buildPermitTransferFromTypedData({
|
|
1452
|
+
chainId: cid,
|
|
1453
|
+
message: {
|
|
1454
|
+
permitted: { token, amount: amountWei },
|
|
1455
|
+
spender: relayer,
|
|
1456
|
+
nonce,
|
|
1457
|
+
deadline
|
|
1458
|
+
}
|
|
1459
|
+
});
|
|
1460
|
+
const wallet = deps.getWalletClient(cid);
|
|
1461
|
+
const signature = await wallet.signTypedData(
|
|
1462
|
+
{ account: deps.ownerAddress, ...typedData }
|
|
1463
|
+
);
|
|
1464
|
+
const result = await post({
|
|
1465
|
+
baseUrl: deps.baseUrl,
|
|
1466
|
+
apiKey: deps.apiKey,
|
|
1467
|
+
body: {
|
|
1468
|
+
chainId: cid,
|
|
1469
|
+
token,
|
|
1470
|
+
from: deps.ownerAddress,
|
|
1471
|
+
to: smartWallet,
|
|
1472
|
+
amount,
|
|
1473
|
+
nonce: nonce.toString(),
|
|
1474
|
+
deadline: deadline.toString(),
|
|
1475
|
+
signature
|
|
1476
|
+
}
|
|
1477
|
+
});
|
|
1478
|
+
return result.txHash;
|
|
1479
|
+
};
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1244
1482
|
// src/client.ts
|
|
1245
1483
|
function encodeMultiAgentCursor(map) {
|
|
1246
1484
|
return Buffer.from(JSON.stringify(map), "utf8").toString("base64");
|
|
@@ -1270,6 +1508,13 @@ var VIEM_CHAIN2 = {
|
|
|
1270
1508
|
8453: import_chains2.base,
|
|
1271
1509
|
42161: import_chains2.arbitrum
|
|
1272
1510
|
};
|
|
1511
|
+
var SPONSORED_WETH_BY_CHAIN = {
|
|
1512
|
+
8453: "0x4200000000000000000000000000000000000006",
|
|
1513
|
+
42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"
|
|
1514
|
+
};
|
|
1515
|
+
function shouldFallbackToUserPaid(error, asset, appCallback) {
|
|
1516
|
+
return asset === "WETH" && appCallback === void 0 && error instanceof OwneyError && error.code === "SPONSOR_REQUEST_FAILED" && error.details?.safeToFallback === true;
|
|
1517
|
+
}
|
|
1273
1518
|
var OwneySDK = class {
|
|
1274
1519
|
agents = /* @__PURE__ */ new Map();
|
|
1275
1520
|
activeAgents = /* @__PURE__ */ new Set();
|
|
@@ -1283,6 +1528,7 @@ var OwneySDK = class {
|
|
|
1283
1528
|
apiKey;
|
|
1284
1529
|
zyfaiRpcUrls;
|
|
1285
1530
|
cachedSponsoredCallback = null;
|
|
1531
|
+
cachedWethSponsoredCallback = null;
|
|
1286
1532
|
initializingAgentsPromise = null;
|
|
1287
1533
|
constructor(config) {
|
|
1288
1534
|
this.apiKey = config.apiKey;
|
|
@@ -1307,6 +1553,7 @@ var OwneySDK = class {
|
|
|
1307
1553
|
}
|
|
1308
1554
|
this.state = { provider, walletAddress, chainId: null };
|
|
1309
1555
|
this.cachedSponsoredCallback = null;
|
|
1556
|
+
this.cachedWethSponsoredCallback = null;
|
|
1310
1557
|
}
|
|
1311
1558
|
/**
|
|
1312
1559
|
* Disconnect from all agents and clear connection state.
|
|
@@ -1320,6 +1567,7 @@ var OwneySDK = class {
|
|
|
1320
1567
|
this.disabledAgents.clear();
|
|
1321
1568
|
this.state = null;
|
|
1322
1569
|
this.cachedSponsoredCallback = null;
|
|
1570
|
+
this.cachedWethSponsoredCallback = null;
|
|
1323
1571
|
}
|
|
1324
1572
|
isAgentDisabled(agentId) {
|
|
1325
1573
|
return this.disabledAgents.has(agentId);
|
|
@@ -1381,18 +1629,48 @@ var OwneySDK = class {
|
|
|
1381
1629
|
// Casts work around viem's chain-narrowed Client vs the generic
|
|
1382
1630
|
// PublicClient/WalletClient param types — structurally identical at
|
|
1383
1631
|
// runtime, but the two share a name TS treats as unrelated.
|
|
1384
|
-
getPublicClient: (cid) => (0,
|
|
1632
|
+
getPublicClient: (cid) => (0, import_viem5.createPublicClient)({
|
|
1385
1633
|
chain: VIEM_CHAIN2[cid],
|
|
1386
|
-
transport: (0,
|
|
1634
|
+
transport: (0, import_viem5.custom)(provider)
|
|
1387
1635
|
}),
|
|
1388
|
-
getWalletClient: (cid) => (0,
|
|
1636
|
+
getWalletClient: (cid) => (0, import_viem5.createWalletClient)({
|
|
1389
1637
|
account: owner,
|
|
1390
1638
|
chain: VIEM_CHAIN2[cid],
|
|
1391
|
-
transport: (0,
|
|
1639
|
+
transport: (0, import_viem5.custom)(provider)
|
|
1392
1640
|
})
|
|
1393
1641
|
});
|
|
1394
1642
|
return this.cachedSponsoredCallback;
|
|
1395
1643
|
}
|
|
1644
|
+
/**
|
|
1645
|
+
* Lazily builds (and caches) the default Permit2 sponsored WETH deposit
|
|
1646
|
+
* callback used when the caller omits `depositCallback` for a WETH
|
|
1647
|
+
* deposit. Mirrors `getDefaultSponsoredCallback()` but signs a Permit2
|
|
1648
|
+
* `PermitTransferFrom` instead of an EIP-3009 authorization.
|
|
1649
|
+
*/
|
|
1650
|
+
getDefaultWethSponsoredCallback() {
|
|
1651
|
+
if (this.cachedWethSponsoredCallback)
|
|
1652
|
+
return this.cachedWethSponsoredCallback;
|
|
1653
|
+
const provider = this.requireConnectedProvider();
|
|
1654
|
+
const owner = this.state.walletAddress;
|
|
1655
|
+
this.cachedWethSponsoredCallback = makeSponsoredWethCallback({
|
|
1656
|
+
apiKey: this.apiKey,
|
|
1657
|
+
ownerAddress: owner,
|
|
1658
|
+
tokenAddressByChain: SPONSORED_WETH_BY_CHAIN,
|
|
1659
|
+
// Casts work around viem's chain-narrowed Client vs the generic
|
|
1660
|
+
// PublicClient/WalletClient param types — structurally identical at
|
|
1661
|
+
// runtime, but the two share a name TS treats as unrelated.
|
|
1662
|
+
getPublicClient: (cid) => (0, import_viem5.createPublicClient)({
|
|
1663
|
+
chain: VIEM_CHAIN2[cid],
|
|
1664
|
+
transport: (0, import_viem5.custom)(provider)
|
|
1665
|
+
}),
|
|
1666
|
+
getWalletClient: (cid) => (0, import_viem5.createWalletClient)({
|
|
1667
|
+
account: owner,
|
|
1668
|
+
chain: VIEM_CHAIN2[cid],
|
|
1669
|
+
transport: (0, import_viem5.custom)(provider)
|
|
1670
|
+
})
|
|
1671
|
+
});
|
|
1672
|
+
return this.cachedWethSponsoredCallback;
|
|
1673
|
+
}
|
|
1396
1674
|
getAgent(agentId) {
|
|
1397
1675
|
const agent = this.agents.get(agentId);
|
|
1398
1676
|
if (!agent) {
|
|
@@ -1546,7 +1824,7 @@ var OwneySDK = class {
|
|
|
1546
1824
|
}
|
|
1547
1825
|
const state = this.requireState();
|
|
1548
1826
|
const chainId = this.requireChainId();
|
|
1549
|
-
const effectiveCallback = depositCallback ?? this.getDefaultSponsoredCallback();
|
|
1827
|
+
const effectiveCallback = depositCallback ?? (asset === "WETH" ? this.getDefaultWethSponsoredCallback() : this.getDefaultSponsoredCallback());
|
|
1550
1828
|
if (agentId) {
|
|
1551
1829
|
if (this.isAgentDisabled(agentId)) {
|
|
1552
1830
|
throw new OwneyError(
|
|
@@ -1558,10 +1836,14 @@ var OwneySDK = class {
|
|
|
1558
1836
|
const agent = this.getAgent(agentId);
|
|
1559
1837
|
this.validateAssetSupport(agent, chainId, asset);
|
|
1560
1838
|
await this.validateMinDepositAmount(agent, state, chainId, asset, amount);
|
|
1561
|
-
return
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1839
|
+
return this.depositWithFallback(
|
|
1840
|
+
agent,
|
|
1841
|
+
state,
|
|
1842
|
+
chainId,
|
|
1843
|
+
amount,
|
|
1844
|
+
asset,
|
|
1845
|
+
effectiveCallback,
|
|
1846
|
+
depositCallback
|
|
1565
1847
|
);
|
|
1566
1848
|
}
|
|
1567
1849
|
const totalAmount = BigInt(amount);
|
|
@@ -1592,14 +1874,78 @@ var OwneySDK = class {
|
|
|
1592
1874
|
}
|
|
1593
1875
|
const agentResults = {};
|
|
1594
1876
|
for (const { agent, amount: agentAmount } of agentAmounts) {
|
|
1595
|
-
agentResults[agent.id] = await
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1877
|
+
agentResults[agent.id] = await this.depositWithFallback(
|
|
1878
|
+
agent,
|
|
1879
|
+
state,
|
|
1880
|
+
chainId,
|
|
1881
|
+
agentAmount,
|
|
1882
|
+
asset,
|
|
1883
|
+
effectiveCallback,
|
|
1884
|
+
depositCallback
|
|
1599
1885
|
);
|
|
1600
1886
|
}
|
|
1601
1887
|
return { agentResults };
|
|
1602
1888
|
}
|
|
1889
|
+
/**
|
|
1890
|
+
* Invokes `agent.deposit` with the resolved sponsored callback, composing
|
|
1891
|
+
* two independent auto-recovery mechanisms:
|
|
1892
|
+
*
|
|
1893
|
+
* 1. Missing Permit2 allowance: when the app did not supply its own
|
|
1894
|
+
* callback and the attempt fails with `PERMIT2_APPROVAL_REQUIRED` on a
|
|
1895
|
+
* WETH deposit, this is the wallet's first gasless WETH deposit. We send
|
|
1896
|
+
* the one-time (user-paid) Permit2 approval via `approvePermit2()` and
|
|
1897
|
+
* retry the SAME sponsored attempt once. Bounded to one approval attempt
|
|
1898
|
+
* per call so a wallet/agent that keeps reporting the allowance as
|
|
1899
|
+
* missing can't loop forever. If `approvePermit2()` itself throws (e.g.
|
|
1900
|
+
* the user rejects the wallet prompt), that error propagates as-is —
|
|
1901
|
+
* the user said no to a transaction, so we must not turn around and ask
|
|
1902
|
+
* them to pay for a different one via the fallback below.
|
|
1903
|
+
* 2. `shouldFallbackToUserPaid`: the SDK's own WETH sponsor path failed at
|
|
1904
|
+
* the infrastructure layer in a provably safe-to-retry way, so we warn
|
|
1905
|
+
* and retry once with `undefined`, falling through to a user-paid
|
|
1906
|
+
* native deposit. This still applies after a successful Permit2
|
|
1907
|
+
* approval retry (the retried sponsored attempt can itself hit a safe
|
|
1908
|
+
* sponsor failure).
|
|
1909
|
+
*
|
|
1910
|
+
* Any other error — an app-supplied callback's own failure in particular —
|
|
1911
|
+
* propagates unchanged. Scoped per agent invocation so one agent's failure
|
|
1912
|
+
* doesn't force a retry of sibling agents in a multi-agent split.
|
|
1913
|
+
*/
|
|
1914
|
+
async depositWithFallback(agent, state, chainId, amount, asset, effectiveCallback, appCallback) {
|
|
1915
|
+
const attempt = (callback) => withFailureReporting(
|
|
1916
|
+
this.apiKey,
|
|
1917
|
+
agent.id,
|
|
1918
|
+
() => agent.deposit(
|
|
1919
|
+
state,
|
|
1920
|
+
chainId,
|
|
1921
|
+
amount,
|
|
1922
|
+
asset,
|
|
1923
|
+
callback
|
|
1924
|
+
)
|
|
1925
|
+
);
|
|
1926
|
+
let approvalAttempted = false;
|
|
1927
|
+
for (; ; ) {
|
|
1928
|
+
try {
|
|
1929
|
+
return await attempt(effectiveCallback);
|
|
1930
|
+
} catch (error) {
|
|
1931
|
+
if (!approvalAttempted && appCallback === void 0 && asset === "WETH" && error instanceof OwneyError && error.code === "PERMIT2_APPROVAL_REQUIRED") {
|
|
1932
|
+
approvalAttempted = true;
|
|
1933
|
+
console.warn(
|
|
1934
|
+
"[owney-sdk] First WETH deposit: sending one-time Permit2 approval..."
|
|
1935
|
+
);
|
|
1936
|
+
await this.approvePermit2();
|
|
1937
|
+
continue;
|
|
1938
|
+
}
|
|
1939
|
+
if (!shouldFallbackToUserPaid(error, asset, appCallback))
|
|
1940
|
+
throw error;
|
|
1941
|
+
console.warn(
|
|
1942
|
+
"[owney-sdk] WETH sponsorship unavailable, falling back to user-paid deposit:",
|
|
1943
|
+
error
|
|
1944
|
+
);
|
|
1945
|
+
return attempt(void 0);
|
|
1946
|
+
}
|
|
1947
|
+
}
|
|
1948
|
+
}
|
|
1603
1949
|
getMinDepositAmount(agent, chainId, asset) {
|
|
1604
1950
|
const chainAssets = agent.supportedAssets.find(
|
|
1605
1951
|
(sa) => sa.chainId === chainId
|
|
@@ -2087,6 +2433,66 @@ var OwneySDK = class {
|
|
|
2087
2433
|
agentUserProfile: results
|
|
2088
2434
|
};
|
|
2089
2435
|
}
|
|
2436
|
+
/**
|
|
2437
|
+
* Ensure the given asset uses backend protocol auto-selection for the active
|
|
2438
|
+
* chain's account. No-op (returns false) for agents that don't support it.
|
|
2439
|
+
* @param asset - "USDC" or "WETH".
|
|
2440
|
+
* @param agentId - Agent to target. Defaults to "zyfai".
|
|
2441
|
+
* @returns whether a profile write occurred.
|
|
2442
|
+
*/
|
|
2443
|
+
async ensureAutoSelectProtocols(asset, agentId = "zyfai") {
|
|
2444
|
+
const state = this.requireState();
|
|
2445
|
+
const chainId = this.requireChainId();
|
|
2446
|
+
const agent = this.getAgent(agentId);
|
|
2447
|
+
if (typeof agent.ensureAutoSelectProtocols !== "function")
|
|
2448
|
+
return false;
|
|
2449
|
+
return agent.ensureAutoSelectProtocols(state, chainId, asset);
|
|
2450
|
+
}
|
|
2451
|
+
/**
|
|
2452
|
+
* One-time, user-paid approval of Permit2 on the sponsored WETH token for
|
|
2453
|
+
* the active chain. Required once per wallet per chain before gasless WETH
|
|
2454
|
+
* deposits; afterwards deposit() is signature-only. Resolves only after the
|
|
2455
|
+
* approval transaction is mined (1 confirmation), so a subsequent deposit()
|
|
2456
|
+
* will see the new allowance; throws if the transaction reverted.
|
|
2457
|
+
* @returns the approval transaction hash.
|
|
2458
|
+
*/
|
|
2459
|
+
async approvePermit2(asset = "WETH") {
|
|
2460
|
+
const state = this.requireState();
|
|
2461
|
+
const chainId = this.requireChainId();
|
|
2462
|
+
const token = SPONSORED_WETH_BY_CHAIN[chainId];
|
|
2463
|
+
if (!token) {
|
|
2464
|
+
throw new OwneyError(
|
|
2465
|
+
"CHAIN_UNSUPPORTED",
|
|
2466
|
+
`No sponsored WETH on chain ${chainId}`
|
|
2467
|
+
);
|
|
2468
|
+
}
|
|
2469
|
+
const provider = this.requireConnectedProvider();
|
|
2470
|
+
const wallet = (0, import_viem5.createWalletClient)({
|
|
2471
|
+
account: state.walletAddress,
|
|
2472
|
+
chain: VIEM_CHAIN2[chainId],
|
|
2473
|
+
transport: (0, import_viem5.custom)(provider)
|
|
2474
|
+
});
|
|
2475
|
+
const hash = await wallet.writeContract({
|
|
2476
|
+
address: token,
|
|
2477
|
+
abi: ERC20_ALLOWANCE_ABI,
|
|
2478
|
+
functionName: "approve",
|
|
2479
|
+
args: [PERMIT2_ADDRESS, MAX_UINT256],
|
|
2480
|
+
account: state.walletAddress,
|
|
2481
|
+
chain: VIEM_CHAIN2[chainId]
|
|
2482
|
+
});
|
|
2483
|
+
const publicClient = (0, import_viem5.createPublicClient)({
|
|
2484
|
+
chain: VIEM_CHAIN2[chainId],
|
|
2485
|
+
transport: (0, import_viem5.custom)(provider)
|
|
2486
|
+
});
|
|
2487
|
+
const receipt = await publicClient.waitForTransactionReceipt({
|
|
2488
|
+
hash,
|
|
2489
|
+
confirmations: 1
|
|
2490
|
+
});
|
|
2491
|
+
if (receipt.status !== "success") {
|
|
2492
|
+
throw new Error(`Permit2 approval reverted (tx ${hash})`);
|
|
2493
|
+
}
|
|
2494
|
+
return hash;
|
|
2495
|
+
}
|
|
2090
2496
|
// --- Discovery (no wallet required) ---
|
|
2091
2497
|
/**
|
|
2092
2498
|
* Get the agent's average APY performance over a time period. Does not require a wallet connection.
|
|
@@ -2185,7 +2591,7 @@ var OwneySDK = class {
|
|
|
2185
2591
|
};
|
|
2186
2592
|
|
|
2187
2593
|
// src/agents/zyfai/zyfai.siwx.ts
|
|
2188
|
-
var
|
|
2594
|
+
var import_viem6 = require("viem");
|
|
2189
2595
|
var import_siwe = require("siwe");
|
|
2190
2596
|
var import_sdk2 = require("@zyfai/sdk");
|
|
2191
2597
|
|
|
@@ -2267,7 +2673,7 @@ function buildSIWXConfig(deps) {
|
|
|
2267
2673
|
issuedAt,
|
|
2268
2674
|
toString() {
|
|
2269
2675
|
return new import_siwe.SiweMessage({
|
|
2270
|
-
address: (0,
|
|
2676
|
+
address: (0, import_viem6.getAddress)(accountAddress),
|
|
2271
2677
|
chainId: numericChainId(chainId),
|
|
2272
2678
|
domain,
|
|
2273
2679
|
uri,
|