@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.js
CHANGED
|
@@ -277,18 +277,18 @@ function tokenDecimals(symbol, explicit) {
|
|
|
277
277
|
return explicit;
|
|
278
278
|
return DECIMALS_BY_SYMBOL[(symbol ?? "").toLowerCase()] ?? 6;
|
|
279
279
|
}
|
|
280
|
-
function mapDeposit(
|
|
280
|
+
function mapDeposit(raw) {
|
|
281
281
|
return {
|
|
282
|
-
txHash:
|
|
283
|
-
smartWallet:
|
|
284
|
-
amount:
|
|
282
|
+
txHash: raw.txHash,
|
|
283
|
+
smartWallet: raw.smartWallet,
|
|
284
|
+
amount: raw.amount
|
|
285
285
|
};
|
|
286
286
|
}
|
|
287
|
-
function mapWithdraw(
|
|
287
|
+
function mapWithdraw(raw) {
|
|
288
288
|
return {
|
|
289
|
-
txHash:
|
|
290
|
-
type:
|
|
291
|
-
amount:
|
|
289
|
+
txHash: raw.txHash,
|
|
290
|
+
type: raw.type,
|
|
291
|
+
amount: raw.amount
|
|
292
292
|
};
|
|
293
293
|
}
|
|
294
294
|
var CHAIN_ID_TO_NAME = {
|
|
@@ -307,10 +307,10 @@ function resolveChainId(chain) {
|
|
|
307
307
|
if (Number.isFinite(asNum) && asNum > 0) return asNum;
|
|
308
308
|
return NAME_TO_CHAIN_ID[chain.trim().toLowerCase()] ?? NaN;
|
|
309
309
|
}
|
|
310
|
-
function mapPendingAllocations(
|
|
311
|
-
if (!Array.isArray(
|
|
310
|
+
function mapPendingAllocations(raw) {
|
|
311
|
+
if (!Array.isArray(raw)) return void 0;
|
|
312
312
|
const pending = [];
|
|
313
|
-
for (const entry of
|
|
313
|
+
for (const entry of raw) {
|
|
314
314
|
if (typeof entry !== "object" || entry === null) continue;
|
|
315
315
|
const e = entry;
|
|
316
316
|
if (typeof e.chainId !== "number" || !Number.isFinite(e.chainId)) continue;
|
|
@@ -333,8 +333,8 @@ function mapPendingAllocations(raw2) {
|
|
|
333
333
|
}
|
|
334
334
|
return pending.length > 0 ? pending : void 0;
|
|
335
335
|
}
|
|
336
|
-
function mapBalances(
|
|
337
|
-
const portfolio =
|
|
336
|
+
function mapBalances(raw, _chainId, smartWallet) {
|
|
337
|
+
const portfolio = raw.portfolio;
|
|
338
338
|
const portfolioByChain = portfolio.portfolioByChain ?? {};
|
|
339
339
|
let totalBalance = 0;
|
|
340
340
|
const tokens = [];
|
|
@@ -403,8 +403,8 @@ function sumTokenValues(tokens) {
|
|
|
403
403
|
function sumTokenEarnings(tokens) {
|
|
404
404
|
return Object.values(tokens).reduce((sum, val) => sum + Number(val), 0);
|
|
405
405
|
}
|
|
406
|
-
function mapEarnings(
|
|
407
|
-
const totalEarningsByChain =
|
|
406
|
+
function mapEarnings(raw, smartWallet) {
|
|
407
|
+
const totalEarningsByChain = raw.data.totalEarningsByChainWithFee ?? raw.data.totalEarningsByChain ?? {};
|
|
408
408
|
const tokens = [];
|
|
409
409
|
for (const [chainIdKey, tokensBySymbol] of Object.entries(
|
|
410
410
|
totalEarningsByChain
|
|
@@ -423,15 +423,15 @@ function mapEarnings(raw2, smartWallet) {
|
|
|
423
423
|
return {
|
|
424
424
|
smartWallet,
|
|
425
425
|
lifetimeEarnings: sumTokenEarnings(
|
|
426
|
-
|
|
426
|
+
raw.data.totalEarningsByTokenWithFee ?? raw.data.totalEarningsByToken
|
|
427
427
|
),
|
|
428
428
|
tokens
|
|
429
429
|
};
|
|
430
430
|
}
|
|
431
|
-
function mapWeightedApyByChain(
|
|
432
|
-
if (!
|
|
431
|
+
function mapWeightedApyByChain(raw) {
|
|
432
|
+
if (!raw) return void 0;
|
|
433
433
|
const out = {};
|
|
434
|
-
for (const [chainKey, tokenApy] of Object.entries(
|
|
434
|
+
for (const [chainKey, tokenApy] of Object.entries(raw)) {
|
|
435
435
|
const chainId = Number(chainKey);
|
|
436
436
|
if (!SUPPORTED_CHAIN_IDS.includes(chainId)) continue;
|
|
437
437
|
const perAsset = {};
|
|
@@ -471,15 +471,15 @@ function rawPoolApyForChain(entry, chainId, tokenSymbol) {
|
|
|
471
471
|
}
|
|
472
472
|
return totalBalance > 0 ? weightedSum / totalBalance : null;
|
|
473
473
|
}
|
|
474
|
-
function mapApyHistory(
|
|
475
|
-
const history = Object.entries(
|
|
474
|
+
function mapApyHistory(raw, chainId, tokenSymbol) {
|
|
475
|
+
const history = Object.entries(raw.history ?? {}).map(([date, entry]) => ({
|
|
476
476
|
date,
|
|
477
477
|
apy: rawPoolApyForChain(entry, chainId, tokenSymbol)
|
|
478
478
|
})).filter((p) => p.apy !== null).sort((a, b) => a.date.localeCompare(b.date));
|
|
479
479
|
return {
|
|
480
|
-
walletAddress:
|
|
481
|
-
weightedApyAfterFee:
|
|
482
|
-
apyByChainAndAsset: mapWeightedApyByChain(
|
|
480
|
+
walletAddress: raw.walletAddress,
|
|
481
|
+
weightedApyAfterFee: raw.weightedApyAfterFee ? sumTokenValues(raw.weightedApyAfterFee) : void 0,
|
|
482
|
+
apyByChainAndAsset: mapWeightedApyByChain(raw.weightedApyAfterFeeByChain),
|
|
483
483
|
history
|
|
484
484
|
};
|
|
485
485
|
}
|
|
@@ -575,23 +575,23 @@ function mapEntries(rawEntries, chainId) {
|
|
|
575
575
|
};
|
|
576
576
|
});
|
|
577
577
|
}
|
|
578
|
-
function mapUserProfile(
|
|
578
|
+
function mapUserProfile(raw, userAddress) {
|
|
579
579
|
return {
|
|
580
580
|
address: userAddress,
|
|
581
|
-
smartWallet:
|
|
582
|
-
chains:
|
|
583
|
-
strategy:
|
|
584
|
-
hasActiveSessionKey:
|
|
585
|
-
protocols:
|
|
586
|
-
splitting:
|
|
587
|
-
minSplits:
|
|
581
|
+
smartWallet: raw.smartWallet || "",
|
|
582
|
+
chains: raw.chains || [],
|
|
583
|
+
strategy: raw.strategy,
|
|
584
|
+
hasActiveSessionKey: raw.hasActiveSessionKey || false,
|
|
585
|
+
protocols: raw.protocols || [],
|
|
586
|
+
splitting: raw.splitting,
|
|
587
|
+
minSplits: raw.minSplits
|
|
588
588
|
};
|
|
589
589
|
}
|
|
590
|
-
function mapApyByStrategy(
|
|
590
|
+
function mapApyByStrategy(raw) {
|
|
591
591
|
const apyPerAsset = {};
|
|
592
592
|
let apySum = 0;
|
|
593
593
|
let apyCount = 0;
|
|
594
|
-
for (const entry of
|
|
594
|
+
for (const entry of raw.data) {
|
|
595
595
|
const supported = SupportedAssets.find(
|
|
596
596
|
(asset) => asset.chainId === entry.chain_id && asset.symbol === entry.token_symbol
|
|
597
597
|
);
|
|
@@ -729,7 +729,7 @@ var isJwtExpired = (token) => {
|
|
|
729
729
|
}
|
|
730
730
|
};
|
|
731
731
|
var memorySessions = /* @__PURE__ */ new Map();
|
|
732
|
-
var isFreshSession = (session) => !!session && !!session.token && !isJwtExpired(session.token);
|
|
732
|
+
var isFreshSession = (session) => !!session && typeof session.isPredeployed === "boolean" && !!session.token && !isJwtExpired(session.token);
|
|
733
733
|
var readLegacySession = (store, address) => {
|
|
734
734
|
if (!store) return null;
|
|
735
735
|
const prefix = legacyKeyPrefix(address);
|
|
@@ -762,15 +762,15 @@ var readSession = (address, _chainId) => {
|
|
|
762
762
|
if (typeof window === "undefined") return null;
|
|
763
763
|
const key2 = buildKey(address);
|
|
764
764
|
const store = storage();
|
|
765
|
-
let
|
|
765
|
+
let raw = null;
|
|
766
766
|
try {
|
|
767
|
-
|
|
767
|
+
raw = store?.getItem(key2) ?? null;
|
|
768
768
|
} catch {
|
|
769
|
-
|
|
769
|
+
raw = null;
|
|
770
770
|
}
|
|
771
|
-
if (
|
|
771
|
+
if (raw) {
|
|
772
772
|
try {
|
|
773
|
-
const parsed = JSON.parse(
|
|
773
|
+
const parsed = JSON.parse(raw);
|
|
774
774
|
if (isFreshSession(parsed)) return parsed;
|
|
775
775
|
} catch {
|
|
776
776
|
}
|
|
@@ -938,8 +938,8 @@ function buildChainsByProtocol(protocols, dashboardChainIds) {
|
|
|
938
938
|
}
|
|
939
939
|
return result;
|
|
940
940
|
}
|
|
941
|
-
function flattenAvailablePools(
|
|
942
|
-
const byChain =
|
|
941
|
+
function flattenAvailablePools(raw) {
|
|
942
|
+
const byChain = raw ?? {};
|
|
943
943
|
const names = [];
|
|
944
944
|
for (const byToken of Object.values(byChain ?? {})) {
|
|
945
945
|
for (const entry of Object.values(byToken ?? {})) {
|
|
@@ -1144,6 +1144,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1144
1144
|
internals.httpClient.setAuthToken(cached.token);
|
|
1145
1145
|
internals.authenticatedUserId = cached.userId;
|
|
1146
1146
|
internals.hasActiveSessionKey = cached.hasActiveSessionKey;
|
|
1147
|
+
internals.isPredeployed = cached.isPredeployed;
|
|
1147
1148
|
return;
|
|
1148
1149
|
}
|
|
1149
1150
|
}
|
|
@@ -1155,7 +1156,8 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1155
1156
|
writeSession(newAddress, newChainId, {
|
|
1156
1157
|
token: newToken,
|
|
1157
1158
|
userId: internals.authenticatedUserId,
|
|
1158
|
-
hasActiveSessionKey: internals.hasActiveSessionKey
|
|
1159
|
+
hasActiveSessionKey: internals.hasActiveSessionKey,
|
|
1160
|
+
isPredeployed: internals.isPredeployed
|
|
1159
1161
|
});
|
|
1160
1162
|
}
|
|
1161
1163
|
};
|
|
@@ -1440,8 +1442,8 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1440
1442
|
const poolResults = await Promise.all(
|
|
1441
1443
|
universe.map(async (protocol) => {
|
|
1442
1444
|
try {
|
|
1443
|
-
const
|
|
1444
|
-
return [protocol.id, flattenAvailablePools(
|
|
1445
|
+
const raw = await this.sdk.getAvailablePools(protocol.id, strategy);
|
|
1446
|
+
return [protocol.id, flattenAvailablePools(raw)];
|
|
1445
1447
|
} catch (error) {
|
|
1446
1448
|
console.warn(
|
|
1447
1449
|
`[zyfai] applyPoolPolicy: getAvailablePools(${protocol.id}) failed, skipping this protocol (non-fatal):`,
|
|
@@ -1507,14 +1509,14 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1507
1509
|
async readWalletState(ownerAddress) {
|
|
1508
1510
|
try {
|
|
1509
1511
|
const { portfolio } = await this.sdk.getPositions(ownerAddress);
|
|
1510
|
-
const
|
|
1512
|
+
const raw = portfolio;
|
|
1511
1513
|
debugLog("zyfai:onboard", "wallet state from getPositions", {
|
|
1512
|
-
predeployed:
|
|
1513
|
-
hasActiveSessionKey:
|
|
1514
|
+
predeployed: raw?.predeployed,
|
|
1515
|
+
hasActiveSessionKey: raw?.hasActiveSessionKey
|
|
1514
1516
|
});
|
|
1515
1517
|
return {
|
|
1516
|
-
predeployed:
|
|
1517
|
-
hasActiveSessionKey:
|
|
1518
|
+
predeployed: raw?.predeployed,
|
|
1519
|
+
hasActiveSessionKey: raw?.hasActiveSessionKey
|
|
1518
1520
|
};
|
|
1519
1521
|
} catch (error) {
|
|
1520
1522
|
console.warn(
|
|
@@ -1606,12 +1608,10 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1606
1608
|
);
|
|
1607
1609
|
return;
|
|
1608
1610
|
}
|
|
1609
|
-
const { hasActiveSessionKey } = await this.readWalletState(ownerAddress);
|
|
1610
1611
|
await this.ensureSessionKey(
|
|
1611
1612
|
ownerAddress,
|
|
1612
1613
|
chainId,
|
|
1613
|
-
wallet.address
|
|
1614
|
-
hasActiveSessionKey
|
|
1614
|
+
wallet.address
|
|
1615
1615
|
);
|
|
1616
1616
|
} catch (error) {
|
|
1617
1617
|
console.warn(
|
|
@@ -1620,7 +1620,17 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1620
1620
|
);
|
|
1621
1621
|
}
|
|
1622
1622
|
}
|
|
1623
|
-
async ensureSessionKey(ownerAddress, chainId, smartWallet
|
|
1623
|
+
async ensureSessionKey(ownerAddress, chainId, smartWallet) {
|
|
1624
|
+
const walletState = await this.readWalletState(ownerAddress);
|
|
1625
|
+
const predeployed = walletState.predeployed;
|
|
1626
|
+
if (predeployed !== false) {
|
|
1627
|
+
debugLog("zyfai:onboard", "skipping manual session key", {
|
|
1628
|
+
chainId,
|
|
1629
|
+
predeployed
|
|
1630
|
+
});
|
|
1631
|
+
return;
|
|
1632
|
+
}
|
|
1633
|
+
const hasActiveSessionKey = walletState.hasActiveSessionKey;
|
|
1624
1634
|
const attemptKey = `${ownerAddress.toLowerCase()}:${chainId}`;
|
|
1625
1635
|
if (this.sessionKeyAttempts.has(attemptKey)) {
|
|
1626
1636
|
debugLog(
|
|
@@ -1713,12 +1723,10 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1713
1723
|
"zyfai:onboard",
|
|
1714
1724
|
"Safe already has code -> no deploy needed, checking the session key"
|
|
1715
1725
|
);
|
|
1716
|
-
const { hasActiveSessionKey } = await this.readWalletState(ownerAddress);
|
|
1717
1726
|
await this.ensureSessionKey(
|
|
1718
1727
|
ownerAddress,
|
|
1719
1728
|
chainId,
|
|
1720
|
-
wallet.address
|
|
1721
|
-
hasActiveSessionKey
|
|
1729
|
+
wallet.address
|
|
1722
1730
|
);
|
|
1723
1731
|
return wallet.address;
|
|
1724
1732
|
}
|
|
@@ -1794,14 +1802,14 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1794
1802
|
return { txHash, smartWallet, amount };
|
|
1795
1803
|
}
|
|
1796
1804
|
await this.ensureWalletDeployed(this.getAddress(), validChainId);
|
|
1797
|
-
const
|
|
1805
|
+
const raw = await this.sdk.depositFunds(
|
|
1798
1806
|
this.getAddress(),
|
|
1799
1807
|
validChainId,
|
|
1800
1808
|
amount,
|
|
1801
1809
|
asset,
|
|
1802
1810
|
"aggressive"
|
|
1803
1811
|
);
|
|
1804
|
-
return mapDeposit(
|
|
1812
|
+
return mapDeposit(raw);
|
|
1805
1813
|
} catch (error) {
|
|
1806
1814
|
throw error;
|
|
1807
1815
|
}
|
|
@@ -1810,27 +1818,27 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1810
1818
|
async withdraw(state, chainId, token, amount) {
|
|
1811
1819
|
const validChainId = isValidChainId(chainId);
|
|
1812
1820
|
await this.ensureConnected(state, validChainId);
|
|
1813
|
-
const
|
|
1821
|
+
const raw = await this.sdk.withdrawFunds(
|
|
1814
1822
|
this.getAddress(),
|
|
1815
1823
|
validChainId,
|
|
1816
1824
|
amount,
|
|
1817
1825
|
token
|
|
1818
1826
|
);
|
|
1819
|
-
if (!
|
|
1827
|
+
if (!raw.success) {
|
|
1820
1828
|
throw new OwneyError(
|
|
1821
1829
|
"WITHDRAW_FAILED",
|
|
1822
|
-
|
|
1823
|
-
{ chainId: validChainId, token, amount, response:
|
|
1830
|
+
raw.message || "Zyfai withdraw failed.",
|
|
1831
|
+
{ chainId: validChainId, token, amount, response: raw },
|
|
1824
1832
|
this.id
|
|
1825
1833
|
);
|
|
1826
1834
|
}
|
|
1827
|
-
return mapWithdraw(
|
|
1835
|
+
return mapWithdraw(raw);
|
|
1828
1836
|
}
|
|
1829
1837
|
// --- IAgent: Portfolio reads ---
|
|
1830
1838
|
async getBalances(state, chainId) {
|
|
1831
1839
|
const { smartWallet, chainId: validChainId } = await this.resolveSmartWallet(state, chainId);
|
|
1832
|
-
const
|
|
1833
|
-
return mapBalances(
|
|
1840
|
+
const raw = await this.sdk.getPortfolio(this.getAddress());
|
|
1841
|
+
return mapBalances(raw, validChainId, smartWallet);
|
|
1834
1842
|
}
|
|
1835
1843
|
earningsKey(state, chainId, smartWallet) {
|
|
1836
1844
|
return JSON.stringify([
|
|
@@ -1843,11 +1851,11 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1843
1851
|
const existing = this.earningsReads.get(key2);
|
|
1844
1852
|
if (existing) return existing;
|
|
1845
1853
|
const generation = this.earningsGeneration;
|
|
1846
|
-
const pending = Promise.resolve().then(() => this.sdk.getOnchainEarnings(smartWallet)).then((
|
|
1854
|
+
const pending = Promise.resolve().then(() => this.sdk.getOnchainEarnings(smartWallet)).then((raw) => {
|
|
1847
1855
|
if (generation === this.earningsGeneration) {
|
|
1848
|
-
this.earningsSnapshot = { key: key2, raw
|
|
1856
|
+
this.earningsSnapshot = { key: key2, raw, at: Date.now() };
|
|
1849
1857
|
}
|
|
1850
|
-
return
|
|
1858
|
+
return raw;
|
|
1851
1859
|
}).finally(() => {
|
|
1852
1860
|
if (this.earningsReads.get(key2) === pending)
|
|
1853
1861
|
this.earningsReads.delete(key2);
|
|
@@ -1857,11 +1865,11 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1857
1865
|
}
|
|
1858
1866
|
async getEarnings(state, chainId) {
|
|
1859
1867
|
const { smartWallet } = await this.resolveSmartWallet(state, chainId);
|
|
1860
|
-
const
|
|
1868
|
+
const raw = await this.readEarnings(
|
|
1861
1869
|
this.earningsKey(state, chainId, smartWallet),
|
|
1862
1870
|
smartWallet
|
|
1863
1871
|
);
|
|
1864
|
-
return mapEarnings(
|
|
1872
|
+
return mapEarnings(raw, smartWallet);
|
|
1865
1873
|
}
|
|
1866
1874
|
async refreshEarnings(state, chainId) {
|
|
1867
1875
|
const { smartWallet } = await this.resolveSmartWallet(state, chainId);
|
|
@@ -1888,8 +1896,8 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1888
1896
|
}
|
|
1889
1897
|
async getAccountApy(state, chainId, days, tokenSymbol) {
|
|
1890
1898
|
const { smartWallet } = await this.resolveSmartWallet(state, chainId);
|
|
1891
|
-
const
|
|
1892
|
-
return mapApyHistory(
|
|
1899
|
+
const raw = await this.sdk.getDailyApyHistory(smartWallet, days);
|
|
1900
|
+
return mapApyHistory(raw, chainId, tokenSymbol);
|
|
1893
1901
|
}
|
|
1894
1902
|
/**
|
|
1895
1903
|
* Owney speaks asset symbols ("USDC" / "WETH"); Zyfai's history endpoint
|
|
@@ -1924,7 +1932,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1924
1932
|
const matched = [];
|
|
1925
1933
|
let backendExhausted = false;
|
|
1926
1934
|
for (let i = 0; i < MAX_BACKEND_CALLS && matched.length < limit; i++) {
|
|
1927
|
-
const
|
|
1935
|
+
const raw = await this.sdk.getHistory(smartWallet, validChainId, {
|
|
1928
1936
|
limit: backendPageSize,
|
|
1929
1937
|
offset,
|
|
1930
1938
|
fromDate: options?.fromDate,
|
|
@@ -1935,13 +1943,13 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1935
1943
|
// asset's rows and handing back a page that filters to nothing.
|
|
1936
1944
|
assetType
|
|
1937
1945
|
});
|
|
1938
|
-
|
|
1946
|
+
raw.data.forEach((entry, idx) => {
|
|
1939
1947
|
if (entry.chainId === validChainId) {
|
|
1940
1948
|
matched.push({ entry, rawIdx: offset + idx });
|
|
1941
1949
|
}
|
|
1942
1950
|
});
|
|
1943
|
-
offset +=
|
|
1944
|
-
if (
|
|
1951
|
+
offset += raw.data.length;
|
|
1952
|
+
if (raw.data.length < backendPageSize) {
|
|
1945
1953
|
backendExhausted = true;
|
|
1946
1954
|
break;
|
|
1947
1955
|
}
|
|
@@ -1963,18 +1971,18 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1963
1971
|
}
|
|
1964
1972
|
async getUserProfile(state, chainId) {
|
|
1965
1973
|
await this.connectAuth(state, chainId);
|
|
1966
|
-
const
|
|
1974
|
+
const raw = await this.sdk.getUserDetails();
|
|
1967
1975
|
debugLog("zyfai:profile", "getUserProfile \u2014 Zyfai reports", {
|
|
1968
1976
|
asset: "USDC (default \u2014 no asset passed)",
|
|
1969
|
-
splitting:
|
|
1970
|
-
minSplits:
|
|
1971
|
-
strategy:
|
|
1972
|
-
chains:
|
|
1973
|
-
protocolCount:
|
|
1974
|
-
hasActiveSessionKey:
|
|
1975
|
-
smartWallet:
|
|
1977
|
+
splitting: raw.splitting,
|
|
1978
|
+
minSplits: raw.minSplits,
|
|
1979
|
+
strategy: raw.strategy,
|
|
1980
|
+
chains: raw.chains,
|
|
1981
|
+
protocolCount: raw.protocols?.length,
|
|
1982
|
+
hasActiveSessionKey: raw.hasActiveSessionKey,
|
|
1983
|
+
smartWallet: raw.smartWallet
|
|
1976
1984
|
});
|
|
1977
|
-
return mapUserProfile(
|
|
1985
|
+
return mapUserProfile(raw, this.connectedAddress);
|
|
1978
1986
|
}
|
|
1979
1987
|
async ensureAutoSelectProtocols(state, chainId, asset) {
|
|
1980
1988
|
await this.connectAuth(state, chainId);
|
|
@@ -1993,63 +2001,237 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1993
2001
|
}
|
|
1994
2002
|
// --- IAgent: Discovery (no wallet required) ---
|
|
1995
2003
|
async getAgentApy(days, options) {
|
|
1996
|
-
const
|
|
2004
|
+
const raw = await this.sdk.getAPYPerStrategy(
|
|
1997
2005
|
false,
|
|
1998
2006
|
DayFilterMapping[days],
|
|
1999
2007
|
"aggressive",
|
|
2000
2008
|
options?.chainId,
|
|
2001
2009
|
options?.tokenSymbol
|
|
2002
2010
|
);
|
|
2003
|
-
return mapApyByStrategy(
|
|
2011
|
+
return mapApyByStrategy(raw);
|
|
2004
2012
|
}
|
|
2005
2013
|
};
|
|
2006
2014
|
|
|
2007
|
-
// src/
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
custom as custom2,
|
|
2012
|
-
encodeFunctionData,
|
|
2013
|
-
erc20Abi,
|
|
2014
|
-
getAddress as getAddress2,
|
|
2015
|
-
isAddress as isAddress2
|
|
2016
|
-
} from "viem";
|
|
2017
|
-
import { base as base3 } from "viem/chains";
|
|
2018
|
-
|
|
2019
|
-
// src/lib/chain-guard.ts
|
|
2020
|
-
var CHAIN_NAMES = {
|
|
2021
|
-
1: "Ethereum",
|
|
2022
|
-
8453: "Base",
|
|
2023
|
-
42161: "Arbitrum"
|
|
2024
|
-
};
|
|
2025
|
-
function chainName(chainId) {
|
|
2026
|
-
return CHAIN_NAMES[chainId] ?? `chain ${chainId}`;
|
|
2027
|
-
}
|
|
2028
|
-
async function ensureWalletOnChain(pub, wallet, expected) {
|
|
2029
|
-
const actual = await pub.getChainId();
|
|
2030
|
-
if (actual === expected) return;
|
|
2015
|
+
// src/lib/routing-api.ts
|
|
2016
|
+
var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
2017
|
+
async function fetchOrgAgentConfig(apiKey, baseUrl = ROUTING_API_BASE_URL) {
|
|
2018
|
+
const url = `${baseUrl}/api/v1/agent/org-config`;
|
|
2031
2019
|
try {
|
|
2032
|
-
await
|
|
2020
|
+
const res = await fetch(url, {
|
|
2021
|
+
method: "GET",
|
|
2022
|
+
headers: {
|
|
2023
|
+
"Content-Type": "application/json",
|
|
2024
|
+
"x-owney-api-key": `${apiKey}`
|
|
2025
|
+
}
|
|
2026
|
+
});
|
|
2027
|
+
if (!res.ok) {
|
|
2028
|
+
if (res.status !== 404) {
|
|
2029
|
+
console.warn(
|
|
2030
|
+
`[owney-sdk] Could not read org agent config (${res.status}); leaving user profiles unchanged.`
|
|
2031
|
+
);
|
|
2032
|
+
}
|
|
2033
|
+
return null;
|
|
2034
|
+
}
|
|
2035
|
+
const json = await res.json();
|
|
2036
|
+
const policy = json.success ? json.data ?? null : null;
|
|
2037
|
+
debugLog(
|
|
2038
|
+
"owney-sdk",
|
|
2039
|
+
policy ? "org agent config: loaded" : "org agent config: none set by this partner \u2014 user profiles will be left as they are",
|
|
2040
|
+
policy ?? void 0
|
|
2041
|
+
);
|
|
2042
|
+
return policy;
|
|
2033
2043
|
} catch (error) {
|
|
2044
|
+
console.warn(
|
|
2045
|
+
"[owney-sdk] Could not read org agent config (non-fatal):",
|
|
2046
|
+
error instanceof Error ? error.message : String(error)
|
|
2047
|
+
);
|
|
2048
|
+
return null;
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
async function fetchAgentKeys(apiKey, baseUrl = ROUTING_API_BASE_URL) {
|
|
2052
|
+
const url = `${baseUrl}/api/v1/agent/keys`;
|
|
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
|
+
const text = await res.text().catch(() => "");
|
|
2034
2062
|
throw new OwneyError(
|
|
2035
|
-
"
|
|
2036
|
-
`
|
|
2037
|
-
{
|
|
2038
|
-
expectedChainId: expected,
|
|
2039
|
-
actualChainId: actual,
|
|
2040
|
-
cause: error instanceof Error ? error.message : String(error)
|
|
2041
|
-
}
|
|
2063
|
+
"API_ROUTING_ERROR",
|
|
2064
|
+
`Routing API error ${res.status}: ${text}`,
|
|
2065
|
+
{ statusCode: res.status, responseBody: text }
|
|
2042
2066
|
);
|
|
2043
2067
|
}
|
|
2044
|
-
const
|
|
2045
|
-
if (
|
|
2068
|
+
const json = await res.json();
|
|
2069
|
+
if (!json.success) {
|
|
2046
2070
|
throw new OwneyError(
|
|
2047
|
-
"
|
|
2048
|
-
`
|
|
2049
|
-
{
|
|
2071
|
+
"API_ROUTING_FAILED",
|
|
2072
|
+
`Routing API request failed: ${json.message}`,
|
|
2073
|
+
{ message: json.message }
|
|
2074
|
+
);
|
|
2075
|
+
}
|
|
2076
|
+
return json.data;
|
|
2077
|
+
}
|
|
2078
|
+
|
|
2079
|
+
// src/lib/health-report.ts
|
|
2080
|
+
var ROUTING_API_BASE_URL2 = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
2081
|
+
async function reportAgentFailure(apiKey, agentType, errorCode, baseUrl = ROUTING_API_BASE_URL2) {
|
|
2082
|
+
try {
|
|
2083
|
+
await fetch(`${baseUrl}/api/v1/agent/health-report`, {
|
|
2084
|
+
method: "POST",
|
|
2085
|
+
headers: {
|
|
2086
|
+
"Content-Type": "application/json",
|
|
2087
|
+
"x-owney-api-key": apiKey
|
|
2088
|
+
},
|
|
2089
|
+
body: JSON.stringify({
|
|
2090
|
+
agent_type: agentType,
|
|
2091
|
+
error_code: errorCode,
|
|
2092
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2093
|
+
})
|
|
2094
|
+
});
|
|
2095
|
+
} catch (err) {
|
|
2096
|
+
console.warn(
|
|
2097
|
+
`[owney-sdk] health-report failed for agent "${agentType}":`,
|
|
2098
|
+
err instanceof Error ? err.message : err
|
|
2099
|
+
);
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2102
|
+
async function withFailureReporting(apiKey, agentType, fn, baseUrl) {
|
|
2103
|
+
try {
|
|
2104
|
+
return await fn();
|
|
2105
|
+
} catch (err) {
|
|
2106
|
+
const errorCode = err instanceof OwneyError ? err.code : "SDK_AGENT_FAILURE";
|
|
2107
|
+
void reportAgentFailure(apiKey, agentType, errorCode, baseUrl);
|
|
2108
|
+
throw err;
|
|
2109
|
+
}
|
|
2110
|
+
}
|
|
2111
|
+
|
|
2112
|
+
// src/lib/helpers/withdraw-helper.ts
|
|
2113
|
+
import { parseUnits } from "viem";
|
|
2114
|
+
function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
|
|
2115
|
+
const target = asset.toUpperCase();
|
|
2116
|
+
return agents.map((agent) => {
|
|
2117
|
+
const agentBalance = aggregated[agent.id];
|
|
2118
|
+
const tokenBalance = agentBalance?.tokens.find(
|
|
2119
|
+
(t) => t.chainId === chainId && t.asset.toUpperCase() === target
|
|
2050
2120
|
);
|
|
2121
|
+
if (!tokenBalance) return { agent, balance: 0n };
|
|
2122
|
+
return { agent, balance: parseUnits(tokenBalance.amount, decimals) };
|
|
2123
|
+
});
|
|
2124
|
+
}
|
|
2125
|
+
function planProportionalShares(balances, requested, totalAvailable) {
|
|
2126
|
+
const plans = balances.map(({ agent, balance }) => ({
|
|
2127
|
+
agent,
|
|
2128
|
+
balance,
|
|
2129
|
+
planned: totalAvailable > 0n ? balance * requested / totalAvailable : 0n
|
|
2130
|
+
}));
|
|
2131
|
+
const assigned = plans.reduce((s, p) => s + p.planned, 0n);
|
|
2132
|
+
let remainder = requested - assigned;
|
|
2133
|
+
const byHeadroom = [...plans].sort((a, b) => {
|
|
2134
|
+
const diff = b.balance - b.planned - (a.balance - a.planned);
|
|
2135
|
+
return diff > 0n ? 1 : diff < 0n ? -1 : 0;
|
|
2136
|
+
});
|
|
2137
|
+
for (const p of byHeadroom) {
|
|
2138
|
+
if (remainder === 0n) break;
|
|
2139
|
+
const headroom = p.balance - p.planned;
|
|
2140
|
+
if (headroom <= 0n) continue;
|
|
2141
|
+
const take = headroom < remainder ? headroom : remainder;
|
|
2142
|
+
p.planned += take;
|
|
2143
|
+
remainder -= take;
|
|
2144
|
+
}
|
|
2145
|
+
return plans;
|
|
2146
|
+
}
|
|
2147
|
+
function planDisabledDrain(disabled, requested) {
|
|
2148
|
+
const sorted = [...disabled].filter((d) => d.balance > 0n).sort((a, b) => b.balance > a.balance ? 1 : b.balance < a.balance ? -1 : 0);
|
|
2149
|
+
const plans = [];
|
|
2150
|
+
let remaining = requested;
|
|
2151
|
+
for (const { agent, balance } of sorted) {
|
|
2152
|
+
if (remaining === 0n) {
|
|
2153
|
+
plans.push({ agent, balance, planned: 0n });
|
|
2154
|
+
continue;
|
|
2155
|
+
}
|
|
2156
|
+
const take = balance < remaining ? balance : remaining;
|
|
2157
|
+
plans.push({ agent, balance, planned: take });
|
|
2158
|
+
remaining -= take;
|
|
2159
|
+
}
|
|
2160
|
+
return { plans, remaining };
|
|
2161
|
+
}
|
|
2162
|
+
function redistributeShare(plans, fromIndex, amount, candidatePool) {
|
|
2163
|
+
const pool = candidatePool ?? plans.slice(fromIndex + 1);
|
|
2164
|
+
const candidates = pool.filter((c) => c.balance - c.planned > 0n);
|
|
2165
|
+
const totalHeadroom = candidates.reduce(
|
|
2166
|
+
(s, c) => s + (c.balance - c.planned),
|
|
2167
|
+
0n
|
|
2168
|
+
);
|
|
2169
|
+
if (totalHeadroom === 0n) return;
|
|
2170
|
+
let distributed = 0n;
|
|
2171
|
+
for (const c of candidates) {
|
|
2172
|
+
const headroom = c.balance - c.planned;
|
|
2173
|
+
const proportional = headroom * amount / totalHeadroom;
|
|
2174
|
+
const give = proportional > headroom ? headroom : proportional;
|
|
2175
|
+
c.planned += give;
|
|
2176
|
+
distributed += give;
|
|
2177
|
+
}
|
|
2178
|
+
let leftover = amount - distributed;
|
|
2179
|
+
for (const c of candidates) {
|
|
2180
|
+
if (leftover === 0n) break;
|
|
2181
|
+
const headroom = c.balance - c.planned;
|
|
2182
|
+
if (headroom <= 0n) continue;
|
|
2183
|
+
const take = headroom < leftover ? headroom : leftover;
|
|
2184
|
+
c.planned += take;
|
|
2185
|
+
leftover -= take;
|
|
2051
2186
|
}
|
|
2052
2187
|
}
|
|
2188
|
+
function sumWithdrawnAmount(results) {
|
|
2189
|
+
return Object.values(results).reduce((sum, r) => sum + BigInt(r.amount), 0n);
|
|
2190
|
+
}
|
|
2191
|
+
|
|
2192
|
+
// src/lib/helpers/account-apy-helper.ts
|
|
2193
|
+
function aggregateApyByChainAndAsset(agentApys, agentBalances) {
|
|
2194
|
+
const sums = {};
|
|
2195
|
+
const weights = {};
|
|
2196
|
+
for (const id of Object.keys(agentApys)) {
|
|
2197
|
+
const cells = agentApys[id].apyByChainAndAsset;
|
|
2198
|
+
const balance = agentBalances[id] ?? 0;
|
|
2199
|
+
if (!cells || balance <= 0) continue;
|
|
2200
|
+
for (const [chainKey, perAsset] of Object.entries(cells)) {
|
|
2201
|
+
if (!perAsset) continue;
|
|
2202
|
+
const chainId = Number(chainKey);
|
|
2203
|
+
for (const [asset, apyValue] of Object.entries(perAsset)) {
|
|
2204
|
+
const apy = Number(apyValue ?? 0);
|
|
2205
|
+
if (apy === 0) continue;
|
|
2206
|
+
sums[chainId] ??= {};
|
|
2207
|
+
weights[chainId] ??= {};
|
|
2208
|
+
sums[chainId][asset] = (sums[chainId][asset] ?? 0) + apy * balance;
|
|
2209
|
+
weights[chainId][asset] = (weights[chainId][asset] ?? 0) + balance;
|
|
2210
|
+
}
|
|
2211
|
+
}
|
|
2212
|
+
}
|
|
2213
|
+
const out = {};
|
|
2214
|
+
for (const chainKey of Object.keys(sums)) {
|
|
2215
|
+
const chainId = Number(chainKey);
|
|
2216
|
+
const perAssetOut = {};
|
|
2217
|
+
for (const asset of Object.keys(sums[chainId])) {
|
|
2218
|
+
const w = weights[chainId][asset];
|
|
2219
|
+
if (w > 0) perAssetOut[asset] = sums[chainId][asset] / w;
|
|
2220
|
+
}
|
|
2221
|
+
if (Object.keys(perAssetOut).length > 0) {
|
|
2222
|
+
out[chainId] = perAssetOut;
|
|
2223
|
+
}
|
|
2224
|
+
}
|
|
2225
|
+
return out;
|
|
2226
|
+
}
|
|
2227
|
+
|
|
2228
|
+
// src/client.ts
|
|
2229
|
+
import {
|
|
2230
|
+
createPublicClient as createPublicClient2,
|
|
2231
|
+
createWalletClient,
|
|
2232
|
+
custom
|
|
2233
|
+
} from "viem";
|
|
2234
|
+
import { base as base2, arbitrum as arbitrum2, mainnet as mainnet2 } from "viem/chains";
|
|
2053
2235
|
|
|
2054
2236
|
// src/lib/transfer-auth.ts
|
|
2055
2237
|
import { bytesToHex } from "viem";
|
|
@@ -2088,25 +2270,24 @@ function randomAuthNonce() {
|
|
|
2088
2270
|
}
|
|
2089
2271
|
|
|
2090
2272
|
// src/lib/sponsor-client.ts
|
|
2091
|
-
var
|
|
2092
|
-
async function
|
|
2093
|
-
const
|
|
2273
|
+
var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
2274
|
+
async function postSponsorTransferAuth(input) {
|
|
2275
|
+
const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
2094
2276
|
let res;
|
|
2095
2277
|
try {
|
|
2096
|
-
res = await fetch(`${
|
|
2278
|
+
res = await fetch(`${base3}/api/v1/sponsor/erc20-transfer-auth`, {
|
|
2097
2279
|
method: "POST",
|
|
2098
2280
|
headers: {
|
|
2099
2281
|
"content-type": "application/json",
|
|
2100
|
-
"x-owney-api-key": input.apiKey
|
|
2101
|
-
Authorization: `Signature ${input.yieldseekerSignature}`
|
|
2282
|
+
"x-owney-api-key": input.apiKey
|
|
2102
2283
|
},
|
|
2103
2284
|
body: JSON.stringify(input.body)
|
|
2104
2285
|
});
|
|
2105
2286
|
} catch (networkError) {
|
|
2106
2287
|
throw new OwneyError(
|
|
2107
2288
|
"SPONSOR_REQUEST_FAILED",
|
|
2108
|
-
`
|
|
2109
|
-
{ cause: String(networkError)
|
|
2289
|
+
`Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
|
|
2290
|
+
{ cause: String(networkError) }
|
|
2110
2291
|
);
|
|
2111
2292
|
}
|
|
2112
2293
|
const text = await res.text();
|
|
@@ -2115,29 +2296,30 @@ async function postPaymasterIntent(input) {
|
|
|
2115
2296
|
parsed = JSON.parse(text);
|
|
2116
2297
|
} catch {
|
|
2117
2298
|
}
|
|
2118
|
-
if (!res.ok || !parsed?.success ||
|
|
2299
|
+
if (!res.ok || !parsed?.success || !parsed.data) {
|
|
2119
2300
|
throw new OwneyError(
|
|
2120
2301
|
"SPONSOR_REQUEST_FAILED",
|
|
2121
|
-
`
|
|
2302
|
+
`Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
|
|
2122
2303
|
{
|
|
2123
2304
|
statusCode: res.status,
|
|
2124
2305
|
responseBody: text.slice(0, 500),
|
|
2125
|
-
|
|
2306
|
+
// 503 SPONSOR_UNAVAILABLE = relayer out of gas; the tx was rejected
|
|
2307
|
+
// before broadcast, so it is safe to fall back to a user-paid deposit.
|
|
2308
|
+
safeToFallback: res.status === 503
|
|
2126
2309
|
}
|
|
2127
2310
|
);
|
|
2128
2311
|
}
|
|
2129
2312
|
return parsed.data;
|
|
2130
2313
|
}
|
|
2131
|
-
async function
|
|
2132
|
-
const
|
|
2314
|
+
async function postSponsorPermit2Transfer(input) {
|
|
2315
|
+
const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
2133
2316
|
let res;
|
|
2134
2317
|
try {
|
|
2135
|
-
res = await fetch(`${
|
|
2318
|
+
res = await fetch(`${base3}/api/v1/sponsor/permit2-transfer`, {
|
|
2136
2319
|
method: "POST",
|
|
2137
2320
|
headers: {
|
|
2138
2321
|
"content-type": "application/json",
|
|
2139
|
-
"x-owney-api-key": input.apiKey
|
|
2140
|
-
...input.yieldseekerSignature ? { Authorization: `Signature ${input.yieldseekerSignature}` } : {}
|
|
2322
|
+
"x-owney-api-key": input.apiKey
|
|
2141
2323
|
},
|
|
2142
2324
|
body: JSON.stringify(input.body)
|
|
2143
2325
|
});
|
|
@@ -2145,48 +2327,7 @@ async function postSponsorTransferAuth(input) {
|
|
|
2145
2327
|
throw new OwneyError(
|
|
2146
2328
|
"SPONSOR_REQUEST_FAILED",
|
|
2147
2329
|
`Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
|
|
2148
|
-
{ cause: String(networkError) }
|
|
2149
|
-
);
|
|
2150
|
-
}
|
|
2151
|
-
const text = await res.text();
|
|
2152
|
-
let parsed = null;
|
|
2153
|
-
try {
|
|
2154
|
-
parsed = JSON.parse(text);
|
|
2155
|
-
} catch {
|
|
2156
|
-
}
|
|
2157
|
-
if (!res.ok || !parsed?.success || !parsed.data) {
|
|
2158
|
-
throw new OwneyError(
|
|
2159
|
-
"SPONSOR_REQUEST_FAILED",
|
|
2160
|
-
`Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
|
|
2161
|
-
{
|
|
2162
|
-
statusCode: res.status,
|
|
2163
|
-
responseBody: text.slice(0, 500),
|
|
2164
|
-
// 503 SPONSOR_UNAVAILABLE = relayer out of gas; the tx was rejected
|
|
2165
|
-
// before broadcast, so it is safe to fall back to a user-paid deposit.
|
|
2166
|
-
safeToFallback: res.status === 503
|
|
2167
|
-
}
|
|
2168
|
-
);
|
|
2169
|
-
}
|
|
2170
|
-
return parsed.data;
|
|
2171
|
-
}
|
|
2172
|
-
async function postSponsorPermit2Transfer(input) {
|
|
2173
|
-
const base5 = input.baseUrl ?? ROUTING_API_BASE_URL;
|
|
2174
|
-
let res;
|
|
2175
|
-
try {
|
|
2176
|
-
res = await fetch(`${base5}/api/v1/sponsor/permit2-transfer`, {
|
|
2177
|
-
method: "POST",
|
|
2178
|
-
headers: {
|
|
2179
|
-
"content-type": "application/json",
|
|
2180
|
-
"x-owney-api-key": input.apiKey,
|
|
2181
|
-
...input.yieldseekerSignature ? { Authorization: `Signature ${input.yieldseekerSignature}` } : {}
|
|
2182
|
-
},
|
|
2183
|
-
body: JSON.stringify(input.body)
|
|
2184
|
-
});
|
|
2185
|
-
} catch (networkError) {
|
|
2186
|
-
throw new OwneyError(
|
|
2187
|
-
"SPONSOR_REQUEST_FAILED",
|
|
2188
|
-
`Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
|
|
2189
|
-
{ cause: String(networkError), safeToFallback: false }
|
|
2330
|
+
{ cause: String(networkError), safeToFallback: false }
|
|
2190
2331
|
);
|
|
2191
2332
|
}
|
|
2192
2333
|
const text = await res.text();
|
|
@@ -2209,11 +2350,11 @@ async function postSponsorPermit2Transfer(input) {
|
|
|
2209
2350
|
return parsed.data;
|
|
2210
2351
|
}
|
|
2211
2352
|
async function getSponsorRelayerAddress(input) {
|
|
2212
|
-
const
|
|
2353
|
+
const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
2213
2354
|
let res;
|
|
2214
2355
|
try {
|
|
2215
2356
|
res = await fetch(
|
|
2216
|
-
`${
|
|
2357
|
+
`${base3}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
|
|
2217
2358
|
{
|
|
2218
2359
|
headers: { "x-owney-api-key": input.apiKey }
|
|
2219
2360
|
}
|
|
@@ -2311,1984 +2452,216 @@ async function readPermit2Allowance(publicClient, token, owner) {
|
|
|
2311
2452
|
address: token,
|
|
2312
2453
|
abi: ERC20_ALLOWANCE_ABI,
|
|
2313
2454
|
functionName: "allowance",
|
|
2314
|
-
args: [owner, PERMIT2_ADDRESS]
|
|
2315
|
-
});
|
|
2316
|
-
}
|
|
2317
|
-
async function readErc20Balance(publicClient, token, owner) {
|
|
2318
|
-
return publicClient.readContract({
|
|
2319
|
-
address: token,
|
|
2320
|
-
abi: ERC20_ALLOWANCE_ABI,
|
|
2321
|
-
functionName: "balanceOf",
|
|
2322
|
-
args: [owner]
|
|
2323
|
-
});
|
|
2324
|
-
}
|
|
2325
|
-
|
|
2326
|
-
// src/lib/sponsored-deposit.ts
|
|
2327
|
-
var AUTH_WINDOW_SECONDS = 15 * 60;
|
|
2328
|
-
var verificationSetter = /* @__PURE__ */ Symbol("owney.depositVerificationSetter");
|
|
2329
|
-
function provideDepositVerificationContext(callback, context) {
|
|
2330
|
-
callback[verificationSetter]?.(context);
|
|
2331
|
-
}
|
|
2332
|
-
function makeVerificationAwareDepositCallback(implementation) {
|
|
2333
|
-
let nextVerification;
|
|
2334
|
-
const callback = async (smartWallet, chainId, amount) => {
|
|
2335
|
-
const verification = nextVerification;
|
|
2336
|
-
nextVerification = void 0;
|
|
2337
|
-
return implementation(smartWallet, chainId, amount, verification);
|
|
2338
|
-
};
|
|
2339
|
-
Object.defineProperty(callback, verificationSetter, {
|
|
2340
|
-
value: (context) => {
|
|
2341
|
-
nextVerification = context;
|
|
2342
|
-
}
|
|
2343
|
-
});
|
|
2344
|
-
return callback;
|
|
2345
|
-
}
|
|
2346
|
-
function makeSponsoredDepositCallback(deps) {
|
|
2347
|
-
const post = deps.httpPost ?? postSponsorTransferAuth;
|
|
2348
|
-
return makeVerificationAwareDepositCallback(
|
|
2349
|
-
async (smartWallet, chainId, amount, verification) => {
|
|
2350
|
-
const cid = chainId;
|
|
2351
|
-
const token = deps.tokenAddressByChain[cid];
|
|
2352
|
-
if (!token) {
|
|
2353
|
-
throw new OwneyError(
|
|
2354
|
-
"CHAIN_UNSUPPORTED",
|
|
2355
|
-
`No sponsored token configured for chain ${chainId}`
|
|
2356
|
-
);
|
|
2357
|
-
}
|
|
2358
|
-
const pub = deps.getPublicClient(cid);
|
|
2359
|
-
const wallet = deps.getWalletClient(cid);
|
|
2360
|
-
await ensureWalletOnChain(pub, wallet, cid);
|
|
2361
|
-
try {
|
|
2362
|
-
const balance = await readErc20Balance(pub, token, deps.ownerAddress);
|
|
2363
|
-
if (balance < BigInt(amount)) {
|
|
2364
|
-
throw new OwneyError(
|
|
2365
|
-
"DEPOSIT_INSUFFICIENT_BALANCE",
|
|
2366
|
-
"Insufficient balance for this deposit.",
|
|
2367
|
-
{ token, chainId: cid, balance: balance.toString(), amount }
|
|
2368
|
-
);
|
|
2369
|
-
}
|
|
2370
|
-
} catch (err) {
|
|
2371
|
-
if (err instanceof OwneyError) throw err;
|
|
2372
|
-
console.warn(
|
|
2373
|
-
"[owney-sdk] Deposit balance pre-check failed (non-fatal):",
|
|
2374
|
-
err instanceof Error ? err.message : String(err)
|
|
2375
|
-
);
|
|
2376
|
-
}
|
|
2377
|
-
const { tokenName, tokenVersion } = await readTokenMeta(pub, token);
|
|
2378
|
-
const validAfter = 0n;
|
|
2379
|
-
const validBefore = BigInt(
|
|
2380
|
-
Math.floor(Date.now() / 1e3) + AUTH_WINDOW_SECONDS
|
|
2381
|
-
);
|
|
2382
|
-
const nonce = randomAuthNonce();
|
|
2383
|
-
const typedData = buildTransferWithAuthorizationTypedData({
|
|
2384
|
-
token,
|
|
2385
|
-
chainId: cid,
|
|
2386
|
-
tokenName,
|
|
2387
|
-
tokenVersion,
|
|
2388
|
-
message: {
|
|
2389
|
-
from: deps.ownerAddress,
|
|
2390
|
-
to: smartWallet,
|
|
2391
|
-
value: BigInt(amount),
|
|
2392
|
-
validAfter,
|
|
2393
|
-
validBefore,
|
|
2394
|
-
nonce
|
|
2395
|
-
}
|
|
2396
|
-
});
|
|
2397
|
-
const authSignature = await wallet.signTypedData({
|
|
2398
|
-
account: deps.ownerAddress,
|
|
2399
|
-
...typedData
|
|
2400
|
-
});
|
|
2401
|
-
deps.onApproved?.();
|
|
2402
|
-
const result = await post({
|
|
2403
|
-
baseUrl: deps.baseUrl,
|
|
2404
|
-
apiKey: deps.apiKey,
|
|
2405
|
-
...verification?.agentId === "yieldseeker" ? { yieldseekerSignature: verification.signature } : {},
|
|
2406
|
-
body: {
|
|
2407
|
-
chainId: cid,
|
|
2408
|
-
token,
|
|
2409
|
-
from: deps.ownerAddress,
|
|
2410
|
-
to: smartWallet,
|
|
2411
|
-
value: amount,
|
|
2412
|
-
validAfter: validAfter.toString(),
|
|
2413
|
-
validBefore: validBefore.toString(),
|
|
2414
|
-
nonce,
|
|
2415
|
-
authSignature,
|
|
2416
|
-
tokenName,
|
|
2417
|
-
tokenVersion,
|
|
2418
|
-
...verification?.agentId === "yieldseeker" ? {
|
|
2419
|
-
yieldseekerUserId: verification.userId,
|
|
2420
|
-
yieldseekerAgentId: verification.yieldseekerAgentId
|
|
2421
|
-
} : {}
|
|
2422
|
-
}
|
|
2423
|
-
});
|
|
2424
|
-
return result.txHash;
|
|
2425
|
-
}
|
|
2426
|
-
);
|
|
2427
|
-
}
|
|
2428
|
-
|
|
2429
|
-
// src/agents/yieldseeker/yieldseeker.auth.ts
|
|
2430
|
-
import { SiweMessage, generateNonce } from "siwe";
|
|
2431
|
-
import {
|
|
2432
|
-
createPublicClient as createPublicClient2,
|
|
2433
|
-
createWalletClient,
|
|
2434
|
-
custom,
|
|
2435
|
-
getAddress
|
|
2436
|
-
} from "viem";
|
|
2437
|
-
import { base as base2 } from "viem/chains";
|
|
2438
|
-
|
|
2439
|
-
// src/agents/yieldseeker/yieldseeker.auth-cache.ts
|
|
2440
|
-
var KEY_PREFIX2 = "owney.yieldseeker.session.v5";
|
|
2441
|
-
var INVALIDATED_KEY_PREFIXES = [
|
|
2442
|
-
"owney.yieldseeker.session",
|
|
2443
|
-
"owney.yieldseeker.session.v3",
|
|
2444
|
-
"owney.yieldseeker.session.v4"
|
|
2445
|
-
];
|
|
2446
|
-
var storage2 = () => {
|
|
2447
|
-
if (typeof window === "undefined") return null;
|
|
2448
|
-
try {
|
|
2449
|
-
return window.localStorage;
|
|
2450
|
-
} catch {
|
|
2451
|
-
return null;
|
|
2452
|
-
}
|
|
2453
|
-
};
|
|
2454
|
-
var buildKey2 = (address, chainId) => `${KEY_PREFIX2}:${address.toLowerCase()}:${chainId}`;
|
|
2455
|
-
var invalidatedKeys = (address, chainId) => INVALIDATED_KEY_PREFIXES.map(
|
|
2456
|
-
(prefix) => `${prefix}:${address.toLowerCase()}:${chainId}`
|
|
2457
|
-
);
|
|
2458
|
-
var clearInvalidatedSessions = (store, address, chainId) => {
|
|
2459
|
-
for (const key2 of invalidatedKeys(address, chainId)) {
|
|
2460
|
-
memorySessions2.delete(key2);
|
|
2461
|
-
try {
|
|
2462
|
-
store?.removeItem(key2);
|
|
2463
|
-
} catch {
|
|
2464
|
-
}
|
|
2465
|
-
}
|
|
2466
|
-
};
|
|
2467
|
-
var memorySessions2 = /* @__PURE__ */ new Map();
|
|
2468
|
-
var isValidSession = (session) => {
|
|
2469
|
-
if (!session?.token) return false;
|
|
2470
|
-
try {
|
|
2471
|
-
const parsed = JSON.parse(atob(session.token));
|
|
2472
|
-
return typeof parsed.message === "string" && typeof parsed.signature === "string" && parsed.signature.startsWith("0x");
|
|
2473
|
-
} catch {
|
|
2474
|
-
return false;
|
|
2475
|
-
}
|
|
2476
|
-
};
|
|
2477
|
-
var readYieldseekerSession = (address, chainId) => {
|
|
2478
|
-
if (typeof window === "undefined") return null;
|
|
2479
|
-
const key2 = buildKey2(address, chainId);
|
|
2480
|
-
const store = storage2();
|
|
2481
|
-
clearInvalidatedSessions(store, address, chainId);
|
|
2482
|
-
let raw2 = null;
|
|
2483
|
-
try {
|
|
2484
|
-
raw2 = store?.getItem(key2) ?? null;
|
|
2485
|
-
} catch {
|
|
2486
|
-
raw2 = null;
|
|
2487
|
-
}
|
|
2488
|
-
if (raw2) {
|
|
2489
|
-
try {
|
|
2490
|
-
const parsed = JSON.parse(raw2);
|
|
2491
|
-
if (isValidSession(parsed)) return parsed.token;
|
|
2492
|
-
} catch {
|
|
2493
|
-
}
|
|
2494
|
-
memorySessions2.delete(key2);
|
|
2495
|
-
try {
|
|
2496
|
-
store?.removeItem(key2);
|
|
2497
|
-
} catch {
|
|
2498
|
-
}
|
|
2499
|
-
return null;
|
|
2500
|
-
}
|
|
2501
|
-
const cached = memorySessions2.get(key2);
|
|
2502
|
-
if (isValidSession(cached)) return cached.token;
|
|
2503
|
-
if (cached) memorySessions2.delete(key2);
|
|
2504
|
-
return null;
|
|
2505
|
-
};
|
|
2506
|
-
var writeYieldseekerSession = (address, chainId, token) => {
|
|
2507
|
-
if (typeof window === "undefined") return;
|
|
2508
|
-
const session = { token };
|
|
2509
|
-
if (!isValidSession(session)) return;
|
|
2510
|
-
const key2 = buildKey2(address, chainId);
|
|
2511
|
-
memorySessions2.set(key2, session);
|
|
2512
|
-
const store = storage2();
|
|
2513
|
-
try {
|
|
2514
|
-
store?.setItem(key2, JSON.stringify(session));
|
|
2515
|
-
} catch {
|
|
2516
|
-
}
|
|
2517
|
-
};
|
|
2518
|
-
var clearYieldseekerSession = (address, chainId) => {
|
|
2519
|
-
const key2 = buildKey2(address, chainId);
|
|
2520
|
-
memorySessions2.delete(key2);
|
|
2521
|
-
const store = storage2();
|
|
2522
|
-
clearInvalidatedSessions(store, address, chainId);
|
|
2523
|
-
try {
|
|
2524
|
-
store?.removeItem(key2);
|
|
2525
|
-
} catch {
|
|
2526
|
-
}
|
|
2527
|
-
};
|
|
2528
|
-
|
|
2529
|
-
// src/agents/yieldseeker/yieldseeker.auth.ts
|
|
2530
|
-
function resolveSiweOrigin(override) {
|
|
2531
|
-
const origin = override?.trim() || (typeof window !== "undefined" ? window.location?.origin : void 0);
|
|
2532
|
-
if (!origin || origin === "null") {
|
|
2533
|
-
throw new Error("Yieldseeker sign-in requires the requesting app's browser origin.");
|
|
2534
|
-
}
|
|
2535
|
-
const url = new URL(origin);
|
|
2536
|
-
if (url.protocol !== "https:" && url.protocol !== "http:") {
|
|
2537
|
-
throw new Error("Yieldseeker sign-in requires an HTTP or HTTPS app origin.");
|
|
2538
|
-
}
|
|
2539
|
-
if (url.username || url.password || url.pathname !== "/" || url.search || url.hash) {
|
|
2540
|
-
throw new Error("Yieldseeker SIWE override must be an origin without credentials, path, query, or fragment.");
|
|
2541
|
-
}
|
|
2542
|
-
return url;
|
|
2543
|
-
}
|
|
2544
|
-
function createYieldseekerSiweMessage(address, chainId, dependencies = {}) {
|
|
2545
|
-
const url = resolveSiweOrigin(dependencies.origin);
|
|
2546
|
-
return new SiweMessage({
|
|
2547
|
-
scheme: url.protocol.slice(0, -1),
|
|
2548
|
-
domain: url.host,
|
|
2549
|
-
address: getAddress(address),
|
|
2550
|
-
uri: url.origin,
|
|
2551
|
-
version: "1",
|
|
2552
|
-
chainId,
|
|
2553
|
-
nonce: (dependencies.nonce ?? generateNonce)(),
|
|
2554
|
-
issuedAt: (dependencies.now ?? (() => /* @__PURE__ */ new Date()))().toISOString()
|
|
2555
|
-
}).prepareMessage();
|
|
2556
|
-
}
|
|
2557
|
-
function encodeYieldseekerAuthToken(token) {
|
|
2558
|
-
const bytes = new TextEncoder().encode(JSON.stringify(token));
|
|
2559
|
-
let binary = "";
|
|
2560
|
-
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
2561
|
-
return btoa(binary);
|
|
2562
|
-
}
|
|
2563
|
-
var YieldseekerAuth = class {
|
|
2564
|
-
constructor(dependencies = {}) {
|
|
2565
|
-
this.dependencies = dependencies;
|
|
2566
|
-
}
|
|
2567
|
-
dependencies;
|
|
2568
|
-
tokens = /* @__PURE__ */ new Map();
|
|
2569
|
-
pending = /* @__PURE__ */ new Map();
|
|
2570
|
-
scopes = /* @__PURE__ */ new Map();
|
|
2571
|
-
key(state, chainId) {
|
|
2572
|
-
return `${state.walletAddress.toLowerCase()}:${chainId}:${resolveSiweOrigin(this.dependencies.origin).origin}`;
|
|
2573
|
-
}
|
|
2574
|
-
async getToken(state, chainId) {
|
|
2575
|
-
const key2 = this.key(state, chainId);
|
|
2576
|
-
const scope = { address: state.walletAddress, chainId };
|
|
2577
|
-
this.scopes.set(key2, scope);
|
|
2578
|
-
const cached = this.tokens.get(key2);
|
|
2579
|
-
if (cached) return cached;
|
|
2580
|
-
const persisted = readYieldseekerSession(scope.address, scope.chainId);
|
|
2581
|
-
if (persisted && this.matchesOrigin(persisted)) {
|
|
2582
|
-
this.tokens.set(key2, persisted);
|
|
2583
|
-
return persisted;
|
|
2584
|
-
}
|
|
2585
|
-
if (persisted) clearYieldseekerSession(scope.address, scope.chainId);
|
|
2586
|
-
const inFlight = this.pending.get(key2);
|
|
2587
|
-
if (inFlight) return inFlight;
|
|
2588
|
-
const request = this.sign(state, chainId).then((token) => {
|
|
2589
|
-
this.tokens.set(key2, token);
|
|
2590
|
-
writeYieldseekerSession(scope.address, scope.chainId, token);
|
|
2591
|
-
return token;
|
|
2592
|
-
});
|
|
2593
|
-
this.pending.set(key2, request);
|
|
2594
|
-
try {
|
|
2595
|
-
return await request;
|
|
2596
|
-
} finally {
|
|
2597
|
-
this.pending.delete(key2);
|
|
2598
|
-
}
|
|
2599
|
-
}
|
|
2600
|
-
matchesOrigin(token) {
|
|
2601
|
-
try {
|
|
2602
|
-
const message = new SiweMessage(JSON.parse(atob(token)).message);
|
|
2603
|
-
const url = resolveSiweOrigin(this.dependencies.origin);
|
|
2604
|
-
return message.domain === url.host && message.uri === url.origin && message.scheme === url.protocol.slice(0, -1);
|
|
2605
|
-
} catch {
|
|
2606
|
-
return false;
|
|
2607
|
-
}
|
|
2608
|
-
}
|
|
2609
|
-
clear(state, chainId) {
|
|
2610
|
-
if (!state || chainId === void 0) {
|
|
2611
|
-
for (const scope of this.scopes.values()) {
|
|
2612
|
-
clearYieldseekerSession(scope.address, scope.chainId);
|
|
2613
|
-
}
|
|
2614
|
-
this.tokens.clear();
|
|
2615
|
-
this.pending.clear();
|
|
2616
|
-
this.scopes.clear();
|
|
2617
|
-
return;
|
|
2618
|
-
}
|
|
2619
|
-
const key2 = this.key(state, chainId);
|
|
2620
|
-
this.tokens.delete(key2);
|
|
2621
|
-
this.pending.delete(key2);
|
|
2622
|
-
this.scopes.delete(key2);
|
|
2623
|
-
clearYieldseekerSession(state.walletAddress, chainId);
|
|
2624
|
-
}
|
|
2625
|
-
async sign(state, chainId) {
|
|
2626
|
-
const account = getAddress(state.walletAddress);
|
|
2627
|
-
const publicClient = createPublicClient2({
|
|
2628
|
-
chain: base2,
|
|
2629
|
-
transport: custom(state.provider)
|
|
2630
|
-
});
|
|
2631
|
-
const walletClient = createWalletClient({
|
|
2632
|
-
account,
|
|
2633
|
-
chain: base2,
|
|
2634
|
-
transport: custom(state.provider)
|
|
2635
|
-
});
|
|
2636
|
-
await ensureWalletOnChain(
|
|
2637
|
-
publicClient,
|
|
2638
|
-
walletClient,
|
|
2639
|
-
8453
|
|
2640
|
-
);
|
|
2641
|
-
const message = createYieldseekerSiweMessage(
|
|
2642
|
-
account,
|
|
2643
|
-
chainId,
|
|
2644
|
-
this.dependencies
|
|
2645
|
-
);
|
|
2646
|
-
const signature = await walletClient.signMessage({ account, message });
|
|
2647
|
-
return encodeYieldseekerAuthToken({ message, signature });
|
|
2648
|
-
}
|
|
2649
|
-
};
|
|
2650
|
-
|
|
2651
|
-
// src/agents/yieldseeker/yieldseeker.identity-cache.ts
|
|
2652
|
-
var KEY_PREFIX3 = "owney.yieldseeker.identity.v1";
|
|
2653
|
-
var YIELDSEEKER_IDENTITY_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
2654
|
-
var memoryIdentities = /* @__PURE__ */ new Map();
|
|
2655
|
-
var storage3 = () => {
|
|
2656
|
-
if (typeof window === "undefined") return null;
|
|
2657
|
-
try {
|
|
2658
|
-
return window.localStorage;
|
|
2659
|
-
} catch {
|
|
2660
|
-
return null;
|
|
2661
|
-
}
|
|
2662
|
-
};
|
|
2663
|
-
var keyFor = (walletAddress, chainId) => `${KEY_PREFIX3}:${walletAddress.toLowerCase()}:${chainId}`;
|
|
2664
|
-
function valid(value, walletAddress, chainId, now) {
|
|
2665
|
-
return Boolean(
|
|
2666
|
-
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
|
|
2667
|
-
);
|
|
2668
|
-
}
|
|
2669
|
-
function readYieldseekerIdentity(walletAddress, chainId, now = Date.now()) {
|
|
2670
|
-
if (typeof window === "undefined") return null;
|
|
2671
|
-
const key2 = keyFor(walletAddress, chainId);
|
|
2672
|
-
const store = storage3();
|
|
2673
|
-
let parsed = null;
|
|
2674
|
-
try {
|
|
2675
|
-
const raw2 = store?.getItem(key2);
|
|
2676
|
-
parsed = raw2 ? JSON.parse(raw2) : null;
|
|
2677
|
-
} catch {
|
|
2678
|
-
parsed = null;
|
|
2679
|
-
}
|
|
2680
|
-
const candidate = parsed ?? memoryIdentities.get(key2);
|
|
2681
|
-
if (valid(candidate, walletAddress, chainId, now)) {
|
|
2682
|
-
memoryIdentities.set(key2, candidate);
|
|
2683
|
-
return { userId: candidate.userId };
|
|
2684
|
-
}
|
|
2685
|
-
memoryIdentities.delete(key2);
|
|
2686
|
-
try {
|
|
2687
|
-
store?.removeItem(key2);
|
|
2688
|
-
} catch {
|
|
2689
|
-
}
|
|
2690
|
-
return null;
|
|
2691
|
-
}
|
|
2692
|
-
function writeYieldseekerIdentity(walletAddress, chainId, userId, now = Date.now()) {
|
|
2693
|
-
if (typeof window === "undefined") return;
|
|
2694
|
-
const identity = {
|
|
2695
|
-
userId,
|
|
2696
|
-
walletAddress,
|
|
2697
|
-
chainId,
|
|
2698
|
-
expiresAt: now + YIELDSEEKER_IDENTITY_TTL_MS
|
|
2699
|
-
};
|
|
2700
|
-
if (!valid(identity, walletAddress, chainId, now)) return;
|
|
2701
|
-
const key2 = keyFor(walletAddress, chainId);
|
|
2702
|
-
memoryIdentities.set(key2, identity);
|
|
2703
|
-
try {
|
|
2704
|
-
storage3()?.setItem(key2, JSON.stringify(identity));
|
|
2705
|
-
} catch {
|
|
2706
|
-
}
|
|
2707
|
-
}
|
|
2708
|
-
function clearYieldseekerIdentity(walletAddress, chainId) {
|
|
2709
|
-
const key2 = keyFor(walletAddress, chainId);
|
|
2710
|
-
memoryIdentities.delete(key2);
|
|
2711
|
-
try {
|
|
2712
|
-
storage3()?.removeItem(key2);
|
|
2713
|
-
} catch {
|
|
2714
|
-
}
|
|
2715
|
-
}
|
|
2716
|
-
|
|
2717
|
-
// src/agents/yieldseeker/yieldseeker.client.ts
|
|
2718
|
-
var DEFAULT_ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
2719
|
-
function getYieldseekerProxyBaseUrl(routingApiBaseUrl = DEFAULT_ROUTING_API_BASE_URL) {
|
|
2720
|
-
return `${routingApiBaseUrl.replace(/\/$/, "")}/api/v1/agent/yieldseeker`;
|
|
2721
|
-
}
|
|
2722
|
-
var YIELDSEEKER_API_BASE_URL = getYieldseekerProxyBaseUrl();
|
|
2723
|
-
var YieldseekerApiError = class extends Error {
|
|
2724
|
-
constructor(status, providerCode, responseFields) {
|
|
2725
|
-
super(`Yieldseeker request failed (${status}): ${providerCode}`);
|
|
2726
|
-
this.status = status;
|
|
2727
|
-
this.providerCode = providerCode;
|
|
2728
|
-
this.responseFields = responseFields;
|
|
2729
|
-
this.name = "YieldseekerApiError";
|
|
2730
|
-
}
|
|
2731
|
-
status;
|
|
2732
|
-
providerCode;
|
|
2733
|
-
responseFields;
|
|
2734
|
-
get isAuthenticationError() {
|
|
2735
|
-
return this.status === 401 || this.status === 403;
|
|
2736
|
-
}
|
|
2737
|
-
};
|
|
2738
|
-
function providerError(body, fallback) {
|
|
2739
|
-
if (!body || typeof body !== "object") return { code: fallback };
|
|
2740
|
-
const record = body;
|
|
2741
|
-
return {
|
|
2742
|
-
code: typeof record.message === "string" ? record.message : fallback,
|
|
2743
|
-
fields: record.fields && typeof record.fields === "object" ? record.fields : void 0
|
|
2744
|
-
};
|
|
2745
|
-
}
|
|
2746
|
-
var YieldseekerApiClient = class {
|
|
2747
|
-
constructor(owneyApiKey, baseUrl = YIELDSEEKER_API_BASE_URL, fetchFn = fetch) {
|
|
2748
|
-
this.owneyApiKey = owneyApiKey;
|
|
2749
|
-
this.baseUrl = baseUrl;
|
|
2750
|
-
this.fetchFn = fetchFn;
|
|
2751
|
-
}
|
|
2752
|
-
owneyApiKey;
|
|
2753
|
-
baseUrl;
|
|
2754
|
-
fetchFn;
|
|
2755
|
-
async request(path, options = {}) {
|
|
2756
|
-
const controller = new AbortController();
|
|
2757
|
-
const timer = setTimeout(
|
|
2758
|
-
() => controller.abort(),
|
|
2759
|
-
options.timeoutMs ?? 15e3
|
|
2760
|
-
);
|
|
2761
|
-
try {
|
|
2762
|
-
const response = await this.fetchFn(`${this.baseUrl}${path}`, {
|
|
2763
|
-
method: options.method ?? "GET",
|
|
2764
|
-
headers: {
|
|
2765
|
-
"Content-Type": "application/json",
|
|
2766
|
-
"x-owney-api-key": this.owneyApiKey,
|
|
2767
|
-
...options.signature ? { Authorization: `Signature ${options.signature}` } : {}
|
|
2768
|
-
},
|
|
2769
|
-
body: options.body ? JSON.stringify(options.body) : void 0,
|
|
2770
|
-
signal: controller.signal
|
|
2771
|
-
});
|
|
2772
|
-
const payload = await response.json().catch(() => null);
|
|
2773
|
-
if (!response.ok) {
|
|
2774
|
-
const error = providerError(payload, `HTTP_${response.status}`);
|
|
2775
|
-
throw new YieldseekerApiError(
|
|
2776
|
-
response.status,
|
|
2777
|
-
error.code,
|
|
2778
|
-
error.fields
|
|
2779
|
-
);
|
|
2780
|
-
}
|
|
2781
|
-
if (payload && typeof payload === "object" && payload.success === true && "data" in payload) {
|
|
2782
|
-
return payload.data;
|
|
2783
|
-
}
|
|
2784
|
-
return payload;
|
|
2785
|
-
} catch (error) {
|
|
2786
|
-
if (error instanceof YieldseekerApiError) throw error;
|
|
2787
|
-
if (error instanceof DOMException && error.name === "AbortError") {
|
|
2788
|
-
throw new YieldseekerApiError(408, "REQUEST_TIMEOUT");
|
|
2789
|
-
}
|
|
2790
|
-
throw new YieldseekerApiError(0, "NETWORK_ERROR", {
|
|
2791
|
-
cause: error instanceof Error ? error.message : String(error)
|
|
2792
|
-
});
|
|
2793
|
-
} finally {
|
|
2794
|
-
clearTimeout(timer);
|
|
2795
|
-
}
|
|
2796
|
-
}
|
|
2797
|
-
};
|
|
2798
|
-
|
|
2799
|
-
// src/agents/yieldseeker/yieldseeker.mapper.ts
|
|
2800
|
-
import { formatUnits, isAddress } from "viem";
|
|
2801
|
-
|
|
2802
|
-
// src/agents/yieldseeker/yieldseeker.types.ts
|
|
2803
|
-
var YIELDSEEKER_ASSET_METADATA = {
|
|
2804
|
-
USDC: {
|
|
2805
|
-
address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
2806
|
-
decimals: 6
|
|
2807
|
-
},
|
|
2808
|
-
WETH: {
|
|
2809
|
-
address: "0x4200000000000000000000000000000000000006",
|
|
2810
|
-
decimals: 18
|
|
2811
|
-
}
|
|
2812
|
-
};
|
|
2813
|
-
|
|
2814
|
-
// src/agents/yieldseeker/yieldseeker.mapper.ts
|
|
2815
|
-
function invalid(endpoint, detail) {
|
|
2816
|
-
throw new OwneyError(
|
|
2817
|
-
"AGENT_INVALID_RESPONSE",
|
|
2818
|
-
`Yieldseeker returned an invalid ${endpoint} response: ${detail}.`,
|
|
2819
|
-
{ endpoint, detail },
|
|
2820
|
-
"yieldseeker"
|
|
2821
|
-
);
|
|
2822
|
-
}
|
|
2823
|
-
function raw(value, endpoint) {
|
|
2824
|
-
if (typeof value !== "string" || !/^-?[0-9]+$/.test(value)) {
|
|
2825
|
-
return invalid(endpoint, "expected a base-10 integer string");
|
|
2826
|
-
}
|
|
2827
|
-
return BigInt(value);
|
|
2828
|
-
}
|
|
2829
|
-
function decimal(value, decimals, endpoint) {
|
|
2830
|
-
return formatUnits(raw(value, endpoint), decimals);
|
|
2831
|
-
}
|
|
2832
|
-
function usd(rawAmount, decimals, price) {
|
|
2833
|
-
return Number(formatUnits(rawAmount, decimals)) * price;
|
|
2834
|
-
}
|
|
2835
|
-
function percent(value) {
|
|
2836
|
-
const result = Number(value);
|
|
2837
|
-
return Number.isFinite(result) ? result * 100 : 0;
|
|
2838
|
-
}
|
|
2839
|
-
var YIELDSEEKER_POSITIVE_YIELD_FEE_RATE = 0.1;
|
|
2840
|
-
function publicApyAfterYieldseekerFee(value) {
|
|
2841
|
-
const grossPercent = percent(value);
|
|
2842
|
-
if (grossPercent <= 0) return grossPercent;
|
|
2843
|
-
const netPercent = grossPercent * (1 - YIELDSEEKER_POSITIVE_YIELD_FEE_RATE);
|
|
2844
|
-
return Math.round(netPercent * 1e12) / 1e12;
|
|
2845
|
-
}
|
|
2846
|
-
function riskAdjustedApyForDays(option, days) {
|
|
2847
|
-
if (days === "7D") return option.riskAdjustedApy7dAverage;
|
|
2848
|
-
if (days === "30D") return option.riskAdjustedApy30dAverage;
|
|
2849
|
-
return (option.riskAdjustedApy7dAverage + option.riskAdjustedApy30dAverage) / 2;
|
|
2850
|
-
}
|
|
2851
|
-
function assetAddressValue(record, address) {
|
|
2852
|
-
const entry = Object.entries(record).find(
|
|
2853
|
-
([key2]) => key2.toLowerCase() === address.toLowerCase()
|
|
2854
|
-
);
|
|
2855
|
-
return entry?.[1] ?? "0";
|
|
2856
|
-
}
|
|
2857
|
-
function position(value, asset, baseAssetDecimals) {
|
|
2858
|
-
const option = value?.yieldOption;
|
|
2859
|
-
if (!option || typeof option.provider !== "string" || typeof option.name !== "string" || typeof option.address !== "string" || !isAddress(option.address)) {
|
|
2860
|
-
return invalid("yield positions", "missing vault metadata");
|
|
2861
|
-
}
|
|
2862
|
-
return {
|
|
2863
|
-
chain: "BASE",
|
|
2864
|
-
protocol: option.provider,
|
|
2865
|
-
protocolId: option.address,
|
|
2866
|
-
pool: option.name,
|
|
2867
|
-
asset,
|
|
2868
|
-
// `assetsRaw` is the ERC-4626 vault-share quantity, whose decimals can
|
|
2869
|
-
// differ from the underlying asset. Yieldseeker already converts it to
|
|
2870
|
-
// underlying base-asset units in `assetsBase`; pair that value with the
|
|
2871
|
-
// snapshot's corresponding `baseAssetDecimals` for display. Keep the raw
|
|
2872
|
-
// share quantity separately because withdraw-from-position expects it.
|
|
2873
|
-
amount: decimal(
|
|
2874
|
-
value.assetsBase,
|
|
2875
|
-
baseAssetDecimals,
|
|
2876
|
-
"yield positions"
|
|
2877
|
-
),
|
|
2878
|
-
amountRaw: String(value.assetsRaw),
|
|
2879
|
-
apy: percent(option.riskAdjustedApy),
|
|
2880
|
-
tvl: Number(option.totalDepositsUsd),
|
|
2881
|
-
liquidity: Number(option.withdrawableDepositsUsd)
|
|
2882
|
-
};
|
|
2883
|
-
}
|
|
2884
|
-
function mapYieldseekerBalances(contexts) {
|
|
2885
|
-
const tokens = [];
|
|
2886
|
-
const assetBalances = [];
|
|
2887
|
-
const positions = [];
|
|
2888
|
-
let totalUsd = 0;
|
|
2889
|
-
for (const context of contexts) {
|
|
2890
|
-
const metadata = YIELDSEEKER_ASSET_METADATA[context.asset];
|
|
2891
|
-
assetBalances.push({
|
|
2892
|
-
chain: "BASE",
|
|
2893
|
-
chainId: 8453,
|
|
2894
|
-
asset: context.asset,
|
|
2895
|
-
amount: decimal(context.snapshot.totalValueBase, context.snapshot.baseAssetDecimals, "snapshot")
|
|
2896
|
-
});
|
|
2897
|
-
const idle = assetAddressValue(
|
|
2898
|
-
context.snapshot.tokenBalances,
|
|
2899
|
-
metadata.address
|
|
2900
|
-
);
|
|
2901
|
-
tokens.push({
|
|
2902
|
-
chain: "BASE",
|
|
2903
|
-
chainId: 8453,
|
|
2904
|
-
asset: context.asset,
|
|
2905
|
-
amount: decimal(idle, metadata.decimals, "snapshot")
|
|
2906
|
-
});
|
|
2907
|
-
positions.push(
|
|
2908
|
-
...context.positions.map(
|
|
2909
|
-
(entry) => position(
|
|
2910
|
-
entry,
|
|
2911
|
-
context.asset,
|
|
2912
|
-
context.snapshot.baseAssetDecimals
|
|
2913
|
-
)
|
|
2914
|
-
)
|
|
2915
|
-
);
|
|
2916
|
-
totalUsd += usd(
|
|
2917
|
-
raw(context.snapshot.totalValueBase, "snapshot"),
|
|
2918
|
-
context.snapshot.baseAssetDecimals,
|
|
2919
|
-
context.snapshot.baseAssetPriceUsd
|
|
2920
|
-
);
|
|
2921
|
-
}
|
|
2922
|
-
return {
|
|
2923
|
-
...contexts.length === 1 ? { smartWallet: contexts[0].wallet.walletAddress } : {},
|
|
2924
|
-
totalBalance: String(totalUsd),
|
|
2925
|
-
totalBalanceAsset: "usdc",
|
|
2926
|
-
assetBalances,
|
|
2927
|
-
tokens,
|
|
2928
|
-
positions
|
|
2929
|
-
};
|
|
2930
|
-
}
|
|
2931
|
-
function mapYieldseekerEarnings(contexts) {
|
|
2932
|
-
const tokens = [];
|
|
2933
|
-
let lifetimeEarnings = 0;
|
|
2934
|
-
for (const context of contexts) {
|
|
2935
|
-
const amount = raw(context.snapshot.cumulativeYieldBase, "snapshot");
|
|
2936
|
-
tokens.push({
|
|
2937
|
-
chain: "BASE",
|
|
2938
|
-
chainId: 8453,
|
|
2939
|
-
asset: context.asset,
|
|
2940
|
-
amount: formatUnits(amount, context.snapshot.baseAssetDecimals)
|
|
2941
|
-
});
|
|
2942
|
-
lifetimeEarnings += usd(
|
|
2943
|
-
amount,
|
|
2944
|
-
context.snapshot.baseAssetDecimals,
|
|
2945
|
-
context.snapshot.baseAssetPriceUsd
|
|
2946
|
-
);
|
|
2947
|
-
}
|
|
2948
|
-
return {
|
|
2949
|
-
smartWallet: contexts[0]?.wallet.walletAddress ?? "0x0000000000000000000000000000000000000000",
|
|
2950
|
-
lifetimeEarnings,
|
|
2951
|
-
tokens
|
|
2952
|
-
};
|
|
2953
|
-
}
|
|
2954
|
-
function apyForDays(snapshot, days) {
|
|
2955
|
-
if (days === "7D") return percent(snapshot.apy7d);
|
|
2956
|
-
if (days === "30D") return percent(snapshot.apy30d);
|
|
2957
|
-
return percent((snapshot.apy7d + snapshot.apy30d) / 2);
|
|
2958
|
-
}
|
|
2959
|
-
function dailyApy(point) {
|
|
2960
|
-
const total = raw(point.totalValueBase, "historic position");
|
|
2961
|
-
const earned = raw(point.dailyYieldBase, "historic position");
|
|
2962
|
-
const principal = total - earned;
|
|
2963
|
-
if (principal <= 0n || earned === 0n) return 0;
|
|
2964
|
-
return Number(earned) / Number(principal) * 365 * 100;
|
|
2965
|
-
}
|
|
2966
|
-
function aggregateHistory(contexts, dayCount) {
|
|
2967
|
-
const byDate = /* @__PURE__ */ new Map();
|
|
2968
|
-
for (const context of contexts) {
|
|
2969
|
-
const points = context.historic?.dailyYieldSnapshots ?? [];
|
|
2970
|
-
for (const point of points.slice(-dayCount)) {
|
|
2971
|
-
const valueUsd = usd(
|
|
2972
|
-
raw(point.totalValueBase, "historic position"),
|
|
2973
|
-
point.baseAssetDecimals,
|
|
2974
|
-
point.baseAssetPriceUsd
|
|
2975
|
-
);
|
|
2976
|
-
const current = byDate.get(point.date) ?? { weighted: 0, valueUsd: 0 };
|
|
2977
|
-
current.weighted += dailyApy(point) * valueUsd;
|
|
2978
|
-
current.valueUsd += valueUsd;
|
|
2979
|
-
byDate.set(point.date, current);
|
|
2980
|
-
}
|
|
2981
|
-
}
|
|
2982
|
-
return [...byDate.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([date, value]) => ({
|
|
2983
|
-
date,
|
|
2984
|
-
apy: value.valueUsd > 0 ? value.weighted / value.valueUsd : 0
|
|
2985
|
-
}));
|
|
2986
|
-
}
|
|
2987
|
-
function mapYieldseekerApy(walletAddress, contexts, days) {
|
|
2988
|
-
let weighted = 0;
|
|
2989
|
-
let totalUsd = 0;
|
|
2990
|
-
const byAsset = {};
|
|
2991
|
-
for (const context of contexts) {
|
|
2992
|
-
const valueUsd = usd(
|
|
2993
|
-
raw(context.snapshot.totalValueBase, "snapshot"),
|
|
2994
|
-
context.snapshot.baseAssetDecimals,
|
|
2995
|
-
context.snapshot.baseAssetPriceUsd
|
|
2996
|
-
);
|
|
2997
|
-
const apy = apyForDays(context.snapshot, days);
|
|
2998
|
-
weighted += apy * valueUsd;
|
|
2999
|
-
totalUsd += valueUsd;
|
|
3000
|
-
byAsset[context.asset] = apy;
|
|
3001
|
-
}
|
|
3002
|
-
const dayCount = Number(days.slice(0, -1));
|
|
3003
|
-
return {
|
|
3004
|
-
walletAddress,
|
|
3005
|
-
weightedApyAfterFee: totalUsd > 0 ? weighted / totalUsd : 0,
|
|
3006
|
-
apyByChainAndAsset: { 8453: byAsset },
|
|
3007
|
-
history: aggregateHistory(contexts, dayCount)
|
|
3008
|
-
};
|
|
3009
|
-
}
|
|
3010
|
-
function actionType(value) {
|
|
3011
|
-
const normalized = value.toLowerCase();
|
|
3012
|
-
if (normalized.includes("deposit")) return "Deposit";
|
|
3013
|
-
if (normalized.includes("withdraw")) return "Withdraw";
|
|
3014
|
-
if (normalized.includes("yield") || normalized.includes("earn"))
|
|
3015
|
-
return "Earned";
|
|
3016
|
-
return "Rebalance";
|
|
3017
|
-
}
|
|
3018
|
-
function transactionHashes(details) {
|
|
3019
|
-
if (!details) return [];
|
|
3020
|
-
const values = [
|
|
3021
|
-
details.transactionHash,
|
|
3022
|
-
details.txHash,
|
|
3023
|
-
...Array.isArray(details.transactionHashes) ? details.transactionHashes : [],
|
|
3024
|
-
...Array.isArray(details.txHashes) ? details.txHashes : []
|
|
3025
|
-
];
|
|
3026
|
-
return values.filter(
|
|
3027
|
-
(value) => typeof value === "string" && /^0x[a-fA-F0-9]{64}$/.test(value)
|
|
3028
|
-
).filter((value, index, all) => all.indexOf(value) === index);
|
|
3029
|
-
}
|
|
3030
|
-
function actionEntry(action) {
|
|
3031
|
-
if (action.actionType.toLowerCase().includes("withdraw")) return void 0;
|
|
3032
|
-
return {
|
|
3033
|
-
agent: "yieldseeker",
|
|
3034
|
-
action: actionType(action.actionType),
|
|
3035
|
-
date: action.createdDate,
|
|
3036
|
-
oldApy: null,
|
|
3037
|
-
newApy: null,
|
|
3038
|
-
transactions: [
|
|
3039
|
-
{
|
|
3040
|
-
txHashes: transactionHashes(action.details),
|
|
3041
|
-
chainId: 8453
|
|
3042
|
-
}
|
|
3043
|
-
],
|
|
3044
|
-
rebalanceLog: []
|
|
3045
|
-
};
|
|
3046
|
-
}
|
|
3047
|
-
function movementEntry(movement, wallet, agent, asset, ownerAddress, vaultAddresses) {
|
|
3048
|
-
const from = movement.fromAddress.toLowerCase();
|
|
3049
|
-
const to = movement.toAddress.toLowerCase();
|
|
3050
|
-
const owner = ownerAddress.toLowerCase();
|
|
3051
|
-
const agentWallet = wallet.walletAddress.toLowerCase();
|
|
3052
|
-
const baseAsset = agent.assetAddress.toLowerCase();
|
|
3053
|
-
if (movement.chainId !== agent.chainId || movement.assetAddress.toLowerCase() !== baseAsset) {
|
|
3054
|
-
return void 0;
|
|
3055
|
-
}
|
|
3056
|
-
let action;
|
|
3057
|
-
if (from === owner && to === agentWallet) {
|
|
3058
|
-
action = "Top up";
|
|
3059
|
-
} else if (from === agentWallet && to === owner) {
|
|
3060
|
-
action = "Withdraw";
|
|
3061
|
-
} else if (from === agentWallet && vaultAddresses.has(to)) {
|
|
3062
|
-
action = "Deposit";
|
|
3063
|
-
}
|
|
3064
|
-
if (!action) return void 0;
|
|
3065
|
-
return {
|
|
3066
|
-
agent: "yieldseeker",
|
|
3067
|
-
action,
|
|
3068
|
-
date: movement.blockDate,
|
|
3069
|
-
oldApy: null,
|
|
3070
|
-
newApy: null,
|
|
3071
|
-
transactions: [
|
|
3072
|
-
{
|
|
3073
|
-
txHashes: [movement.transactionHash],
|
|
3074
|
-
chainId: agent.chainId,
|
|
3075
|
-
tokenSymbol: asset,
|
|
3076
|
-
amount: decimal(
|
|
3077
|
-
movement.assetAmount,
|
|
3078
|
-
YIELDSEEKER_ASSET_METADATA[asset].decimals,
|
|
3079
|
-
"historic position"
|
|
3080
|
-
)
|
|
3081
|
-
}
|
|
3082
|
-
],
|
|
3083
|
-
rebalanceLog: []
|
|
3084
|
-
};
|
|
3085
|
-
}
|
|
3086
|
-
function mapYieldseekerHistory(contexts, options) {
|
|
3087
|
-
const entries = contexts.flatMap((context) => {
|
|
3088
|
-
const vaultAddresses = new Set(
|
|
3089
|
-
context.positions.map(
|
|
3090
|
-
(position2) => position2.yieldOption.address.toLowerCase()
|
|
3091
|
-
)
|
|
3092
|
-
);
|
|
3093
|
-
return [
|
|
3094
|
-
...(context.historic?.movements ?? []).map(
|
|
3095
|
-
(movement) => movementEntry(
|
|
3096
|
-
movement,
|
|
3097
|
-
context.wallet,
|
|
3098
|
-
context.agent,
|
|
3099
|
-
context.asset,
|
|
3100
|
-
options.ownerAddress,
|
|
3101
|
-
vaultAddresses
|
|
3102
|
-
)
|
|
3103
|
-
),
|
|
3104
|
-
...(context.actions ?? []).map(actionEntry)
|
|
3105
|
-
].filter((entry) => entry !== void 0);
|
|
3106
|
-
});
|
|
3107
|
-
const filtered = entries.filter(
|
|
3108
|
-
(entry) => (!options.fromDate || entry.date >= options.fromDate) && (!options.toDate || entry.date <= options.toDate)
|
|
3109
|
-
).filter((entry, index, all) => {
|
|
3110
|
-
const transactionHash = entry.transactions[0]?.txHashes[0];
|
|
3111
|
-
if (!transactionHash) return true;
|
|
3112
|
-
return all.findIndex(
|
|
3113
|
-
(candidate) => candidate.action === entry.action && candidate.transactions[0]?.txHashes[0] === transactionHash
|
|
3114
|
-
) === index;
|
|
3115
|
-
}).sort((left, right) => right.date.localeCompare(left.date));
|
|
3116
|
-
return {
|
|
3117
|
-
data: filtered.slice(0, options.limit),
|
|
3118
|
-
// v1 returns the whole action/movement collection and defines no cursor.
|
|
3119
|
-
// Report a terminal page so callers never loop over the same prefix.
|
|
3120
|
-
hasMore: false
|
|
3121
|
-
};
|
|
3122
|
-
}
|
|
3123
|
-
function mapYieldseekerProfile(address, contexts) {
|
|
3124
|
-
const protocols = /* @__PURE__ */ new Set();
|
|
3125
|
-
for (const context of contexts) {
|
|
3126
|
-
for (const current of context.positions) {
|
|
3127
|
-
if (current.yieldOption?.provider) {
|
|
3128
|
-
protocols.add(String(current.yieldOption.provider));
|
|
3129
|
-
}
|
|
3130
|
-
}
|
|
3131
|
-
}
|
|
3132
|
-
return {
|
|
3133
|
-
address,
|
|
3134
|
-
smartWallet: contexts[0]?.wallet.walletAddress ?? "0x0000000000000000000000000000000000000000",
|
|
3135
|
-
chains: contexts.length > 0 ? [8453] : [],
|
|
3136
|
-
hasActiveSessionKey: contexts.some(
|
|
3137
|
-
(context) => context.wallet.initializedDate != null
|
|
3138
|
-
),
|
|
3139
|
-
protocols: [...protocols]
|
|
3140
|
-
};
|
|
3141
|
-
}
|
|
3142
|
-
function mapYieldseekerAgentApy(options, days) {
|
|
3143
|
-
const perAsset = {};
|
|
3144
|
-
const all = [];
|
|
3145
|
-
for (const entry of options) {
|
|
3146
|
-
const apys = entry.yieldOptions.map(
|
|
3147
|
-
(option) => publicApyAfterYieldseekerFee(riskAdjustedApyForDays(option, days))
|
|
3148
|
-
).filter(Number.isFinite);
|
|
3149
|
-
if (apys.length === 0) continue;
|
|
3150
|
-
const average = apys.reduce((sum, value) => sum + value, 0) / apys.length;
|
|
3151
|
-
perAsset[entry.asset] = average;
|
|
3152
|
-
all.push(average);
|
|
3153
|
-
}
|
|
3154
|
-
return {
|
|
3155
|
-
averageApy: all.length > 0 ? all.reduce((sum, value) => sum + value, 0) / all.length : 0,
|
|
3156
|
-
detailedApys: { apyPerAsset: { 8453: perAsset } }
|
|
3157
|
-
};
|
|
3158
|
-
}
|
|
3159
|
-
|
|
3160
|
-
// src/agents/yieldseeker/yieldseeker.agent.ts
|
|
3161
|
-
var OWNEY_AGENT_NAME = "owney";
|
|
3162
|
-
var YIELDSEEKER_USERNAME_PREFIX = "owney_";
|
|
3163
|
-
var YIELDSEEKER_USERNAME_RANDOM_LENGTH = 14;
|
|
3164
|
-
var YIELDSEEKER_USERNAME_CREATE_ATTEMPTS = 3;
|
|
3165
|
-
function generateYieldseekerUsername() {
|
|
3166
|
-
const suffix = globalThis.crypto.randomUUID().replaceAll("-", "").slice(0, YIELDSEEKER_USERNAME_RANDOM_LENGTH).toLowerCase();
|
|
3167
|
-
return `${YIELDSEEKER_USERNAME_PREFIX}${suffix}`;
|
|
3168
|
-
}
|
|
3169
|
-
function isUsernameConflict(error) {
|
|
3170
|
-
if (!(error instanceof YieldseekerApiError)) return false;
|
|
3171
|
-
const code = error.providerCode.toUpperCase();
|
|
3172
|
-
return code.includes("USERNAME") && (code.includes("TAKEN") || code.includes("EXIST") || code.includes("UNAVAILABLE") || code.includes("IN_USE"));
|
|
3173
|
-
}
|
|
3174
|
-
var YIELDSEEKER_AGENT_WALLET_ABI = [
|
|
3175
|
-
{
|
|
3176
|
-
type: "function",
|
|
3177
|
-
name: "withdrawAssetToUser",
|
|
3178
|
-
stateMutability: "nonpayable",
|
|
3179
|
-
inputs: [
|
|
3180
|
-
{ name: "recipient", type: "address" },
|
|
3181
|
-
{ name: "asset", type: "address" },
|
|
3182
|
-
{ name: "amount", type: "uint256" }
|
|
3183
|
-
],
|
|
3184
|
-
outputs: []
|
|
3185
|
-
},
|
|
3186
|
-
{
|
|
3187
|
-
type: "function",
|
|
3188
|
-
name: "withdrawAllAssetToUser",
|
|
3189
|
-
stateMutability: "nonpayable",
|
|
3190
|
-
inputs: [
|
|
3191
|
-
{ name: "recipient", type: "address" },
|
|
3192
|
-
{ name: "asset", type: "address" }
|
|
3193
|
-
],
|
|
3194
|
-
outputs: []
|
|
3195
|
-
}
|
|
3196
|
-
];
|
|
3197
|
-
function query(params) {
|
|
3198
|
-
const search = new URLSearchParams();
|
|
3199
|
-
for (const [key2, value] of Object.entries(params)) {
|
|
3200
|
-
if (value !== void 0) search.set(key2, String(value));
|
|
3201
|
-
}
|
|
3202
|
-
const encoded = search.toString();
|
|
3203
|
-
return encoded ? `?${encoded}` : "";
|
|
3204
|
-
}
|
|
3205
|
-
var YieldseekerAgent = class {
|
|
3206
|
-
id = "yieldseeker";
|
|
3207
|
-
balanceComposition = "tokens-plus-positions";
|
|
3208
|
-
supportedChainIds = [8453];
|
|
3209
|
-
supportedAssets = [
|
|
3210
|
-
{
|
|
3211
|
-
chainId: 8453,
|
|
3212
|
-
chain: "BASE",
|
|
3213
|
-
assets: [
|
|
3214
|
-
{ symbol: "USDC", minDepositAmount: "10000000" },
|
|
3215
|
-
{ symbol: "WETH", minDepositAmount: "1" }
|
|
3216
|
-
]
|
|
3217
|
-
}
|
|
3218
|
-
];
|
|
3219
|
-
api;
|
|
3220
|
-
auth;
|
|
3221
|
-
transactionExecutor;
|
|
3222
|
-
unwindReceiptWaiter;
|
|
3223
|
-
agentContexts = /* @__PURE__ */ new Map();
|
|
3224
|
-
users = /* @__PURE__ */ new Map();
|
|
3225
|
-
pendingAgents = /* @__PURE__ */ new Map();
|
|
3226
|
-
constructor(owneyApiKey, options = {}) {
|
|
3227
|
-
this.api = new YieldseekerApiClient(
|
|
3228
|
-
owneyApiKey,
|
|
3229
|
-
options.baseUrl ?? getYieldseekerProxyBaseUrl(),
|
|
3230
|
-
options.fetchFn
|
|
3231
|
-
);
|
|
3232
|
-
this.auth = new YieldseekerAuth(options.auth);
|
|
3233
|
-
this.transactionExecutor = options.transactionExecutor;
|
|
3234
|
-
this.unwindReceiptWaiter = options.unwindReceiptWaiter;
|
|
3235
|
-
}
|
|
3236
|
-
async disconnect() {
|
|
3237
|
-
this.auth.clear();
|
|
3238
|
-
for (const key2 of this.users.keys()) {
|
|
3239
|
-
const [walletAddress, chainId] = key2.split(":");
|
|
3240
|
-
clearYieldseekerIdentity(walletAddress, Number(chainId));
|
|
3241
|
-
}
|
|
3242
|
-
this.users.clear();
|
|
3243
|
-
this.agentContexts.clear();
|
|
3244
|
-
this.pendingAgents.clear();
|
|
3245
|
-
}
|
|
3246
|
-
async activateAgent(state, chainId, asset) {
|
|
3247
|
-
this.assertChain(chainId);
|
|
3248
|
-
const targetAsset = asset ?? "USDC";
|
|
3249
|
-
this.assertAsset(targetAsset);
|
|
3250
|
-
await this.ensureAgent(state, chainId, targetAsset);
|
|
3251
|
-
}
|
|
3252
|
-
async deposit(state, chainId, amount, asset, depositCallback) {
|
|
3253
|
-
this.assertChain(chainId);
|
|
3254
|
-
this.assertAsset(asset);
|
|
3255
|
-
if (BigInt(amount) <= 0n) {
|
|
3256
|
-
throw new OwneyError(
|
|
3257
|
-
"DEPOSIT_AMOUNT_BELOW_MINIMUM",
|
|
3258
|
-
"Yieldseeker deposits must be greater than zero.",
|
|
3259
|
-
{ amount, minDepositAmount: "1" },
|
|
3260
|
-
this.id
|
|
3261
|
-
);
|
|
3262
|
-
}
|
|
3263
|
-
const context = await this.ensureAgent(state, chainId, asset);
|
|
3264
|
-
let txHash;
|
|
3265
|
-
try {
|
|
3266
|
-
if (depositCallback) {
|
|
3267
|
-
provideDepositVerificationContext(depositCallback, {
|
|
3268
|
-
agentId: "yieldseeker",
|
|
3269
|
-
signature: await this.auth.getToken(state, chainId),
|
|
3270
|
-
userId: context.user.userId,
|
|
3271
|
-
yieldseekerAgentId: context.agent.agentId
|
|
3272
|
-
});
|
|
3273
|
-
txHash = await depositCallback(
|
|
3274
|
-
context.wallet.walletAddress,
|
|
3275
|
-
chainId,
|
|
3276
|
-
amount
|
|
3277
|
-
);
|
|
3278
|
-
await this.waitForReceipt(state, chainId, txHash);
|
|
3279
|
-
} else {
|
|
3280
|
-
txHash = await this.submitTransaction(state, chainId, {
|
|
3281
|
-
from: getAddress2(state.walletAddress),
|
|
3282
|
-
to: YIELDSEEKER_ASSET_METADATA[asset].address,
|
|
3283
|
-
data: encodeFunctionData({
|
|
3284
|
-
abi: erc20Abi,
|
|
3285
|
-
functionName: "transfer",
|
|
3286
|
-
args: [getAddress2(context.wallet.walletAddress), BigInt(amount)]
|
|
3287
|
-
}),
|
|
3288
|
-
value: "0",
|
|
3289
|
-
chainId
|
|
3290
|
-
});
|
|
3291
|
-
}
|
|
3292
|
-
await this.deployAfterFunding(state, chainId, context);
|
|
3293
|
-
} finally {
|
|
3294
|
-
await this.refreshSnapshotAfterMovement(
|
|
3295
|
-
state,
|
|
3296
|
-
chainId,
|
|
3297
|
-
context,
|
|
3298
|
-
"deposit"
|
|
3299
|
-
);
|
|
3300
|
-
}
|
|
3301
|
-
return {
|
|
3302
|
-
txHash,
|
|
3303
|
-
smartWallet: context.wallet.walletAddress,
|
|
3304
|
-
amount
|
|
3305
|
-
};
|
|
3306
|
-
}
|
|
3307
|
-
async withdraw(state, chainId, asset, amount) {
|
|
3308
|
-
this.assertChain(chainId);
|
|
3309
|
-
this.assertAsset(asset);
|
|
3310
|
-
if (amount !== void 0 && BigInt(amount) <= 0n) {
|
|
3311
|
-
throw new OwneyError(
|
|
3312
|
-
"WITHDRAW_FAILED",
|
|
3313
|
-
"Yieldseeker withdrawals must be greater than zero.",
|
|
3314
|
-
{ amount },
|
|
3315
|
-
this.id
|
|
3316
|
-
);
|
|
3317
|
-
}
|
|
3318
|
-
const context = await this.findAgent(state, chainId, asset);
|
|
3319
|
-
if (!context) {
|
|
3320
|
-
throw new OwneyError(
|
|
3321
|
-
"WITHDRAW_INSUFFICIENT_BALANCE",
|
|
3322
|
-
`No Yieldseeker ${asset} agent exists for this wallet.`,
|
|
3323
|
-
{ asset, available: "0" },
|
|
3324
|
-
this.id
|
|
3325
|
-
);
|
|
3326
|
-
}
|
|
3327
|
-
try {
|
|
3328
|
-
const portfolio = await this.loadPortfolioContext(
|
|
3329
|
-
state,
|
|
3330
|
-
chainId,
|
|
3331
|
-
context
|
|
3332
|
-
);
|
|
3333
|
-
const metadata = YIELDSEEKER_ASSET_METADATA[asset];
|
|
3334
|
-
const idleEntry = Object.entries(portfolio.snapshot.tokenBalances).find(
|
|
3335
|
-
([address]) => address.toLowerCase() === metadata.address.toLowerCase()
|
|
3336
|
-
);
|
|
3337
|
-
const idle = BigInt(idleEntry?.[1] ?? "0");
|
|
3338
|
-
const deployed = portfolio.positions.reduce(
|
|
3339
|
-
(total, position2) => total + BigInt(position2.withdrawableAssetsRaw),
|
|
3340
|
-
0n
|
|
3341
|
-
);
|
|
3342
|
-
const totalAvailable = idle + deployed;
|
|
3343
|
-
const requested = amount === void 0 ? totalAvailable : BigInt(amount);
|
|
3344
|
-
if (requested > totalAvailable) {
|
|
3345
|
-
throw new OwneyError(
|
|
3346
|
-
"WITHDRAW_INSUFFICIENT_BALANCE",
|
|
3347
|
-
`Requested withdrawal "${requested}" exceeds available Yieldseeker balance "${totalAvailable}" for asset "${asset}".`,
|
|
3348
|
-
{
|
|
3349
|
-
asset,
|
|
3350
|
-
requested: requested.toString(),
|
|
3351
|
-
available: totalAvailable.toString()
|
|
3352
|
-
},
|
|
3353
|
-
this.id
|
|
3354
|
-
);
|
|
3355
|
-
}
|
|
3356
|
-
let remaining = requested > idle ? requested - idle : 0n;
|
|
3357
|
-
for (const position2 of portfolio.positions) {
|
|
3358
|
-
if (remaining === 0n) break;
|
|
3359
|
-
const available = BigInt(position2.withdrawableAssetsRaw);
|
|
3360
|
-
if (available <= 0n) continue;
|
|
3361
|
-
const assetsRaw = available < remaining ? available : remaining;
|
|
3362
|
-
const response = await this.walletRequest(
|
|
3363
|
-
state,
|
|
3364
|
-
chainId,
|
|
3365
|
-
this.agentPath(context, "withdraw-from-position"),
|
|
3366
|
-
{
|
|
3367
|
-
method: "POST",
|
|
3368
|
-
body: {
|
|
3369
|
-
chainId,
|
|
3370
|
-
vaultAddress: position2.yieldOption.address,
|
|
3371
|
-
assetsRaw: assetsRaw.toString()
|
|
3372
|
-
}
|
|
3373
|
-
}
|
|
3374
|
-
);
|
|
3375
|
-
if (!this.isTransactionHash(response?.transactionHash)) {
|
|
3376
|
-
throw this.invalidResponse("position withdrawal");
|
|
3377
|
-
}
|
|
3378
|
-
await this.waitForReceipt(state, chainId, response.transactionHash);
|
|
3379
|
-
remaining -= assetsRaw;
|
|
3380
|
-
}
|
|
3381
|
-
if (remaining > 0n) {
|
|
3382
|
-
throw this.invalidResponse("yield positions", {
|
|
3383
|
-
reason: "Withdrawable positions could not cover the request.",
|
|
3384
|
-
remaining: remaining.toString()
|
|
3385
|
-
});
|
|
3386
|
-
}
|
|
3387
|
-
const account = getAddress2(state.walletAddress);
|
|
3388
|
-
const txHash = await this.submitTransaction(state, chainId, {
|
|
3389
|
-
from: account,
|
|
3390
|
-
to: getAddress2(context.wallet.walletAddress),
|
|
3391
|
-
data: amount === void 0 ? encodeFunctionData({
|
|
3392
|
-
abi: YIELDSEEKER_AGENT_WALLET_ABI,
|
|
3393
|
-
functionName: "withdrawAllAssetToUser",
|
|
3394
|
-
args: [account, metadata.address]
|
|
3395
|
-
}) : encodeFunctionData({
|
|
3396
|
-
abi: YIELDSEEKER_AGENT_WALLET_ABI,
|
|
3397
|
-
functionName: "withdrawAssetToUser",
|
|
3398
|
-
args: [account, metadata.address, requested]
|
|
3399
|
-
}),
|
|
3400
|
-
value: "0",
|
|
3401
|
-
chainId
|
|
3402
|
-
});
|
|
3403
|
-
return {
|
|
3404
|
-
txHash,
|
|
3405
|
-
type: amount === void 0 ? "full" : "partial",
|
|
3406
|
-
amount: requested.toString()
|
|
3407
|
-
};
|
|
3408
|
-
} finally {
|
|
3409
|
-
await this.refreshSnapshotAfterMovement(
|
|
3410
|
-
state,
|
|
3411
|
-
chainId,
|
|
3412
|
-
context,
|
|
3413
|
-
"withdrawal"
|
|
3414
|
-
);
|
|
3415
|
-
}
|
|
3416
|
-
}
|
|
3417
|
-
async getBalances(state, chainId) {
|
|
3418
|
-
this.assertChain(chainId);
|
|
3419
|
-
return mapYieldseekerBalances(await this.loadPortfolio(state, chainId, {}));
|
|
3420
|
-
}
|
|
3421
|
-
async getEarnings(state, chainId) {
|
|
3422
|
-
this.assertChain(chainId);
|
|
3423
|
-
return mapYieldseekerEarnings(await this.loadPortfolio(state, chainId, {}));
|
|
3424
|
-
}
|
|
3425
|
-
async getAccountApy(state, chainId, days, tokenSymbol) {
|
|
3426
|
-
this.assertChain(chainId);
|
|
3427
|
-
const asset = tokenSymbol?.toUpperCase();
|
|
3428
|
-
if (asset !== void 0) this.assertAsset(asset);
|
|
3429
|
-
const contexts = await this.loadPortfolio(state, chainId, {
|
|
3430
|
-
...asset ? { asset } : {},
|
|
3431
|
-
historic: true
|
|
3432
|
-
});
|
|
3433
|
-
return mapYieldseekerApy(state.walletAddress, contexts, days);
|
|
3434
|
-
}
|
|
3435
|
-
async getHistory(state, chainId, options) {
|
|
3436
|
-
this.assertChain(chainId);
|
|
3437
|
-
const asset = options?.tokenSymbol?.toUpperCase();
|
|
3438
|
-
if (asset !== void 0) this.assertAsset(asset);
|
|
3439
|
-
const contexts = await this.loadPortfolio(state, chainId, {
|
|
3440
|
-
...asset ? { asset } : {},
|
|
3441
|
-
historic: true,
|
|
3442
|
-
actions: true
|
|
3443
|
-
});
|
|
3444
|
-
return mapYieldseekerHistory(contexts, {
|
|
3445
|
-
limit: options?.limit ?? 10,
|
|
3446
|
-
ownerAddress: state.walletAddress,
|
|
3447
|
-
...options?.fromDate ? { fromDate: options.fromDate } : {},
|
|
3448
|
-
...options?.toDate ? { toDate: options.toDate } : {}
|
|
3449
|
-
});
|
|
3450
|
-
}
|
|
3451
|
-
async getUserProfile(state, chainId) {
|
|
3452
|
-
this.assertChain(chainId);
|
|
3453
|
-
return mapYieldseekerProfile(
|
|
3454
|
-
state.walletAddress,
|
|
3455
|
-
await this.loadPortfolio(state, chainId, {})
|
|
3456
|
-
);
|
|
3457
|
-
}
|
|
3458
|
-
async getAgentApy(days, options) {
|
|
3459
|
-
this.assertOptionalChain(options?.chainId);
|
|
3460
|
-
const requested = options?.tokenSymbol?.toUpperCase();
|
|
3461
|
-
if (requested !== void 0) this.assertAsset(requested);
|
|
3462
|
-
const assets = requested ? [requested] : ["USDC", "WETH"];
|
|
3463
|
-
const values = await Promise.all(
|
|
3464
|
-
assets.map(async (asset) => {
|
|
3465
|
-
const metadata = YIELDSEEKER_ASSET_METADATA[asset];
|
|
3466
|
-
const response = await this.api.request(
|
|
3467
|
-
`/chains/8453/assets/${metadata.address}/yield-options`
|
|
3468
|
-
);
|
|
3469
|
-
if (!Array.isArray(response?.yieldOptions)) {
|
|
3470
|
-
throw this.invalidResponse("yield options");
|
|
3471
|
-
}
|
|
3472
|
-
return { asset, yieldOptions: response.yieldOptions };
|
|
3473
|
-
})
|
|
3474
|
-
);
|
|
3475
|
-
return mapYieldseekerAgentApy(values, days);
|
|
3476
|
-
}
|
|
3477
|
-
userKey(state, chainId) {
|
|
3478
|
-
return `${state.walletAddress.toLowerCase()}:${chainId}`;
|
|
3479
|
-
}
|
|
3480
|
-
contextKey(state, chainId, asset) {
|
|
3481
|
-
return `${this.userKey(state, chainId)}:${asset}`;
|
|
3482
|
-
}
|
|
3483
|
-
async resolveUser(state, chainId) {
|
|
3484
|
-
const key2 = this.userKey(state, chainId);
|
|
3485
|
-
const inMemory = this.users.get(key2);
|
|
3486
|
-
if (inMemory) return inMemory;
|
|
3487
|
-
const persisted = readYieldseekerIdentity(state.walletAddress, chainId);
|
|
3488
|
-
if (persisted) {
|
|
3489
|
-
this.users.set(key2, persisted);
|
|
3490
|
-
return persisted;
|
|
3491
|
-
}
|
|
3492
|
-
const walletAddress = getAddress2(state.walletAddress);
|
|
3493
|
-
let user = null;
|
|
3494
|
-
try {
|
|
3495
|
-
const login = await this.providerRequest(
|
|
3496
|
-
state,
|
|
3497
|
-
chainId,
|
|
3498
|
-
"/users/login-with-wallet",
|
|
3499
|
-
{ method: "POST", body: { walletAddress } }
|
|
3500
|
-
);
|
|
3501
|
-
user = login?.user ?? null;
|
|
3502
|
-
if (!user) {
|
|
3503
|
-
throw this.invalidResponse("wallet login", {
|
|
3504
|
-
reason: "A successful login returned no user."
|
|
3505
|
-
});
|
|
3506
|
-
}
|
|
3507
|
-
} catch (error) {
|
|
3508
|
-
if (!(error instanceof YieldseekerApiError) || error.providerCode !== "NO_USER") {
|
|
3509
|
-
if (error instanceof OwneyError) throw error;
|
|
3510
|
-
throw this.mapApiError(error);
|
|
3511
|
-
}
|
|
3512
|
-
let created;
|
|
3513
|
-
for (let attempt = 0; attempt < YIELDSEEKER_USERNAME_CREATE_ATTEMPTS; attempt += 1) {
|
|
3514
|
-
try {
|
|
3515
|
-
created = await this.providerRequest(
|
|
3516
|
-
state,
|
|
3517
|
-
chainId,
|
|
3518
|
-
"/users",
|
|
3519
|
-
{
|
|
3520
|
-
method: "POST",
|
|
3521
|
-
body: {
|
|
3522
|
-
walletAddress,
|
|
3523
|
-
username: generateYieldseekerUsername()
|
|
3524
|
-
}
|
|
3525
|
-
}
|
|
3526
|
-
);
|
|
3527
|
-
break;
|
|
3528
|
-
} catch (createError) {
|
|
3529
|
-
const canRetry = isUsernameConflict(createError) && attempt + 1 < YIELDSEEKER_USERNAME_CREATE_ATTEMPTS;
|
|
3530
|
-
if (canRetry) continue;
|
|
3531
|
-
throw this.mapApiError(createError);
|
|
3532
|
-
}
|
|
3533
|
-
}
|
|
3534
|
-
user = created?.user ?? null;
|
|
3535
|
-
}
|
|
3536
|
-
if (!user || !/^[a-zA-Z0-9_-]{1,128}$/.test(user.userId)) {
|
|
3537
|
-
throw this.invalidResponse("wallet identity");
|
|
3538
|
-
}
|
|
3539
|
-
const resolved = { userId: user.userId };
|
|
3540
|
-
this.users.set(key2, resolved);
|
|
3541
|
-
writeYieldseekerIdentity(state.walletAddress, chainId, resolved.userId);
|
|
3542
|
-
return resolved;
|
|
3543
|
-
}
|
|
3544
|
-
forgetUser(state, chainId) {
|
|
3545
|
-
this.users.delete(this.userKey(state, chainId));
|
|
3546
|
-
clearYieldseekerIdentity(state.walletAddress, chainId);
|
|
3547
|
-
}
|
|
3548
|
-
async ensureAgent(state, chainId, asset) {
|
|
3549
|
-
const key2 = this.contextKey(state, chainId, asset);
|
|
3550
|
-
const cached = this.agentContexts.get(key2);
|
|
3551
|
-
if (cached) return cached;
|
|
3552
|
-
const pending = this.pendingAgents.get(key2);
|
|
3553
|
-
if (pending) return pending;
|
|
3554
|
-
const request = this.resolveAgent(state, chainId, asset, true).then(
|
|
3555
|
-
(context) => {
|
|
3556
|
-
if (!context) throw this.invalidResponse("agent creation");
|
|
3557
|
-
this.agentContexts.set(key2, context);
|
|
3558
|
-
return context;
|
|
3559
|
-
}
|
|
3560
|
-
);
|
|
3561
|
-
this.pendingAgents.set(key2, request);
|
|
3562
|
-
try {
|
|
3563
|
-
return await request;
|
|
3564
|
-
} finally {
|
|
3565
|
-
this.pendingAgents.delete(key2);
|
|
3566
|
-
}
|
|
3567
|
-
}
|
|
3568
|
-
async findAgent(state, chainId, asset) {
|
|
3569
|
-
const key2 = this.contextKey(state, chainId, asset);
|
|
3570
|
-
const cached = this.agentContexts.get(key2);
|
|
3571
|
-
if (cached) return cached;
|
|
3572
|
-
const context = await this.resolveAgent(state, chainId, asset, false);
|
|
3573
|
-
if (context) this.agentContexts.set(key2, context);
|
|
3574
|
-
return context;
|
|
3575
|
-
}
|
|
3576
|
-
async resolveAgent(state, chainId, asset, createIfMissing) {
|
|
3577
|
-
const user = await this.resolveUser(state, chainId);
|
|
3578
|
-
const response = await this.walletRequest(
|
|
3579
|
-
state,
|
|
3580
|
-
chainId,
|
|
3581
|
-
`/users/${user.userId}/agents`
|
|
3582
|
-
);
|
|
3583
|
-
if (!Array.isArray(response?.agents)) {
|
|
3584
|
-
throw this.invalidResponse("agent list");
|
|
3585
|
-
}
|
|
3586
|
-
const metadata = YIELDSEEKER_ASSET_METADATA[asset];
|
|
3587
|
-
let agent = response.agents.find(
|
|
3588
|
-
(candidate) => this.isOwneyAgent(candidate) && candidate.chainId === chainId && candidate.type === "vault" && candidate.assetAddress.toLowerCase() === metadata.address.toLowerCase()
|
|
3589
|
-
);
|
|
3590
|
-
if (!agent && createIfMissing) {
|
|
3591
|
-
const created = await this.walletRequest(
|
|
3592
|
-
state,
|
|
3593
|
-
chainId,
|
|
3594
|
-
`/users/${user.userId}/agents`,
|
|
3595
|
-
{
|
|
3596
|
-
method: "POST",
|
|
3597
|
-
body: {
|
|
3598
|
-
name: OWNEY_AGENT_NAME,
|
|
3599
|
-
emoji: "\u{1F989}",
|
|
3600
|
-
chainId,
|
|
3601
|
-
assetAddress: metadata.address,
|
|
3602
|
-
type: "vault",
|
|
3603
|
-
rulePreset: null
|
|
3604
|
-
}
|
|
3605
|
-
}
|
|
3606
|
-
);
|
|
3607
|
-
agent = created?.agent;
|
|
3608
|
-
}
|
|
3609
|
-
if (!agent) return null;
|
|
3610
|
-
this.assertAgent(agent);
|
|
3611
|
-
const walletResponse = await this.walletRequest(
|
|
3612
|
-
state,
|
|
3613
|
-
chainId,
|
|
3614
|
-
`/users/${user.userId}/agents/${agent.agentId}/wallet`
|
|
3615
|
-
);
|
|
3616
|
-
if (!walletResponse?.agentWallet || !isAddress2(walletResponse.agentWallet.walletAddress)) {
|
|
3617
|
-
throw this.invalidResponse("agent wallet");
|
|
3618
|
-
}
|
|
3619
|
-
return { user, agent, wallet: walletResponse.agentWallet, asset };
|
|
3620
|
-
}
|
|
3621
|
-
async loadPortfolio(state, chainId, options) {
|
|
3622
|
-
const user = await this.resolveUser(state, chainId);
|
|
3623
|
-
const response = await this.walletRequest(
|
|
3624
|
-
state,
|
|
3625
|
-
chainId,
|
|
3626
|
-
`/users/${user.userId}/agents`
|
|
3627
|
-
);
|
|
3628
|
-
if (!Array.isArray(response?.agents)) {
|
|
3629
|
-
throw this.invalidResponse("agent list");
|
|
3630
|
-
}
|
|
3631
|
-
const contexts = [];
|
|
3632
|
-
for (const agent of response.agents) {
|
|
3633
|
-
const asset = this.assetForAgent(agent);
|
|
3634
|
-
if (!this.isOwneyAgent(agent) || !asset || agent.chainId !== chainId || agent.type !== "vault" || options.asset && options.asset !== asset) {
|
|
3635
|
-
continue;
|
|
3636
|
-
}
|
|
3637
|
-
this.assertAgent(agent);
|
|
3638
|
-
const walletResponse = await this.walletRequest(
|
|
3639
|
-
state,
|
|
3640
|
-
chainId,
|
|
3641
|
-
`/users/${user.userId}/agents/${agent.agentId}/wallet`
|
|
3642
|
-
);
|
|
3643
|
-
if (!walletResponse?.agentWallet || !isAddress2(walletResponse.agentWallet.walletAddress)) {
|
|
3644
|
-
throw this.invalidResponse("agent wallet");
|
|
3645
|
-
}
|
|
3646
|
-
const context = {
|
|
3647
|
-
user,
|
|
3648
|
-
agent,
|
|
3649
|
-
wallet: walletResponse.agentWallet,
|
|
3650
|
-
asset
|
|
3651
|
-
};
|
|
3652
|
-
this.agentContexts.set(this.contextKey(state, chainId, asset), context);
|
|
3653
|
-
contexts.push(context);
|
|
3654
|
-
}
|
|
3655
|
-
return Promise.all(
|
|
3656
|
-
contexts.map(
|
|
3657
|
-
(context) => this.loadPortfolioContext(state, chainId, context, options)
|
|
3658
|
-
)
|
|
3659
|
-
);
|
|
3660
|
-
}
|
|
3661
|
-
async loadPortfolioContext(state, chainId, context, options = {}) {
|
|
3662
|
-
const [snapshot, positions, historic, actions] = await Promise.all([
|
|
3663
|
-
this.walletRequest(
|
|
3664
|
-
state,
|
|
3665
|
-
chainId,
|
|
3666
|
-
`${this.agentPath(context, "snapshot")}${query({
|
|
3667
|
-
shouldOnlyUseRecentValue: true,
|
|
3668
|
-
shouldAllowStaleOnError: true
|
|
3669
|
-
})}`
|
|
3670
|
-
),
|
|
3671
|
-
this.walletRequest(
|
|
3672
|
-
state,
|
|
3673
|
-
chainId,
|
|
3674
|
-
this.agentPath(context, "yield-positions")
|
|
3675
|
-
),
|
|
3676
|
-
options.historic ? this.walletRequest(
|
|
3677
|
-
state,
|
|
3678
|
-
chainId,
|
|
3679
|
-
this.agentPath(context, "wallet/historic-position")
|
|
3680
|
-
) : Promise.resolve(void 0),
|
|
3681
|
-
options.actions ? this.walletRequest(
|
|
3682
|
-
state,
|
|
3683
|
-
chainId,
|
|
3684
|
-
this.agentPath(context, "actions")
|
|
3685
|
-
) : Promise.resolve(void 0)
|
|
3686
|
-
]);
|
|
3687
|
-
if (!snapshot?.agentSnapshot) {
|
|
3688
|
-
throw this.invalidResponse("agent snapshot");
|
|
3689
|
-
}
|
|
3690
|
-
if (!Array.isArray(positions?.yieldPositions)) {
|
|
3691
|
-
throw this.invalidResponse("yield positions");
|
|
3692
|
-
}
|
|
3693
|
-
return {
|
|
3694
|
-
...context,
|
|
3695
|
-
snapshot: snapshot.agentSnapshot,
|
|
3696
|
-
positions: positions.yieldPositions,
|
|
3697
|
-
...historic?.position ? { historic: historic.position } : {},
|
|
3698
|
-
...actions?.actions ? { actions: actions.actions } : {}
|
|
3699
|
-
};
|
|
3700
|
-
}
|
|
3701
|
-
async deployAfterFunding(state, chainId, context) {
|
|
3702
|
-
if (context.wallet.initializedDate != null) return;
|
|
3703
|
-
try {
|
|
3704
|
-
const deployed = await this.walletRequest(
|
|
3705
|
-
state,
|
|
3706
|
-
chainId,
|
|
3707
|
-
this.agentPath(context, "deploy"),
|
|
3708
|
-
{ method: "POST", body: {} }
|
|
3709
|
-
);
|
|
3710
|
-
if (deployed?.agentWallet) {
|
|
3711
|
-
context.wallet = deployed.agentWallet;
|
|
3712
|
-
}
|
|
3713
|
-
} catch (error) {
|
|
3714
|
-
console.warn(
|
|
3715
|
-
"[owney-sdk] Yieldseeker deposit is funded but not deployable yet:",
|
|
3716
|
-
error
|
|
3717
|
-
);
|
|
3718
|
-
}
|
|
3719
|
-
}
|
|
3720
|
-
async refreshSnapshotAfterMovement(state, chainId, context, movement) {
|
|
3721
|
-
try {
|
|
3722
|
-
const response = await this.walletRequest(
|
|
3723
|
-
state,
|
|
3724
|
-
chainId,
|
|
3725
|
-
`${this.agentPath(context, "snapshot")}${query({
|
|
3726
|
-
shouldForceRefresh: true
|
|
3727
|
-
})}`
|
|
3728
|
-
);
|
|
3729
|
-
if (!response?.agentSnapshot) {
|
|
3730
|
-
throw this.invalidResponse("agent snapshot refresh");
|
|
3731
|
-
}
|
|
3732
|
-
} catch (error) {
|
|
3733
|
-
console.warn(
|
|
3734
|
-
`[owney-sdk] Yieldseeker ${movement} snapshot refresh failed:`,
|
|
3735
|
-
error
|
|
3736
|
-
);
|
|
3737
|
-
}
|
|
3738
|
-
}
|
|
3739
|
-
agentPath(context, suffix) {
|
|
3740
|
-
return `/users/${context.user.userId}/agents/${context.agent.agentId}/${suffix}`;
|
|
3741
|
-
}
|
|
3742
|
-
async walletRequest(state, chainId, path, options = {}) {
|
|
3743
|
-
try {
|
|
3744
|
-
return await this.providerRequest(state, chainId, path, options);
|
|
3745
|
-
} catch (error) {
|
|
3746
|
-
throw this.mapApiError(error);
|
|
3747
|
-
}
|
|
3748
|
-
}
|
|
3749
|
-
async providerRequest(state, chainId, path, options = {}) {
|
|
3750
|
-
this.assertChain(chainId);
|
|
3751
|
-
const request = (signature2) => this.api.request(path, {
|
|
3752
|
-
...options,
|
|
3753
|
-
signature: signature2
|
|
3754
|
-
});
|
|
3755
|
-
let signature = await this.auth.getToken(state, chainId);
|
|
3756
|
-
try {
|
|
3757
|
-
return await request(signature);
|
|
3758
|
-
} catch (error) {
|
|
3759
|
-
if (!(error instanceof YieldseekerApiError)) throw error;
|
|
3760
|
-
if (error.providerCode === "NO_USER") throw error;
|
|
3761
|
-
if (!error.isAuthenticationError) throw error;
|
|
3762
|
-
this.auth.clear(state, chainId);
|
|
3763
|
-
signature = await this.auth.getToken(state, chainId);
|
|
3764
|
-
try {
|
|
3765
|
-
return await request(signature);
|
|
3766
|
-
} catch (retryError) {
|
|
3767
|
-
if (retryError instanceof YieldseekerApiError && retryError.isAuthenticationError) {
|
|
3768
|
-
this.forgetUser(state, chainId);
|
|
3769
|
-
}
|
|
3770
|
-
throw retryError;
|
|
3771
|
-
}
|
|
3772
|
-
}
|
|
3773
|
-
}
|
|
3774
|
-
mapApiError(error) {
|
|
3775
|
-
if (!(error instanceof YieldseekerApiError)) {
|
|
3776
|
-
return new OwneyError(
|
|
3777
|
-
"AGENT_API_ERROR",
|
|
3778
|
-
"Yieldseeker request failed.",
|
|
3779
|
-
{ cause: error instanceof Error ? error.message : String(error) },
|
|
3780
|
-
this.id
|
|
3781
|
-
);
|
|
3782
|
-
}
|
|
3783
|
-
const code = error.isAuthenticationError ? "AGENT_AUTH_FAILED" : error.providerCode === "REQUEST_TIMEOUT" ? "AGENT_TIMEOUT" : "AGENT_API_ERROR";
|
|
3784
|
-
return new OwneyError(
|
|
3785
|
-
code,
|
|
3786
|
-
`Yieldseeker request failed: ${error.providerCode}.`,
|
|
3787
|
-
{
|
|
3788
|
-
statusCode: error.status,
|
|
3789
|
-
providerCode: error.providerCode,
|
|
3790
|
-
...error.responseFields ? { fields: error.responseFields } : {}
|
|
3791
|
-
},
|
|
3792
|
-
this.id
|
|
3793
|
-
);
|
|
3794
|
-
}
|
|
3795
|
-
async submitTransaction(state, chainId, transaction) {
|
|
3796
|
-
if (this.transactionExecutor) {
|
|
3797
|
-
return this.transactionExecutor(state, chainId, transaction);
|
|
3798
|
-
}
|
|
3799
|
-
this.assertTransaction(transaction, state, chainId);
|
|
3800
|
-
const account = getAddress2(state.walletAddress);
|
|
3801
|
-
const walletClient = createWalletClient2({
|
|
3802
|
-
account,
|
|
3803
|
-
chain: base3,
|
|
3804
|
-
transport: custom2(state.provider)
|
|
3805
|
-
});
|
|
3806
|
-
const publicClient = createPublicClient3({
|
|
3807
|
-
chain: base3,
|
|
3808
|
-
transport: custom2(state.provider)
|
|
3809
|
-
});
|
|
3810
|
-
await ensureWalletOnChain(
|
|
3811
|
-
publicClient,
|
|
3812
|
-
walletClient,
|
|
3813
|
-
8453
|
|
3814
|
-
);
|
|
3815
|
-
const hash = await walletClient.sendTransaction({
|
|
3816
|
-
account,
|
|
3817
|
-
chain: base3,
|
|
3818
|
-
to: getAddress2(transaction.to),
|
|
3819
|
-
data: transaction.data,
|
|
3820
|
-
value: BigInt(transaction.value)
|
|
3821
|
-
});
|
|
3822
|
-
const receipt = await publicClient.waitForTransactionReceipt({
|
|
3823
|
-
hash,
|
|
3824
|
-
confirmations: 1
|
|
3825
|
-
});
|
|
3826
|
-
if (receipt.status !== "success") {
|
|
3827
|
-
throw new OwneyError(
|
|
3828
|
-
"AGENT_TRANSACTION_REVERTED",
|
|
3829
|
-
`Yieldseeker transaction reverted (${hash}).`,
|
|
3830
|
-
{ transactionHash: hash },
|
|
3831
|
-
this.id
|
|
3832
|
-
);
|
|
3833
|
-
}
|
|
3834
|
-
return hash;
|
|
3835
|
-
}
|
|
3836
|
-
async waitForReceipt(state, chainId, transactionHash) {
|
|
3837
|
-
if (this.unwindReceiptWaiter) {
|
|
3838
|
-
await this.unwindReceiptWaiter(state, chainId, transactionHash);
|
|
3839
|
-
return;
|
|
3840
|
-
}
|
|
3841
|
-
const publicClient = createPublicClient3({
|
|
3842
|
-
chain: base3,
|
|
3843
|
-
transport: custom2(state.provider)
|
|
3844
|
-
});
|
|
3845
|
-
const receipt = await publicClient.waitForTransactionReceipt({
|
|
3846
|
-
hash: transactionHash,
|
|
3847
|
-
confirmations: 1
|
|
3848
|
-
});
|
|
3849
|
-
if (receipt.status !== "success") {
|
|
3850
|
-
throw new OwneyError(
|
|
3851
|
-
"AGENT_TRANSACTION_REVERTED",
|
|
3852
|
-
`Yieldseeker transaction reverted (${transactionHash}).`,
|
|
3853
|
-
{ transactionHash },
|
|
3854
|
-
this.id
|
|
3855
|
-
);
|
|
3856
|
-
}
|
|
3857
|
-
}
|
|
3858
|
-
assertTransaction(transaction, state, chainId) {
|
|
3859
|
-
if (!transaction || typeof transaction.from !== "string" || !isAddress2(transaction.from) || typeof transaction.to !== "string" || !isAddress2(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 || getAddress2(transaction.from) !== getAddress2(state.walletAddress)) {
|
|
3860
|
-
throw this.invalidResponse("transaction");
|
|
3861
|
-
}
|
|
3862
|
-
}
|
|
3863
|
-
assertAgent(agent) {
|
|
3864
|
-
if (typeof agent.agentId !== "string" || typeof agent.assetAddress !== "string" || !isAddress2(agent.assetAddress) || agent.chainId !== 8453) {
|
|
3865
|
-
throw this.invalidResponse("agent");
|
|
3866
|
-
}
|
|
3867
|
-
}
|
|
3868
|
-
isOwneyAgent(agent) {
|
|
3869
|
-
return typeof agent.name === "string" && agent.name.trim().toLowerCase() === OWNEY_AGENT_NAME;
|
|
3870
|
-
}
|
|
3871
|
-
assetForAgent(agent) {
|
|
3872
|
-
for (const asset of ["USDC", "WETH"]) {
|
|
3873
|
-
if (agent.assetAddress.toLowerCase() === YIELDSEEKER_ASSET_METADATA[asset].address.toLowerCase()) {
|
|
3874
|
-
return asset;
|
|
3875
|
-
}
|
|
3876
|
-
}
|
|
3877
|
-
return null;
|
|
3878
|
-
}
|
|
3879
|
-
isTransactionHash(value) {
|
|
3880
|
-
return typeof value === "string" && /^0x[a-fA-F0-9]{64}$/.test(value);
|
|
3881
|
-
}
|
|
3882
|
-
assertChain(chainId) {
|
|
3883
|
-
if (chainId !== 8453) {
|
|
3884
|
-
throw new OwneyError(
|
|
3885
|
-
"CHAIN_UNSUPPORTED",
|
|
3886
|
-
`Yieldseeker does not support chain ${chainId}.`,
|
|
3887
|
-
{ chainId, supportedChainIds: [8453] },
|
|
3888
|
-
this.id
|
|
3889
|
-
);
|
|
3890
|
-
}
|
|
3891
|
-
}
|
|
3892
|
-
assertOptionalChain(chainId) {
|
|
3893
|
-
if (chainId !== void 0) this.assertChain(chainId);
|
|
3894
|
-
}
|
|
3895
|
-
assertAsset(asset) {
|
|
3896
|
-
if (asset !== "USDC" && asset !== "WETH") {
|
|
3897
|
-
throw new OwneyError(
|
|
3898
|
-
"ASSET_UNSUPPORTED",
|
|
3899
|
-
`Yieldseeker does not support asset ${asset} in the Owney rollout.`,
|
|
3900
|
-
{
|
|
3901
|
-
asset,
|
|
3902
|
-
supportedAssets: ["USDC", "WETH"],
|
|
3903
|
-
providerAlsoAdvertises: ["cbBTC"]
|
|
3904
|
-
},
|
|
3905
|
-
this.id
|
|
3906
|
-
);
|
|
3907
|
-
}
|
|
3908
|
-
}
|
|
3909
|
-
invalidResponse(operation, details = {}) {
|
|
3910
|
-
return new OwneyError(
|
|
3911
|
-
"AGENT_INVALID_RESPONSE",
|
|
3912
|
-
`Yieldseeker returned an invalid ${operation} response.`,
|
|
3913
|
-
details,
|
|
3914
|
-
this.id
|
|
3915
|
-
);
|
|
3916
|
-
}
|
|
3917
|
-
};
|
|
3918
|
-
|
|
3919
|
-
// src/lib/routing-api.ts
|
|
3920
|
-
var ROUTING_API_BASE_URL2 = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
3921
|
-
async function fetchOrgAgentConfig(apiKey, baseUrl = ROUTING_API_BASE_URL2) {
|
|
3922
|
-
const url = `${baseUrl}/api/v1/agent/org-config`;
|
|
3923
|
-
try {
|
|
3924
|
-
const res = await fetch(url, {
|
|
3925
|
-
method: "GET",
|
|
3926
|
-
headers: {
|
|
3927
|
-
"Content-Type": "application/json",
|
|
3928
|
-
"x-owney-api-key": `${apiKey}`
|
|
3929
|
-
}
|
|
3930
|
-
});
|
|
3931
|
-
if (!res.ok) {
|
|
3932
|
-
if (res.status !== 404) {
|
|
3933
|
-
console.warn(
|
|
3934
|
-
`[owney-sdk] Could not read org agent config (${res.status}); leaving user profiles unchanged.`
|
|
3935
|
-
);
|
|
3936
|
-
}
|
|
3937
|
-
return null;
|
|
3938
|
-
}
|
|
3939
|
-
const json = await res.json();
|
|
3940
|
-
const policy = json.success ? json.data ?? null : null;
|
|
3941
|
-
debugLog(
|
|
3942
|
-
"owney-sdk",
|
|
3943
|
-
policy ? "org agent config: loaded" : "org agent config: none set by this partner \u2014 user profiles will be left as they are",
|
|
3944
|
-
policy ?? void 0
|
|
3945
|
-
);
|
|
3946
|
-
return policy;
|
|
3947
|
-
} catch (error) {
|
|
3948
|
-
console.warn(
|
|
3949
|
-
"[owney-sdk] Could not read org agent config (non-fatal):",
|
|
3950
|
-
error instanceof Error ? error.message : String(error)
|
|
3951
|
-
);
|
|
3952
|
-
return null;
|
|
3953
|
-
}
|
|
3954
|
-
}
|
|
3955
|
-
async function fetchAgentKeys(apiKey, baseUrl = ROUTING_API_BASE_URL2) {
|
|
3956
|
-
const url = `${baseUrl}/api/v1/agent/keys`;
|
|
3957
|
-
const res = await fetch(url, {
|
|
3958
|
-
method: "GET",
|
|
3959
|
-
headers: {
|
|
3960
|
-
"Content-Type": "application/json",
|
|
3961
|
-
"x-owney-api-key": `${apiKey}`
|
|
3962
|
-
}
|
|
3963
|
-
});
|
|
3964
|
-
if (!res.ok) {
|
|
3965
|
-
const text = await res.text().catch(() => "");
|
|
3966
|
-
throw new OwneyError(
|
|
3967
|
-
"API_ROUTING_ERROR",
|
|
3968
|
-
`Routing API error ${res.status}: ${text}`,
|
|
3969
|
-
{ statusCode: res.status, responseBody: text }
|
|
3970
|
-
);
|
|
3971
|
-
}
|
|
3972
|
-
const json = await res.json();
|
|
3973
|
-
if (!json.success) {
|
|
3974
|
-
throw new OwneyError(
|
|
3975
|
-
"API_ROUTING_FAILED",
|
|
3976
|
-
`Routing API request failed: ${json.message}`,
|
|
3977
|
-
{ message: json.message }
|
|
3978
|
-
);
|
|
3979
|
-
}
|
|
3980
|
-
return json.data;
|
|
3981
|
-
}
|
|
3982
|
-
|
|
3983
|
-
// src/lib/health-report.ts
|
|
3984
|
-
var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
3985
|
-
async function reportAgentFailure(apiKey, agentType, errorCode, baseUrl = ROUTING_API_BASE_URL3) {
|
|
3986
|
-
try {
|
|
3987
|
-
await fetch(`${baseUrl}/api/v1/agent/health-report`, {
|
|
3988
|
-
method: "POST",
|
|
3989
|
-
headers: {
|
|
3990
|
-
"Content-Type": "application/json",
|
|
3991
|
-
"x-owney-api-key": apiKey
|
|
3992
|
-
},
|
|
3993
|
-
body: JSON.stringify({
|
|
3994
|
-
agent_type: agentType,
|
|
3995
|
-
error_code: errorCode,
|
|
3996
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
3997
|
-
})
|
|
3998
|
-
});
|
|
3999
|
-
} catch (err) {
|
|
4000
|
-
console.warn(
|
|
4001
|
-
`[owney-sdk] health-report failed for agent "${agentType}":`,
|
|
4002
|
-
err instanceof Error ? err.message : err
|
|
4003
|
-
);
|
|
4004
|
-
}
|
|
4005
|
-
}
|
|
4006
|
-
async function withFailureReporting(apiKey, agentType, fn, baseUrl) {
|
|
4007
|
-
try {
|
|
4008
|
-
return await fn();
|
|
4009
|
-
} catch (err) {
|
|
4010
|
-
const errorCode = err instanceof OwneyError ? err.code : "SDK_AGENT_FAILURE";
|
|
4011
|
-
void reportAgentFailure(apiKey, agentType, errorCode, baseUrl);
|
|
4012
|
-
throw err;
|
|
4013
|
-
}
|
|
4014
|
-
}
|
|
4015
|
-
|
|
4016
|
-
// src/lib/helpers/withdraw-helper.ts
|
|
4017
|
-
import { parseUnits } from "viem";
|
|
4018
|
-
function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
|
|
4019
|
-
const target = asset.toUpperCase();
|
|
4020
|
-
return agents.map((agent) => {
|
|
4021
|
-
const agentBalance = aggregated[agent.id];
|
|
4022
|
-
const tokenBalance = agentBalance?.tokens.find(
|
|
4023
|
-
(t) => t.chainId === chainId && t.asset.toUpperCase() === target
|
|
4024
|
-
);
|
|
4025
|
-
let balance = tokenBalance ? parseUnits(tokenBalance.amount, decimals) : 0n;
|
|
4026
|
-
if (agent.balanceComposition === "tokens-plus-positions") {
|
|
4027
|
-
const chainNameById = {
|
|
4028
|
-
1: "ETHEREUM",
|
|
4029
|
-
8453: "BASE",
|
|
4030
|
-
42161: "ARBITRUM"
|
|
4031
|
-
};
|
|
4032
|
-
const targetChain = chainNameById[chainId];
|
|
4033
|
-
for (const position2 of agentBalance?.positions ?? []) {
|
|
4034
|
-
const positionChain = position2.chain.trim().toUpperCase();
|
|
4035
|
-
const matchesChain = positionChain === String(chainId) || targetChain !== void 0 && positionChain === targetChain;
|
|
4036
|
-
if (!matchesChain || position2.asset.toUpperCase() !== target) continue;
|
|
4037
|
-
if (position2.amountRaw !== void 0) {
|
|
4038
|
-
try {
|
|
4039
|
-
balance += BigInt(position2.amountRaw);
|
|
4040
|
-
continue;
|
|
4041
|
-
} catch {
|
|
4042
|
-
}
|
|
4043
|
-
}
|
|
4044
|
-
balance += parseUnits(position2.amount, decimals);
|
|
4045
|
-
}
|
|
4046
|
-
}
|
|
4047
|
-
return { agent, balance };
|
|
2455
|
+
args: [owner, PERMIT2_ADDRESS]
|
|
4048
2456
|
});
|
|
4049
2457
|
}
|
|
4050
|
-
function
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
const assigned = plans.reduce((s, p) => s + p.planned, 0n);
|
|
4057
|
-
let remainder = requested - assigned;
|
|
4058
|
-
const byHeadroom = [...plans].sort((a, b) => {
|
|
4059
|
-
const diff = b.balance - b.planned - (a.balance - a.planned);
|
|
4060
|
-
return diff > 0n ? 1 : diff < 0n ? -1 : 0;
|
|
2458
|
+
async function readErc20Balance(publicClient, token, owner) {
|
|
2459
|
+
return publicClient.readContract({
|
|
2460
|
+
address: token,
|
|
2461
|
+
abi: ERC20_ALLOWANCE_ABI,
|
|
2462
|
+
functionName: "balanceOf",
|
|
2463
|
+
args: [owner]
|
|
4061
2464
|
});
|
|
4062
|
-
for (const p of byHeadroom) {
|
|
4063
|
-
if (remainder === 0n) break;
|
|
4064
|
-
const headroom = p.balance - p.planned;
|
|
4065
|
-
if (headroom <= 0n) continue;
|
|
4066
|
-
const take = headroom < remainder ? headroom : remainder;
|
|
4067
|
-
p.planned += take;
|
|
4068
|
-
remainder -= take;
|
|
4069
|
-
}
|
|
4070
|
-
return plans;
|
|
4071
2465
|
}
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
continue;
|
|
4082
|
-
}
|
|
4083
|
-
const take = balance < remaining ? balance : remaining;
|
|
4084
|
-
plans.push({ agent, balance, planned: take });
|
|
4085
|
-
remaining -= take;
|
|
4086
|
-
}
|
|
4087
|
-
return { plans, remaining };
|
|
2466
|
+
|
|
2467
|
+
// src/lib/chain-guard.ts
|
|
2468
|
+
var CHAIN_NAMES = {
|
|
2469
|
+
1: "Ethereum",
|
|
2470
|
+
8453: "Base",
|
|
2471
|
+
42161: "Arbitrum"
|
|
2472
|
+
};
|
|
2473
|
+
function chainName(chainId) {
|
|
2474
|
+
return CHAIN_NAMES[chainId] ?? `chain ${chainId}`;
|
|
4088
2475
|
}
|
|
4089
|
-
function
|
|
4090
|
-
const
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
(
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
2476
|
+
async function ensureWalletOnChain(pub, wallet, expected) {
|
|
2477
|
+
const actual = await pub.getChainId();
|
|
2478
|
+
if (actual === expected) return;
|
|
2479
|
+
try {
|
|
2480
|
+
await wallet.switchChain({ id: expected });
|
|
2481
|
+
} catch (error) {
|
|
2482
|
+
throw new OwneyError(
|
|
2483
|
+
"CHAIN_MISMATCH",
|
|
2484
|
+
`Your wallet is on ${chainName(actual)}. Switch it to ${chainName(expected)} and try again.`,
|
|
2485
|
+
{
|
|
2486
|
+
expectedChainId: expected,
|
|
2487
|
+
actualChainId: actual,
|
|
2488
|
+
cause: error instanceof Error ? error.message : String(error)
|
|
2489
|
+
}
|
|
2490
|
+
);
|
|
4104
2491
|
}
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
leftover -= take;
|
|
2492
|
+
const after = await pub.getChainId();
|
|
2493
|
+
if (after !== expected) {
|
|
2494
|
+
throw new OwneyError(
|
|
2495
|
+
"CHAIN_MISMATCH",
|
|
2496
|
+
`Your wallet is still on ${chainName(after)}. Switch it to ${chainName(expected)} and try again.`,
|
|
2497
|
+
{ expectedChainId: expected, actualChainId: after }
|
|
2498
|
+
);
|
|
4113
2499
|
}
|
|
4114
2500
|
}
|
|
4115
|
-
function sumWithdrawnAmount(results) {
|
|
4116
|
-
return Object.values(results).reduce((sum, r) => sum + BigInt(r.amount), 0n);
|
|
4117
|
-
}
|
|
4118
2501
|
|
|
4119
|
-
// src/lib/
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
return Number.isFinite(amount) && amount > 0 ? total + amount : total;
|
|
4132
|
-
}, 0);
|
|
4133
|
-
}
|
|
4134
|
-
function aggregateApyHistory(agentApys, agentBalances) {
|
|
4135
|
-
const byDate = /* @__PURE__ */ new Map();
|
|
4136
|
-
for (const [id, accountApy] of Object.entries(agentApys)) {
|
|
4137
|
-
const balance = agentBalances[id] ?? 0;
|
|
4138
|
-
if (!Number.isFinite(balance) || balance <= 0) continue;
|
|
4139
|
-
for (const point of accountApy.history ?? []) {
|
|
4140
|
-
const apy = Number(point.apy);
|
|
4141
|
-
if (!point.date || !Number.isFinite(apy)) continue;
|
|
4142
|
-
const current = byDate.get(point.date) ?? { weightedSum: 0, weight: 0 };
|
|
4143
|
-
current.weightedSum += apy * balance;
|
|
4144
|
-
current.weight += balance;
|
|
4145
|
-
byDate.set(point.date, current);
|
|
2502
|
+
// src/lib/sponsored-deposit.ts
|
|
2503
|
+
var AUTH_WINDOW_SECONDS = 15 * 60;
|
|
2504
|
+
function makeSponsoredDepositCallback(deps) {
|
|
2505
|
+
const post = deps.httpPost ?? postSponsorTransferAuth;
|
|
2506
|
+
return async (smartWallet, chainId, amount) => {
|
|
2507
|
+
const cid = chainId;
|
|
2508
|
+
const token = deps.tokenAddressByChain[cid];
|
|
2509
|
+
if (!token) {
|
|
2510
|
+
throw new OwneyError(
|
|
2511
|
+
"CHAIN_UNSUPPORTED",
|
|
2512
|
+
`No sponsored token configured for chain ${chainId}`
|
|
2513
|
+
);
|
|
4146
2514
|
}
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
const balance = agentBalances[id] ?? 0;
|
|
4159
|
-
if (!cells || balance <= 0) continue;
|
|
4160
|
-
for (const [chainKey, perAsset] of Object.entries(cells)) {
|
|
4161
|
-
if (!perAsset) continue;
|
|
4162
|
-
const chainId = Number(chainKey);
|
|
4163
|
-
for (const [asset, apyValue] of Object.entries(perAsset)) {
|
|
4164
|
-
const apy = Number(apyValue ?? 0);
|
|
4165
|
-
if (apy === 0) continue;
|
|
4166
|
-
sums[chainId] ??= {};
|
|
4167
|
-
weights[chainId] ??= {};
|
|
4168
|
-
sums[chainId][asset] = (sums[chainId][asset] ?? 0) + apy * balance;
|
|
4169
|
-
weights[chainId][asset] = (weights[chainId][asset] ?? 0) + balance;
|
|
2515
|
+
const pub = deps.getPublicClient(cid);
|
|
2516
|
+
const wallet = deps.getWalletClient(cid);
|
|
2517
|
+
await ensureWalletOnChain(pub, wallet, cid);
|
|
2518
|
+
try {
|
|
2519
|
+
const balance = await readErc20Balance(pub, token, deps.ownerAddress);
|
|
2520
|
+
if (balance < BigInt(amount)) {
|
|
2521
|
+
throw new OwneyError(
|
|
2522
|
+
"DEPOSIT_INSUFFICIENT_BALANCE",
|
|
2523
|
+
"Insufficient balance for this deposit.",
|
|
2524
|
+
{ token, chainId: cid, balance: balance.toString(), amount }
|
|
2525
|
+
);
|
|
4170
2526
|
}
|
|
2527
|
+
} catch (err) {
|
|
2528
|
+
if (err instanceof OwneyError) throw err;
|
|
2529
|
+
console.warn(
|
|
2530
|
+
"[owney-sdk] Deposit balance pre-check failed (non-fatal):",
|
|
2531
|
+
err instanceof Error ? err.message : String(err)
|
|
2532
|
+
);
|
|
4171
2533
|
}
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
2534
|
+
const { tokenName, tokenVersion } = await readTokenMeta(pub, token);
|
|
2535
|
+
const validAfter = 0n;
|
|
2536
|
+
const validBefore = BigInt(
|
|
2537
|
+
Math.floor(Date.now() / 1e3) + AUTH_WINDOW_SECONDS
|
|
2538
|
+
);
|
|
2539
|
+
const nonce = randomAuthNonce();
|
|
2540
|
+
const typedData = buildTransferWithAuthorizationTypedData({
|
|
2541
|
+
token,
|
|
2542
|
+
chainId: cid,
|
|
2543
|
+
tokenName,
|
|
2544
|
+
tokenVersion,
|
|
2545
|
+
message: {
|
|
2546
|
+
from: deps.ownerAddress,
|
|
2547
|
+
to: smartWallet,
|
|
2548
|
+
value: BigInt(amount),
|
|
2549
|
+
validAfter,
|
|
2550
|
+
validBefore,
|
|
2551
|
+
nonce
|
|
2552
|
+
}
|
|
2553
|
+
});
|
|
2554
|
+
const authSignature = await wallet.signTypedData({
|
|
2555
|
+
account: deps.ownerAddress,
|
|
2556
|
+
...typedData
|
|
2557
|
+
});
|
|
2558
|
+
deps.onApproved?.();
|
|
2559
|
+
const result = await post({
|
|
2560
|
+
baseUrl: deps.baseUrl,
|
|
2561
|
+
apiKey: deps.apiKey,
|
|
2562
|
+
body: {
|
|
2563
|
+
chainId: cid,
|
|
2564
|
+
token,
|
|
2565
|
+
from: deps.ownerAddress,
|
|
2566
|
+
to: smartWallet,
|
|
2567
|
+
value: amount,
|
|
2568
|
+
validAfter: validAfter.toString(),
|
|
2569
|
+
validBefore: validBefore.toString(),
|
|
2570
|
+
nonce,
|
|
2571
|
+
authSignature,
|
|
2572
|
+
tokenName,
|
|
2573
|
+
tokenVersion
|
|
2574
|
+
}
|
|
2575
|
+
});
|
|
2576
|
+
return result.txHash;
|
|
2577
|
+
};
|
|
4186
2578
|
}
|
|
4187
2579
|
|
|
4188
|
-
// src/client.ts
|
|
4189
|
-
import {
|
|
4190
|
-
createPublicClient as createPublicClient4,
|
|
4191
|
-
createWalletClient as createWalletClient3,
|
|
4192
|
-
custom as custom3
|
|
4193
|
-
} from "viem";
|
|
4194
|
-
import { base as base4, arbitrum as arbitrum2, mainnet as mainnet2 } from "viem/chains";
|
|
4195
|
-
|
|
4196
2580
|
// src/lib/sponsored-weth-deposit.ts
|
|
4197
2581
|
var PERMIT_WINDOW_SECONDS = 15 * 60;
|
|
4198
2582
|
function makeSponsoredWethCallback(deps) {
|
|
4199
2583
|
const get = deps.httpGet ?? getSponsorRelayerAddress;
|
|
4200
2584
|
const post = deps.httpPost ?? postSponsorPermit2Transfer;
|
|
4201
|
-
return
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
`No sponsored WETH configured for chain ${chainId}`
|
|
4209
|
-
);
|
|
4210
|
-
}
|
|
4211
|
-
const amountWei = BigInt(amount);
|
|
4212
|
-
const pub = deps.getPublicClient(cid);
|
|
4213
|
-
const wallet = deps.getWalletClient(cid);
|
|
4214
|
-
await ensureWalletOnChain(pub, wallet, cid);
|
|
4215
|
-
try {
|
|
4216
|
-
const balance = await readErc20Balance(pub, token, deps.ownerAddress);
|
|
4217
|
-
if (balance < amountWei) {
|
|
4218
|
-
throw new OwneyError(
|
|
4219
|
-
"DEPOSIT_INSUFFICIENT_BALANCE",
|
|
4220
|
-
"Insufficient WETH balance for this deposit.",
|
|
4221
|
-
{ token, chainId: cid, balance: balance.toString(), amount }
|
|
4222
|
-
);
|
|
4223
|
-
}
|
|
4224
|
-
} catch (err) {
|
|
4225
|
-
if (err instanceof OwneyError) throw err;
|
|
4226
|
-
console.warn(
|
|
4227
|
-
"[owney-sdk] WETH balance pre-check failed (non-fatal):",
|
|
4228
|
-
err instanceof Error ? err.message : String(err)
|
|
4229
|
-
);
|
|
4230
|
-
}
|
|
4231
|
-
const allowance = await readPermit2Allowance(
|
|
4232
|
-
pub,
|
|
4233
|
-
token,
|
|
4234
|
-
deps.ownerAddress
|
|
2585
|
+
return async (smartWallet, chainId, amount) => {
|
|
2586
|
+
const cid = chainId;
|
|
2587
|
+
const token = deps.tokenAddressByChain[cid];
|
|
2588
|
+
if (!token) {
|
|
2589
|
+
throw new OwneyError(
|
|
2590
|
+
"CHAIN_UNSUPPORTED",
|
|
2591
|
+
`No sponsored WETH configured for chain ${chainId}`
|
|
4235
2592
|
);
|
|
4236
|
-
|
|
2593
|
+
}
|
|
2594
|
+
const amountWei = BigInt(amount);
|
|
2595
|
+
const pub = deps.getPublicClient(cid);
|
|
2596
|
+
const wallet = deps.getWalletClient(cid);
|
|
2597
|
+
await ensureWalletOnChain(pub, wallet, cid);
|
|
2598
|
+
try {
|
|
2599
|
+
const balance = await readErc20Balance(pub, token, deps.ownerAddress);
|
|
2600
|
+
if (balance < amountWei) {
|
|
4237
2601
|
throw new OwneyError(
|
|
4238
|
-
"
|
|
4239
|
-
"WETH
|
|
4240
|
-
{ token, chainId: cid,
|
|
2602
|
+
"DEPOSIT_INSUFFICIENT_BALANCE",
|
|
2603
|
+
"Insufficient WETH balance for this deposit.",
|
|
2604
|
+
{ token, chainId: cid, balance: balance.toString(), amount }
|
|
4241
2605
|
);
|
|
4242
2606
|
}
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
const nonce = randomPermit2Nonce();
|
|
4249
|
-
const deadline = BigInt(
|
|
4250
|
-
Math.floor(Date.now() / 1e3) + PERMIT_WINDOW_SECONDS
|
|
2607
|
+
} catch (err) {
|
|
2608
|
+
if (err instanceof OwneyError) throw err;
|
|
2609
|
+
console.warn(
|
|
2610
|
+
"[owney-sdk] WETH balance pre-check failed (non-fatal):",
|
|
2611
|
+
err instanceof Error ? err.message : String(err)
|
|
4251
2612
|
);
|
|
4252
|
-
const typedData = buildPermitTransferFromTypedData({
|
|
4253
|
-
chainId: cid,
|
|
4254
|
-
message: {
|
|
4255
|
-
permitted: { token, amount: amountWei },
|
|
4256
|
-
spender: relayer,
|
|
4257
|
-
nonce,
|
|
4258
|
-
deadline
|
|
4259
|
-
}
|
|
4260
|
-
});
|
|
4261
|
-
const signature = await wallet.signTypedData({
|
|
4262
|
-
account: deps.ownerAddress,
|
|
4263
|
-
...typedData
|
|
4264
|
-
});
|
|
4265
|
-
deps.onApproved?.();
|
|
4266
|
-
const result = await post({
|
|
4267
|
-
baseUrl: deps.baseUrl,
|
|
4268
|
-
apiKey: deps.apiKey,
|
|
4269
|
-
...verification?.agentId === "yieldseeker" ? { yieldseekerSignature: verification.signature } : {},
|
|
4270
|
-
body: {
|
|
4271
|
-
chainId: cid,
|
|
4272
|
-
token,
|
|
4273
|
-
from: deps.ownerAddress,
|
|
4274
|
-
to: smartWallet,
|
|
4275
|
-
amount,
|
|
4276
|
-
nonce: nonce.toString(),
|
|
4277
|
-
deadline: deadline.toString(),
|
|
4278
|
-
signature,
|
|
4279
|
-
...verification?.agentId === "yieldseeker" ? {
|
|
4280
|
-
yieldseekerUserId: verification.userId,
|
|
4281
|
-
yieldseekerAgentId: verification.yieldseekerAgentId
|
|
4282
|
-
} : {}
|
|
4283
|
-
}
|
|
4284
|
-
});
|
|
4285
|
-
return result.txHash;
|
|
4286
2613
|
}
|
|
4287
|
-
|
|
2614
|
+
const allowance = await readPermit2Allowance(pub, token, deps.ownerAddress);
|
|
2615
|
+
if (allowance < amountWei) {
|
|
2616
|
+
throw new OwneyError(
|
|
2617
|
+
"PERMIT2_APPROVAL_REQUIRED",
|
|
2618
|
+
"WETH gasless deposits need a one-time Permit2 approval; call approvePermit2() first",
|
|
2619
|
+
{ token, chainId: cid, allowance: allowance.toString(), amount }
|
|
2620
|
+
);
|
|
2621
|
+
}
|
|
2622
|
+
const relayer = await get({
|
|
2623
|
+
baseUrl: deps.baseUrl,
|
|
2624
|
+
apiKey: deps.apiKey,
|
|
2625
|
+
chainId: cid
|
|
2626
|
+
});
|
|
2627
|
+
const nonce = randomPermit2Nonce();
|
|
2628
|
+
const deadline = BigInt(
|
|
2629
|
+
Math.floor(Date.now() / 1e3) + PERMIT_WINDOW_SECONDS
|
|
2630
|
+
);
|
|
2631
|
+
const typedData = buildPermitTransferFromTypedData({
|
|
2632
|
+
chainId: cid,
|
|
2633
|
+
message: {
|
|
2634
|
+
permitted: { token, amount: amountWei },
|
|
2635
|
+
spender: relayer,
|
|
2636
|
+
nonce,
|
|
2637
|
+
deadline
|
|
2638
|
+
}
|
|
2639
|
+
});
|
|
2640
|
+
const signature = await wallet.signTypedData({
|
|
2641
|
+
account: deps.ownerAddress,
|
|
2642
|
+
...typedData
|
|
2643
|
+
});
|
|
2644
|
+
deps.onApproved?.();
|
|
2645
|
+
const result = await post({
|
|
2646
|
+
baseUrl: deps.baseUrl,
|
|
2647
|
+
apiKey: deps.apiKey,
|
|
2648
|
+
body: {
|
|
2649
|
+
chainId: cid,
|
|
2650
|
+
token,
|
|
2651
|
+
from: deps.ownerAddress,
|
|
2652
|
+
to: smartWallet,
|
|
2653
|
+
amount,
|
|
2654
|
+
nonce: nonce.toString(),
|
|
2655
|
+
deadline: deadline.toString(),
|
|
2656
|
+
signature
|
|
2657
|
+
}
|
|
2658
|
+
});
|
|
2659
|
+
return result.txHash;
|
|
2660
|
+
};
|
|
4288
2661
|
}
|
|
4289
2662
|
|
|
4290
2663
|
// src/lib/sponsored-calls-deposit.ts
|
|
4291
|
-
import { encodeFunctionData
|
|
2664
|
+
import { encodeFunctionData, erc20Abi, toHex } from "viem";
|
|
4292
2665
|
var DEFAULT_POLL_INTERVAL_MS = 1500;
|
|
4293
2666
|
var DEFAULT_MAX_POLLS = 30;
|
|
4294
2667
|
async function paymasterSupported(provider, owner, chainId) {
|
|
@@ -4314,7 +2687,7 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
4314
2687
|
}
|
|
4315
2688
|
return new URL(configured, origin).toString();
|
|
4316
2689
|
};
|
|
4317
|
-
return
|
|
2690
|
+
return async (smartWallet, chainId, amount) => {
|
|
4318
2691
|
const cid = chainId;
|
|
4319
2692
|
const token = deps.tokenAddressByChain[cid];
|
|
4320
2693
|
if (!token) {
|
|
@@ -4330,37 +2703,11 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
4330
2703
|
{ chainId }
|
|
4331
2704
|
);
|
|
4332
2705
|
}
|
|
4333
|
-
const data =
|
|
4334
|
-
abi:
|
|
2706
|
+
const data = encodeFunctionData({
|
|
2707
|
+
abi: erc20Abi,
|
|
4335
2708
|
functionName: "transfer",
|
|
4336
2709
|
args: [smartWallet, BigInt(amount)]
|
|
4337
2710
|
});
|
|
4338
|
-
let paymasterUrl = absolutePaymasterUrl();
|
|
4339
|
-
if (verification?.agentId === "yieldseeker") {
|
|
4340
|
-
if (chainId !== 8453) {
|
|
4341
|
-
throw new OwneyError(
|
|
4342
|
-
"CHAIN_UNSUPPORTED",
|
|
4343
|
-
`Yieldseeker Base Account sponsorship is not available on chain ${chainId}.`
|
|
4344
|
-
);
|
|
4345
|
-
}
|
|
4346
|
-
const { intent } = await postPaymasterIntent({
|
|
4347
|
-
baseUrl: deps.routingApiBaseUrl,
|
|
4348
|
-
apiKey: deps.apiKey,
|
|
4349
|
-
yieldseekerSignature: verification.signature,
|
|
4350
|
-
body: {
|
|
4351
|
-
chainId,
|
|
4352
|
-
token,
|
|
4353
|
-
from: deps.ownerAddress,
|
|
4354
|
-
to: smartWallet,
|
|
4355
|
-
amount,
|
|
4356
|
-
yieldseekerUserId: verification.userId,
|
|
4357
|
-
yieldseekerAgentId: verification.yieldseekerAgentId
|
|
4358
|
-
}
|
|
4359
|
-
});
|
|
4360
|
-
const url = new URL(paymasterUrl);
|
|
4361
|
-
url.searchParams.set("owneyIntent", intent);
|
|
4362
|
-
paymasterUrl = url.toString();
|
|
4363
|
-
}
|
|
4364
2711
|
const sendResult = await deps.provider.request({
|
|
4365
2712
|
method: "wallet_sendCalls",
|
|
4366
2713
|
params: [
|
|
@@ -4371,7 +2718,7 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
4371
2718
|
atomicRequired: false,
|
|
4372
2719
|
calls: [{ to: token, value: "0x0", data }],
|
|
4373
2720
|
capabilities: {
|
|
4374
|
-
paymasterService: { url:
|
|
2721
|
+
paymasterService: { url: absolutePaymasterUrl() }
|
|
4375
2722
|
}
|
|
4376
2723
|
}
|
|
4377
2724
|
]
|
|
@@ -4401,7 +2748,7 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
4401
2748
|
`No receipt for calls ${callsId} after ${maxPolls} polls; the deposit may still settle.`,
|
|
4402
2749
|
{ chainId, callsId }
|
|
4403
2750
|
);
|
|
4404
|
-
}
|
|
2751
|
+
};
|
|
4405
2752
|
}
|
|
4406
2753
|
|
|
4407
2754
|
// src/client.ts
|
|
@@ -4431,7 +2778,7 @@ var SPONSORED_USDC_BY_CHAIN = {
|
|
|
4431
2778
|
1: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
|
|
4432
2779
|
};
|
|
4433
2780
|
var VIEM_CHAIN2 = {
|
|
4434
|
-
8453:
|
|
2781
|
+
8453: base2,
|
|
4435
2782
|
42161: arbitrum2,
|
|
4436
2783
|
1: mainnet2
|
|
4437
2784
|
};
|
|
@@ -4461,8 +2808,6 @@ var OwneySDK = class {
|
|
|
4461
2808
|
orgAgentConfig;
|
|
4462
2809
|
orgAgentConfigPromise = null;
|
|
4463
2810
|
zyfaiRpcUrls;
|
|
4464
|
-
yieldseekerApiBaseUrl;
|
|
4465
|
-
yieldseekerSiweOrigin;
|
|
4466
2811
|
routingApiBaseUrl;
|
|
4467
2812
|
referralSource;
|
|
4468
2813
|
cachedSponsoredCallback = null;
|
|
@@ -4485,8 +2830,6 @@ var OwneySDK = class {
|
|
|
4485
2830
|
this.apiKey = config.apiKey;
|
|
4486
2831
|
if (config.debug) setOwneyDebug(true);
|
|
4487
2832
|
this.zyfaiRpcUrls = config.zyfaiRpcUrls;
|
|
4488
|
-
this.yieldseekerApiBaseUrl = config.yieldseekerApiBaseUrl;
|
|
4489
|
-
this.yieldseekerSiweOrigin = config.yieldseekerSiweOrigin;
|
|
4490
2833
|
this.routingApiBaseUrl = config.routingApiBaseUrl;
|
|
4491
2834
|
this.paymasterServiceUrl = config.paymasterServiceUrl;
|
|
4492
2835
|
this.referralSource = config.referralSource;
|
|
@@ -4593,14 +2936,14 @@ var OwneySDK = class {
|
|
|
4593
2936
|
// Casts work around viem's chain-narrowed Client vs the generic
|
|
4594
2937
|
// PublicClient/WalletClient param types — structurally identical at
|
|
4595
2938
|
// runtime, but the two share a name TS treats as unrelated.
|
|
4596
|
-
getPublicClient: (cid) =>
|
|
2939
|
+
getPublicClient: (cid) => createPublicClient2({
|
|
4597
2940
|
chain: VIEM_CHAIN2[cid],
|
|
4598
|
-
transport:
|
|
2941
|
+
transport: custom(provider)
|
|
4599
2942
|
}),
|
|
4600
|
-
getWalletClient: (cid) =>
|
|
2943
|
+
getWalletClient: (cid) => createWalletClient({
|
|
4601
2944
|
account: owner,
|
|
4602
2945
|
chain: VIEM_CHAIN2[cid],
|
|
4603
|
-
transport:
|
|
2946
|
+
transport: custom(provider)
|
|
4604
2947
|
})
|
|
4605
2948
|
});
|
|
4606
2949
|
if (!onApproved) this.cachedSponsoredCallback = callback;
|
|
@@ -4617,8 +2960,6 @@ var OwneySDK = class {
|
|
|
4617
2960
|
if (!onApproved && cached) return cached;
|
|
4618
2961
|
const provider = this.requireConnectedProvider();
|
|
4619
2962
|
const callback = makeSponsoredCallsCallback({
|
|
4620
|
-
apiKey: this.apiKey,
|
|
4621
|
-
routingApiBaseUrl: this.routingApiBaseUrl,
|
|
4622
2963
|
provider,
|
|
4623
2964
|
ownerAddress: this.state.walletAddress,
|
|
4624
2965
|
paymasterServiceUrl: this.paymasterServiceUrl,
|
|
@@ -4648,14 +2989,14 @@ var OwneySDK = class {
|
|
|
4648
2989
|
// Casts work around viem's chain-narrowed Client vs the generic
|
|
4649
2990
|
// PublicClient/WalletClient param types — structurally identical at
|
|
4650
2991
|
// runtime, but the two share a name TS treats as unrelated.
|
|
4651
|
-
getPublicClient: (cid) =>
|
|
2992
|
+
getPublicClient: (cid) => createPublicClient2({
|
|
4652
2993
|
chain: VIEM_CHAIN2[cid],
|
|
4653
|
-
transport:
|
|
2994
|
+
transport: custom(provider)
|
|
4654
2995
|
}),
|
|
4655
|
-
getWalletClient: (cid) =>
|
|
2996
|
+
getWalletClient: (cid) => createWalletClient({
|
|
4656
2997
|
account: owner,
|
|
4657
2998
|
chain: VIEM_CHAIN2[cid],
|
|
4658
|
-
transport:
|
|
2999
|
+
transport: custom(provider)
|
|
4659
3000
|
})
|
|
4660
3001
|
});
|
|
4661
3002
|
if (!onApproved) this.cachedWethSponsoredCallback = callback;
|
|
@@ -4686,10 +3027,12 @@ var OwneySDK = class {
|
|
|
4686
3027
|
this.orgAgentConfigPromise = fetchOrgAgentConfig(
|
|
4687
3028
|
this.apiKey,
|
|
4688
3029
|
this.routingApiBaseUrl
|
|
4689
|
-
).then(
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
3030
|
+
).then(
|
|
3031
|
+
(config) => {
|
|
3032
|
+
this.orgAgentConfig = config;
|
|
3033
|
+
return config;
|
|
3034
|
+
}
|
|
3035
|
+
);
|
|
4693
3036
|
}
|
|
4694
3037
|
return this.orgAgentConfigPromise;
|
|
4695
3038
|
}
|
|
@@ -4729,14 +3072,7 @@ var OwneySDK = class {
|
|
|
4729
3072
|
this.routingApiBaseUrl
|
|
4730
3073
|
);
|
|
4731
3074
|
this.disabledAgents.clear();
|
|
4732
|
-
for (const {
|
|
4733
|
-
key: key2,
|
|
4734
|
-
agent_type,
|
|
4735
|
-
is_enabled,
|
|
4736
|
-
is_configured
|
|
4737
|
-
} of agentKeys) {
|
|
4738
|
-
const configured = is_configured ?? Boolean(key2);
|
|
4739
|
-
if (!configured) continue;
|
|
3075
|
+
for (const { key: key2, agent_type, is_enabled } of agentKeys) {
|
|
4740
3076
|
const agent = this.createAgent(agent_type, key2);
|
|
4741
3077
|
if (!agent) continue;
|
|
4742
3078
|
this.agents.set(agent_type, agent);
|
|
@@ -4760,15 +3096,8 @@ var OwneySDK = class {
|
|
|
4760
3096
|
}
|
|
4761
3097
|
createAgent(agentId, key2) {
|
|
4762
3098
|
if (agentId === "zyfai") {
|
|
4763
|
-
if (!key2) return null;
|
|
4764
3099
|
return new ZyfaiAgent(key2, this.zyfaiRpcUrls, this.referralSource);
|
|
4765
3100
|
}
|
|
4766
|
-
if (agentId === "yieldseeker") {
|
|
4767
|
-
return new YieldseekerAgent(this.apiKey, {
|
|
4768
|
-
auth: { origin: this.yieldseekerSiweOrigin },
|
|
4769
|
-
baseUrl: this.yieldseekerApiBaseUrl ?? getYieldseekerProxyBaseUrl(this.routingApiBaseUrl)
|
|
4770
|
-
});
|
|
4771
|
-
}
|
|
4772
3101
|
return null;
|
|
4773
3102
|
}
|
|
4774
3103
|
/**
|
|
@@ -4813,7 +3142,7 @@ var OwneySDK = class {
|
|
|
4813
3142
|
* If provided, ALL specified agents must support the chainId or the call
|
|
4814
3143
|
* throws before activating any agent.
|
|
4815
3144
|
*/
|
|
4816
|
-
async activateAgent(chainId, agentId
|
|
3145
|
+
async activateAgent(chainId, agentId) {
|
|
4817
3146
|
const state = this.requireState();
|
|
4818
3147
|
await this.ensureAgentsInitialized();
|
|
4819
3148
|
if (agentId !== void 0) {
|
|
@@ -4849,7 +3178,7 @@ var OwneySDK = class {
|
|
|
4849
3178
|
this.activeAgents.add(id);
|
|
4850
3179
|
}
|
|
4851
3180
|
state.chainId = chainId;
|
|
4852
|
-
await this.activateAgentsInTurn(agents, state, chainId
|
|
3181
|
+
await this.activateAgentsInTurn(agents, state, chainId);
|
|
4853
3182
|
return;
|
|
4854
3183
|
}
|
|
4855
3184
|
const compatible = [...this.agents.values()].filter(
|
|
@@ -4870,7 +3199,7 @@ var OwneySDK = class {
|
|
|
4870
3199
|
const enabledCompatible = compatible.filter(
|
|
4871
3200
|
(agent) => !this.isAgentDisabled(agent.id)
|
|
4872
3201
|
);
|
|
4873
|
-
await this.activateAgentsInTurn(enabledCompatible, state, chainId
|
|
3202
|
+
await this.activateAgentsInTurn(enabledCompatible, state, chainId);
|
|
4874
3203
|
}
|
|
4875
3204
|
/**
|
|
4876
3205
|
* Activate agents ONE AT A TIME, each followed by its org policy.
|
|
@@ -4886,25 +3215,17 @@ var OwneySDK = class {
|
|
|
4886
3215
|
* at a time anyway.
|
|
4887
3216
|
*
|
|
4888
3217
|
* Every agent is attempted even if an earlier one fails, so one declined
|
|
4889
|
-
* signature can't deny the remaining agents their turn.
|
|
4890
|
-
*
|
|
4891
|
-
*
|
|
3218
|
+
* signature can't deny the remaining agents their turn. The first failure is
|
|
3219
|
+
* rethrown (matching the previous `Promise.all` rejection) once all agents
|
|
3220
|
+
* have had a chance to activate.
|
|
4892
3221
|
*/
|
|
4893
|
-
async activateAgentsInTurn(agents, state, chainId
|
|
3222
|
+
async activateAgentsInTurn(agents, state, chainId) {
|
|
4894
3223
|
let firstError = null;
|
|
4895
|
-
const activatedAgentIds = [];
|
|
4896
|
-
const failedAgents = [];
|
|
4897
3224
|
for (const agent of agents) {
|
|
4898
3225
|
try {
|
|
4899
|
-
await agent.activateAgent(state, chainId
|
|
3226
|
+
await agent.activateAgent(state, chainId);
|
|
4900
3227
|
await this.applyOrgPolicyTo(agent, state, chainId);
|
|
4901
|
-
activatedAgentIds.push(agent.id);
|
|
4902
3228
|
} catch (error) {
|
|
4903
|
-
failedAgents.push({
|
|
4904
|
-
agentId: agent.id,
|
|
4905
|
-
code: error instanceof OwneyError ? error.code : void 0,
|
|
4906
|
-
message: error instanceof Error ? error.message : String(error)
|
|
4907
|
-
});
|
|
4908
3229
|
if (firstError === null) {
|
|
4909
3230
|
firstError = error;
|
|
4910
3231
|
} else {
|
|
@@ -4912,16 +3233,7 @@ var OwneySDK = class {
|
|
|
4912
3233
|
}
|
|
4913
3234
|
}
|
|
4914
3235
|
}
|
|
4915
|
-
if (firstError
|
|
4916
|
-
if (activatedAgentIds.length === 0) throw firstError;
|
|
4917
|
-
const failedAgentIds = failedAgents.map(({ agentId }) => agentId);
|
|
4918
|
-
const activeNames = activatedAgentIds.map(this.formatAgentName).join(", ");
|
|
4919
|
-
const remainingNames = failedAgentIds.map(this.formatAgentName).join(", ");
|
|
4920
|
-
throw new OwneyError(
|
|
4921
|
-
"AGENT_ACTIVATION_PARTIAL_FAILURE",
|
|
4922
|
-
`${activeNames} activated, but ${remainingNames} still needs activation. Try again and approve the remaining wallet request.`,
|
|
4923
|
-
{ activatedAgentIds, failedAgentIds, failures: failedAgents }
|
|
4924
|
-
);
|
|
3236
|
+
if (firstError !== null) throw firstError;
|
|
4925
3237
|
}
|
|
4926
3238
|
/**
|
|
4927
3239
|
* Deposit into a specific agent, or distribute across all eligible agents.
|
|
@@ -5135,10 +3447,10 @@ var OwneySDK = class {
|
|
|
5135
3447
|
agent,
|
|
5136
3448
|
amount: i === agents.length - 1 ? perAgent + remainder : perAgent
|
|
5137
3449
|
}));
|
|
5138
|
-
const
|
|
3450
|
+
const valid = splits.filter(
|
|
5139
3451
|
(s) => s.amount > 0n && (exempt.has(s.agent.id) || s.amount >= this.getMinDepositAmount(s.agent, chainId, asset))
|
|
5140
3452
|
);
|
|
5141
|
-
if (
|
|
3453
|
+
if (valid.length === agents.length) {
|
|
5142
3454
|
return splits.map((s) => ({ agent: s.agent, amount: String(s.amount) }));
|
|
5143
3455
|
}
|
|
5144
3456
|
const targets = agentsRequiringActivation.length > 0 ? agentsRequiringActivation : agents;
|
|
@@ -5157,11 +3469,6 @@ var OwneySDK = class {
|
|
|
5157
3469
|
)
|
|
5158
3470
|
}));
|
|
5159
3471
|
}
|
|
5160
|
-
formatAgentName(agentId) {
|
|
5161
|
-
if (agentId === "zyfai") return "Zyfai";
|
|
5162
|
-
if (agentId === "yieldseeker") return "Yieldseeker";
|
|
5163
|
-
return agentId;
|
|
5164
|
-
}
|
|
5165
3472
|
async validateMinDepositAmount(agent, state, chainId, asset, amount) {
|
|
5166
3473
|
const minDepositAmount = this.getMinDepositAmount(agent, chainId, asset);
|
|
5167
3474
|
const parsedAmount = BigInt(amount);
|
|
@@ -5193,12 +3500,12 @@ var OwneySDK = class {
|
|
|
5193
3500
|
(t) => t.chainId === chainId && t.asset.toLowerCase() === target
|
|
5194
3501
|
);
|
|
5195
3502
|
const targetChainName = agent.supportedAssets.find((entry) => entry.chainId === chainId)?.chain?.trim().toUpperCase();
|
|
5196
|
-
const
|
|
3503
|
+
const position = (balance.positions ?? []).find((p) => {
|
|
5197
3504
|
const positionChain = p.chain.trim().toUpperCase();
|
|
5198
3505
|
const matchesChain = positionChain === String(chainId) || targetChainName !== void 0 && positionChain === targetChainName;
|
|
5199
3506
|
return matchesChain && p.asset.toLowerCase() === target && Number(p.amount) > 0;
|
|
5200
3507
|
});
|
|
5201
|
-
return !!token && Number(token.amount) > 0 || !!
|
|
3508
|
+
return !!token && Number(token.amount) > 0 || !!position;
|
|
5202
3509
|
} catch (error) {
|
|
5203
3510
|
if (requireReliableRead) {
|
|
5204
3511
|
throw new OwneyError(
|
|
@@ -5313,10 +3620,6 @@ var OwneySDK = class {
|
|
|
5313
3620
|
}
|
|
5314
3621
|
const requested = BigInt(amount);
|
|
5315
3622
|
const aggregated = await this.getBalances();
|
|
5316
|
-
const unavailableAgents = eligibleAgents.filter(
|
|
5317
|
-
(agent) => !(agent.id in aggregated.agentBalances)
|
|
5318
|
-
);
|
|
5319
|
-
const unavailableAgentIds = unavailableAgents.map((agent) => agent.id);
|
|
5320
3623
|
const balances = projectAgentBalancesForAsset(
|
|
5321
3624
|
eligibleAgents,
|
|
5322
3625
|
aggregated.agentBalances,
|
|
@@ -5325,18 +3628,7 @@ var OwneySDK = class {
|
|
|
5325
3628
|
assetInfo.decimals
|
|
5326
3629
|
);
|
|
5327
3630
|
const totalAvailable = balances.reduce((sum, x) => sum + x.balance, 0n);
|
|
5328
|
-
if (totalAvailable
|
|
5329
|
-
throw new OwneyError(
|
|
5330
|
-
"WITHDRAW_BALANCE_UNAVAILABLE",
|
|
5331
|
-
`Cannot safely plan the withdrawal because balance data is unavailable for: ${unavailableAgentIds.join(", ")}.`,
|
|
5332
|
-
{
|
|
5333
|
-
asset,
|
|
5334
|
-
unavailableAgents: unavailableAgentIds,
|
|
5335
|
-
agentErrors: aggregated.agentErrors
|
|
5336
|
-
}
|
|
5337
|
-
);
|
|
5338
|
-
}
|
|
5339
|
-
if (totalAvailable < requested && unavailableAgents.length === 0) {
|
|
3631
|
+
if (totalAvailable < requested) {
|
|
5340
3632
|
throw new OwneyError(
|
|
5341
3633
|
"WITHDRAW_INSUFFICIENT_BALANCE",
|
|
5342
3634
|
`Requested withdrawal "${amount}" exceeds available balance "${totalAvailable.toString()}" for asset "${asset}".`,
|
|
@@ -5347,7 +3639,6 @@ var OwneySDK = class {
|
|
|
5347
3639
|
}
|
|
5348
3640
|
);
|
|
5349
3641
|
}
|
|
5350
|
-
const plannedTarget = totalAvailable < requested ? totalAvailable : requested;
|
|
5351
3642
|
const disabledBalances = balances.filter(
|
|
5352
3643
|
(b) => this.isAgentDisabled(b.agent.id)
|
|
5353
3644
|
);
|
|
@@ -5356,7 +3647,7 @@ var OwneySDK = class {
|
|
|
5356
3647
|
);
|
|
5357
3648
|
const { plans: disabledPlans, remaining: afterDrain } = planDisabledDrain(
|
|
5358
3649
|
disabledBalances,
|
|
5359
|
-
|
|
3650
|
+
requested
|
|
5360
3651
|
);
|
|
5361
3652
|
const enabledTotal = enabledBalances.reduce((s, b) => s + b.balance, 0n);
|
|
5362
3653
|
const enabledPlans = afterDrain > 0n ? planProportionalShares(enabledBalances, afterDrain, enabledTotal) : enabledBalances.map(({ agent, balance }) => ({
|
|
@@ -5366,9 +3657,7 @@ var OwneySDK = class {
|
|
|
5366
3657
|
}));
|
|
5367
3658
|
const plans = [...disabledPlans, ...enabledPlans];
|
|
5368
3659
|
const results = {};
|
|
5369
|
-
const agentErrors = {
|
|
5370
|
-
...aggregated.agentErrors ?? {}
|
|
5371
|
-
};
|
|
3660
|
+
const agentErrors = {};
|
|
5372
3661
|
for (let i = 0; i < plans.length; i++) {
|
|
5373
3662
|
const p = plans[i];
|
|
5374
3663
|
if (p.planned === 0n) continue;
|
|
@@ -5415,8 +3704,7 @@ var OwneySDK = class {
|
|
|
5415
3704
|
requested: amount,
|
|
5416
3705
|
withdrawn: withdrawn.toString(),
|
|
5417
3706
|
partialResults: results,
|
|
5418
|
-
agentErrors
|
|
5419
|
-
...unavailableAgentIds.length > 0 ? { unavailableAgents: unavailableAgentIds } : {}
|
|
3707
|
+
agentErrors
|
|
5420
3708
|
}
|
|
5421
3709
|
);
|
|
5422
3710
|
}
|
|
@@ -5434,10 +3722,7 @@ var OwneySDK = class {
|
|
|
5434
3722
|
if (agentId) {
|
|
5435
3723
|
const agent = this.getAgent(agentId);
|
|
5436
3724
|
const result = await this.readAgent(agent, "balances", () => agent.getBalances(state, chainId));
|
|
5437
|
-
return
|
|
5438
|
-
...result,
|
|
5439
|
-
balanceComposition: agent.balanceComposition ?? "tokens-include-positions"
|
|
5440
|
-
};
|
|
3725
|
+
return result;
|
|
5441
3726
|
}
|
|
5442
3727
|
let totalBalance = 0;
|
|
5443
3728
|
const results = {};
|
|
@@ -5445,13 +3730,7 @@ var OwneySDK = class {
|
|
|
5445
3730
|
const balanceResults = await Promise.allSettled(
|
|
5446
3731
|
entries.map(async ([id, agent]) => {
|
|
5447
3732
|
const b = await this.readAgent(agent, "balances", () => agent.getBalances(state, chainId));
|
|
5448
|
-
return [
|
|
5449
|
-
id,
|
|
5450
|
-
{
|
|
5451
|
-
...b,
|
|
5452
|
-
balanceComposition: agent.balanceComposition ?? "tokens-include-positions"
|
|
5453
|
-
}
|
|
5454
|
-
];
|
|
3733
|
+
return [id, b];
|
|
5455
3734
|
})
|
|
5456
3735
|
);
|
|
5457
3736
|
let successCount = 0;
|
|
@@ -5473,7 +3752,6 @@ var OwneySDK = class {
|
|
|
5473
3752
|
const retryDelay = rateLimitDelay(reason);
|
|
5474
3753
|
if (retryDelay !== void 0) agentRetryAt[agentId2] = Date.now() + retryDelay;
|
|
5475
3754
|
agentErrors[agentId2] = reason instanceof Error ? reason.message : String(reason);
|
|
5476
|
-
console.error(`[owney-sdk] Balance fetch failed for agent "${agentId2}":`, reason);
|
|
5477
3755
|
}
|
|
5478
3756
|
if (successCount === 0) {
|
|
5479
3757
|
throw new OwneyError(
|
|
@@ -5586,10 +3864,7 @@ var OwneySDK = class {
|
|
|
5586
3864
|
Promise.all(
|
|
5587
3865
|
entries.map(async ([id, agent]) => {
|
|
5588
3866
|
const b = await this.readAgent(agent, "balances", () => agent.getBalances(state, chainId));
|
|
5589
|
-
return [
|
|
5590
|
-
id,
|
|
5591
|
-
balanceForApyScope(b, chainId, tokenSymbol)
|
|
5592
|
-
];
|
|
3867
|
+
return [id, Number(b.totalBalance)];
|
|
5593
3868
|
})
|
|
5594
3869
|
)
|
|
5595
3870
|
]);
|
|
@@ -5617,12 +3892,10 @@ var OwneySDK = class {
|
|
|
5617
3892
|
}
|
|
5618
3893
|
}
|
|
5619
3894
|
const apyByChainAndAsset = aggregateApyByChainAndAsset(results, balances);
|
|
5620
|
-
const history = aggregateApyHistory(results, balances);
|
|
5621
3895
|
return {
|
|
5622
3896
|
totalApy: String(totalApy),
|
|
5623
3897
|
agentApy: results,
|
|
5624
|
-
apyByChainAndAsset
|
|
5625
|
-
history
|
|
3898
|
+
apyByChainAndAsset
|
|
5626
3899
|
};
|
|
5627
3900
|
}
|
|
5628
3901
|
/**
|
|
@@ -5770,10 +4043,10 @@ var OwneySDK = class {
|
|
|
5770
4043
|
);
|
|
5771
4044
|
}
|
|
5772
4045
|
const provider = this.requireConnectedProvider();
|
|
5773
|
-
const wallet =
|
|
4046
|
+
const wallet = createWalletClient({
|
|
5774
4047
|
account: state.walletAddress,
|
|
5775
4048
|
chain: VIEM_CHAIN2[chainId],
|
|
5776
|
-
transport:
|
|
4049
|
+
transport: custom(provider)
|
|
5777
4050
|
});
|
|
5778
4051
|
const hash = await wallet.writeContract({
|
|
5779
4052
|
address: token,
|
|
@@ -5783,9 +4056,9 @@ var OwneySDK = class {
|
|
|
5783
4056
|
account: state.walletAddress,
|
|
5784
4057
|
chain: VIEM_CHAIN2[chainId]
|
|
5785
4058
|
});
|
|
5786
|
-
const publicClient =
|
|
4059
|
+
const publicClient = createPublicClient2({
|
|
5787
4060
|
chain: VIEM_CHAIN2[chainId],
|
|
5788
|
-
transport:
|
|
4061
|
+
transport: custom(provider)
|
|
5789
4062
|
});
|
|
5790
4063
|
const receipt = await publicClient.waitForTransactionReceipt({
|
|
5791
4064
|
hash,
|
|
@@ -5822,9 +4095,7 @@ var OwneySDK = class {
|
|
|
5822
4095
|
return this.readAgent(agent, "agentApy", () => agent.getAgentApy(days, agentOptions), { days, ...agentOptions });
|
|
5823
4096
|
}
|
|
5824
4097
|
const results = {};
|
|
5825
|
-
const agentEntries = [...this.agents.entries()]
|
|
5826
|
-
([id]) => !this.isAgentDisabled(id)
|
|
5827
|
-
);
|
|
4098
|
+
const agentEntries = [...this.agents.entries()];
|
|
5828
4099
|
const apyResults = await Promise.all(
|
|
5829
4100
|
agentEntries.map(async ([id, agent]) => {
|
|
5830
4101
|
const apy = await this.readAgent(agent, "agentApy", () => agent.getAgentApy(days, agentOptions), { days, ...agentOptions });
|
|
@@ -5899,13 +4170,13 @@ var OwneySDK = class {
|
|
|
5899
4170
|
};
|
|
5900
4171
|
|
|
5901
4172
|
// src/agents/zyfai/zyfai.siwx.ts
|
|
5902
|
-
import { getAddress
|
|
5903
|
-
import { SiweMessage
|
|
4173
|
+
import { getAddress } from "viem";
|
|
4174
|
+
import { SiweMessage } from "siwe";
|
|
5904
4175
|
import { ZyfaiSDK as ZyfaiSDK2 } from "@zyfai/sdk";
|
|
5905
4176
|
|
|
5906
4177
|
// src/agents/zyfai/zyfai.siwx-cache.ts
|
|
5907
|
-
var
|
|
5908
|
-
var
|
|
4178
|
+
var KEY_PREFIX2 = "owney.siwx.session";
|
|
4179
|
+
var storage2 = () => {
|
|
5909
4180
|
if (typeof window === "undefined") return null;
|
|
5910
4181
|
try {
|
|
5911
4182
|
return window.localStorage;
|
|
@@ -5913,8 +4184,8 @@ var storage4 = () => {
|
|
|
5913
4184
|
return null;
|
|
5914
4185
|
}
|
|
5915
4186
|
};
|
|
5916
|
-
var
|
|
5917
|
-
var legacyKeyPrefix2 = (address) => `${
|
|
4187
|
+
var buildKey2 = (address) => `${KEY_PREFIX2}:${address.toLowerCase()}`;
|
|
4188
|
+
var legacyKeyPrefix2 = (address) => `${KEY_PREFIX2}:${address.toLowerCase()}:`;
|
|
5918
4189
|
var memorySiwxSessions = /* @__PURE__ */ new Map();
|
|
5919
4190
|
var readLegacySiwxSession = (store, address) => {
|
|
5920
4191
|
if (!store) return null;
|
|
@@ -5945,17 +4216,17 @@ var readLegacySiwxSession = (store, address) => {
|
|
|
5945
4216
|
};
|
|
5946
4217
|
var readSiwxSession = (address, chainId) => {
|
|
5947
4218
|
if (typeof window === "undefined") return null;
|
|
5948
|
-
const key2 =
|
|
5949
|
-
const store =
|
|
5950
|
-
let
|
|
4219
|
+
const key2 = buildKey2(address);
|
|
4220
|
+
const store = storage2();
|
|
4221
|
+
let raw = null;
|
|
5951
4222
|
try {
|
|
5952
|
-
|
|
4223
|
+
raw = store?.getItem(key2) ?? null;
|
|
5953
4224
|
} catch {
|
|
5954
|
-
|
|
4225
|
+
raw = null;
|
|
5955
4226
|
}
|
|
5956
|
-
if (
|
|
4227
|
+
if (raw) {
|
|
5957
4228
|
try {
|
|
5958
|
-
return JSON.parse(
|
|
4229
|
+
return JSON.parse(raw);
|
|
5959
4230
|
} catch {
|
|
5960
4231
|
memorySiwxSessions.delete(key2);
|
|
5961
4232
|
try {
|
|
@@ -5974,18 +4245,18 @@ var readSiwxSession = (address, chainId) => {
|
|
|
5974
4245
|
};
|
|
5975
4246
|
var writeSiwxSession = (address, _chainId, session) => {
|
|
5976
4247
|
if (typeof window === "undefined") return;
|
|
5977
|
-
const key2 =
|
|
4248
|
+
const key2 = buildKey2(address);
|
|
5978
4249
|
memorySiwxSessions.set(key2, session);
|
|
5979
|
-
const store =
|
|
4250
|
+
const store = storage2();
|
|
5980
4251
|
try {
|
|
5981
4252
|
store?.setItem(key2, JSON.stringify(session));
|
|
5982
4253
|
} catch {
|
|
5983
4254
|
}
|
|
5984
4255
|
};
|
|
5985
4256
|
var clearSiwxSession = (address, _chainId) => {
|
|
5986
|
-
const key2 =
|
|
4257
|
+
const key2 = buildKey2(address);
|
|
5987
4258
|
memorySiwxSessions.delete(key2);
|
|
5988
|
-
const store =
|
|
4259
|
+
const store = storage2();
|
|
5989
4260
|
try {
|
|
5990
4261
|
store?.removeItem(key2);
|
|
5991
4262
|
} catch {
|
|
@@ -6025,8 +4296,8 @@ function buildSIWXConfig(deps) {
|
|
|
6025
4296
|
statement: STATEMENT,
|
|
6026
4297
|
issuedAt,
|
|
6027
4298
|
toString() {
|
|
6028
|
-
return new
|
|
6029
|
-
address:
|
|
4299
|
+
return new SiweMessage({
|
|
4300
|
+
address: getAddress(accountAddress),
|
|
6030
4301
|
chainId: numericChainId(chainId),
|
|
6031
4302
|
domain,
|
|
6032
4303
|
uri,
|
|
@@ -6068,7 +4339,7 @@ function buildSIWXConfig(deps) {
|
|
|
6068
4339
|
const persistSession = async (session) => {
|
|
6069
4340
|
const address = session.data.accountAddress;
|
|
6070
4341
|
const id = numericChainId(session.data.chainId);
|
|
6071
|
-
const message = new
|
|
4342
|
+
const message = new SiweMessage(session.message);
|
|
6072
4343
|
const login = await post("/auth/login", {
|
|
6073
4344
|
message,
|
|
6074
4345
|
signature: session.signature,
|
|
@@ -6077,7 +4348,8 @@ function buildSIWXConfig(deps) {
|
|
|
6077
4348
|
writeSession(address, id, {
|
|
6078
4349
|
token: login.accessToken,
|
|
6079
4350
|
userId: login.userId ?? null,
|
|
6080
|
-
hasActiveSessionKey: Boolean(login.hasActiveSessionKey)
|
|
4351
|
+
hasActiveSessionKey: Boolean(login.hasActiveSessionKey),
|
|
4352
|
+
isPredeployed: login.predeployed
|
|
6081
4353
|
});
|
|
6082
4354
|
const stored = {
|
|
6083
4355
|
data: session.data,
|
|
@@ -6116,7 +4388,6 @@ export {
|
|
|
6116
4388
|
NotConnectedError,
|
|
6117
4389
|
OwneyError,
|
|
6118
4390
|
OwneySDK,
|
|
6119
|
-
YieldseekerAgent,
|
|
6120
4391
|
createOwneySIWX,
|
|
6121
4392
|
setOwneyDebug
|
|
6122
4393
|
};
|