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