@owney/sdk 0.7.16-beta.1 → 0.7.16-beta.2
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 +1090 -532
- package/dist/index.d.cts +23 -6
- package/dist/index.d.ts +23 -6
- package/dist/index.js +1100 -541
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -181,18 +181,18 @@ function tokenDecimals(symbol, explicit) {
|
|
|
181
181
|
return explicit;
|
|
182
182
|
return DECIMALS_BY_SYMBOL[(symbol ?? "").toLowerCase()] ?? 6;
|
|
183
183
|
}
|
|
184
|
-
function mapDeposit(
|
|
184
|
+
function mapDeposit(raw2) {
|
|
185
185
|
return {
|
|
186
|
-
txHash:
|
|
187
|
-
smartWallet:
|
|
188
|
-
amount:
|
|
186
|
+
txHash: raw2.txHash,
|
|
187
|
+
smartWallet: raw2.smartWallet,
|
|
188
|
+
amount: raw2.amount
|
|
189
189
|
};
|
|
190
190
|
}
|
|
191
|
-
function mapWithdraw(
|
|
191
|
+
function mapWithdraw(raw2) {
|
|
192
192
|
return {
|
|
193
|
-
txHash:
|
|
194
|
-
type:
|
|
195
|
-
amount:
|
|
193
|
+
txHash: raw2.txHash,
|
|
194
|
+
type: raw2.type,
|
|
195
|
+
amount: raw2.amount
|
|
196
196
|
};
|
|
197
197
|
}
|
|
198
198
|
var CHAIN_ID_TO_NAME = {
|
|
@@ -211,10 +211,10 @@ function resolveChainId(chain) {
|
|
|
211
211
|
if (Number.isFinite(asNum) && asNum > 0) return asNum;
|
|
212
212
|
return NAME_TO_CHAIN_ID[chain.trim().toLowerCase()] ?? NaN;
|
|
213
213
|
}
|
|
214
|
-
function mapPendingAllocations(
|
|
215
|
-
if (!Array.isArray(
|
|
214
|
+
function mapPendingAllocations(raw2) {
|
|
215
|
+
if (!Array.isArray(raw2)) return void 0;
|
|
216
216
|
const pending = [];
|
|
217
|
-
for (const entry of
|
|
217
|
+
for (const entry of raw2) {
|
|
218
218
|
if (typeof entry !== "object" || entry === null) continue;
|
|
219
219
|
const e = entry;
|
|
220
220
|
if (typeof e.chainId !== "number" || !Number.isFinite(e.chainId)) continue;
|
|
@@ -237,8 +237,8 @@ function mapPendingAllocations(raw) {
|
|
|
237
237
|
}
|
|
238
238
|
return pending.length > 0 ? pending : void 0;
|
|
239
239
|
}
|
|
240
|
-
function mapBalances(
|
|
241
|
-
const portfolio =
|
|
240
|
+
function mapBalances(raw2, _chainId, smartWallet) {
|
|
241
|
+
const portfolio = raw2.portfolio;
|
|
242
242
|
const portfolioByChain = portfolio.portfolioByChain ?? {};
|
|
243
243
|
let totalBalance = 0;
|
|
244
244
|
const tokens = [];
|
|
@@ -307,8 +307,8 @@ function sumTokenValues(tokens) {
|
|
|
307
307
|
function sumTokenEarnings(tokens) {
|
|
308
308
|
return Object.values(tokens).reduce((sum, val) => sum + Number(val), 0);
|
|
309
309
|
}
|
|
310
|
-
function mapEarnings(
|
|
311
|
-
const totalEarningsByChain =
|
|
310
|
+
function mapEarnings(raw2, smartWallet) {
|
|
311
|
+
const totalEarningsByChain = raw2.data.totalEarningsByChainWithFee ?? raw2.data.totalEarningsByChain ?? {};
|
|
312
312
|
const tokens = [];
|
|
313
313
|
for (const [chainIdKey, tokensBySymbol] of Object.entries(
|
|
314
314
|
totalEarningsByChain
|
|
@@ -327,22 +327,22 @@ function mapEarnings(raw, smartWallet) {
|
|
|
327
327
|
return {
|
|
328
328
|
smartWallet,
|
|
329
329
|
lifetimeEarnings: sumTokenEarnings(
|
|
330
|
-
|
|
330
|
+
raw2.data.totalEarningsByTokenWithFee ?? raw2.data.totalEarningsByToken
|
|
331
331
|
),
|
|
332
332
|
tokens
|
|
333
333
|
};
|
|
334
334
|
}
|
|
335
|
-
function mapWeightedApyByChain(
|
|
336
|
-
if (!
|
|
335
|
+
function mapWeightedApyByChain(raw2) {
|
|
336
|
+
if (!raw2) return void 0;
|
|
337
337
|
const out = {};
|
|
338
|
-
for (const [chainKey, tokenApy] of Object.entries(
|
|
338
|
+
for (const [chainKey, tokenApy] of Object.entries(raw2)) {
|
|
339
339
|
const chainId = Number(chainKey);
|
|
340
340
|
if (!SUPPORTED_CHAIN_IDS.includes(chainId)) continue;
|
|
341
341
|
const perAsset = {};
|
|
342
342
|
for (const [symbol, apy] of Object.entries(tokenApy)) {
|
|
343
|
-
const
|
|
344
|
-
if (!SUPPORTED_TOKENS.includes(
|
|
345
|
-
perAsset[
|
|
343
|
+
const token = symbol;
|
|
344
|
+
if (!SUPPORTED_TOKENS.includes(token)) continue;
|
|
345
|
+
perAsset[token] = apy;
|
|
346
346
|
}
|
|
347
347
|
if (Object.keys(perAsset).length > 0) out[chainId] = perAsset;
|
|
348
348
|
}
|
|
@@ -361,15 +361,15 @@ function rawPoolApyForChain(entry, chainId, tokenSymbol) {
|
|
|
361
361
|
}
|
|
362
362
|
return totalBalance > 0 ? weightedSum / totalBalance : null;
|
|
363
363
|
}
|
|
364
|
-
function mapApyHistory(
|
|
365
|
-
const history = Object.entries(
|
|
364
|
+
function mapApyHistory(raw2, chainId, tokenSymbol) {
|
|
365
|
+
const history = Object.entries(raw2.history ?? {}).map(([date, entry]) => ({
|
|
366
366
|
date,
|
|
367
367
|
apy: rawPoolApyForChain(entry, chainId, tokenSymbol)
|
|
368
368
|
})).filter((p) => p.apy !== null).sort((a, b) => a.date.localeCompare(b.date));
|
|
369
369
|
return {
|
|
370
|
-
walletAddress:
|
|
371
|
-
weightedApyAfterFee:
|
|
372
|
-
apyByChainAndAsset: mapWeightedApyByChain(
|
|
370
|
+
walletAddress: raw2.walletAddress,
|
|
371
|
+
weightedApyAfterFee: raw2.weightedApyAfterFee ? sumTokenValues(raw2.weightedApyAfterFee) : void 0,
|
|
372
|
+
apyByChainAndAsset: mapWeightedApyByChain(raw2.weightedApyAfterFeeByChain),
|
|
373
373
|
history
|
|
374
374
|
};
|
|
375
375
|
}
|
|
@@ -461,23 +461,23 @@ function mapEntries(rawEntries, chainId) {
|
|
|
461
461
|
};
|
|
462
462
|
});
|
|
463
463
|
}
|
|
464
|
-
function mapUserProfile(
|
|
464
|
+
function mapUserProfile(raw2, userAddress) {
|
|
465
465
|
return {
|
|
466
466
|
address: userAddress,
|
|
467
|
-
smartWallet:
|
|
468
|
-
chains:
|
|
469
|
-
strategy:
|
|
470
|
-
hasActiveSessionKey:
|
|
471
|
-
protocols:
|
|
472
|
-
splitting:
|
|
473
|
-
minSplits:
|
|
467
|
+
smartWallet: raw2.smartWallet || "",
|
|
468
|
+
chains: raw2.chains || [],
|
|
469
|
+
strategy: raw2.strategy,
|
|
470
|
+
hasActiveSessionKey: raw2.hasActiveSessionKey || false,
|
|
471
|
+
protocols: raw2.protocols || [],
|
|
472
|
+
splitting: raw2.splitting,
|
|
473
|
+
minSplits: raw2.minSplits
|
|
474
474
|
};
|
|
475
475
|
}
|
|
476
|
-
function mapApyByStrategy(
|
|
476
|
+
function mapApyByStrategy(raw2) {
|
|
477
477
|
const apyPerAsset = {};
|
|
478
478
|
let apySum = 0;
|
|
479
479
|
let apyCount = 0;
|
|
480
|
-
for (const entry of
|
|
480
|
+
for (const entry of raw2.data) {
|
|
481
481
|
const supported = SupportedAssets.find(
|
|
482
482
|
(asset) => asset.chainId === entry.chain_id && asset.symbol === entry.token_symbol
|
|
483
483
|
);
|
|
@@ -511,23 +511,23 @@ function computeAllocationApy(positions) {
|
|
|
511
511
|
weightedSum += apy * value;
|
|
512
512
|
totalValue += value;
|
|
513
513
|
const chainId = resolveChainId(p.chain);
|
|
514
|
-
const
|
|
514
|
+
const token = p.asset;
|
|
515
515
|
if (!SUPPORTED_CHAIN_IDS.includes(chainId)) continue;
|
|
516
|
-
if (!SUPPORTED_TOKENS.includes(
|
|
516
|
+
if (!SUPPORTED_TOKENS.includes(token)) continue;
|
|
517
517
|
const perAsset = buckets[chainId] ?? {};
|
|
518
|
-
const cell = perAsset[
|
|
518
|
+
const cell = perAsset[token] ?? { weightedSum: 0, value: 0 };
|
|
519
519
|
cell.weightedSum += apy * value;
|
|
520
520
|
cell.value += value;
|
|
521
|
-
perAsset[
|
|
521
|
+
perAsset[token] = cell;
|
|
522
522
|
buckets[chainId] = perAsset;
|
|
523
523
|
}
|
|
524
524
|
const apyByChainAndAsset = {};
|
|
525
525
|
for (const [chainKey, perAsset] of Object.entries(buckets)) {
|
|
526
526
|
const chainId = Number(chainKey);
|
|
527
527
|
const out = {};
|
|
528
|
-
for (const [
|
|
528
|
+
for (const [token, cell] of Object.entries(perAsset ?? {})) {
|
|
529
529
|
if (cell && cell.value > 0) {
|
|
530
|
-
out[
|
|
530
|
+
out[token] = cell.weightedSum / cell.value;
|
|
531
531
|
}
|
|
532
532
|
}
|
|
533
533
|
if (Object.keys(out).length > 0) apyByChainAndAsset[chainId] = out;
|
|
@@ -541,9 +541,9 @@ var TRANSFER_TOPIC = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4d
|
|
|
541
541
|
function topicToAddress(topic) {
|
|
542
542
|
return `0x${(topic ?? "").slice(-40)}`.toLowerCase();
|
|
543
543
|
}
|
|
544
|
-
function extractWithdrawnAmount(logs, recipient,
|
|
544
|
+
function extractWithdrawnAmount(logs, recipient, token, decimals) {
|
|
545
545
|
const wantRecipient = recipient.toLowerCase();
|
|
546
|
-
const wantToken =
|
|
546
|
+
const wantToken = token.toLowerCase();
|
|
547
547
|
let total = 0n;
|
|
548
548
|
let matched = false;
|
|
549
549
|
for (const log of logs) {
|
|
@@ -569,11 +569,11 @@ var InvalidHistoryCursorError = class extends Error {
|
|
|
569
569
|
function encodeHistoryCursor(payload) {
|
|
570
570
|
return Buffer.from(JSON.stringify(payload), "utf8").toString("base64");
|
|
571
571
|
}
|
|
572
|
-
function decodeHistoryCursor(
|
|
573
|
-
if (!
|
|
572
|
+
function decodeHistoryCursor(token) {
|
|
573
|
+
if (!token) throw new InvalidHistoryCursorError("Cursor is empty.");
|
|
574
574
|
let parsed;
|
|
575
575
|
try {
|
|
576
|
-
const json = Buffer.from(
|
|
576
|
+
const json = Buffer.from(token, "base64").toString("utf8");
|
|
577
577
|
parsed = JSON.parse(json);
|
|
578
578
|
} catch {
|
|
579
579
|
throw new InvalidHistoryCursorError("Cursor is not valid base64 JSON.");
|
|
@@ -596,8 +596,8 @@ var storage = () => {
|
|
|
596
596
|
};
|
|
597
597
|
var buildKey = (address) => `${KEY_PREFIX}:${address.toLowerCase()}`;
|
|
598
598
|
var legacyKeyPrefix = (address) => `${KEY_PREFIX}:${address.toLowerCase()}:`;
|
|
599
|
-
var isJwtExpired = (
|
|
600
|
-
const parts =
|
|
599
|
+
var isJwtExpired = (token) => {
|
|
600
|
+
const parts = token.split(".");
|
|
601
601
|
if (parts.length !== 3) return false;
|
|
602
602
|
try {
|
|
603
603
|
const payload = parts[1].replace(/-/g, "+").replace(/_/g, "/");
|
|
@@ -644,15 +644,15 @@ var readSession = (address, _chainId) => {
|
|
|
644
644
|
if (typeof window === "undefined") return null;
|
|
645
645
|
const key2 = buildKey(address);
|
|
646
646
|
const store = storage();
|
|
647
|
-
let
|
|
647
|
+
let raw2 = null;
|
|
648
648
|
try {
|
|
649
|
-
|
|
649
|
+
raw2 = store?.getItem(key2) ?? null;
|
|
650
650
|
} catch {
|
|
651
|
-
|
|
651
|
+
raw2 = null;
|
|
652
652
|
}
|
|
653
|
-
if (
|
|
653
|
+
if (raw2) {
|
|
654
654
|
try {
|
|
655
|
-
const parsed = JSON.parse(
|
|
655
|
+
const parsed = JSON.parse(raw2);
|
|
656
656
|
if (isFreshSession(parsed)) return parsed;
|
|
657
657
|
} catch {
|
|
658
658
|
}
|
|
@@ -820,8 +820,8 @@ function buildChainsByProtocol(protocols, dashboardChainIds) {
|
|
|
820
820
|
}
|
|
821
821
|
return result;
|
|
822
822
|
}
|
|
823
|
-
function flattenAvailablePools(
|
|
824
|
-
const byChain =
|
|
823
|
+
function flattenAvailablePools(raw2) {
|
|
824
|
+
const byChain = raw2 ?? {};
|
|
825
825
|
const names = [];
|
|
826
826
|
for (const byToken of Object.values(byChain ?? {})) {
|
|
827
827
|
for (const entry of Object.values(byToken ?? {})) {
|
|
@@ -1332,8 +1332,8 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1332
1332
|
const poolResults = await Promise.all(
|
|
1333
1333
|
universe.map(async (protocol) => {
|
|
1334
1334
|
try {
|
|
1335
|
-
const
|
|
1336
|
-
return [protocol.id, flattenAvailablePools(
|
|
1335
|
+
const raw2 = await this.sdk.getAvailablePools(protocol.id, strategy);
|
|
1336
|
+
return [protocol.id, flattenAvailablePools(raw2)];
|
|
1337
1337
|
} catch (error) {
|
|
1338
1338
|
console.warn(
|
|
1339
1339
|
`[zyfai] applyPoolPolicy: getAvailablePools(${protocol.id}) failed, skipping this protocol (non-fatal):`,
|
|
@@ -1399,14 +1399,14 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1399
1399
|
async readWalletState(ownerAddress) {
|
|
1400
1400
|
try {
|
|
1401
1401
|
const { portfolio } = await this.sdk.getPositions(ownerAddress);
|
|
1402
|
-
const
|
|
1402
|
+
const raw2 = portfolio;
|
|
1403
1403
|
debugLog("zyfai:onboard", "wallet state from getPositions", {
|
|
1404
|
-
predeployed:
|
|
1405
|
-
hasActiveSessionKey:
|
|
1404
|
+
predeployed: raw2?.predeployed,
|
|
1405
|
+
hasActiveSessionKey: raw2?.hasActiveSessionKey
|
|
1406
1406
|
});
|
|
1407
1407
|
return {
|
|
1408
|
-
predeployed:
|
|
1409
|
-
hasActiveSessionKey:
|
|
1408
|
+
predeployed: raw2?.predeployed,
|
|
1409
|
+
hasActiveSessionKey: raw2?.hasActiveSessionKey
|
|
1410
1410
|
};
|
|
1411
1411
|
} catch (error) {
|
|
1412
1412
|
console.warn(
|
|
@@ -1686,48 +1686,48 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1686
1686
|
return { txHash, smartWallet, amount };
|
|
1687
1687
|
}
|
|
1688
1688
|
await this.ensureWalletDeployed(this.getAddress(), validChainId);
|
|
1689
|
-
const
|
|
1689
|
+
const raw2 = await this.sdk.depositFunds(
|
|
1690
1690
|
this.getAddress(),
|
|
1691
1691
|
validChainId,
|
|
1692
1692
|
amount,
|
|
1693
1693
|
asset,
|
|
1694
1694
|
"aggressive"
|
|
1695
1695
|
);
|
|
1696
|
-
return mapDeposit(
|
|
1696
|
+
return mapDeposit(raw2);
|
|
1697
1697
|
} catch (error) {
|
|
1698
1698
|
throw error;
|
|
1699
1699
|
}
|
|
1700
1700
|
}
|
|
1701
1701
|
// --- IAgent: Fund operations ---
|
|
1702
|
-
async withdraw(state, chainId,
|
|
1702
|
+
async withdraw(state, chainId, token, amount) {
|
|
1703
1703
|
const validChainId = isValidChainId(chainId);
|
|
1704
1704
|
await this.ensureConnected(state, validChainId);
|
|
1705
|
-
const
|
|
1705
|
+
const raw2 = await this.sdk.withdrawFunds(
|
|
1706
1706
|
this.getAddress(),
|
|
1707
1707
|
validChainId,
|
|
1708
1708
|
amount,
|
|
1709
|
-
|
|
1709
|
+
token
|
|
1710
1710
|
);
|
|
1711
|
-
if (!
|
|
1711
|
+
if (!raw2.success) {
|
|
1712
1712
|
throw new OwneyError(
|
|
1713
1713
|
"WITHDRAW_FAILED",
|
|
1714
|
-
|
|
1715
|
-
{ chainId: validChainId, token
|
|
1714
|
+
raw2.message || "Zyfai withdraw failed.",
|
|
1715
|
+
{ chainId: validChainId, token, amount, response: raw2 },
|
|
1716
1716
|
this.id
|
|
1717
1717
|
);
|
|
1718
1718
|
}
|
|
1719
|
-
return mapWithdraw(
|
|
1719
|
+
return mapWithdraw(raw2);
|
|
1720
1720
|
}
|
|
1721
1721
|
// --- IAgent: Portfolio reads ---
|
|
1722
1722
|
async getBalances(state, chainId) {
|
|
1723
1723
|
const { smartWallet, chainId: validChainId } = await this.resolveSmartWallet(state, chainId);
|
|
1724
|
-
const
|
|
1725
|
-
return mapBalances(
|
|
1724
|
+
const raw2 = await this.sdk.getPortfolio(this.getAddress());
|
|
1725
|
+
return mapBalances(raw2, validChainId, smartWallet);
|
|
1726
1726
|
}
|
|
1727
1727
|
async getEarnings(state, chainId) {
|
|
1728
1728
|
const { smartWallet } = await this.resolveSmartWallet(state, chainId);
|
|
1729
|
-
const
|
|
1730
|
-
return mapEarnings(
|
|
1729
|
+
const raw2 = await this.sdk.getOnchainEarnings(smartWallet);
|
|
1730
|
+
return mapEarnings(raw2, smartWallet);
|
|
1731
1731
|
}
|
|
1732
1732
|
async refreshEarnings(state, chainId) {
|
|
1733
1733
|
if (this.earningsRefreshInFlight) return this.earningsRefreshInFlight;
|
|
@@ -1747,8 +1747,8 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1747
1747
|
}
|
|
1748
1748
|
async getAccountApy(state, chainId, days, tokenSymbol) {
|
|
1749
1749
|
const { smartWallet } = await this.resolveSmartWallet(state, chainId);
|
|
1750
|
-
const
|
|
1751
|
-
return mapApyHistory(
|
|
1750
|
+
const raw2 = await this.sdk.getDailyApyHistory(smartWallet, days);
|
|
1751
|
+
return mapApyHistory(raw2, chainId, tokenSymbol);
|
|
1752
1752
|
}
|
|
1753
1753
|
/**
|
|
1754
1754
|
* Owney speaks asset symbols ("USDC" / "WETH"); Zyfai's history endpoint
|
|
@@ -1783,7 +1783,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1783
1783
|
const matched = [];
|
|
1784
1784
|
let backendExhausted = false;
|
|
1785
1785
|
for (let i = 0; i < MAX_BACKEND_CALLS && matched.length < limit; i++) {
|
|
1786
|
-
const
|
|
1786
|
+
const raw2 = await this.sdk.getHistory(smartWallet, validChainId, {
|
|
1787
1787
|
limit: backendPageSize,
|
|
1788
1788
|
offset,
|
|
1789
1789
|
fromDate: options?.fromDate,
|
|
@@ -1794,13 +1794,13 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1794
1794
|
// asset's rows and handing back a page that filters to nothing.
|
|
1795
1795
|
assetType
|
|
1796
1796
|
});
|
|
1797
|
-
|
|
1797
|
+
raw2.data.forEach((entry, idx) => {
|
|
1798
1798
|
if (entry.chainId === validChainId) {
|
|
1799
1799
|
matched.push({ entry, rawIdx: offset + idx });
|
|
1800
1800
|
}
|
|
1801
1801
|
});
|
|
1802
|
-
offset +=
|
|
1803
|
-
if (
|
|
1802
|
+
offset += raw2.data.length;
|
|
1803
|
+
if (raw2.data.length < backendPageSize) {
|
|
1804
1804
|
backendExhausted = true;
|
|
1805
1805
|
break;
|
|
1806
1806
|
}
|
|
@@ -1822,18 +1822,18 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1822
1822
|
}
|
|
1823
1823
|
async getUserProfile(state, chainId) {
|
|
1824
1824
|
await this.connectAuth(state, chainId);
|
|
1825
|
-
const
|
|
1825
|
+
const raw2 = await this.sdk.getUserDetails();
|
|
1826
1826
|
debugLog("zyfai:profile", "getUserProfile \u2014 Zyfai reports", {
|
|
1827
1827
|
asset: "USDC (default \u2014 no asset passed)",
|
|
1828
|
-
splitting:
|
|
1829
|
-
minSplits:
|
|
1830
|
-
strategy:
|
|
1831
|
-
chains:
|
|
1832
|
-
protocolCount:
|
|
1833
|
-
hasActiveSessionKey:
|
|
1834
|
-
smartWallet:
|
|
1828
|
+
splitting: raw2.splitting,
|
|
1829
|
+
minSplits: raw2.minSplits,
|
|
1830
|
+
strategy: raw2.strategy,
|
|
1831
|
+
chains: raw2.chains,
|
|
1832
|
+
protocolCount: raw2.protocols?.length,
|
|
1833
|
+
hasActiveSessionKey: raw2.hasActiveSessionKey,
|
|
1834
|
+
smartWallet: raw2.smartWallet
|
|
1835
1835
|
});
|
|
1836
|
-
return mapUserProfile(
|
|
1836
|
+
return mapUserProfile(raw2, this.connectedAddress);
|
|
1837
1837
|
}
|
|
1838
1838
|
async ensureAutoSelectProtocols(state, chainId, asset) {
|
|
1839
1839
|
await this.connectAuth(state, chainId);
|
|
@@ -1852,14 +1852,14 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1852
1852
|
}
|
|
1853
1853
|
// --- IAgent: Discovery (no wallet required) ---
|
|
1854
1854
|
async getAgentApy(days, options) {
|
|
1855
|
-
const
|
|
1855
|
+
const raw2 = await this.sdk.getAPYPerStrategy(
|
|
1856
1856
|
false,
|
|
1857
1857
|
DayFilterMapping[days],
|
|
1858
1858
|
"aggressive",
|
|
1859
1859
|
options?.chainId,
|
|
1860
1860
|
options?.tokenSymbol
|
|
1861
1861
|
);
|
|
1862
|
-
return mapApyByStrategy(
|
|
1862
|
+
return mapApyByStrategy(raw2);
|
|
1863
1863
|
}
|
|
1864
1864
|
};
|
|
1865
1865
|
|
|
@@ -1925,10 +1925,10 @@ function buildTransferWithAuthorizationTypedData(input) {
|
|
|
1925
1925
|
message: input.message
|
|
1926
1926
|
};
|
|
1927
1927
|
}
|
|
1928
|
-
async function readTokenMeta(publicClient,
|
|
1928
|
+
async function readTokenMeta(publicClient, token) {
|
|
1929
1929
|
const [tokenName, tokenVersion] = await Promise.all([
|
|
1930
|
-
publicClient.readContract({ address:
|
|
1931
|
-
publicClient.readContract({ address:
|
|
1930
|
+
publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "name" }),
|
|
1931
|
+
publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "version" }).catch(() => "2")
|
|
1932
1932
|
]);
|
|
1933
1933
|
return { tokenName, tokenVersion };
|
|
1934
1934
|
}
|
|
@@ -1940,6 +1940,45 @@ function randomAuthNonce() {
|
|
|
1940
1940
|
|
|
1941
1941
|
// src/lib/sponsor-client.ts
|
|
1942
1942
|
var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
1943
|
+
async function postPaymasterIntent(input) {
|
|
1944
|
+
const base5 = input.baseUrl ?? ROUTING_API_BASE_URL;
|
|
1945
|
+
let res;
|
|
1946
|
+
try {
|
|
1947
|
+
res = await fetch(`${base5}/api/v1/sponsor/paymaster-intent`, {
|
|
1948
|
+
method: "POST",
|
|
1949
|
+
headers: {
|
|
1950
|
+
"content-type": "application/json",
|
|
1951
|
+
"x-owney-api-key": input.apiKey,
|
|
1952
|
+
Authorization: `Signature ${input.yieldseekerSignature}`
|
|
1953
|
+
},
|
|
1954
|
+
body: JSON.stringify(input.body)
|
|
1955
|
+
});
|
|
1956
|
+
} catch (networkError) {
|
|
1957
|
+
throw new OwneyError(
|
|
1958
|
+
"SPONSOR_REQUEST_FAILED",
|
|
1959
|
+
`Paymaster intent network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
|
|
1960
|
+
{ cause: String(networkError), safeToFallback: true }
|
|
1961
|
+
);
|
|
1962
|
+
}
|
|
1963
|
+
const text = await res.text();
|
|
1964
|
+
let parsed = null;
|
|
1965
|
+
try {
|
|
1966
|
+
parsed = JSON.parse(text);
|
|
1967
|
+
} catch {
|
|
1968
|
+
}
|
|
1969
|
+
if (!res.ok || !parsed?.success || typeof parsed.data?.intent !== "string" || typeof parsed.data.expiresAt !== "number") {
|
|
1970
|
+
throw new OwneyError(
|
|
1971
|
+
"SPONSOR_REQUEST_FAILED",
|
|
1972
|
+
`Paymaster intent API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
|
|
1973
|
+
{
|
|
1974
|
+
statusCode: res.status,
|
|
1975
|
+
responseBody: text.slice(0, 500),
|
|
1976
|
+
safeToFallback: true
|
|
1977
|
+
}
|
|
1978
|
+
);
|
|
1979
|
+
}
|
|
1980
|
+
return parsed.data;
|
|
1981
|
+
}
|
|
1943
1982
|
async function postSponsorTransferAuth(input) {
|
|
1944
1983
|
const base5 = input.baseUrl ?? ROUTING_API_BASE_URL;
|
|
1945
1984
|
let res;
|
|
@@ -1949,7 +1988,7 @@ async function postSponsorTransferAuth(input) {
|
|
|
1949
1988
|
headers: {
|
|
1950
1989
|
"content-type": "application/json",
|
|
1951
1990
|
"x-owney-api-key": input.apiKey,
|
|
1952
|
-
...input.yieldseekerSignature ? {
|
|
1991
|
+
...input.yieldseekerSignature ? { Authorization: `Signature ${input.yieldseekerSignature}` } : {}
|
|
1953
1992
|
},
|
|
1954
1993
|
body: JSON.stringify(input.body)
|
|
1955
1994
|
});
|
|
@@ -1990,7 +2029,7 @@ async function postSponsorPermit2Transfer(input) {
|
|
|
1990
2029
|
headers: {
|
|
1991
2030
|
"content-type": "application/json",
|
|
1992
2031
|
"x-owney-api-key": input.apiKey,
|
|
1993
|
-
...input.yieldseekerSignature ? {
|
|
2032
|
+
...input.yieldseekerSignature ? { Authorization: `Signature ${input.yieldseekerSignature}` } : {}
|
|
1994
2033
|
},
|
|
1995
2034
|
body: JSON.stringify(input.body)
|
|
1996
2035
|
});
|
|
@@ -2118,17 +2157,17 @@ function randomPermit2Nonce() {
|
|
|
2118
2157
|
globalThis.crypto.getRandomValues(bytes);
|
|
2119
2158
|
return BigInt((0, import_viem3.bytesToHex)(bytes));
|
|
2120
2159
|
}
|
|
2121
|
-
async function readPermit2Allowance(publicClient,
|
|
2160
|
+
async function readPermit2Allowance(publicClient, token, owner) {
|
|
2122
2161
|
return publicClient.readContract({
|
|
2123
|
-
address:
|
|
2162
|
+
address: token,
|
|
2124
2163
|
abi: ERC20_ALLOWANCE_ABI,
|
|
2125
2164
|
functionName: "allowance",
|
|
2126
2165
|
args: [owner, PERMIT2_ADDRESS]
|
|
2127
2166
|
});
|
|
2128
2167
|
}
|
|
2129
|
-
async function readErc20Balance(publicClient,
|
|
2168
|
+
async function readErc20Balance(publicClient, token, owner) {
|
|
2130
2169
|
return publicClient.readContract({
|
|
2131
|
-
address:
|
|
2170
|
+
address: token,
|
|
2132
2171
|
abi: ERC20_ALLOWANCE_ABI,
|
|
2133
2172
|
functionName: "balanceOf",
|
|
2134
2173
|
args: [owner]
|
|
@@ -2160,8 +2199,8 @@ function makeSponsoredDepositCallback(deps) {
|
|
|
2160
2199
|
return makeVerificationAwareDepositCallback(
|
|
2161
2200
|
async (smartWallet, chainId, amount, verification) => {
|
|
2162
2201
|
const cid = chainId;
|
|
2163
|
-
const
|
|
2164
|
-
if (!
|
|
2202
|
+
const token = deps.tokenAddressByChain[cid];
|
|
2203
|
+
if (!token) {
|
|
2165
2204
|
throw new OwneyError(
|
|
2166
2205
|
"CHAIN_UNSUPPORTED",
|
|
2167
2206
|
`No sponsored token configured for chain ${chainId}`
|
|
@@ -2171,12 +2210,12 @@ function makeSponsoredDepositCallback(deps) {
|
|
|
2171
2210
|
const wallet = deps.getWalletClient(cid);
|
|
2172
2211
|
await ensureWalletOnChain(pub, wallet, cid);
|
|
2173
2212
|
try {
|
|
2174
|
-
const balance = await readErc20Balance(pub,
|
|
2213
|
+
const balance = await readErc20Balance(pub, token, deps.ownerAddress);
|
|
2175
2214
|
if (balance < BigInt(amount)) {
|
|
2176
2215
|
throw new OwneyError(
|
|
2177
2216
|
"DEPOSIT_INSUFFICIENT_BALANCE",
|
|
2178
2217
|
"Insufficient balance for this deposit.",
|
|
2179
|
-
{ token
|
|
2218
|
+
{ token, chainId: cid, balance: balance.toString(), amount }
|
|
2180
2219
|
);
|
|
2181
2220
|
}
|
|
2182
2221
|
} catch (err) {
|
|
@@ -2186,14 +2225,14 @@ function makeSponsoredDepositCallback(deps) {
|
|
|
2186
2225
|
err instanceof Error ? err.message : String(err)
|
|
2187
2226
|
);
|
|
2188
2227
|
}
|
|
2189
|
-
const { tokenName, tokenVersion } = await readTokenMeta(pub,
|
|
2228
|
+
const { tokenName, tokenVersion } = await readTokenMeta(pub, token);
|
|
2190
2229
|
const validAfter = 0n;
|
|
2191
2230
|
const validBefore = BigInt(
|
|
2192
2231
|
Math.floor(Date.now() / 1e3) + AUTH_WINDOW_SECONDS
|
|
2193
2232
|
);
|
|
2194
2233
|
const nonce = randomAuthNonce();
|
|
2195
2234
|
const typedData = buildTransferWithAuthorizationTypedData({
|
|
2196
|
-
token
|
|
2235
|
+
token,
|
|
2197
2236
|
chainId: cid,
|
|
2198
2237
|
tokenName,
|
|
2199
2238
|
tokenVersion,
|
|
@@ -2217,7 +2256,7 @@ function makeSponsoredDepositCallback(deps) {
|
|
|
2217
2256
|
...verification?.agentId === "yieldseeker" ? { yieldseekerSignature: verification.signature } : {},
|
|
2218
2257
|
body: {
|
|
2219
2258
|
chainId: cid,
|
|
2220
|
-
token
|
|
2259
|
+
token,
|
|
2221
2260
|
from: deps.ownerAddress,
|
|
2222
2261
|
to: smartWallet,
|
|
2223
2262
|
value: amount,
|
|
@@ -2226,7 +2265,11 @@ function makeSponsoredDepositCallback(deps) {
|
|
|
2226
2265
|
nonce,
|
|
2227
2266
|
authSignature,
|
|
2228
2267
|
tokenName,
|
|
2229
|
-
tokenVersion
|
|
2268
|
+
tokenVersion,
|
|
2269
|
+
...verification?.agentId === "yieldseeker" ? {
|
|
2270
|
+
yieldseekerUserId: verification.userId,
|
|
2271
|
+
yieldseekerAgentId: verification.yieldseekerAgentId
|
|
2272
|
+
} : {}
|
|
2230
2273
|
}
|
|
2231
2274
|
});
|
|
2232
2275
|
return result.txHash;
|
|
@@ -2240,7 +2283,11 @@ var import_viem4 = require("viem");
|
|
|
2240
2283
|
var import_chains2 = require("viem/chains");
|
|
2241
2284
|
|
|
2242
2285
|
// src/agents/yieldseeker/yieldseeker.auth-cache.ts
|
|
2243
|
-
var KEY_PREFIX2 = "owney.yieldseeker.session";
|
|
2286
|
+
var KEY_PREFIX2 = "owney.yieldseeker.session.v4";
|
|
2287
|
+
var INVALIDATED_KEY_PREFIXES = [
|
|
2288
|
+
"owney.yieldseeker.session",
|
|
2289
|
+
"owney.yieldseeker.session.v3"
|
|
2290
|
+
];
|
|
2244
2291
|
var storage2 = () => {
|
|
2245
2292
|
if (typeof window === "undefined") return null;
|
|
2246
2293
|
try {
|
|
@@ -2250,6 +2297,18 @@ var storage2 = () => {
|
|
|
2250
2297
|
}
|
|
2251
2298
|
};
|
|
2252
2299
|
var buildKey2 = (address, chainId) => `${KEY_PREFIX2}:${address.toLowerCase()}:${chainId}`;
|
|
2300
|
+
var invalidatedKeys = (address, chainId) => INVALIDATED_KEY_PREFIXES.map(
|
|
2301
|
+
(prefix) => `${prefix}:${address.toLowerCase()}:${chainId}`
|
|
2302
|
+
);
|
|
2303
|
+
var clearInvalidatedSessions = (store, address, chainId) => {
|
|
2304
|
+
for (const key2 of invalidatedKeys(address, chainId)) {
|
|
2305
|
+
memorySessions2.delete(key2);
|
|
2306
|
+
try {
|
|
2307
|
+
store?.removeItem(key2);
|
|
2308
|
+
} catch {
|
|
2309
|
+
}
|
|
2310
|
+
}
|
|
2311
|
+
};
|
|
2253
2312
|
var memorySessions2 = /* @__PURE__ */ new Map();
|
|
2254
2313
|
var isValidSession = (session) => {
|
|
2255
2314
|
if (!session?.token) return false;
|
|
@@ -2264,15 +2323,16 @@ var readYieldseekerSession = (address, chainId) => {
|
|
|
2264
2323
|
if (typeof window === "undefined") return null;
|
|
2265
2324
|
const key2 = buildKey2(address, chainId);
|
|
2266
2325
|
const store = storage2();
|
|
2267
|
-
|
|
2326
|
+
clearInvalidatedSessions(store, address, chainId);
|
|
2327
|
+
let raw2 = null;
|
|
2268
2328
|
try {
|
|
2269
|
-
|
|
2329
|
+
raw2 = store?.getItem(key2) ?? null;
|
|
2270
2330
|
} catch {
|
|
2271
|
-
|
|
2331
|
+
raw2 = null;
|
|
2272
2332
|
}
|
|
2273
|
-
if (
|
|
2333
|
+
if (raw2) {
|
|
2274
2334
|
try {
|
|
2275
|
-
const parsed = JSON.parse(
|
|
2335
|
+
const parsed = JSON.parse(raw2);
|
|
2276
2336
|
if (isValidSession(parsed)) return parsed.token;
|
|
2277
2337
|
} catch {
|
|
2278
2338
|
}
|
|
@@ -2288,9 +2348,9 @@ var readYieldseekerSession = (address, chainId) => {
|
|
|
2288
2348
|
if (cached) memorySessions2.delete(key2);
|
|
2289
2349
|
return null;
|
|
2290
2350
|
};
|
|
2291
|
-
var writeYieldseekerSession = (address, chainId,
|
|
2351
|
+
var writeYieldseekerSession = (address, chainId, token) => {
|
|
2292
2352
|
if (typeof window === "undefined") return;
|
|
2293
|
-
const session = { token
|
|
2353
|
+
const session = { token };
|
|
2294
2354
|
if (!isValidSession(session)) return;
|
|
2295
2355
|
const key2 = buildKey2(address, chainId);
|
|
2296
2356
|
memorySessions2.set(key2, session);
|
|
@@ -2304,6 +2364,7 @@ var clearYieldseekerSession = (address, chainId) => {
|
|
|
2304
2364
|
const key2 = buildKey2(address, chainId);
|
|
2305
2365
|
memorySessions2.delete(key2);
|
|
2306
2366
|
const store = storage2();
|
|
2367
|
+
clearInvalidatedSessions(store, address, chainId);
|
|
2307
2368
|
try {
|
|
2308
2369
|
store?.removeItem(key2);
|
|
2309
2370
|
} catch {
|
|
@@ -2322,8 +2383,8 @@ function createYieldseekerSiweMessage(address, chainId, dependencies = {}) {
|
|
|
2322
2383
|
issuedAt: (dependencies.now ?? (() => /* @__PURE__ */ new Date()))().toISOString()
|
|
2323
2384
|
}).prepareMessage();
|
|
2324
2385
|
}
|
|
2325
|
-
function encodeYieldseekerAuthToken(
|
|
2326
|
-
const bytes = new TextEncoder().encode(JSON.stringify(
|
|
2386
|
+
function encodeYieldseekerAuthToken(token) {
|
|
2387
|
+
const bytes = new TextEncoder().encode(JSON.stringify(token));
|
|
2327
2388
|
let binary = "";
|
|
2328
2389
|
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
2329
2390
|
return btoa(binary);
|
|
@@ -2352,10 +2413,10 @@ var YieldseekerAuth = class {
|
|
|
2352
2413
|
}
|
|
2353
2414
|
const inFlight = this.pending.get(key2);
|
|
2354
2415
|
if (inFlight) return inFlight;
|
|
2355
|
-
const request = this.sign(state, chainId).then((
|
|
2356
|
-
this.tokens.set(key2,
|
|
2357
|
-
writeYieldseekerSession(scope.address, scope.chainId,
|
|
2358
|
-
return
|
|
2416
|
+
const request = this.sign(state, chainId).then((token) => {
|
|
2417
|
+
this.tokens.set(key2, token);
|
|
2418
|
+
writeYieldseekerSession(scope.address, scope.chainId, token);
|
|
2419
|
+
return token;
|
|
2359
2420
|
});
|
|
2360
2421
|
this.pending.set(key2, request);
|
|
2361
2422
|
try {
|
|
@@ -2406,6 +2467,72 @@ var YieldseekerAuth = class {
|
|
|
2406
2467
|
}
|
|
2407
2468
|
};
|
|
2408
2469
|
|
|
2470
|
+
// src/agents/yieldseeker/yieldseeker.identity-cache.ts
|
|
2471
|
+
var KEY_PREFIX3 = "owney.yieldseeker.identity.v1";
|
|
2472
|
+
var YIELDSEEKER_IDENTITY_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
2473
|
+
var memoryIdentities = /* @__PURE__ */ new Map();
|
|
2474
|
+
var storage3 = () => {
|
|
2475
|
+
if (typeof window === "undefined") return null;
|
|
2476
|
+
try {
|
|
2477
|
+
return window.localStorage;
|
|
2478
|
+
} catch {
|
|
2479
|
+
return null;
|
|
2480
|
+
}
|
|
2481
|
+
};
|
|
2482
|
+
var keyFor = (walletAddress, chainId) => `${KEY_PREFIX3}:${walletAddress.toLowerCase()}:${chainId}`;
|
|
2483
|
+
function valid(value, walletAddress, chainId, now) {
|
|
2484
|
+
return Boolean(
|
|
2485
|
+
value && typeof value.userId === "string" && /^[a-zA-Z0-9_-]{1,128}$/.test(value.userId) && value.walletAddress.toLowerCase() === walletAddress.toLowerCase() && value.chainId === chainId && Number.isSafeInteger(value.expiresAt) && value.expiresAt > now
|
|
2486
|
+
);
|
|
2487
|
+
}
|
|
2488
|
+
function readYieldseekerIdentity(walletAddress, chainId, now = Date.now()) {
|
|
2489
|
+
if (typeof window === "undefined") return null;
|
|
2490
|
+
const key2 = keyFor(walletAddress, chainId);
|
|
2491
|
+
const store = storage3();
|
|
2492
|
+
let parsed = null;
|
|
2493
|
+
try {
|
|
2494
|
+
const raw2 = store?.getItem(key2);
|
|
2495
|
+
parsed = raw2 ? JSON.parse(raw2) : null;
|
|
2496
|
+
} catch {
|
|
2497
|
+
parsed = null;
|
|
2498
|
+
}
|
|
2499
|
+
const candidate = parsed ?? memoryIdentities.get(key2);
|
|
2500
|
+
if (valid(candidate, walletAddress, chainId, now)) {
|
|
2501
|
+
memoryIdentities.set(key2, candidate);
|
|
2502
|
+
return { userId: candidate.userId };
|
|
2503
|
+
}
|
|
2504
|
+
memoryIdentities.delete(key2);
|
|
2505
|
+
try {
|
|
2506
|
+
store?.removeItem(key2);
|
|
2507
|
+
} catch {
|
|
2508
|
+
}
|
|
2509
|
+
return null;
|
|
2510
|
+
}
|
|
2511
|
+
function writeYieldseekerIdentity(walletAddress, chainId, userId, now = Date.now()) {
|
|
2512
|
+
if (typeof window === "undefined") return;
|
|
2513
|
+
const identity = {
|
|
2514
|
+
userId,
|
|
2515
|
+
walletAddress,
|
|
2516
|
+
chainId,
|
|
2517
|
+
expiresAt: now + YIELDSEEKER_IDENTITY_TTL_MS
|
|
2518
|
+
};
|
|
2519
|
+
if (!valid(identity, walletAddress, chainId, now)) return;
|
|
2520
|
+
const key2 = keyFor(walletAddress, chainId);
|
|
2521
|
+
memoryIdentities.set(key2, identity);
|
|
2522
|
+
try {
|
|
2523
|
+
storage3()?.setItem(key2, JSON.stringify(identity));
|
|
2524
|
+
} catch {
|
|
2525
|
+
}
|
|
2526
|
+
}
|
|
2527
|
+
function clearYieldseekerIdentity(walletAddress, chainId) {
|
|
2528
|
+
const key2 = keyFor(walletAddress, chainId);
|
|
2529
|
+
memoryIdentities.delete(key2);
|
|
2530
|
+
try {
|
|
2531
|
+
storage3()?.removeItem(key2);
|
|
2532
|
+
} catch {
|
|
2533
|
+
}
|
|
2534
|
+
}
|
|
2535
|
+
|
|
2409
2536
|
// src/agents/yieldseeker/yieldseeker.client.ts
|
|
2410
2537
|
var DEFAULT_ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
2411
2538
|
function getYieldseekerProxyBaseUrl(routingApiBaseUrl = DEFAULT_ROUTING_API_BASE_URL) {
|
|
@@ -2456,7 +2583,7 @@ var YieldseekerApiClient = class {
|
|
|
2456
2583
|
headers: {
|
|
2457
2584
|
"Content-Type": "application/json",
|
|
2458
2585
|
"x-owney-api-key": this.owneyApiKey,
|
|
2459
|
-
...options.signature ? {
|
|
2586
|
+
...options.signature ? { Authorization: `Signature ${options.signature}` } : {}
|
|
2460
2587
|
},
|
|
2461
2588
|
body: options.body ? JSON.stringify(options.body) : void 0,
|
|
2462
2589
|
signal: controller.signal
|
|
@@ -2490,24 +2617,20 @@ var YieldseekerApiClient = class {
|
|
|
2490
2617
|
|
|
2491
2618
|
// src/agents/yieldseeker/yieldseeker.mapper.ts
|
|
2492
2619
|
var import_viem5 = require("viem");
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
);
|
|
2504
|
-
}
|
|
2505
|
-
try {
|
|
2506
|
-
return (0, import_viem5.formatUnits)(BigInt(value), decimals);
|
|
2507
|
-
} catch {
|
|
2508
|
-
return invalid("history", `invalid rebalance amount ${value}`);
|
|
2620
|
+
|
|
2621
|
+
// src/agents/yieldseeker/yieldseeker.types.ts
|
|
2622
|
+
var YIELDSEEKER_ASSET_METADATA = {
|
|
2623
|
+
USDC: {
|
|
2624
|
+
address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
2625
|
+
decimals: 6
|
|
2626
|
+
},
|
|
2627
|
+
WETH: {
|
|
2628
|
+
address: "0x4200000000000000000000000000000000000006",
|
|
2629
|
+
decimals: 18
|
|
2509
2630
|
}
|
|
2510
|
-
}
|
|
2631
|
+
};
|
|
2632
|
+
|
|
2633
|
+
// src/agents/yieldseeker/yieldseeker.mapper.ts
|
|
2511
2634
|
function invalid(endpoint, detail) {
|
|
2512
2635
|
throw new OwneyError(
|
|
2513
2636
|
"AGENT_INVALID_RESPONSE",
|
|
@@ -2516,193 +2639,313 @@ function invalid(endpoint, detail) {
|
|
|
2516
2639
|
"yieldseeker"
|
|
2517
2640
|
);
|
|
2518
2641
|
}
|
|
2519
|
-
function
|
|
2520
|
-
if (
|
|
2521
|
-
return invalid(endpoint, "expected
|
|
2642
|
+
function raw(value, endpoint) {
|
|
2643
|
+
if (typeof value !== "string" || !/^-?[0-9]+$/.test(value)) {
|
|
2644
|
+
return invalid(endpoint, "expected a base-10 integer string");
|
|
2522
2645
|
}
|
|
2523
|
-
return value;
|
|
2646
|
+
return BigInt(value);
|
|
2524
2647
|
}
|
|
2525
|
-
function
|
|
2526
|
-
|
|
2527
|
-
return requireObject(root[key2], endpoint);
|
|
2648
|
+
function decimal(value, decimals, endpoint) {
|
|
2649
|
+
return (0, import_viem5.formatUnits)(raw(value, endpoint), decimals);
|
|
2528
2650
|
}
|
|
2529
|
-
function
|
|
2530
|
-
return
|
|
2531
|
-
chain: value.chain,
|
|
2532
|
-
chainId: value.chainId,
|
|
2533
|
-
asset: value.asset,
|
|
2534
|
-
amount: String(value.amount)
|
|
2535
|
-
};
|
|
2651
|
+
function usd(rawAmount, decimals, price) {
|
|
2652
|
+
return Number((0, import_viem5.formatUnits)(rawAmount, decimals)) * price;
|
|
2536
2653
|
}
|
|
2537
|
-
function
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
protocol: String(value.protocol),
|
|
2541
|
-
...value.protocolId ? { protocolId: value.protocolId } : {},
|
|
2542
|
-
...value.pool ? { pool: value.pool } : {},
|
|
2543
|
-
asset: String(value.asset),
|
|
2544
|
-
amount: String(value.amount),
|
|
2545
|
-
...value.amountRaw !== void 0 ? { amountRaw: value.amountRaw } : {},
|
|
2546
|
-
...typeof value.apy === "number" ? { apy: value.apy } : {},
|
|
2547
|
-
...typeof value.tvl === "number" ? { tvl: value.tvl } : {},
|
|
2548
|
-
...typeof value.liquidity === "number" ? { liquidity: value.liquidity } : {}
|
|
2549
|
-
};
|
|
2654
|
+
function percent(value) {
|
|
2655
|
+
const result = Number(value);
|
|
2656
|
+
return Number.isFinite(result) ? result * 100 : 0;
|
|
2550
2657
|
}
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
for (const [asset, apy] of Object.entries(assets)) {
|
|
2558
|
-
if ((asset === "USDC" || asset === "WETH") && typeof apy === "number") {
|
|
2559
|
-
mapped[8453][asset] = apy;
|
|
2560
|
-
}
|
|
2561
|
-
}
|
|
2562
|
-
}
|
|
2563
|
-
return mapped;
|
|
2658
|
+
var YIELDSEEKER_POSITIVE_YIELD_FEE_RATE = 0.1;
|
|
2659
|
+
function publicApyAfterYieldseekerFee(value) {
|
|
2660
|
+
const grossPercent = percent(value);
|
|
2661
|
+
if (grossPercent <= 0) return grossPercent;
|
|
2662
|
+
const netPercent = grossPercent * (1 - YIELDSEEKER_POSITIVE_YIELD_FEE_RATE);
|
|
2663
|
+
return Math.round(netPercent * 1e12) / 1e12;
|
|
2564
2664
|
}
|
|
2565
|
-
function
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2665
|
+
function riskAdjustedApyForDays(option, days) {
|
|
2666
|
+
if (days === "7D") return option.riskAdjustedApy7dAverage;
|
|
2667
|
+
if (days === "30D") return option.riskAdjustedApy30dAverage;
|
|
2668
|
+
return (option.riskAdjustedApy7dAverage + option.riskAdjustedApy30dAverage) / 2;
|
|
2669
|
+
}
|
|
2670
|
+
function assetAddressValue(record, address) {
|
|
2671
|
+
const entry = Object.entries(record).find(
|
|
2672
|
+
([key2]) => key2.toLowerCase() === address.toLowerCase()
|
|
2570
2673
|
);
|
|
2571
|
-
|
|
2572
|
-
|
|
2674
|
+
return entry?.[1] ?? "0";
|
|
2675
|
+
}
|
|
2676
|
+
function position(value, asset) {
|
|
2677
|
+
const option = value?.yieldOption;
|
|
2678
|
+
if (!option || typeof option.provider !== "string" || typeof option.name !== "string" || typeof option.address !== "string" || !(0, import_viem5.isAddress)(option.address)) {
|
|
2679
|
+
return invalid("yield positions", "missing vault metadata");
|
|
2573
2680
|
}
|
|
2681
|
+
const decimals = YIELDSEEKER_ASSET_METADATA[asset].decimals;
|
|
2574
2682
|
return {
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2683
|
+
chain: "BASE",
|
|
2684
|
+
protocol: option.provider,
|
|
2685
|
+
protocolId: option.address,
|
|
2686
|
+
pool: option.name,
|
|
2687
|
+
asset,
|
|
2688
|
+
amount: decimal(value.assetsRaw, decimals, "yield positions"),
|
|
2689
|
+
amountRaw: String(value.assetsRaw),
|
|
2690
|
+
apy: percent(option.riskAdjustedApy),
|
|
2691
|
+
tvl: Number(option.totalDepositsUsd),
|
|
2692
|
+
liquidity: Number(option.withdrawableDepositsUsd)
|
|
2580
2693
|
};
|
|
2581
2694
|
}
|
|
2582
|
-
function mapYieldseekerBalances(
|
|
2583
|
-
const
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2695
|
+
function mapYieldseekerBalances(contexts) {
|
|
2696
|
+
const tokens = [];
|
|
2697
|
+
const positions = [];
|
|
2698
|
+
let totalUsd = 0;
|
|
2699
|
+
for (const context of contexts) {
|
|
2700
|
+
const metadata = YIELDSEEKER_ASSET_METADATA[context.asset];
|
|
2701
|
+
const idle = assetAddressValue(
|
|
2702
|
+
context.snapshot.tokenBalances,
|
|
2703
|
+
metadata.address
|
|
2704
|
+
);
|
|
2705
|
+
tokens.push({
|
|
2706
|
+
chain: "BASE",
|
|
2707
|
+
chainId: 8453,
|
|
2708
|
+
asset: context.asset,
|
|
2709
|
+
amount: decimal(idle, metadata.decimals, "snapshot")
|
|
2710
|
+
});
|
|
2711
|
+
positions.push(
|
|
2712
|
+
...context.positions.map((entry) => position(entry, context.asset))
|
|
2713
|
+
);
|
|
2714
|
+
totalUsd += usd(
|
|
2715
|
+
raw(context.snapshot.totalValueBase, "snapshot"),
|
|
2716
|
+
context.snapshot.baseAssetDecimals,
|
|
2717
|
+
context.snapshot.baseAssetPriceUsd
|
|
2718
|
+
);
|
|
2590
2719
|
}
|
|
2591
2720
|
return {
|
|
2592
|
-
smartWallet:
|
|
2593
|
-
totalBalance:
|
|
2594
|
-
totalBalanceAsset:
|
|
2595
|
-
tokens
|
|
2596
|
-
positions
|
|
2721
|
+
...contexts.length === 1 ? { smartWallet: contexts[0].wallet.walletAddress } : {},
|
|
2722
|
+
totalBalance: String(totalUsd),
|
|
2723
|
+
totalBalanceAsset: "usdc",
|
|
2724
|
+
tokens,
|
|
2725
|
+
positions
|
|
2597
2726
|
};
|
|
2598
2727
|
}
|
|
2599
|
-
function mapYieldseekerEarnings(
|
|
2600
|
-
const
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
"
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2728
|
+
function mapYieldseekerEarnings(contexts) {
|
|
2729
|
+
const tokens = [];
|
|
2730
|
+
let lifetimeEarnings = 0;
|
|
2731
|
+
for (const context of contexts) {
|
|
2732
|
+
const amount = raw(context.snapshot.cumulativeYieldBase, "snapshot");
|
|
2733
|
+
tokens.push({
|
|
2734
|
+
chain: "BASE",
|
|
2735
|
+
chainId: 8453,
|
|
2736
|
+
asset: context.asset,
|
|
2737
|
+
amount: (0, import_viem5.formatUnits)(amount, context.snapshot.baseAssetDecimals)
|
|
2738
|
+
});
|
|
2739
|
+
lifetimeEarnings += usd(
|
|
2740
|
+
amount,
|
|
2741
|
+
context.snapshot.baseAssetDecimals,
|
|
2742
|
+
context.snapshot.baseAssetPriceUsd
|
|
2743
|
+
);
|
|
2607
2744
|
}
|
|
2608
2745
|
return {
|
|
2609
|
-
smartWallet:
|
|
2610
|
-
lifetimeEarnings
|
|
2611
|
-
tokens
|
|
2746
|
+
smartWallet: contexts[0]?.wallet.walletAddress ?? "0x0000000000000000000000000000000000000000",
|
|
2747
|
+
lifetimeEarnings,
|
|
2748
|
+
tokens
|
|
2612
2749
|
};
|
|
2613
2750
|
}
|
|
2614
|
-
function
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2751
|
+
function apyForDays(snapshot, days) {
|
|
2752
|
+
if (days === "7D") return percent(snapshot.apy7d);
|
|
2753
|
+
if (days === "30D") return percent(snapshot.apy30d);
|
|
2754
|
+
return percent((snapshot.apy7d + snapshot.apy30d) / 2);
|
|
2755
|
+
}
|
|
2756
|
+
function dailyApy(point) {
|
|
2757
|
+
const total = raw(point.totalValueBase, "historic position");
|
|
2758
|
+
const earned = raw(point.dailyYieldBase, "historic position");
|
|
2759
|
+
const principal = total - earned;
|
|
2760
|
+
if (principal <= 0n || earned === 0n) return 0;
|
|
2761
|
+
return Number(earned) / Number(principal) * 365 * 100;
|
|
2762
|
+
}
|
|
2763
|
+
function aggregateHistory(contexts, dayCount) {
|
|
2764
|
+
const byDate = /* @__PURE__ */ new Map();
|
|
2765
|
+
for (const context of contexts) {
|
|
2766
|
+
const points = context.historic?.dailyYieldSnapshots ?? [];
|
|
2767
|
+
for (const point of points.slice(-dayCount)) {
|
|
2768
|
+
const valueUsd = usd(
|
|
2769
|
+
raw(point.totalValueBase, "historic position"),
|
|
2770
|
+
point.baseAssetDecimals,
|
|
2771
|
+
point.baseAssetPriceUsd
|
|
2772
|
+
);
|
|
2773
|
+
const current = byDate.get(point.date) ?? { weighted: 0, valueUsd: 0 };
|
|
2774
|
+
current.weighted += dailyApy(point) * valueUsd;
|
|
2775
|
+
current.valueUsd += valueUsd;
|
|
2776
|
+
byDate.set(point.date, current);
|
|
2777
|
+
}
|
|
2622
2778
|
}
|
|
2779
|
+
return [...byDate.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([date, value]) => ({
|
|
2780
|
+
date,
|
|
2781
|
+
apy: value.valueUsd > 0 ? value.weighted / value.valueUsd : 0
|
|
2782
|
+
}));
|
|
2783
|
+
}
|
|
2784
|
+
function mapYieldseekerApy(walletAddress, contexts, days) {
|
|
2785
|
+
let weighted = 0;
|
|
2786
|
+
let totalUsd = 0;
|
|
2787
|
+
const byAsset = {};
|
|
2788
|
+
for (const context of contexts) {
|
|
2789
|
+
const valueUsd = usd(
|
|
2790
|
+
raw(context.snapshot.totalValueBase, "snapshot"),
|
|
2791
|
+
context.snapshot.baseAssetDecimals,
|
|
2792
|
+
context.snapshot.baseAssetPriceUsd
|
|
2793
|
+
);
|
|
2794
|
+
const apy = apyForDays(context.snapshot, days);
|
|
2795
|
+
weighted += apy * valueUsd;
|
|
2796
|
+
totalUsd += valueUsd;
|
|
2797
|
+
byAsset[context.asset] = apy;
|
|
2798
|
+
}
|
|
2799
|
+
const dayCount = Number(days.slice(0, -1));
|
|
2623
2800
|
return {
|
|
2624
|
-
walletAddress
|
|
2625
|
-
weightedApyAfterFee:
|
|
2626
|
-
apyByChainAndAsset:
|
|
2627
|
-
history:
|
|
2628
|
-
date: String(point.date),
|
|
2629
|
-
apy: Number(point.apy)
|
|
2630
|
-
}))
|
|
2801
|
+
walletAddress,
|
|
2802
|
+
weightedApyAfterFee: totalUsd > 0 ? weighted / totalUsd : 0,
|
|
2803
|
+
apyByChainAndAsset: { 8453: byAsset },
|
|
2804
|
+
history: aggregateHistory(contexts, dayCount)
|
|
2631
2805
|
};
|
|
2632
2806
|
}
|
|
2633
|
-
function
|
|
2634
|
-
const normalized = value.
|
|
2635
|
-
if (normalized
|
|
2636
|
-
if (normalized
|
|
2637
|
-
if (normalized
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2807
|
+
function actionType(value) {
|
|
2808
|
+
const normalized = value.toLowerCase();
|
|
2809
|
+
if (normalized.includes("deposit")) return "Deposit";
|
|
2810
|
+
if (normalized.includes("withdraw")) return "Withdraw";
|
|
2811
|
+
if (normalized.includes("yield") || normalized.includes("earn"))
|
|
2812
|
+
return "Earned";
|
|
2813
|
+
return "Rebalance";
|
|
2814
|
+
}
|
|
2815
|
+
function transactionHashes(details) {
|
|
2816
|
+
if (!details) return [];
|
|
2817
|
+
const values = [
|
|
2818
|
+
details.transactionHash,
|
|
2819
|
+
details.txHash,
|
|
2820
|
+
...Array.isArray(details.transactionHashes) ? details.transactionHashes : [],
|
|
2821
|
+
...Array.isArray(details.txHashes) ? details.txHashes : []
|
|
2822
|
+
];
|
|
2823
|
+
return values.filter(
|
|
2824
|
+
(value) => typeof value === "string" && /^0x[a-fA-F0-9]{64}$/.test(value)
|
|
2825
|
+
).filter((value, index, all) => all.indexOf(value) === index);
|
|
2642
2826
|
}
|
|
2643
|
-
function
|
|
2827
|
+
function actionEntry(action) {
|
|
2644
2828
|
return {
|
|
2645
2829
|
agent: "yieldseeker",
|
|
2646
|
-
action:
|
|
2647
|
-
date:
|
|
2648
|
-
oldApy:
|
|
2649
|
-
newApy:
|
|
2650
|
-
transactions:
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
rebalanceLog:
|
|
2657
|
-
fromProtocol: String(entry.fromProtocol),
|
|
2658
|
-
toProtocol: String(entry.toProtocol),
|
|
2659
|
-
...entry.fromPool ? { fromPool: entry.fromPool } : {},
|
|
2660
|
-
...entry.toPool ? { toPool: entry.toPool } : {},
|
|
2661
|
-
tokenSymbol: String(entry.tokenSymbol),
|
|
2662
|
-
// Unlike Yieldseeker's other read-response amounts, live history
|
|
2663
|
-
// rebalance amounts are returned in the token's smallest unit. Normalize
|
|
2664
|
-
// them at the adapter boundary so every Owney consumer receives the
|
|
2665
|
-
// shared human-readable decimal shape.
|
|
2666
|
-
amount: rebalanceAmount(String(entry.amount), String(entry.tokenSymbol)),
|
|
2667
|
-
status: entry.status
|
|
2668
|
-
}))
|
|
2830
|
+
action: actionType(action.actionType),
|
|
2831
|
+
date: action.createdDate,
|
|
2832
|
+
oldApy: null,
|
|
2833
|
+
newApy: null,
|
|
2834
|
+
transactions: [
|
|
2835
|
+
{
|
|
2836
|
+
txHashes: transactionHashes(action.details),
|
|
2837
|
+
chainId: 8453
|
|
2838
|
+
}
|
|
2839
|
+
],
|
|
2840
|
+
rebalanceLog: []
|
|
2669
2841
|
};
|
|
2670
2842
|
}
|
|
2671
|
-
function
|
|
2672
|
-
const
|
|
2673
|
-
|
|
2674
|
-
"
|
|
2675
|
-
"
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2843
|
+
function movementEntry(movement, wallet, agent, asset) {
|
|
2844
|
+
const isDeposit = movement.toAddress.toLowerCase() === wallet.walletAddress.toLowerCase();
|
|
2845
|
+
return {
|
|
2846
|
+
agent: "yieldseeker",
|
|
2847
|
+
action: isDeposit ? "Deposit" : "Withdraw",
|
|
2848
|
+
date: movement.blockDate,
|
|
2849
|
+
oldApy: null,
|
|
2850
|
+
newApy: null,
|
|
2851
|
+
transactions: [
|
|
2852
|
+
{
|
|
2853
|
+
txHashes: [movement.transactionHash],
|
|
2854
|
+
chainId: agent.chainId,
|
|
2855
|
+
tokenSymbol: asset,
|
|
2856
|
+
amount: decimal(
|
|
2857
|
+
movement.assetAmount,
|
|
2858
|
+
YIELDSEEKER_ASSET_METADATA[asset].decimals,
|
|
2859
|
+
"historic position"
|
|
2860
|
+
)
|
|
2861
|
+
}
|
|
2862
|
+
],
|
|
2863
|
+
rebalanceLog: []
|
|
2864
|
+
};
|
|
2865
|
+
}
|
|
2866
|
+
function mapYieldseekerHistory(contexts, options) {
|
|
2867
|
+
const entries = contexts.flatMap((context) => [
|
|
2868
|
+
...(context.actions ?? []).map(actionEntry),
|
|
2869
|
+
...(context.historic?.movements ?? []).map(
|
|
2870
|
+
(movement) => movementEntry(movement, context.wallet, context.agent, context.asset)
|
|
2871
|
+
)
|
|
2872
|
+
]);
|
|
2873
|
+
const filtered = entries.filter(
|
|
2874
|
+
(entry) => (!options.fromDate || entry.date >= options.fromDate) && (!options.toDate || entry.date <= options.toDate)
|
|
2875
|
+
).filter(
|
|
2876
|
+
(entry, index, all) => all.findIndex(
|
|
2877
|
+
(candidate) => candidate.action === entry.action && candidate.date === entry.date && candidate.transactions[0]?.txHashes[0] === entry.transactions[0]?.txHashes[0]
|
|
2878
|
+
) === index
|
|
2879
|
+
).sort((left, right) => right.date.localeCompare(left.date));
|
|
2880
|
+
return {
|
|
2881
|
+
data: filtered.slice(0, options.limit),
|
|
2882
|
+
// v1 returns the whole action/movement collection and defines no cursor.
|
|
2883
|
+
// Report a terminal page so callers never loop over the same prefix.
|
|
2884
|
+
hasMore: false
|
|
2885
|
+
};
|
|
2886
|
+
}
|
|
2887
|
+
function mapYieldseekerProfile(address, contexts) {
|
|
2888
|
+
const protocols = /* @__PURE__ */ new Set();
|
|
2889
|
+
for (const context of contexts) {
|
|
2890
|
+
for (const current of context.positions) {
|
|
2891
|
+
if (current.yieldOption?.provider) {
|
|
2892
|
+
protocols.add(String(current.yieldOption.provider));
|
|
2893
|
+
}
|
|
2894
|
+
}
|
|
2679
2895
|
}
|
|
2680
2896
|
return {
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2897
|
+
address,
|
|
2898
|
+
smartWallet: contexts[0]?.wallet.walletAddress ?? "0x0000000000000000000000000000000000000000",
|
|
2899
|
+
chains: contexts.length > 0 ? [8453] : [],
|
|
2900
|
+
hasActiveSessionKey: contexts.some(
|
|
2901
|
+
(context) => context.wallet.initializedDate != null
|
|
2902
|
+
),
|
|
2903
|
+
protocols: [...protocols]
|
|
2684
2904
|
};
|
|
2685
2905
|
}
|
|
2686
|
-
function mapYieldseekerAgentApy(
|
|
2687
|
-
const
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2906
|
+
function mapYieldseekerAgentApy(options, days) {
|
|
2907
|
+
const perAsset = {};
|
|
2908
|
+
const all = [];
|
|
2909
|
+
for (const entry of options) {
|
|
2910
|
+
const apys = entry.yieldOptions.map(
|
|
2911
|
+
(option) => publicApyAfterYieldseekerFee(riskAdjustedApyForDays(option, days))
|
|
2912
|
+
).filter(Number.isFinite);
|
|
2913
|
+
if (apys.length === 0) continue;
|
|
2914
|
+
const average = apys.reduce((sum, value) => sum + value, 0) / apys.length;
|
|
2915
|
+
perAsset[entry.asset] = average;
|
|
2916
|
+
all.push(average);
|
|
2694
2917
|
}
|
|
2695
2918
|
return {
|
|
2696
|
-
averageApy:
|
|
2697
|
-
|
|
2698
|
-
detailedApys: {
|
|
2699
|
-
apyPerAsset: mapApyMatrix(agentApy.detailedApys.apyPerAsset)
|
|
2700
|
-
}
|
|
2701
|
-
} : {}
|
|
2919
|
+
averageApy: all.length > 0 ? all.reduce((sum, value) => sum + value, 0) / all.length : 0,
|
|
2920
|
+
detailedApys: { apyPerAsset: { 8453: perAsset } }
|
|
2702
2921
|
};
|
|
2703
2922
|
}
|
|
2704
2923
|
|
|
2705
2924
|
// src/agents/yieldseeker/yieldseeker.agent.ts
|
|
2925
|
+
var OWNEY_AGENT_NAME = "owney";
|
|
2926
|
+
var YIELDSEEKER_AGENT_WALLET_ABI = [
|
|
2927
|
+
{
|
|
2928
|
+
type: "function",
|
|
2929
|
+
name: "withdrawAssetToUser",
|
|
2930
|
+
stateMutability: "nonpayable",
|
|
2931
|
+
inputs: [
|
|
2932
|
+
{ name: "recipient", type: "address" },
|
|
2933
|
+
{ name: "asset", type: "address" },
|
|
2934
|
+
{ name: "amount", type: "uint256" }
|
|
2935
|
+
],
|
|
2936
|
+
outputs: []
|
|
2937
|
+
},
|
|
2938
|
+
{
|
|
2939
|
+
type: "function",
|
|
2940
|
+
name: "withdrawAllAssetToUser",
|
|
2941
|
+
stateMutability: "nonpayable",
|
|
2942
|
+
inputs: [
|
|
2943
|
+
{ name: "recipient", type: "address" },
|
|
2944
|
+
{ name: "asset", type: "address" }
|
|
2945
|
+
],
|
|
2946
|
+
outputs: []
|
|
2947
|
+
}
|
|
2948
|
+
];
|
|
2706
2949
|
function query(params) {
|
|
2707
2950
|
const search = new URLSearchParams();
|
|
2708
2951
|
for (const [key2, value] of Object.entries(params)) {
|
|
@@ -2720,7 +2963,7 @@ var YieldseekerAgent = class {
|
|
|
2720
2963
|
chainId: 8453,
|
|
2721
2964
|
chain: "BASE",
|
|
2722
2965
|
assets: [
|
|
2723
|
-
{ symbol: "USDC", minDepositAmount: "
|
|
2966
|
+
{ symbol: "USDC", minDepositAmount: "10000000" },
|
|
2724
2967
|
{ symbol: "WETH", minDepositAmount: "1" }
|
|
2725
2968
|
]
|
|
2726
2969
|
}
|
|
@@ -2729,7 +2972,9 @@ var YieldseekerAgent = class {
|
|
|
2729
2972
|
auth;
|
|
2730
2973
|
transactionExecutor;
|
|
2731
2974
|
unwindReceiptWaiter;
|
|
2732
|
-
|
|
2975
|
+
agentContexts = /* @__PURE__ */ new Map();
|
|
2976
|
+
users = /* @__PURE__ */ new Map();
|
|
2977
|
+
pendingAgents = /* @__PURE__ */ new Map();
|
|
2733
2978
|
constructor(owneyApiKey, options = {}) {
|
|
2734
2979
|
this.api = new YieldseekerApiClient(
|
|
2735
2980
|
owneyApiKey,
|
|
@@ -2742,14 +2987,19 @@ var YieldseekerAgent = class {
|
|
|
2742
2987
|
}
|
|
2743
2988
|
async disconnect() {
|
|
2744
2989
|
this.auth.clear();
|
|
2745
|
-
this.
|
|
2990
|
+
for (const key2 of this.users.keys()) {
|
|
2991
|
+
const [walletAddress, chainId] = key2.split(":");
|
|
2992
|
+
clearYieldseekerIdentity(walletAddress, Number(chainId));
|
|
2993
|
+
}
|
|
2994
|
+
this.users.clear();
|
|
2995
|
+
this.agentContexts.clear();
|
|
2996
|
+
this.pendingAgents.clear();
|
|
2746
2997
|
}
|
|
2747
2998
|
async activateAgent(state, chainId, asset) {
|
|
2748
2999
|
this.assertChain(chainId);
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
}
|
|
3000
|
+
const targetAsset = asset ?? "USDC";
|
|
3001
|
+
this.assertAsset(targetAsset);
|
|
3002
|
+
await this.ensureAgent(state, chainId, targetAsset);
|
|
2753
3003
|
}
|
|
2754
3004
|
async deposit(state, chainId, amount, asset, depositCallback) {
|
|
2755
3005
|
this.assertChain(chainId);
|
|
@@ -2762,42 +3012,48 @@ var YieldseekerAgent = class {
|
|
|
2762
3012
|
this.id
|
|
2763
3013
|
);
|
|
2764
3014
|
}
|
|
2765
|
-
await this.
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
3015
|
+
const context = await this.ensureAgent(state, chainId, asset);
|
|
3016
|
+
let txHash;
|
|
3017
|
+
try {
|
|
3018
|
+
if (depositCallback) {
|
|
3019
|
+
provideDepositVerificationContext(depositCallback, {
|
|
3020
|
+
agentId: "yieldseeker",
|
|
3021
|
+
signature: await this.auth.getToken(state, chainId),
|
|
3022
|
+
userId: context.user.userId,
|
|
3023
|
+
yieldseekerAgentId: context.agent.agentId
|
|
3024
|
+
});
|
|
3025
|
+
txHash = await depositCallback(
|
|
3026
|
+
context.wallet.walletAddress,
|
|
3027
|
+
chainId,
|
|
3028
|
+
amount
|
|
3029
|
+
);
|
|
3030
|
+
await this.waitForReceipt(state, chainId, txHash);
|
|
3031
|
+
} else {
|
|
3032
|
+
txHash = await this.submitTransaction(state, chainId, {
|
|
3033
|
+
from: (0, import_viem6.getAddress)(state.walletAddress),
|
|
3034
|
+
to: YIELDSEEKER_ASSET_METADATA[asset].address,
|
|
3035
|
+
data: (0, import_viem6.encodeFunctionData)({
|
|
3036
|
+
abi: import_viem6.erc20Abi,
|
|
3037
|
+
functionName: "transfer",
|
|
3038
|
+
args: [(0, import_viem6.getAddress)(context.wallet.walletAddress), BigInt(amount)]
|
|
3039
|
+
}),
|
|
3040
|
+
value: "0",
|
|
3041
|
+
chainId
|
|
3042
|
+
});
|
|
3043
|
+
}
|
|
3044
|
+
await this.deployAfterFunding(state, chainId, context);
|
|
3045
|
+
} finally {
|
|
3046
|
+
await this.refreshSnapshotAfterMovement(
|
|
3047
|
+
state,
|
|
3048
|
+
chainId,
|
|
3049
|
+
context,
|
|
3050
|
+
"deposit"
|
|
3051
|
+
);
|
|
2796
3052
|
}
|
|
2797
3053
|
return {
|
|
2798
3054
|
txHash,
|
|
2799
|
-
smartWallet:
|
|
2800
|
-
amount
|
|
3055
|
+
smartWallet: context.wallet.walletAddress,
|
|
3056
|
+
amount
|
|
2801
3057
|
};
|
|
2802
3058
|
}
|
|
2803
3059
|
async withdraw(state, chainId, asset, amount) {
|
|
@@ -2811,198 +3067,454 @@ var YieldseekerAgent = class {
|
|
|
2811
3067
|
this.id
|
|
2812
3068
|
);
|
|
2813
3069
|
}
|
|
2814
|
-
const
|
|
2815
|
-
|
|
2816
|
-
const targetAsset = asset.toUpperCase();
|
|
2817
|
-
const idle = balances.tokens.filter(
|
|
2818
|
-
(token2) => token2.chainId === chainId && token2.asset.toUpperCase() === targetAsset
|
|
2819
|
-
).reduce((total, token2) => total + (0, import_viem6.parseUnits)(token2.amount, decimals), 0n);
|
|
2820
|
-
const positions = (balances.positions ?? []).filter(
|
|
2821
|
-
(position2) => this.positionMatchesChain(position2.chain, chainId) && position2.asset.toUpperCase() === targetAsset
|
|
2822
|
-
).map((position2) => ({
|
|
2823
|
-
position: position2,
|
|
2824
|
-
amount: position2.amountRaw !== void 0 ? BigInt(position2.amountRaw) : (0, import_viem6.parseUnits)(position2.amount, decimals)
|
|
2825
|
-
}));
|
|
2826
|
-
const deployed = positions.reduce(
|
|
2827
|
-
(total, position2) => total + position2.amount,
|
|
2828
|
-
0n
|
|
2829
|
-
);
|
|
2830
|
-
const totalAvailable = idle + deployed;
|
|
2831
|
-
const requested = amount === void 0 ? totalAvailable : BigInt(amount);
|
|
2832
|
-
if (requested > totalAvailable) {
|
|
3070
|
+
const context = await this.findAgent(state, chainId, asset);
|
|
3071
|
+
if (!context) {
|
|
2833
3072
|
throw new OwneyError(
|
|
2834
3073
|
"WITHDRAW_INSUFFICIENT_BALANCE",
|
|
2835
|
-
`
|
|
2836
|
-
{
|
|
2837
|
-
asset,
|
|
2838
|
-
requested: requested.toString(),
|
|
2839
|
-
available: totalAvailable.toString()
|
|
2840
|
-
},
|
|
3074
|
+
`No Yieldseeker ${asset} agent exists for this wallet.`,
|
|
3075
|
+
{ asset, available: "0" },
|
|
2841
3076
|
this.id
|
|
2842
3077
|
);
|
|
2843
3078
|
}
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
3079
|
+
try {
|
|
3080
|
+
const portfolio = await this.loadPortfolioContext(
|
|
3081
|
+
state,
|
|
3082
|
+
chainId,
|
|
3083
|
+
context
|
|
3084
|
+
);
|
|
3085
|
+
const metadata = YIELDSEEKER_ASSET_METADATA[asset];
|
|
3086
|
+
const idleEntry = Object.entries(portfolio.snapshot.tokenBalances).find(
|
|
3087
|
+
([address]) => address.toLowerCase() === metadata.address.toLowerCase()
|
|
3088
|
+
);
|
|
3089
|
+
const idle = BigInt(idleEntry?.[1] ?? "0");
|
|
3090
|
+
const deployed = portfolio.positions.reduce(
|
|
3091
|
+
(total, position2) => total + BigInt(position2.withdrawableAssetsRaw),
|
|
3092
|
+
0n
|
|
3093
|
+
);
|
|
3094
|
+
const totalAvailable = idle + deployed;
|
|
3095
|
+
const requested = amount === void 0 ? totalAvailable : BigInt(amount);
|
|
3096
|
+
if (requested > totalAvailable) {
|
|
3097
|
+
throw new OwneyError(
|
|
3098
|
+
"WITHDRAW_INSUFFICIENT_BALANCE",
|
|
3099
|
+
`Requested withdrawal "${requested}" exceeds available Yieldseeker balance "${totalAvailable}" for asset "${asset}".`,
|
|
3100
|
+
{
|
|
3101
|
+
asset,
|
|
3102
|
+
requested: requested.toString(),
|
|
3103
|
+
available: totalAvailable.toString()
|
|
3104
|
+
},
|
|
3105
|
+
this.id
|
|
3106
|
+
);
|
|
3107
|
+
}
|
|
3108
|
+
let remaining = requested > idle ? requested - idle : 0n;
|
|
3109
|
+
for (const position2 of portfolio.positions) {
|
|
3110
|
+
if (remaining === 0n) break;
|
|
3111
|
+
const available = BigInt(position2.withdrawableAssetsRaw);
|
|
3112
|
+
if (available <= 0n) continue;
|
|
3113
|
+
const assetsRaw = available < remaining ? available : remaining;
|
|
3114
|
+
const response = await this.walletRequest(
|
|
3115
|
+
state,
|
|
3116
|
+
chainId,
|
|
3117
|
+
this.agentPath(context, "withdraw-from-position"),
|
|
3118
|
+
{
|
|
3119
|
+
method: "POST",
|
|
3120
|
+
body: {
|
|
3121
|
+
chainId,
|
|
3122
|
+
vaultAddress: position2.yieldOption.address,
|
|
3123
|
+
assetsRaw: assetsRaw.toString()
|
|
3124
|
+
}
|
|
3125
|
+
}
|
|
3126
|
+
);
|
|
3127
|
+
if (!this.isTransactionHash(response?.transactionHash)) {
|
|
3128
|
+
throw this.invalidResponse("position withdrawal");
|
|
3129
|
+
}
|
|
3130
|
+
await this.waitForReceipt(state, chainId, response.transactionHash);
|
|
3131
|
+
remaining -= assetsRaw;
|
|
3132
|
+
}
|
|
3133
|
+
if (remaining > 0n) {
|
|
3134
|
+
throw this.invalidResponse("yield positions", {
|
|
3135
|
+
reason: "Withdrawable positions could not cover the request.",
|
|
3136
|
+
remaining: remaining.toString()
|
|
2855
3137
|
});
|
|
2856
3138
|
}
|
|
2857
|
-
const
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
3139
|
+
const account = (0, import_viem6.getAddress)(state.walletAddress);
|
|
3140
|
+
const txHash = await this.submitTransaction(state, chainId, {
|
|
3141
|
+
from: account,
|
|
3142
|
+
to: (0, import_viem6.getAddress)(context.wallet.walletAddress),
|
|
3143
|
+
data: amount === void 0 ? (0, import_viem6.encodeFunctionData)({
|
|
3144
|
+
abi: YIELDSEEKER_AGENT_WALLET_ABI,
|
|
3145
|
+
functionName: "withdrawAllAssetToUser",
|
|
3146
|
+
args: [account, metadata.address]
|
|
3147
|
+
}) : (0, import_viem6.encodeFunctionData)({
|
|
3148
|
+
abi: YIELDSEEKER_AGENT_WALLET_ABI,
|
|
3149
|
+
functionName: "withdrawAssetToUser",
|
|
3150
|
+
args: [account, metadata.address, requested]
|
|
3151
|
+
}),
|
|
3152
|
+
value: "0",
|
|
3153
|
+
chainId
|
|
2861
3154
|
});
|
|
2862
|
-
|
|
3155
|
+
return {
|
|
3156
|
+
txHash,
|
|
3157
|
+
type: amount === void 0 ? "full" : "partial",
|
|
3158
|
+
amount: requested.toString()
|
|
3159
|
+
};
|
|
3160
|
+
} finally {
|
|
3161
|
+
await this.refreshSnapshotAfterMovement(
|
|
3162
|
+
state,
|
|
3163
|
+
chainId,
|
|
3164
|
+
context,
|
|
3165
|
+
"withdrawal"
|
|
3166
|
+
);
|
|
2863
3167
|
}
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
3168
|
+
}
|
|
3169
|
+
async getBalances(state, chainId) {
|
|
3170
|
+
this.assertChain(chainId);
|
|
3171
|
+
return mapYieldseekerBalances(await this.loadPortfolio(state, chainId, {}));
|
|
3172
|
+
}
|
|
3173
|
+
async getEarnings(state, chainId) {
|
|
3174
|
+
this.assertChain(chainId);
|
|
3175
|
+
return mapYieldseekerEarnings(await this.loadPortfolio(state, chainId, {}));
|
|
3176
|
+
}
|
|
3177
|
+
async getAccountApy(state, chainId, days, tokenSymbol) {
|
|
3178
|
+
this.assertChain(chainId);
|
|
3179
|
+
const asset = tokenSymbol?.toUpperCase();
|
|
3180
|
+
if (asset !== void 0) this.assertAsset(asset);
|
|
3181
|
+
const contexts = await this.loadPortfolio(state, chainId, {
|
|
3182
|
+
...asset ? { asset } : {},
|
|
3183
|
+
historic: true
|
|
3184
|
+
});
|
|
3185
|
+
return mapYieldseekerApy(state.walletAddress, contexts, days);
|
|
3186
|
+
}
|
|
3187
|
+
async getHistory(state, chainId, options) {
|
|
3188
|
+
this.assertChain(chainId);
|
|
3189
|
+
const asset = options?.tokenSymbol?.toUpperCase();
|
|
3190
|
+
if (asset !== void 0) this.assertAsset(asset);
|
|
3191
|
+
const contexts = await this.loadPortfolio(state, chainId, {
|
|
3192
|
+
...asset ? { asset } : {},
|
|
3193
|
+
historic: true,
|
|
3194
|
+
actions: true
|
|
3195
|
+
});
|
|
3196
|
+
return mapYieldseekerHistory(contexts, {
|
|
3197
|
+
limit: options?.limit ?? 10,
|
|
3198
|
+
...options?.fromDate ? { fromDate: options.fromDate } : {},
|
|
3199
|
+
...options?.toDate ? { toDate: options.toDate } : {}
|
|
3200
|
+
});
|
|
3201
|
+
}
|
|
3202
|
+
async getUserProfile(state, chainId) {
|
|
3203
|
+
this.assertChain(chainId);
|
|
3204
|
+
return mapYieldseekerProfile(
|
|
3205
|
+
state.walletAddress,
|
|
3206
|
+
await this.loadPortfolio(state, chainId, {})
|
|
3207
|
+
);
|
|
3208
|
+
}
|
|
3209
|
+
async getAgentApy(days, options) {
|
|
3210
|
+
this.assertOptionalChain(options?.chainId);
|
|
3211
|
+
const requested = options?.tokenSymbol?.toUpperCase();
|
|
3212
|
+
if (requested !== void 0) this.assertAsset(requested);
|
|
3213
|
+
const assets = requested ? [requested] : ["USDC", "WETH"];
|
|
3214
|
+
const values = await Promise.all(
|
|
3215
|
+
assets.map(async (asset) => {
|
|
3216
|
+
const metadata = YIELDSEEKER_ASSET_METADATA[asset];
|
|
3217
|
+
const response = await this.api.request(
|
|
3218
|
+
`/chains/8453/assets/${metadata.address}/yield-options`
|
|
3219
|
+
);
|
|
3220
|
+
if (!Array.isArray(response?.yieldOptions)) {
|
|
3221
|
+
throw this.invalidResponse("yield options");
|
|
3222
|
+
}
|
|
3223
|
+
return { asset, yieldOptions: response.yieldOptions };
|
|
3224
|
+
})
|
|
3225
|
+
);
|
|
3226
|
+
return mapYieldseekerAgentApy(values, days);
|
|
3227
|
+
}
|
|
3228
|
+
userKey(state, chainId) {
|
|
3229
|
+
return `${state.walletAddress.toLowerCase()}:${chainId}`;
|
|
3230
|
+
}
|
|
3231
|
+
contextKey(state, chainId, asset) {
|
|
3232
|
+
return `${this.userKey(state, chainId)}:${asset}`;
|
|
3233
|
+
}
|
|
3234
|
+
async resolveUser(state, chainId) {
|
|
3235
|
+
const key2 = this.userKey(state, chainId);
|
|
3236
|
+
const inMemory = this.users.get(key2);
|
|
3237
|
+
if (inMemory) return inMemory;
|
|
3238
|
+
const persisted = readYieldseekerIdentity(state.walletAddress, chainId);
|
|
3239
|
+
if (persisted) {
|
|
3240
|
+
this.users.set(key2, persisted);
|
|
3241
|
+
return persisted;
|
|
3242
|
+
}
|
|
3243
|
+
const walletAddress = (0, import_viem6.getAddress)(state.walletAddress);
|
|
3244
|
+
let user = null;
|
|
3245
|
+
try {
|
|
3246
|
+
const login = await this.providerRequest(
|
|
3247
|
+
state,
|
|
3248
|
+
chainId,
|
|
3249
|
+
"/users/login-with-wallet",
|
|
3250
|
+
{ method: "POST", body: { walletAddress } }
|
|
3251
|
+
);
|
|
3252
|
+
user = login?.user ?? null;
|
|
3253
|
+
if (!user) {
|
|
3254
|
+
throw this.invalidResponse("wallet login", {
|
|
3255
|
+
reason: "A successful login returned no user."
|
|
3256
|
+
});
|
|
3257
|
+
}
|
|
3258
|
+
} catch (error) {
|
|
3259
|
+
if (!(error instanceof YieldseekerApiError) || error.providerCode !== "NO_USER") {
|
|
3260
|
+
if (error instanceof OwneyError) throw error;
|
|
3261
|
+
throw this.mapApiError(error);
|
|
3262
|
+
}
|
|
3263
|
+
let created;
|
|
3264
|
+
try {
|
|
3265
|
+
created = await this.providerRequest(
|
|
3266
|
+
state,
|
|
3267
|
+
chainId,
|
|
3268
|
+
"/users",
|
|
3269
|
+
{
|
|
3270
|
+
method: "POST",
|
|
3271
|
+
body: {
|
|
3272
|
+
walletAddress,
|
|
3273
|
+
username: `owney-${walletAddress.slice(2).toLowerCase()}`
|
|
3274
|
+
}
|
|
3275
|
+
}
|
|
3276
|
+
);
|
|
3277
|
+
} catch (createError) {
|
|
3278
|
+
throw this.mapApiError(createError);
|
|
3279
|
+
}
|
|
3280
|
+
user = created?.user ?? null;
|
|
3281
|
+
}
|
|
3282
|
+
if (!user || !/^[a-zA-Z0-9_-]{1,128}$/.test(user.userId)) {
|
|
3283
|
+
throw this.invalidResponse("wallet identity");
|
|
3284
|
+
}
|
|
3285
|
+
const resolved = { userId: user.userId };
|
|
3286
|
+
this.users.set(key2, resolved);
|
|
3287
|
+
writeYieldseekerIdentity(state.walletAddress, chainId, resolved.userId);
|
|
3288
|
+
return resolved;
|
|
3289
|
+
}
|
|
3290
|
+
forgetUser(state, chainId) {
|
|
3291
|
+
this.users.delete(this.userKey(state, chainId));
|
|
3292
|
+
clearYieldseekerIdentity(state.walletAddress, chainId);
|
|
3293
|
+
}
|
|
3294
|
+
async ensureAgent(state, chainId, asset) {
|
|
3295
|
+
const key2 = this.contextKey(state, chainId, asset);
|
|
3296
|
+
const cached = this.agentContexts.get(key2);
|
|
3297
|
+
if (cached) return cached;
|
|
3298
|
+
const pending = this.pendingAgents.get(key2);
|
|
3299
|
+
if (pending) return pending;
|
|
3300
|
+
const request = this.resolveAgent(state, chainId, asset, true).then(
|
|
3301
|
+
(context) => {
|
|
3302
|
+
if (!context) throw this.invalidResponse("agent creation");
|
|
3303
|
+
this.agentContexts.set(key2, context);
|
|
3304
|
+
return context;
|
|
3305
|
+
}
|
|
3306
|
+
);
|
|
3307
|
+
this.pendingAgents.set(key2, request);
|
|
3308
|
+
try {
|
|
3309
|
+
return await request;
|
|
3310
|
+
} finally {
|
|
3311
|
+
this.pendingAgents.delete(key2);
|
|
2870
3312
|
}
|
|
2871
|
-
|
|
2872
|
-
|
|
3313
|
+
}
|
|
3314
|
+
async findAgent(state, chainId, asset) {
|
|
3315
|
+
const key2 = this.contextKey(state, chainId, asset);
|
|
3316
|
+
const cached = this.agentContexts.get(key2);
|
|
3317
|
+
if (cached) return cached;
|
|
3318
|
+
const context = await this.resolveAgent(state, chainId, asset, false);
|
|
3319
|
+
if (context) this.agentContexts.set(key2, context);
|
|
3320
|
+
return context;
|
|
3321
|
+
}
|
|
3322
|
+
async resolveAgent(state, chainId, asset, createIfMissing) {
|
|
3323
|
+
const user = await this.resolveUser(state, chainId);
|
|
3324
|
+
const response = await this.walletRequest(
|
|
3325
|
+
state,
|
|
3326
|
+
chainId,
|
|
3327
|
+
`/users/${user.userId}/agents`
|
|
3328
|
+
);
|
|
3329
|
+
if (!Array.isArray(response?.agents)) {
|
|
3330
|
+
throw this.invalidResponse("agent list");
|
|
3331
|
+
}
|
|
3332
|
+
const metadata = YIELDSEEKER_ASSET_METADATA[asset];
|
|
3333
|
+
let agent = response.agents.find(
|
|
3334
|
+
(candidate) => this.isOwneyAgent(candidate) && candidate.chainId === chainId && candidate.type === "vault" && candidate.assetAddress.toLowerCase() === metadata.address.toLowerCase()
|
|
3335
|
+
);
|
|
3336
|
+
if (!agent && createIfMissing) {
|
|
3337
|
+
const created = await this.walletRequest(
|
|
2873
3338
|
state,
|
|
2874
3339
|
chainId,
|
|
2875
|
-
|
|
3340
|
+
`/users/${user.userId}/agents`,
|
|
2876
3341
|
{
|
|
2877
3342
|
method: "POST",
|
|
2878
3343
|
body: {
|
|
3344
|
+
name: OWNEY_AGENT_NAME,
|
|
3345
|
+
emoji: "\u{1F989}",
|
|
2879
3346
|
chainId,
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
3347
|
+
assetAddress: metadata.address,
|
|
3348
|
+
type: "vault",
|
|
3349
|
+
rulePreset: null
|
|
2883
3350
|
}
|
|
2884
3351
|
}
|
|
2885
3352
|
);
|
|
2886
|
-
|
|
2887
|
-
if (!this.isTransactionHash(transactionHash)) {
|
|
2888
|
-
throw this.invalidResponse("position unwind");
|
|
2889
|
-
}
|
|
2890
|
-
await this.waitForUnwindReceipt(state, chainId, transactionHash);
|
|
3353
|
+
agent = created?.agent;
|
|
2891
3354
|
}
|
|
2892
|
-
|
|
3355
|
+
if (!agent) return null;
|
|
3356
|
+
this.assertAgent(agent);
|
|
3357
|
+
const walletResponse = await this.walletRequest(
|
|
2893
3358
|
state,
|
|
2894
3359
|
chainId,
|
|
2895
|
-
|
|
2896
|
-
{
|
|
2897
|
-
method: "POST",
|
|
2898
|
-
body: { chainId, asset, ...amount !== void 0 ? { amount } : {} }
|
|
2899
|
-
}
|
|
3360
|
+
`/users/${user.userId}/agents/${agent.agentId}/wallet`
|
|
2900
3361
|
);
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
throw this.invalidResponse("withdrawal");
|
|
3362
|
+
if (!walletResponse?.agentWallet || !(0, import_viem6.isAddress)(walletResponse.agentWallet.walletAddress)) {
|
|
3363
|
+
throw this.invalidResponse("agent wallet");
|
|
2904
3364
|
}
|
|
2905
|
-
|
|
3365
|
+
return { user, agent, wallet: walletResponse.agentWallet, asset };
|
|
3366
|
+
}
|
|
3367
|
+
async loadPortfolio(state, chainId, options) {
|
|
3368
|
+
const user = await this.resolveUser(state, chainId);
|
|
3369
|
+
const response = await this.walletRequest(
|
|
2906
3370
|
state,
|
|
2907
3371
|
chainId,
|
|
2908
|
-
|
|
3372
|
+
`/users/${user.userId}/agents`
|
|
2909
3373
|
);
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
3374
|
+
if (!Array.isArray(response?.agents)) {
|
|
3375
|
+
throw this.invalidResponse("agent list");
|
|
3376
|
+
}
|
|
3377
|
+
const contexts = [];
|
|
3378
|
+
for (const agent of response.agents) {
|
|
3379
|
+
const asset = this.assetForAgent(agent);
|
|
3380
|
+
if (!this.isOwneyAgent(agent) || !asset || agent.chainId !== chainId || agent.type !== "vault" || options.asset && options.asset !== asset) {
|
|
3381
|
+
continue;
|
|
3382
|
+
}
|
|
3383
|
+
this.assertAgent(agent);
|
|
3384
|
+
const walletResponse = await this.walletRequest(
|
|
2919
3385
|
state,
|
|
2920
3386
|
chainId,
|
|
2921
|
-
`/
|
|
3387
|
+
`/users/${user.userId}/agents/${agent.agentId}/wallet`
|
|
3388
|
+
);
|
|
3389
|
+
if (!walletResponse?.agentWallet || !(0, import_viem6.isAddress)(walletResponse.agentWallet.walletAddress)) {
|
|
3390
|
+
throw this.invalidResponse("agent wallet");
|
|
3391
|
+
}
|
|
3392
|
+
const context = {
|
|
3393
|
+
user,
|
|
3394
|
+
agent,
|
|
3395
|
+
wallet: walletResponse.agentWallet,
|
|
3396
|
+
asset
|
|
3397
|
+
};
|
|
3398
|
+
this.agentContexts.set(this.contextKey(state, chainId, asset), context);
|
|
3399
|
+
contexts.push(context);
|
|
3400
|
+
}
|
|
3401
|
+
return Promise.all(
|
|
3402
|
+
contexts.map(
|
|
3403
|
+
(context) => this.loadPortfolioContext(state, chainId, context, options)
|
|
2922
3404
|
)
|
|
2923
3405
|
);
|
|
2924
3406
|
}
|
|
2925
|
-
async
|
|
2926
|
-
|
|
2927
|
-
|
|
3407
|
+
async loadPortfolioContext(state, chainId, context, options = {}) {
|
|
3408
|
+
const [snapshot, positions, historic, actions] = await Promise.all([
|
|
3409
|
+
this.walletRequest(
|
|
2928
3410
|
state,
|
|
2929
3411
|
chainId,
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
3412
|
+
`${this.agentPath(context, "snapshot")}${query({
|
|
3413
|
+
shouldOnlyUseRecentValue: true,
|
|
3414
|
+
shouldAllowStaleOnError: true
|
|
3415
|
+
})}`
|
|
3416
|
+
),
|
|
3417
|
+
this.walletRequest(
|
|
3418
|
+
state,
|
|
3419
|
+
chainId,
|
|
3420
|
+
this.agentPath(context, "yield-positions")
|
|
3421
|
+
),
|
|
3422
|
+
options.historic ? this.walletRequest(
|
|
3423
|
+
state,
|
|
3424
|
+
chainId,
|
|
3425
|
+
this.agentPath(context, "wallet/historic-position")
|
|
3426
|
+
) : Promise.resolve(void 0),
|
|
3427
|
+
options.actions ? this.walletRequest(
|
|
3428
|
+
state,
|
|
3429
|
+
chainId,
|
|
3430
|
+
this.agentPath(context, "actions")
|
|
3431
|
+
) : Promise.resolve(void 0)
|
|
3432
|
+
]);
|
|
3433
|
+
if (!snapshot?.agentSnapshot) {
|
|
3434
|
+
throw this.invalidResponse("agent snapshot");
|
|
3435
|
+
}
|
|
3436
|
+
if (!Array.isArray(positions?.yieldPositions)) {
|
|
3437
|
+
throw this.invalidResponse("yield positions");
|
|
3438
|
+
}
|
|
3439
|
+
return {
|
|
3440
|
+
...context,
|
|
3441
|
+
snapshot: snapshot.agentSnapshot,
|
|
3442
|
+
positions: positions.yieldPositions,
|
|
3443
|
+
...historic?.position ? { historic: historic.position } : {},
|
|
3444
|
+
...actions?.actions ? { actions: actions.actions } : {}
|
|
3445
|
+
};
|
|
2933
3446
|
}
|
|
2934
|
-
async
|
|
2935
|
-
|
|
2936
|
-
|
|
3447
|
+
async deployAfterFunding(state, chainId, context) {
|
|
3448
|
+
if (context.wallet.initializedDate != null) return;
|
|
3449
|
+
try {
|
|
3450
|
+
const deployed = await this.walletRequest(
|
|
2937
3451
|
state,
|
|
2938
3452
|
chainId,
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
3453
|
+
this.agentPath(context, "deploy"),
|
|
3454
|
+
{ method: "POST", body: {} }
|
|
3455
|
+
);
|
|
3456
|
+
if (deployed?.agentWallet) {
|
|
3457
|
+
context.wallet = deployed.agentWallet;
|
|
3458
|
+
}
|
|
3459
|
+
} catch (error) {
|
|
3460
|
+
console.warn(
|
|
3461
|
+
"[owney-sdk] Yieldseeker deposit is funded but not deployable yet:",
|
|
3462
|
+
error
|
|
3463
|
+
);
|
|
3464
|
+
}
|
|
2942
3465
|
}
|
|
2943
|
-
async
|
|
2944
|
-
|
|
2945
|
-
await this.walletRequest(
|
|
3466
|
+
async refreshSnapshotAfterMovement(state, chainId, context, movement) {
|
|
3467
|
+
try {
|
|
3468
|
+
const response = await this.walletRequest(
|
|
2946
3469
|
state,
|
|
2947
3470
|
chainId,
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
limit: options?.limit ?? 10,
|
|
2951
|
-
cursor: options?.cursor,
|
|
2952
|
-
fromDate: options?.fromDate,
|
|
2953
|
-
toDate: options?.toDate
|
|
3471
|
+
`${this.agentPath(context, "snapshot")}${query({
|
|
3472
|
+
shouldForceRefresh: true
|
|
2954
3473
|
})}`
|
|
2955
|
-
)
|
|
2956
|
-
|
|
3474
|
+
);
|
|
3475
|
+
if (!response?.agentSnapshot) {
|
|
3476
|
+
throw this.invalidResponse("agent snapshot refresh");
|
|
3477
|
+
}
|
|
3478
|
+
} catch (error) {
|
|
3479
|
+
console.warn(
|
|
3480
|
+
`[owney-sdk] Yieldseeker ${movement} snapshot refresh failed:`,
|
|
3481
|
+
error
|
|
3482
|
+
);
|
|
3483
|
+
}
|
|
2957
3484
|
}
|
|
2958
|
-
|
|
2959
|
-
return
|
|
2960
|
-
await this.walletRequest(state, chainId, `/profile${query({ chainId })}`)
|
|
2961
|
-
);
|
|
3485
|
+
agentPath(context, suffix) {
|
|
3486
|
+
return `/users/${context.user.userId}/agents/${context.agent.agentId}/${suffix}`;
|
|
2962
3487
|
}
|
|
2963
|
-
async
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
days,
|
|
2969
|
-
tokenSymbol: options?.tokenSymbol,
|
|
2970
|
-
chainId: options?.chainId
|
|
2971
|
-
})}`
|
|
2972
|
-
)
|
|
2973
|
-
);
|
|
2974
|
-
}
|
|
2975
|
-
async ensureActivated(state, chainId, asset) {
|
|
2976
|
-
const key2 = `${state.walletAddress.toLowerCase()}:${chainId}:${asset}`;
|
|
2977
|
-
if (this.activated.has(key2)) return;
|
|
2978
|
-
const response = await this.walletRequest(
|
|
2979
|
-
state,
|
|
2980
|
-
chainId,
|
|
2981
|
-
"/activation",
|
|
2982
|
-
{ method: "POST", body: { chainId, asset } }
|
|
2983
|
-
);
|
|
2984
|
-
if (typeof response?.activation?.smartWallet !== "string" || typeof response.activation.deployed !== "boolean" || typeof response.activation.hasActiveSessionKey !== "boolean") {
|
|
2985
|
-
throw this.invalidResponse("activation");
|
|
3488
|
+
async walletRequest(state, chainId, path, options = {}) {
|
|
3489
|
+
try {
|
|
3490
|
+
return await this.providerRequest(state, chainId, path, options);
|
|
3491
|
+
} catch (error) {
|
|
3492
|
+
throw this.mapApiError(error);
|
|
2986
3493
|
}
|
|
2987
|
-
this.activated.add(key2);
|
|
2988
3494
|
}
|
|
2989
|
-
async
|
|
3495
|
+
async providerRequest(state, chainId, path, options = {}) {
|
|
2990
3496
|
this.assertChain(chainId);
|
|
3497
|
+
const request = (signature2) => this.api.request(path, {
|
|
3498
|
+
...options,
|
|
3499
|
+
signature: signature2
|
|
3500
|
+
});
|
|
2991
3501
|
let signature = await this.auth.getToken(state, chainId);
|
|
2992
3502
|
try {
|
|
2993
|
-
return await
|
|
3503
|
+
return await request(signature);
|
|
2994
3504
|
} catch (error) {
|
|
2995
3505
|
if (!(error instanceof YieldseekerApiError)) throw error;
|
|
2996
|
-
if (error.
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3506
|
+
if (error.providerCode === "NO_USER") throw error;
|
|
3507
|
+
if (!error.isAuthenticationError) throw error;
|
|
3508
|
+
this.auth.clear(state, chainId);
|
|
3509
|
+
signature = await this.auth.getToken(state, chainId);
|
|
3510
|
+
try {
|
|
3511
|
+
return await request(signature);
|
|
3512
|
+
} catch (retryError) {
|
|
3513
|
+
if (retryError instanceof YieldseekerApiError && retryError.isAuthenticationError) {
|
|
3514
|
+
this.forgetUser(state, chainId);
|
|
3003
3515
|
}
|
|
3516
|
+
throw retryError;
|
|
3004
3517
|
}
|
|
3005
|
-
throw this.mapApiError(error);
|
|
3006
3518
|
}
|
|
3007
3519
|
}
|
|
3008
3520
|
mapApiError(error) {
|
|
@@ -3030,15 +3542,8 @@ var YieldseekerAgent = class {
|
|
|
3030
3542
|
if (this.transactionExecutor) {
|
|
3031
3543
|
return this.transactionExecutor(state, chainId, transaction);
|
|
3032
3544
|
}
|
|
3033
|
-
|
|
3034
|
-
throw this.invalidResponse("transaction");
|
|
3035
|
-
}
|
|
3545
|
+
this.assertTransaction(transaction, state, chainId);
|
|
3036
3546
|
const account = (0, import_viem6.getAddress)(state.walletAddress);
|
|
3037
|
-
if ((0, import_viem6.getAddress)(transaction.from) !== account) {
|
|
3038
|
-
throw this.invalidResponse("transaction", {
|
|
3039
|
-
reason: "transaction.from does not match the connected wallet"
|
|
3040
|
-
});
|
|
3041
|
-
}
|
|
3042
3547
|
const walletClient = (0, import_viem6.createWalletClient)({
|
|
3043
3548
|
account,
|
|
3044
3549
|
chain: import_chains3.base,
|
|
@@ -3074,7 +3579,7 @@ var YieldseekerAgent = class {
|
|
|
3074
3579
|
}
|
|
3075
3580
|
return hash;
|
|
3076
3581
|
}
|
|
3077
|
-
async
|
|
3582
|
+
async waitForReceipt(state, chainId, transactionHash) {
|
|
3078
3583
|
if (this.unwindReceiptWaiter) {
|
|
3079
3584
|
await this.unwindReceiptWaiter(state, chainId, transactionHash);
|
|
3080
3585
|
return;
|
|
@@ -3090,15 +3595,32 @@ var YieldseekerAgent = class {
|
|
|
3090
3595
|
if (receipt.status !== "success") {
|
|
3091
3596
|
throw new OwneyError(
|
|
3092
3597
|
"AGENT_TRANSACTION_REVERTED",
|
|
3093
|
-
`Yieldseeker
|
|
3598
|
+
`Yieldseeker transaction reverted (${transactionHash}).`,
|
|
3094
3599
|
{ transactionHash },
|
|
3095
3600
|
this.id
|
|
3096
3601
|
);
|
|
3097
3602
|
}
|
|
3098
3603
|
}
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3604
|
+
assertTransaction(transaction, state, chainId) {
|
|
3605
|
+
if (!transaction || typeof transaction.from !== "string" || !(0, import_viem6.isAddress)(transaction.from) || typeof transaction.to !== "string" || !(0, import_viem6.isAddress)(transaction.to) || typeof transaction.data !== "string" || !/^0x[a-fA-F0-9]*$/.test(transaction.data) || typeof transaction.value !== "string" || !/^[0-9]+$/.test(transaction.value) || transaction.chainId !== chainId || (0, import_viem6.getAddress)(transaction.from) !== (0, import_viem6.getAddress)(state.walletAddress)) {
|
|
3606
|
+
throw this.invalidResponse("transaction");
|
|
3607
|
+
}
|
|
3608
|
+
}
|
|
3609
|
+
assertAgent(agent) {
|
|
3610
|
+
if (typeof agent.agentId !== "string" || typeof agent.assetAddress !== "string" || !(0, import_viem6.isAddress)(agent.assetAddress) || agent.chainId !== 8453) {
|
|
3611
|
+
throw this.invalidResponse("agent");
|
|
3612
|
+
}
|
|
3613
|
+
}
|
|
3614
|
+
isOwneyAgent(agent) {
|
|
3615
|
+
return typeof agent.name === "string" && agent.name.trim().toLowerCase() === OWNEY_AGENT_NAME;
|
|
3616
|
+
}
|
|
3617
|
+
assetForAgent(agent) {
|
|
3618
|
+
for (const asset of ["USDC", "WETH"]) {
|
|
3619
|
+
if (agent.assetAddress.toLowerCase() === YIELDSEEKER_ASSET_METADATA[asset].address.toLowerCase()) {
|
|
3620
|
+
return asset;
|
|
3621
|
+
}
|
|
3622
|
+
}
|
|
3623
|
+
return null;
|
|
3102
3624
|
}
|
|
3103
3625
|
isTransactionHash(value) {
|
|
3104
3626
|
return typeof value === "string" && /^0x[a-fA-F0-9]{64}$/.test(value);
|
|
@@ -3120,8 +3642,12 @@ var YieldseekerAgent = class {
|
|
|
3120
3642
|
if (asset !== "USDC" && asset !== "WETH") {
|
|
3121
3643
|
throw new OwneyError(
|
|
3122
3644
|
"ASSET_UNSUPPORTED",
|
|
3123
|
-
`Yieldseeker does not support asset ${asset}.`,
|
|
3124
|
-
{
|
|
3645
|
+
`Yieldseeker does not support asset ${asset} in the Owney rollout.`,
|
|
3646
|
+
{
|
|
3647
|
+
asset,
|
|
3648
|
+
supportedAssets: ["USDC", "WETH"],
|
|
3649
|
+
providerAlsoAdvertises: ["cbBTC"]
|
|
3650
|
+
},
|
|
3125
3651
|
this.id
|
|
3126
3652
|
);
|
|
3127
3653
|
}
|
|
@@ -3343,11 +3869,11 @@ function balanceForApyScope(balance, chainId, tokenSymbol) {
|
|
|
3343
3869
|
return Number.isFinite(total) && total > 0 ? total : 0;
|
|
3344
3870
|
}
|
|
3345
3871
|
const normalizedToken = tokenSymbol.toUpperCase();
|
|
3346
|
-
return balance.tokens.reduce((total,
|
|
3347
|
-
if (Number(
|
|
3872
|
+
return balance.tokens.reduce((total, token) => {
|
|
3873
|
+
if (Number(token.chainId) !== chainId || String(token.asset).toUpperCase() !== normalizedToken) {
|
|
3348
3874
|
return total;
|
|
3349
3875
|
}
|
|
3350
|
-
const amount = Number(
|
|
3876
|
+
const amount = Number(token.amount);
|
|
3351
3877
|
return Number.isFinite(amount) && amount > 0 ? total + amount : total;
|
|
3352
3878
|
}, 0);
|
|
3353
3879
|
}
|
|
@@ -3417,8 +3943,8 @@ function makeSponsoredWethCallback(deps) {
|
|
|
3417
3943
|
return makeVerificationAwareDepositCallback(
|
|
3418
3944
|
async (smartWallet, chainId, amount, verification) => {
|
|
3419
3945
|
const cid = chainId;
|
|
3420
|
-
const
|
|
3421
|
-
if (!
|
|
3946
|
+
const token = deps.tokenAddressByChain[cid];
|
|
3947
|
+
if (!token) {
|
|
3422
3948
|
throw new OwneyError(
|
|
3423
3949
|
"CHAIN_UNSUPPORTED",
|
|
3424
3950
|
`No sponsored WETH configured for chain ${chainId}`
|
|
@@ -3429,12 +3955,12 @@ function makeSponsoredWethCallback(deps) {
|
|
|
3429
3955
|
const wallet = deps.getWalletClient(cid);
|
|
3430
3956
|
await ensureWalletOnChain(pub, wallet, cid);
|
|
3431
3957
|
try {
|
|
3432
|
-
const balance = await readErc20Balance(pub,
|
|
3958
|
+
const balance = await readErc20Balance(pub, token, deps.ownerAddress);
|
|
3433
3959
|
if (balance < amountWei) {
|
|
3434
3960
|
throw new OwneyError(
|
|
3435
3961
|
"DEPOSIT_INSUFFICIENT_BALANCE",
|
|
3436
3962
|
"Insufficient WETH balance for this deposit.",
|
|
3437
|
-
{ token
|
|
3963
|
+
{ token, chainId: cid, balance: balance.toString(), amount }
|
|
3438
3964
|
);
|
|
3439
3965
|
}
|
|
3440
3966
|
} catch (err) {
|
|
@@ -3446,14 +3972,14 @@ function makeSponsoredWethCallback(deps) {
|
|
|
3446
3972
|
}
|
|
3447
3973
|
const allowance = await readPermit2Allowance(
|
|
3448
3974
|
pub,
|
|
3449
|
-
|
|
3975
|
+
token,
|
|
3450
3976
|
deps.ownerAddress
|
|
3451
3977
|
);
|
|
3452
3978
|
if (allowance < amountWei) {
|
|
3453
3979
|
throw new OwneyError(
|
|
3454
3980
|
"PERMIT2_APPROVAL_REQUIRED",
|
|
3455
3981
|
"WETH gasless deposits need a one-time Permit2 approval; call approvePermit2() first",
|
|
3456
|
-
{ token
|
|
3982
|
+
{ token, chainId: cid, allowance: allowance.toString(), amount }
|
|
3457
3983
|
);
|
|
3458
3984
|
}
|
|
3459
3985
|
const relayer = await get({
|
|
@@ -3468,7 +3994,7 @@ function makeSponsoredWethCallback(deps) {
|
|
|
3468
3994
|
const typedData = buildPermitTransferFromTypedData({
|
|
3469
3995
|
chainId: cid,
|
|
3470
3996
|
message: {
|
|
3471
|
-
permitted: { token
|
|
3997
|
+
permitted: { token, amount: amountWei },
|
|
3472
3998
|
spender: relayer,
|
|
3473
3999
|
nonce,
|
|
3474
4000
|
deadline
|
|
@@ -3485,13 +4011,17 @@ function makeSponsoredWethCallback(deps) {
|
|
|
3485
4011
|
...verification?.agentId === "yieldseeker" ? { yieldseekerSignature: verification.signature } : {},
|
|
3486
4012
|
body: {
|
|
3487
4013
|
chainId: cid,
|
|
3488
|
-
token
|
|
4014
|
+
token,
|
|
3489
4015
|
from: deps.ownerAddress,
|
|
3490
4016
|
to: smartWallet,
|
|
3491
4017
|
amount,
|
|
3492
4018
|
nonce: nonce.toString(),
|
|
3493
4019
|
deadline: deadline.toString(),
|
|
3494
|
-
signature
|
|
4020
|
+
signature,
|
|
4021
|
+
...verification?.agentId === "yieldseeker" ? {
|
|
4022
|
+
yieldseekerUserId: verification.userId,
|
|
4023
|
+
yieldseekerAgentId: verification.yieldseekerAgentId
|
|
4024
|
+
} : {}
|
|
3495
4025
|
}
|
|
3496
4026
|
});
|
|
3497
4027
|
return result.txHash;
|
|
@@ -3526,10 +4056,10 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
3526
4056
|
}
|
|
3527
4057
|
return new URL(configured, origin).toString();
|
|
3528
4058
|
};
|
|
3529
|
-
return async (smartWallet, chainId, amount) => {
|
|
4059
|
+
return makeVerificationAwareDepositCallback(async (smartWallet, chainId, amount, verification) => {
|
|
3530
4060
|
const cid = chainId;
|
|
3531
|
-
const
|
|
3532
|
-
if (!
|
|
4061
|
+
const token = deps.tokenAddressByChain[cid];
|
|
4062
|
+
if (!token) {
|
|
3533
4063
|
throw new OwneyError(
|
|
3534
4064
|
"CHAIN_UNSUPPORTED",
|
|
3535
4065
|
`No sponsored token configured for chain ${chainId}`
|
|
@@ -3547,6 +4077,32 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
3547
4077
|
functionName: "transfer",
|
|
3548
4078
|
args: [smartWallet, BigInt(amount)]
|
|
3549
4079
|
});
|
|
4080
|
+
let paymasterUrl = absolutePaymasterUrl();
|
|
4081
|
+
if (verification?.agentId === "yieldseeker") {
|
|
4082
|
+
if (chainId !== 8453) {
|
|
4083
|
+
throw new OwneyError(
|
|
4084
|
+
"CHAIN_UNSUPPORTED",
|
|
4085
|
+
`Yieldseeker Base Account sponsorship is not available on chain ${chainId}.`
|
|
4086
|
+
);
|
|
4087
|
+
}
|
|
4088
|
+
const { intent } = await postPaymasterIntent({
|
|
4089
|
+
baseUrl: deps.routingApiBaseUrl,
|
|
4090
|
+
apiKey: deps.apiKey,
|
|
4091
|
+
yieldseekerSignature: verification.signature,
|
|
4092
|
+
body: {
|
|
4093
|
+
chainId,
|
|
4094
|
+
token,
|
|
4095
|
+
from: deps.ownerAddress,
|
|
4096
|
+
to: smartWallet,
|
|
4097
|
+
amount,
|
|
4098
|
+
yieldseekerUserId: verification.userId,
|
|
4099
|
+
yieldseekerAgentId: verification.yieldseekerAgentId
|
|
4100
|
+
}
|
|
4101
|
+
});
|
|
4102
|
+
const url = new URL(paymasterUrl);
|
|
4103
|
+
url.searchParams.set("owneyIntent", intent);
|
|
4104
|
+
paymasterUrl = url.toString();
|
|
4105
|
+
}
|
|
3550
4106
|
const sendResult = await deps.provider.request({
|
|
3551
4107
|
method: "wallet_sendCalls",
|
|
3552
4108
|
params: [
|
|
@@ -3555,9 +4111,9 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
3555
4111
|
from: deps.ownerAddress,
|
|
3556
4112
|
chainId: (0, import_viem8.toHex)(chainId),
|
|
3557
4113
|
atomicRequired: false,
|
|
3558
|
-
calls: [{ to:
|
|
4114
|
+
calls: [{ to: token, value: "0x0", data }],
|
|
3559
4115
|
capabilities: {
|
|
3560
|
-
paymasterService: { url:
|
|
4116
|
+
paymasterService: { url: paymasterUrl }
|
|
3561
4117
|
}
|
|
3562
4118
|
}
|
|
3563
4119
|
]
|
|
@@ -3587,17 +4143,17 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
3587
4143
|
`No receipt for calls ${callsId} after ${maxPolls} polls; the deposit may still settle.`,
|
|
3588
4144
|
{ chainId, callsId }
|
|
3589
4145
|
);
|
|
3590
|
-
};
|
|
4146
|
+
});
|
|
3591
4147
|
}
|
|
3592
4148
|
|
|
3593
4149
|
// src/client.ts
|
|
3594
4150
|
function encodeMultiAgentCursor(map) {
|
|
3595
4151
|
return Buffer.from(JSON.stringify(map), "utf8").toString("base64");
|
|
3596
4152
|
}
|
|
3597
|
-
function decodeMultiAgentCursor(
|
|
4153
|
+
function decodeMultiAgentCursor(token) {
|
|
3598
4154
|
let parsed;
|
|
3599
4155
|
try {
|
|
3600
|
-
const json = Buffer.from(
|
|
4156
|
+
const json = Buffer.from(token, "base64").toString("utf8");
|
|
3601
4157
|
parsed = JSON.parse(json);
|
|
3602
4158
|
} catch {
|
|
3603
4159
|
throw new InvalidHistoryCursorError(
|
|
@@ -3786,6 +4342,8 @@ var OwneySDK = class {
|
|
|
3786
4342
|
if (!onApproved && cached) return cached;
|
|
3787
4343
|
const provider = this.requireConnectedProvider();
|
|
3788
4344
|
const callback = makeSponsoredCallsCallback({
|
|
4345
|
+
apiKey: this.apiKey,
|
|
4346
|
+
routingApiBaseUrl: this.routingApiBaseUrl,
|
|
3789
4347
|
provider,
|
|
3790
4348
|
ownerAddress: this.state.walletAddress,
|
|
3791
4349
|
paymasterServiceUrl: this.paymasterServiceUrl,
|
|
@@ -4228,15 +4786,15 @@ var OwneySDK = class {
|
|
|
4228
4786
|
agent,
|
|
4229
4787
|
amount: i === agents.length - 1 ? perAgent + remainder : perAgent
|
|
4230
4788
|
}));
|
|
4231
|
-
const
|
|
4789
|
+
const valid2 = splits.filter(
|
|
4232
4790
|
(s) => exempt.has(s.agent.id) || s.amount >= this.getMinDepositAmount(s.agent, chainId, asset)
|
|
4233
4791
|
);
|
|
4234
|
-
if (
|
|
4792
|
+
if (valid2.length === agents.length) {
|
|
4235
4793
|
return splits.map((s) => ({ agent: s.agent, amount: String(s.amount) }));
|
|
4236
4794
|
}
|
|
4237
4795
|
return this.splitDepositAmount(
|
|
4238
4796
|
totalAmount,
|
|
4239
|
-
|
|
4797
|
+
valid2.map((s) => s.agent),
|
|
4240
4798
|
chainId,
|
|
4241
4799
|
asset,
|
|
4242
4800
|
exempt
|
|
@@ -4269,10 +4827,10 @@ var OwneySDK = class {
|
|
|
4269
4827
|
try {
|
|
4270
4828
|
const balance = await agent.getBalances(state, chainId);
|
|
4271
4829
|
const target = asset.toLowerCase();
|
|
4272
|
-
const
|
|
4830
|
+
const token = balance.tokens.find(
|
|
4273
4831
|
(t) => t.chainId === chainId && t.asset.toLowerCase() === target
|
|
4274
4832
|
);
|
|
4275
|
-
return !!
|
|
4833
|
+
return !!token && Number(token.amount) > 0;
|
|
4276
4834
|
} catch {
|
|
4277
4835
|
return false;
|
|
4278
4836
|
}
|
|
@@ -4323,9 +4881,9 @@ var OwneySDK = class {
|
|
|
4323
4881
|
const { asset, amount, agentId } = options;
|
|
4324
4882
|
const state = this.requireState();
|
|
4325
4883
|
const chainId = this.requireChainId();
|
|
4326
|
-
const
|
|
4884
|
+
const token = asset;
|
|
4327
4885
|
const assetInfo = SupportedAssets.find(
|
|
4328
|
-
(a) => a.chainId === chainId && a.symbol ===
|
|
4886
|
+
(a) => a.chainId === chainId && a.symbol === token
|
|
4329
4887
|
);
|
|
4330
4888
|
if (!assetInfo) {
|
|
4331
4889
|
throw new OwneyError(
|
|
@@ -4339,7 +4897,7 @@ var OwneySDK = class {
|
|
|
4339
4897
|
return withFailureReporting(
|
|
4340
4898
|
this.apiKey,
|
|
4341
4899
|
agent.id,
|
|
4342
|
-
() => agent.withdraw(state, chainId,
|
|
4900
|
+
() => agent.withdraw(state, chainId, token, amount),
|
|
4343
4901
|
this.routingApiBaseUrl
|
|
4344
4902
|
);
|
|
4345
4903
|
}
|
|
@@ -4349,7 +4907,7 @@ var OwneySDK = class {
|
|
|
4349
4907
|
const agentErrors2 = {};
|
|
4350
4908
|
for (const agent of eligibleAgents) {
|
|
4351
4909
|
try {
|
|
4352
|
-
results2[agent.id] = await agent.withdraw(state, chainId,
|
|
4910
|
+
results2[agent.id] = await agent.withdraw(state, chainId, token);
|
|
4353
4911
|
} catch (err) {
|
|
4354
4912
|
console.error(`withdraw failed for agent "${agent.id}":`, err);
|
|
4355
4913
|
agentErrors2[agent.id] = err instanceof Error ? err.message : String(err);
|
|
@@ -4439,7 +4997,7 @@ var OwneySDK = class {
|
|
|
4439
4997
|
results[p.agent.id] = await p.agent.withdraw(
|
|
4440
4998
|
state,
|
|
4441
4999
|
chainId,
|
|
4442
|
-
|
|
5000
|
+
token,
|
|
4443
5001
|
p.planned.toString()
|
|
4444
5002
|
);
|
|
4445
5003
|
} catch (err) {
|
|
@@ -4790,8 +5348,8 @@ var OwneySDK = class {
|
|
|
4790
5348
|
const state = this.requireState();
|
|
4791
5349
|
const chainId = this.requireChainId();
|
|
4792
5350
|
this.validateAssetSupport(this.getAgent("zyfai"), chainId, "WETH");
|
|
4793
|
-
const
|
|
4794
|
-
if (!
|
|
5351
|
+
const token = SPONSORED_WETH_BY_CHAIN[chainId];
|
|
5352
|
+
if (!token) {
|
|
4795
5353
|
throw new OwneyError(
|
|
4796
5354
|
"CHAIN_UNSUPPORTED",
|
|
4797
5355
|
`No sponsored WETH on chain ${chainId}`
|
|
@@ -4804,7 +5362,7 @@ var OwneySDK = class {
|
|
|
4804
5362
|
transport: (0, import_viem9.custom)(provider)
|
|
4805
5363
|
});
|
|
4806
5364
|
const hash = await wallet.writeContract({
|
|
4807
|
-
address:
|
|
5365
|
+
address: token,
|
|
4808
5366
|
abi: ERC20_ALLOWANCE_ABI,
|
|
4809
5367
|
functionName: "approve",
|
|
4810
5368
|
args: [PERMIT2_ADDRESS, MAX_UINT256],
|
|
@@ -4929,8 +5487,8 @@ var import_siwe2 = require("siwe");
|
|
|
4929
5487
|
var import_sdk2 = require("@zyfai/sdk");
|
|
4930
5488
|
|
|
4931
5489
|
// src/agents/zyfai/zyfai.siwx-cache.ts
|
|
4932
|
-
var
|
|
4933
|
-
var
|
|
5490
|
+
var KEY_PREFIX4 = "owney.siwx.session";
|
|
5491
|
+
var storage4 = () => {
|
|
4934
5492
|
if (typeof window === "undefined") return null;
|
|
4935
5493
|
try {
|
|
4936
5494
|
return window.localStorage;
|
|
@@ -4938,8 +5496,8 @@ var storage3 = () => {
|
|
|
4938
5496
|
return null;
|
|
4939
5497
|
}
|
|
4940
5498
|
};
|
|
4941
|
-
var buildKey3 = (address) => `${
|
|
4942
|
-
var legacyKeyPrefix2 = (address) => `${
|
|
5499
|
+
var buildKey3 = (address) => `${KEY_PREFIX4}:${address.toLowerCase()}`;
|
|
5500
|
+
var legacyKeyPrefix2 = (address) => `${KEY_PREFIX4}:${address.toLowerCase()}:`;
|
|
4943
5501
|
var memorySiwxSessions = /* @__PURE__ */ new Map();
|
|
4944
5502
|
var readLegacySiwxSession = (store, address) => {
|
|
4945
5503
|
if (!store) return null;
|
|
@@ -4971,16 +5529,16 @@ var readLegacySiwxSession = (store, address) => {
|
|
|
4971
5529
|
var readSiwxSession = (address, chainId) => {
|
|
4972
5530
|
if (typeof window === "undefined") return null;
|
|
4973
5531
|
const key2 = buildKey3(address);
|
|
4974
|
-
const store =
|
|
4975
|
-
let
|
|
5532
|
+
const store = storage4();
|
|
5533
|
+
let raw2 = null;
|
|
4976
5534
|
try {
|
|
4977
|
-
|
|
5535
|
+
raw2 = store?.getItem(key2) ?? null;
|
|
4978
5536
|
} catch {
|
|
4979
|
-
|
|
5537
|
+
raw2 = null;
|
|
4980
5538
|
}
|
|
4981
|
-
if (
|
|
5539
|
+
if (raw2) {
|
|
4982
5540
|
try {
|
|
4983
|
-
return JSON.parse(
|
|
5541
|
+
return JSON.parse(raw2);
|
|
4984
5542
|
} catch {
|
|
4985
5543
|
memorySiwxSessions.delete(key2);
|
|
4986
5544
|
try {
|
|
@@ -5001,7 +5559,7 @@ var writeSiwxSession = (address, _chainId, session) => {
|
|
|
5001
5559
|
if (typeof window === "undefined") return;
|
|
5002
5560
|
const key2 = buildKey3(address);
|
|
5003
5561
|
memorySiwxSessions.set(key2, session);
|
|
5004
|
-
const store =
|
|
5562
|
+
const store = storage4();
|
|
5005
5563
|
try {
|
|
5006
5564
|
store?.setItem(key2, JSON.stringify(session));
|
|
5007
5565
|
} catch {
|
|
@@ -5010,7 +5568,7 @@ var writeSiwxSession = (address, _chainId, session) => {
|
|
|
5010
5568
|
var clearSiwxSession = (address, _chainId) => {
|
|
5011
5569
|
const key2 = buildKey3(address);
|
|
5012
5570
|
memorySiwxSessions.delete(key2);
|
|
5013
|
-
const store =
|
|
5571
|
+
const store = storage4();
|
|
5014
5572
|
try {
|
|
5015
5573
|
store?.removeItem(key2);
|
|
5016
5574
|
} catch {
|