@owney/sdk 0.7.17-beta.3 → 0.7.18
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/README.md +0 -2
- package/dist/index.cjs +581 -2298
- package/dist/index.d.cts +11 -133
- package/dist/index.d.ts +11 -133
- package/dist/index.js +577 -2306
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -26,7 +26,6 @@ __export(index_exports, {
|
|
|
26
26
|
NotConnectedError: () => NotConnectedError,
|
|
27
27
|
OwneyError: () => OwneyError,
|
|
28
28
|
OwneySDK: () => OwneySDK,
|
|
29
|
-
YieldseekerAgent: () => YieldseekerAgent,
|
|
30
29
|
createOwneySIWX: () => createOwneySIWX,
|
|
31
30
|
setOwneyDebug: () => setOwneyDebug
|
|
32
31
|
});
|
|
@@ -311,18 +310,18 @@ function tokenDecimals(symbol, explicit) {
|
|
|
311
310
|
return explicit;
|
|
312
311
|
return DECIMALS_BY_SYMBOL[(symbol ?? "").toLowerCase()] ?? 6;
|
|
313
312
|
}
|
|
314
|
-
function mapDeposit(
|
|
313
|
+
function mapDeposit(raw) {
|
|
315
314
|
return {
|
|
316
|
-
txHash:
|
|
317
|
-
smartWallet:
|
|
318
|
-
amount:
|
|
315
|
+
txHash: raw.txHash,
|
|
316
|
+
smartWallet: raw.smartWallet,
|
|
317
|
+
amount: raw.amount
|
|
319
318
|
};
|
|
320
319
|
}
|
|
321
|
-
function mapWithdraw(
|
|
320
|
+
function mapWithdraw(raw) {
|
|
322
321
|
return {
|
|
323
|
-
txHash:
|
|
324
|
-
type:
|
|
325
|
-
amount:
|
|
322
|
+
txHash: raw.txHash,
|
|
323
|
+
type: raw.type,
|
|
324
|
+
amount: raw.amount
|
|
326
325
|
};
|
|
327
326
|
}
|
|
328
327
|
var CHAIN_ID_TO_NAME = {
|
|
@@ -341,10 +340,10 @@ function resolveChainId(chain) {
|
|
|
341
340
|
if (Number.isFinite(asNum) && asNum > 0) return asNum;
|
|
342
341
|
return NAME_TO_CHAIN_ID[chain.trim().toLowerCase()] ?? NaN;
|
|
343
342
|
}
|
|
344
|
-
function mapPendingAllocations(
|
|
345
|
-
if (!Array.isArray(
|
|
343
|
+
function mapPendingAllocations(raw) {
|
|
344
|
+
if (!Array.isArray(raw)) return void 0;
|
|
346
345
|
const pending = [];
|
|
347
|
-
for (const entry of
|
|
346
|
+
for (const entry of raw) {
|
|
348
347
|
if (typeof entry !== "object" || entry === null) continue;
|
|
349
348
|
const e = entry;
|
|
350
349
|
if (typeof e.chainId !== "number" || !Number.isFinite(e.chainId)) continue;
|
|
@@ -367,8 +366,8 @@ function mapPendingAllocations(raw2) {
|
|
|
367
366
|
}
|
|
368
367
|
return pending.length > 0 ? pending : void 0;
|
|
369
368
|
}
|
|
370
|
-
function mapBalances(
|
|
371
|
-
const portfolio =
|
|
369
|
+
function mapBalances(raw, _chainId, smartWallet) {
|
|
370
|
+
const portfolio = raw.portfolio;
|
|
372
371
|
const portfolioByChain = portfolio.portfolioByChain ?? {};
|
|
373
372
|
let totalBalance = 0;
|
|
374
373
|
const tokens = [];
|
|
@@ -437,8 +436,8 @@ function sumTokenValues(tokens) {
|
|
|
437
436
|
function sumTokenEarnings(tokens) {
|
|
438
437
|
return Object.values(tokens).reduce((sum, val) => sum + Number(val), 0);
|
|
439
438
|
}
|
|
440
|
-
function mapEarnings(
|
|
441
|
-
const totalEarningsByChain =
|
|
439
|
+
function mapEarnings(raw, smartWallet) {
|
|
440
|
+
const totalEarningsByChain = raw.data.totalEarningsByChainWithFee ?? raw.data.totalEarningsByChain ?? {};
|
|
442
441
|
const tokens = [];
|
|
443
442
|
for (const [chainIdKey, tokensBySymbol] of Object.entries(
|
|
444
443
|
totalEarningsByChain
|
|
@@ -457,15 +456,15 @@ function mapEarnings(raw2, smartWallet) {
|
|
|
457
456
|
return {
|
|
458
457
|
smartWallet,
|
|
459
458
|
lifetimeEarnings: sumTokenEarnings(
|
|
460
|
-
|
|
459
|
+
raw.data.totalEarningsByTokenWithFee ?? raw.data.totalEarningsByToken
|
|
461
460
|
),
|
|
462
461
|
tokens
|
|
463
462
|
};
|
|
464
463
|
}
|
|
465
|
-
function mapWeightedApyByChain(
|
|
466
|
-
if (!
|
|
464
|
+
function mapWeightedApyByChain(raw) {
|
|
465
|
+
if (!raw) return void 0;
|
|
467
466
|
const out = {};
|
|
468
|
-
for (const [chainKey, tokenApy] of Object.entries(
|
|
467
|
+
for (const [chainKey, tokenApy] of Object.entries(raw)) {
|
|
469
468
|
const chainId = Number(chainKey);
|
|
470
469
|
if (!SUPPORTED_CHAIN_IDS.includes(chainId)) continue;
|
|
471
470
|
const perAsset = {};
|
|
@@ -505,15 +504,15 @@ function rawPoolApyForChain(entry, chainId, tokenSymbol) {
|
|
|
505
504
|
}
|
|
506
505
|
return totalBalance > 0 ? weightedSum / totalBalance : null;
|
|
507
506
|
}
|
|
508
|
-
function mapApyHistory(
|
|
509
|
-
const history = Object.entries(
|
|
507
|
+
function mapApyHistory(raw, chainId, tokenSymbol) {
|
|
508
|
+
const history = Object.entries(raw.history ?? {}).map(([date, entry]) => ({
|
|
510
509
|
date,
|
|
511
510
|
apy: rawPoolApyForChain(entry, chainId, tokenSymbol)
|
|
512
511
|
})).filter((p) => p.apy !== null).sort((a, b) => a.date.localeCompare(b.date));
|
|
513
512
|
return {
|
|
514
|
-
walletAddress:
|
|
515
|
-
weightedApyAfterFee:
|
|
516
|
-
apyByChainAndAsset: mapWeightedApyByChain(
|
|
513
|
+
walletAddress: raw.walletAddress,
|
|
514
|
+
weightedApyAfterFee: raw.weightedApyAfterFee ? sumTokenValues(raw.weightedApyAfterFee) : void 0,
|
|
515
|
+
apyByChainAndAsset: mapWeightedApyByChain(raw.weightedApyAfterFeeByChain),
|
|
517
516
|
history
|
|
518
517
|
};
|
|
519
518
|
}
|
|
@@ -609,23 +608,23 @@ function mapEntries(rawEntries, chainId) {
|
|
|
609
608
|
};
|
|
610
609
|
});
|
|
611
610
|
}
|
|
612
|
-
function mapUserProfile(
|
|
611
|
+
function mapUserProfile(raw, userAddress) {
|
|
613
612
|
return {
|
|
614
613
|
address: userAddress,
|
|
615
|
-
smartWallet:
|
|
616
|
-
chains:
|
|
617
|
-
strategy:
|
|
618
|
-
hasActiveSessionKey:
|
|
619
|
-
protocols:
|
|
620
|
-
splitting:
|
|
621
|
-
minSplits:
|
|
614
|
+
smartWallet: raw.smartWallet || "",
|
|
615
|
+
chains: raw.chains || [],
|
|
616
|
+
strategy: raw.strategy,
|
|
617
|
+
hasActiveSessionKey: raw.hasActiveSessionKey || false,
|
|
618
|
+
protocols: raw.protocols || [],
|
|
619
|
+
splitting: raw.splitting,
|
|
620
|
+
minSplits: raw.minSplits
|
|
622
621
|
};
|
|
623
622
|
}
|
|
624
|
-
function mapApyByStrategy(
|
|
623
|
+
function mapApyByStrategy(raw) {
|
|
625
624
|
const apyPerAsset = {};
|
|
626
625
|
let apySum = 0;
|
|
627
626
|
let apyCount = 0;
|
|
628
|
-
for (const entry of
|
|
627
|
+
for (const entry of raw.data) {
|
|
629
628
|
const supported = SupportedAssets.find(
|
|
630
629
|
(asset) => asset.chainId === entry.chain_id && asset.symbol === entry.token_symbol
|
|
631
630
|
);
|
|
@@ -763,7 +762,7 @@ var isJwtExpired = (token) => {
|
|
|
763
762
|
}
|
|
764
763
|
};
|
|
765
764
|
var memorySessions = /* @__PURE__ */ new Map();
|
|
766
|
-
var isFreshSession = (session) => !!session && !!session.token && !isJwtExpired(session.token);
|
|
765
|
+
var isFreshSession = (session) => !!session && typeof session.isPredeployed === "boolean" && !!session.token && !isJwtExpired(session.token);
|
|
767
766
|
var readLegacySession = (store, address) => {
|
|
768
767
|
if (!store) return null;
|
|
769
768
|
const prefix = legacyKeyPrefix(address);
|
|
@@ -796,15 +795,15 @@ var readSession = (address, _chainId) => {
|
|
|
796
795
|
if (typeof window === "undefined") return null;
|
|
797
796
|
const key2 = buildKey(address);
|
|
798
797
|
const store = storage();
|
|
799
|
-
let
|
|
798
|
+
let raw = null;
|
|
800
799
|
try {
|
|
801
|
-
|
|
800
|
+
raw = store?.getItem(key2) ?? null;
|
|
802
801
|
} catch {
|
|
803
|
-
|
|
802
|
+
raw = null;
|
|
804
803
|
}
|
|
805
|
-
if (
|
|
804
|
+
if (raw) {
|
|
806
805
|
try {
|
|
807
|
-
const parsed = JSON.parse(
|
|
806
|
+
const parsed = JSON.parse(raw);
|
|
808
807
|
if (isFreshSession(parsed)) return parsed;
|
|
809
808
|
} catch {
|
|
810
809
|
}
|
|
@@ -972,8 +971,8 @@ function buildChainsByProtocol(protocols, dashboardChainIds) {
|
|
|
972
971
|
}
|
|
973
972
|
return result;
|
|
974
973
|
}
|
|
975
|
-
function flattenAvailablePools(
|
|
976
|
-
const byChain =
|
|
974
|
+
function flattenAvailablePools(raw) {
|
|
975
|
+
const byChain = raw ?? {};
|
|
977
976
|
const names = [];
|
|
978
977
|
for (const byToken of Object.values(byChain ?? {})) {
|
|
979
978
|
for (const entry of Object.values(byToken ?? {})) {
|
|
@@ -1178,6 +1177,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1178
1177
|
internals.httpClient.setAuthToken(cached.token);
|
|
1179
1178
|
internals.authenticatedUserId = cached.userId;
|
|
1180
1179
|
internals.hasActiveSessionKey = cached.hasActiveSessionKey;
|
|
1180
|
+
internals.isPredeployed = cached.isPredeployed;
|
|
1181
1181
|
return;
|
|
1182
1182
|
}
|
|
1183
1183
|
}
|
|
@@ -1189,7 +1189,8 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1189
1189
|
writeSession(newAddress, newChainId, {
|
|
1190
1190
|
token: newToken,
|
|
1191
1191
|
userId: internals.authenticatedUserId,
|
|
1192
|
-
hasActiveSessionKey: internals.hasActiveSessionKey
|
|
1192
|
+
hasActiveSessionKey: internals.hasActiveSessionKey,
|
|
1193
|
+
isPredeployed: internals.isPredeployed
|
|
1193
1194
|
});
|
|
1194
1195
|
}
|
|
1195
1196
|
};
|
|
@@ -1474,8 +1475,8 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1474
1475
|
const poolResults = await Promise.all(
|
|
1475
1476
|
universe.map(async (protocol) => {
|
|
1476
1477
|
try {
|
|
1477
|
-
const
|
|
1478
|
-
return [protocol.id, flattenAvailablePools(
|
|
1478
|
+
const raw = await this.sdk.getAvailablePools(protocol.id, strategy);
|
|
1479
|
+
return [protocol.id, flattenAvailablePools(raw)];
|
|
1479
1480
|
} catch (error) {
|
|
1480
1481
|
console.warn(
|
|
1481
1482
|
`[zyfai] applyPoolPolicy: getAvailablePools(${protocol.id}) failed, skipping this protocol (non-fatal):`,
|
|
@@ -1541,14 +1542,14 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1541
1542
|
async readWalletState(ownerAddress) {
|
|
1542
1543
|
try {
|
|
1543
1544
|
const { portfolio } = await this.sdk.getPositions(ownerAddress);
|
|
1544
|
-
const
|
|
1545
|
+
const raw = portfolio;
|
|
1545
1546
|
debugLog("zyfai:onboard", "wallet state from getPositions", {
|
|
1546
|
-
predeployed:
|
|
1547
|
-
hasActiveSessionKey:
|
|
1547
|
+
predeployed: raw?.predeployed,
|
|
1548
|
+
hasActiveSessionKey: raw?.hasActiveSessionKey
|
|
1548
1549
|
});
|
|
1549
1550
|
return {
|
|
1550
|
-
predeployed:
|
|
1551
|
-
hasActiveSessionKey:
|
|
1551
|
+
predeployed: raw?.predeployed,
|
|
1552
|
+
hasActiveSessionKey: raw?.hasActiveSessionKey
|
|
1552
1553
|
};
|
|
1553
1554
|
} catch (error) {
|
|
1554
1555
|
console.warn(
|
|
@@ -1640,12 +1641,10 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1640
1641
|
);
|
|
1641
1642
|
return;
|
|
1642
1643
|
}
|
|
1643
|
-
const { hasActiveSessionKey } = await this.readWalletState(ownerAddress);
|
|
1644
1644
|
await this.ensureSessionKey(
|
|
1645
1645
|
ownerAddress,
|
|
1646
1646
|
chainId,
|
|
1647
|
-
wallet.address
|
|
1648
|
-
hasActiveSessionKey
|
|
1647
|
+
wallet.address
|
|
1649
1648
|
);
|
|
1650
1649
|
} catch (error) {
|
|
1651
1650
|
console.warn(
|
|
@@ -1654,7 +1653,17 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1654
1653
|
);
|
|
1655
1654
|
}
|
|
1656
1655
|
}
|
|
1657
|
-
async ensureSessionKey(ownerAddress, chainId, smartWallet
|
|
1656
|
+
async ensureSessionKey(ownerAddress, chainId, smartWallet) {
|
|
1657
|
+
const walletState = await this.readWalletState(ownerAddress);
|
|
1658
|
+
const predeployed = walletState.predeployed;
|
|
1659
|
+
if (predeployed !== false) {
|
|
1660
|
+
debugLog("zyfai:onboard", "skipping manual session key", {
|
|
1661
|
+
chainId,
|
|
1662
|
+
predeployed
|
|
1663
|
+
});
|
|
1664
|
+
return;
|
|
1665
|
+
}
|
|
1666
|
+
const hasActiveSessionKey = walletState.hasActiveSessionKey;
|
|
1658
1667
|
const attemptKey = `${ownerAddress.toLowerCase()}:${chainId}`;
|
|
1659
1668
|
if (this.sessionKeyAttempts.has(attemptKey)) {
|
|
1660
1669
|
debugLog(
|
|
@@ -1747,12 +1756,10 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1747
1756
|
"zyfai:onboard",
|
|
1748
1757
|
"Safe already has code -> no deploy needed, checking the session key"
|
|
1749
1758
|
);
|
|
1750
|
-
const { hasActiveSessionKey } = await this.readWalletState(ownerAddress);
|
|
1751
1759
|
await this.ensureSessionKey(
|
|
1752
1760
|
ownerAddress,
|
|
1753
1761
|
chainId,
|
|
1754
|
-
wallet.address
|
|
1755
|
-
hasActiveSessionKey
|
|
1762
|
+
wallet.address
|
|
1756
1763
|
);
|
|
1757
1764
|
return wallet.address;
|
|
1758
1765
|
}
|
|
@@ -1828,14 +1835,14 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1828
1835
|
return { txHash, smartWallet, amount };
|
|
1829
1836
|
}
|
|
1830
1837
|
await this.ensureWalletDeployed(this.getAddress(), validChainId);
|
|
1831
|
-
const
|
|
1838
|
+
const raw = await this.sdk.depositFunds(
|
|
1832
1839
|
this.getAddress(),
|
|
1833
1840
|
validChainId,
|
|
1834
1841
|
amount,
|
|
1835
1842
|
asset,
|
|
1836
1843
|
"aggressive"
|
|
1837
1844
|
);
|
|
1838
|
-
return mapDeposit(
|
|
1845
|
+
return mapDeposit(raw);
|
|
1839
1846
|
} catch (error) {
|
|
1840
1847
|
throw error;
|
|
1841
1848
|
}
|
|
@@ -1844,27 +1851,27 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1844
1851
|
async withdraw(state, chainId, token, amount) {
|
|
1845
1852
|
const validChainId = isValidChainId(chainId);
|
|
1846
1853
|
await this.ensureConnected(state, validChainId);
|
|
1847
|
-
const
|
|
1854
|
+
const raw = await this.sdk.withdrawFunds(
|
|
1848
1855
|
this.getAddress(),
|
|
1849
1856
|
validChainId,
|
|
1850
1857
|
amount,
|
|
1851
1858
|
token
|
|
1852
1859
|
);
|
|
1853
|
-
if (!
|
|
1860
|
+
if (!raw.success) {
|
|
1854
1861
|
throw new OwneyError(
|
|
1855
1862
|
"WITHDRAW_FAILED",
|
|
1856
|
-
|
|
1857
|
-
{ chainId: validChainId, token, amount, response:
|
|
1863
|
+
raw.message || "Zyfai withdraw failed.",
|
|
1864
|
+
{ chainId: validChainId, token, amount, response: raw },
|
|
1858
1865
|
this.id
|
|
1859
1866
|
);
|
|
1860
1867
|
}
|
|
1861
|
-
return mapWithdraw(
|
|
1868
|
+
return mapWithdraw(raw);
|
|
1862
1869
|
}
|
|
1863
1870
|
// --- IAgent: Portfolio reads ---
|
|
1864
1871
|
async getBalances(state, chainId) {
|
|
1865
1872
|
const { smartWallet, chainId: validChainId } = await this.resolveSmartWallet(state, chainId);
|
|
1866
|
-
const
|
|
1867
|
-
return mapBalances(
|
|
1873
|
+
const raw = await this.sdk.getPortfolio(this.getAddress());
|
|
1874
|
+
return mapBalances(raw, validChainId, smartWallet);
|
|
1868
1875
|
}
|
|
1869
1876
|
earningsKey(state, chainId, smartWallet) {
|
|
1870
1877
|
return JSON.stringify([
|
|
@@ -1877,11 +1884,11 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1877
1884
|
const existing = this.earningsReads.get(key2);
|
|
1878
1885
|
if (existing) return existing;
|
|
1879
1886
|
const generation = this.earningsGeneration;
|
|
1880
|
-
const pending = Promise.resolve().then(() => this.sdk.getOnchainEarnings(smartWallet)).then((
|
|
1887
|
+
const pending = Promise.resolve().then(() => this.sdk.getOnchainEarnings(smartWallet)).then((raw) => {
|
|
1881
1888
|
if (generation === this.earningsGeneration) {
|
|
1882
|
-
this.earningsSnapshot = { key: key2, raw
|
|
1889
|
+
this.earningsSnapshot = { key: key2, raw, at: Date.now() };
|
|
1883
1890
|
}
|
|
1884
|
-
return
|
|
1891
|
+
return raw;
|
|
1885
1892
|
}).finally(() => {
|
|
1886
1893
|
if (this.earningsReads.get(key2) === pending)
|
|
1887
1894
|
this.earningsReads.delete(key2);
|
|
@@ -1891,11 +1898,11 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1891
1898
|
}
|
|
1892
1899
|
async getEarnings(state, chainId) {
|
|
1893
1900
|
const { smartWallet } = await this.resolveSmartWallet(state, chainId);
|
|
1894
|
-
const
|
|
1901
|
+
const raw = await this.readEarnings(
|
|
1895
1902
|
this.earningsKey(state, chainId, smartWallet),
|
|
1896
1903
|
smartWallet
|
|
1897
1904
|
);
|
|
1898
|
-
return mapEarnings(
|
|
1905
|
+
return mapEarnings(raw, smartWallet);
|
|
1899
1906
|
}
|
|
1900
1907
|
async refreshEarnings(state, chainId) {
|
|
1901
1908
|
const { smartWallet } = await this.resolveSmartWallet(state, chainId);
|
|
@@ -1922,8 +1929,8 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1922
1929
|
}
|
|
1923
1930
|
async getAccountApy(state, chainId, days, tokenSymbol) {
|
|
1924
1931
|
const { smartWallet } = await this.resolveSmartWallet(state, chainId);
|
|
1925
|
-
const
|
|
1926
|
-
return mapApyHistory(
|
|
1932
|
+
const raw = await this.sdk.getDailyApyHistory(smartWallet, days);
|
|
1933
|
+
return mapApyHistory(raw, chainId, tokenSymbol);
|
|
1927
1934
|
}
|
|
1928
1935
|
/**
|
|
1929
1936
|
* Owney speaks asset symbols ("USDC" / "WETH"); Zyfai's history endpoint
|
|
@@ -1958,7 +1965,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1958
1965
|
const matched = [];
|
|
1959
1966
|
let backendExhausted = false;
|
|
1960
1967
|
for (let i = 0; i < MAX_BACKEND_CALLS && matched.length < limit; i++) {
|
|
1961
|
-
const
|
|
1968
|
+
const raw = await this.sdk.getHistory(smartWallet, validChainId, {
|
|
1962
1969
|
limit: backendPageSize,
|
|
1963
1970
|
offset,
|
|
1964
1971
|
fromDate: options?.fromDate,
|
|
@@ -1969,13 +1976,13 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1969
1976
|
// asset's rows and handing back a page that filters to nothing.
|
|
1970
1977
|
assetType
|
|
1971
1978
|
});
|
|
1972
|
-
|
|
1979
|
+
raw.data.forEach((entry, idx) => {
|
|
1973
1980
|
if (entry.chainId === validChainId) {
|
|
1974
1981
|
matched.push({ entry, rawIdx: offset + idx });
|
|
1975
1982
|
}
|
|
1976
1983
|
});
|
|
1977
|
-
offset +=
|
|
1978
|
-
if (
|
|
1984
|
+
offset += raw.data.length;
|
|
1985
|
+
if (raw.data.length < backendPageSize) {
|
|
1979
1986
|
backendExhausted = true;
|
|
1980
1987
|
break;
|
|
1981
1988
|
}
|
|
@@ -1997,18 +2004,18 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1997
2004
|
}
|
|
1998
2005
|
async getUserProfile(state, chainId) {
|
|
1999
2006
|
await this.connectAuth(state, chainId);
|
|
2000
|
-
const
|
|
2007
|
+
const raw = await this.sdk.getUserDetails();
|
|
2001
2008
|
debugLog("zyfai:profile", "getUserProfile \u2014 Zyfai reports", {
|
|
2002
2009
|
asset: "USDC (default \u2014 no asset passed)",
|
|
2003
|
-
splitting:
|
|
2004
|
-
minSplits:
|
|
2005
|
-
strategy:
|
|
2006
|
-
chains:
|
|
2007
|
-
protocolCount:
|
|
2008
|
-
hasActiveSessionKey:
|
|
2009
|
-
smartWallet:
|
|
2010
|
+
splitting: raw.splitting,
|
|
2011
|
+
minSplits: raw.minSplits,
|
|
2012
|
+
strategy: raw.strategy,
|
|
2013
|
+
chains: raw.chains,
|
|
2014
|
+
protocolCount: raw.protocols?.length,
|
|
2015
|
+
hasActiveSessionKey: raw.hasActiveSessionKey,
|
|
2016
|
+
smartWallet: raw.smartWallet
|
|
2010
2017
|
});
|
|
2011
|
-
return mapUserProfile(
|
|
2018
|
+
return mapUserProfile(raw, this.connectedAddress);
|
|
2012
2019
|
}
|
|
2013
2020
|
async ensureAutoSelectProtocols(state, chainId, asset) {
|
|
2014
2021
|
await this.connectAuth(state, chainId);
|
|
@@ -2027,58 +2034,236 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2027
2034
|
}
|
|
2028
2035
|
// --- IAgent: Discovery (no wallet required) ---
|
|
2029
2036
|
async getAgentApy(days, options) {
|
|
2030
|
-
const
|
|
2037
|
+
const raw = await this.sdk.getAPYPerStrategy(
|
|
2031
2038
|
false,
|
|
2032
2039
|
DayFilterMapping[days],
|
|
2033
2040
|
"aggressive",
|
|
2034
2041
|
options?.chainId,
|
|
2035
2042
|
options?.tokenSymbol
|
|
2036
2043
|
);
|
|
2037
|
-
return mapApyByStrategy(
|
|
2044
|
+
return mapApyByStrategy(raw);
|
|
2038
2045
|
}
|
|
2039
2046
|
};
|
|
2040
2047
|
|
|
2041
|
-
// src/
|
|
2042
|
-
var
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
// src/lib/chain-guard.ts
|
|
2046
|
-
var CHAIN_NAMES = {
|
|
2047
|
-
1: "Ethereum",
|
|
2048
|
-
8453: "Base",
|
|
2049
|
-
42161: "Arbitrum"
|
|
2050
|
-
};
|
|
2051
|
-
function chainName(chainId) {
|
|
2052
|
-
return CHAIN_NAMES[chainId] ?? `chain ${chainId}`;
|
|
2053
|
-
}
|
|
2054
|
-
async function ensureWalletOnChain(pub, wallet, expected) {
|
|
2055
|
-
const actual = await pub.getChainId();
|
|
2056
|
-
if (actual === expected) return;
|
|
2048
|
+
// src/lib/routing-api.ts
|
|
2049
|
+
var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
2050
|
+
async function fetchOrgAgentConfig(apiKey, baseUrl = ROUTING_API_BASE_URL) {
|
|
2051
|
+
const url = `${baseUrl}/api/v1/agent/org-config`;
|
|
2057
2052
|
try {
|
|
2058
|
-
await
|
|
2053
|
+
const res = await fetch(url, {
|
|
2054
|
+
method: "GET",
|
|
2055
|
+
headers: {
|
|
2056
|
+
"Content-Type": "application/json",
|
|
2057
|
+
"x-owney-api-key": `${apiKey}`
|
|
2058
|
+
}
|
|
2059
|
+
});
|
|
2060
|
+
if (!res.ok) {
|
|
2061
|
+
if (res.status !== 404) {
|
|
2062
|
+
console.warn(
|
|
2063
|
+
`[owney-sdk] Could not read org agent config (${res.status}); leaving user profiles unchanged.`
|
|
2064
|
+
);
|
|
2065
|
+
}
|
|
2066
|
+
return null;
|
|
2067
|
+
}
|
|
2068
|
+
const json = await res.json();
|
|
2069
|
+
const policy = json.success ? json.data ?? null : null;
|
|
2070
|
+
debugLog(
|
|
2071
|
+
"owney-sdk",
|
|
2072
|
+
policy ? "org agent config: loaded" : "org agent config: none set by this partner \u2014 user profiles will be left as they are",
|
|
2073
|
+
policy ?? void 0
|
|
2074
|
+
);
|
|
2075
|
+
return policy;
|
|
2059
2076
|
} catch (error) {
|
|
2077
|
+
console.warn(
|
|
2078
|
+
"[owney-sdk] Could not read org agent config (non-fatal):",
|
|
2079
|
+
error instanceof Error ? error.message : String(error)
|
|
2080
|
+
);
|
|
2081
|
+
return null;
|
|
2082
|
+
}
|
|
2083
|
+
}
|
|
2084
|
+
async function fetchAgentKeys(apiKey, baseUrl = ROUTING_API_BASE_URL) {
|
|
2085
|
+
const url = `${baseUrl}/api/v1/agent/keys`;
|
|
2086
|
+
const res = await fetch(url, {
|
|
2087
|
+
method: "GET",
|
|
2088
|
+
headers: {
|
|
2089
|
+
"Content-Type": "application/json",
|
|
2090
|
+
"x-owney-api-key": `${apiKey}`
|
|
2091
|
+
}
|
|
2092
|
+
});
|
|
2093
|
+
if (!res.ok) {
|
|
2094
|
+
const text = await res.text().catch(() => "");
|
|
2060
2095
|
throw new OwneyError(
|
|
2061
|
-
"
|
|
2062
|
-
`
|
|
2063
|
-
{
|
|
2064
|
-
expectedChainId: expected,
|
|
2065
|
-
actualChainId: actual,
|
|
2066
|
-
cause: error instanceof Error ? error.message : String(error)
|
|
2067
|
-
}
|
|
2096
|
+
"API_ROUTING_ERROR",
|
|
2097
|
+
`Routing API error ${res.status}: ${text}`,
|
|
2098
|
+
{ statusCode: res.status, responseBody: text }
|
|
2068
2099
|
);
|
|
2069
2100
|
}
|
|
2070
|
-
const
|
|
2071
|
-
if (
|
|
2101
|
+
const json = await res.json();
|
|
2102
|
+
if (!json.success) {
|
|
2072
2103
|
throw new OwneyError(
|
|
2073
|
-
"
|
|
2074
|
-
`
|
|
2075
|
-
{
|
|
2104
|
+
"API_ROUTING_FAILED",
|
|
2105
|
+
`Routing API request failed: ${json.message}`,
|
|
2106
|
+
{ message: json.message }
|
|
2076
2107
|
);
|
|
2077
2108
|
}
|
|
2109
|
+
return json.data;
|
|
2078
2110
|
}
|
|
2079
2111
|
|
|
2080
|
-
// src/lib/
|
|
2112
|
+
// src/lib/health-report.ts
|
|
2113
|
+
var ROUTING_API_BASE_URL2 = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
2114
|
+
async function reportAgentFailure(apiKey, agentType, errorCode, baseUrl = ROUTING_API_BASE_URL2) {
|
|
2115
|
+
try {
|
|
2116
|
+
await fetch(`${baseUrl}/api/v1/agent/health-report`, {
|
|
2117
|
+
method: "POST",
|
|
2118
|
+
headers: {
|
|
2119
|
+
"Content-Type": "application/json",
|
|
2120
|
+
"x-owney-api-key": apiKey
|
|
2121
|
+
},
|
|
2122
|
+
body: JSON.stringify({
|
|
2123
|
+
agent_type: agentType,
|
|
2124
|
+
error_code: errorCode,
|
|
2125
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2126
|
+
})
|
|
2127
|
+
});
|
|
2128
|
+
} catch (err) {
|
|
2129
|
+
console.warn(
|
|
2130
|
+
`[owney-sdk] health-report failed for agent "${agentType}":`,
|
|
2131
|
+
err instanceof Error ? err.message : err
|
|
2132
|
+
);
|
|
2133
|
+
}
|
|
2134
|
+
}
|
|
2135
|
+
async function withFailureReporting(apiKey, agentType, fn, baseUrl) {
|
|
2136
|
+
try {
|
|
2137
|
+
return await fn();
|
|
2138
|
+
} catch (err) {
|
|
2139
|
+
const errorCode = err instanceof OwneyError ? err.code : "SDK_AGENT_FAILURE";
|
|
2140
|
+
void reportAgentFailure(apiKey, agentType, errorCode, baseUrl);
|
|
2141
|
+
throw err;
|
|
2142
|
+
}
|
|
2143
|
+
}
|
|
2144
|
+
|
|
2145
|
+
// src/lib/helpers/withdraw-helper.ts
|
|
2081
2146
|
var import_viem2 = require("viem");
|
|
2147
|
+
function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
|
|
2148
|
+
const target = asset.toUpperCase();
|
|
2149
|
+
return agents.map((agent) => {
|
|
2150
|
+
const agentBalance = aggregated[agent.id];
|
|
2151
|
+
const tokenBalance = agentBalance?.tokens.find(
|
|
2152
|
+
(t) => t.chainId === chainId && t.asset.toUpperCase() === target
|
|
2153
|
+
);
|
|
2154
|
+
if (!tokenBalance) return { agent, balance: 0n };
|
|
2155
|
+
return { agent, balance: (0, import_viem2.parseUnits)(tokenBalance.amount, decimals) };
|
|
2156
|
+
});
|
|
2157
|
+
}
|
|
2158
|
+
function planProportionalShares(balances, requested, totalAvailable) {
|
|
2159
|
+
const plans = balances.map(({ agent, balance }) => ({
|
|
2160
|
+
agent,
|
|
2161
|
+
balance,
|
|
2162
|
+
planned: totalAvailable > 0n ? balance * requested / totalAvailable : 0n
|
|
2163
|
+
}));
|
|
2164
|
+
const assigned = plans.reduce((s, p) => s + p.planned, 0n);
|
|
2165
|
+
let remainder = requested - assigned;
|
|
2166
|
+
const byHeadroom = [...plans].sort((a, b) => {
|
|
2167
|
+
const diff = b.balance - b.planned - (a.balance - a.planned);
|
|
2168
|
+
return diff > 0n ? 1 : diff < 0n ? -1 : 0;
|
|
2169
|
+
});
|
|
2170
|
+
for (const p of byHeadroom) {
|
|
2171
|
+
if (remainder === 0n) break;
|
|
2172
|
+
const headroom = p.balance - p.planned;
|
|
2173
|
+
if (headroom <= 0n) continue;
|
|
2174
|
+
const take = headroom < remainder ? headroom : remainder;
|
|
2175
|
+
p.planned += take;
|
|
2176
|
+
remainder -= take;
|
|
2177
|
+
}
|
|
2178
|
+
return plans;
|
|
2179
|
+
}
|
|
2180
|
+
function planDisabledDrain(disabled, requested) {
|
|
2181
|
+
const sorted = [...disabled].filter((d) => d.balance > 0n).sort((a, b) => b.balance > a.balance ? 1 : b.balance < a.balance ? -1 : 0);
|
|
2182
|
+
const plans = [];
|
|
2183
|
+
let remaining = requested;
|
|
2184
|
+
for (const { agent, balance } of sorted) {
|
|
2185
|
+
if (remaining === 0n) {
|
|
2186
|
+
plans.push({ agent, balance, planned: 0n });
|
|
2187
|
+
continue;
|
|
2188
|
+
}
|
|
2189
|
+
const take = balance < remaining ? balance : remaining;
|
|
2190
|
+
plans.push({ agent, balance, planned: take });
|
|
2191
|
+
remaining -= take;
|
|
2192
|
+
}
|
|
2193
|
+
return { plans, remaining };
|
|
2194
|
+
}
|
|
2195
|
+
function redistributeShare(plans, fromIndex, amount, candidatePool) {
|
|
2196
|
+
const pool = candidatePool ?? plans.slice(fromIndex + 1);
|
|
2197
|
+
const candidates = pool.filter((c) => c.balance - c.planned > 0n);
|
|
2198
|
+
const totalHeadroom = candidates.reduce(
|
|
2199
|
+
(s, c) => s + (c.balance - c.planned),
|
|
2200
|
+
0n
|
|
2201
|
+
);
|
|
2202
|
+
if (totalHeadroom === 0n) return;
|
|
2203
|
+
let distributed = 0n;
|
|
2204
|
+
for (const c of candidates) {
|
|
2205
|
+
const headroom = c.balance - c.planned;
|
|
2206
|
+
const proportional = headroom * amount / totalHeadroom;
|
|
2207
|
+
const give = proportional > headroom ? headroom : proportional;
|
|
2208
|
+
c.planned += give;
|
|
2209
|
+
distributed += give;
|
|
2210
|
+
}
|
|
2211
|
+
let leftover = amount - distributed;
|
|
2212
|
+
for (const c of candidates) {
|
|
2213
|
+
if (leftover === 0n) break;
|
|
2214
|
+
const headroom = c.balance - c.planned;
|
|
2215
|
+
if (headroom <= 0n) continue;
|
|
2216
|
+
const take = headroom < leftover ? headroom : leftover;
|
|
2217
|
+
c.planned += take;
|
|
2218
|
+
leftover -= take;
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
function sumWithdrawnAmount(results) {
|
|
2222
|
+
return Object.values(results).reduce((sum, r) => sum + BigInt(r.amount), 0n);
|
|
2223
|
+
}
|
|
2224
|
+
|
|
2225
|
+
// src/lib/helpers/account-apy-helper.ts
|
|
2226
|
+
function aggregateApyByChainAndAsset(agentApys, agentBalances) {
|
|
2227
|
+
const sums = {};
|
|
2228
|
+
const weights = {};
|
|
2229
|
+
for (const id of Object.keys(agentApys)) {
|
|
2230
|
+
const cells = agentApys[id].apyByChainAndAsset;
|
|
2231
|
+
const balance = agentBalances[id] ?? 0;
|
|
2232
|
+
if (!cells || balance <= 0) continue;
|
|
2233
|
+
for (const [chainKey, perAsset] of Object.entries(cells)) {
|
|
2234
|
+
if (!perAsset) continue;
|
|
2235
|
+
const chainId = Number(chainKey);
|
|
2236
|
+
for (const [asset, apyValue] of Object.entries(perAsset)) {
|
|
2237
|
+
const apy = Number(apyValue ?? 0);
|
|
2238
|
+
if (apy === 0) continue;
|
|
2239
|
+
sums[chainId] ??= {};
|
|
2240
|
+
weights[chainId] ??= {};
|
|
2241
|
+
sums[chainId][asset] = (sums[chainId][asset] ?? 0) + apy * balance;
|
|
2242
|
+
weights[chainId][asset] = (weights[chainId][asset] ?? 0) + balance;
|
|
2243
|
+
}
|
|
2244
|
+
}
|
|
2245
|
+
}
|
|
2246
|
+
const out = {};
|
|
2247
|
+
for (const chainKey of Object.keys(sums)) {
|
|
2248
|
+
const chainId = Number(chainKey);
|
|
2249
|
+
const perAssetOut = {};
|
|
2250
|
+
for (const asset of Object.keys(sums[chainId])) {
|
|
2251
|
+
const w = weights[chainId][asset];
|
|
2252
|
+
if (w > 0) perAssetOut[asset] = sums[chainId][asset] / w;
|
|
2253
|
+
}
|
|
2254
|
+
if (Object.keys(perAssetOut).length > 0) {
|
|
2255
|
+
out[chainId] = perAssetOut;
|
|
2256
|
+
}
|
|
2257
|
+
}
|
|
2258
|
+
return out;
|
|
2259
|
+
}
|
|
2260
|
+
|
|
2261
|
+
// src/client.ts
|
|
2262
|
+
var import_viem6 = require("viem");
|
|
2263
|
+
var import_chains2 = require("viem/chains");
|
|
2264
|
+
|
|
2265
|
+
// src/lib/transfer-auth.ts
|
|
2266
|
+
var import_viem3 = require("viem");
|
|
2082
2267
|
var ERC20_META_ABI = [
|
|
2083
2268
|
{ type: "function", name: "name", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] },
|
|
2084
2269
|
{ type: "function", name: "version", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] }
|
|
@@ -2110,29 +2295,28 @@ async function readTokenMeta(publicClient, token) {
|
|
|
2110
2295
|
function randomAuthNonce() {
|
|
2111
2296
|
const bytes = new Uint8Array(32);
|
|
2112
2297
|
globalThis.crypto.getRandomValues(bytes);
|
|
2113
|
-
return (0,
|
|
2298
|
+
return (0, import_viem3.bytesToHex)(bytes);
|
|
2114
2299
|
}
|
|
2115
2300
|
|
|
2116
2301
|
// src/lib/sponsor-client.ts
|
|
2117
|
-
var
|
|
2118
|
-
async function
|
|
2119
|
-
const
|
|
2302
|
+
var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
2303
|
+
async function postSponsorTransferAuth(input) {
|
|
2304
|
+
const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
2120
2305
|
let res;
|
|
2121
2306
|
try {
|
|
2122
|
-
res = await fetch(`${
|
|
2307
|
+
res = await fetch(`${base3}/api/v1/sponsor/erc20-transfer-auth`, {
|
|
2123
2308
|
method: "POST",
|
|
2124
2309
|
headers: {
|
|
2125
2310
|
"content-type": "application/json",
|
|
2126
|
-
"x-owney-api-key": input.apiKey
|
|
2127
|
-
Authorization: `Signature ${input.yieldseekerSignature}`
|
|
2311
|
+
"x-owney-api-key": input.apiKey
|
|
2128
2312
|
},
|
|
2129
2313
|
body: JSON.stringify(input.body)
|
|
2130
2314
|
});
|
|
2131
2315
|
} catch (networkError) {
|
|
2132
2316
|
throw new OwneyError(
|
|
2133
2317
|
"SPONSOR_REQUEST_FAILED",
|
|
2134
|
-
`
|
|
2135
|
-
{ cause: String(networkError)
|
|
2318
|
+
`Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
|
|
2319
|
+
{ cause: String(networkError) }
|
|
2136
2320
|
);
|
|
2137
2321
|
}
|
|
2138
2322
|
const text = await res.text();
|
|
@@ -2141,29 +2325,30 @@ async function postPaymasterIntent(input) {
|
|
|
2141
2325
|
parsed = JSON.parse(text);
|
|
2142
2326
|
} catch {
|
|
2143
2327
|
}
|
|
2144
|
-
if (!res.ok || !parsed?.success ||
|
|
2328
|
+
if (!res.ok || !parsed?.success || !parsed.data) {
|
|
2145
2329
|
throw new OwneyError(
|
|
2146
2330
|
"SPONSOR_REQUEST_FAILED",
|
|
2147
|
-
`
|
|
2331
|
+
`Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
|
|
2148
2332
|
{
|
|
2149
2333
|
statusCode: res.status,
|
|
2150
2334
|
responseBody: text.slice(0, 500),
|
|
2151
|
-
|
|
2335
|
+
// 503 SPONSOR_UNAVAILABLE = relayer out of gas; the tx was rejected
|
|
2336
|
+
// before broadcast, so it is safe to fall back to a user-paid deposit.
|
|
2337
|
+
safeToFallback: res.status === 503
|
|
2152
2338
|
}
|
|
2153
2339
|
);
|
|
2154
2340
|
}
|
|
2155
2341
|
return parsed.data;
|
|
2156
2342
|
}
|
|
2157
|
-
async function
|
|
2158
|
-
const
|
|
2343
|
+
async function postSponsorPermit2Transfer(input) {
|
|
2344
|
+
const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
2159
2345
|
let res;
|
|
2160
2346
|
try {
|
|
2161
|
-
res = await fetch(`${
|
|
2347
|
+
res = await fetch(`${base3}/api/v1/sponsor/permit2-transfer`, {
|
|
2162
2348
|
method: "POST",
|
|
2163
2349
|
headers: {
|
|
2164
2350
|
"content-type": "application/json",
|
|
2165
|
-
"x-owney-api-key": input.apiKey
|
|
2166
|
-
...input.yieldseekerSignature ? { Authorization: `Signature ${input.yieldseekerSignature}` } : {}
|
|
2351
|
+
"x-owney-api-key": input.apiKey
|
|
2167
2352
|
},
|
|
2168
2353
|
body: JSON.stringify(input.body)
|
|
2169
2354
|
});
|
|
@@ -2171,7 +2356,7 @@ async function postSponsorTransferAuth(input) {
|
|
|
2171
2356
|
throw new OwneyError(
|
|
2172
2357
|
"SPONSOR_REQUEST_FAILED",
|
|
2173
2358
|
`Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
|
|
2174
|
-
{ cause: String(networkError) }
|
|
2359
|
+
{ cause: String(networkError), safeToFallback: false }
|
|
2175
2360
|
);
|
|
2176
2361
|
}
|
|
2177
2362
|
const text = await res.text();
|
|
@@ -2187,59 +2372,18 @@ async function postSponsorTransferAuth(input) {
|
|
|
2187
2372
|
{
|
|
2188
2373
|
statusCode: res.status,
|
|
2189
2374
|
responseBody: text.slice(0, 500),
|
|
2190
|
-
|
|
2191
|
-
// before broadcast, so it is safe to fall back to a user-paid deposit.
|
|
2192
|
-
safeToFallback: res.status === 503
|
|
2193
|
-
}
|
|
2194
|
-
);
|
|
2195
|
-
}
|
|
2196
|
-
return parsed.data;
|
|
2197
|
-
}
|
|
2198
|
-
async function postSponsorPermit2Transfer(input) {
|
|
2199
|
-
const base5 = input.baseUrl ?? ROUTING_API_BASE_URL;
|
|
2200
|
-
let res;
|
|
2201
|
-
try {
|
|
2202
|
-
res = await fetch(`${base5}/api/v1/sponsor/permit2-transfer`, {
|
|
2203
|
-
method: "POST",
|
|
2204
|
-
headers: {
|
|
2205
|
-
"content-type": "application/json",
|
|
2206
|
-
"x-owney-api-key": input.apiKey,
|
|
2207
|
-
...input.yieldseekerSignature ? { Authorization: `Signature ${input.yieldseekerSignature}` } : {}
|
|
2208
|
-
},
|
|
2209
|
-
body: JSON.stringify(input.body)
|
|
2210
|
-
});
|
|
2211
|
-
} catch (networkError) {
|
|
2212
|
-
throw new OwneyError(
|
|
2213
|
-
"SPONSOR_REQUEST_FAILED",
|
|
2214
|
-
`Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
|
|
2215
|
-
{ cause: String(networkError), safeToFallback: false }
|
|
2216
|
-
);
|
|
2217
|
-
}
|
|
2218
|
-
const text = await res.text();
|
|
2219
|
-
let parsed = null;
|
|
2220
|
-
try {
|
|
2221
|
-
parsed = JSON.parse(text);
|
|
2222
|
-
} catch {
|
|
2223
|
-
}
|
|
2224
|
-
if (!res.ok || !parsed?.success || !parsed.data) {
|
|
2225
|
-
throw new OwneyError(
|
|
2226
|
-
"SPONSOR_REQUEST_FAILED",
|
|
2227
|
-
`Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
|
|
2228
|
-
{
|
|
2229
|
-
statusCode: res.status,
|
|
2230
|
-
responseBody: text.slice(0, 500),
|
|
2231
|
-
safeToFallback: res.status >= 400 && res.status < 500 || res.status === 503
|
|
2375
|
+
safeToFallback: res.status >= 400 && res.status < 500 || res.status === 503
|
|
2232
2376
|
}
|
|
2233
2377
|
);
|
|
2234
2378
|
}
|
|
2235
2379
|
return parsed.data;
|
|
2236
2380
|
}
|
|
2237
2381
|
async function getSponsorRelayerAddress(input) {
|
|
2238
|
-
const
|
|
2382
|
+
const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
2239
2383
|
let res;
|
|
2240
2384
|
try {
|
|
2241
2385
|
res = await fetch(
|
|
2242
|
-
`${
|
|
2386
|
+
`${base3}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
|
|
2243
2387
|
{
|
|
2244
2388
|
headers: { "x-owney-api-key": input.apiKey }
|
|
2245
2389
|
}
|
|
@@ -2272,7 +2416,7 @@ async function getSponsorRelayerAddress(input) {
|
|
|
2272
2416
|
}
|
|
2273
2417
|
|
|
2274
2418
|
// src/lib/permit2.ts
|
|
2275
|
-
var
|
|
2419
|
+
var import_viem4 = require("viem");
|
|
2276
2420
|
var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
2277
2421
|
var MAX_UINT256 = 2n ** 256n - 1n;
|
|
2278
2422
|
var ERC20_ALLOWANCE_ABI = [
|
|
@@ -2330,7 +2474,7 @@ function buildPermitTransferFromTypedData(input) {
|
|
|
2330
2474
|
function randomPermit2Nonce() {
|
|
2331
2475
|
const bytes = new Uint8Array(32);
|
|
2332
2476
|
globalThis.crypto.getRandomValues(bytes);
|
|
2333
|
-
return BigInt((0,
|
|
2477
|
+
return BigInt((0, import_viem4.bytesToHex)(bytes));
|
|
2334
2478
|
}
|
|
2335
2479
|
async function readPermit2Allowance(publicClient, token, owner) {
|
|
2336
2480
|
return publicClient.readContract({
|
|
@@ -2340,1972 +2484,213 @@ async function readPermit2Allowance(publicClient, token, owner) {
|
|
|
2340
2484
|
args: [owner, PERMIT2_ADDRESS]
|
|
2341
2485
|
});
|
|
2342
2486
|
}
|
|
2343
|
-
async function readErc20Balance(publicClient, token, owner) {
|
|
2344
|
-
return publicClient.readContract({
|
|
2345
|
-
address: token,
|
|
2346
|
-
abi: ERC20_ALLOWANCE_ABI,
|
|
2347
|
-
functionName: "balanceOf",
|
|
2348
|
-
args: [owner]
|
|
2349
|
-
});
|
|
2350
|
-
}
|
|
2351
|
-
|
|
2352
|
-
// src/lib/sponsored-deposit.ts
|
|
2353
|
-
var AUTH_WINDOW_SECONDS = 15 * 60;
|
|
2354
|
-
var verificationSetter = /* @__PURE__ */ Symbol("owney.depositVerificationSetter");
|
|
2355
|
-
function provideDepositVerificationContext(callback, context) {
|
|
2356
|
-
callback[verificationSetter]?.(context);
|
|
2357
|
-
}
|
|
2358
|
-
function makeVerificationAwareDepositCallback(implementation) {
|
|
2359
|
-
let nextVerification;
|
|
2360
|
-
const callback = async (smartWallet, chainId, amount) => {
|
|
2361
|
-
const verification = nextVerification;
|
|
2362
|
-
nextVerification = void 0;
|
|
2363
|
-
return implementation(smartWallet, chainId, amount, verification);
|
|
2364
|
-
};
|
|
2365
|
-
Object.defineProperty(callback, verificationSetter, {
|
|
2366
|
-
value: (context) => {
|
|
2367
|
-
nextVerification = context;
|
|
2368
|
-
}
|
|
2369
|
-
});
|
|
2370
|
-
return callback;
|
|
2371
|
-
}
|
|
2372
|
-
function makeSponsoredDepositCallback(deps) {
|
|
2373
|
-
const post = deps.httpPost ?? postSponsorTransferAuth;
|
|
2374
|
-
return makeVerificationAwareDepositCallback(
|
|
2375
|
-
async (smartWallet, chainId, amount, verification) => {
|
|
2376
|
-
const cid = chainId;
|
|
2377
|
-
const token = deps.tokenAddressByChain[cid];
|
|
2378
|
-
if (!token) {
|
|
2379
|
-
throw new OwneyError(
|
|
2380
|
-
"CHAIN_UNSUPPORTED",
|
|
2381
|
-
`No sponsored token configured for chain ${chainId}`
|
|
2382
|
-
);
|
|
2383
|
-
}
|
|
2384
|
-
const pub = deps.getPublicClient(cid);
|
|
2385
|
-
const wallet = deps.getWalletClient(cid);
|
|
2386
|
-
await ensureWalletOnChain(pub, wallet, cid);
|
|
2387
|
-
try {
|
|
2388
|
-
const balance = await readErc20Balance(pub, token, deps.ownerAddress);
|
|
2389
|
-
if (balance < BigInt(amount)) {
|
|
2390
|
-
throw new OwneyError(
|
|
2391
|
-
"DEPOSIT_INSUFFICIENT_BALANCE",
|
|
2392
|
-
"Insufficient balance for this deposit.",
|
|
2393
|
-
{ token, chainId: cid, balance: balance.toString(), amount }
|
|
2394
|
-
);
|
|
2395
|
-
}
|
|
2396
|
-
} catch (err) {
|
|
2397
|
-
if (err instanceof OwneyError) throw err;
|
|
2398
|
-
console.warn(
|
|
2399
|
-
"[owney-sdk] Deposit balance pre-check failed (non-fatal):",
|
|
2400
|
-
err instanceof Error ? err.message : String(err)
|
|
2401
|
-
);
|
|
2402
|
-
}
|
|
2403
|
-
const { tokenName, tokenVersion } = await readTokenMeta(pub, token);
|
|
2404
|
-
const validAfter = 0n;
|
|
2405
|
-
const validBefore = BigInt(
|
|
2406
|
-
Math.floor(Date.now() / 1e3) + AUTH_WINDOW_SECONDS
|
|
2407
|
-
);
|
|
2408
|
-
const nonce = randomAuthNonce();
|
|
2409
|
-
const typedData = buildTransferWithAuthorizationTypedData({
|
|
2410
|
-
token,
|
|
2411
|
-
chainId: cid,
|
|
2412
|
-
tokenName,
|
|
2413
|
-
tokenVersion,
|
|
2414
|
-
message: {
|
|
2415
|
-
from: deps.ownerAddress,
|
|
2416
|
-
to: smartWallet,
|
|
2417
|
-
value: BigInt(amount),
|
|
2418
|
-
validAfter,
|
|
2419
|
-
validBefore,
|
|
2420
|
-
nonce
|
|
2421
|
-
}
|
|
2422
|
-
});
|
|
2423
|
-
const authSignature = await wallet.signTypedData({
|
|
2424
|
-
account: deps.ownerAddress,
|
|
2425
|
-
...typedData
|
|
2426
|
-
});
|
|
2427
|
-
deps.onApproved?.();
|
|
2428
|
-
const result = await post({
|
|
2429
|
-
baseUrl: deps.baseUrl,
|
|
2430
|
-
apiKey: deps.apiKey,
|
|
2431
|
-
...verification?.agentId === "yieldseeker" ? { yieldseekerSignature: verification.signature } : {},
|
|
2432
|
-
body: {
|
|
2433
|
-
chainId: cid,
|
|
2434
|
-
token,
|
|
2435
|
-
from: deps.ownerAddress,
|
|
2436
|
-
to: smartWallet,
|
|
2437
|
-
value: amount,
|
|
2438
|
-
validAfter: validAfter.toString(),
|
|
2439
|
-
validBefore: validBefore.toString(),
|
|
2440
|
-
nonce,
|
|
2441
|
-
authSignature,
|
|
2442
|
-
tokenName,
|
|
2443
|
-
tokenVersion,
|
|
2444
|
-
...verification?.agentId === "yieldseeker" ? {
|
|
2445
|
-
yieldseekerUserId: verification.userId,
|
|
2446
|
-
yieldseekerAgentId: verification.yieldseekerAgentId
|
|
2447
|
-
} : {}
|
|
2448
|
-
}
|
|
2449
|
-
});
|
|
2450
|
-
return result.txHash;
|
|
2451
|
-
}
|
|
2452
|
-
);
|
|
2453
|
-
}
|
|
2454
|
-
|
|
2455
|
-
// src/agents/yieldseeker/yieldseeker.auth.ts
|
|
2456
|
-
var import_siwe = require("siwe");
|
|
2457
|
-
var import_viem4 = require("viem");
|
|
2458
|
-
var import_chains2 = require("viem/chains");
|
|
2459
|
-
|
|
2460
|
-
// src/agents/yieldseeker/yieldseeker.auth-cache.ts
|
|
2461
|
-
var KEY_PREFIX2 = "owney.yieldseeker.session.v5";
|
|
2462
|
-
var INVALIDATED_KEY_PREFIXES = [
|
|
2463
|
-
"owney.yieldseeker.session",
|
|
2464
|
-
"owney.yieldseeker.session.v3",
|
|
2465
|
-
"owney.yieldseeker.session.v4"
|
|
2466
|
-
];
|
|
2467
|
-
var storage2 = () => {
|
|
2468
|
-
if (typeof window === "undefined") return null;
|
|
2469
|
-
try {
|
|
2470
|
-
return window.localStorage;
|
|
2471
|
-
} catch {
|
|
2472
|
-
return null;
|
|
2473
|
-
}
|
|
2474
|
-
};
|
|
2475
|
-
var buildKey2 = (address, chainId) => `${KEY_PREFIX2}:${address.toLowerCase()}:${chainId}`;
|
|
2476
|
-
var invalidatedKeys = (address, chainId) => INVALIDATED_KEY_PREFIXES.map(
|
|
2477
|
-
(prefix) => `${prefix}:${address.toLowerCase()}:${chainId}`
|
|
2478
|
-
);
|
|
2479
|
-
var clearInvalidatedSessions = (store, address, chainId) => {
|
|
2480
|
-
for (const key2 of invalidatedKeys(address, chainId)) {
|
|
2481
|
-
memorySessions2.delete(key2);
|
|
2482
|
-
try {
|
|
2483
|
-
store?.removeItem(key2);
|
|
2484
|
-
} catch {
|
|
2485
|
-
}
|
|
2486
|
-
}
|
|
2487
|
-
};
|
|
2488
|
-
var memorySessions2 = /* @__PURE__ */ new Map();
|
|
2489
|
-
var isValidSession = (session) => {
|
|
2490
|
-
if (!session?.token) return false;
|
|
2491
|
-
try {
|
|
2492
|
-
const parsed = JSON.parse(atob(session.token));
|
|
2493
|
-
return typeof parsed.message === "string" && typeof parsed.signature === "string" && parsed.signature.startsWith("0x");
|
|
2494
|
-
} catch {
|
|
2495
|
-
return false;
|
|
2496
|
-
}
|
|
2497
|
-
};
|
|
2498
|
-
var readYieldseekerSession = (address, chainId) => {
|
|
2499
|
-
if (typeof window === "undefined") return null;
|
|
2500
|
-
const key2 = buildKey2(address, chainId);
|
|
2501
|
-
const store = storage2();
|
|
2502
|
-
clearInvalidatedSessions(store, address, chainId);
|
|
2503
|
-
let raw2 = null;
|
|
2504
|
-
try {
|
|
2505
|
-
raw2 = store?.getItem(key2) ?? null;
|
|
2506
|
-
} catch {
|
|
2507
|
-
raw2 = null;
|
|
2508
|
-
}
|
|
2509
|
-
if (raw2) {
|
|
2510
|
-
try {
|
|
2511
|
-
const parsed = JSON.parse(raw2);
|
|
2512
|
-
if (isValidSession(parsed)) return parsed.token;
|
|
2513
|
-
} catch {
|
|
2514
|
-
}
|
|
2515
|
-
memorySessions2.delete(key2);
|
|
2516
|
-
try {
|
|
2517
|
-
store?.removeItem(key2);
|
|
2518
|
-
} catch {
|
|
2519
|
-
}
|
|
2520
|
-
return null;
|
|
2521
|
-
}
|
|
2522
|
-
const cached = memorySessions2.get(key2);
|
|
2523
|
-
if (isValidSession(cached)) return cached.token;
|
|
2524
|
-
if (cached) memorySessions2.delete(key2);
|
|
2525
|
-
return null;
|
|
2526
|
-
};
|
|
2527
|
-
var writeYieldseekerSession = (address, chainId, token) => {
|
|
2528
|
-
if (typeof window === "undefined") return;
|
|
2529
|
-
const session = { token };
|
|
2530
|
-
if (!isValidSession(session)) return;
|
|
2531
|
-
const key2 = buildKey2(address, chainId);
|
|
2532
|
-
memorySessions2.set(key2, session);
|
|
2533
|
-
const store = storage2();
|
|
2534
|
-
try {
|
|
2535
|
-
store?.setItem(key2, JSON.stringify(session));
|
|
2536
|
-
} catch {
|
|
2537
|
-
}
|
|
2538
|
-
};
|
|
2539
|
-
var clearYieldseekerSession = (address, chainId) => {
|
|
2540
|
-
const key2 = buildKey2(address, chainId);
|
|
2541
|
-
memorySessions2.delete(key2);
|
|
2542
|
-
const store = storage2();
|
|
2543
|
-
clearInvalidatedSessions(store, address, chainId);
|
|
2544
|
-
try {
|
|
2545
|
-
store?.removeItem(key2);
|
|
2546
|
-
} catch {
|
|
2547
|
-
}
|
|
2548
|
-
};
|
|
2549
|
-
|
|
2550
|
-
// src/agents/yieldseeker/yieldseeker.auth.ts
|
|
2551
|
-
function resolveSiweOrigin(override) {
|
|
2552
|
-
const origin = override?.trim() || (typeof window !== "undefined" ? window.location?.origin : void 0);
|
|
2553
|
-
if (!origin || origin === "null") {
|
|
2554
|
-
throw new Error("Yieldseeker sign-in requires the requesting app's browser origin.");
|
|
2555
|
-
}
|
|
2556
|
-
const url = new URL(origin);
|
|
2557
|
-
if (url.protocol !== "https:" && url.protocol !== "http:") {
|
|
2558
|
-
throw new Error("Yieldseeker sign-in requires an HTTP or HTTPS app origin.");
|
|
2559
|
-
}
|
|
2560
|
-
if (url.username || url.password || url.pathname !== "/" || url.search || url.hash) {
|
|
2561
|
-
throw new Error("Yieldseeker SIWE override must be an origin without credentials, path, query, or fragment.");
|
|
2562
|
-
}
|
|
2563
|
-
return url;
|
|
2564
|
-
}
|
|
2565
|
-
function createYieldseekerSiweMessage(address, chainId, dependencies = {}) {
|
|
2566
|
-
const url = resolveSiweOrigin(dependencies.origin);
|
|
2567
|
-
return new import_siwe.SiweMessage({
|
|
2568
|
-
scheme: url.protocol.slice(0, -1),
|
|
2569
|
-
domain: url.host,
|
|
2570
|
-
address: (0, import_viem4.getAddress)(address),
|
|
2571
|
-
uri: url.origin,
|
|
2572
|
-
version: "1",
|
|
2573
|
-
chainId,
|
|
2574
|
-
nonce: (dependencies.nonce ?? import_siwe.generateNonce)(),
|
|
2575
|
-
issuedAt: (dependencies.now ?? (() => /* @__PURE__ */ new Date()))().toISOString()
|
|
2576
|
-
}).prepareMessage();
|
|
2577
|
-
}
|
|
2578
|
-
function encodeYieldseekerAuthToken(token) {
|
|
2579
|
-
const bytes = new TextEncoder().encode(JSON.stringify(token));
|
|
2580
|
-
let binary = "";
|
|
2581
|
-
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
2582
|
-
return btoa(binary);
|
|
2583
|
-
}
|
|
2584
|
-
var YieldseekerAuth = class {
|
|
2585
|
-
constructor(dependencies = {}) {
|
|
2586
|
-
this.dependencies = dependencies;
|
|
2587
|
-
}
|
|
2588
|
-
dependencies;
|
|
2589
|
-
tokens = /* @__PURE__ */ new Map();
|
|
2590
|
-
pending = /* @__PURE__ */ new Map();
|
|
2591
|
-
scopes = /* @__PURE__ */ new Map();
|
|
2592
|
-
key(state, chainId) {
|
|
2593
|
-
return `${state.walletAddress.toLowerCase()}:${chainId}:${resolveSiweOrigin(this.dependencies.origin).origin}`;
|
|
2594
|
-
}
|
|
2595
|
-
async getToken(state, chainId) {
|
|
2596
|
-
const key2 = this.key(state, chainId);
|
|
2597
|
-
const scope = { address: state.walletAddress, chainId };
|
|
2598
|
-
this.scopes.set(key2, scope);
|
|
2599
|
-
const cached = this.tokens.get(key2);
|
|
2600
|
-
if (cached) return cached;
|
|
2601
|
-
const persisted = readYieldseekerSession(scope.address, scope.chainId);
|
|
2602
|
-
if (persisted && this.matchesOrigin(persisted)) {
|
|
2603
|
-
this.tokens.set(key2, persisted);
|
|
2604
|
-
return persisted;
|
|
2605
|
-
}
|
|
2606
|
-
if (persisted) clearYieldseekerSession(scope.address, scope.chainId);
|
|
2607
|
-
const inFlight = this.pending.get(key2);
|
|
2608
|
-
if (inFlight) return inFlight;
|
|
2609
|
-
const request = this.sign(state, chainId).then((token) => {
|
|
2610
|
-
this.tokens.set(key2, token);
|
|
2611
|
-
writeYieldseekerSession(scope.address, scope.chainId, token);
|
|
2612
|
-
return token;
|
|
2613
|
-
});
|
|
2614
|
-
this.pending.set(key2, request);
|
|
2615
|
-
try {
|
|
2616
|
-
return await request;
|
|
2617
|
-
} finally {
|
|
2618
|
-
this.pending.delete(key2);
|
|
2619
|
-
}
|
|
2620
|
-
}
|
|
2621
|
-
matchesOrigin(token) {
|
|
2622
|
-
try {
|
|
2623
|
-
const message = new import_siwe.SiweMessage(JSON.parse(atob(token)).message);
|
|
2624
|
-
const url = resolveSiweOrigin(this.dependencies.origin);
|
|
2625
|
-
return message.domain === url.host && message.uri === url.origin && message.scheme === url.protocol.slice(0, -1);
|
|
2626
|
-
} catch {
|
|
2627
|
-
return false;
|
|
2628
|
-
}
|
|
2629
|
-
}
|
|
2630
|
-
clear(state, chainId) {
|
|
2631
|
-
if (!state || chainId === void 0) {
|
|
2632
|
-
for (const scope of this.scopes.values()) {
|
|
2633
|
-
clearYieldseekerSession(scope.address, scope.chainId);
|
|
2634
|
-
}
|
|
2635
|
-
this.tokens.clear();
|
|
2636
|
-
this.pending.clear();
|
|
2637
|
-
this.scopes.clear();
|
|
2638
|
-
return;
|
|
2639
|
-
}
|
|
2640
|
-
const key2 = this.key(state, chainId);
|
|
2641
|
-
this.tokens.delete(key2);
|
|
2642
|
-
this.pending.delete(key2);
|
|
2643
|
-
this.scopes.delete(key2);
|
|
2644
|
-
clearYieldseekerSession(state.walletAddress, chainId);
|
|
2645
|
-
}
|
|
2646
|
-
async sign(state, chainId) {
|
|
2647
|
-
const account = (0, import_viem4.getAddress)(state.walletAddress);
|
|
2648
|
-
const publicClient = (0, import_viem4.createPublicClient)({
|
|
2649
|
-
chain: import_chains2.base,
|
|
2650
|
-
transport: (0, import_viem4.custom)(state.provider)
|
|
2651
|
-
});
|
|
2652
|
-
const walletClient = (0, import_viem4.createWalletClient)({
|
|
2653
|
-
account,
|
|
2654
|
-
chain: import_chains2.base,
|
|
2655
|
-
transport: (0, import_viem4.custom)(state.provider)
|
|
2656
|
-
});
|
|
2657
|
-
await ensureWalletOnChain(
|
|
2658
|
-
publicClient,
|
|
2659
|
-
walletClient,
|
|
2660
|
-
8453
|
|
2661
|
-
);
|
|
2662
|
-
const message = createYieldseekerSiweMessage(
|
|
2663
|
-
account,
|
|
2664
|
-
chainId,
|
|
2665
|
-
this.dependencies
|
|
2666
|
-
);
|
|
2667
|
-
const signature = await walletClient.signMessage({ account, message });
|
|
2668
|
-
return encodeYieldseekerAuthToken({ message, signature });
|
|
2669
|
-
}
|
|
2670
|
-
};
|
|
2671
|
-
|
|
2672
|
-
// src/agents/yieldseeker/yieldseeker.identity-cache.ts
|
|
2673
|
-
var KEY_PREFIX3 = "owney.yieldseeker.identity.v1";
|
|
2674
|
-
var YIELDSEEKER_IDENTITY_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
2675
|
-
var memoryIdentities = /* @__PURE__ */ new Map();
|
|
2676
|
-
var storage3 = () => {
|
|
2677
|
-
if (typeof window === "undefined") return null;
|
|
2678
|
-
try {
|
|
2679
|
-
return window.localStorage;
|
|
2680
|
-
} catch {
|
|
2681
|
-
return null;
|
|
2682
|
-
}
|
|
2683
|
-
};
|
|
2684
|
-
var keyFor = (walletAddress, chainId) => `${KEY_PREFIX3}:${walletAddress.toLowerCase()}:${chainId}`;
|
|
2685
|
-
function valid(value, walletAddress, chainId, now) {
|
|
2686
|
-
return Boolean(
|
|
2687
|
-
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
|
|
2688
|
-
);
|
|
2689
|
-
}
|
|
2690
|
-
function readYieldseekerIdentity(walletAddress, chainId, now = Date.now()) {
|
|
2691
|
-
if (typeof window === "undefined") return null;
|
|
2692
|
-
const key2 = keyFor(walletAddress, chainId);
|
|
2693
|
-
const store = storage3();
|
|
2694
|
-
let parsed = null;
|
|
2695
|
-
try {
|
|
2696
|
-
const raw2 = store?.getItem(key2);
|
|
2697
|
-
parsed = raw2 ? JSON.parse(raw2) : null;
|
|
2698
|
-
} catch {
|
|
2699
|
-
parsed = null;
|
|
2700
|
-
}
|
|
2701
|
-
const candidate = parsed ?? memoryIdentities.get(key2);
|
|
2702
|
-
if (valid(candidate, walletAddress, chainId, now)) {
|
|
2703
|
-
memoryIdentities.set(key2, candidate);
|
|
2704
|
-
return { userId: candidate.userId };
|
|
2705
|
-
}
|
|
2706
|
-
memoryIdentities.delete(key2);
|
|
2707
|
-
try {
|
|
2708
|
-
store?.removeItem(key2);
|
|
2709
|
-
} catch {
|
|
2710
|
-
}
|
|
2711
|
-
return null;
|
|
2712
|
-
}
|
|
2713
|
-
function writeYieldseekerIdentity(walletAddress, chainId, userId, now = Date.now()) {
|
|
2714
|
-
if (typeof window === "undefined") return;
|
|
2715
|
-
const identity = {
|
|
2716
|
-
userId,
|
|
2717
|
-
walletAddress,
|
|
2718
|
-
chainId,
|
|
2719
|
-
expiresAt: now + YIELDSEEKER_IDENTITY_TTL_MS
|
|
2720
|
-
};
|
|
2721
|
-
if (!valid(identity, walletAddress, chainId, now)) return;
|
|
2722
|
-
const key2 = keyFor(walletAddress, chainId);
|
|
2723
|
-
memoryIdentities.set(key2, identity);
|
|
2724
|
-
try {
|
|
2725
|
-
storage3()?.setItem(key2, JSON.stringify(identity));
|
|
2726
|
-
} catch {
|
|
2727
|
-
}
|
|
2728
|
-
}
|
|
2729
|
-
function clearYieldseekerIdentity(walletAddress, chainId) {
|
|
2730
|
-
const key2 = keyFor(walletAddress, chainId);
|
|
2731
|
-
memoryIdentities.delete(key2);
|
|
2732
|
-
try {
|
|
2733
|
-
storage3()?.removeItem(key2);
|
|
2734
|
-
} catch {
|
|
2735
|
-
}
|
|
2736
|
-
}
|
|
2737
|
-
|
|
2738
|
-
// src/agents/yieldseeker/yieldseeker.client.ts
|
|
2739
|
-
var DEFAULT_ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
2740
|
-
function getYieldseekerProxyBaseUrl(routingApiBaseUrl = DEFAULT_ROUTING_API_BASE_URL) {
|
|
2741
|
-
return `${routingApiBaseUrl.replace(/\/$/, "")}/api/v1/agent/yieldseeker`;
|
|
2742
|
-
}
|
|
2743
|
-
var YIELDSEEKER_API_BASE_URL = getYieldseekerProxyBaseUrl();
|
|
2744
|
-
var YieldseekerApiError = class extends Error {
|
|
2745
|
-
constructor(status, providerCode, responseFields) {
|
|
2746
|
-
super(`Yieldseeker request failed (${status}): ${providerCode}`);
|
|
2747
|
-
this.status = status;
|
|
2748
|
-
this.providerCode = providerCode;
|
|
2749
|
-
this.responseFields = responseFields;
|
|
2750
|
-
this.name = "YieldseekerApiError";
|
|
2751
|
-
}
|
|
2752
|
-
status;
|
|
2753
|
-
providerCode;
|
|
2754
|
-
responseFields;
|
|
2755
|
-
get isAuthenticationError() {
|
|
2756
|
-
return this.status === 401 || this.status === 403;
|
|
2757
|
-
}
|
|
2758
|
-
};
|
|
2759
|
-
function providerError(body, fallback) {
|
|
2760
|
-
if (!body || typeof body !== "object") return { code: fallback };
|
|
2761
|
-
const record = body;
|
|
2762
|
-
return {
|
|
2763
|
-
code: typeof record.message === "string" ? record.message : fallback,
|
|
2764
|
-
fields: record.fields && typeof record.fields === "object" ? record.fields : void 0
|
|
2765
|
-
};
|
|
2766
|
-
}
|
|
2767
|
-
var YieldseekerApiClient = class {
|
|
2768
|
-
constructor(owneyApiKey, baseUrl = YIELDSEEKER_API_BASE_URL, fetchFn = fetch) {
|
|
2769
|
-
this.owneyApiKey = owneyApiKey;
|
|
2770
|
-
this.baseUrl = baseUrl;
|
|
2771
|
-
this.fetchFn = fetchFn;
|
|
2772
|
-
}
|
|
2773
|
-
owneyApiKey;
|
|
2774
|
-
baseUrl;
|
|
2775
|
-
fetchFn;
|
|
2776
|
-
async request(path, options = {}) {
|
|
2777
|
-
const controller = new AbortController();
|
|
2778
|
-
const timer = setTimeout(
|
|
2779
|
-
() => controller.abort(),
|
|
2780
|
-
options.timeoutMs ?? 15e3
|
|
2781
|
-
);
|
|
2782
|
-
try {
|
|
2783
|
-
const response = await this.fetchFn(`${this.baseUrl}${path}`, {
|
|
2784
|
-
method: options.method ?? "GET",
|
|
2785
|
-
headers: {
|
|
2786
|
-
"Content-Type": "application/json",
|
|
2787
|
-
"x-owney-api-key": this.owneyApiKey,
|
|
2788
|
-
...options.signature ? { Authorization: `Signature ${options.signature}` } : {}
|
|
2789
|
-
},
|
|
2790
|
-
body: options.body ? JSON.stringify(options.body) : void 0,
|
|
2791
|
-
signal: controller.signal
|
|
2792
|
-
});
|
|
2793
|
-
const payload = await response.json().catch(() => null);
|
|
2794
|
-
if (!response.ok) {
|
|
2795
|
-
const error = providerError(payload, `HTTP_${response.status}`);
|
|
2796
|
-
throw new YieldseekerApiError(
|
|
2797
|
-
response.status,
|
|
2798
|
-
error.code,
|
|
2799
|
-
error.fields
|
|
2800
|
-
);
|
|
2801
|
-
}
|
|
2802
|
-
if (payload && typeof payload === "object" && payload.success === true && "data" in payload) {
|
|
2803
|
-
return payload.data;
|
|
2804
|
-
}
|
|
2805
|
-
return payload;
|
|
2806
|
-
} catch (error) {
|
|
2807
|
-
if (error instanceof YieldseekerApiError) throw error;
|
|
2808
|
-
if (error instanceof DOMException && error.name === "AbortError") {
|
|
2809
|
-
throw new YieldseekerApiError(408, "REQUEST_TIMEOUT");
|
|
2810
|
-
}
|
|
2811
|
-
throw new YieldseekerApiError(0, "NETWORK_ERROR", {
|
|
2812
|
-
cause: error instanceof Error ? error.message : String(error)
|
|
2813
|
-
});
|
|
2814
|
-
} finally {
|
|
2815
|
-
clearTimeout(timer);
|
|
2816
|
-
}
|
|
2817
|
-
}
|
|
2818
|
-
};
|
|
2819
|
-
|
|
2820
|
-
// src/agents/yieldseeker/yieldseeker.mapper.ts
|
|
2821
|
-
var import_viem5 = require("viem");
|
|
2822
|
-
|
|
2823
|
-
// src/agents/yieldseeker/yieldseeker.types.ts
|
|
2824
|
-
var YIELDSEEKER_ASSET_METADATA = {
|
|
2825
|
-
USDC: {
|
|
2826
|
-
address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
2827
|
-
decimals: 6
|
|
2828
|
-
},
|
|
2829
|
-
WETH: {
|
|
2830
|
-
address: "0x4200000000000000000000000000000000000006",
|
|
2831
|
-
decimals: 18
|
|
2832
|
-
}
|
|
2833
|
-
};
|
|
2834
|
-
|
|
2835
|
-
// src/agents/yieldseeker/yieldseeker.mapper.ts
|
|
2836
|
-
function invalid(endpoint, detail) {
|
|
2837
|
-
throw new OwneyError(
|
|
2838
|
-
"AGENT_INVALID_RESPONSE",
|
|
2839
|
-
`Yieldseeker returned an invalid ${endpoint} response: ${detail}.`,
|
|
2840
|
-
{ endpoint, detail },
|
|
2841
|
-
"yieldseeker"
|
|
2842
|
-
);
|
|
2843
|
-
}
|
|
2844
|
-
function raw(value, endpoint) {
|
|
2845
|
-
if (typeof value !== "string" || !/^-?[0-9]+$/.test(value)) {
|
|
2846
|
-
return invalid(endpoint, "expected a base-10 integer string");
|
|
2847
|
-
}
|
|
2848
|
-
return BigInt(value);
|
|
2849
|
-
}
|
|
2850
|
-
function decimal(value, decimals, endpoint) {
|
|
2851
|
-
return (0, import_viem5.formatUnits)(raw(value, endpoint), decimals);
|
|
2852
|
-
}
|
|
2853
|
-
function usd(rawAmount, decimals, price) {
|
|
2854
|
-
return Number((0, import_viem5.formatUnits)(rawAmount, decimals)) * price;
|
|
2855
|
-
}
|
|
2856
|
-
function percent(value) {
|
|
2857
|
-
const result = Number(value);
|
|
2858
|
-
return Number.isFinite(result) ? result * 100 : 0;
|
|
2859
|
-
}
|
|
2860
|
-
var YIELDSEEKER_POSITIVE_YIELD_FEE_RATE = 0.1;
|
|
2861
|
-
function publicApyAfterYieldseekerFee(value) {
|
|
2862
|
-
const grossPercent = percent(value);
|
|
2863
|
-
if (grossPercent <= 0) return grossPercent;
|
|
2864
|
-
const netPercent = grossPercent * (1 - YIELDSEEKER_POSITIVE_YIELD_FEE_RATE);
|
|
2865
|
-
return Math.round(netPercent * 1e12) / 1e12;
|
|
2866
|
-
}
|
|
2867
|
-
function riskAdjustedApyForDays(option, days) {
|
|
2868
|
-
if (days === "7D") return option.riskAdjustedApy7dAverage;
|
|
2869
|
-
if (days === "30D") return option.riskAdjustedApy30dAverage;
|
|
2870
|
-
return (option.riskAdjustedApy7dAverage + option.riskAdjustedApy30dAverage) / 2;
|
|
2871
|
-
}
|
|
2872
|
-
function assetAddressValue(record, address) {
|
|
2873
|
-
const entry = Object.entries(record).find(
|
|
2874
|
-
([key2]) => key2.toLowerCase() === address.toLowerCase()
|
|
2875
|
-
);
|
|
2876
|
-
return entry?.[1] ?? "0";
|
|
2877
|
-
}
|
|
2878
|
-
function position(value, asset, baseAssetDecimals) {
|
|
2879
|
-
const option = value?.yieldOption;
|
|
2880
|
-
if (!option || typeof option.provider !== "string" || typeof option.name !== "string" || typeof option.address !== "string" || !(0, import_viem5.isAddress)(option.address)) {
|
|
2881
|
-
return invalid("yield positions", "missing vault metadata");
|
|
2882
|
-
}
|
|
2883
|
-
return {
|
|
2884
|
-
chain: "BASE",
|
|
2885
|
-
protocol: option.provider,
|
|
2886
|
-
protocolId: option.address,
|
|
2887
|
-
pool: option.name,
|
|
2888
|
-
asset,
|
|
2889
|
-
// `assetsRaw` is the ERC-4626 vault-share quantity, whose decimals can
|
|
2890
|
-
// differ from the underlying asset. Yieldseeker already converts it to
|
|
2891
|
-
// underlying base-asset units in `assetsBase`; pair that value with the
|
|
2892
|
-
// snapshot's corresponding `baseAssetDecimals` for display. Keep the raw
|
|
2893
|
-
// share quantity separately because withdraw-from-position expects it.
|
|
2894
|
-
amount: decimal(
|
|
2895
|
-
value.assetsBase,
|
|
2896
|
-
baseAssetDecimals,
|
|
2897
|
-
"yield positions"
|
|
2898
|
-
),
|
|
2899
|
-
amountRaw: String(value.assetsRaw),
|
|
2900
|
-
apy: percent(option.riskAdjustedApy),
|
|
2901
|
-
tvl: Number(option.totalDepositsUsd),
|
|
2902
|
-
liquidity: Number(option.withdrawableDepositsUsd)
|
|
2903
|
-
};
|
|
2904
|
-
}
|
|
2905
|
-
function mapYieldseekerBalances(contexts) {
|
|
2906
|
-
const tokens = [];
|
|
2907
|
-
const assetBalances = [];
|
|
2908
|
-
const positions = [];
|
|
2909
|
-
let totalUsd = 0;
|
|
2910
|
-
for (const context of contexts) {
|
|
2911
|
-
const metadata = YIELDSEEKER_ASSET_METADATA[context.asset];
|
|
2912
|
-
assetBalances.push({
|
|
2913
|
-
chain: "BASE",
|
|
2914
|
-
chainId: 8453,
|
|
2915
|
-
asset: context.asset,
|
|
2916
|
-
amount: decimal(context.snapshot.totalValueBase, context.snapshot.baseAssetDecimals, "snapshot")
|
|
2917
|
-
});
|
|
2918
|
-
const idle = assetAddressValue(
|
|
2919
|
-
context.snapshot.tokenBalances,
|
|
2920
|
-
metadata.address
|
|
2921
|
-
);
|
|
2922
|
-
tokens.push({
|
|
2923
|
-
chain: "BASE",
|
|
2924
|
-
chainId: 8453,
|
|
2925
|
-
asset: context.asset,
|
|
2926
|
-
amount: decimal(idle, metadata.decimals, "snapshot")
|
|
2927
|
-
});
|
|
2928
|
-
positions.push(
|
|
2929
|
-
...context.positions.map(
|
|
2930
|
-
(entry) => position(
|
|
2931
|
-
entry,
|
|
2932
|
-
context.asset,
|
|
2933
|
-
context.snapshot.baseAssetDecimals
|
|
2934
|
-
)
|
|
2935
|
-
)
|
|
2936
|
-
);
|
|
2937
|
-
totalUsd += usd(
|
|
2938
|
-
raw(context.snapshot.totalValueBase, "snapshot"),
|
|
2939
|
-
context.snapshot.baseAssetDecimals,
|
|
2940
|
-
context.snapshot.baseAssetPriceUsd
|
|
2941
|
-
);
|
|
2942
|
-
}
|
|
2943
|
-
return {
|
|
2944
|
-
...contexts.length === 1 ? { smartWallet: contexts[0].wallet.walletAddress } : {},
|
|
2945
|
-
totalBalance: String(totalUsd),
|
|
2946
|
-
totalBalanceAsset: "usdc",
|
|
2947
|
-
assetBalances,
|
|
2948
|
-
tokens,
|
|
2949
|
-
positions
|
|
2950
|
-
};
|
|
2951
|
-
}
|
|
2952
|
-
function mapYieldseekerEarnings(contexts) {
|
|
2953
|
-
const tokens = [];
|
|
2954
|
-
let lifetimeEarnings = 0;
|
|
2955
|
-
for (const context of contexts) {
|
|
2956
|
-
const amount = raw(context.snapshot.cumulativeYieldBase, "snapshot");
|
|
2957
|
-
tokens.push({
|
|
2958
|
-
chain: "BASE",
|
|
2959
|
-
chainId: 8453,
|
|
2960
|
-
asset: context.asset,
|
|
2961
|
-
amount: (0, import_viem5.formatUnits)(amount, context.snapshot.baseAssetDecimals)
|
|
2962
|
-
});
|
|
2963
|
-
lifetimeEarnings += usd(
|
|
2964
|
-
amount,
|
|
2965
|
-
context.snapshot.baseAssetDecimals,
|
|
2966
|
-
context.snapshot.baseAssetPriceUsd
|
|
2967
|
-
);
|
|
2968
|
-
}
|
|
2969
|
-
return {
|
|
2970
|
-
smartWallet: contexts[0]?.wallet.walletAddress ?? "0x0000000000000000000000000000000000000000",
|
|
2971
|
-
lifetimeEarnings,
|
|
2972
|
-
tokens
|
|
2973
|
-
};
|
|
2974
|
-
}
|
|
2975
|
-
function apyForDays(snapshot, days) {
|
|
2976
|
-
if (days === "7D") return percent(snapshot.apy7d);
|
|
2977
|
-
if (days === "30D") return percent(snapshot.apy30d);
|
|
2978
|
-
return percent((snapshot.apy7d + snapshot.apy30d) / 2);
|
|
2979
|
-
}
|
|
2980
|
-
function dailyApy(point) {
|
|
2981
|
-
const total = raw(point.totalValueBase, "historic position");
|
|
2982
|
-
const earned = raw(point.dailyYieldBase, "historic position");
|
|
2983
|
-
const principal = total - earned;
|
|
2984
|
-
if (principal <= 0n || earned === 0n) return 0;
|
|
2985
|
-
return Number(earned) / Number(principal) * 365 * 100;
|
|
2986
|
-
}
|
|
2987
|
-
function aggregateHistory(contexts, dayCount) {
|
|
2988
|
-
const byDate = /* @__PURE__ */ new Map();
|
|
2989
|
-
for (const context of contexts) {
|
|
2990
|
-
const points = context.historic?.dailyYieldSnapshots ?? [];
|
|
2991
|
-
for (const point of points.slice(-dayCount)) {
|
|
2992
|
-
const valueUsd = usd(
|
|
2993
|
-
raw(point.totalValueBase, "historic position"),
|
|
2994
|
-
point.baseAssetDecimals,
|
|
2995
|
-
point.baseAssetPriceUsd
|
|
2996
|
-
);
|
|
2997
|
-
const current = byDate.get(point.date) ?? { weighted: 0, valueUsd: 0 };
|
|
2998
|
-
current.weighted += dailyApy(point) * valueUsd;
|
|
2999
|
-
current.valueUsd += valueUsd;
|
|
3000
|
-
byDate.set(point.date, current);
|
|
3001
|
-
}
|
|
3002
|
-
}
|
|
3003
|
-
return [...byDate.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([date, value]) => ({
|
|
3004
|
-
date,
|
|
3005
|
-
apy: value.valueUsd > 0 ? value.weighted / value.valueUsd : 0
|
|
3006
|
-
}));
|
|
3007
|
-
}
|
|
3008
|
-
function mapYieldseekerApy(walletAddress, contexts, days) {
|
|
3009
|
-
let weighted = 0;
|
|
3010
|
-
let totalUsd = 0;
|
|
3011
|
-
const byAsset = {};
|
|
3012
|
-
for (const context of contexts) {
|
|
3013
|
-
const valueUsd = usd(
|
|
3014
|
-
raw(context.snapshot.totalValueBase, "snapshot"),
|
|
3015
|
-
context.snapshot.baseAssetDecimals,
|
|
3016
|
-
context.snapshot.baseAssetPriceUsd
|
|
3017
|
-
);
|
|
3018
|
-
const apy = apyForDays(context.snapshot, days);
|
|
3019
|
-
weighted += apy * valueUsd;
|
|
3020
|
-
totalUsd += valueUsd;
|
|
3021
|
-
byAsset[context.asset] = apy;
|
|
3022
|
-
}
|
|
3023
|
-
const dayCount = Number(days.slice(0, -1));
|
|
3024
|
-
return {
|
|
3025
|
-
walletAddress,
|
|
3026
|
-
weightedApyAfterFee: totalUsd > 0 ? weighted / totalUsd : 0,
|
|
3027
|
-
apyByChainAndAsset: { 8453: byAsset },
|
|
3028
|
-
history: aggregateHistory(contexts, dayCount)
|
|
3029
|
-
};
|
|
3030
|
-
}
|
|
3031
|
-
function actionType(value) {
|
|
3032
|
-
const normalized = value.toLowerCase();
|
|
3033
|
-
if (normalized.includes("deposit")) return "Deposit";
|
|
3034
|
-
if (normalized.includes("withdraw")) return "Withdraw";
|
|
3035
|
-
if (normalized.includes("yield") || normalized.includes("earn"))
|
|
3036
|
-
return "Earned";
|
|
3037
|
-
return "Rebalance";
|
|
3038
|
-
}
|
|
3039
|
-
function transactionHashes(details) {
|
|
3040
|
-
if (!details) return [];
|
|
3041
|
-
const values = [
|
|
3042
|
-
details.transactionHash,
|
|
3043
|
-
details.txHash,
|
|
3044
|
-
...Array.isArray(details.transactionHashes) ? details.transactionHashes : [],
|
|
3045
|
-
...Array.isArray(details.txHashes) ? details.txHashes : []
|
|
3046
|
-
];
|
|
3047
|
-
return values.filter(
|
|
3048
|
-
(value) => typeof value === "string" && /^0x[a-fA-F0-9]{64}$/.test(value)
|
|
3049
|
-
).filter((value, index, all) => all.indexOf(value) === index);
|
|
3050
|
-
}
|
|
3051
|
-
function actionEntry(action) {
|
|
3052
|
-
if (action.actionType.toLowerCase().includes("withdraw")) return void 0;
|
|
3053
|
-
return {
|
|
3054
|
-
agent: "yieldseeker",
|
|
3055
|
-
action: actionType(action.actionType),
|
|
3056
|
-
date: action.createdDate,
|
|
3057
|
-
oldApy: null,
|
|
3058
|
-
newApy: null,
|
|
3059
|
-
transactions: [
|
|
3060
|
-
{
|
|
3061
|
-
txHashes: transactionHashes(action.details),
|
|
3062
|
-
chainId: 8453
|
|
3063
|
-
}
|
|
3064
|
-
],
|
|
3065
|
-
rebalanceLog: []
|
|
3066
|
-
};
|
|
3067
|
-
}
|
|
3068
|
-
function movementEntry(movement, wallet, agent, asset, ownerAddress, vaultAddresses) {
|
|
3069
|
-
const from = movement.fromAddress.toLowerCase();
|
|
3070
|
-
const to = movement.toAddress.toLowerCase();
|
|
3071
|
-
const owner = ownerAddress.toLowerCase();
|
|
3072
|
-
const agentWallet = wallet.walletAddress.toLowerCase();
|
|
3073
|
-
const baseAsset = agent.assetAddress.toLowerCase();
|
|
3074
|
-
if (movement.chainId !== agent.chainId || movement.assetAddress.toLowerCase() !== baseAsset) {
|
|
3075
|
-
return void 0;
|
|
3076
|
-
}
|
|
3077
|
-
let action;
|
|
3078
|
-
if (from === owner && to === agentWallet) {
|
|
3079
|
-
action = "Top up";
|
|
3080
|
-
} else if (from === agentWallet && to === owner) {
|
|
3081
|
-
action = "Withdraw";
|
|
3082
|
-
} else if (from === agentWallet && vaultAddresses.has(to)) {
|
|
3083
|
-
action = "Deposit";
|
|
3084
|
-
}
|
|
3085
|
-
if (!action) return void 0;
|
|
3086
|
-
return {
|
|
3087
|
-
agent: "yieldseeker",
|
|
3088
|
-
action,
|
|
3089
|
-
date: movement.blockDate,
|
|
3090
|
-
oldApy: null,
|
|
3091
|
-
newApy: null,
|
|
3092
|
-
transactions: [
|
|
3093
|
-
{
|
|
3094
|
-
txHashes: [movement.transactionHash],
|
|
3095
|
-
chainId: agent.chainId,
|
|
3096
|
-
tokenSymbol: asset,
|
|
3097
|
-
amount: decimal(
|
|
3098
|
-
movement.assetAmount,
|
|
3099
|
-
YIELDSEEKER_ASSET_METADATA[asset].decimals,
|
|
3100
|
-
"historic position"
|
|
3101
|
-
)
|
|
3102
|
-
}
|
|
3103
|
-
],
|
|
3104
|
-
rebalanceLog: []
|
|
3105
|
-
};
|
|
3106
|
-
}
|
|
3107
|
-
function mapYieldseekerHistory(contexts, options) {
|
|
3108
|
-
const entries = contexts.flatMap((context) => {
|
|
3109
|
-
const vaultAddresses = new Set(
|
|
3110
|
-
context.positions.map(
|
|
3111
|
-
(position2) => position2.yieldOption.address.toLowerCase()
|
|
3112
|
-
)
|
|
3113
|
-
);
|
|
3114
|
-
return [
|
|
3115
|
-
...(context.historic?.movements ?? []).map(
|
|
3116
|
-
(movement) => movementEntry(
|
|
3117
|
-
movement,
|
|
3118
|
-
context.wallet,
|
|
3119
|
-
context.agent,
|
|
3120
|
-
context.asset,
|
|
3121
|
-
options.ownerAddress,
|
|
3122
|
-
vaultAddresses
|
|
3123
|
-
)
|
|
3124
|
-
),
|
|
3125
|
-
...(context.actions ?? []).map(actionEntry)
|
|
3126
|
-
].filter((entry) => entry !== void 0);
|
|
3127
|
-
});
|
|
3128
|
-
const filtered = entries.filter(
|
|
3129
|
-
(entry) => (!options.fromDate || entry.date >= options.fromDate) && (!options.toDate || entry.date <= options.toDate)
|
|
3130
|
-
).filter((entry, index, all) => {
|
|
3131
|
-
const transactionHash = entry.transactions[0]?.txHashes[0];
|
|
3132
|
-
if (!transactionHash) return true;
|
|
3133
|
-
return all.findIndex(
|
|
3134
|
-
(candidate) => candidate.action === entry.action && candidate.transactions[0]?.txHashes[0] === transactionHash
|
|
3135
|
-
) === index;
|
|
3136
|
-
}).sort((left, right) => right.date.localeCompare(left.date));
|
|
3137
|
-
return {
|
|
3138
|
-
data: filtered.slice(0, options.limit),
|
|
3139
|
-
// v1 returns the whole action/movement collection and defines no cursor.
|
|
3140
|
-
// Report a terminal page so callers never loop over the same prefix.
|
|
3141
|
-
hasMore: false
|
|
3142
|
-
};
|
|
3143
|
-
}
|
|
3144
|
-
function mapYieldseekerProfile(address, contexts) {
|
|
3145
|
-
const protocols = /* @__PURE__ */ new Set();
|
|
3146
|
-
for (const context of contexts) {
|
|
3147
|
-
for (const current of context.positions) {
|
|
3148
|
-
if (current.yieldOption?.provider) {
|
|
3149
|
-
protocols.add(String(current.yieldOption.provider));
|
|
3150
|
-
}
|
|
3151
|
-
}
|
|
3152
|
-
}
|
|
3153
|
-
return {
|
|
3154
|
-
address,
|
|
3155
|
-
smartWallet: contexts[0]?.wallet.walletAddress ?? "0x0000000000000000000000000000000000000000",
|
|
3156
|
-
chains: contexts.length > 0 ? [8453] : [],
|
|
3157
|
-
hasActiveSessionKey: contexts.some(
|
|
3158
|
-
(context) => context.wallet.initializedDate != null
|
|
3159
|
-
),
|
|
3160
|
-
protocols: [...protocols]
|
|
3161
|
-
};
|
|
3162
|
-
}
|
|
3163
|
-
function mapYieldseekerAgentApy(options, days) {
|
|
3164
|
-
const perAsset = {};
|
|
3165
|
-
const all = [];
|
|
3166
|
-
for (const entry of options) {
|
|
3167
|
-
const apys = entry.yieldOptions.map(
|
|
3168
|
-
(option) => publicApyAfterYieldseekerFee(riskAdjustedApyForDays(option, days))
|
|
3169
|
-
).filter(Number.isFinite);
|
|
3170
|
-
if (apys.length === 0) continue;
|
|
3171
|
-
const average = apys.reduce((sum, value) => sum + value, 0) / apys.length;
|
|
3172
|
-
perAsset[entry.asset] = average;
|
|
3173
|
-
all.push(average);
|
|
3174
|
-
}
|
|
3175
|
-
return {
|
|
3176
|
-
averageApy: all.length > 0 ? all.reduce((sum, value) => sum + value, 0) / all.length : 0,
|
|
3177
|
-
detailedApys: { apyPerAsset: { 8453: perAsset } }
|
|
3178
|
-
};
|
|
3179
|
-
}
|
|
3180
|
-
|
|
3181
|
-
// src/agents/yieldseeker/yieldseeker.agent.ts
|
|
3182
|
-
var OWNEY_AGENT_NAME = "owney";
|
|
3183
|
-
var YIELDSEEKER_USERNAME_PREFIX = "owney_";
|
|
3184
|
-
var YIELDSEEKER_USERNAME_RANDOM_LENGTH = 14;
|
|
3185
|
-
var YIELDSEEKER_USERNAME_CREATE_ATTEMPTS = 3;
|
|
3186
|
-
function generateYieldseekerUsername() {
|
|
3187
|
-
const suffix = globalThis.crypto.randomUUID().replaceAll("-", "").slice(0, YIELDSEEKER_USERNAME_RANDOM_LENGTH).toLowerCase();
|
|
3188
|
-
return `${YIELDSEEKER_USERNAME_PREFIX}${suffix}`;
|
|
3189
|
-
}
|
|
3190
|
-
function isUsernameConflict(error) {
|
|
3191
|
-
if (!(error instanceof YieldseekerApiError)) return false;
|
|
3192
|
-
const code = error.providerCode.toUpperCase();
|
|
3193
|
-
return code.includes("USERNAME") && (code.includes("TAKEN") || code.includes("EXIST") || code.includes("UNAVAILABLE") || code.includes("IN_USE"));
|
|
3194
|
-
}
|
|
3195
|
-
var YIELDSEEKER_AGENT_WALLET_ABI = [
|
|
3196
|
-
{
|
|
3197
|
-
type: "function",
|
|
3198
|
-
name: "withdrawAssetToUser",
|
|
3199
|
-
stateMutability: "nonpayable",
|
|
3200
|
-
inputs: [
|
|
3201
|
-
{ name: "recipient", type: "address" },
|
|
3202
|
-
{ name: "asset", type: "address" },
|
|
3203
|
-
{ name: "amount", type: "uint256" }
|
|
3204
|
-
],
|
|
3205
|
-
outputs: []
|
|
3206
|
-
},
|
|
3207
|
-
{
|
|
3208
|
-
type: "function",
|
|
3209
|
-
name: "withdrawAllAssetToUser",
|
|
3210
|
-
stateMutability: "nonpayable",
|
|
3211
|
-
inputs: [
|
|
3212
|
-
{ name: "recipient", type: "address" },
|
|
3213
|
-
{ name: "asset", type: "address" }
|
|
3214
|
-
],
|
|
3215
|
-
outputs: []
|
|
3216
|
-
}
|
|
3217
|
-
];
|
|
3218
|
-
function query(params) {
|
|
3219
|
-
const search = new URLSearchParams();
|
|
3220
|
-
for (const [key2, value] of Object.entries(params)) {
|
|
3221
|
-
if (value !== void 0) search.set(key2, String(value));
|
|
3222
|
-
}
|
|
3223
|
-
const encoded = search.toString();
|
|
3224
|
-
return encoded ? `?${encoded}` : "";
|
|
3225
|
-
}
|
|
3226
|
-
var YieldseekerAgent = class {
|
|
3227
|
-
id = "yieldseeker";
|
|
3228
|
-
balanceComposition = "tokens-plus-positions";
|
|
3229
|
-
supportedChainIds = [8453];
|
|
3230
|
-
supportedAssets = [
|
|
3231
|
-
{
|
|
3232
|
-
chainId: 8453,
|
|
3233
|
-
chain: "BASE",
|
|
3234
|
-
assets: [
|
|
3235
|
-
{ symbol: "USDC", minDepositAmount: "10000000" },
|
|
3236
|
-
{ symbol: "WETH", minDepositAmount: "1" }
|
|
3237
|
-
]
|
|
3238
|
-
}
|
|
3239
|
-
];
|
|
3240
|
-
api;
|
|
3241
|
-
auth;
|
|
3242
|
-
transactionExecutor;
|
|
3243
|
-
unwindReceiptWaiter;
|
|
3244
|
-
agentContexts = /* @__PURE__ */ new Map();
|
|
3245
|
-
users = /* @__PURE__ */ new Map();
|
|
3246
|
-
pendingAgents = /* @__PURE__ */ new Map();
|
|
3247
|
-
constructor(owneyApiKey, options = {}) {
|
|
3248
|
-
this.api = new YieldseekerApiClient(
|
|
3249
|
-
owneyApiKey,
|
|
3250
|
-
options.baseUrl ?? getYieldseekerProxyBaseUrl(),
|
|
3251
|
-
options.fetchFn
|
|
3252
|
-
);
|
|
3253
|
-
this.auth = new YieldseekerAuth(options.auth);
|
|
3254
|
-
this.transactionExecutor = options.transactionExecutor;
|
|
3255
|
-
this.unwindReceiptWaiter = options.unwindReceiptWaiter;
|
|
3256
|
-
}
|
|
3257
|
-
async disconnect() {
|
|
3258
|
-
this.auth.clear();
|
|
3259
|
-
for (const key2 of this.users.keys()) {
|
|
3260
|
-
const [walletAddress, chainId] = key2.split(":");
|
|
3261
|
-
clearYieldseekerIdentity(walletAddress, Number(chainId));
|
|
3262
|
-
}
|
|
3263
|
-
this.users.clear();
|
|
3264
|
-
this.agentContexts.clear();
|
|
3265
|
-
this.pendingAgents.clear();
|
|
3266
|
-
}
|
|
3267
|
-
async activateAgent(state, chainId, asset) {
|
|
3268
|
-
this.assertChain(chainId);
|
|
3269
|
-
const targetAsset = asset ?? "USDC";
|
|
3270
|
-
this.assertAsset(targetAsset);
|
|
3271
|
-
await this.ensureAgent(state, chainId, targetAsset);
|
|
3272
|
-
}
|
|
3273
|
-
async deposit(state, chainId, amount, asset, depositCallback) {
|
|
3274
|
-
this.assertChain(chainId);
|
|
3275
|
-
this.assertAsset(asset);
|
|
3276
|
-
if (BigInt(amount) <= 0n) {
|
|
3277
|
-
throw new OwneyError(
|
|
3278
|
-
"DEPOSIT_AMOUNT_BELOW_MINIMUM",
|
|
3279
|
-
"Yieldseeker deposits must be greater than zero.",
|
|
3280
|
-
{ amount, minDepositAmount: "1" },
|
|
3281
|
-
this.id
|
|
3282
|
-
);
|
|
3283
|
-
}
|
|
3284
|
-
const context = await this.ensureAgent(state, chainId, asset);
|
|
3285
|
-
let txHash;
|
|
3286
|
-
try {
|
|
3287
|
-
if (depositCallback) {
|
|
3288
|
-
provideDepositVerificationContext(depositCallback, {
|
|
3289
|
-
agentId: "yieldseeker",
|
|
3290
|
-
signature: await this.auth.getToken(state, chainId),
|
|
3291
|
-
userId: context.user.userId,
|
|
3292
|
-
yieldseekerAgentId: context.agent.agentId
|
|
3293
|
-
});
|
|
3294
|
-
txHash = await depositCallback(
|
|
3295
|
-
context.wallet.walletAddress,
|
|
3296
|
-
chainId,
|
|
3297
|
-
amount
|
|
3298
|
-
);
|
|
3299
|
-
await this.waitForReceipt(state, chainId, txHash);
|
|
3300
|
-
} else {
|
|
3301
|
-
txHash = await this.submitTransaction(state, chainId, {
|
|
3302
|
-
from: (0, import_viem6.getAddress)(state.walletAddress),
|
|
3303
|
-
to: YIELDSEEKER_ASSET_METADATA[asset].address,
|
|
3304
|
-
data: (0, import_viem6.encodeFunctionData)({
|
|
3305
|
-
abi: import_viem6.erc20Abi,
|
|
3306
|
-
functionName: "transfer",
|
|
3307
|
-
args: [(0, import_viem6.getAddress)(context.wallet.walletAddress), BigInt(amount)]
|
|
3308
|
-
}),
|
|
3309
|
-
value: "0",
|
|
3310
|
-
chainId
|
|
3311
|
-
});
|
|
3312
|
-
}
|
|
3313
|
-
await this.deployAfterFunding(state, chainId, context);
|
|
3314
|
-
} finally {
|
|
3315
|
-
await this.refreshSnapshotAfterMovement(
|
|
3316
|
-
state,
|
|
3317
|
-
chainId,
|
|
3318
|
-
context,
|
|
3319
|
-
"deposit"
|
|
3320
|
-
);
|
|
3321
|
-
}
|
|
3322
|
-
return {
|
|
3323
|
-
txHash,
|
|
3324
|
-
smartWallet: context.wallet.walletAddress,
|
|
3325
|
-
amount
|
|
3326
|
-
};
|
|
3327
|
-
}
|
|
3328
|
-
async withdraw(state, chainId, asset, amount) {
|
|
3329
|
-
this.assertChain(chainId);
|
|
3330
|
-
this.assertAsset(asset);
|
|
3331
|
-
if (amount !== void 0 && BigInt(amount) <= 0n) {
|
|
3332
|
-
throw new OwneyError(
|
|
3333
|
-
"WITHDRAW_FAILED",
|
|
3334
|
-
"Yieldseeker withdrawals must be greater than zero.",
|
|
3335
|
-
{ amount },
|
|
3336
|
-
this.id
|
|
3337
|
-
);
|
|
3338
|
-
}
|
|
3339
|
-
const context = await this.findAgent(state, chainId, asset);
|
|
3340
|
-
if (!context) {
|
|
3341
|
-
throw new OwneyError(
|
|
3342
|
-
"WITHDRAW_INSUFFICIENT_BALANCE",
|
|
3343
|
-
`No Yieldseeker ${asset} agent exists for this wallet.`,
|
|
3344
|
-
{ asset, available: "0" },
|
|
3345
|
-
this.id
|
|
3346
|
-
);
|
|
3347
|
-
}
|
|
3348
|
-
try {
|
|
3349
|
-
const portfolio = await this.loadPortfolioContext(
|
|
3350
|
-
state,
|
|
3351
|
-
chainId,
|
|
3352
|
-
context
|
|
3353
|
-
);
|
|
3354
|
-
const metadata = YIELDSEEKER_ASSET_METADATA[asset];
|
|
3355
|
-
const idleEntry = Object.entries(portfolio.snapshot.tokenBalances).find(
|
|
3356
|
-
([address]) => address.toLowerCase() === metadata.address.toLowerCase()
|
|
3357
|
-
);
|
|
3358
|
-
const idle = BigInt(idleEntry?.[1] ?? "0");
|
|
3359
|
-
const deployed = portfolio.positions.reduce(
|
|
3360
|
-
(total, position2) => total + BigInt(position2.withdrawableAssetsRaw),
|
|
3361
|
-
0n
|
|
3362
|
-
);
|
|
3363
|
-
const totalAvailable = idle + deployed;
|
|
3364
|
-
const requested = amount === void 0 ? totalAvailable : BigInt(amount);
|
|
3365
|
-
if (requested > totalAvailable) {
|
|
3366
|
-
throw new OwneyError(
|
|
3367
|
-
"WITHDRAW_INSUFFICIENT_BALANCE",
|
|
3368
|
-
`Requested withdrawal "${requested}" exceeds available Yieldseeker balance "${totalAvailable}" for asset "${asset}".`,
|
|
3369
|
-
{
|
|
3370
|
-
asset,
|
|
3371
|
-
requested: requested.toString(),
|
|
3372
|
-
available: totalAvailable.toString()
|
|
3373
|
-
},
|
|
3374
|
-
this.id
|
|
3375
|
-
);
|
|
3376
|
-
}
|
|
3377
|
-
let remaining = requested > idle ? requested - idle : 0n;
|
|
3378
|
-
for (const position2 of portfolio.positions) {
|
|
3379
|
-
if (remaining === 0n) break;
|
|
3380
|
-
const available = BigInt(position2.withdrawableAssetsRaw);
|
|
3381
|
-
if (available <= 0n) continue;
|
|
3382
|
-
const assetsRaw = available < remaining ? available : remaining;
|
|
3383
|
-
const response = await this.walletRequest(
|
|
3384
|
-
state,
|
|
3385
|
-
chainId,
|
|
3386
|
-
this.agentPath(context, "withdraw-from-position"),
|
|
3387
|
-
{
|
|
3388
|
-
method: "POST",
|
|
3389
|
-
body: {
|
|
3390
|
-
chainId,
|
|
3391
|
-
vaultAddress: position2.yieldOption.address,
|
|
3392
|
-
assetsRaw: assetsRaw.toString()
|
|
3393
|
-
}
|
|
3394
|
-
}
|
|
3395
|
-
);
|
|
3396
|
-
if (!this.isTransactionHash(response?.transactionHash)) {
|
|
3397
|
-
throw this.invalidResponse("position withdrawal");
|
|
3398
|
-
}
|
|
3399
|
-
await this.waitForReceipt(state, chainId, response.transactionHash);
|
|
3400
|
-
remaining -= assetsRaw;
|
|
3401
|
-
}
|
|
3402
|
-
if (remaining > 0n) {
|
|
3403
|
-
throw this.invalidResponse("yield positions", {
|
|
3404
|
-
reason: "Withdrawable positions could not cover the request.",
|
|
3405
|
-
remaining: remaining.toString()
|
|
3406
|
-
});
|
|
3407
|
-
}
|
|
3408
|
-
const account = (0, import_viem6.getAddress)(state.walletAddress);
|
|
3409
|
-
const txHash = await this.submitTransaction(state, chainId, {
|
|
3410
|
-
from: account,
|
|
3411
|
-
to: (0, import_viem6.getAddress)(context.wallet.walletAddress),
|
|
3412
|
-
data: amount === void 0 ? (0, import_viem6.encodeFunctionData)({
|
|
3413
|
-
abi: YIELDSEEKER_AGENT_WALLET_ABI,
|
|
3414
|
-
functionName: "withdrawAllAssetToUser",
|
|
3415
|
-
args: [account, metadata.address]
|
|
3416
|
-
}) : (0, import_viem6.encodeFunctionData)({
|
|
3417
|
-
abi: YIELDSEEKER_AGENT_WALLET_ABI,
|
|
3418
|
-
functionName: "withdrawAssetToUser",
|
|
3419
|
-
args: [account, metadata.address, requested]
|
|
3420
|
-
}),
|
|
3421
|
-
value: "0",
|
|
3422
|
-
chainId
|
|
3423
|
-
});
|
|
3424
|
-
return {
|
|
3425
|
-
txHash,
|
|
3426
|
-
type: amount === void 0 ? "full" : "partial",
|
|
3427
|
-
amount: requested.toString()
|
|
3428
|
-
};
|
|
3429
|
-
} finally {
|
|
3430
|
-
await this.refreshSnapshotAfterMovement(
|
|
3431
|
-
state,
|
|
3432
|
-
chainId,
|
|
3433
|
-
context,
|
|
3434
|
-
"withdrawal"
|
|
3435
|
-
);
|
|
3436
|
-
}
|
|
3437
|
-
}
|
|
3438
|
-
async getBalances(state, chainId) {
|
|
3439
|
-
this.assertChain(chainId);
|
|
3440
|
-
return mapYieldseekerBalances(await this.loadPortfolio(state, chainId, {}));
|
|
3441
|
-
}
|
|
3442
|
-
async getEarnings(state, chainId) {
|
|
3443
|
-
this.assertChain(chainId);
|
|
3444
|
-
return mapYieldseekerEarnings(await this.loadPortfolio(state, chainId, {}));
|
|
3445
|
-
}
|
|
3446
|
-
async getAccountApy(state, chainId, days, tokenSymbol) {
|
|
3447
|
-
this.assertChain(chainId);
|
|
3448
|
-
const asset = tokenSymbol?.toUpperCase();
|
|
3449
|
-
if (asset !== void 0) this.assertAsset(asset);
|
|
3450
|
-
const contexts = await this.loadPortfolio(state, chainId, {
|
|
3451
|
-
...asset ? { asset } : {},
|
|
3452
|
-
historic: true
|
|
3453
|
-
});
|
|
3454
|
-
return mapYieldseekerApy(state.walletAddress, contexts, days);
|
|
3455
|
-
}
|
|
3456
|
-
async getHistory(state, chainId, options) {
|
|
3457
|
-
this.assertChain(chainId);
|
|
3458
|
-
const asset = options?.tokenSymbol?.toUpperCase();
|
|
3459
|
-
if (asset !== void 0) this.assertAsset(asset);
|
|
3460
|
-
const contexts = await this.loadPortfolio(state, chainId, {
|
|
3461
|
-
...asset ? { asset } : {},
|
|
3462
|
-
historic: true,
|
|
3463
|
-
actions: true
|
|
3464
|
-
});
|
|
3465
|
-
return mapYieldseekerHistory(contexts, {
|
|
3466
|
-
limit: options?.limit ?? 10,
|
|
3467
|
-
ownerAddress: state.walletAddress,
|
|
3468
|
-
...options?.fromDate ? { fromDate: options.fromDate } : {},
|
|
3469
|
-
...options?.toDate ? { toDate: options.toDate } : {}
|
|
3470
|
-
});
|
|
3471
|
-
}
|
|
3472
|
-
async getUserProfile(state, chainId) {
|
|
3473
|
-
this.assertChain(chainId);
|
|
3474
|
-
return mapYieldseekerProfile(
|
|
3475
|
-
state.walletAddress,
|
|
3476
|
-
await this.loadPortfolio(state, chainId, {})
|
|
3477
|
-
);
|
|
3478
|
-
}
|
|
3479
|
-
async getAgentApy(days, options) {
|
|
3480
|
-
this.assertOptionalChain(options?.chainId);
|
|
3481
|
-
const requested = options?.tokenSymbol?.toUpperCase();
|
|
3482
|
-
if (requested !== void 0) this.assertAsset(requested);
|
|
3483
|
-
const assets = requested ? [requested] : ["USDC", "WETH"];
|
|
3484
|
-
const values = await Promise.all(
|
|
3485
|
-
assets.map(async (asset) => {
|
|
3486
|
-
const metadata = YIELDSEEKER_ASSET_METADATA[asset];
|
|
3487
|
-
const response = await this.api.request(
|
|
3488
|
-
`/chains/8453/assets/${metadata.address}/yield-options`
|
|
3489
|
-
);
|
|
3490
|
-
if (!Array.isArray(response?.yieldOptions)) {
|
|
3491
|
-
throw this.invalidResponse("yield options");
|
|
3492
|
-
}
|
|
3493
|
-
return { asset, yieldOptions: response.yieldOptions };
|
|
3494
|
-
})
|
|
3495
|
-
);
|
|
3496
|
-
return mapYieldseekerAgentApy(values, days);
|
|
3497
|
-
}
|
|
3498
|
-
userKey(state, chainId) {
|
|
3499
|
-
return `${state.walletAddress.toLowerCase()}:${chainId}`;
|
|
3500
|
-
}
|
|
3501
|
-
contextKey(state, chainId, asset) {
|
|
3502
|
-
return `${this.userKey(state, chainId)}:${asset}`;
|
|
3503
|
-
}
|
|
3504
|
-
async resolveUser(state, chainId) {
|
|
3505
|
-
const key2 = this.userKey(state, chainId);
|
|
3506
|
-
const inMemory = this.users.get(key2);
|
|
3507
|
-
if (inMemory) return inMemory;
|
|
3508
|
-
const persisted = readYieldseekerIdentity(state.walletAddress, chainId);
|
|
3509
|
-
if (persisted) {
|
|
3510
|
-
this.users.set(key2, persisted);
|
|
3511
|
-
return persisted;
|
|
3512
|
-
}
|
|
3513
|
-
const walletAddress = (0, import_viem6.getAddress)(state.walletAddress);
|
|
3514
|
-
let user = null;
|
|
3515
|
-
try {
|
|
3516
|
-
const login = await this.providerRequest(
|
|
3517
|
-
state,
|
|
3518
|
-
chainId,
|
|
3519
|
-
"/users/login-with-wallet",
|
|
3520
|
-
{ method: "POST", body: { walletAddress } }
|
|
3521
|
-
);
|
|
3522
|
-
user = login?.user ?? null;
|
|
3523
|
-
if (!user) {
|
|
3524
|
-
throw this.invalidResponse("wallet login", {
|
|
3525
|
-
reason: "A successful login returned no user."
|
|
3526
|
-
});
|
|
3527
|
-
}
|
|
3528
|
-
} catch (error) {
|
|
3529
|
-
if (!(error instanceof YieldseekerApiError) || error.providerCode !== "NO_USER") {
|
|
3530
|
-
if (error instanceof OwneyError) throw error;
|
|
3531
|
-
throw this.mapApiError(error);
|
|
3532
|
-
}
|
|
3533
|
-
let created;
|
|
3534
|
-
for (let attempt = 0; attempt < YIELDSEEKER_USERNAME_CREATE_ATTEMPTS; attempt += 1) {
|
|
3535
|
-
try {
|
|
3536
|
-
created = await this.providerRequest(
|
|
3537
|
-
state,
|
|
3538
|
-
chainId,
|
|
3539
|
-
"/users",
|
|
3540
|
-
{
|
|
3541
|
-
method: "POST",
|
|
3542
|
-
body: {
|
|
3543
|
-
walletAddress,
|
|
3544
|
-
username: generateYieldseekerUsername()
|
|
3545
|
-
}
|
|
3546
|
-
}
|
|
3547
|
-
);
|
|
3548
|
-
break;
|
|
3549
|
-
} catch (createError) {
|
|
3550
|
-
const canRetry = isUsernameConflict(createError) && attempt + 1 < YIELDSEEKER_USERNAME_CREATE_ATTEMPTS;
|
|
3551
|
-
if (canRetry) continue;
|
|
3552
|
-
throw this.mapApiError(createError);
|
|
3553
|
-
}
|
|
3554
|
-
}
|
|
3555
|
-
user = created?.user ?? null;
|
|
3556
|
-
}
|
|
3557
|
-
if (!user || !/^[a-zA-Z0-9_-]{1,128}$/.test(user.userId)) {
|
|
3558
|
-
throw this.invalidResponse("wallet identity");
|
|
3559
|
-
}
|
|
3560
|
-
const resolved = { userId: user.userId };
|
|
3561
|
-
this.users.set(key2, resolved);
|
|
3562
|
-
writeYieldseekerIdentity(state.walletAddress, chainId, resolved.userId);
|
|
3563
|
-
return resolved;
|
|
3564
|
-
}
|
|
3565
|
-
forgetUser(state, chainId) {
|
|
3566
|
-
this.users.delete(this.userKey(state, chainId));
|
|
3567
|
-
clearYieldseekerIdentity(state.walletAddress, chainId);
|
|
3568
|
-
}
|
|
3569
|
-
async ensureAgent(state, chainId, asset) {
|
|
3570
|
-
const key2 = this.contextKey(state, chainId, asset);
|
|
3571
|
-
const cached = this.agentContexts.get(key2);
|
|
3572
|
-
if (cached) return cached;
|
|
3573
|
-
const pending = this.pendingAgents.get(key2);
|
|
3574
|
-
if (pending) return pending;
|
|
3575
|
-
const request = this.resolveAgent(state, chainId, asset, true).then(
|
|
3576
|
-
(context) => {
|
|
3577
|
-
if (!context) throw this.invalidResponse("agent creation");
|
|
3578
|
-
this.agentContexts.set(key2, context);
|
|
3579
|
-
return context;
|
|
3580
|
-
}
|
|
3581
|
-
);
|
|
3582
|
-
this.pendingAgents.set(key2, request);
|
|
3583
|
-
try {
|
|
3584
|
-
return await request;
|
|
3585
|
-
} finally {
|
|
3586
|
-
this.pendingAgents.delete(key2);
|
|
3587
|
-
}
|
|
3588
|
-
}
|
|
3589
|
-
async findAgent(state, chainId, asset) {
|
|
3590
|
-
const key2 = this.contextKey(state, chainId, asset);
|
|
3591
|
-
const cached = this.agentContexts.get(key2);
|
|
3592
|
-
if (cached) return cached;
|
|
3593
|
-
const context = await this.resolveAgent(state, chainId, asset, false);
|
|
3594
|
-
if (context) this.agentContexts.set(key2, context);
|
|
3595
|
-
return context;
|
|
3596
|
-
}
|
|
3597
|
-
async resolveAgent(state, chainId, asset, createIfMissing) {
|
|
3598
|
-
const user = await this.resolveUser(state, chainId);
|
|
3599
|
-
const response = await this.walletRequest(
|
|
3600
|
-
state,
|
|
3601
|
-
chainId,
|
|
3602
|
-
`/users/${user.userId}/agents`
|
|
3603
|
-
);
|
|
3604
|
-
if (!Array.isArray(response?.agents)) {
|
|
3605
|
-
throw this.invalidResponse("agent list");
|
|
3606
|
-
}
|
|
3607
|
-
const metadata = YIELDSEEKER_ASSET_METADATA[asset];
|
|
3608
|
-
let agent = response.agents.find(
|
|
3609
|
-
(candidate) => this.isOwneyAgent(candidate) && candidate.chainId === chainId && candidate.type === "vault" && candidate.assetAddress.toLowerCase() === metadata.address.toLowerCase()
|
|
3610
|
-
);
|
|
3611
|
-
if (!agent && createIfMissing) {
|
|
3612
|
-
const created = await this.walletRequest(
|
|
3613
|
-
state,
|
|
3614
|
-
chainId,
|
|
3615
|
-
`/users/${user.userId}/agents`,
|
|
3616
|
-
{
|
|
3617
|
-
method: "POST",
|
|
3618
|
-
body: {
|
|
3619
|
-
name: OWNEY_AGENT_NAME,
|
|
3620
|
-
emoji: "\u{1F989}",
|
|
3621
|
-
chainId,
|
|
3622
|
-
assetAddress: metadata.address,
|
|
3623
|
-
type: "vault",
|
|
3624
|
-
rulePreset: null
|
|
3625
|
-
}
|
|
3626
|
-
}
|
|
3627
|
-
);
|
|
3628
|
-
agent = created?.agent;
|
|
3629
|
-
}
|
|
3630
|
-
if (!agent) return null;
|
|
3631
|
-
this.assertAgent(agent);
|
|
3632
|
-
const walletResponse = await this.walletRequest(
|
|
3633
|
-
state,
|
|
3634
|
-
chainId,
|
|
3635
|
-
`/users/${user.userId}/agents/${agent.agentId}/wallet`
|
|
3636
|
-
);
|
|
3637
|
-
if (!walletResponse?.agentWallet || !(0, import_viem6.isAddress)(walletResponse.agentWallet.walletAddress)) {
|
|
3638
|
-
throw this.invalidResponse("agent wallet");
|
|
3639
|
-
}
|
|
3640
|
-
return { user, agent, wallet: walletResponse.agentWallet, asset };
|
|
3641
|
-
}
|
|
3642
|
-
async loadPortfolio(state, chainId, options) {
|
|
3643
|
-
const user = await this.resolveUser(state, chainId);
|
|
3644
|
-
const response = await this.walletRequest(
|
|
3645
|
-
state,
|
|
3646
|
-
chainId,
|
|
3647
|
-
`/users/${user.userId}/agents`
|
|
3648
|
-
);
|
|
3649
|
-
if (!Array.isArray(response?.agents)) {
|
|
3650
|
-
throw this.invalidResponse("agent list");
|
|
3651
|
-
}
|
|
3652
|
-
const contexts = [];
|
|
3653
|
-
for (const agent of response.agents) {
|
|
3654
|
-
const asset = this.assetForAgent(agent);
|
|
3655
|
-
if (!this.isOwneyAgent(agent) || !asset || agent.chainId !== chainId || agent.type !== "vault" || options.asset && options.asset !== asset) {
|
|
3656
|
-
continue;
|
|
3657
|
-
}
|
|
3658
|
-
this.assertAgent(agent);
|
|
3659
|
-
const walletResponse = await this.walletRequest(
|
|
3660
|
-
state,
|
|
3661
|
-
chainId,
|
|
3662
|
-
`/users/${user.userId}/agents/${agent.agentId}/wallet`
|
|
3663
|
-
);
|
|
3664
|
-
if (!walletResponse?.agentWallet || !(0, import_viem6.isAddress)(walletResponse.agentWallet.walletAddress)) {
|
|
3665
|
-
throw this.invalidResponse("agent wallet");
|
|
3666
|
-
}
|
|
3667
|
-
const context = {
|
|
3668
|
-
user,
|
|
3669
|
-
agent,
|
|
3670
|
-
wallet: walletResponse.agentWallet,
|
|
3671
|
-
asset
|
|
3672
|
-
};
|
|
3673
|
-
this.agentContexts.set(this.contextKey(state, chainId, asset), context);
|
|
3674
|
-
contexts.push(context);
|
|
3675
|
-
}
|
|
3676
|
-
return Promise.all(
|
|
3677
|
-
contexts.map(
|
|
3678
|
-
(context) => this.loadPortfolioContext(state, chainId, context, options)
|
|
3679
|
-
)
|
|
3680
|
-
);
|
|
3681
|
-
}
|
|
3682
|
-
async loadPortfolioContext(state, chainId, context, options = {}) {
|
|
3683
|
-
const [snapshot, positions, historic, actions] = await Promise.all([
|
|
3684
|
-
this.walletRequest(
|
|
3685
|
-
state,
|
|
3686
|
-
chainId,
|
|
3687
|
-
`${this.agentPath(context, "snapshot")}${query({
|
|
3688
|
-
shouldOnlyUseRecentValue: true,
|
|
3689
|
-
shouldAllowStaleOnError: true
|
|
3690
|
-
})}`
|
|
3691
|
-
),
|
|
3692
|
-
this.walletRequest(
|
|
3693
|
-
state,
|
|
3694
|
-
chainId,
|
|
3695
|
-
this.agentPath(context, "yield-positions")
|
|
3696
|
-
),
|
|
3697
|
-
options.historic ? this.walletRequest(
|
|
3698
|
-
state,
|
|
3699
|
-
chainId,
|
|
3700
|
-
this.agentPath(context, "wallet/historic-position")
|
|
3701
|
-
) : Promise.resolve(void 0),
|
|
3702
|
-
options.actions ? this.walletRequest(
|
|
3703
|
-
state,
|
|
3704
|
-
chainId,
|
|
3705
|
-
this.agentPath(context, "actions")
|
|
3706
|
-
) : Promise.resolve(void 0)
|
|
3707
|
-
]);
|
|
3708
|
-
if (!snapshot?.agentSnapshot) {
|
|
3709
|
-
throw this.invalidResponse("agent snapshot");
|
|
3710
|
-
}
|
|
3711
|
-
if (!Array.isArray(positions?.yieldPositions)) {
|
|
3712
|
-
throw this.invalidResponse("yield positions");
|
|
3713
|
-
}
|
|
3714
|
-
return {
|
|
3715
|
-
...context,
|
|
3716
|
-
snapshot: snapshot.agentSnapshot,
|
|
3717
|
-
positions: positions.yieldPositions,
|
|
3718
|
-
...historic?.position ? { historic: historic.position } : {},
|
|
3719
|
-
...actions?.actions ? { actions: actions.actions } : {}
|
|
3720
|
-
};
|
|
3721
|
-
}
|
|
3722
|
-
async deployAfterFunding(state, chainId, context) {
|
|
3723
|
-
if (context.wallet.initializedDate != null) return;
|
|
3724
|
-
try {
|
|
3725
|
-
const deployed = await this.walletRequest(
|
|
3726
|
-
state,
|
|
3727
|
-
chainId,
|
|
3728
|
-
this.agentPath(context, "deploy"),
|
|
3729
|
-
{ method: "POST", body: {} }
|
|
3730
|
-
);
|
|
3731
|
-
if (deployed?.agentWallet) {
|
|
3732
|
-
context.wallet = deployed.agentWallet;
|
|
3733
|
-
}
|
|
3734
|
-
} catch (error) {
|
|
3735
|
-
console.warn(
|
|
3736
|
-
"[owney-sdk] Yieldseeker deposit is funded but not deployable yet:",
|
|
3737
|
-
error
|
|
3738
|
-
);
|
|
3739
|
-
}
|
|
3740
|
-
}
|
|
3741
|
-
async refreshSnapshotAfterMovement(state, chainId, context, movement) {
|
|
3742
|
-
try {
|
|
3743
|
-
const response = await this.walletRequest(
|
|
3744
|
-
state,
|
|
3745
|
-
chainId,
|
|
3746
|
-
`${this.agentPath(context, "snapshot")}${query({
|
|
3747
|
-
shouldForceRefresh: true
|
|
3748
|
-
})}`
|
|
3749
|
-
);
|
|
3750
|
-
if (!response?.agentSnapshot) {
|
|
3751
|
-
throw this.invalidResponse("agent snapshot refresh");
|
|
3752
|
-
}
|
|
3753
|
-
} catch (error) {
|
|
3754
|
-
console.warn(
|
|
3755
|
-
`[owney-sdk] Yieldseeker ${movement} snapshot refresh failed:`,
|
|
3756
|
-
error
|
|
3757
|
-
);
|
|
3758
|
-
}
|
|
3759
|
-
}
|
|
3760
|
-
agentPath(context, suffix) {
|
|
3761
|
-
return `/users/${context.user.userId}/agents/${context.agent.agentId}/${suffix}`;
|
|
3762
|
-
}
|
|
3763
|
-
async walletRequest(state, chainId, path, options = {}) {
|
|
3764
|
-
try {
|
|
3765
|
-
return await this.providerRequest(state, chainId, path, options);
|
|
3766
|
-
} catch (error) {
|
|
3767
|
-
throw this.mapApiError(error);
|
|
3768
|
-
}
|
|
3769
|
-
}
|
|
3770
|
-
async providerRequest(state, chainId, path, options = {}) {
|
|
3771
|
-
this.assertChain(chainId);
|
|
3772
|
-
const request = (signature2) => this.api.request(path, {
|
|
3773
|
-
...options,
|
|
3774
|
-
signature: signature2
|
|
3775
|
-
});
|
|
3776
|
-
let signature = await this.auth.getToken(state, chainId);
|
|
3777
|
-
try {
|
|
3778
|
-
return await request(signature);
|
|
3779
|
-
} catch (error) {
|
|
3780
|
-
if (!(error instanceof YieldseekerApiError)) throw error;
|
|
3781
|
-
if (error.providerCode === "NO_USER") throw error;
|
|
3782
|
-
if (!error.isAuthenticationError) throw error;
|
|
3783
|
-
this.auth.clear(state, chainId);
|
|
3784
|
-
signature = await this.auth.getToken(state, chainId);
|
|
3785
|
-
try {
|
|
3786
|
-
return await request(signature);
|
|
3787
|
-
} catch (retryError) {
|
|
3788
|
-
if (retryError instanceof YieldseekerApiError && retryError.isAuthenticationError) {
|
|
3789
|
-
this.forgetUser(state, chainId);
|
|
3790
|
-
}
|
|
3791
|
-
throw retryError;
|
|
3792
|
-
}
|
|
3793
|
-
}
|
|
3794
|
-
}
|
|
3795
|
-
mapApiError(error) {
|
|
3796
|
-
if (!(error instanceof YieldseekerApiError)) {
|
|
3797
|
-
return new OwneyError(
|
|
3798
|
-
"AGENT_API_ERROR",
|
|
3799
|
-
"Yieldseeker request failed.",
|
|
3800
|
-
{ cause: error instanceof Error ? error.message : String(error) },
|
|
3801
|
-
this.id
|
|
3802
|
-
);
|
|
3803
|
-
}
|
|
3804
|
-
const code = error.isAuthenticationError ? "AGENT_AUTH_FAILED" : error.providerCode === "REQUEST_TIMEOUT" ? "AGENT_TIMEOUT" : "AGENT_API_ERROR";
|
|
3805
|
-
return new OwneyError(
|
|
3806
|
-
code,
|
|
3807
|
-
`Yieldseeker request failed: ${error.providerCode}.`,
|
|
3808
|
-
{
|
|
3809
|
-
statusCode: error.status,
|
|
3810
|
-
providerCode: error.providerCode,
|
|
3811
|
-
...error.responseFields ? { fields: error.responseFields } : {}
|
|
3812
|
-
},
|
|
3813
|
-
this.id
|
|
3814
|
-
);
|
|
3815
|
-
}
|
|
3816
|
-
async submitTransaction(state, chainId, transaction) {
|
|
3817
|
-
if (this.transactionExecutor) {
|
|
3818
|
-
return this.transactionExecutor(state, chainId, transaction);
|
|
3819
|
-
}
|
|
3820
|
-
this.assertTransaction(transaction, state, chainId);
|
|
3821
|
-
const account = (0, import_viem6.getAddress)(state.walletAddress);
|
|
3822
|
-
const walletClient = (0, import_viem6.createWalletClient)({
|
|
3823
|
-
account,
|
|
3824
|
-
chain: import_chains3.base,
|
|
3825
|
-
transport: (0, import_viem6.custom)(state.provider)
|
|
3826
|
-
});
|
|
3827
|
-
const publicClient = (0, import_viem6.createPublicClient)({
|
|
3828
|
-
chain: import_chains3.base,
|
|
3829
|
-
transport: (0, import_viem6.custom)(state.provider)
|
|
3830
|
-
});
|
|
3831
|
-
await ensureWalletOnChain(
|
|
3832
|
-
publicClient,
|
|
3833
|
-
walletClient,
|
|
3834
|
-
8453
|
|
3835
|
-
);
|
|
3836
|
-
const hash = await walletClient.sendTransaction({
|
|
3837
|
-
account,
|
|
3838
|
-
chain: import_chains3.base,
|
|
3839
|
-
to: (0, import_viem6.getAddress)(transaction.to),
|
|
3840
|
-
data: transaction.data,
|
|
3841
|
-
value: BigInt(transaction.value)
|
|
3842
|
-
});
|
|
3843
|
-
const receipt = await publicClient.waitForTransactionReceipt({
|
|
3844
|
-
hash,
|
|
3845
|
-
confirmations: 1
|
|
3846
|
-
});
|
|
3847
|
-
if (receipt.status !== "success") {
|
|
3848
|
-
throw new OwneyError(
|
|
3849
|
-
"AGENT_TRANSACTION_REVERTED",
|
|
3850
|
-
`Yieldseeker transaction reverted (${hash}).`,
|
|
3851
|
-
{ transactionHash: hash },
|
|
3852
|
-
this.id
|
|
3853
|
-
);
|
|
3854
|
-
}
|
|
3855
|
-
return hash;
|
|
3856
|
-
}
|
|
3857
|
-
async waitForReceipt(state, chainId, transactionHash) {
|
|
3858
|
-
if (this.unwindReceiptWaiter) {
|
|
3859
|
-
await this.unwindReceiptWaiter(state, chainId, transactionHash);
|
|
3860
|
-
return;
|
|
3861
|
-
}
|
|
3862
|
-
const publicClient = (0, import_viem6.createPublicClient)({
|
|
3863
|
-
chain: import_chains3.base,
|
|
3864
|
-
transport: (0, import_viem6.custom)(state.provider)
|
|
3865
|
-
});
|
|
3866
|
-
const receipt = await publicClient.waitForTransactionReceipt({
|
|
3867
|
-
hash: transactionHash,
|
|
3868
|
-
confirmations: 1
|
|
3869
|
-
});
|
|
3870
|
-
if (receipt.status !== "success") {
|
|
3871
|
-
throw new OwneyError(
|
|
3872
|
-
"AGENT_TRANSACTION_REVERTED",
|
|
3873
|
-
`Yieldseeker transaction reverted (${transactionHash}).`,
|
|
3874
|
-
{ transactionHash },
|
|
3875
|
-
this.id
|
|
3876
|
-
);
|
|
3877
|
-
}
|
|
3878
|
-
}
|
|
3879
|
-
assertTransaction(transaction, state, chainId) {
|
|
3880
|
-
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)) {
|
|
3881
|
-
throw this.invalidResponse("transaction");
|
|
3882
|
-
}
|
|
3883
|
-
}
|
|
3884
|
-
assertAgent(agent) {
|
|
3885
|
-
if (typeof agent.agentId !== "string" || typeof agent.assetAddress !== "string" || !(0, import_viem6.isAddress)(agent.assetAddress) || agent.chainId !== 8453) {
|
|
3886
|
-
throw this.invalidResponse("agent");
|
|
3887
|
-
}
|
|
3888
|
-
}
|
|
3889
|
-
isOwneyAgent(agent) {
|
|
3890
|
-
return typeof agent.name === "string" && agent.name.trim().toLowerCase() === OWNEY_AGENT_NAME;
|
|
3891
|
-
}
|
|
3892
|
-
assetForAgent(agent) {
|
|
3893
|
-
for (const asset of ["USDC", "WETH"]) {
|
|
3894
|
-
if (agent.assetAddress.toLowerCase() === YIELDSEEKER_ASSET_METADATA[asset].address.toLowerCase()) {
|
|
3895
|
-
return asset;
|
|
3896
|
-
}
|
|
3897
|
-
}
|
|
3898
|
-
return null;
|
|
3899
|
-
}
|
|
3900
|
-
isTransactionHash(value) {
|
|
3901
|
-
return typeof value === "string" && /^0x[a-fA-F0-9]{64}$/.test(value);
|
|
3902
|
-
}
|
|
3903
|
-
assertChain(chainId) {
|
|
3904
|
-
if (chainId !== 8453) {
|
|
3905
|
-
throw new OwneyError(
|
|
3906
|
-
"CHAIN_UNSUPPORTED",
|
|
3907
|
-
`Yieldseeker does not support chain ${chainId}.`,
|
|
3908
|
-
{ chainId, supportedChainIds: [8453] },
|
|
3909
|
-
this.id
|
|
3910
|
-
);
|
|
3911
|
-
}
|
|
3912
|
-
}
|
|
3913
|
-
assertOptionalChain(chainId) {
|
|
3914
|
-
if (chainId !== void 0) this.assertChain(chainId);
|
|
3915
|
-
}
|
|
3916
|
-
assertAsset(asset) {
|
|
3917
|
-
if (asset !== "USDC" && asset !== "WETH") {
|
|
3918
|
-
throw new OwneyError(
|
|
3919
|
-
"ASSET_UNSUPPORTED",
|
|
3920
|
-
`Yieldseeker does not support asset ${asset} in the Owney rollout.`,
|
|
3921
|
-
{
|
|
3922
|
-
asset,
|
|
3923
|
-
supportedAssets: ["USDC", "WETH"],
|
|
3924
|
-
providerAlsoAdvertises: ["cbBTC"]
|
|
3925
|
-
},
|
|
3926
|
-
this.id
|
|
3927
|
-
);
|
|
3928
|
-
}
|
|
3929
|
-
}
|
|
3930
|
-
invalidResponse(operation, details = {}) {
|
|
3931
|
-
return new OwneyError(
|
|
3932
|
-
"AGENT_INVALID_RESPONSE",
|
|
3933
|
-
`Yieldseeker returned an invalid ${operation} response.`,
|
|
3934
|
-
details,
|
|
3935
|
-
this.id
|
|
3936
|
-
);
|
|
3937
|
-
}
|
|
3938
|
-
};
|
|
3939
|
-
|
|
3940
|
-
// src/lib/routing-api.ts
|
|
3941
|
-
var ROUTING_API_BASE_URL2 = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
3942
|
-
async function fetchOrgAgentConfig(apiKey, baseUrl = ROUTING_API_BASE_URL2) {
|
|
3943
|
-
const url = `${baseUrl}/api/v1/agent/org-config`;
|
|
3944
|
-
try {
|
|
3945
|
-
const res = await fetch(url, {
|
|
3946
|
-
method: "GET",
|
|
3947
|
-
headers: {
|
|
3948
|
-
"Content-Type": "application/json",
|
|
3949
|
-
"x-owney-api-key": `${apiKey}`
|
|
3950
|
-
}
|
|
3951
|
-
});
|
|
3952
|
-
if (!res.ok) {
|
|
3953
|
-
if (res.status !== 404) {
|
|
3954
|
-
console.warn(
|
|
3955
|
-
`[owney-sdk] Could not read org agent config (${res.status}); leaving user profiles unchanged.`
|
|
3956
|
-
);
|
|
3957
|
-
}
|
|
3958
|
-
return null;
|
|
3959
|
-
}
|
|
3960
|
-
const json = await res.json();
|
|
3961
|
-
const policy = json.success ? json.data ?? null : null;
|
|
3962
|
-
debugLog(
|
|
3963
|
-
"owney-sdk",
|
|
3964
|
-
policy ? "org agent config: loaded" : "org agent config: none set by this partner \u2014 user profiles will be left as they are",
|
|
3965
|
-
policy ?? void 0
|
|
3966
|
-
);
|
|
3967
|
-
return policy;
|
|
3968
|
-
} catch (error) {
|
|
3969
|
-
console.warn(
|
|
3970
|
-
"[owney-sdk] Could not read org agent config (non-fatal):",
|
|
3971
|
-
error instanceof Error ? error.message : String(error)
|
|
3972
|
-
);
|
|
3973
|
-
return null;
|
|
3974
|
-
}
|
|
3975
|
-
}
|
|
3976
|
-
async function fetchAgentKeys(apiKey, baseUrl = ROUTING_API_BASE_URL2) {
|
|
3977
|
-
const url = `${baseUrl}/api/v1/agent/keys`;
|
|
3978
|
-
const res = await fetch(url, {
|
|
3979
|
-
method: "GET",
|
|
3980
|
-
headers: {
|
|
3981
|
-
"Content-Type": "application/json",
|
|
3982
|
-
"x-owney-api-key": `${apiKey}`
|
|
3983
|
-
}
|
|
3984
|
-
});
|
|
3985
|
-
if (!res.ok) {
|
|
3986
|
-
const text = await res.text().catch(() => "");
|
|
3987
|
-
throw new OwneyError(
|
|
3988
|
-
"API_ROUTING_ERROR",
|
|
3989
|
-
`Routing API error ${res.status}: ${text}`,
|
|
3990
|
-
{ statusCode: res.status, responseBody: text }
|
|
3991
|
-
);
|
|
3992
|
-
}
|
|
3993
|
-
const json = await res.json();
|
|
3994
|
-
if (!json.success) {
|
|
3995
|
-
throw new OwneyError(
|
|
3996
|
-
"API_ROUTING_FAILED",
|
|
3997
|
-
`Routing API request failed: ${json.message}`,
|
|
3998
|
-
{ message: json.message }
|
|
3999
|
-
);
|
|
4000
|
-
}
|
|
4001
|
-
return json.data;
|
|
4002
|
-
}
|
|
4003
|
-
|
|
4004
|
-
// src/lib/health-report.ts
|
|
4005
|
-
var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
4006
|
-
async function reportAgentFailure(apiKey, agentType, errorCode, baseUrl = ROUTING_API_BASE_URL3) {
|
|
4007
|
-
try {
|
|
4008
|
-
await fetch(`${baseUrl}/api/v1/agent/health-report`, {
|
|
4009
|
-
method: "POST",
|
|
4010
|
-
headers: {
|
|
4011
|
-
"Content-Type": "application/json",
|
|
4012
|
-
"x-owney-api-key": apiKey
|
|
4013
|
-
},
|
|
4014
|
-
body: JSON.stringify({
|
|
4015
|
-
agent_type: agentType,
|
|
4016
|
-
error_code: errorCode,
|
|
4017
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
4018
|
-
})
|
|
4019
|
-
});
|
|
4020
|
-
} catch (err) {
|
|
4021
|
-
console.warn(
|
|
4022
|
-
`[owney-sdk] health-report failed for agent "${agentType}":`,
|
|
4023
|
-
err instanceof Error ? err.message : err
|
|
4024
|
-
);
|
|
4025
|
-
}
|
|
4026
|
-
}
|
|
4027
|
-
async function withFailureReporting(apiKey, agentType, fn, baseUrl) {
|
|
4028
|
-
try {
|
|
4029
|
-
return await fn();
|
|
4030
|
-
} catch (err) {
|
|
4031
|
-
const errorCode = err instanceof OwneyError ? err.code : "SDK_AGENT_FAILURE";
|
|
4032
|
-
void reportAgentFailure(apiKey, agentType, errorCode, baseUrl);
|
|
4033
|
-
throw err;
|
|
4034
|
-
}
|
|
4035
|
-
}
|
|
4036
|
-
|
|
4037
|
-
// src/lib/helpers/withdraw-helper.ts
|
|
4038
|
-
var import_viem7 = require("viem");
|
|
4039
|
-
function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
|
|
4040
|
-
const target = asset.toUpperCase();
|
|
4041
|
-
return agents.map((agent) => {
|
|
4042
|
-
const agentBalance = aggregated[agent.id];
|
|
4043
|
-
const tokenBalance = agentBalance?.tokens.find(
|
|
4044
|
-
(t) => t.chainId === chainId && t.asset.toUpperCase() === target
|
|
4045
|
-
);
|
|
4046
|
-
let balance = tokenBalance ? (0, import_viem7.parseUnits)(tokenBalance.amount, decimals) : 0n;
|
|
4047
|
-
if (agent.balanceComposition === "tokens-plus-positions") {
|
|
4048
|
-
const chainNameById = {
|
|
4049
|
-
1: "ETHEREUM",
|
|
4050
|
-
8453: "BASE",
|
|
4051
|
-
42161: "ARBITRUM"
|
|
4052
|
-
};
|
|
4053
|
-
const targetChain = chainNameById[chainId];
|
|
4054
|
-
for (const position2 of agentBalance?.positions ?? []) {
|
|
4055
|
-
const positionChain = position2.chain.trim().toUpperCase();
|
|
4056
|
-
const matchesChain = positionChain === String(chainId) || targetChain !== void 0 && positionChain === targetChain;
|
|
4057
|
-
if (!matchesChain || position2.asset.toUpperCase() !== target) continue;
|
|
4058
|
-
if (position2.amountRaw !== void 0) {
|
|
4059
|
-
try {
|
|
4060
|
-
balance += BigInt(position2.amountRaw);
|
|
4061
|
-
continue;
|
|
4062
|
-
} catch {
|
|
4063
|
-
}
|
|
4064
|
-
}
|
|
4065
|
-
balance += (0, import_viem7.parseUnits)(position2.amount, decimals);
|
|
4066
|
-
}
|
|
4067
|
-
}
|
|
4068
|
-
return { agent, balance };
|
|
4069
|
-
});
|
|
4070
|
-
}
|
|
4071
|
-
function planProportionalShares(balances, requested, totalAvailable) {
|
|
4072
|
-
const plans = balances.map(({ agent, balance }) => ({
|
|
4073
|
-
agent,
|
|
4074
|
-
balance,
|
|
4075
|
-
planned: totalAvailable > 0n ? balance * requested / totalAvailable : 0n
|
|
4076
|
-
}));
|
|
4077
|
-
const assigned = plans.reduce((s, p) => s + p.planned, 0n);
|
|
4078
|
-
let remainder = requested - assigned;
|
|
4079
|
-
const byHeadroom = [...plans].sort((a, b) => {
|
|
4080
|
-
const diff = b.balance - b.planned - (a.balance - a.planned);
|
|
4081
|
-
return diff > 0n ? 1 : diff < 0n ? -1 : 0;
|
|
2487
|
+
async function readErc20Balance(publicClient, token, owner) {
|
|
2488
|
+
return publicClient.readContract({
|
|
2489
|
+
address: token,
|
|
2490
|
+
abi: ERC20_ALLOWANCE_ABI,
|
|
2491
|
+
functionName: "balanceOf",
|
|
2492
|
+
args: [owner]
|
|
4082
2493
|
});
|
|
4083
|
-
for (const p of byHeadroom) {
|
|
4084
|
-
if (remainder === 0n) break;
|
|
4085
|
-
const headroom = p.balance - p.planned;
|
|
4086
|
-
if (headroom <= 0n) continue;
|
|
4087
|
-
const take = headroom < remainder ? headroom : remainder;
|
|
4088
|
-
p.planned += take;
|
|
4089
|
-
remainder -= take;
|
|
4090
|
-
}
|
|
4091
|
-
return plans;
|
|
4092
2494
|
}
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
continue;
|
|
4103
|
-
}
|
|
4104
|
-
const take = balance < remaining ? balance : remaining;
|
|
4105
|
-
plans.push({ agent, balance, planned: take });
|
|
4106
|
-
remaining -= take;
|
|
4107
|
-
}
|
|
4108
|
-
return { plans, remaining };
|
|
2495
|
+
|
|
2496
|
+
// src/lib/chain-guard.ts
|
|
2497
|
+
var CHAIN_NAMES = {
|
|
2498
|
+
1: "Ethereum",
|
|
2499
|
+
8453: "Base",
|
|
2500
|
+
42161: "Arbitrum"
|
|
2501
|
+
};
|
|
2502
|
+
function chainName(chainId) {
|
|
2503
|
+
return CHAIN_NAMES[chainId] ?? `chain ${chainId}`;
|
|
4109
2504
|
}
|
|
4110
|
-
function
|
|
4111
|
-
const
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
(
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
2505
|
+
async function ensureWalletOnChain(pub, wallet, expected) {
|
|
2506
|
+
const actual = await pub.getChainId();
|
|
2507
|
+
if (actual === expected) return;
|
|
2508
|
+
try {
|
|
2509
|
+
await wallet.switchChain({ id: expected });
|
|
2510
|
+
} catch (error) {
|
|
2511
|
+
throw new OwneyError(
|
|
2512
|
+
"CHAIN_MISMATCH",
|
|
2513
|
+
`Your wallet is on ${chainName(actual)}. Switch it to ${chainName(expected)} and try again.`,
|
|
2514
|
+
{
|
|
2515
|
+
expectedChainId: expected,
|
|
2516
|
+
actualChainId: actual,
|
|
2517
|
+
cause: error instanceof Error ? error.message : String(error)
|
|
2518
|
+
}
|
|
2519
|
+
);
|
|
4125
2520
|
}
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
leftover -= take;
|
|
2521
|
+
const after = await pub.getChainId();
|
|
2522
|
+
if (after !== expected) {
|
|
2523
|
+
throw new OwneyError(
|
|
2524
|
+
"CHAIN_MISMATCH",
|
|
2525
|
+
`Your wallet is still on ${chainName(after)}. Switch it to ${chainName(expected)} and try again.`,
|
|
2526
|
+
{ expectedChainId: expected, actualChainId: after }
|
|
2527
|
+
);
|
|
4134
2528
|
}
|
|
4135
2529
|
}
|
|
4136
|
-
function sumWithdrawnAmount(results) {
|
|
4137
|
-
return Object.values(results).reduce((sum, r) => sum + BigInt(r.amount), 0n);
|
|
4138
|
-
}
|
|
4139
2530
|
|
|
4140
|
-
// src/lib/
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
return Number.isFinite(amount) && amount > 0 ? total + amount : total;
|
|
4153
|
-
}, 0);
|
|
4154
|
-
}
|
|
4155
|
-
function aggregateApyHistory(agentApys, agentBalances) {
|
|
4156
|
-
const byDate = /* @__PURE__ */ new Map();
|
|
4157
|
-
for (const [id, accountApy] of Object.entries(agentApys)) {
|
|
4158
|
-
const balance = agentBalances[id] ?? 0;
|
|
4159
|
-
if (!Number.isFinite(balance) || balance <= 0) continue;
|
|
4160
|
-
for (const point of accountApy.history ?? []) {
|
|
4161
|
-
const apy = Number(point.apy);
|
|
4162
|
-
if (!point.date || !Number.isFinite(apy)) continue;
|
|
4163
|
-
const current = byDate.get(point.date) ?? { weightedSum: 0, weight: 0 };
|
|
4164
|
-
current.weightedSum += apy * balance;
|
|
4165
|
-
current.weight += balance;
|
|
4166
|
-
byDate.set(point.date, current);
|
|
2531
|
+
// src/lib/sponsored-deposit.ts
|
|
2532
|
+
var AUTH_WINDOW_SECONDS = 15 * 60;
|
|
2533
|
+
function makeSponsoredDepositCallback(deps) {
|
|
2534
|
+
const post = deps.httpPost ?? postSponsorTransferAuth;
|
|
2535
|
+
return async (smartWallet, chainId, amount) => {
|
|
2536
|
+
const cid = chainId;
|
|
2537
|
+
const token = deps.tokenAddressByChain[cid];
|
|
2538
|
+
if (!token) {
|
|
2539
|
+
throw new OwneyError(
|
|
2540
|
+
"CHAIN_UNSUPPORTED",
|
|
2541
|
+
`No sponsored token configured for chain ${chainId}`
|
|
2542
|
+
);
|
|
4167
2543
|
}
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
const balance = agentBalances[id] ?? 0;
|
|
4180
|
-
if (!cells || balance <= 0) continue;
|
|
4181
|
-
for (const [chainKey, perAsset] of Object.entries(cells)) {
|
|
4182
|
-
if (!perAsset) continue;
|
|
4183
|
-
const chainId = Number(chainKey);
|
|
4184
|
-
for (const [asset, apyValue] of Object.entries(perAsset)) {
|
|
4185
|
-
const apy = Number(apyValue ?? 0);
|
|
4186
|
-
if (apy === 0) continue;
|
|
4187
|
-
sums[chainId] ??= {};
|
|
4188
|
-
weights[chainId] ??= {};
|
|
4189
|
-
sums[chainId][asset] = (sums[chainId][asset] ?? 0) + apy * balance;
|
|
4190
|
-
weights[chainId][asset] = (weights[chainId][asset] ?? 0) + balance;
|
|
2544
|
+
const pub = deps.getPublicClient(cid);
|
|
2545
|
+
const wallet = deps.getWalletClient(cid);
|
|
2546
|
+
await ensureWalletOnChain(pub, wallet, cid);
|
|
2547
|
+
try {
|
|
2548
|
+
const balance = await readErc20Balance(pub, token, deps.ownerAddress);
|
|
2549
|
+
if (balance < BigInt(amount)) {
|
|
2550
|
+
throw new OwneyError(
|
|
2551
|
+
"DEPOSIT_INSUFFICIENT_BALANCE",
|
|
2552
|
+
"Insufficient balance for this deposit.",
|
|
2553
|
+
{ token, chainId: cid, balance: balance.toString(), amount }
|
|
2554
|
+
);
|
|
4191
2555
|
}
|
|
2556
|
+
} catch (err) {
|
|
2557
|
+
if (err instanceof OwneyError) throw err;
|
|
2558
|
+
console.warn(
|
|
2559
|
+
"[owney-sdk] Deposit balance pre-check failed (non-fatal):",
|
|
2560
|
+
err instanceof Error ? err.message : String(err)
|
|
2561
|
+
);
|
|
4192
2562
|
}
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
2563
|
+
const { tokenName, tokenVersion } = await readTokenMeta(pub, token);
|
|
2564
|
+
const validAfter = 0n;
|
|
2565
|
+
const validBefore = BigInt(
|
|
2566
|
+
Math.floor(Date.now() / 1e3) + AUTH_WINDOW_SECONDS
|
|
2567
|
+
);
|
|
2568
|
+
const nonce = randomAuthNonce();
|
|
2569
|
+
const typedData = buildTransferWithAuthorizationTypedData({
|
|
2570
|
+
token,
|
|
2571
|
+
chainId: cid,
|
|
2572
|
+
tokenName,
|
|
2573
|
+
tokenVersion,
|
|
2574
|
+
message: {
|
|
2575
|
+
from: deps.ownerAddress,
|
|
2576
|
+
to: smartWallet,
|
|
2577
|
+
value: BigInt(amount),
|
|
2578
|
+
validAfter,
|
|
2579
|
+
validBefore,
|
|
2580
|
+
nonce
|
|
2581
|
+
}
|
|
2582
|
+
});
|
|
2583
|
+
const authSignature = await wallet.signTypedData({
|
|
2584
|
+
account: deps.ownerAddress,
|
|
2585
|
+
...typedData
|
|
2586
|
+
});
|
|
2587
|
+
deps.onApproved?.();
|
|
2588
|
+
const result = await post({
|
|
2589
|
+
baseUrl: deps.baseUrl,
|
|
2590
|
+
apiKey: deps.apiKey,
|
|
2591
|
+
body: {
|
|
2592
|
+
chainId: cid,
|
|
2593
|
+
token,
|
|
2594
|
+
from: deps.ownerAddress,
|
|
2595
|
+
to: smartWallet,
|
|
2596
|
+
value: amount,
|
|
2597
|
+
validAfter: validAfter.toString(),
|
|
2598
|
+
validBefore: validBefore.toString(),
|
|
2599
|
+
nonce,
|
|
2600
|
+
authSignature,
|
|
2601
|
+
tokenName,
|
|
2602
|
+
tokenVersion
|
|
2603
|
+
}
|
|
2604
|
+
});
|
|
2605
|
+
return result.txHash;
|
|
2606
|
+
};
|
|
4207
2607
|
}
|
|
4208
2608
|
|
|
4209
|
-
// src/client.ts
|
|
4210
|
-
var import_viem9 = require("viem");
|
|
4211
|
-
var import_chains4 = require("viem/chains");
|
|
4212
|
-
|
|
4213
2609
|
// src/lib/sponsored-weth-deposit.ts
|
|
4214
2610
|
var PERMIT_WINDOW_SECONDS = 15 * 60;
|
|
4215
2611
|
function makeSponsoredWethCallback(deps) {
|
|
4216
2612
|
const get = deps.httpGet ?? getSponsorRelayerAddress;
|
|
4217
2613
|
const post = deps.httpPost ?? postSponsorPermit2Transfer;
|
|
4218
|
-
return
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
`No sponsored WETH configured for chain ${chainId}`
|
|
4226
|
-
);
|
|
4227
|
-
}
|
|
4228
|
-
const amountWei = BigInt(amount);
|
|
4229
|
-
const pub = deps.getPublicClient(cid);
|
|
4230
|
-
const wallet = deps.getWalletClient(cid);
|
|
4231
|
-
await ensureWalletOnChain(pub, wallet, cid);
|
|
4232
|
-
try {
|
|
4233
|
-
const balance = await readErc20Balance(pub, token, deps.ownerAddress);
|
|
4234
|
-
if (balance < amountWei) {
|
|
4235
|
-
throw new OwneyError(
|
|
4236
|
-
"DEPOSIT_INSUFFICIENT_BALANCE",
|
|
4237
|
-
"Insufficient WETH balance for this deposit.",
|
|
4238
|
-
{ token, chainId: cid, balance: balance.toString(), amount }
|
|
4239
|
-
);
|
|
4240
|
-
}
|
|
4241
|
-
} catch (err) {
|
|
4242
|
-
if (err instanceof OwneyError) throw err;
|
|
4243
|
-
console.warn(
|
|
4244
|
-
"[owney-sdk] WETH balance pre-check failed (non-fatal):",
|
|
4245
|
-
err instanceof Error ? err.message : String(err)
|
|
4246
|
-
);
|
|
4247
|
-
}
|
|
4248
|
-
const allowance = await readPermit2Allowance(
|
|
4249
|
-
pub,
|
|
4250
|
-
token,
|
|
4251
|
-
deps.ownerAddress
|
|
2614
|
+
return async (smartWallet, chainId, amount) => {
|
|
2615
|
+
const cid = chainId;
|
|
2616
|
+
const token = deps.tokenAddressByChain[cid];
|
|
2617
|
+
if (!token) {
|
|
2618
|
+
throw new OwneyError(
|
|
2619
|
+
"CHAIN_UNSUPPORTED",
|
|
2620
|
+
`No sponsored WETH configured for chain ${chainId}`
|
|
4252
2621
|
);
|
|
4253
|
-
|
|
2622
|
+
}
|
|
2623
|
+
const amountWei = BigInt(amount);
|
|
2624
|
+
const pub = deps.getPublicClient(cid);
|
|
2625
|
+
const wallet = deps.getWalletClient(cid);
|
|
2626
|
+
await ensureWalletOnChain(pub, wallet, cid);
|
|
2627
|
+
try {
|
|
2628
|
+
const balance = await readErc20Balance(pub, token, deps.ownerAddress);
|
|
2629
|
+
if (balance < amountWei) {
|
|
4254
2630
|
throw new OwneyError(
|
|
4255
|
-
"
|
|
4256
|
-
"WETH
|
|
4257
|
-
{ token, chainId: cid,
|
|
2631
|
+
"DEPOSIT_INSUFFICIENT_BALANCE",
|
|
2632
|
+
"Insufficient WETH balance for this deposit.",
|
|
2633
|
+
{ token, chainId: cid, balance: balance.toString(), amount }
|
|
4258
2634
|
);
|
|
4259
2635
|
}
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
const nonce = randomPermit2Nonce();
|
|
4266
|
-
const deadline = BigInt(
|
|
4267
|
-
Math.floor(Date.now() / 1e3) + PERMIT_WINDOW_SECONDS
|
|
2636
|
+
} catch (err) {
|
|
2637
|
+
if (err instanceof OwneyError) throw err;
|
|
2638
|
+
console.warn(
|
|
2639
|
+
"[owney-sdk] WETH balance pre-check failed (non-fatal):",
|
|
2640
|
+
err instanceof Error ? err.message : String(err)
|
|
4268
2641
|
);
|
|
4269
|
-
const typedData = buildPermitTransferFromTypedData({
|
|
4270
|
-
chainId: cid,
|
|
4271
|
-
message: {
|
|
4272
|
-
permitted: { token, amount: amountWei },
|
|
4273
|
-
spender: relayer,
|
|
4274
|
-
nonce,
|
|
4275
|
-
deadline
|
|
4276
|
-
}
|
|
4277
|
-
});
|
|
4278
|
-
const signature = await wallet.signTypedData({
|
|
4279
|
-
account: deps.ownerAddress,
|
|
4280
|
-
...typedData
|
|
4281
|
-
});
|
|
4282
|
-
deps.onApproved?.();
|
|
4283
|
-
const result = await post({
|
|
4284
|
-
baseUrl: deps.baseUrl,
|
|
4285
|
-
apiKey: deps.apiKey,
|
|
4286
|
-
...verification?.agentId === "yieldseeker" ? { yieldseekerSignature: verification.signature } : {},
|
|
4287
|
-
body: {
|
|
4288
|
-
chainId: cid,
|
|
4289
|
-
token,
|
|
4290
|
-
from: deps.ownerAddress,
|
|
4291
|
-
to: smartWallet,
|
|
4292
|
-
amount,
|
|
4293
|
-
nonce: nonce.toString(),
|
|
4294
|
-
deadline: deadline.toString(),
|
|
4295
|
-
signature,
|
|
4296
|
-
...verification?.agentId === "yieldseeker" ? {
|
|
4297
|
-
yieldseekerUserId: verification.userId,
|
|
4298
|
-
yieldseekerAgentId: verification.yieldseekerAgentId
|
|
4299
|
-
} : {}
|
|
4300
|
-
}
|
|
4301
|
-
});
|
|
4302
|
-
return result.txHash;
|
|
4303
2642
|
}
|
|
4304
|
-
|
|
2643
|
+
const allowance = await readPermit2Allowance(pub, token, deps.ownerAddress);
|
|
2644
|
+
if (allowance < amountWei) {
|
|
2645
|
+
throw new OwneyError(
|
|
2646
|
+
"PERMIT2_APPROVAL_REQUIRED",
|
|
2647
|
+
"WETH gasless deposits need a one-time Permit2 approval; call approvePermit2() first",
|
|
2648
|
+
{ token, chainId: cid, allowance: allowance.toString(), amount }
|
|
2649
|
+
);
|
|
2650
|
+
}
|
|
2651
|
+
const relayer = await get({
|
|
2652
|
+
baseUrl: deps.baseUrl,
|
|
2653
|
+
apiKey: deps.apiKey,
|
|
2654
|
+
chainId: cid
|
|
2655
|
+
});
|
|
2656
|
+
const nonce = randomPermit2Nonce();
|
|
2657
|
+
const deadline = BigInt(
|
|
2658
|
+
Math.floor(Date.now() / 1e3) + PERMIT_WINDOW_SECONDS
|
|
2659
|
+
);
|
|
2660
|
+
const typedData = buildPermitTransferFromTypedData({
|
|
2661
|
+
chainId: cid,
|
|
2662
|
+
message: {
|
|
2663
|
+
permitted: { token, amount: amountWei },
|
|
2664
|
+
spender: relayer,
|
|
2665
|
+
nonce,
|
|
2666
|
+
deadline
|
|
2667
|
+
}
|
|
2668
|
+
});
|
|
2669
|
+
const signature = await wallet.signTypedData({
|
|
2670
|
+
account: deps.ownerAddress,
|
|
2671
|
+
...typedData
|
|
2672
|
+
});
|
|
2673
|
+
deps.onApproved?.();
|
|
2674
|
+
const result = await post({
|
|
2675
|
+
baseUrl: deps.baseUrl,
|
|
2676
|
+
apiKey: deps.apiKey,
|
|
2677
|
+
body: {
|
|
2678
|
+
chainId: cid,
|
|
2679
|
+
token,
|
|
2680
|
+
from: deps.ownerAddress,
|
|
2681
|
+
to: smartWallet,
|
|
2682
|
+
amount,
|
|
2683
|
+
nonce: nonce.toString(),
|
|
2684
|
+
deadline: deadline.toString(),
|
|
2685
|
+
signature
|
|
2686
|
+
}
|
|
2687
|
+
});
|
|
2688
|
+
return result.txHash;
|
|
2689
|
+
};
|
|
4305
2690
|
}
|
|
4306
2691
|
|
|
4307
2692
|
// src/lib/sponsored-calls-deposit.ts
|
|
4308
|
-
var
|
|
2693
|
+
var import_viem5 = require("viem");
|
|
4309
2694
|
var DEFAULT_POLL_INTERVAL_MS = 1500;
|
|
4310
2695
|
var DEFAULT_MAX_POLLS = 30;
|
|
4311
2696
|
async function paymasterSupported(provider, owner, chainId) {
|
|
@@ -4313,7 +2698,7 @@ async function paymasterSupported(provider, owner, chainId) {
|
|
|
4313
2698
|
method: "wallet_getCapabilities",
|
|
4314
2699
|
params: [owner]
|
|
4315
2700
|
});
|
|
4316
|
-
const forChain = caps?.[(0,
|
|
2701
|
+
const forChain = caps?.[(0, import_viem5.toHex)(chainId)] ?? caps?.[String(chainId)];
|
|
4317
2702
|
return Boolean(forChain?.paymasterService?.supported);
|
|
4318
2703
|
}
|
|
4319
2704
|
function makeSponsoredCallsCallback(deps) {
|
|
@@ -4331,7 +2716,7 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
4331
2716
|
}
|
|
4332
2717
|
return new URL(configured, origin).toString();
|
|
4333
2718
|
};
|
|
4334
|
-
return
|
|
2719
|
+
return async (smartWallet, chainId, amount) => {
|
|
4335
2720
|
const cid = chainId;
|
|
4336
2721
|
const token = deps.tokenAddressByChain[cid];
|
|
4337
2722
|
if (!token) {
|
|
@@ -4347,48 +2732,22 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
4347
2732
|
{ chainId }
|
|
4348
2733
|
);
|
|
4349
2734
|
}
|
|
4350
|
-
const data = (0,
|
|
4351
|
-
abi:
|
|
2735
|
+
const data = (0, import_viem5.encodeFunctionData)({
|
|
2736
|
+
abi: import_viem5.erc20Abi,
|
|
4352
2737
|
functionName: "transfer",
|
|
4353
2738
|
args: [smartWallet, BigInt(amount)]
|
|
4354
2739
|
});
|
|
4355
|
-
let paymasterUrl = absolutePaymasterUrl();
|
|
4356
|
-
if (verification?.agentId === "yieldseeker") {
|
|
4357
|
-
if (chainId !== 8453) {
|
|
4358
|
-
throw new OwneyError(
|
|
4359
|
-
"CHAIN_UNSUPPORTED",
|
|
4360
|
-
`Yieldseeker Base Account sponsorship is not available on chain ${chainId}.`
|
|
4361
|
-
);
|
|
4362
|
-
}
|
|
4363
|
-
const { intent } = await postPaymasterIntent({
|
|
4364
|
-
baseUrl: deps.routingApiBaseUrl,
|
|
4365
|
-
apiKey: deps.apiKey,
|
|
4366
|
-
yieldseekerSignature: verification.signature,
|
|
4367
|
-
body: {
|
|
4368
|
-
chainId,
|
|
4369
|
-
token,
|
|
4370
|
-
from: deps.ownerAddress,
|
|
4371
|
-
to: smartWallet,
|
|
4372
|
-
amount,
|
|
4373
|
-
yieldseekerUserId: verification.userId,
|
|
4374
|
-
yieldseekerAgentId: verification.yieldseekerAgentId
|
|
4375
|
-
}
|
|
4376
|
-
});
|
|
4377
|
-
const url = new URL(paymasterUrl);
|
|
4378
|
-
url.searchParams.set("owneyIntent", intent);
|
|
4379
|
-
paymasterUrl = url.toString();
|
|
4380
|
-
}
|
|
4381
2740
|
const sendResult = await deps.provider.request({
|
|
4382
2741
|
method: "wallet_sendCalls",
|
|
4383
2742
|
params: [
|
|
4384
2743
|
{
|
|
4385
2744
|
version: "2.0.0",
|
|
4386
2745
|
from: deps.ownerAddress,
|
|
4387
|
-
chainId: (0,
|
|
2746
|
+
chainId: (0, import_viem5.toHex)(chainId),
|
|
4388
2747
|
atomicRequired: false,
|
|
4389
2748
|
calls: [{ to: token, value: "0x0", data }],
|
|
4390
2749
|
capabilities: {
|
|
4391
|
-
paymasterService: { url:
|
|
2750
|
+
paymasterService: { url: absolutePaymasterUrl() }
|
|
4392
2751
|
}
|
|
4393
2752
|
}
|
|
4394
2753
|
]
|
|
@@ -4418,7 +2777,7 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
4418
2777
|
`No receipt for calls ${callsId} after ${maxPolls} polls; the deposit may still settle.`,
|
|
4419
2778
|
{ chainId, callsId }
|
|
4420
2779
|
);
|
|
4421
|
-
}
|
|
2780
|
+
};
|
|
4422
2781
|
}
|
|
4423
2782
|
|
|
4424
2783
|
// src/client.ts
|
|
@@ -4448,9 +2807,9 @@ var SPONSORED_USDC_BY_CHAIN = {
|
|
|
4448
2807
|
1: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
|
|
4449
2808
|
};
|
|
4450
2809
|
var VIEM_CHAIN2 = {
|
|
4451
|
-
8453:
|
|
4452
|
-
42161:
|
|
4453
|
-
1:
|
|
2810
|
+
8453: import_chains2.base,
|
|
2811
|
+
42161: import_chains2.arbitrum,
|
|
2812
|
+
1: import_chains2.mainnet
|
|
4454
2813
|
};
|
|
4455
2814
|
var SPONSORED_WETH_BY_CHAIN = {
|
|
4456
2815
|
8453: "0x4200000000000000000000000000000000000006",
|
|
@@ -4478,8 +2837,6 @@ var OwneySDK = class {
|
|
|
4478
2837
|
orgAgentConfig;
|
|
4479
2838
|
orgAgentConfigPromise = null;
|
|
4480
2839
|
zyfaiRpcUrls;
|
|
4481
|
-
yieldseekerApiBaseUrl;
|
|
4482
|
-
yieldseekerSiweOrigin;
|
|
4483
2840
|
routingApiBaseUrl;
|
|
4484
2841
|
referralSource;
|
|
4485
2842
|
cachedSponsoredCallback = null;
|
|
@@ -4502,8 +2859,6 @@ var OwneySDK = class {
|
|
|
4502
2859
|
this.apiKey = config.apiKey;
|
|
4503
2860
|
if (config.debug) setOwneyDebug(true);
|
|
4504
2861
|
this.zyfaiRpcUrls = config.zyfaiRpcUrls;
|
|
4505
|
-
this.yieldseekerApiBaseUrl = config.yieldseekerApiBaseUrl;
|
|
4506
|
-
this.yieldseekerSiweOrigin = config.yieldseekerSiweOrigin;
|
|
4507
2862
|
this.routingApiBaseUrl = config.routingApiBaseUrl;
|
|
4508
2863
|
this.paymasterServiceUrl = config.paymasterServiceUrl;
|
|
4509
2864
|
this.referralSource = config.referralSource;
|
|
@@ -4610,14 +2965,14 @@ var OwneySDK = class {
|
|
|
4610
2965
|
// Casts work around viem's chain-narrowed Client vs the generic
|
|
4611
2966
|
// PublicClient/WalletClient param types — structurally identical at
|
|
4612
2967
|
// runtime, but the two share a name TS treats as unrelated.
|
|
4613
|
-
getPublicClient: (cid) => (0,
|
|
2968
|
+
getPublicClient: (cid) => (0, import_viem6.createPublicClient)({
|
|
4614
2969
|
chain: VIEM_CHAIN2[cid],
|
|
4615
|
-
transport: (0,
|
|
2970
|
+
transport: (0, import_viem6.custom)(provider)
|
|
4616
2971
|
}),
|
|
4617
|
-
getWalletClient: (cid) => (0,
|
|
2972
|
+
getWalletClient: (cid) => (0, import_viem6.createWalletClient)({
|
|
4618
2973
|
account: owner,
|
|
4619
2974
|
chain: VIEM_CHAIN2[cid],
|
|
4620
|
-
transport: (0,
|
|
2975
|
+
transport: (0, import_viem6.custom)(provider)
|
|
4621
2976
|
})
|
|
4622
2977
|
});
|
|
4623
2978
|
if (!onApproved) this.cachedSponsoredCallback = callback;
|
|
@@ -4634,8 +2989,6 @@ var OwneySDK = class {
|
|
|
4634
2989
|
if (!onApproved && cached) return cached;
|
|
4635
2990
|
const provider = this.requireConnectedProvider();
|
|
4636
2991
|
const callback = makeSponsoredCallsCallback({
|
|
4637
|
-
apiKey: this.apiKey,
|
|
4638
|
-
routingApiBaseUrl: this.routingApiBaseUrl,
|
|
4639
2992
|
provider,
|
|
4640
2993
|
ownerAddress: this.state.walletAddress,
|
|
4641
2994
|
paymasterServiceUrl: this.paymasterServiceUrl,
|
|
@@ -4665,14 +3018,14 @@ var OwneySDK = class {
|
|
|
4665
3018
|
// Casts work around viem's chain-narrowed Client vs the generic
|
|
4666
3019
|
// PublicClient/WalletClient param types — structurally identical at
|
|
4667
3020
|
// runtime, but the two share a name TS treats as unrelated.
|
|
4668
|
-
getPublicClient: (cid) => (0,
|
|
3021
|
+
getPublicClient: (cid) => (0, import_viem6.createPublicClient)({
|
|
4669
3022
|
chain: VIEM_CHAIN2[cid],
|
|
4670
|
-
transport: (0,
|
|
3023
|
+
transport: (0, import_viem6.custom)(provider)
|
|
4671
3024
|
}),
|
|
4672
|
-
getWalletClient: (cid) => (0,
|
|
3025
|
+
getWalletClient: (cid) => (0, import_viem6.createWalletClient)({
|
|
4673
3026
|
account: owner,
|
|
4674
3027
|
chain: VIEM_CHAIN2[cid],
|
|
4675
|
-
transport: (0,
|
|
3028
|
+
transport: (0, import_viem6.custom)(provider)
|
|
4676
3029
|
})
|
|
4677
3030
|
});
|
|
4678
3031
|
if (!onApproved) this.cachedWethSponsoredCallback = callback;
|
|
@@ -4703,10 +3056,12 @@ var OwneySDK = class {
|
|
|
4703
3056
|
this.orgAgentConfigPromise = fetchOrgAgentConfig(
|
|
4704
3057
|
this.apiKey,
|
|
4705
3058
|
this.routingApiBaseUrl
|
|
4706
|
-
).then(
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
|
|
3059
|
+
).then(
|
|
3060
|
+
(config) => {
|
|
3061
|
+
this.orgAgentConfig = config;
|
|
3062
|
+
return config;
|
|
3063
|
+
}
|
|
3064
|
+
);
|
|
4710
3065
|
}
|
|
4711
3066
|
return this.orgAgentConfigPromise;
|
|
4712
3067
|
}
|
|
@@ -4746,14 +3101,7 @@ var OwneySDK = class {
|
|
|
4746
3101
|
this.routingApiBaseUrl
|
|
4747
3102
|
);
|
|
4748
3103
|
this.disabledAgents.clear();
|
|
4749
|
-
for (const {
|
|
4750
|
-
key: key2,
|
|
4751
|
-
agent_type,
|
|
4752
|
-
is_enabled,
|
|
4753
|
-
is_configured
|
|
4754
|
-
} of agentKeys) {
|
|
4755
|
-
const configured = is_configured ?? Boolean(key2);
|
|
4756
|
-
if (!configured) continue;
|
|
3104
|
+
for (const { key: key2, agent_type, is_enabled } of agentKeys) {
|
|
4757
3105
|
const agent = this.createAgent(agent_type, key2);
|
|
4758
3106
|
if (!agent) continue;
|
|
4759
3107
|
this.agents.set(agent_type, agent);
|
|
@@ -4777,15 +3125,8 @@ var OwneySDK = class {
|
|
|
4777
3125
|
}
|
|
4778
3126
|
createAgent(agentId, key2) {
|
|
4779
3127
|
if (agentId === "zyfai") {
|
|
4780
|
-
if (!key2) return null;
|
|
4781
3128
|
return new ZyfaiAgent(key2, this.zyfaiRpcUrls, this.referralSource);
|
|
4782
3129
|
}
|
|
4783
|
-
if (agentId === "yieldseeker") {
|
|
4784
|
-
return new YieldseekerAgent(this.apiKey, {
|
|
4785
|
-
auth: { origin: this.yieldseekerSiweOrigin },
|
|
4786
|
-
baseUrl: this.yieldseekerApiBaseUrl ?? getYieldseekerProxyBaseUrl(this.routingApiBaseUrl)
|
|
4787
|
-
});
|
|
4788
|
-
}
|
|
4789
3130
|
return null;
|
|
4790
3131
|
}
|
|
4791
3132
|
/**
|
|
@@ -4830,7 +3171,7 @@ var OwneySDK = class {
|
|
|
4830
3171
|
* If provided, ALL specified agents must support the chainId or the call
|
|
4831
3172
|
* throws before activating any agent.
|
|
4832
3173
|
*/
|
|
4833
|
-
async activateAgent(chainId, agentId
|
|
3174
|
+
async activateAgent(chainId, agentId) {
|
|
4834
3175
|
const state = this.requireState();
|
|
4835
3176
|
await this.ensureAgentsInitialized();
|
|
4836
3177
|
if (agentId !== void 0) {
|
|
@@ -4866,7 +3207,7 @@ var OwneySDK = class {
|
|
|
4866
3207
|
this.activeAgents.add(id);
|
|
4867
3208
|
}
|
|
4868
3209
|
state.chainId = chainId;
|
|
4869
|
-
await this.activateAgentsInTurn(agents, state, chainId
|
|
3210
|
+
await this.activateAgentsInTurn(agents, state, chainId);
|
|
4870
3211
|
return;
|
|
4871
3212
|
}
|
|
4872
3213
|
const compatible = [...this.agents.values()].filter(
|
|
@@ -4887,7 +3228,7 @@ var OwneySDK = class {
|
|
|
4887
3228
|
const enabledCompatible = compatible.filter(
|
|
4888
3229
|
(agent) => !this.isAgentDisabled(agent.id)
|
|
4889
3230
|
);
|
|
4890
|
-
await this.activateAgentsInTurn(enabledCompatible, state, chainId
|
|
3231
|
+
await this.activateAgentsInTurn(enabledCompatible, state, chainId);
|
|
4891
3232
|
}
|
|
4892
3233
|
/**
|
|
4893
3234
|
* Activate agents ONE AT A TIME, each followed by its org policy.
|
|
@@ -4903,25 +3244,17 @@ var OwneySDK = class {
|
|
|
4903
3244
|
* at a time anyway.
|
|
4904
3245
|
*
|
|
4905
3246
|
* Every agent is attempted even if an earlier one fails, so one declined
|
|
4906
|
-
* signature can't deny the remaining agents their turn.
|
|
4907
|
-
*
|
|
4908
|
-
*
|
|
3247
|
+
* signature can't deny the remaining agents their turn. The first failure is
|
|
3248
|
+
* rethrown (matching the previous `Promise.all` rejection) once all agents
|
|
3249
|
+
* have had a chance to activate.
|
|
4909
3250
|
*/
|
|
4910
|
-
async activateAgentsInTurn(agents, state, chainId
|
|
3251
|
+
async activateAgentsInTurn(agents, state, chainId) {
|
|
4911
3252
|
let firstError = null;
|
|
4912
|
-
const activatedAgentIds = [];
|
|
4913
|
-
const failedAgents = [];
|
|
4914
3253
|
for (const agent of agents) {
|
|
4915
3254
|
try {
|
|
4916
|
-
await agent.activateAgent(state, chainId
|
|
3255
|
+
await agent.activateAgent(state, chainId);
|
|
4917
3256
|
await this.applyOrgPolicyTo(agent, state, chainId);
|
|
4918
|
-
activatedAgentIds.push(agent.id);
|
|
4919
3257
|
} catch (error) {
|
|
4920
|
-
failedAgents.push({
|
|
4921
|
-
agentId: agent.id,
|
|
4922
|
-
code: error instanceof OwneyError ? error.code : void 0,
|
|
4923
|
-
message: error instanceof Error ? error.message : String(error)
|
|
4924
|
-
});
|
|
4925
3258
|
if (firstError === null) {
|
|
4926
3259
|
firstError = error;
|
|
4927
3260
|
} else {
|
|
@@ -4929,16 +3262,7 @@ var OwneySDK = class {
|
|
|
4929
3262
|
}
|
|
4930
3263
|
}
|
|
4931
3264
|
}
|
|
4932
|
-
if (firstError
|
|
4933
|
-
if (activatedAgentIds.length === 0) throw firstError;
|
|
4934
|
-
const failedAgentIds = failedAgents.map(({ agentId }) => agentId);
|
|
4935
|
-
const activeNames = activatedAgentIds.map(this.formatAgentName).join(", ");
|
|
4936
|
-
const remainingNames = failedAgentIds.map(this.formatAgentName).join(", ");
|
|
4937
|
-
throw new OwneyError(
|
|
4938
|
-
"AGENT_ACTIVATION_PARTIAL_FAILURE",
|
|
4939
|
-
`${activeNames} activated, but ${remainingNames} still needs activation. Try again and approve the remaining wallet request.`,
|
|
4940
|
-
{ activatedAgentIds, failedAgentIds, failures: failedAgents }
|
|
4941
|
-
);
|
|
3265
|
+
if (firstError !== null) throw firstError;
|
|
4942
3266
|
}
|
|
4943
3267
|
/**
|
|
4944
3268
|
* Deposit into a specific agent, or distribute across all eligible agents.
|
|
@@ -5152,10 +3476,10 @@ var OwneySDK = class {
|
|
|
5152
3476
|
agent,
|
|
5153
3477
|
amount: i === agents.length - 1 ? perAgent + remainder : perAgent
|
|
5154
3478
|
}));
|
|
5155
|
-
const
|
|
3479
|
+
const valid = splits.filter(
|
|
5156
3480
|
(s) => s.amount > 0n && (exempt.has(s.agent.id) || s.amount >= this.getMinDepositAmount(s.agent, chainId, asset))
|
|
5157
3481
|
);
|
|
5158
|
-
if (
|
|
3482
|
+
if (valid.length === agents.length) {
|
|
5159
3483
|
return splits.map((s) => ({ agent: s.agent, amount: String(s.amount) }));
|
|
5160
3484
|
}
|
|
5161
3485
|
const targets = agentsRequiringActivation.length > 0 ? agentsRequiringActivation : agents;
|
|
@@ -5174,11 +3498,6 @@ var OwneySDK = class {
|
|
|
5174
3498
|
)
|
|
5175
3499
|
}));
|
|
5176
3500
|
}
|
|
5177
|
-
formatAgentName(agentId) {
|
|
5178
|
-
if (agentId === "zyfai") return "Zyfai";
|
|
5179
|
-
if (agentId === "yieldseeker") return "Yieldseeker";
|
|
5180
|
-
return agentId;
|
|
5181
|
-
}
|
|
5182
3501
|
async validateMinDepositAmount(agent, state, chainId, asset, amount) {
|
|
5183
3502
|
const minDepositAmount = this.getMinDepositAmount(agent, chainId, asset);
|
|
5184
3503
|
const parsedAmount = BigInt(amount);
|
|
@@ -5210,12 +3529,12 @@ var OwneySDK = class {
|
|
|
5210
3529
|
(t) => t.chainId === chainId && t.asset.toLowerCase() === target
|
|
5211
3530
|
);
|
|
5212
3531
|
const targetChainName = agent.supportedAssets.find((entry) => entry.chainId === chainId)?.chain?.trim().toUpperCase();
|
|
5213
|
-
const
|
|
3532
|
+
const position = (balance.positions ?? []).find((p) => {
|
|
5214
3533
|
const positionChain = p.chain.trim().toUpperCase();
|
|
5215
3534
|
const matchesChain = positionChain === String(chainId) || targetChainName !== void 0 && positionChain === targetChainName;
|
|
5216
3535
|
return matchesChain && p.asset.toLowerCase() === target && Number(p.amount) > 0;
|
|
5217
3536
|
});
|
|
5218
|
-
return !!token && Number(token.amount) > 0 || !!
|
|
3537
|
+
return !!token && Number(token.amount) > 0 || !!position;
|
|
5219
3538
|
} catch (error) {
|
|
5220
3539
|
if (requireReliableRead) {
|
|
5221
3540
|
throw new OwneyError(
|
|
@@ -5330,10 +3649,6 @@ var OwneySDK = class {
|
|
|
5330
3649
|
}
|
|
5331
3650
|
const requested = BigInt(amount);
|
|
5332
3651
|
const aggregated = await this.getBalances();
|
|
5333
|
-
const unavailableAgents = eligibleAgents.filter(
|
|
5334
|
-
(agent) => !(agent.id in aggregated.agentBalances)
|
|
5335
|
-
);
|
|
5336
|
-
const unavailableAgentIds = unavailableAgents.map((agent) => agent.id);
|
|
5337
3652
|
const balances = projectAgentBalancesForAsset(
|
|
5338
3653
|
eligibleAgents,
|
|
5339
3654
|
aggregated.agentBalances,
|
|
@@ -5342,18 +3657,7 @@ var OwneySDK = class {
|
|
|
5342
3657
|
assetInfo.decimals
|
|
5343
3658
|
);
|
|
5344
3659
|
const totalAvailable = balances.reduce((sum, x) => sum + x.balance, 0n);
|
|
5345
|
-
if (totalAvailable
|
|
5346
|
-
throw new OwneyError(
|
|
5347
|
-
"WITHDRAW_BALANCE_UNAVAILABLE",
|
|
5348
|
-
`Cannot safely plan the withdrawal because balance data is unavailable for: ${unavailableAgentIds.join(", ")}.`,
|
|
5349
|
-
{
|
|
5350
|
-
asset,
|
|
5351
|
-
unavailableAgents: unavailableAgentIds,
|
|
5352
|
-
agentErrors: aggregated.agentErrors
|
|
5353
|
-
}
|
|
5354
|
-
);
|
|
5355
|
-
}
|
|
5356
|
-
if (totalAvailable < requested && unavailableAgents.length === 0) {
|
|
3660
|
+
if (totalAvailable < requested) {
|
|
5357
3661
|
throw new OwneyError(
|
|
5358
3662
|
"WITHDRAW_INSUFFICIENT_BALANCE",
|
|
5359
3663
|
`Requested withdrawal "${amount}" exceeds available balance "${totalAvailable.toString()}" for asset "${asset}".`,
|
|
@@ -5364,7 +3668,6 @@ var OwneySDK = class {
|
|
|
5364
3668
|
}
|
|
5365
3669
|
);
|
|
5366
3670
|
}
|
|
5367
|
-
const plannedTarget = totalAvailable < requested ? totalAvailable : requested;
|
|
5368
3671
|
const disabledBalances = balances.filter(
|
|
5369
3672
|
(b) => this.isAgentDisabled(b.agent.id)
|
|
5370
3673
|
);
|
|
@@ -5373,7 +3676,7 @@ var OwneySDK = class {
|
|
|
5373
3676
|
);
|
|
5374
3677
|
const { plans: disabledPlans, remaining: afterDrain } = planDisabledDrain(
|
|
5375
3678
|
disabledBalances,
|
|
5376
|
-
|
|
3679
|
+
requested
|
|
5377
3680
|
);
|
|
5378
3681
|
const enabledTotal = enabledBalances.reduce((s, b) => s + b.balance, 0n);
|
|
5379
3682
|
const enabledPlans = afterDrain > 0n ? planProportionalShares(enabledBalances, afterDrain, enabledTotal) : enabledBalances.map(({ agent, balance }) => ({
|
|
@@ -5383,9 +3686,7 @@ var OwneySDK = class {
|
|
|
5383
3686
|
}));
|
|
5384
3687
|
const plans = [...disabledPlans, ...enabledPlans];
|
|
5385
3688
|
const results = {};
|
|
5386
|
-
const agentErrors = {
|
|
5387
|
-
...aggregated.agentErrors ?? {}
|
|
5388
|
-
};
|
|
3689
|
+
const agentErrors = {};
|
|
5389
3690
|
for (let i = 0; i < plans.length; i++) {
|
|
5390
3691
|
const p = plans[i];
|
|
5391
3692
|
if (p.planned === 0n) continue;
|
|
@@ -5432,8 +3733,7 @@ var OwneySDK = class {
|
|
|
5432
3733
|
requested: amount,
|
|
5433
3734
|
withdrawn: withdrawn.toString(),
|
|
5434
3735
|
partialResults: results,
|
|
5435
|
-
agentErrors
|
|
5436
|
-
...unavailableAgentIds.length > 0 ? { unavailableAgents: unavailableAgentIds } : {}
|
|
3736
|
+
agentErrors
|
|
5437
3737
|
}
|
|
5438
3738
|
);
|
|
5439
3739
|
}
|
|
@@ -5451,10 +3751,7 @@ var OwneySDK = class {
|
|
|
5451
3751
|
if (agentId) {
|
|
5452
3752
|
const agent = this.getAgent(agentId);
|
|
5453
3753
|
const result = await this.readAgent(agent, "balances", () => agent.getBalances(state, chainId));
|
|
5454
|
-
return
|
|
5455
|
-
...result,
|
|
5456
|
-
balanceComposition: agent.balanceComposition ?? "tokens-include-positions"
|
|
5457
|
-
};
|
|
3754
|
+
return result;
|
|
5458
3755
|
}
|
|
5459
3756
|
let totalBalance = 0;
|
|
5460
3757
|
const results = {};
|
|
@@ -5462,13 +3759,7 @@ var OwneySDK = class {
|
|
|
5462
3759
|
const balanceResults = await Promise.allSettled(
|
|
5463
3760
|
entries.map(async ([id, agent]) => {
|
|
5464
3761
|
const b = await this.readAgent(agent, "balances", () => agent.getBalances(state, chainId));
|
|
5465
|
-
return [
|
|
5466
|
-
id,
|
|
5467
|
-
{
|
|
5468
|
-
...b,
|
|
5469
|
-
balanceComposition: agent.balanceComposition ?? "tokens-include-positions"
|
|
5470
|
-
}
|
|
5471
|
-
];
|
|
3762
|
+
return [id, b];
|
|
5472
3763
|
})
|
|
5473
3764
|
);
|
|
5474
3765
|
let successCount = 0;
|
|
@@ -5490,7 +3781,6 @@ var OwneySDK = class {
|
|
|
5490
3781
|
const retryDelay = rateLimitDelay(reason);
|
|
5491
3782
|
if (retryDelay !== void 0) agentRetryAt[agentId2] = Date.now() + retryDelay;
|
|
5492
3783
|
agentErrors[agentId2] = reason instanceof Error ? reason.message : String(reason);
|
|
5493
|
-
console.error(`[owney-sdk] Balance fetch failed for agent "${agentId2}":`, reason);
|
|
5494
3784
|
}
|
|
5495
3785
|
if (successCount === 0) {
|
|
5496
3786
|
throw new OwneyError(
|
|
@@ -5603,10 +3893,7 @@ var OwneySDK = class {
|
|
|
5603
3893
|
Promise.all(
|
|
5604
3894
|
entries.map(async ([id, agent]) => {
|
|
5605
3895
|
const b = await this.readAgent(agent, "balances", () => agent.getBalances(state, chainId));
|
|
5606
|
-
return [
|
|
5607
|
-
id,
|
|
5608
|
-
balanceForApyScope(b, chainId, tokenSymbol)
|
|
5609
|
-
];
|
|
3896
|
+
return [id, Number(b.totalBalance)];
|
|
5610
3897
|
})
|
|
5611
3898
|
)
|
|
5612
3899
|
]);
|
|
@@ -5634,12 +3921,10 @@ var OwneySDK = class {
|
|
|
5634
3921
|
}
|
|
5635
3922
|
}
|
|
5636
3923
|
const apyByChainAndAsset = aggregateApyByChainAndAsset(results, balances);
|
|
5637
|
-
const history = aggregateApyHistory(results, balances);
|
|
5638
3924
|
return {
|
|
5639
3925
|
totalApy: String(totalApy),
|
|
5640
3926
|
agentApy: results,
|
|
5641
|
-
apyByChainAndAsset
|
|
5642
|
-
history
|
|
3927
|
+
apyByChainAndAsset
|
|
5643
3928
|
};
|
|
5644
3929
|
}
|
|
5645
3930
|
/**
|
|
@@ -5787,10 +4072,10 @@ var OwneySDK = class {
|
|
|
5787
4072
|
);
|
|
5788
4073
|
}
|
|
5789
4074
|
const provider = this.requireConnectedProvider();
|
|
5790
|
-
const wallet = (0,
|
|
4075
|
+
const wallet = (0, import_viem6.createWalletClient)({
|
|
5791
4076
|
account: state.walletAddress,
|
|
5792
4077
|
chain: VIEM_CHAIN2[chainId],
|
|
5793
|
-
transport: (0,
|
|
4078
|
+
transport: (0, import_viem6.custom)(provider)
|
|
5794
4079
|
});
|
|
5795
4080
|
const hash = await wallet.writeContract({
|
|
5796
4081
|
address: token,
|
|
@@ -5800,9 +4085,9 @@ var OwneySDK = class {
|
|
|
5800
4085
|
account: state.walletAddress,
|
|
5801
4086
|
chain: VIEM_CHAIN2[chainId]
|
|
5802
4087
|
});
|
|
5803
|
-
const publicClient = (0,
|
|
4088
|
+
const publicClient = (0, import_viem6.createPublicClient)({
|
|
5804
4089
|
chain: VIEM_CHAIN2[chainId],
|
|
5805
|
-
transport: (0,
|
|
4090
|
+
transport: (0, import_viem6.custom)(provider)
|
|
5806
4091
|
});
|
|
5807
4092
|
const receipt = await publicClient.waitForTransactionReceipt({
|
|
5808
4093
|
hash,
|
|
@@ -5839,9 +4124,7 @@ var OwneySDK = class {
|
|
|
5839
4124
|
return this.readAgent(agent, "agentApy", () => agent.getAgentApy(days, agentOptions), { days, ...agentOptions });
|
|
5840
4125
|
}
|
|
5841
4126
|
const results = {};
|
|
5842
|
-
const agentEntries = [...this.agents.entries()]
|
|
5843
|
-
([id]) => !this.isAgentDisabled(id)
|
|
5844
|
-
);
|
|
4127
|
+
const agentEntries = [...this.agents.entries()];
|
|
5845
4128
|
const apyResults = await Promise.all(
|
|
5846
4129
|
agentEntries.map(async ([id, agent]) => {
|
|
5847
4130
|
const apy = await this.readAgent(agent, "agentApy", () => agent.getAgentApy(days, agentOptions), { days, ...agentOptions });
|
|
@@ -5916,13 +4199,13 @@ var OwneySDK = class {
|
|
|
5916
4199
|
};
|
|
5917
4200
|
|
|
5918
4201
|
// src/agents/zyfai/zyfai.siwx.ts
|
|
5919
|
-
var
|
|
5920
|
-
var
|
|
4202
|
+
var import_viem7 = require("viem");
|
|
4203
|
+
var import_siwe = require("siwe");
|
|
5921
4204
|
var import_sdk2 = require("@zyfai/sdk");
|
|
5922
4205
|
|
|
5923
4206
|
// src/agents/zyfai/zyfai.siwx-cache.ts
|
|
5924
|
-
var
|
|
5925
|
-
var
|
|
4207
|
+
var KEY_PREFIX2 = "owney.siwx.session";
|
|
4208
|
+
var storage2 = () => {
|
|
5926
4209
|
if (typeof window === "undefined") return null;
|
|
5927
4210
|
try {
|
|
5928
4211
|
return window.localStorage;
|
|
@@ -5930,8 +4213,8 @@ var storage4 = () => {
|
|
|
5930
4213
|
return null;
|
|
5931
4214
|
}
|
|
5932
4215
|
};
|
|
5933
|
-
var
|
|
5934
|
-
var legacyKeyPrefix2 = (address) => `${
|
|
4216
|
+
var buildKey2 = (address) => `${KEY_PREFIX2}:${address.toLowerCase()}`;
|
|
4217
|
+
var legacyKeyPrefix2 = (address) => `${KEY_PREFIX2}:${address.toLowerCase()}:`;
|
|
5935
4218
|
var memorySiwxSessions = /* @__PURE__ */ new Map();
|
|
5936
4219
|
var readLegacySiwxSession = (store, address) => {
|
|
5937
4220
|
if (!store) return null;
|
|
@@ -5962,17 +4245,17 @@ var readLegacySiwxSession = (store, address) => {
|
|
|
5962
4245
|
};
|
|
5963
4246
|
var readSiwxSession = (address, chainId) => {
|
|
5964
4247
|
if (typeof window === "undefined") return null;
|
|
5965
|
-
const key2 =
|
|
5966
|
-
const store =
|
|
5967
|
-
let
|
|
4248
|
+
const key2 = buildKey2(address);
|
|
4249
|
+
const store = storage2();
|
|
4250
|
+
let raw = null;
|
|
5968
4251
|
try {
|
|
5969
|
-
|
|
4252
|
+
raw = store?.getItem(key2) ?? null;
|
|
5970
4253
|
} catch {
|
|
5971
|
-
|
|
4254
|
+
raw = null;
|
|
5972
4255
|
}
|
|
5973
|
-
if (
|
|
4256
|
+
if (raw) {
|
|
5974
4257
|
try {
|
|
5975
|
-
return JSON.parse(
|
|
4258
|
+
return JSON.parse(raw);
|
|
5976
4259
|
} catch {
|
|
5977
4260
|
memorySiwxSessions.delete(key2);
|
|
5978
4261
|
try {
|
|
@@ -5991,18 +4274,18 @@ var readSiwxSession = (address, chainId) => {
|
|
|
5991
4274
|
};
|
|
5992
4275
|
var writeSiwxSession = (address, _chainId, session) => {
|
|
5993
4276
|
if (typeof window === "undefined") return;
|
|
5994
|
-
const key2 =
|
|
4277
|
+
const key2 = buildKey2(address);
|
|
5995
4278
|
memorySiwxSessions.set(key2, session);
|
|
5996
|
-
const store =
|
|
4279
|
+
const store = storage2();
|
|
5997
4280
|
try {
|
|
5998
4281
|
store?.setItem(key2, JSON.stringify(session));
|
|
5999
4282
|
} catch {
|
|
6000
4283
|
}
|
|
6001
4284
|
};
|
|
6002
4285
|
var clearSiwxSession = (address, _chainId) => {
|
|
6003
|
-
const key2 =
|
|
4286
|
+
const key2 = buildKey2(address);
|
|
6004
4287
|
memorySiwxSessions.delete(key2);
|
|
6005
|
-
const store =
|
|
4288
|
+
const store = storage2();
|
|
6006
4289
|
try {
|
|
6007
4290
|
store?.removeItem(key2);
|
|
6008
4291
|
} catch {
|
|
@@ -6042,8 +4325,8 @@ function buildSIWXConfig(deps) {
|
|
|
6042
4325
|
statement: STATEMENT,
|
|
6043
4326
|
issuedAt,
|
|
6044
4327
|
toString() {
|
|
6045
|
-
return new
|
|
6046
|
-
address: (0,
|
|
4328
|
+
return new import_siwe.SiweMessage({
|
|
4329
|
+
address: (0, import_viem7.getAddress)(accountAddress),
|
|
6047
4330
|
chainId: numericChainId(chainId),
|
|
6048
4331
|
domain,
|
|
6049
4332
|
uri,
|
|
@@ -6085,7 +4368,7 @@ function buildSIWXConfig(deps) {
|
|
|
6085
4368
|
const persistSession = async (session) => {
|
|
6086
4369
|
const address = session.data.accountAddress;
|
|
6087
4370
|
const id = numericChainId(session.data.chainId);
|
|
6088
|
-
const message = new
|
|
4371
|
+
const message = new import_siwe.SiweMessage(session.message);
|
|
6089
4372
|
const login = await post("/auth/login", {
|
|
6090
4373
|
message,
|
|
6091
4374
|
signature: session.signature,
|
|
@@ -6094,7 +4377,8 @@ function buildSIWXConfig(deps) {
|
|
|
6094
4377
|
writeSession(address, id, {
|
|
6095
4378
|
token: login.accessToken,
|
|
6096
4379
|
userId: login.userId ?? null,
|
|
6097
|
-
hasActiveSessionKey: Boolean(login.hasActiveSessionKey)
|
|
4380
|
+
hasActiveSessionKey: Boolean(login.hasActiveSessionKey),
|
|
4381
|
+
isPredeployed: login.predeployed
|
|
6098
4382
|
});
|
|
6099
4383
|
const stored = {
|
|
6100
4384
|
data: session.data,
|
|
@@ -6134,7 +4418,6 @@ function createOwneySIWX(config) {
|
|
|
6134
4418
|
NotConnectedError,
|
|
6135
4419
|
OwneyError,
|
|
6136
4420
|
OwneySDK,
|
|
6137
|
-
YieldseekerAgent,
|
|
6138
4421
|
createOwneySIWX,
|
|
6139
4422
|
setOwneyDebug
|
|
6140
4423
|
});
|