@owney/sdk 0.7.25-beta.18 → 0.7.25-beta.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +983 -410
- package/dist/index.d.cts +33 -20
- package/dist/index.d.ts +33 -20
- package/dist/index.js +892 -317
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -50,6 +50,29 @@ var accountExecutionAbi = (0, import_viem.parseAbi)([
|
|
|
50
50
|
]);
|
|
51
51
|
var entryPoint06 = "0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789";
|
|
52
52
|
var entryPoint07 = "0x0000000071727de22e5e9d8baf0edac6f37da032";
|
|
53
|
+
function yieldseekerExecution(receipt, evidence) {
|
|
54
|
+
const operationEvents = receipt.logs.flatMap((log) => {
|
|
55
|
+
if (![entryPoint06, entryPoint07].includes(log.address.toLowerCase())) return [];
|
|
56
|
+
try {
|
|
57
|
+
const event = (0, import_viem.decodeEventLog)({ abi: import_account_abstraction.entryPoint06Abi, data: log.data, topics: log.topics });
|
|
58
|
+
return event.eventName === "UserOperationEvent" ? [{ ...event.args, logIndex: log.logIndex }] : [];
|
|
59
|
+
} catch {
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
}).sort((a, b) => a.logIndex - b.logIndex);
|
|
63
|
+
const bundled = !!evidence.userOpHash || !!evidence.callsId || operationEvents.length > 0 || [entryPoint06, entryPoint07].includes(receipt.to?.toLowerCase() ?? "");
|
|
64
|
+
if (!bundled) return { status: "confirmed", logs: receipt.logs };
|
|
65
|
+
const senders = evidence.userOperation?.sender ? [evidence.userOperation.sender.toLowerCase()] : evidence.callsId ? [evidence.walletAddress.toLowerCase()] : [evidence.walletAddress.toLowerCase(), evidence.agentWallet?.toLowerCase()];
|
|
66
|
+
const matches = operationEvents.filter((event) => senders.includes(event.sender.toLowerCase()) && (!evidence.userOpHash || event.userOpHash.toLowerCase() === evidence.userOpHash.toLowerCase()));
|
|
67
|
+
if (matches.length !== 1) return { status: "unknown", logs: [] };
|
|
68
|
+
const operation = matches[0];
|
|
69
|
+
if (!operation.success) return { status: "failed", logs: [] };
|
|
70
|
+
const previous = operationEvents.filter((event) => event.logIndex < operation.logIndex).at(-1)?.logIndex ?? -1;
|
|
71
|
+
return {
|
|
72
|
+
status: "confirmed",
|
|
73
|
+
logs: receipt.logs.filter((log) => log.logIndex > previous && log.logIndex < operation.logIndex)
|
|
74
|
+
};
|
|
75
|
+
}
|
|
53
76
|
function isFullYieldseekerWithdrawal(transaction, evidence, tokenAddress, receipt) {
|
|
54
77
|
if (evidence.agentId !== "yieldseeker" || transaction.chainId !== evidence.chainId || transaction.hash.toLowerCase() !== evidence.txHash?.toLowerCase() || !evidence.agentWallet) return false;
|
|
55
78
|
const matchesFullCall = (data) => {
|
|
@@ -95,8 +118,27 @@ function isFullYieldseekerWithdrawal(transaction, evidence, tokenAddress, receip
|
|
|
95
118
|
return false;
|
|
96
119
|
}
|
|
97
120
|
}
|
|
98
|
-
function inspectFundingReceipt(receipt, evidence, tokenAddress, direction) {
|
|
121
|
+
function inspectFundingReceipt(receipt, evidence, tokenAddress, direction, options = {}) {
|
|
122
|
+
evidence = {
|
|
123
|
+
...evidence,
|
|
124
|
+
confirmedAmount: void 0,
|
|
125
|
+
amountCompletion: void 0,
|
|
126
|
+
shortfallAmount: void 0,
|
|
127
|
+
blockNumber: void 0,
|
|
128
|
+
logIndexes: void 0,
|
|
129
|
+
transferLogs: void 0
|
|
130
|
+
};
|
|
131
|
+
if (evidence.txHash && receipt.transactionHash && evidence.txHash.toLowerCase() !== receipt.transactionHash.toLowerCase())
|
|
132
|
+
return { ...evidence, transfer: "unknown", delivery: direction === "withdraw" ? "unknown" : "not-applicable" };
|
|
99
133
|
if (receipt.status !== "success") return { ...evidence, transfer: "failed", delivery: "failed" };
|
|
134
|
+
const execution = direction === "withdraw" && evidence.agentId === "yieldseeker" ? yieldseekerExecution(receipt, evidence) : { status: "confirmed", logs: receipt.logs };
|
|
135
|
+
if (execution.status !== "confirmed") return {
|
|
136
|
+
...evidence,
|
|
137
|
+
blockNumber: receipt.blockNumber.toString(),
|
|
138
|
+
...execution.status === "failed" ? { confirmedAmount: "0" } : {},
|
|
139
|
+
transfer: execution.status,
|
|
140
|
+
delivery: execution.status
|
|
141
|
+
};
|
|
100
142
|
let amount = 0n;
|
|
101
143
|
const seen = /* @__PURE__ */ new Set();
|
|
102
144
|
const attributed = /* @__PURE__ */ new Map();
|
|
@@ -107,7 +149,7 @@ function inspectFundingReceipt(receipt, evidence, tokenAddress, direction) {
|
|
|
107
149
|
const logIndexes = [];
|
|
108
150
|
const transferLogs = [];
|
|
109
151
|
const zeroTransferLogs = [];
|
|
110
|
-
for (const log of [...
|
|
152
|
+
for (const log of [...execution.logs].sort((a, b) => a.logIndex - b.logIndex)) {
|
|
111
153
|
if (log.address.toLowerCase() !== tokenAddress.toLowerCase()) continue;
|
|
112
154
|
if (seen.has(log.logIndex)) continue;
|
|
113
155
|
seen.add(log.logIndex);
|
|
@@ -133,7 +175,7 @@ function inspectFundingReceipt(receipt, evidence, tokenAddress, direction) {
|
|
|
133
175
|
}
|
|
134
176
|
}
|
|
135
177
|
const expected = /^\d+$/.test(evidence.intendedAmount) ? BigInt(evidence.intendedAmount) : void 0;
|
|
136
|
-
const emptyPayout = direction === "withdraw" && evidence.agentId === "yieldseeker" && amount === 0n && zeroTransferLogs.length > 0 &&
|
|
178
|
+
const emptyPayout = direction === "withdraw" && evidence.agentId === "yieldseeker" && amount === 0n && zeroTransferLogs.length > 0 && execution.logs.some((log) => {
|
|
137
179
|
if (log.address.toLowerCase() !== agent) return false;
|
|
138
180
|
try {
|
|
139
181
|
const { args } = (0, import_viem.decodeEventLog)({ abi: withdrawalEventAbi, data: log.data, topics: log.topics });
|
|
@@ -151,18 +193,30 @@ function inspectFundingReceipt(receipt, evidence, tokenAddress, direction) {
|
|
|
151
193
|
transfer: "failed",
|
|
152
194
|
delivery: "failed"
|
|
153
195
|
};
|
|
154
|
-
const
|
|
196
|
+
const exactReceipt = !!evidence.txHash && /^0x[\da-f]{64}$/i.test(evidence.txHash) && receipt.transactionHash?.toLowerCase() === evidence.txHash.toLowerCase();
|
|
197
|
+
const delivered = amount > 0n && (options.requireAmountMatch ? expected === void 0 || amount === expected : direction === "withdraw" && exactReceipt || expected === void 0 || amount >= expected);
|
|
155
198
|
return {
|
|
156
199
|
...evidence,
|
|
157
200
|
blockNumber: receipt.blockNumber.toString(),
|
|
158
201
|
logIndexes,
|
|
159
202
|
transferLogs,
|
|
160
203
|
...amount > 0n ? { confirmedAmount: amount.toString() } : {},
|
|
204
|
+
...delivered && direction === "withdraw" && expected !== void 0 ? {
|
|
205
|
+
amountCompletion: amount < expected ? "shortfall" : "complete",
|
|
206
|
+
shortfallAmount: (amount < expected ? expected - amount : 0n).toString()
|
|
207
|
+
} : {},
|
|
161
208
|
transfer: delivered ? "confirmed" : "unknown",
|
|
162
209
|
delivery: direction === "withdraw" ? delivered ? "confirmed" : "unknown" : "not-applicable"
|
|
163
210
|
};
|
|
164
211
|
}
|
|
165
212
|
|
|
213
|
+
// src/lib/helpers/funding-amount.ts
|
|
214
|
+
function isFundingAmount(value, allowZero = false) {
|
|
215
|
+
if (typeof value !== "string" || !/^\d{1,78}$/.test(value)) return false;
|
|
216
|
+
const amount = BigInt(value);
|
|
217
|
+
return (allowZero ? amount >= 0n : amount > 0n) && amount <= (1n << 256n) - 1n;
|
|
218
|
+
}
|
|
219
|
+
|
|
166
220
|
// src/lib/deposit-batch-callback.ts
|
|
167
221
|
var batchCallbacks = /* @__PURE__ */ new WeakMap();
|
|
168
222
|
var getDepositBatchTransfer = (callback) => callback ? batchCallbacks.get(callback) : void 0;
|
|
@@ -379,7 +433,7 @@ var AgentReads = class {
|
|
|
379
433
|
|
|
380
434
|
// src/agents/zyfai/zyfai.withdraw-submission.ts
|
|
381
435
|
var listenersByClient = /* @__PURE__ */ new WeakMap();
|
|
382
|
-
function observeWithdrawalSubmission(sdk, chainId, token) {
|
|
436
|
+
function observeWithdrawalSubmission(sdk, chainId, token, assertCurrent) {
|
|
383
437
|
const client = sdk.httpClient;
|
|
384
438
|
if (!client || typeof client.get !== "function" || typeof client.post !== "function")
|
|
385
439
|
return { attempted: () => void 0, rejected: () => false, request: () => void 0, stop: () => {
|
|
@@ -396,6 +450,7 @@ function observeWithdrawalSubmission(sdk, chainId, token) {
|
|
|
396
450
|
const withdrawal = method === "get" && url === "/users/withdraw" || method === "post" && url === "/users/partial-withdraw";
|
|
397
451
|
const payload = method === "get" ? options?.params : options;
|
|
398
452
|
const matching = withdrawal ? [...observers].filter((observer) => observer.chainId === payload?.chainId && observer.token === payload?.tokenSymbol) : [];
|
|
453
|
+
for (const observer of matching) observer.assertCurrent?.();
|
|
399
454
|
const startedAt = Date.now();
|
|
400
455
|
const request2 = {
|
|
401
456
|
attempted: true,
|
|
@@ -440,7 +495,7 @@ function observeWithdrawalSubmission(sdk, chainId, token) {
|
|
|
440
495
|
const status = error?.response?.status;
|
|
441
496
|
if (request2.httpStatus === void 0 && typeof status === "number" && Number.isInteger(status) && status >= 100 && status <= 599)
|
|
442
497
|
request2.httpStatus = status;
|
|
443
|
-
request2.failure = message === "Unauthorized: Invalid API key" ? "unauthorized" : message === "Forbidden: Access denied" ? "forbidden" : message === "Rate limit exceeded. Please try again later." ? "rate-limited" : /^Idle balance \d+(?:\.\d+)? (USDC|WETH|ETH|EURC) is below the minimum withdrawal of \d+(?:\.\d+)? \1\.?$/.test(message) ? "insufficient-balance" : /^User doesn't have any active session key\.?$/.test(message) ? "session-key-missing" : method === "post" && request2.httpStatus === 400 && message === "Partial withdrawal already in progress" ? "withdrawal-in-progress" : message === "Network error: Unable to reach the server" ? "network" : "other";
|
|
498
|
+
request2.failure = message === "Unauthorized: Invalid API key" ? "unauthorized" : message === "Forbidden: Access denied" ? "forbidden" : message === "Rate limit exceeded. Please try again later." ? "rate-limited" : request2.httpStatus === 400 && message === "No balance to withdraw" ? "insufficient-balance" : /^Idle balance \d+(?:\.\d+)? (USDC|WETH|ETH|EURC) is below the minimum withdrawal of \d+(?:\.\d+)? \1\.?$/.test(message) ? "insufficient-balance" : /^User doesn't have any active session key\.?$/.test(message) ? "session-key-missing" : method === "post" && request2.httpStatus === 400 && message === "Partial withdrawal already in progress" ? "withdrawal-in-progress" : message === "Network error: Unable to reach the server" ? "network" : "other";
|
|
444
499
|
if (["unauthorized", "forbidden", "rate-limited", "insufficient-balance", "session-key-missing", "withdrawal-in-progress"].includes(request2.failure) && (request2.httpStatus === void 0 || request2.httpStatus >= 400 && request2.httpStatus < 500)) notify("rejected");
|
|
445
500
|
throw error;
|
|
446
501
|
} finally {
|
|
@@ -453,7 +508,7 @@ function observeWithdrawalSubmission(sdk, chainId, token) {
|
|
|
453
508
|
let submitted = false;
|
|
454
509
|
let rejected = false;
|
|
455
510
|
let request = { attempted: false };
|
|
456
|
-
const listener = { chainId, token, notify: (outcome, evidence) => {
|
|
511
|
+
const listener = { chainId, token, assertCurrent, notify: (outcome, evidence) => {
|
|
457
512
|
request = evidence;
|
|
458
513
|
if (outcome === "attempted") submitted = true;
|
|
459
514
|
else if (outcome === "rejected") rejected = true;
|
|
@@ -504,10 +559,8 @@ function hasEmptyWithdrawalSnapshot(raw2, chainId, token) {
|
|
|
504
559
|
return true;
|
|
505
560
|
}
|
|
506
561
|
|
|
507
|
-
// src/agents/zyfai/zyfai.
|
|
508
|
-
var
|
|
509
|
-
var import_viem4 = require("viem");
|
|
510
|
-
var import_chains = require("viem/chains");
|
|
562
|
+
// src/agents/zyfai/zyfai.deposit.ts
|
|
563
|
+
var import_viem2 = require("viem");
|
|
511
564
|
|
|
512
565
|
// src/types/config.ts
|
|
513
566
|
var P_SUPPORTED_CHAINS = {
|
|
@@ -556,6 +609,43 @@ var SupportedAssets = [
|
|
|
556
609
|
}
|
|
557
610
|
];
|
|
558
611
|
|
|
612
|
+
// src/agents/zyfai/zyfai.deposit.ts
|
|
613
|
+
async function submitZyfaiDeposit({ sdk, state, chain, amount, asset, smartWallet, assertCurrent }) {
|
|
614
|
+
const owner = state.walletAddress;
|
|
615
|
+
const provider = state.provider;
|
|
616
|
+
const token = SupportedAssets.find((value) => value.chainId === chain.id && value.symbol === asset);
|
|
617
|
+
if (!token || !(0, import_viem2.isAddress)(owner) || !(0, import_viem2.isAddress)(smartWallet) || !/^\d+$/.test(amount) || BigInt(amount) <= 0n)
|
|
618
|
+
throw new OwneyError("AGENT_INVALID_RESPONSE", "Invalid Zyfai deposit transfer.", { chainId: chain.id, asset }, "zyfai");
|
|
619
|
+
assertCurrent();
|
|
620
|
+
const prepared = await sdk.prepareEnterPosition({ userAddress: owner, chainId: chain.id, amount, asset, strategy: "aggressive" });
|
|
621
|
+
assertCurrent();
|
|
622
|
+
const expectedData = (0, import_viem2.encodeFunctionData)({ abi: import_viem2.erc20Abi, functionName: "transfer", args: [smartWallet, BigInt(amount)] });
|
|
623
|
+
const transfer = prepared?.transfer;
|
|
624
|
+
if (!transfer || transfer.safeAddress?.toLowerCase() !== smartWallet.toLowerCase() || transfer.tokenAddress?.toLowerCase() !== token.address.toLowerCase() || transfer.to?.toLowerCase() !== token.address.toLowerCase() || transfer.data?.toLowerCase() !== expectedData.toLowerCase() || transfer.value !== "0")
|
|
625
|
+
throw new OwneyError("AGENT_INVALID_RESPONSE", "Zyfai prepared a different deposit transfer.", { chainId: chain.id, asset }, "zyfai");
|
|
626
|
+
const wallet = (0, import_viem2.createWalletClient)({ account: owner, chain, transport: (0, import_viem2.custom)({
|
|
627
|
+
request: async (args) => {
|
|
628
|
+
assertCurrent();
|
|
629
|
+
if (args.method === "eth_sendTransaction") {
|
|
630
|
+
const [accounts, chainId] = await Promise.all([
|
|
631
|
+
provider.request({ method: "eth_accounts" }),
|
|
632
|
+
provider.request({ method: "eth_chainId" })
|
|
633
|
+
]);
|
|
634
|
+
assertCurrent();
|
|
635
|
+
if (!Array.isArray(accounts) || typeof accounts[0] !== "string" || accounts[0].toLowerCase() !== owner.toLowerCase() || Number(chainId) !== chain.id)
|
|
636
|
+
throw new OwneyError("NOT_CONNECTED", "Wallet changed while preparing Zyfai deposit.", void 0, "zyfai");
|
|
637
|
+
}
|
|
638
|
+
return provider.request(args);
|
|
639
|
+
}
|
|
640
|
+
}, { retryCount: 0 }) });
|
|
641
|
+
return wallet.sendTransaction({ account: owner, chain, to: token.address, data: expectedData, value: 0n });
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
// src/agents/zyfai/zyfai.agent.ts
|
|
645
|
+
var import_sdk = require("@zyfai/sdk");
|
|
646
|
+
var import_viem5 = require("viem");
|
|
647
|
+
var import_chains = require("viem/chains");
|
|
648
|
+
|
|
559
649
|
// src/lib/debug.ts
|
|
560
650
|
var configuredDebug = false;
|
|
561
651
|
function setOwneyDebug(enabled) {
|
|
@@ -600,8 +690,8 @@ var DayFilterMapping = {
|
|
|
600
690
|
};
|
|
601
691
|
|
|
602
692
|
// src/agents/zyfai/zyfai.mapper.ts
|
|
603
|
-
var
|
|
604
|
-
var exactHexAmount = (raw2, decimals) => (0,
|
|
693
|
+
var import_viem3 = require("viem");
|
|
694
|
+
var exactHexAmount = (raw2, decimals) => (0, import_viem3.formatUnits)(BigInt(/^0x/i.test(raw2) ? raw2 : `0x${raw2}`), decimals);
|
|
605
695
|
var DECIMALS_BY_SYMBOL = {
|
|
606
696
|
usdc: 6,
|
|
607
697
|
weth: 18,
|
|
@@ -615,13 +705,6 @@ function tokenDecimals(symbol, explicit) {
|
|
|
615
705
|
return explicit;
|
|
616
706
|
return DECIMALS_BY_SYMBOL[(symbol ?? "").toLowerCase()] ?? 6;
|
|
617
707
|
}
|
|
618
|
-
function mapDeposit(raw2) {
|
|
619
|
-
return {
|
|
620
|
-
txHash: raw2.txHash,
|
|
621
|
-
smartWallet: raw2.smartWallet,
|
|
622
|
-
amount: raw2.amount
|
|
623
|
-
};
|
|
624
|
-
}
|
|
625
708
|
function mapWithdraw(raw2) {
|
|
626
709
|
return {
|
|
627
710
|
txHash: raw2.txHash,
|
|
@@ -707,7 +790,7 @@ function mapBalances(raw2, _chainId, smartWallet) {
|
|
|
707
790
|
// legacy `amount` fallback is hex. Runtime
|
|
708
791
|
// getBalances payloads often carry one (e.g. 18 for WETH) — prefer that
|
|
709
792
|
// when present, otherwise fall back to the per-symbol lookup.
|
|
710
|
-
amount: p.underlyingAmountWithFee ?? p.underlyingAmount ? (0,
|
|
793
|
+
amount: p.underlyingAmountWithFee ?? p.underlyingAmount ? (0, import_viem3.formatUnits)(
|
|
711
794
|
BigInt(p.underlyingAmountWithFee ?? p.underlyingAmount ?? "0"),
|
|
712
795
|
tokenDecimals(
|
|
713
796
|
p.token_symbol,
|
|
@@ -1372,7 +1455,7 @@ function protocolsPolicyNeedsUpdate(current, desiredProtocols, desiredAutoSelect
|
|
|
1372
1455
|
}
|
|
1373
1456
|
|
|
1374
1457
|
// src/lib/paid-rpc.ts
|
|
1375
|
-
var
|
|
1458
|
+
var import_viem4 = require("viem");
|
|
1376
1459
|
var PAID_RPC_RETRY_COUNT = 3;
|
|
1377
1460
|
var PAID_RPC_RETRY_DELAY_MS = 1e3;
|
|
1378
1461
|
function configuredRpcProxyBaseUrl(baseUrl) {
|
|
@@ -1408,9 +1491,9 @@ function createPaidRpcClient(chain, rpcUrls) {
|
|
|
1408
1491
|
rpcUrls,
|
|
1409
1492
|
chain.id
|
|
1410
1493
|
);
|
|
1411
|
-
return (0,
|
|
1494
|
+
return (0, import_viem4.createPublicClient)({
|
|
1412
1495
|
chain,
|
|
1413
|
-
transport: (0,
|
|
1496
|
+
transport: (0, import_viem4.http)(url, {
|
|
1414
1497
|
retryCount: PAID_RPC_RETRY_COUNT,
|
|
1415
1498
|
retryDelay: PAID_RPC_RETRY_DELAY_MS
|
|
1416
1499
|
})
|
|
@@ -1507,7 +1590,7 @@ async function withPaidRpcDiagnostics(operation, chainId, rpcMethod, agentId) {
|
|
|
1507
1590
|
}
|
|
1508
1591
|
|
|
1509
1592
|
// src/agents/zyfai/zyfai.agent.ts
|
|
1510
|
-
var ERC7579_IS_MODULE_INSTALLED_ABI = (0,
|
|
1593
|
+
var ERC7579_IS_MODULE_INSTALLED_ABI = (0, import_viem5.parseAbi)([
|
|
1511
1594
|
"function isModuleInstalled(uint256 moduleTypeId, address module, bytes additionalContext) view returns (bool)"
|
|
1512
1595
|
]);
|
|
1513
1596
|
var WETH_ADDRESS_BY_CHAIN = {
|
|
@@ -1521,6 +1604,14 @@ var POOL_POLICY_CHAIN_IDS = [8453, 42161, 1];
|
|
|
1521
1604
|
var EARNINGS_REFRESH_COOLDOWN_MS = 60 * 60 * 1e3;
|
|
1522
1605
|
var WITHDRAW_BALANCE_TIMEOUT_MS = 2e3;
|
|
1523
1606
|
var ZyfaiAgent = class _ZyfaiAgent {
|
|
1607
|
+
constructor(apiKey, rpcUrls, referralSource) {
|
|
1608
|
+
this.apiKey = apiKey;
|
|
1609
|
+
this.referralSource = referralSource;
|
|
1610
|
+
this.rpcUrls = resolveRpcUrls(rpcUrls);
|
|
1611
|
+
this.sdk = this.createSdk();
|
|
1612
|
+
}
|
|
1613
|
+
apiKey;
|
|
1614
|
+
referralSource;
|
|
1524
1615
|
id = "zyfai";
|
|
1525
1616
|
supportedChainIds = [8453, 42161, 1];
|
|
1526
1617
|
supportedAssets = [
|
|
@@ -1565,6 +1656,9 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1565
1656
|
*/
|
|
1566
1657
|
sessionKeyAttempts = /* @__PURE__ */ new Set();
|
|
1567
1658
|
connectAuthPromise = null;
|
|
1659
|
+
connectAuthScope = null;
|
|
1660
|
+
connectionGeneration = 0;
|
|
1661
|
+
sdkHasConnected = false;
|
|
1568
1662
|
rpcUrls;
|
|
1569
1663
|
publicClients = /* @__PURE__ */ new Map();
|
|
1570
1664
|
// Receipt-derived amounts and log identities, scoped to the owner and asset.
|
|
@@ -1575,17 +1669,20 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1575
1669
|
earningsSnapshot = null;
|
|
1576
1670
|
earningsGeneration = 0;
|
|
1577
1671
|
balanceSnapshots = /* @__PURE__ */ new WeakMap();
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1672
|
+
/** A replaced wallet session gets its own vendor client. In-flight calls
|
|
1673
|
+
* keep their original client; authentication must never change owners under
|
|
1674
|
+
* an operation that is waiting for provider reads or an HTTP response. */
|
|
1675
|
+
createSdk() {
|
|
1676
|
+
const sdk = new import_sdk.ZyfaiSDK({
|
|
1677
|
+
apiKey: this.apiKey,
|
|
1582
1678
|
rpcUrls: this.rpcUrls,
|
|
1583
1679
|
// Forwarded to /auth/login by the SDK's own SIWE handshake, so
|
|
1584
1680
|
// attribution survives without the AppKit SIWX config (which carried it
|
|
1585
1681
|
// via `createOwneySIWX({ referralSource })` when apps used the modal).
|
|
1586
|
-
referralSource
|
|
1682
|
+
referralSource: this.referralSource
|
|
1587
1683
|
});
|
|
1588
|
-
this.installAuthCache();
|
|
1684
|
+
this.installAuthCache(sdk);
|
|
1685
|
+
return sdk;
|
|
1589
1686
|
}
|
|
1590
1687
|
getPublicClient(chainId) {
|
|
1591
1688
|
const cached = this.publicClients.get(chainId);
|
|
@@ -1660,7 +1757,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1660
1757
|
}, asset.address, entry.action === "Withdraw" ? "withdraw" : "deposit");
|
|
1661
1758
|
if (evidence.transfer === "confirmed" && evidence.confirmedAmount) {
|
|
1662
1759
|
Object.assign(tx, {
|
|
1663
|
-
amount: (0,
|
|
1760
|
+
amount: (0, import_viem5.formatUnits)(BigInt(evidence.confirmedAmount), asset.decimals),
|
|
1664
1761
|
amountRaw: evidence.confirmedAmount,
|
|
1665
1762
|
blockNumber: evidence.blockNumber,
|
|
1666
1763
|
logIndexes: evidence.logIndexes,
|
|
@@ -1684,9 +1781,9 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1684
1781
|
* No-op on the server (no `window`) — the SDK is constructed during SSR
|
|
1685
1782
|
* for some apps and the patch only matters in the browser anyway.
|
|
1686
1783
|
*/
|
|
1687
|
-
installAuthCache() {
|
|
1784
|
+
installAuthCache(sdk = this.sdk) {
|
|
1688
1785
|
if (typeof window === "undefined") return;
|
|
1689
|
-
const internals =
|
|
1786
|
+
const internals = sdk;
|
|
1690
1787
|
const original = internals.authenticateUser.bind(internals);
|
|
1691
1788
|
internals.authenticateUser = async () => {
|
|
1692
1789
|
if (internals.authenticatedUserId !== null) return;
|
|
@@ -1731,25 +1828,41 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1731
1828
|
/** Light connect: SIWE auth only. Re-auths if chain changed. */
|
|
1732
1829
|
async connectAuth(state, chainId) {
|
|
1733
1830
|
const validChainId = isValidChainId(chainId);
|
|
1734
|
-
|
|
1831
|
+
const owner = state.walletAddress.toLowerCase();
|
|
1832
|
+
const scope = `${owner}:${validChainId}`;
|
|
1833
|
+
if (this.connectedAddress?.toLowerCase() === owner && this.connectedChainId === validChainId) {
|
|
1735
1834
|
return;
|
|
1736
1835
|
}
|
|
1737
|
-
if (this.connectAuthPromise) {
|
|
1836
|
+
if (this.connectAuthPromise && this.connectAuthScope === scope) {
|
|
1738
1837
|
await this.connectAuthPromise;
|
|
1739
|
-
return;
|
|
1838
|
+
return this.connectAuth(state, chainId);
|
|
1740
1839
|
}
|
|
1741
|
-
this.
|
|
1840
|
+
if (this.sdkHasConnected || this.connectedAddress) this.sdk = this.createSdk();
|
|
1841
|
+
this.sdkHasConnected = true;
|
|
1842
|
+
const executionSdk = this.sdk;
|
|
1843
|
+
const generation = ++this.connectionGeneration;
|
|
1844
|
+
this.connectedAddress = null;
|
|
1845
|
+
this.connectedChainId = null;
|
|
1846
|
+
const pending = (async () => {
|
|
1742
1847
|
const address = await this.connectAccountWithRetry(
|
|
1743
1848
|
state.provider,
|
|
1744
|
-
validChainId
|
|
1849
|
+
validChainId,
|
|
1850
|
+
executionSdk
|
|
1745
1851
|
);
|
|
1852
|
+
if (generation !== this.connectionGeneration || address.toLowerCase() !== owner)
|
|
1853
|
+
throw new OwneyError("NOT_CONNECTED", "Wallet changed while connecting Zyfai.", void 0, this.id);
|
|
1746
1854
|
this.connectedAddress = address;
|
|
1747
1855
|
this.connectedChainId = validChainId;
|
|
1748
1856
|
})();
|
|
1857
|
+
this.connectAuthPromise = pending;
|
|
1858
|
+
this.connectAuthScope = scope;
|
|
1749
1859
|
try {
|
|
1750
|
-
await
|
|
1860
|
+
await pending;
|
|
1751
1861
|
} finally {
|
|
1752
|
-
this.connectAuthPromise
|
|
1862
|
+
if (this.connectAuthPromise === pending) {
|
|
1863
|
+
this.connectAuthPromise = null;
|
|
1864
|
+
this.connectAuthScope = null;
|
|
1865
|
+
}
|
|
1753
1866
|
}
|
|
1754
1867
|
}
|
|
1755
1868
|
/**
|
|
@@ -1761,16 +1874,16 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1761
1874
|
* JWT from a misconfigured API key; we retry once either way, and if the
|
|
1762
1875
|
* second attempt still fails the original error propagates.
|
|
1763
1876
|
*/
|
|
1764
|
-
async connectAccountWithRetry(provider, chainId) {
|
|
1877
|
+
async connectAccountWithRetry(provider, chainId, executionSdk = this.sdk) {
|
|
1765
1878
|
try {
|
|
1766
|
-
return await
|
|
1879
|
+
return await executionSdk.connectAccount(provider, chainId);
|
|
1767
1880
|
} catch (error) {
|
|
1768
1881
|
const message = error instanceof Error ? error.message : String(error);
|
|
1769
1882
|
if (!message.toLowerCase().includes("unauthorized")) throw error;
|
|
1770
|
-
const internals =
|
|
1883
|
+
const internals = executionSdk;
|
|
1771
1884
|
const address = internals.walletClient?.account?.address;
|
|
1772
1885
|
if (address) clearSession(address, chainId);
|
|
1773
|
-
return await
|
|
1886
|
+
return await executionSdk.connectAccount(provider, chainId);
|
|
1774
1887
|
}
|
|
1775
1888
|
}
|
|
1776
1889
|
/**
|
|
@@ -1782,11 +1895,17 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1782
1895
|
* withdrawFunds) fail with "No account connected".
|
|
1783
1896
|
*/
|
|
1784
1897
|
async ensureConnected(state, chainId) {
|
|
1898
|
+
const assertOwner = () => {
|
|
1899
|
+
if (this.connectedAddress?.toLowerCase() !== state.walletAddress.toLowerCase() || this.connectedChainId !== chainId)
|
|
1900
|
+
throw new OwneyError("NOT_CONNECTED", "Wallet changed while connecting Zyfai.", void 0, this.id);
|
|
1901
|
+
};
|
|
1785
1902
|
await this.connectAuth(state, chainId);
|
|
1903
|
+
assertOwner();
|
|
1786
1904
|
const internals = this.sdk;
|
|
1787
1905
|
if (!internals.walletClient || internals.authenticatedUserId === null) {
|
|
1788
1906
|
this.connectedChainId = null;
|
|
1789
1907
|
await this.connectAuth(state, chainId);
|
|
1908
|
+
assertOwner();
|
|
1790
1909
|
}
|
|
1791
1910
|
}
|
|
1792
1911
|
/** A rejected execution session must not be reused by the next foreground attempt. */
|
|
@@ -1847,6 +1966,8 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1847
1966
|
}
|
|
1848
1967
|
// --- IAgent: Connection lifecycle ---
|
|
1849
1968
|
async disconnect() {
|
|
1969
|
+
const executionSdk = this.sdk;
|
|
1970
|
+
this.connectionGeneration++;
|
|
1850
1971
|
this.earningsGeneration++;
|
|
1851
1972
|
this.earningsReads.clear();
|
|
1852
1973
|
this.earningsRefreshes.clear();
|
|
@@ -1854,10 +1975,14 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1854
1975
|
if (this.connectedAddress && this.connectedChainId !== null) {
|
|
1855
1976
|
clearSession(this.connectedAddress, this.connectedChainId);
|
|
1856
1977
|
}
|
|
1857
|
-
await this.sdk.disconnectAccount();
|
|
1858
1978
|
this.connectedAddress = null;
|
|
1859
1979
|
this.connectedChainId = null;
|
|
1980
|
+
this.connectAuthPromise = null;
|
|
1981
|
+
this.connectAuthScope = null;
|
|
1860
1982
|
this.smartWalletCache.clear();
|
|
1983
|
+
this.sdk = this.createSdk();
|
|
1984
|
+
this.sdkHasConnected = false;
|
|
1985
|
+
await executionSdk.disconnectAccount();
|
|
1861
1986
|
}
|
|
1862
1987
|
// --- IAgent: Account lifecycle ---
|
|
1863
1988
|
async activateAgent(state, chainId) {
|
|
@@ -2346,93 +2471,79 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2346
2471
|
return redeployed.address;
|
|
2347
2472
|
}
|
|
2348
2473
|
async deposit(state, chainId, amount, asset, depositCallback, onProgress) {
|
|
2474
|
+
const validChainId = isValidChainId(chainId);
|
|
2475
|
+
const owner = state.walletAddress;
|
|
2476
|
+
const provider = state.provider;
|
|
2477
|
+
await this.ensureConnected(state, validChainId);
|
|
2478
|
+
const executionSdk = this.sdk;
|
|
2479
|
+
const generation = this.connectionGeneration;
|
|
2480
|
+
const assertCurrent = () => {
|
|
2481
|
+
const account = executionSdk.walletClient?.account?.address;
|
|
2482
|
+
if (generation !== this.connectionGeneration || executionSdk !== this.sdk || this.connectedAddress?.toLowerCase() !== owner.toLowerCase() || this.connectedChainId !== validChainId || state.walletAddress.toLowerCase() !== owner.toLowerCase() || state.provider !== provider || state.chainId !== null && state.chainId !== validChainId || account && account.toLowerCase() !== owner.toLowerCase())
|
|
2483
|
+
throw new OwneyError("NOT_CONNECTED", "Wallet changed while preparing Zyfai deposit.", void 0, this.id);
|
|
2484
|
+
};
|
|
2485
|
+
assertCurrent();
|
|
2486
|
+
const smartWallet = await this.ensureWalletDeployed(owner, validChainId);
|
|
2487
|
+
assertCurrent();
|
|
2488
|
+
notifyFunding(onProgress, {
|
|
2489
|
+
agentId: this.id,
|
|
2490
|
+
chainId,
|
|
2491
|
+
token: asset,
|
|
2492
|
+
walletAddress: owner,
|
|
2493
|
+
agentWallet: smartWallet,
|
|
2494
|
+
intendedAmount: amount,
|
|
2495
|
+
transfer: "pending",
|
|
2496
|
+
registration: "pending",
|
|
2497
|
+
delivery: "not-applicable"
|
|
2498
|
+
});
|
|
2499
|
+
const txHash = depositCallback ? await depositCallback(smartWallet, validChainId, amount) : await submitZyfaiDeposit({
|
|
2500
|
+
sdk: executionSdk,
|
|
2501
|
+
state: { ...state, walletAddress: owner, provider },
|
|
2502
|
+
chain: VIEM_CHAIN[validChainId],
|
|
2503
|
+
amount,
|
|
2504
|
+
asset,
|
|
2505
|
+
smartWallet,
|
|
2506
|
+
assertCurrent
|
|
2507
|
+
});
|
|
2508
|
+
let evidence = {
|
|
2509
|
+
agentId: this.id,
|
|
2510
|
+
chainId,
|
|
2511
|
+
token: asset,
|
|
2512
|
+
walletAddress: owner,
|
|
2513
|
+
agentWallet: smartWallet,
|
|
2514
|
+
intendedAmount: amount,
|
|
2515
|
+
txHash,
|
|
2516
|
+
transfer: "pending",
|
|
2517
|
+
registration: "pending",
|
|
2518
|
+
delivery: "not-applicable"
|
|
2519
|
+
};
|
|
2520
|
+
notifyFunding(onProgress, evidence);
|
|
2349
2521
|
try {
|
|
2350
|
-
const
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
token: asset,
|
|
2361
|
-
walletAddress: state.walletAddress,
|
|
2362
|
-
agentWallet: smartWallet,
|
|
2363
|
-
intendedAmount: amount,
|
|
2364
|
-
transfer: "pending",
|
|
2365
|
-
registration: "pending",
|
|
2366
|
-
delivery: "not-applicable"
|
|
2367
|
-
});
|
|
2368
|
-
const txHash = await depositCallback(smartWallet, validChainId, amount);
|
|
2369
|
-
let evidence2 = {
|
|
2370
|
-
agentId: this.id,
|
|
2371
|
-
chainId,
|
|
2372
|
-
token: asset,
|
|
2373
|
-
walletAddress: state.walletAddress,
|
|
2374
|
-
agentWallet: smartWallet,
|
|
2375
|
-
intendedAmount: amount,
|
|
2376
|
-
txHash,
|
|
2377
|
-
transfer: "pending",
|
|
2378
|
-
registration: "pending",
|
|
2379
|
-
delivery: "not-applicable"
|
|
2380
|
-
};
|
|
2381
|
-
notifyFunding(onProgress, evidence2);
|
|
2382
|
-
try {
|
|
2383
|
-
const receipt = await this.getPublicClient(validChainId).getTransactionReceipt({ hash: txHash });
|
|
2384
|
-
const token = SupportedAssets.find((token2) => token2.chainId === chainId && token2.symbol === asset);
|
|
2385
|
-
evidence2 = inspectFundingReceipt(receipt, evidence2, token.address, "deposit");
|
|
2386
|
-
} catch {
|
|
2387
|
-
evidence2 = { ...evidence2, transfer: "unknown" };
|
|
2388
|
-
}
|
|
2389
|
-
notifyFunding(onProgress, evidence2);
|
|
2390
|
-
if (evidence2.transfer === "failed")
|
|
2391
|
-
throw new OwneyError("AGENT_TRANSACTION_REVERTED", "Zyfai deposit transaction reverted.", { txHash }, this.id);
|
|
2392
|
-
try {
|
|
2393
|
-
const tokenAddress = asset === "WETH" ? WETH_ADDRESS_BY_CHAIN[validChainId] : void 0;
|
|
2394
|
-
await (tokenAddress ? this.sdk.logDeposit(validChainId, txHash, amount, tokenAddress) : this.sdk.logDeposit(validChainId, txHash, amount));
|
|
2395
|
-
evidence2 = { ...evidence2, registration: "confirmed" };
|
|
2396
|
-
} catch {
|
|
2397
|
-
evidence2 = { ...evidence2, registration: "unknown" };
|
|
2398
|
-
}
|
|
2399
|
-
notifyFunding(onProgress, evidence2);
|
|
2400
|
-
return { txHash, smartWallet, amount, evidence: evidence2 };
|
|
2401
|
-
}
|
|
2402
|
-
await this.ensureWalletDeployed(this.getAddress(), validChainId);
|
|
2403
|
-
const raw2 = await this.sdk.sendDeposit(
|
|
2404
|
-
this.getAddress(),
|
|
2405
|
-
validChainId,
|
|
2406
|
-
amount,
|
|
2407
|
-
asset,
|
|
2408
|
-
"aggressive"
|
|
2409
|
-
);
|
|
2410
|
-
let evidence = {
|
|
2411
|
-
agentId: this.id,
|
|
2412
|
-
chainId,
|
|
2413
|
-
token: asset,
|
|
2414
|
-
walletAddress: state.walletAddress,
|
|
2415
|
-
agentWallet: raw2.smartWallet,
|
|
2416
|
-
intendedAmount: amount,
|
|
2417
|
-
txHash: raw2.txHash,
|
|
2418
|
-
transfer: "unknown",
|
|
2419
|
-
registration: raw2.registration ? "confirmed" : "unknown",
|
|
2420
|
-
delivery: "not-applicable"
|
|
2421
|
-
};
|
|
2422
|
-
notifyFunding(onProgress, evidence);
|
|
2423
|
-
try {
|
|
2424
|
-
const receipt = await this.getPublicClient(validChainId).getTransactionReceipt({ hash: raw2.txHash });
|
|
2425
|
-
const token = SupportedAssets.find((value) => value.chainId === chainId && value.symbol === asset);
|
|
2426
|
-
evidence = inspectFundingReceipt(receipt, evidence, token.address, "deposit");
|
|
2427
|
-
} catch {
|
|
2428
|
-
}
|
|
2429
|
-
notifyFunding(onProgress, evidence);
|
|
2430
|
-
if (evidence.transfer === "failed")
|
|
2431
|
-
throw new OwneyError("AGENT_TRANSACTION_REVERTED", "Zyfai deposit transaction reverted.", { txHash: raw2.txHash }, this.id);
|
|
2432
|
-
return { ...mapDeposit(raw2), evidence };
|
|
2433
|
-
} catch (error) {
|
|
2434
|
-
throw error;
|
|
2522
|
+
const receipt = await this.getPublicClient(validChainId).waitForTransactionReceipt({
|
|
2523
|
+
hash: txHash,
|
|
2524
|
+
confirmations: 1,
|
|
2525
|
+
timeout: 9e4,
|
|
2526
|
+
checkReplacement: false
|
|
2527
|
+
});
|
|
2528
|
+
const token = SupportedAssets.find((value) => value.chainId === chainId && value.symbol === asset);
|
|
2529
|
+
evidence = inspectFundingReceipt(receipt, evidence, token.address, "deposit");
|
|
2530
|
+
} catch {
|
|
2531
|
+
evidence = { ...evidence, transfer: "unknown" };
|
|
2435
2532
|
}
|
|
2533
|
+
notifyFunding(onProgress, evidence);
|
|
2534
|
+
if (evidence.transfer === "failed")
|
|
2535
|
+
throw new OwneyError("AGENT_TRANSACTION_REVERTED", "Zyfai deposit transaction reverted.", { txHash }, this.id);
|
|
2536
|
+
if (evidence.transfer !== "confirmed") return { txHash, smartWallet, amount, evidence };
|
|
2537
|
+
try {
|
|
2538
|
+
assertCurrent();
|
|
2539
|
+
const tokenAddress = asset === "WETH" ? WETH_ADDRESS_BY_CHAIN[validChainId] : void 0;
|
|
2540
|
+
await (tokenAddress ? executionSdk.logDeposit(validChainId, txHash, amount, tokenAddress) : executionSdk.logDeposit(validChainId, txHash, amount));
|
|
2541
|
+
evidence = { ...evidence, registration: "confirmed" };
|
|
2542
|
+
} catch {
|
|
2543
|
+
evidence = { ...evidence, registration: "unknown" };
|
|
2544
|
+
}
|
|
2545
|
+
notifyFunding(onProgress, evidence);
|
|
2546
|
+
return { txHash, smartWallet, amount, evidence };
|
|
2436
2547
|
}
|
|
2437
2548
|
// --- IAgent: Fund operations ---
|
|
2438
2549
|
/** Only after a definitive endpoint rejection, combine a new provider
|
|
@@ -2462,7 +2573,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2462
2573
|
this.sdk.getPortfolio(owner).catch(() => void 0)
|
|
2463
2574
|
]);
|
|
2464
2575
|
assertScope();
|
|
2465
|
-
if (!(0,
|
|
2576
|
+
if (!(0, import_viem5.isAddress)(wallet.address) || !registered.smartWallet || registered.smartWallet.toLowerCase() !== wallet.address.toLowerCase())
|
|
2466
2577
|
throw new OwneyError(
|
|
2467
2578
|
"AGENT_AUTH_FAILED",
|
|
2468
2579
|
"Could not verify Zyfai's withdrawal wallet.",
|
|
@@ -2473,7 +2584,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2473
2584
|
const asset = SupportedAssets.find((value) => value.chainId === chainId && value.symbol === token);
|
|
2474
2585
|
const idle = asset ? await this.getPublicClient(chainId).readContract({
|
|
2475
2586
|
address: asset.address,
|
|
2476
|
-
abi:
|
|
2587
|
+
abi: import_viem5.erc20Abi,
|
|
2477
2588
|
functionName: "balanceOf",
|
|
2478
2589
|
args: [wallet.address]
|
|
2479
2590
|
}).catch(() => void 0) : void 0;
|
|
@@ -2502,11 +2613,12 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2502
2613
|
/** Called only after the execution endpoint explicitly rejected a request.
|
|
2503
2614
|
* A timeout or an accepted request never authorizes repair and resubmission. */
|
|
2504
2615
|
async recoverWithdrawalSession(state, chainId, token, owner) {
|
|
2616
|
+
const generation = this.connectionGeneration;
|
|
2505
2617
|
await this.assertNotEmptyRejectedWithdrawal(state, chainId, token, owner);
|
|
2506
2618
|
const internals = this.sdk;
|
|
2507
2619
|
const assertScope = () => {
|
|
2508
2620
|
const account = internals.walletClient?.account?.address;
|
|
2509
|
-
if (state.walletAddress.toLowerCase() !== owner.toLowerCase() || this.connectedAddress?.toLowerCase() !== owner.toLowerCase() || this.connectedChainId !== chainId || account && account.toLowerCase() !== owner.toLowerCase())
|
|
2621
|
+
if (generation !== this.connectionGeneration || state.walletAddress.toLowerCase() !== owner.toLowerCase() || this.connectedAddress?.toLowerCase() !== owner.toLowerCase() || this.connectedChainId !== chainId || account && account.toLowerCase() !== owner.toLowerCase())
|
|
2510
2622
|
throw new OwneyError("NOT_CONNECTED", "Wallet changed while preparing Zyfai withdrawal.", void 0, this.id);
|
|
2511
2623
|
};
|
|
2512
2624
|
assertScope();
|
|
@@ -2535,6 +2647,8 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2535
2647
|
}
|
|
2536
2648
|
}
|
|
2537
2649
|
async withdraw(state, chainId, token, amount, onProgress) {
|
|
2650
|
+
if (amount !== void 0 && (typeof amount !== "string" || !/^[0-9]+$/.test(amount) || BigInt(amount) <= 0n))
|
|
2651
|
+
throw new OwneyError("WITHDRAW_INVALID_AMOUNT", "Withdrawal amount must be a positive integer in token base units.", void 0, this.id);
|
|
2538
2652
|
const validChainId = isValidChainId(chainId);
|
|
2539
2653
|
try {
|
|
2540
2654
|
await this.ensureConnected(state, validChainId);
|
|
@@ -2551,16 +2665,40 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2551
2665
|
});
|
|
2552
2666
|
throw error;
|
|
2553
2667
|
}
|
|
2554
|
-
|
|
2555
|
-
const
|
|
2556
|
-
const
|
|
2668
|
+
const executionSdk = this.sdk;
|
|
2669
|
+
const internals = executionSdk;
|
|
2670
|
+
const generation = this.connectionGeneration;
|
|
2671
|
+
const owner = state.walletAddress;
|
|
2672
|
+
let staleSessionError;
|
|
2673
|
+
const assertCurrent = () => {
|
|
2674
|
+
const account = internals.walletClient?.account?.address;
|
|
2675
|
+
if (generation !== this.connectionGeneration || this.connectedAddress?.toLowerCase() !== owner.toLowerCase() || this.connectedChainId !== validChainId || state.chainId !== null && state.chainId !== validChainId || account && account.toLowerCase() !== owner.toLowerCase()) {
|
|
2676
|
+
staleSessionError = new OwneyError(
|
|
2677
|
+
"NOT_CONNECTED",
|
|
2678
|
+
"Wallet changed before Zyfai withdrawal submission.",
|
|
2679
|
+
{ phase: "prepare", rejectedBeforeSubmission: true },
|
|
2680
|
+
this.id
|
|
2681
|
+
);
|
|
2682
|
+
throw staleSessionError;
|
|
2683
|
+
}
|
|
2684
|
+
};
|
|
2685
|
+
let observation = observeWithdrawalSubmission(executionSdk, validChainId, token, assertCurrent);
|
|
2686
|
+
const authToken = internals.httpClient?.authToken;
|
|
2557
2687
|
let raw2;
|
|
2558
2688
|
try {
|
|
2559
2689
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
2560
2690
|
try {
|
|
2561
|
-
|
|
2691
|
+
assertCurrent();
|
|
2692
|
+
raw2 = await executionSdk.withdrawFunds(owner, validChainId, amount, token);
|
|
2562
2693
|
break;
|
|
2563
2694
|
} catch (error) {
|
|
2695
|
+
if (observation.rejected()) {
|
|
2696
|
+
try {
|
|
2697
|
+
assertCurrent();
|
|
2698
|
+
} catch {
|
|
2699
|
+
throw error;
|
|
2700
|
+
}
|
|
2701
|
+
}
|
|
2564
2702
|
if (!amount && observation.rejected() && observation.request()?.failure === "insufficient-balance") {
|
|
2565
2703
|
try {
|
|
2566
2704
|
await this.assertNotEmptyRejectedWithdrawal(state, validChainId, token, owner);
|
|
@@ -2578,7 +2716,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2578
2716
|
);
|
|
2579
2717
|
await this.recoverWithdrawalSession(state, validChainId, token, owner);
|
|
2580
2718
|
observation.stop();
|
|
2581
|
-
observation = observeWithdrawalSubmission(
|
|
2719
|
+
observation = observeWithdrawalSubmission(executionSdk, validChainId, token, assertCurrent);
|
|
2582
2720
|
}
|
|
2583
2721
|
}
|
|
2584
2722
|
if (!raw2) throw new OwneyError(
|
|
@@ -2588,6 +2726,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2588
2726
|
this.id
|
|
2589
2727
|
);
|
|
2590
2728
|
} catch (error) {
|
|
2729
|
+
if (staleSessionError && observation.attempted() === false) error = staleSessionError;
|
|
2591
2730
|
this.invalidateRejectedWithdrawalSession(error, state, validChainId, authToken);
|
|
2592
2731
|
if (observation.attempted() !== void 0) {
|
|
2593
2732
|
const failed = observation.attempted() === false || observation.rejected();
|
|
@@ -2608,7 +2747,6 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2608
2747
|
observation.stop();
|
|
2609
2748
|
}
|
|
2610
2749
|
if (!raw2.success) {
|
|
2611
|
-
const unresolved = !!raw2.txHash || /already|pending|queued|in.progress/i.test(raw2.message ?? "");
|
|
2612
2750
|
notifyFunding(onProgress, {
|
|
2613
2751
|
agentId: this.id,
|
|
2614
2752
|
chainId,
|
|
@@ -2616,9 +2754,9 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2616
2754
|
walletAddress: state.walletAddress,
|
|
2617
2755
|
intendedAmount: amount ?? "MAX",
|
|
2618
2756
|
txHash: raw2.txHash,
|
|
2619
|
-
transfer:
|
|
2757
|
+
transfer: "unknown",
|
|
2620
2758
|
registration: "not-applicable",
|
|
2621
|
-
delivery:
|
|
2759
|
+
delivery: "unknown",
|
|
2622
2760
|
withdrawalRequest: observation.request()
|
|
2623
2761
|
});
|
|
2624
2762
|
throw new OwneyError(
|
|
@@ -2645,8 +2783,9 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2645
2783
|
}
|
|
2646
2784
|
/** Registration recovery never signs, transfers, activates, or refreshes authentication. */
|
|
2647
2785
|
async retryDepositRegistration(state, evidence) {
|
|
2648
|
-
const
|
|
2649
|
-
|
|
2786
|
+
const executionSdk = this.sdk;
|
|
2787
|
+
const internals = executionSdk;
|
|
2788
|
+
if (evidence.agentId !== this.id || evidence.walletAddress.toLowerCase() !== state.walletAddress.toLowerCase() || evidence.chainId !== state.chainId || !internals.httpClient.authToken || internals.authenticatedUserId === null || this.connectedAddress?.toLowerCase() !== state.walletAddress.toLowerCase() || this.connectedChainId !== evidence.chainId) {
|
|
2650
2789
|
throw new OwneyError("NOT_CONNECTED", "Reconnect the wallet before recovering deposit registration.");
|
|
2651
2790
|
}
|
|
2652
2791
|
if (evidence.transfer !== "confirmed" || !evidence.txHash) {
|
|
@@ -2654,16 +2793,16 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2654
2793
|
}
|
|
2655
2794
|
const cid = isValidChainId(evidence.chainId);
|
|
2656
2795
|
const tokenAddress = evidence.token === "WETH" ? WETH_ADDRESS_BY_CHAIN[cid] : void 0;
|
|
2657
|
-
await
|
|
2796
|
+
await executionSdk.logDeposit(cid, evidence.txHash, evidence.intendedAmount, tokenAddress);
|
|
2658
2797
|
return { ...evidence, registration: "confirmed" };
|
|
2659
2798
|
}
|
|
2660
2799
|
// --- IAgent: Portfolio reads ---
|
|
2661
2800
|
async getFundingWallet(state, chainId) {
|
|
2662
2801
|
return (await this.sdk.getSmartWalletAddress(state.walletAddress, isValidChainId(chainId))).address;
|
|
2663
2802
|
}
|
|
2664
|
-
/** A positive Safe balance is a
|
|
2665
|
-
*
|
|
2666
|
-
*
|
|
2803
|
+
/** A positive deployed Safe balance is a conservative planning floor. Zero
|
|
2804
|
+
* requires both the mapped Safe's exact idle balance and a fresh complete
|
|
2805
|
+
* empty portfolio, including for an undeployed counterfactual Safe. */
|
|
2667
2806
|
async getWithdrawableBalance(state, chainId, token) {
|
|
2668
2807
|
const validChainId = isValidChainId(chainId);
|
|
2669
2808
|
const asset = SupportedAssets.find((value) => value.chainId === validChainId && value.symbol === token);
|
|
@@ -2692,20 +2831,27 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2692
2831
|
this.sdk.getSmartWalletByEOA(owner)
|
|
2693
2832
|
]);
|
|
2694
2833
|
assertScope();
|
|
2695
|
-
if (!(0,
|
|
2834
|
+
if (!(0, import_viem5.isAddress)(wallet.address) || wallet.isDeployed !== false && (wallet.isDeployed !== true || wallet.isOwner !== true) || !registered.smartWallet || registered.smartWallet.toLowerCase() !== wallet.address.toLowerCase()) throw unavailable();
|
|
2696
2835
|
const client = this.getPublicClient(validChainId);
|
|
2697
2836
|
const blockNumber = await client.getBlockNumber({ cacheTime: 0 });
|
|
2698
2837
|
assertScope();
|
|
2699
2838
|
const idle = await client.readContract({
|
|
2700
2839
|
address: asset.address,
|
|
2701
|
-
abi:
|
|
2840
|
+
abi: import_viem5.erc20Abi,
|
|
2702
2841
|
functionName: "balanceOf",
|
|
2703
2842
|
args: [wallet.address],
|
|
2704
2843
|
blockNumber
|
|
2705
2844
|
});
|
|
2706
2845
|
assertScope();
|
|
2707
|
-
if (typeof idle !== "bigint" || idle
|
|
2708
|
-
|
|
2846
|
+
if (typeof idle !== "bigint" || idle < 0n) throw unavailable();
|
|
2847
|
+
if (idle > 0n) {
|
|
2848
|
+
if (wallet.isDeployed !== true || wallet.isOwner !== true) throw unavailable();
|
|
2849
|
+
return idle;
|
|
2850
|
+
}
|
|
2851
|
+
const portfolio = await this.sdk.getPortfolio(owner);
|
|
2852
|
+
assertScope();
|
|
2853
|
+
if (!hasEmptyWithdrawalSnapshot(portfolio, validChainId, token)) throw unavailable();
|
|
2854
|
+
return 0n;
|
|
2709
2855
|
};
|
|
2710
2856
|
try {
|
|
2711
2857
|
return await Promise.race([read2(), new Promise((_, reject) => {
|
|
@@ -2748,7 +2894,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2748
2894
|
if (blockNumber < BigInt(evidence.blockNumber)) return void 0;
|
|
2749
2895
|
const idle = await client.readContract({
|
|
2750
2896
|
address: asset.address,
|
|
2751
|
-
abi:
|
|
2897
|
+
abi: import_viem5.erc20Abi,
|
|
2752
2898
|
functionName: "balanceOf",
|
|
2753
2899
|
args: [balance.smartWallet],
|
|
2754
2900
|
blockNumber
|
|
@@ -2953,7 +3099,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2953
3099
|
};
|
|
2954
3100
|
|
|
2955
3101
|
// src/agents/yieldseeker/yieldseeker.agent.ts
|
|
2956
|
-
var
|
|
3102
|
+
var import_viem13 = require("viem");
|
|
2957
3103
|
var import_chains4 = require("viem/chains");
|
|
2958
3104
|
|
|
2959
3105
|
// src/lib/chain-guard.ts
|
|
@@ -2992,7 +3138,7 @@ async function ensureWalletOnChain(pub, wallet, expected) {
|
|
|
2992
3138
|
}
|
|
2993
3139
|
|
|
2994
3140
|
// src/lib/transfer-auth.ts
|
|
2995
|
-
var
|
|
3141
|
+
var import_viem6 = require("viem");
|
|
2996
3142
|
|
|
2997
3143
|
// src/lib/sponsor-client.ts
|
|
2998
3144
|
var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
@@ -3108,7 +3254,7 @@ async function postSponsorBatchTransfer(input) {
|
|
|
3108
3254
|
}
|
|
3109
3255
|
|
|
3110
3256
|
// src/lib/permit2.ts
|
|
3111
|
-
var
|
|
3257
|
+
var import_viem7 = require("viem");
|
|
3112
3258
|
var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
3113
3259
|
var MAX_UINT256 = 2n ** 256n - 1n;
|
|
3114
3260
|
function permit2ApprovalAmount(requiredAmount) {
|
|
@@ -3149,7 +3295,7 @@ var ERC20_ALLOWANCE_ABI = [
|
|
|
3149
3295
|
function randomPermit2Nonce() {
|
|
3150
3296
|
const bytes = new Uint8Array(32);
|
|
3151
3297
|
globalThis.crypto.getRandomValues(bytes);
|
|
3152
|
-
return BigInt((0,
|
|
3298
|
+
return BigInt((0, import_viem7.bytesToHex)(bytes));
|
|
3153
3299
|
}
|
|
3154
3300
|
async function readPermit2Allowance(publicClient, token, owner, blockNumber) {
|
|
3155
3301
|
return publicClient.readContract({
|
|
@@ -3192,7 +3338,7 @@ function makeVerificationAwareDepositCallback(implementation) {
|
|
|
3192
3338
|
|
|
3193
3339
|
// src/agents/yieldseeker/yieldseeker.auth.ts
|
|
3194
3340
|
var import_siwe = require("siwe");
|
|
3195
|
-
var
|
|
3341
|
+
var import_viem8 = require("viem");
|
|
3196
3342
|
var import_chains2 = require("viem/chains");
|
|
3197
3343
|
|
|
3198
3344
|
// src/agents/yieldseeker/yieldseeker.auth-cache.ts
|
|
@@ -3305,7 +3451,7 @@ function createYieldseekerSiweMessage(address, chainId, dependencies = {}) {
|
|
|
3305
3451
|
return new import_siwe.SiweMessage({
|
|
3306
3452
|
scheme: url.protocol.slice(0, -1),
|
|
3307
3453
|
domain: url.host,
|
|
3308
|
-
address: (0,
|
|
3454
|
+
address: (0, import_viem8.getAddress)(address),
|
|
3309
3455
|
uri: url.origin,
|
|
3310
3456
|
version: "1",
|
|
3311
3457
|
chainId,
|
|
@@ -3391,15 +3537,15 @@ var YieldseekerAuth = class {
|
|
|
3391
3537
|
clearYieldseekerSession(state.walletAddress, chainId);
|
|
3392
3538
|
}
|
|
3393
3539
|
async sign(state, chainId) {
|
|
3394
|
-
const account = (0,
|
|
3395
|
-
const publicClient = (0,
|
|
3540
|
+
const account = (0, import_viem8.getAddress)(state.walletAddress);
|
|
3541
|
+
const publicClient = (0, import_viem8.createPublicClient)({
|
|
3396
3542
|
chain: import_chains2.base,
|
|
3397
|
-
transport: (0,
|
|
3543
|
+
transport: (0, import_viem8.custom)(state.provider)
|
|
3398
3544
|
});
|
|
3399
|
-
const walletClient = (0,
|
|
3545
|
+
const walletClient = (0, import_viem8.createWalletClient)({
|
|
3400
3546
|
account,
|
|
3401
3547
|
chain: import_chains2.base,
|
|
3402
|
-
transport: (0,
|
|
3548
|
+
transport: (0, import_viem8.custom)(state.provider)
|
|
3403
3549
|
});
|
|
3404
3550
|
await ensureWalletOnChain(
|
|
3405
3551
|
publicClient,
|
|
@@ -3566,7 +3712,7 @@ var YieldseekerApiClient = class {
|
|
|
3566
3712
|
};
|
|
3567
3713
|
|
|
3568
3714
|
// src/agents/yieldseeker/yieldseeker.mapper.ts
|
|
3569
|
-
var
|
|
3715
|
+
var import_viem9 = require("viem");
|
|
3570
3716
|
|
|
3571
3717
|
// src/lib/helpers/snapshot-apy.ts
|
|
3572
3718
|
var DAY_MS = 864e5;
|
|
@@ -3633,10 +3779,18 @@ function raw(value, endpoint) {
|
|
|
3633
3779
|
return BigInt(value);
|
|
3634
3780
|
}
|
|
3635
3781
|
function decimal(value, decimals, endpoint) {
|
|
3636
|
-
return (0,
|
|
3782
|
+
return (0, import_viem9.formatUnits)(raw(value, endpoint), decimals);
|
|
3783
|
+
}
|
|
3784
|
+
function balanceRaw(value, endpoint) {
|
|
3785
|
+
const amount = raw(value, endpoint);
|
|
3786
|
+
if (amount < 0n) return invalid(endpoint, "expected a non-negative balance");
|
|
3787
|
+
return amount;
|
|
3788
|
+
}
|
|
3789
|
+
function balanceDecimal(value, decimals, endpoint) {
|
|
3790
|
+
return (0, import_viem9.formatUnits)(balanceRaw(value, endpoint), decimals);
|
|
3637
3791
|
}
|
|
3638
3792
|
function usd(rawAmount, decimals, price) {
|
|
3639
|
-
return Number((0,
|
|
3793
|
+
return Number((0, import_viem9.formatUnits)(rawAmount, decimals)) * price;
|
|
3640
3794
|
}
|
|
3641
3795
|
function percent(value) {
|
|
3642
3796
|
const result = Number(value);
|
|
@@ -3662,7 +3816,7 @@ function assetAddressValue(record, address) {
|
|
|
3662
3816
|
}
|
|
3663
3817
|
function position(value, asset, baseAssetDecimals) {
|
|
3664
3818
|
const option = value?.yieldOption;
|
|
3665
|
-
if (!option || typeof option.provider !== "string" || typeof option.name !== "string" || typeof option.address !== "string" || !(0,
|
|
3819
|
+
if (!option || typeof option.provider !== "string" || typeof option.name !== "string" || typeof option.address !== "string" || !(0, import_viem9.isAddress)(option.address)) {
|
|
3666
3820
|
return invalid("yield positions", "missing vault metadata");
|
|
3667
3821
|
}
|
|
3668
3822
|
return {
|
|
@@ -3676,13 +3830,13 @@ function position(value, asset, baseAssetDecimals) {
|
|
|
3676
3830
|
// underlying base-asset units in `assetsBase`; pair that value with the
|
|
3677
3831
|
// snapshot's corresponding `baseAssetDecimals` for display. Keep the raw
|
|
3678
3832
|
// share quantity separate from the withdrawable underlying asset amount.
|
|
3679
|
-
amount:
|
|
3833
|
+
amount: balanceDecimal(
|
|
3680
3834
|
value.assetsBase,
|
|
3681
3835
|
baseAssetDecimals,
|
|
3682
3836
|
"yield positions"
|
|
3683
3837
|
),
|
|
3684
|
-
amountRaw:
|
|
3685
|
-
withdrawableAmountRaw:
|
|
3838
|
+
amountRaw: balanceRaw(value.assetsRaw, "yield positions").toString(),
|
|
3839
|
+
withdrawableAmountRaw: balanceRaw(value.withdrawableAssetsRaw, "yield positions").toString(),
|
|
3686
3840
|
apy: percent(option.riskAdjustedApy),
|
|
3687
3841
|
tvl: Number(option.totalDepositsUsd),
|
|
3688
3842
|
liquidity: Number(option.withdrawableDepositsUsd)
|
|
@@ -3699,7 +3853,7 @@ function mapYieldseekerBalances(contexts) {
|
|
|
3699
3853
|
chain: "BASE",
|
|
3700
3854
|
chainId: 8453,
|
|
3701
3855
|
asset: context.asset,
|
|
3702
|
-
amount:
|
|
3856
|
+
amount: balanceDecimal(context.snapshot.totalValueBase, context.snapshot.baseAssetDecimals, "snapshot")
|
|
3703
3857
|
});
|
|
3704
3858
|
const idle = assetAddressValue(
|
|
3705
3859
|
context.snapshot.tokenBalances,
|
|
@@ -3709,7 +3863,7 @@ function mapYieldseekerBalances(contexts) {
|
|
|
3709
3863
|
chain: "BASE",
|
|
3710
3864
|
chainId: 8453,
|
|
3711
3865
|
asset: context.asset,
|
|
3712
|
-
amount:
|
|
3866
|
+
amount: balanceDecimal(idle, metadata.decimals, "snapshot")
|
|
3713
3867
|
});
|
|
3714
3868
|
positions.push(
|
|
3715
3869
|
...context.positions.map(
|
|
@@ -3721,7 +3875,7 @@ function mapYieldseekerBalances(contexts) {
|
|
|
3721
3875
|
)
|
|
3722
3876
|
);
|
|
3723
3877
|
totalUsd += usd(
|
|
3724
|
-
|
|
3878
|
+
balanceRaw(context.snapshot.totalValueBase, "snapshot"),
|
|
3725
3879
|
context.snapshot.baseAssetDecimals,
|
|
3726
3880
|
context.snapshot.baseAssetPriceUsd
|
|
3727
3881
|
);
|
|
@@ -3755,7 +3909,7 @@ function mapYieldseekerEarnings(contexts) {
|
|
|
3755
3909
|
chain: "BASE",
|
|
3756
3910
|
chainId: 8453,
|
|
3757
3911
|
asset: context.asset,
|
|
3758
|
-
amount: (0,
|
|
3912
|
+
amount: (0, import_viem9.formatUnits)(amount, context.snapshot.baseAssetDecimals)
|
|
3759
3913
|
});
|
|
3760
3914
|
lifetimeEarnings += usd(
|
|
3761
3915
|
amount,
|
|
@@ -3769,6 +3923,35 @@ function mapYieldseekerEarnings(contexts) {
|
|
|
3769
3923
|
tokens
|
|
3770
3924
|
};
|
|
3771
3925
|
}
|
|
3926
|
+
function mapYieldseekerDailyEarnings(walletAddress, contexts, days, now = Date.now()) {
|
|
3927
|
+
const today = new Date(now).toISOString().slice(0, 10);
|
|
3928
|
+
const dayCount = { "7D": 7, "14D": 14, "30D": 30 }[days];
|
|
3929
|
+
const cutoff = new Date(Date.parse(today) - dayCount * 864e5).toISOString().slice(0, 10);
|
|
3930
|
+
const assets = contexts.flatMap((context) => {
|
|
3931
|
+
const snapshots = context.historic?.dailyYieldSnapshots;
|
|
3932
|
+
if (!Array.isArray(snapshots)) invalid("historic position", "missing daily yield snapshots");
|
|
3933
|
+
const byDate = /* @__PURE__ */ new Map();
|
|
3934
|
+
for (const snapshot of snapshots) {
|
|
3935
|
+
const time = Date.parse(snapshot.date);
|
|
3936
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(snapshot.date) || !Number.isFinite(time) || new Date(time).toISOString().slice(0, 10) !== snapshot.date) {
|
|
3937
|
+
invalid("historic position", "expected a UTC snapshot date");
|
|
3938
|
+
}
|
|
3939
|
+
if (snapshot.date > today) continue;
|
|
3940
|
+
if (snapshot.baseAssetDecimals !== YIELDSEEKER_ASSET_METADATA[context.asset].decimals) {
|
|
3941
|
+
invalid("historic position", "base asset decimals do not match the selected asset");
|
|
3942
|
+
}
|
|
3943
|
+
const amount = Number(decimal(snapshot.cumulativeYieldBase, snapshot.baseAssetDecimals, "historic position"));
|
|
3944
|
+
if (!Number.isFinite(amount)) invalid("historic position", "expected finite cumulative yield");
|
|
3945
|
+
byDate.set(snapshot.date, { date: snapshot.date, amount });
|
|
3946
|
+
}
|
|
3947
|
+
const sorted = [...byDate.values()].sort((a, b) => a.date.localeCompare(b.date));
|
|
3948
|
+
const window2 = sorted.filter((point) => point.date >= cutoff);
|
|
3949
|
+
if (!window2.length) return [];
|
|
3950
|
+
const opening = sorted.filter((point) => point.date < cutoff).at(-1);
|
|
3951
|
+
return [{ asset: context.asset, points: opening ? [opening, ...window2] : window2 }];
|
|
3952
|
+
}).sort((a, b) => a.asset.localeCompare(b.asset));
|
|
3953
|
+
return { walletAddress, chainId: 8453, assets };
|
|
3954
|
+
}
|
|
3772
3955
|
function apyForDays(context, days, now) {
|
|
3773
3956
|
if (days === "7D") return percent(context.snapshot.apy7d);
|
|
3774
3957
|
if (days === "30D") return percent(context.snapshot.apy30d);
|
|
@@ -3884,7 +4067,7 @@ function allocationEntry(action, context) {
|
|
|
3884
4067
|
const leg = deposit;
|
|
3885
4068
|
const symbol = typeof leg.assetSymbol === "string" ? leg.assetSymbol.toUpperCase() : "";
|
|
3886
4069
|
if (symbol !== context.asset && !(context.asset === "WETH" && symbol === "ETH")) return void 0;
|
|
3887
|
-
if (typeof leg.vaultAddress !== "string" || !(0,
|
|
4070
|
+
if (typeof leg.vaultAddress !== "string" || !(0, import_viem9.isAddress)(leg.vaultAddress)) return void 0;
|
|
3888
4071
|
const rawAmount = typeof leg.rawAmount === "string" && /^\d+$/.test(leg.rawAmount) ? BigInt(leg.rawAmount) : typeof leg.rawAmount === "number" && Number.isSafeInteger(leg.rawAmount) ? BigInt(leg.rawAmount) : void 0;
|
|
3889
4072
|
if (rawAmount === void 0 || rawAmount <= 0n) return void 0;
|
|
3890
4073
|
const option = context.positions.find((position2) => position2.yieldOption.address.toLowerCase() === leg.vaultAddress.toLowerCase())?.yieldOption;
|
|
@@ -3892,7 +4075,7 @@ function allocationEntry(action, context) {
|
|
|
3892
4075
|
protocol: typeof leg.vaultProvider === "string" && leg.vaultProvider ? leg.vaultProvider : option?.provider || "Vault",
|
|
3893
4076
|
pool: typeof leg.vaultName === "string" && leg.vaultName ? leg.vaultName : option?.name,
|
|
3894
4077
|
tokenSymbol: context.asset,
|
|
3895
|
-
amount: (0,
|
|
4078
|
+
amount: (0, import_viem9.formatUnits)(rawAmount, YIELDSEEKER_ASSET_METADATA[context.asset].decimals)
|
|
3896
4079
|
});
|
|
3897
4080
|
amountRaw += rawAmount;
|
|
3898
4081
|
}
|
|
@@ -3911,7 +4094,7 @@ function allocationEntry(action, context) {
|
|
|
3911
4094
|
tokenSymbol: context.asset,
|
|
3912
4095
|
agentWallet: context.wallet.walletAddress,
|
|
3913
4096
|
amountRaw: String(amountRaw),
|
|
3914
|
-
amount: (0,
|
|
4097
|
+
amount: (0, import_viem9.formatUnits)(amountRaw, YIELDSEEKER_ASSET_METADATA[context.asset].decimals)
|
|
3915
4098
|
}]
|
|
3916
4099
|
};
|
|
3917
4100
|
}
|
|
@@ -4035,7 +4218,7 @@ function mapYieldseekerHistory(contexts, options) {
|
|
|
4035
4218
|
const known = new Set(target.logIndexes ?? []);
|
|
4036
4219
|
if (tx.logIndexes?.some((index) => !known.has(index))) {
|
|
4037
4220
|
target.amountRaw = String(BigInt(target.amountRaw ?? "0") + BigInt(tx.amountRaw));
|
|
4038
|
-
target.amount = (0,
|
|
4221
|
+
target.amount = (0, import_viem9.formatUnits)(
|
|
4039
4222
|
BigInt(target.amountRaw),
|
|
4040
4223
|
YIELDSEEKER_ASSET_METADATA[target.tokenSymbol].decimals
|
|
4041
4224
|
);
|
|
@@ -4116,7 +4299,7 @@ function mapYieldseekerAgentApy(options, days) {
|
|
|
4116
4299
|
}
|
|
4117
4300
|
|
|
4118
4301
|
// src/lib/remaining-vault-balance.ts
|
|
4119
|
-
var
|
|
4302
|
+
var import_viem10 = require("viem");
|
|
4120
4303
|
async function remainingVaultBalance(client, wallet, asset, vaults, blockNumber) {
|
|
4121
4304
|
const addresses = [...new Set(vaults.map((value) => value.toLowerCase()))];
|
|
4122
4305
|
if (addresses.length > 64) return void 0;
|
|
@@ -4127,8 +4310,8 @@ async function remainingVaultBalance(client, wallet, asset, vaults, blockNumber)
|
|
|
4127
4310
|
blockNumber,
|
|
4128
4311
|
allowFailure: true,
|
|
4129
4312
|
contracts: batch.map((address) => ({
|
|
4130
|
-
address: (0,
|
|
4131
|
-
abi:
|
|
4313
|
+
address: (0, import_viem10.getAddress)(address),
|
|
4314
|
+
abi: import_viem10.erc20Abi,
|
|
4132
4315
|
functionName: "balanceOf",
|
|
4133
4316
|
args: [wallet]
|
|
4134
4317
|
}))
|
|
@@ -4138,15 +4321,15 @@ async function remainingVaultBalance(client, wallet, asset, vaults, blockNumber)
|
|
|
4138
4321
|
for (let index = 0; index < batch.length; index++) {
|
|
4139
4322
|
const result = balances[index];
|
|
4140
4323
|
if (result?.status !== "success" || typeof result.result !== "bigint" || result.result < 0n) return void 0;
|
|
4141
|
-
if (result.result > 0n) funded.push({ address: (0,
|
|
4324
|
+
if (result.result > 0n) funded.push({ address: (0, import_viem10.getAddress)(batch[index]), shares: result.result });
|
|
4142
4325
|
}
|
|
4143
4326
|
if (!funded.length) return 0n;
|
|
4144
4327
|
const valuations = await client.multicall({
|
|
4145
4328
|
blockNumber,
|
|
4146
4329
|
allowFailure: true,
|
|
4147
4330
|
contracts: funded.flatMap(({ address, shares }) => [
|
|
4148
|
-
{ address, abi:
|
|
4149
|
-
{ address, abi:
|
|
4331
|
+
{ address, abi: import_viem10.erc4626Abi, functionName: "asset" },
|
|
4332
|
+
{ address, abi: import_viem10.erc4626Abi, functionName: "convertToAssets", args: [shares] }
|
|
4150
4333
|
])
|
|
4151
4334
|
});
|
|
4152
4335
|
if (valuations.length !== funded.length * 2) return void 0;
|
|
@@ -4162,12 +4345,12 @@ async function remainingVaultBalance(client, wallet, asset, vaults, blockNumber)
|
|
|
4162
4345
|
}
|
|
4163
4346
|
|
|
4164
4347
|
// src/agents/yieldseeker/yieldseeker.wallet-version.ts
|
|
4165
|
-
var
|
|
4348
|
+
var import_viem11 = require("viem");
|
|
4166
4349
|
var YIELDSEEKER_FACTORY = "0x9c7410a0faCAC60850C46eE5b58B518daec95130";
|
|
4167
4350
|
var YIELDSEEKER_V1_IMPLEMENTATION = "0x32403455357589523435dB18b414057D7cE05051";
|
|
4168
4351
|
var YIELDSEEKER_V2_IMPLEMENTATION = "0x613Db9c924ADB7A7A90c11b02Cce20c913E3Fe50";
|
|
4169
4352
|
var ERC1967_IMPLEMENTATION_SLOT = "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc";
|
|
4170
|
-
var walletAbi = (0,
|
|
4353
|
+
var walletAbi = (0, import_viem11.parseAbi)([
|
|
4171
4354
|
"function owner() view returns (address)",
|
|
4172
4355
|
"function ownerAgentIndex() view returns (uint256)",
|
|
4173
4356
|
"function baseAsset() view returns (address)",
|
|
@@ -4175,7 +4358,7 @@ var walletAbi = (0, import_viem10.parseAbi)([
|
|
|
4175
4358
|
"function upgradeToLatest()",
|
|
4176
4359
|
"event Upgraded(address indexed implementation)"
|
|
4177
4360
|
]);
|
|
4178
|
-
var factoryAbi = (0,
|
|
4361
|
+
var factoryAbi = (0, import_viem11.parseAbi)([
|
|
4179
4362
|
"function userWallets(address owner, uint256 index) view returns (address)",
|
|
4180
4363
|
"function agentWalletImplementation() view returns (address)"
|
|
4181
4364
|
]);
|
|
@@ -4183,9 +4366,9 @@ function yieldseekerOwnerPath(code) {
|
|
|
4183
4366
|
return !code || code === "0x" || /^0xef0100[0-9a-f]{40}$/i.test(code) ? "eoa" : "smart";
|
|
4184
4367
|
}
|
|
4185
4368
|
async function readYieldseekerWalletStatus(client, wallet, owner, asset, blockNumber) {
|
|
4186
|
-
const agentWallet = (0,
|
|
4187
|
-
const expectedOwner = (0,
|
|
4188
|
-
const expectedAsset = (0,
|
|
4369
|
+
const agentWallet = (0, import_viem11.getAddress)(wallet);
|
|
4370
|
+
const expectedOwner = (0, import_viem11.getAddress)(owner);
|
|
4371
|
+
const expectedAsset = (0, import_viem11.getAddress)(asset);
|
|
4189
4372
|
const [code, ownerCode, slot, actualOwner, index, actualAsset, actualFactory, latest] = await Promise.all([
|
|
4190
4373
|
client.getBytecode({ address: agentWallet, blockNumber }),
|
|
4191
4374
|
client.getBytecode({ address: expectedOwner, blockNumber }),
|
|
@@ -4199,7 +4382,7 @@ async function readYieldseekerWalletStatus(client, wallet, owner, asset, blockNu
|
|
|
4199
4382
|
if (!code || code === "0x" || !slot || /^0x0+$/.test(slot)) {
|
|
4200
4383
|
throw new Error("Yieldseeker wallet is not a deployed ERC1967 proxy");
|
|
4201
4384
|
}
|
|
4202
|
-
const implementation = (0,
|
|
4385
|
+
const implementation = (0, import_viem11.getAddress)(`0x${slot.slice(-40)}`);
|
|
4203
4386
|
const mapped = await client.readContract({
|
|
4204
4387
|
address: YIELDSEEKER_FACTORY,
|
|
4205
4388
|
abi: factoryAbi,
|
|
@@ -4207,8 +4390,8 @@ async function readYieldseekerWalletStatus(client, wallet, owner, asset, blockNu
|
|
|
4207
4390
|
args: [expectedOwner, index],
|
|
4208
4391
|
blockNumber
|
|
4209
4392
|
});
|
|
4210
|
-
const verified = (0,
|
|
4211
|
-
const version = !verified ? "unknown" : (0,
|
|
4393
|
+
const verified = (0, import_viem11.isAddressEqual)(actualOwner, expectedOwner) && (0, import_viem11.isAddressEqual)(actualAsset, expectedAsset) && (0, import_viem11.isAddressEqual)(actualFactory, YIELDSEEKER_FACTORY) && (0, import_viem11.isAddressEqual)(mapped, agentWallet);
|
|
4394
|
+
const version = !verified ? "unknown" : (0, import_viem11.isAddressEqual)(implementation, YIELDSEEKER_V2_IMPLEMENTATION) ? "v2" : (0, import_viem11.isAddressEqual)(implementation, YIELDSEEKER_V1_IMPLEMENTATION) ? "v1" : "unknown";
|
|
4212
4395
|
return {
|
|
4213
4396
|
agentWallet,
|
|
4214
4397
|
owner: actualOwner,
|
|
@@ -4217,13 +4400,13 @@ async function readYieldseekerWalletStatus(client, wallet, owner, asset, blockNu
|
|
|
4217
4400
|
implementation,
|
|
4218
4401
|
version,
|
|
4219
4402
|
verified,
|
|
4220
|
-
upgradeAvailable: version === "v1" && (0,
|
|
4403
|
+
upgradeAvailable: version === "v1" && (0, import_viem11.isAddressEqual)(latest, YIELDSEEKER_V2_IMPLEMENTATION)
|
|
4221
4404
|
};
|
|
4222
4405
|
}
|
|
4223
4406
|
var YIELDSEEKER_UPGRADE_ABI = walletAbi;
|
|
4224
4407
|
|
|
4225
4408
|
// src/agents/yieldseeker/yieldseeker.sponsored-withdraw.ts
|
|
4226
|
-
var
|
|
4409
|
+
var import_viem12 = require("viem");
|
|
4227
4410
|
var import_account_abstraction2 = require("viem/account-abstraction");
|
|
4228
4411
|
var import_accounts = require("viem/accounts");
|
|
4229
4412
|
var import_chains3 = require("viem/chains");
|
|
@@ -4310,7 +4493,7 @@ function rpcDiagnostics(data) {
|
|
|
4310
4493
|
details.revertName = data.revertName;
|
|
4311
4494
|
if (typeof data?.aaCode === "string" && /^AA[0-9]{2}$/.test(data.aaCode)) details.aaCode = data.aaCode;
|
|
4312
4495
|
if (typeof data?.panicCode === "string" && /^0x[0-9a-fA-F]{1,2}$/.test(data.panicCode)) {
|
|
4313
|
-
const panicCode = (0,
|
|
4496
|
+
const panicCode = (0, import_viem12.toHex)(BigInt(data.panicCode));
|
|
4314
4497
|
if (["0x0", "0x1", "0x11", "0x12", "0x21", "0x22", "0x31", "0x32", "0x41", "0x51"].includes(panicCode))
|
|
4315
4498
|
details.panicCode = panicCode;
|
|
4316
4499
|
}
|
|
@@ -4530,14 +4713,14 @@ async function submitEoa(input) {
|
|
|
4530
4713
|
throw sponsorError("Base did not return EIP-1559 gas fees.", true);
|
|
4531
4714
|
let operation = {
|
|
4532
4715
|
sender: input.agentWallet,
|
|
4533
|
-
nonce: (0,
|
|
4716
|
+
nonce: (0, import_viem12.toHex)(nonce),
|
|
4534
4717
|
initCode: "0x",
|
|
4535
4718
|
callData: input.callData,
|
|
4536
|
-
callGasLimit: (0,
|
|
4537
|
-
verificationGasLimit: (0,
|
|
4538
|
-
preVerificationGas: (0,
|
|
4539
|
-
maxFeePerGas: (0,
|
|
4540
|
-
maxPriorityFeePerGas: (0,
|
|
4719
|
+
callGasLimit: (0, import_viem12.toHex)(3e5),
|
|
4720
|
+
verificationGasLimit: (0, import_viem12.toHex)(3e5),
|
|
4721
|
+
preVerificationGas: (0, import_viem12.toHex)(6e4),
|
|
4722
|
+
maxFeePerGas: (0, import_viem12.toHex)(fees.maxFeePerGas * USER_OP_FEE_HEADROOM),
|
|
4723
|
+
maxPriorityFeePerGas: (0, import_viem12.toHex)(fees.maxPriorityFeePerGas),
|
|
4541
4724
|
paymasterAndData: "0x",
|
|
4542
4725
|
signature: "0x"
|
|
4543
4726
|
};
|
|
@@ -4545,7 +4728,7 @@ async function submitEoa(input) {
|
|
|
4545
4728
|
const stub = await rpc(
|
|
4546
4729
|
input.rpcUrl,
|
|
4547
4730
|
"pm_getPaymasterStubData",
|
|
4548
|
-
[operation, ENTRY_POINT_V06, (0,
|
|
4731
|
+
[operation, ENTRY_POINT_V06, (0, import_viem12.toHex)(8453), {}],
|
|
4549
4732
|
"prepare"
|
|
4550
4733
|
);
|
|
4551
4734
|
if (!stub.paymasterAndData?.startsWith("0x"))
|
|
@@ -4560,7 +4743,7 @@ async function submitEoa(input) {
|
|
|
4560
4743
|
const final = await rpc(
|
|
4561
4744
|
input.rpcUrl,
|
|
4562
4745
|
"pm_getPaymasterData",
|
|
4563
|
-
[operation, ENTRY_POINT_V06, (0,
|
|
4746
|
+
[operation, ENTRY_POINT_V06, (0, import_viem12.toHex)(8453), {}],
|
|
4564
4747
|
"prepare"
|
|
4565
4748
|
);
|
|
4566
4749
|
if (!final.paymasterAndData?.startsWith("0x"))
|
|
@@ -4570,10 +4753,10 @@ async function submitEoa(input) {
|
|
|
4570
4753
|
const userOpHash = operationHash(operation);
|
|
4571
4754
|
await assertOwnerSession(input.state, input.owner);
|
|
4572
4755
|
assertIntentFresh(input.expiresAt);
|
|
4573
|
-
const wallet = (0,
|
|
4756
|
+
const wallet = (0, import_viem12.createWalletClient)({
|
|
4574
4757
|
account: input.owner,
|
|
4575
4758
|
chain: import_chains3.base,
|
|
4576
|
-
transport: (0,
|
|
4759
|
+
transport: (0, import_viem12.custom)(input.state.provider)
|
|
4577
4760
|
});
|
|
4578
4761
|
const signature = await wallet.signMessage({ message: { raw: userOpHash } });
|
|
4579
4762
|
operation = { ...operation, signature };
|
|
@@ -4651,13 +4834,13 @@ async function submitSmart(input) {
|
|
|
4651
4834
|
} catch {
|
|
4652
4835
|
throw sponsorError("This account cannot check paymaster support on Base.", true);
|
|
4653
4836
|
}
|
|
4654
|
-
const supportsPaymaster = capabilities?.[(0,
|
|
4837
|
+
const supportsPaymaster = capabilities?.[(0, import_viem12.toHex)(8453)]?.paymasterService?.supported ?? capabilities?.["8453"]?.paymasterService?.supported ?? capabilities?.["0x0"]?.paymasterService?.supported;
|
|
4655
4838
|
if (supportsPaymaster !== true)
|
|
4656
4839
|
throw sponsorError("This account cannot use a paymaster on Base.", true);
|
|
4657
4840
|
await assertOwnerSession(input.state, input.owner);
|
|
4658
4841
|
let sent;
|
|
4659
4842
|
assertIntentFresh(input.expiresAt);
|
|
4660
|
-
const requestedId = (0,
|
|
4843
|
+
const requestedId = (0, import_viem12.toHex)(globalThis.crypto.getRandomValues(new Uint8Array(32)));
|
|
4661
4844
|
savePending(input.onPending, { callsId: requestedId }, true);
|
|
4662
4845
|
await checkpoint(input.onBeforeSubmission, { callsId: requestedId });
|
|
4663
4846
|
try {
|
|
@@ -4666,7 +4849,7 @@ async function submitSmart(input) {
|
|
|
4666
4849
|
params: [{
|
|
4667
4850
|
version: "2.0.0",
|
|
4668
4851
|
from: input.owner,
|
|
4669
|
-
chainId: (0,
|
|
4852
|
+
chainId: (0, import_viem12.toHex)(8453),
|
|
4670
4853
|
id: requestedId,
|
|
4671
4854
|
atomicRequired: false,
|
|
4672
4855
|
calls: [{ to: input.agentWallet, value: "0x0", data: input.callData }],
|
|
@@ -4741,7 +4924,7 @@ async function submitSmart(input) {
|
|
|
4741
4924
|
);
|
|
4742
4925
|
}
|
|
4743
4926
|
async function submitYieldseekerSponsoredWithdrawal(input) {
|
|
4744
|
-
const owner = (0,
|
|
4927
|
+
const owner = (0, import_viem12.getAddress)(input.state.walletAddress);
|
|
4745
4928
|
const { intent, rpcUrl } = await requestIntent({
|
|
4746
4929
|
apiKey: input.apiKey,
|
|
4747
4930
|
routingApiBaseUrl: input.routingApiBaseUrl,
|
|
@@ -4760,7 +4943,7 @@ async function submitYieldseekerSponsoredWithdrawal(input) {
|
|
|
4760
4943
|
return intent.ownerPath === "eoa" ? submitEoa(args) : submitSmart(args);
|
|
4761
4944
|
}
|
|
4762
4945
|
async function submitYieldseekerSponsoredUpgrade(input) {
|
|
4763
|
-
const owner = (0,
|
|
4946
|
+
const owner = (0, import_viem12.getAddress)(input.state.walletAddress);
|
|
4764
4947
|
const { intent, rpcUrl } = await requestIntent({
|
|
4765
4948
|
apiKey: input.apiKey,
|
|
4766
4949
|
routingApiBaseUrl: input.routingApiBaseUrl,
|
|
@@ -4875,6 +5058,7 @@ var YieldseekerAgent = class {
|
|
|
4875
5058
|
receiptClient;
|
|
4876
5059
|
// A client preparation hint only; the routing API still checks live identity.
|
|
4877
5060
|
withdrawalVersionCache = /* @__PURE__ */ new Map();
|
|
5061
|
+
pendingUpgrades = /* @__PURE__ */ new Map();
|
|
4878
5062
|
transactionExecutor;
|
|
4879
5063
|
unwindReceiptWaiter;
|
|
4880
5064
|
agentContexts = /* @__PURE__ */ new Map();
|
|
@@ -4925,8 +5109,8 @@ var YieldseekerAgent = class {
|
|
|
4925
5109
|
if (useCachedV2 && cached && Date.now() - cached.at < 15 * 6e4) return { ...cached.status };
|
|
4926
5110
|
const status = await readYieldseekerWalletStatus(
|
|
4927
5111
|
this.getReceiptClient(),
|
|
4928
|
-
(0,
|
|
4929
|
-
(0,
|
|
5112
|
+
(0, import_viem13.getAddress)(context.wallet.walletAddress),
|
|
5113
|
+
(0, import_viem13.getAddress)(state.walletAddress),
|
|
4930
5114
|
YIELDSEEKER_ASSET_METADATA[asset].address
|
|
4931
5115
|
);
|
|
4932
5116
|
this.rememberWalletStatus(key2, status);
|
|
@@ -4956,12 +5140,12 @@ var YieldseekerAgent = class {
|
|
|
4956
5140
|
const pendingKey2 = `owney.yieldseeker.upgrade:${before.owner.toLowerCase()}:${before.agentWallet.toLowerCase()}`;
|
|
4957
5141
|
const confirmUpgrade = async (hash, receipt2) => {
|
|
4958
5142
|
this.withdrawalVersionCache.delete(versionKey);
|
|
4959
|
-
const upgradeTopic = (0,
|
|
5143
|
+
const upgradeTopic = (0, import_viem13.encodeEventTopics)({ abi: YIELDSEEKER_UPGRADE_ABI, eventName: "Upgraded" })[0];
|
|
4960
5144
|
const lastUpgrade = receipt2?.logs.filter((log) => log.address.toLowerCase() === before.agentWallet.toLowerCase() && log.topics[0] === upgradeTopic).at(-1);
|
|
4961
5145
|
const expectedUpgrade = (() => {
|
|
4962
5146
|
if (!lastUpgrade || lastUpgrade.removed) return false;
|
|
4963
5147
|
try {
|
|
4964
|
-
const event = (0,
|
|
5148
|
+
const event = (0, import_viem13.decodeEventLog)({ abi: YIELDSEEKER_UPGRADE_ABI, eventName: "Upgraded", data: lastUpgrade.data, topics: lastUpgrade.topics });
|
|
4965
5149
|
return event.args.implementation.toLowerCase() === YIELDSEEKER_V2_IMPLEMENTATION.toLowerCase();
|
|
4966
5150
|
} catch {
|
|
4967
5151
|
return false;
|
|
@@ -4990,10 +5174,30 @@ var YieldseekerAgent = class {
|
|
|
4990
5174
|
} catch {
|
|
4991
5175
|
storage5 = void 0;
|
|
4992
5176
|
}
|
|
4993
|
-
const
|
|
5177
|
+
const clearRecordedUpgrade = () => {
|
|
5178
|
+
this.pendingUpgrades.delete(pendingKey2);
|
|
4994
5179
|
try {
|
|
4995
5180
|
storage5?.removeItem(pendingKey2);
|
|
4996
5181
|
} catch {
|
|
5182
|
+
this.pendingUpgrades.set(pendingKey2, null);
|
|
5183
|
+
}
|
|
5184
|
+
};
|
|
5185
|
+
const pendingUpgrade = (hash) => new OwneyError(
|
|
5186
|
+
"WITHDRAW_IN_PROGRESS",
|
|
5187
|
+
"Yieldseeker wallet upgrade is awaiting confirmation. Retry to check its status.",
|
|
5188
|
+
{ txHash: hash, reason: "UPGRADE_CONFIRMATION_PENDING", phase: "observe", safeToFallback: false },
|
|
5189
|
+
this.id
|
|
5190
|
+
);
|
|
5191
|
+
const terminalUpgradeFailure = (error) => error instanceof OwneyError && (error.code === "AGENT_TRANSACTION_REVERTED" || error.details?.reason === "TRANSACTION_REPLACED_WITH_DIFFERENT_CALL");
|
|
5192
|
+
const readUpgradeReceipt = async (hash) => {
|
|
5193
|
+
try {
|
|
5194
|
+
return await this.waitForReceipt(state, chainId, hash);
|
|
5195
|
+
} catch (error) {
|
|
5196
|
+
if (terminalUpgradeFailure(error)) {
|
|
5197
|
+
clearRecordedUpgrade();
|
|
5198
|
+
throw error;
|
|
5199
|
+
}
|
|
5200
|
+
throw pendingUpgrade(hash);
|
|
4997
5201
|
}
|
|
4998
5202
|
};
|
|
4999
5203
|
if (!storage5 && (gasMode === "sponsored" || before.ownerPath === "smart"))
|
|
@@ -5005,7 +5209,7 @@ var YieldseekerAgent = class {
|
|
|
5005
5209
|
);
|
|
5006
5210
|
let prior = null;
|
|
5007
5211
|
try {
|
|
5008
|
-
const saved = storage5?.getItem(pendingKey2);
|
|
5212
|
+
const saved = this.pendingUpgrades.has(pendingKey2) ? JSON.stringify(this.pendingUpgrades.get(pendingKey2)) : storage5?.getItem(pendingKey2);
|
|
5009
5213
|
try {
|
|
5010
5214
|
prior = JSON.parse(saved ?? "null");
|
|
5011
5215
|
} catch {
|
|
@@ -5049,7 +5253,7 @@ var YieldseekerAgent = class {
|
|
|
5049
5253
|
this.id
|
|
5050
5254
|
);
|
|
5051
5255
|
if (Number(callsStatus?.status) === 400 || Number(callsStatus?.status) === 500) {
|
|
5052
|
-
|
|
5256
|
+
clearRecordedUpgrade();
|
|
5053
5257
|
throw new OwneyError(
|
|
5054
5258
|
"SPONSOR_REQUEST_FAILED",
|
|
5055
5259
|
"The earlier sponsored upgrade failed.",
|
|
@@ -5061,8 +5265,8 @@ var YieldseekerAgent = class {
|
|
|
5061
5265
|
earlierHash = hashes.length === 1 ? hashes[0] : void 0;
|
|
5062
5266
|
}
|
|
5063
5267
|
if (earlierHash) {
|
|
5064
|
-
const recovered = await confirmUpgrade(earlierHash, await
|
|
5065
|
-
|
|
5268
|
+
const recovered = await confirmUpgrade(earlierHash, await readUpgradeReceipt(earlierHash));
|
|
5269
|
+
clearRecordedUpgrade();
|
|
5066
5270
|
return recovered;
|
|
5067
5271
|
}
|
|
5068
5272
|
throw new OwneyError(
|
|
@@ -5079,7 +5283,7 @@ var YieldseekerAgent = class {
|
|
|
5079
5283
|
{ version: before.version },
|
|
5080
5284
|
this.id
|
|
5081
5285
|
);
|
|
5082
|
-
const data = (0,
|
|
5286
|
+
const data = (0, import_viem13.encodeFunctionData)({ abi: YIELDSEEKER_UPGRADE_ABI, functionName: "upgradeToLatest" });
|
|
5083
5287
|
let txHash;
|
|
5084
5288
|
let receipt;
|
|
5085
5289
|
if (gasMode === "sponsored") {
|
|
@@ -5106,33 +5310,52 @@ var YieldseekerAgent = class {
|
|
|
5106
5310
|
asset: YIELDSEEKER_ASSET_METADATA[asset].address,
|
|
5107
5311
|
callData: data,
|
|
5108
5312
|
onPending: (pending) => {
|
|
5109
|
-
const current = storage5.getItem(pendingKey2);
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
...pending
|
|
5114
|
-
}));
|
|
5313
|
+
const current = this.pendingUpgrades.has(pendingKey2) ? this.pendingUpgrades.get(pendingKey2) : JSON.parse(storage5.getItem(pendingKey2) ?? "null");
|
|
5314
|
+
const next = { startedAt: Date.now(), ...current, ...pending };
|
|
5315
|
+
storage5.setItem(pendingKey2, JSON.stringify(next));
|
|
5316
|
+
this.pendingUpgrades.delete(pendingKey2);
|
|
5115
5317
|
}
|
|
5116
5318
|
});
|
|
5117
5319
|
txHash = upgraded.txHash;
|
|
5118
5320
|
receipt = upgraded.receipt;
|
|
5119
5321
|
} catch (error) {
|
|
5120
|
-
if (error?.code === 4001 || error instanceof OwneyError && error.code === "SPONSOR_REQUEST_FAILED" && (error.details?.safeToFallback === true || error.details?.executionFailed === true))
|
|
5322
|
+
if (error?.code === 4001 || terminalUpgradeFailure(error) || error instanceof OwneyError && error.code === "SPONSOR_REQUEST_FAILED" && (error.details?.safeToFallback === true || error.details?.executionFailed === true)) clearRecordedUpgrade();
|
|
5121
5323
|
throw error;
|
|
5122
5324
|
}
|
|
5123
5325
|
} else {
|
|
5124
|
-
|
|
5125
|
-
|
|
5126
|
-
|
|
5127
|
-
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
|
|
5326
|
+
let submittedHash;
|
|
5327
|
+
try {
|
|
5328
|
+
txHash = await this.submitTransaction(state, chainId, {
|
|
5329
|
+
from: (0, import_viem13.getAddress)(state.walletAddress),
|
|
5330
|
+
to: before.agentWallet,
|
|
5331
|
+
data,
|
|
5332
|
+
value: "0",
|
|
5333
|
+
chainId
|
|
5334
|
+
}, (hash) => {
|
|
5335
|
+
submittedHash = hash;
|
|
5336
|
+
const pending = { txHash: hash };
|
|
5337
|
+
this.pendingUpgrades.set(pendingKey2, pending);
|
|
5338
|
+
try {
|
|
5339
|
+
if (storage5) {
|
|
5340
|
+
storage5.setItem(pendingKey2, JSON.stringify(pending));
|
|
5341
|
+
this.pendingUpgrades.delete(pendingKey2);
|
|
5342
|
+
}
|
|
5343
|
+
} catch {
|
|
5344
|
+
}
|
|
5345
|
+
}, (value) => {
|
|
5346
|
+
receipt = value;
|
|
5347
|
+
});
|
|
5348
|
+
} catch (error) {
|
|
5349
|
+
if (terminalUpgradeFailure(error)) {
|
|
5350
|
+
clearRecordedUpgrade();
|
|
5351
|
+
throw error;
|
|
5352
|
+
}
|
|
5353
|
+
if (submittedHash) throw pendingUpgrade(submittedHash);
|
|
5354
|
+
throw error;
|
|
5355
|
+
}
|
|
5133
5356
|
}
|
|
5134
|
-
const confirmed = await confirmUpgrade(txHash, receipt ?? await
|
|
5135
|
-
|
|
5357
|
+
const confirmed = await confirmUpgrade(txHash, receipt ?? await readUpgradeReceipt(txHash));
|
|
5358
|
+
clearRecordedUpgrade();
|
|
5136
5359
|
return confirmed;
|
|
5137
5360
|
}
|
|
5138
5361
|
async disconnect() {
|
|
@@ -5209,12 +5432,12 @@ var YieldseekerAgent = class {
|
|
|
5209
5432
|
} else {
|
|
5210
5433
|
try {
|
|
5211
5434
|
txHash = await this.submitTransaction(state, chainId, {
|
|
5212
|
-
from: (0,
|
|
5435
|
+
from: (0, import_viem13.getAddress)(state.walletAddress),
|
|
5213
5436
|
to: YIELDSEEKER_ASSET_METADATA[asset].address,
|
|
5214
|
-
data: (0,
|
|
5215
|
-
abi:
|
|
5437
|
+
data: (0, import_viem13.encodeFunctionData)({
|
|
5438
|
+
abi: import_viem13.erc20Abi,
|
|
5216
5439
|
functionName: "transfer",
|
|
5217
|
-
args: [(0,
|
|
5440
|
+
args: [(0, import_viem13.getAddress)(context.wallet.walletAddress), BigInt(amount)]
|
|
5218
5441
|
}),
|
|
5219
5442
|
value: "0",
|
|
5220
5443
|
chainId
|
|
@@ -5348,7 +5571,7 @@ var YieldseekerAgent = class {
|
|
|
5348
5571
|
);
|
|
5349
5572
|
const positionsRead = this.readWithdrawalPositions(state, chainId, context);
|
|
5350
5573
|
const metadata = YIELDSEEKER_ASSET_METADATA[asset];
|
|
5351
|
-
const agentWallet = (0,
|
|
5574
|
+
const agentWallet = (0, import_viem13.getAddress)(context.wallet.walletAddress);
|
|
5352
5575
|
const readOwnerFunds = async (blockNumber) => {
|
|
5353
5576
|
const feeTracker = await withPaidRpcDiagnostics(() => this.getReceiptClient().readContract({
|
|
5354
5577
|
address: agentWallet,
|
|
@@ -5357,18 +5580,18 @@ var YieldseekerAgent = class {
|
|
|
5357
5580
|
blockNumber
|
|
5358
5581
|
}), chainId, "eth_call", this.id);
|
|
5359
5582
|
this.assertSession(generation, chainId, asset);
|
|
5360
|
-
if (!(0,
|
|
5583
|
+
if (!(0, import_viem13.isAddress)(feeTracker) || /^0x0{40}$/i.test(feeTracker))
|
|
5361
5584
|
throw this.invalidResponse("wallet fee tracker");
|
|
5362
5585
|
const [idle2, fees] = await Promise.all([
|
|
5363
5586
|
withPaidRpcDiagnostics(() => this.getReceiptClient().readContract({
|
|
5364
5587
|
address: metadata.address,
|
|
5365
|
-
abi:
|
|
5588
|
+
abi: import_viem13.erc20Abi,
|
|
5366
5589
|
functionName: "balanceOf",
|
|
5367
5590
|
args: [agentWallet],
|
|
5368
5591
|
blockNumber
|
|
5369
5592
|
}), chainId, "eth_call", this.id),
|
|
5370
5593
|
withPaidRpcDiagnostics(() => this.getReceiptClient().readContract({
|
|
5371
|
-
address: (0,
|
|
5594
|
+
address: (0, import_viem13.getAddress)(feeTracker),
|
|
5372
5595
|
abi: YIELDSEEKER_FEE_TRACKER_ABI,
|
|
5373
5596
|
functionName: "getFeesOwed",
|
|
5374
5597
|
args: [agentWallet],
|
|
@@ -5410,13 +5633,13 @@ var YieldseekerAgent = class {
|
|
|
5410
5633
|
let active = true;
|
|
5411
5634
|
const checks = this.readVaultLiquidity(values.map((position2) => position2.yieldOption), agentWallet, blockNumber).catch(() => []);
|
|
5412
5635
|
const reads = values.map(async (position2, index) => {
|
|
5413
|
-
const address = (0,
|
|
5636
|
+
const address = (0, import_viem13.getAddress)(position2.yieldOption.address);
|
|
5414
5637
|
try {
|
|
5415
5638
|
const group = (await checks).slice(index * 3, index * 3 + 3);
|
|
5416
5639
|
if (!active || group.length !== 3 || group.some((value) => value.status !== "success")) return null;
|
|
5417
5640
|
this.assertSession(generation, chainId, asset);
|
|
5418
5641
|
const [underlying, shares, withdrawable] = group.map((value) => value.result);
|
|
5419
|
-
if (typeof underlying !== "string" || !(0,
|
|
5642
|
+
if (typeof underlying !== "string" || !(0, import_viem13.isAddress)(underlying) || underlying.toLowerCase() !== metadata.address.toLowerCase() || typeof shares !== "bigint" || shares < 0n || typeof withdrawable !== "bigint" || withdrawable < 0n) return null;
|
|
5420
5643
|
const verified = { ...position2, assetsRaw: shares.toString(), withdrawableAssetsRaw: withdrawable.toString() };
|
|
5421
5644
|
if (shares > 0n && withdrawable === 0n) {
|
|
5422
5645
|
let positiveValue = false;
|
|
@@ -5424,7 +5647,7 @@ var YieldseekerAgent = class {
|
|
|
5424
5647
|
try {
|
|
5425
5648
|
const value = await this.getReceiptClient().readContract({
|
|
5426
5649
|
address,
|
|
5427
|
-
abi:
|
|
5650
|
+
abi: import_viem13.erc4626Abi,
|
|
5428
5651
|
functionName,
|
|
5429
5652
|
args: [shares],
|
|
5430
5653
|
blockNumber
|
|
@@ -5514,6 +5737,18 @@ var YieldseekerAgent = class {
|
|
|
5514
5737
|
);
|
|
5515
5738
|
}
|
|
5516
5739
|
if (requested > totalAvailable) {
|
|
5740
|
+
if (!funds.complete)
|
|
5741
|
+
throw new OwneyError(
|
|
5742
|
+
"WITHDRAW_BALANCE_UNAVAILABLE",
|
|
5743
|
+
"Yieldseeker withdrawal liquidity could not be verified for the requested amount.",
|
|
5744
|
+
{
|
|
5745
|
+
asset,
|
|
5746
|
+
requested: requested.toString(),
|
|
5747
|
+
verifiedAvailable: totalAvailable.toString(),
|
|
5748
|
+
reason: "YIELDSEEKER_LIQUIDITY_UNVERIFIED"
|
|
5749
|
+
},
|
|
5750
|
+
this.id
|
|
5751
|
+
);
|
|
5517
5752
|
throw new OwneyError(
|
|
5518
5753
|
"WITHDRAW_INSUFFICIENT_BALANCE",
|
|
5519
5754
|
`Requested withdrawal "${requested}" exceeds available Yieldseeker balance "${totalAvailable}" for asset "${asset}".`,
|
|
@@ -5528,6 +5763,7 @@ var YieldseekerAgent = class {
|
|
|
5528
5763
|
const requiredIdle = requested + initialFunds.fees;
|
|
5529
5764
|
let remaining = requiredIdle > idle ? requiredIdle - idle : 0n;
|
|
5530
5765
|
let grossUnwound = 0n;
|
|
5766
|
+
let confirmedUnwinds = 0n;
|
|
5531
5767
|
let latestUnwindBlock;
|
|
5532
5768
|
const unwind = async (position2, assetsRaw) => {
|
|
5533
5769
|
this.assertSession(generation, chainId, asset);
|
|
@@ -5545,7 +5781,10 @@ var YieldseekerAgent = class {
|
|
|
5545
5781
|
if (!this.isTransactionHash(response?.transactionHash)) throw this.invalidResponse("position withdrawal");
|
|
5546
5782
|
unwindTransactionHash = response.transactionHash;
|
|
5547
5783
|
const unwindReceipt = await this.waitForReceipt(state, chainId, unwindTransactionHash);
|
|
5548
|
-
if (unwindReceipt)
|
|
5784
|
+
if (unwindReceipt) {
|
|
5785
|
+
latestUnwindBlock = unwindReceipt.blockNumber;
|
|
5786
|
+
confirmedUnwinds++;
|
|
5787
|
+
}
|
|
5549
5788
|
} catch (error) {
|
|
5550
5789
|
this.invalidateFundingRead(state, chainId, asset);
|
|
5551
5790
|
throw new OwneyError(
|
|
@@ -5615,7 +5854,7 @@ var YieldseekerAgent = class {
|
|
|
5615
5854
|
const feeRate = feeRateBps ?? 0;
|
|
5616
5855
|
const maxFee = confirmedMovement && Number.isInteger(feeRate) && feeRate >= 0 && feeRate <= 1e3 ? (grossUnwound * BigInt(feeRate) + 9999n) / 10000n : 0n;
|
|
5617
5856
|
const shortfall = availableForOwner < requested ? requested - availableForOwner : 0n;
|
|
5618
|
-
if (availableForOwner === 0n || amount !== void 0 && shortfall > maxFee) {
|
|
5857
|
+
if (availableForOwner === 0n || amount !== void 0 && shortfall > maxFee + confirmedUnwinds) {
|
|
5619
5858
|
this.invalidateFundingRead(state, chainId, asset);
|
|
5620
5859
|
if (amount === void 0 && positionsStatus !== "empty")
|
|
5621
5860
|
throw new OwneyError(
|
|
@@ -5637,14 +5876,15 @@ var YieldseekerAgent = class {
|
|
|
5637
5876
|
delta: maxSettlementBasis.delta - payout,
|
|
5638
5877
|
expectedNetDeposits: maxSettlementBasis.expectedNetDeposits - payout
|
|
5639
5878
|
} : this.snapshotMovement(state, chainId, context, -payout);
|
|
5640
|
-
const account = (0,
|
|
5879
|
+
const account = (0, import_viem13.getAddress)(state.walletAddress);
|
|
5641
5880
|
let receipt;
|
|
5642
|
-
const base6 = { agentId: this.id, chainId, token: asset, walletAddress: state.walletAddress, agentWallet: context.wallet.walletAddress, intendedAmount: amount
|
|
5643
|
-
|
|
5881
|
+
const base6 = { agentId: this.id, chainId, token: asset, walletAddress: state.walletAddress, agentWallet: context.wallet.walletAddress, intendedAmount: amount ?? "MAX", transfer: "pending", registration: "not-applicable", delivery: "pending" };
|
|
5882
|
+
let submissionEvidence = base6;
|
|
5883
|
+
const data = amount === void 0 ? (0, import_viem13.encodeFunctionData)({
|
|
5644
5884
|
abi: YIELDSEEKER_AGENT_WALLET_ABI,
|
|
5645
5885
|
functionName: "withdrawAllAssetToUser",
|
|
5646
5886
|
args: [account, metadata.address]
|
|
5647
|
-
}) : (0,
|
|
5887
|
+
}) : (0, import_viem13.encodeFunctionData)({
|
|
5648
5888
|
abi: YIELDSEEKER_AGENT_WALLET_ABI,
|
|
5649
5889
|
functionName: "withdrawAssetToUser",
|
|
5650
5890
|
args: [account, metadata.address, payout]
|
|
@@ -5660,10 +5900,13 @@ var YieldseekerAgent = class {
|
|
|
5660
5900
|
refreshYieldseekerSignature: (rejected) => this.auth.refreshToken(state, chainId, rejected),
|
|
5661
5901
|
userId: context.user.userId,
|
|
5662
5902
|
agentId: context.agent.agentId,
|
|
5663
|
-
agentWallet: (0,
|
|
5903
|
+
agentWallet: (0, import_viem13.getAddress)(context.wallet.walletAddress),
|
|
5664
5904
|
asset: metadata.address,
|
|
5665
5905
|
callData: data,
|
|
5666
|
-
onPending: (pending) =>
|
|
5906
|
+
onPending: (pending) => {
|
|
5907
|
+
submissionEvidence = { ...submissionEvidence, ...pending };
|
|
5908
|
+
notifyFunding(onProgress, submissionEvidence);
|
|
5909
|
+
},
|
|
5667
5910
|
onBeforeSubmission: async (pending) => {
|
|
5668
5911
|
await onBeforeSubmission?.({ ...base6, ...pending });
|
|
5669
5912
|
onOwnerTransferAttempted?.();
|
|
@@ -5675,7 +5918,7 @@ var YieldseekerAgent = class {
|
|
|
5675
5918
|
onOwnerTransferAttempted?.();
|
|
5676
5919
|
txHash = await this.submitTransaction(state, chainId, {
|
|
5677
5920
|
from: account,
|
|
5678
|
-
to: (0,
|
|
5921
|
+
to: (0, import_viem13.getAddress)(context.wallet.walletAddress),
|
|
5679
5922
|
data,
|
|
5680
5923
|
value: "0",
|
|
5681
5924
|
chainId
|
|
@@ -5683,10 +5926,20 @@ var YieldseekerAgent = class {
|
|
|
5683
5926
|
receipt = value;
|
|
5684
5927
|
});
|
|
5685
5928
|
}
|
|
5686
|
-
|
|
5687
|
-
settlement = plannedMovement;
|
|
5688
|
-
const evidence = receipt ? inspectFundingReceipt(receipt, { ...base6, txHash }, metadata.address, "withdraw") : { ...base6, txHash, confirmedAmount: payout.toString(), transfer: "confirmed", delivery: "confirmed" };
|
|
5929
|
+
const evidence = receipt ? inspectFundingReceipt(receipt, { ...submissionEvidence, txHash }, metadata.address, "withdraw") : { ...submissionEvidence, txHash, transfer: "pending", delivery: "pending" };
|
|
5689
5930
|
notifyFunding(onProgress, evidence);
|
|
5931
|
+
const explicitEmptyPayout = evidence.transfer === "failed" && evidence.confirmedAmount === "0" && evidence.transferLogs?.some((log) => log.amountRaw === "0");
|
|
5932
|
+
if (evidence.transfer === "failed" && !explicitEmptyPayout)
|
|
5933
|
+
throw new OwneyError(
|
|
5934
|
+
"AGENT_TRANSACTION_REVERTED",
|
|
5935
|
+
"The Yieldseeker withdrawal completed without transferring funds.",
|
|
5936
|
+
{ asset, available: "0", txHash },
|
|
5937
|
+
this.id
|
|
5938
|
+
);
|
|
5939
|
+
if (!explicitEmptyPayout && (evidence.transfer !== "confirmed" || evidence.delivery !== "confirmed" || !evidence.confirmedAmount))
|
|
5940
|
+
return { txHash, type: "partial", completion: "unverified", amount: "0", evidence };
|
|
5941
|
+
confirmedMovement = true;
|
|
5942
|
+
settlement = evidence.confirmedAmount === payout.toString() ? plannedMovement : null;
|
|
5690
5943
|
let completion = maxLiquidity && !maxLiquidity.complete ? "unverified" : void 0;
|
|
5691
5944
|
if (amount === void 0) {
|
|
5692
5945
|
const verificationDeadline = Date.now() + YIELDSEEKER_MAX_POSITION_VERIFICATION_MS;
|
|
@@ -5707,7 +5960,7 @@ var YieldseekerAgent = class {
|
|
|
5707
5960
|
positions = proof.positions;
|
|
5708
5961
|
positionsStatus = hasPositions(positions) ? "remaining" : proof.verified ? "empty" : "unavailable";
|
|
5709
5962
|
if (positionsStatus === "remaining") {
|
|
5710
|
-
const result = { txHash, type: "partial", amount: evidence.confirmedAmount ??
|
|
5963
|
+
const result = { txHash, type: "partial", amount: evidence.confirmedAmount ?? "0", evidence };
|
|
5711
5964
|
throw new OwneyError(
|
|
5712
5965
|
"WITHDRAW_PARTIAL_FAILURE",
|
|
5713
5966
|
"Yieldseeker MAX could not confirm that all vault positions were cleared.",
|
|
@@ -5727,7 +5980,7 @@ var YieldseekerAgent = class {
|
|
|
5727
5980
|
}
|
|
5728
5981
|
if (!proof.verified) completion = "unverified";
|
|
5729
5982
|
}
|
|
5730
|
-
if (
|
|
5983
|
+
if (explicitEmptyPayout)
|
|
5731
5984
|
throw new OwneyError(
|
|
5732
5985
|
"WITHDRAW_INSUFFICIENT_BALANCE",
|
|
5733
5986
|
"The Yieldseeker withdrawal completed without transferring funds.",
|
|
@@ -5742,7 +5995,7 @@ var YieldseekerAgent = class {
|
|
|
5742
5995
|
type: amount === void 0 && !completion ? "full" : "partial",
|
|
5743
5996
|
...completion ? { completion } : {},
|
|
5744
5997
|
...feeAdjustment ? { feeAdjustment } : {},
|
|
5745
|
-
amount: evidence.confirmedAmount ??
|
|
5998
|
+
amount: evidence.confirmedAmount ?? "0",
|
|
5746
5999
|
evidence
|
|
5747
6000
|
};
|
|
5748
6001
|
} finally {
|
|
@@ -5783,17 +6036,17 @@ var YieldseekerAgent = class {
|
|
|
5783
6036
|
return proof.available;
|
|
5784
6037
|
}
|
|
5785
6038
|
async readVaultLiquidity(options, wallet, blockNumber) {
|
|
5786
|
-
const owner = (0,
|
|
6039
|
+
const owner = (0, import_viem13.getAddress)(wallet);
|
|
5787
6040
|
const batches = Array.from({ length: Math.ceil(options.length / YIELDSEEKER_VAULTS_PER_RPC_BATCH) }, (_, index) => options.slice(index * YIELDSEEKER_VAULTS_PER_RPC_BATCH, (index + 1) * YIELDSEEKER_VAULTS_PER_RPC_BATCH));
|
|
5788
6041
|
const results = await Promise.all(batches.map((batch) => this.getReceiptClient().multicall({
|
|
5789
6042
|
blockNumber,
|
|
5790
6043
|
allowFailure: true,
|
|
5791
6044
|
contracts: batch.flatMap((option) => {
|
|
5792
|
-
const address = (0,
|
|
6045
|
+
const address = (0, import_viem13.getAddress)(option.address);
|
|
5793
6046
|
return [
|
|
5794
|
-
{ address, abi:
|
|
5795
|
-
{ address, abi:
|
|
5796
|
-
{ address, abi:
|
|
6047
|
+
{ address, abi: import_viem13.erc4626Abi, functionName: "asset" },
|
|
6048
|
+
{ address, abi: import_viem13.erc20Abi, functionName: "balanceOf", args: [owner] },
|
|
6049
|
+
{ address, abi: import_viem13.erc4626Abi, functionName: "maxWithdraw", args: [owner] }
|
|
5797
6050
|
];
|
|
5798
6051
|
})
|
|
5799
6052
|
})));
|
|
@@ -5804,7 +6057,7 @@ var YieldseekerAgent = class {
|
|
|
5804
6057
|
const seen = /* @__PURE__ */ new Set();
|
|
5805
6058
|
for (const value of values) {
|
|
5806
6059
|
const option = value?.yieldOption;
|
|
5807
|
-
if (!option || typeof option.address !== "string" || !(0,
|
|
6060
|
+
if (!option || typeof option.address !== "string" || !(0, import_viem13.isAddress)(option.address) || seen.has(option.address.toLowerCase()) || option.chainId !== void 0 && option.chainId !== chainId || option.assetAddress !== void 0 && (typeof option.assetAddress !== "string" || option.assetAddress.toLowerCase() !== underlying) || typeof value.assetsRaw !== "string" || !/^\d+$/.test(value.assetsRaw) || typeof value.withdrawableAssetsRaw !== "string" || !/^\d+$/.test(value.withdrawableAssetsRaw))
|
|
5808
6061
|
throw this.invalidResponse("yield positions");
|
|
5809
6062
|
seen.add(option.address.toLowerCase());
|
|
5810
6063
|
}
|
|
@@ -5817,7 +6070,7 @@ var YieldseekerAgent = class {
|
|
|
5817
6070
|
const historic = this.readCache.get(`historic:${key2}`)?.value?.position;
|
|
5818
6071
|
const receivedAssets = new Set((historic?.movements ?? []).filter((movement) => movement.chainId === chainId && movement.agentWalletId === context.wallet.agentWalletId && movement.toAddress?.toLowerCase() === context.wallet.walletAddress.toLowerCase()).filter((movement) => typeof movement.assetAddress === "string").map((movement) => movement.assetAddress.toLowerCase()));
|
|
5819
6072
|
for (const option of this.yieldOptions.get(context.asset)?.value ?? []) {
|
|
5820
|
-
if (option.chainId !== chainId || typeof option.assetAddress !== "string" || option.assetAddress.toLowerCase() !== YIELDSEEKER_ASSET_METADATA[context.asset].address.toLowerCase() || !(0,
|
|
6073
|
+
if (option.chainId !== chainId || typeof option.assetAddress !== "string" || option.assetAddress.toLowerCase() !== YIELDSEEKER_ASSET_METADATA[context.asset].address.toLowerCase() || !(0, import_viem13.isAddress)(option.address) || !receivedAssets.has(option.address.toLowerCase()) || hints.has(option.address.toLowerCase())) continue;
|
|
5821
6074
|
hints.set(option.address.toLowerCase(), {
|
|
5822
6075
|
yieldOption: option,
|
|
5823
6076
|
assetsRaw: "0",
|
|
@@ -5869,7 +6122,7 @@ var YieldseekerAgent = class {
|
|
|
5869
6122
|
const read2 = async () => {
|
|
5870
6123
|
const client = this.getReceiptClient();
|
|
5871
6124
|
const blockNumber = await client.getBlockNumber({ cacheTime: 0 });
|
|
5872
|
-
const wallet = (0,
|
|
6125
|
+
const wallet = (0, import_viem13.getAddress)(context.wallet.walletAddress);
|
|
5873
6126
|
assertReadCurrent();
|
|
5874
6127
|
if (typeof blockNumber !== "bigint") throw unavailable();
|
|
5875
6128
|
const indexedPositions = this.validateWithdrawalPositions(positions ?? [], chainId, context.asset);
|
|
@@ -5879,11 +6132,11 @@ var YieldseekerAgent = class {
|
|
|
5879
6132
|
for (const position2 of indexedPositions) candidates.set(position2.yieldOption.address.toLowerCase(), position2.yieldOption);
|
|
5880
6133
|
const options = [...candidates.values()];
|
|
5881
6134
|
if (options.length > YIELDSEEKER_WITHDRAWAL_CANDIDATE_LIMIT) throw unavailable();
|
|
5882
|
-
const
|
|
5883
|
-
|
|
6135
|
+
const checksRead = this.readVaultLiquidity(options, wallet, blockNumber).then((value) => ({ value }), (error) => ({ error }));
|
|
6136
|
+
const [idle, feeTracker] = await Promise.all([
|
|
5884
6137
|
client.readContract({
|
|
5885
6138
|
address: metadata.address,
|
|
5886
|
-
abi:
|
|
6139
|
+
abi: import_viem13.erc20Abi,
|
|
5887
6140
|
functionName: "balanceOf",
|
|
5888
6141
|
args: [wallet],
|
|
5889
6142
|
blockNumber
|
|
@@ -5895,10 +6148,10 @@ var YieldseekerAgent = class {
|
|
|
5895
6148
|
blockNumber
|
|
5896
6149
|
})
|
|
5897
6150
|
]);
|
|
5898
|
-
if (typeof idle !== "bigint" || idle < 0n || !(0,
|
|
6151
|
+
if (typeof idle !== "bigint" || idle < 0n || !(0, import_viem13.isAddress)(feeTracker) || /^0x0{40}$/i.test(feeTracker)) throw unavailable();
|
|
5899
6152
|
assertReadCurrent();
|
|
5900
6153
|
const fees = await client.readContract({
|
|
5901
|
-
address: (0,
|
|
6154
|
+
address: (0, import_viem13.getAddress)(feeTracker),
|
|
5902
6155
|
abi: YIELDSEEKER_FEE_TRACKER_ABI,
|
|
5903
6156
|
functionName: "getFeesOwed",
|
|
5904
6157
|
args: [wallet],
|
|
@@ -5908,6 +6161,18 @@ var YieldseekerAgent = class {
|
|
|
5908
6161
|
const verified = [];
|
|
5909
6162
|
const verifiedVaults = [];
|
|
5910
6163
|
let deployed = 0n;
|
|
6164
|
+
const proof = (complete) => ({
|
|
6165
|
+
blockNumber,
|
|
6166
|
+
idle,
|
|
6167
|
+
fees,
|
|
6168
|
+
available: idle + deployed > fees ? idle + deployed - fees : 0n,
|
|
6169
|
+
positions: [...verified],
|
|
6170
|
+
verifiedVaults: [...verifiedVaults],
|
|
6171
|
+
indexedPositions,
|
|
6172
|
+
complete
|
|
6173
|
+
});
|
|
6174
|
+
assertReadCurrent();
|
|
6175
|
+
knownProof = proof(false);
|
|
5911
6176
|
const collect = (options2, results) => {
|
|
5912
6177
|
assertReadCurrent();
|
|
5913
6178
|
const known = this.balanceVaults.get(contextKey) ?? /* @__PURE__ */ new Set();
|
|
@@ -5923,7 +6188,7 @@ var YieldseekerAgent = class {
|
|
|
5923
6188
|
return;
|
|
5924
6189
|
}
|
|
5925
6190
|
const [underlying, shares, withdrawable] = group.map((value) => value.result);
|
|
5926
|
-
if (typeof underlying !== "string" || !(0,
|
|
6191
|
+
if (typeof underlying !== "string" || !(0, import_viem13.isAddress)(underlying) || underlying.toLowerCase() !== metadata.address.toLowerCase() || typeof shares !== "bigint" || shares < 0n || typeof withdrawable !== "bigint" || withdrawable < 0n || shares === 0n && withdrawable > 0n) {
|
|
5927
6192
|
valid2 = false;
|
|
5928
6193
|
return;
|
|
5929
6194
|
}
|
|
@@ -5940,17 +6205,10 @@ var YieldseekerAgent = class {
|
|
|
5940
6205
|
});
|
|
5941
6206
|
return valid2;
|
|
5942
6207
|
};
|
|
5943
|
-
const
|
|
5944
|
-
|
|
5945
|
-
|
|
5946
|
-
|
|
5947
|
-
fees,
|
|
5948
|
-
available: idle + deployed > fees ? idle + deployed - fees : 0n,
|
|
5949
|
-
positions: [...verified],
|
|
5950
|
-
verifiedVaults: [...verifiedVaults],
|
|
5951
|
-
indexedPositions,
|
|
5952
|
-
complete
|
|
5953
|
-
});
|
|
6208
|
+
const checks = await checksRead;
|
|
6209
|
+
assertReadCurrent();
|
|
6210
|
+
if ("error" in checks) throw checks.error;
|
|
6211
|
+
const allKnownVerified = collect(options, checks.value);
|
|
5954
6212
|
knownProof = proof(false);
|
|
5955
6213
|
const indexed = new Map(indexedPositions.map((position2) => [position2.yieldOption.address.toLowerCase(), position2]));
|
|
5956
6214
|
const discrepancy = verified.some((position2) => {
|
|
@@ -5967,7 +6225,7 @@ var YieldseekerAgent = class {
|
|
|
5967
6225
|
assertReadCurrent();
|
|
5968
6226
|
const eligible = /* @__PURE__ */ new Map();
|
|
5969
6227
|
for (const option of catalog ?? []) {
|
|
5970
|
-
if (option?.chainId === chainId && typeof option.assetAddress === "string" && option.assetAddress.toLowerCase() === metadata.address.toLowerCase() && (0,
|
|
6228
|
+
if (option?.chainId === chainId && typeof option.assetAddress === "string" && option.assetAddress.toLowerCase() === metadata.address.toLowerCase() && (0, import_viem13.isAddress)(option.address))
|
|
5971
6229
|
eligible.set(option.address.toLowerCase(), option);
|
|
5972
6230
|
}
|
|
5973
6231
|
const extra = [...eligible].filter(([address]) => !candidates.has(address)).map(([, option]) => option);
|
|
@@ -6018,7 +6276,7 @@ var YieldseekerAgent = class {
|
|
|
6018
6276
|
const key2 = this.contextKey(state, evidence.chainId, evidence.token);
|
|
6019
6277
|
const generation = this.readGeneration, version = this.portfolioVersion(key2);
|
|
6020
6278
|
if (read2.readVersion !== version) return void 0;
|
|
6021
|
-
const wallet = (0,
|
|
6279
|
+
const wallet = (0, import_viem13.getAddress)(context.wallet.walletAddress);
|
|
6022
6280
|
const asset = YIELDSEEKER_ASSET_METADATA[evidence.token];
|
|
6023
6281
|
const client = this.getReceiptClient();
|
|
6024
6282
|
const blockNumber = await client.getBlockNumber({ cacheTime: 0 });
|
|
@@ -6026,10 +6284,10 @@ var YieldseekerAgent = class {
|
|
|
6026
6284
|
const vaults = [...this.balanceVaults.get(key2) ?? []];
|
|
6027
6285
|
const [invested, idle, tracker] = await Promise.all([
|
|
6028
6286
|
remainingVaultBalance(client, wallet, asset.address, vaults, blockNumber),
|
|
6029
|
-
client.readContract({ address: asset.address, abi:
|
|
6287
|
+
client.readContract({ address: asset.address, abi: import_viem13.erc20Abi, functionName: "balanceOf", args: [wallet], blockNumber }),
|
|
6030
6288
|
client.readContract({ address: wallet, abi: YIELDSEEKER_AGENT_WALLET_ABI, functionName: "feeTracker", blockNumber })
|
|
6031
6289
|
]);
|
|
6032
|
-
if (invested === void 0 || typeof idle !== "bigint" || idle < 0n || !(0,
|
|
6290
|
+
if (invested === void 0 || typeof idle !== "bigint" || idle < 0n || !(0, import_viem13.isAddress)(tracker) || /^0x0{40}$/i.test(tracker)) return void 0;
|
|
6033
6291
|
const fees = await client.readContract({
|
|
6034
6292
|
address: tracker,
|
|
6035
6293
|
abi: YIELDSEEKER_FEE_TRACKER_ABI,
|
|
@@ -6042,7 +6300,7 @@ var YieldseekerAgent = class {
|
|
|
6042
6300
|
const total = idle + invested > fees ? idle + invested - fees : 0n;
|
|
6043
6301
|
const displayed = balance.assetBalances?.find((item) => item.chainId === evidence.chainId && item.asset === evidence.token);
|
|
6044
6302
|
if (!displayed || !evidence.confirmedAmount || !/^\d+$/.test(evidence.confirmedAmount)) return void 0;
|
|
6045
|
-
const amount = (0,
|
|
6303
|
+
const amount = (0, import_viem13.parseUnits)(displayed.amount, asset.decimals);
|
|
6046
6304
|
if (amount < 0n) return void 0;
|
|
6047
6305
|
const displayUnit = evidence.token === "USDC" ? 5000n : 500000000000n;
|
|
6048
6306
|
const movementUnit = BigInt(evidence.confirmedAmount) / 1000n;
|
|
@@ -6088,9 +6346,9 @@ var YieldseekerAgent = class {
|
|
|
6088
6346
|
if (!context) return void 0;
|
|
6089
6347
|
const idle = await withPaidRpcDiagnostics(() => this.getReceiptClient().readContract({
|
|
6090
6348
|
address: YIELDSEEKER_ASSET_METADATA[asset].address,
|
|
6091
|
-
abi:
|
|
6349
|
+
abi: import_viem13.erc20Abi,
|
|
6092
6350
|
functionName: "balanceOf",
|
|
6093
|
-
args: [(0,
|
|
6351
|
+
args: [(0, import_viem13.getAddress)(context.wallet.walletAddress)]
|
|
6094
6352
|
}), chainId, "eth_call", this.id);
|
|
6095
6353
|
this.assertSession(generation, chainId, asset);
|
|
6096
6354
|
if (typeof idle !== "bigint" || idle < 0n) throw this.invalidResponse("wallet deposit balance");
|
|
@@ -6098,7 +6356,7 @@ var YieldseekerAgent = class {
|
|
|
6098
6356
|
}
|
|
6099
6357
|
async getEarnings(state, chainId) {
|
|
6100
6358
|
this.assertChain(chainId);
|
|
6101
|
-
return mapYieldseekerEarnings(await this.loadPortfolio(state, chainId, {}));
|
|
6359
|
+
return mapYieldseekerEarnings(await this.loadPortfolio(state, chainId, { includePositions: false }));
|
|
6102
6360
|
}
|
|
6103
6361
|
async getAccountApy(state, chainId, days, tokenSymbol) {
|
|
6104
6362
|
this.assertChain(chainId);
|
|
@@ -6110,6 +6368,17 @@ var YieldseekerAgent = class {
|
|
|
6110
6368
|
});
|
|
6111
6369
|
return mapYieldseekerApy(state.walletAddress, contexts, days);
|
|
6112
6370
|
}
|
|
6371
|
+
async getDailyEarnings(state, chainId, days, tokenSymbol) {
|
|
6372
|
+
this.assertChain(chainId);
|
|
6373
|
+
const asset = tokenSymbol?.toUpperCase();
|
|
6374
|
+
if (asset !== void 0) this.assertAsset(asset);
|
|
6375
|
+
const contexts = await this.loadActivityPortfolio(state, chainId, {
|
|
6376
|
+
...asset ? { asset } : {},
|
|
6377
|
+
historic: true,
|
|
6378
|
+
includePositions: false
|
|
6379
|
+
});
|
|
6380
|
+
return mapYieldseekerDailyEarnings(state.walletAddress, contexts, days);
|
|
6381
|
+
}
|
|
6113
6382
|
async getHistory(state, chainId, options) {
|
|
6114
6383
|
this.assertChain(chainId);
|
|
6115
6384
|
const asset = options?.tokenSymbol?.toUpperCase();
|
|
@@ -6126,7 +6395,7 @@ var YieldseekerAgent = class {
|
|
|
6126
6395
|
);
|
|
6127
6396
|
const vaultAddresses = new Set(
|
|
6128
6397
|
catalog.flat().filter(
|
|
6129
|
-
(yieldOption) => yieldOption.chainId === chainId && (0,
|
|
6398
|
+
(yieldOption) => yieldOption.chainId === chainId && (0, import_viem13.isAddress)(yieldOption.address)
|
|
6130
6399
|
).map((yieldOption) => yieldOption.address.toLowerCase())
|
|
6131
6400
|
);
|
|
6132
6401
|
return mapYieldseekerHistory(contexts, {
|
|
@@ -6255,7 +6524,7 @@ var YieldseekerAgent = class {
|
|
|
6255
6524
|
`/users/${user.userId}/agents/${agent.agentId}/wallet`
|
|
6256
6525
|
).then((walletResponse) => {
|
|
6257
6526
|
this.assertSession(generation, chainId, asset);
|
|
6258
|
-
if (!walletResponse?.agentWallet || !(0,
|
|
6527
|
+
if (!walletResponse?.agentWallet || !(0, import_viem13.isAddress)(walletResponse.agentWallet.walletAddress)) {
|
|
6259
6528
|
throw this.invalidResponse("agent wallet");
|
|
6260
6529
|
}
|
|
6261
6530
|
const context = {
|
|
@@ -6285,7 +6554,7 @@ var YieldseekerAgent = class {
|
|
|
6285
6554
|
this.users.set(key2, persisted);
|
|
6286
6555
|
return persisted;
|
|
6287
6556
|
}
|
|
6288
|
-
const walletAddress = (0,
|
|
6557
|
+
const walletAddress = (0, import_viem13.getAddress)(state.walletAddress);
|
|
6289
6558
|
const generation = this.readGeneration;
|
|
6290
6559
|
let user = null;
|
|
6291
6560
|
try {
|
|
@@ -6620,7 +6889,7 @@ var YieldseekerAgent = class {
|
|
|
6620
6889
|
}
|
|
6621
6890
|
async loadPortfolioParts(state, chainId, context, options, contextKey) {
|
|
6622
6891
|
const [positions, historic, actions] = await Promise.all([
|
|
6623
|
-
this.cachedRead(
|
|
6892
|
+
options.includePositions === false ? Promise.resolve({ yieldPositions: [] }) : this.cachedRead(
|
|
6624
6893
|
`positions:${contextKey}`,
|
|
6625
6894
|
this.portfolioCacheMs(contextKey),
|
|
6626
6895
|
async () => {
|
|
@@ -6669,7 +6938,7 @@ var YieldseekerAgent = class {
|
|
|
6669
6938
|
this.agentPath(context, "deploy"),
|
|
6670
6939
|
{ method: "POST", body: {} }
|
|
6671
6940
|
);
|
|
6672
|
-
if (!deployed?.agentWallet || !(0,
|
|
6941
|
+
if (!deployed?.agentWallet || !(0, import_viem13.isAddress)(deployed.agentWallet.walletAddress) || deployed.agentWallet.walletAddress.toLowerCase() !== walletAddress) {
|
|
6673
6942
|
throw this.invalidResponse("agent deployment", {
|
|
6674
6943
|
reason: "Deploy did not return the expected Agent Wallet."
|
|
6675
6944
|
});
|
|
@@ -6772,20 +7041,20 @@ var YieldseekerAgent = class {
|
|
|
6772
7041
|
}
|
|
6773
7042
|
async submitTransaction(state, chainId, transaction, onSubmitted, onReceipt) {
|
|
6774
7043
|
if (this.transactionExecutor) {
|
|
6775
|
-
const hash2 = await this.transactionExecutor(state, chainId, transaction);
|
|
7044
|
+
const hash2 = await this.transactionExecutor(state, chainId, transaction, onReceipt);
|
|
6776
7045
|
onSubmitted?.(hash2);
|
|
6777
7046
|
return hash2;
|
|
6778
7047
|
}
|
|
6779
7048
|
this.assertTransaction(transaction, state, chainId);
|
|
6780
|
-
const account = (0,
|
|
6781
|
-
const walletClient = (0,
|
|
7049
|
+
const account = (0, import_viem13.getAddress)(state.walletAddress);
|
|
7050
|
+
const walletClient = (0, import_viem13.createWalletClient)({
|
|
6782
7051
|
account,
|
|
6783
7052
|
chain: import_chains4.base,
|
|
6784
|
-
transport: (0,
|
|
7053
|
+
transport: (0, import_viem13.custom)(state.provider)
|
|
6785
7054
|
});
|
|
6786
|
-
const walletChainClient = (0,
|
|
7055
|
+
const walletChainClient = (0, import_viem13.createPublicClient)({
|
|
6787
7056
|
chain: import_chains4.base,
|
|
6788
|
-
transport: (0,
|
|
7057
|
+
transport: (0, import_viem13.custom)(state.provider)
|
|
6789
7058
|
});
|
|
6790
7059
|
await ensureWalletOnChain(
|
|
6791
7060
|
walletChainClient,
|
|
@@ -6795,7 +7064,7 @@ var YieldseekerAgent = class {
|
|
|
6795
7064
|
const hash = await walletClient.sendTransaction({
|
|
6796
7065
|
account,
|
|
6797
7066
|
chain: import_chains4.base,
|
|
6798
|
-
to: (0,
|
|
7067
|
+
to: (0, import_viem13.getAddress)(transaction.to),
|
|
6799
7068
|
data: transaction.data,
|
|
6800
7069
|
value: BigInt(transaction.value)
|
|
6801
7070
|
});
|
|
@@ -6899,12 +7168,12 @@ var YieldseekerAgent = class {
|
|
|
6899
7168
|
return receipt;
|
|
6900
7169
|
}
|
|
6901
7170
|
assertTransaction(transaction, state, chainId) {
|
|
6902
|
-
if (!transaction || typeof transaction.from !== "string" || !(0,
|
|
7171
|
+
if (!transaction || typeof transaction.from !== "string" || !(0, import_viem13.isAddress)(transaction.from) || typeof transaction.to !== "string" || !(0, import_viem13.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_viem13.getAddress)(transaction.from) !== (0, import_viem13.getAddress)(state.walletAddress)) {
|
|
6903
7172
|
throw this.invalidResponse("transaction");
|
|
6904
7173
|
}
|
|
6905
7174
|
}
|
|
6906
7175
|
assertAgent(agent) {
|
|
6907
|
-
if (typeof agent.agentId !== "string" || typeof agent.assetAddress !== "string" || !(0,
|
|
7176
|
+
if (typeof agent.agentId !== "string" || typeof agent.assetAddress !== "string" || !(0, import_viem13.isAddress)(agent.assetAddress) || agent.chainId !== 8453) {
|
|
6908
7177
|
throw this.invalidResponse("agent");
|
|
6909
7178
|
}
|
|
6910
7179
|
}
|
|
@@ -7058,15 +7327,24 @@ async function withFailureReporting(apiKey, agentType, fn, baseUrl) {
|
|
|
7058
7327
|
}
|
|
7059
7328
|
|
|
7060
7329
|
// src/lib/helpers/withdraw-helper.ts
|
|
7061
|
-
var
|
|
7330
|
+
var import_viem14 = require("viem");
|
|
7062
7331
|
function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
|
|
7063
7332
|
const target = asset.toUpperCase();
|
|
7064
7333
|
return agents.map((agent) => {
|
|
7334
|
+
let invalidBalance = false;
|
|
7335
|
+
const readAmount = (value, raw2 = false) => {
|
|
7336
|
+
if (typeof value !== "string" || !(raw2 ? /^\d+$/ : /^\d+(?:\.\d+)?$/).test(value)) {
|
|
7337
|
+
invalidBalance = true;
|
|
7338
|
+
return 0n;
|
|
7339
|
+
}
|
|
7340
|
+
const [whole, fraction] = value.split(".");
|
|
7341
|
+
return raw2 ? BigInt(value) : (0, import_viem14.parseUnits)(fraction === void 0 ? whole : `${whole}.${fraction.slice(0, decimals)}`, decimals);
|
|
7342
|
+
};
|
|
7065
7343
|
const agentBalance = aggregated[agent.id];
|
|
7066
7344
|
const tokenBalance = agentBalance?.tokens.find(
|
|
7067
7345
|
(t) => t.chainId === chainId && t.asset.toUpperCase() === target
|
|
7068
7346
|
);
|
|
7069
|
-
let balance = tokenBalance ? (
|
|
7347
|
+
let balance = tokenBalance ? readAmount(tokenBalance.amount) : 0n;
|
|
7070
7348
|
if (agent.balanceComposition === "tokens-plus-positions") {
|
|
7071
7349
|
const chainNameById = {
|
|
7072
7350
|
1: "ETHEREUM",
|
|
@@ -7078,20 +7356,22 @@ function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decima
|
|
|
7078
7356
|
const positionChain = position2.chain.trim().toUpperCase();
|
|
7079
7357
|
const matchesChain = positionChain === String(chainId) || targetChain !== void 0 && positionChain === targetChain;
|
|
7080
7358
|
if (!matchesChain || position2.asset.toUpperCase() !== target) continue;
|
|
7081
|
-
balance += position2.withdrawableAmountRaw !== void 0 ?
|
|
7359
|
+
balance += position2.withdrawableAmountRaw !== void 0 ? readAmount(position2.withdrawableAmountRaw, true) : readAmount(position2.amount);
|
|
7082
7360
|
}
|
|
7083
7361
|
}
|
|
7084
7362
|
const assetTotal = agentBalance?.assetBalances?.find(
|
|
7085
7363
|
(t) => t.chainId === chainId && t.asset.toUpperCase() === target
|
|
7086
7364
|
);
|
|
7087
7365
|
if (assetTotal) {
|
|
7088
|
-
const total = (
|
|
7366
|
+
const total = readAmount(assetTotal.amount);
|
|
7089
7367
|
if (total < balance) balance = total > 0n ? total : 0n;
|
|
7090
7368
|
}
|
|
7091
|
-
return { agent, balance };
|
|
7369
|
+
return invalidBalance ? { agent, balance: 0n, invalidBalance: true } : { agent, balance };
|
|
7092
7370
|
});
|
|
7093
7371
|
}
|
|
7094
7372
|
function planProportionalShares(balances, requested, totalAvailable) {
|
|
7373
|
+
if (requested < 0n || totalAvailable < 0n || balances.some((entry) => entry.balance < 0n) || balances.reduce((sum, entry) => sum + entry.balance, 0n) !== totalAvailable || requested > totalAvailable)
|
|
7374
|
+
throw new Error("Invalid withdrawal planning amounts.");
|
|
7095
7375
|
const plans = balances.map(({ agent, balance }) => ({
|
|
7096
7376
|
agent,
|
|
7097
7377
|
balance,
|
|
@@ -7114,6 +7394,8 @@ function planProportionalShares(balances, requested, totalAvailable) {
|
|
|
7114
7394
|
return plans;
|
|
7115
7395
|
}
|
|
7116
7396
|
function planDisabledDrain(disabled, requested) {
|
|
7397
|
+
if (requested < 0n || disabled.some((entry) => entry.balance < 0n))
|
|
7398
|
+
throw new Error("Invalid withdrawal planning amounts.");
|
|
7117
7399
|
const sorted = [...disabled].filter((d) => d.balance > 0n).sort(
|
|
7118
7400
|
(a, b) => b.balance > a.balance ? 1 : b.balance < a.balance ? -1 : 0
|
|
7119
7401
|
);
|
|
@@ -7131,6 +7413,7 @@ function planDisabledDrain(disabled, requested) {
|
|
|
7131
7413
|
return { plans, remaining };
|
|
7132
7414
|
}
|
|
7133
7415
|
function redistributeShare(plans, fromIndex, amount, candidatePool) {
|
|
7416
|
+
if (amount <= 0n) return;
|
|
7134
7417
|
const pool = candidatePool ?? plans.slice(fromIndex + 1);
|
|
7135
7418
|
const candidates = pool.filter((c) => c.balance - c.planned > 0n);
|
|
7136
7419
|
const totalHeadroom = candidates.reduce(
|
|
@@ -7157,7 +7440,13 @@ function redistributeShare(plans, fromIndex, amount, candidatePool) {
|
|
|
7157
7440
|
}
|
|
7158
7441
|
}
|
|
7159
7442
|
function sumWithdrawnAmount(results) {
|
|
7160
|
-
return Object.values(results).reduce((sum,
|
|
7443
|
+
return Object.values(results).reduce((sum, result) => sum + (confirmedWithdrawalAmount(result) ?? 0n), 0n);
|
|
7444
|
+
}
|
|
7445
|
+
function confirmedWithdrawalAmount(result) {
|
|
7446
|
+
const evidence = result.evidence;
|
|
7447
|
+
if (evidence && (evidence.transfer !== "confirmed" || evidence.delivery !== "confirmed")) return void 0;
|
|
7448
|
+
const value = evidence ? evidence.confirmedAmount : result.amount;
|
|
7449
|
+
return typeof value === "string" && /^\d+$/.test(value) ? BigInt(value) : void 0;
|
|
7161
7450
|
}
|
|
7162
7451
|
|
|
7163
7452
|
// src/lib/helpers/account-apy-helper.ts
|
|
@@ -7243,15 +7532,52 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
|
|
|
7243
7532
|
return out;
|
|
7244
7533
|
}
|
|
7245
7534
|
|
|
7535
|
+
// src/lib/helpers/daily-earnings-helper.ts
|
|
7536
|
+
function aggregateDailyEarnings(series, tokenSymbol) {
|
|
7537
|
+
const wanted = tokenSymbol?.toUpperCase();
|
|
7538
|
+
const byAsset = /* @__PURE__ */ new Map();
|
|
7539
|
+
for (const account of series) {
|
|
7540
|
+
for (const { asset, points } of account.assets) {
|
|
7541
|
+
const symbol = asset.toUpperCase();
|
|
7542
|
+
if (!points.length || wanted && symbol !== wanted) continue;
|
|
7543
|
+
const components = byAsset.get(symbol) ?? [];
|
|
7544
|
+
components.push([...points].sort((a, b) => a.date.localeCompare(b.date)));
|
|
7545
|
+
byAsset.set(symbol, components);
|
|
7546
|
+
}
|
|
7547
|
+
}
|
|
7548
|
+
return [...byAsset.entries()].map(([asset, components]) => {
|
|
7549
|
+
const dates = [...new Set(components.flatMap((points2) => points2.map((point) => point.date)))].sort();
|
|
7550
|
+
const cursors = components.map((points2) => ({
|
|
7551
|
+
index: 0,
|
|
7552
|
+
// Providers can have different lifetime/window offsets and start dates.
|
|
7553
|
+
// Remove each opening reading before combining their earned amounts.
|
|
7554
|
+
baseline: points2[0].amount,
|
|
7555
|
+
current: points2[0].amount
|
|
7556
|
+
}));
|
|
7557
|
+
const points = dates.map((date) => {
|
|
7558
|
+
let amount = 0;
|
|
7559
|
+
components.forEach((component, index) => {
|
|
7560
|
+
const cursor = cursors[index];
|
|
7561
|
+
while (cursor.index < component.length && component[cursor.index].date <= date) {
|
|
7562
|
+
cursor.current = component[cursor.index++].amount;
|
|
7563
|
+
}
|
|
7564
|
+
amount += cursor.current - cursor.baseline;
|
|
7565
|
+
});
|
|
7566
|
+
return { date, amount };
|
|
7567
|
+
});
|
|
7568
|
+
return { asset, points };
|
|
7569
|
+
}).sort((a, b) => a.asset.localeCompare(b.asset));
|
|
7570
|
+
}
|
|
7571
|
+
|
|
7246
7572
|
// src/client.ts
|
|
7247
|
-
var
|
|
7573
|
+
var import_viem18 = require("viem");
|
|
7248
7574
|
var import_chains5 = require("viem/chains");
|
|
7249
7575
|
|
|
7250
7576
|
// src/lib/sponsored-token-batch.ts
|
|
7251
|
-
var
|
|
7577
|
+
var import_viem16 = require("viem");
|
|
7252
7578
|
|
|
7253
7579
|
// src/lib/permit2-batch.ts
|
|
7254
|
-
var
|
|
7580
|
+
var import_viem15 = require("viem");
|
|
7255
7581
|
var BATCH_PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
7256
7582
|
var BASE_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
|
|
7257
7583
|
var ERC2612_PERMIT_TYPES = {
|
|
@@ -7263,7 +7589,7 @@ var ERC2612_PERMIT_TYPES = {
|
|
|
7263
7589
|
{ name: "deadline", type: "uint256" }
|
|
7264
7590
|
]
|
|
7265
7591
|
};
|
|
7266
|
-
var ERC2612_READ_ABI = (0,
|
|
7592
|
+
var ERC2612_READ_ABI = (0, import_viem15.parseAbi)([
|
|
7267
7593
|
"function name() view returns (string)",
|
|
7268
7594
|
"function version() view returns (string)",
|
|
7269
7595
|
"function nonces(address owner) view returns (uint256)"
|
|
@@ -7301,7 +7627,7 @@ var PERMIT_BATCH_TYPES = {
|
|
|
7301
7627
|
{ name: "amount", type: "uint256" }
|
|
7302
7628
|
]
|
|
7303
7629
|
};
|
|
7304
|
-
var PERMIT2_BATCH_ABI = (0,
|
|
7630
|
+
var PERMIT2_BATCH_ABI = (0, import_viem15.parseAbi)([
|
|
7305
7631
|
"struct TokenPermissions { address token; uint256 amount; }",
|
|
7306
7632
|
"struct PermitBatchTransferFrom { TokenPermissions[] permitted; uint256 nonce; uint256 deadline; }",
|
|
7307
7633
|
"struct SignatureTransferDetails { address to; uint256 requestedAmount; }",
|
|
@@ -7334,9 +7660,29 @@ function batchTypedData(b, spender) {
|
|
|
7334
7660
|
}
|
|
7335
7661
|
};
|
|
7336
7662
|
}
|
|
7663
|
+
var BATCH_WITNESS_TYPE = "Deposit witness)Deposit(address[] recipients)TokenPermissions(address token,uint256 amount)";
|
|
7664
|
+
function batchWitness(b) {
|
|
7665
|
+
return (0, import_viem15.hashStruct)({
|
|
7666
|
+
types: PERMIT_BATCH_TYPES,
|
|
7667
|
+
primaryType: "Deposit",
|
|
7668
|
+
data: { recipients: b.transfers.map((t) => t.to) }
|
|
7669
|
+
});
|
|
7670
|
+
}
|
|
7671
|
+
function batchArgs(b) {
|
|
7672
|
+
return [
|
|
7673
|
+
batchPermit(b),
|
|
7674
|
+
b.transfers.map((t) => ({ to: t.to, requestedAmount: BigInt(t.amount) })),
|
|
7675
|
+
b.from,
|
|
7676
|
+
batchWitness(b),
|
|
7677
|
+
BATCH_WITNESS_TYPE,
|
|
7678
|
+
b.signature
|
|
7679
|
+
];
|
|
7680
|
+
}
|
|
7337
7681
|
|
|
7338
7682
|
// src/lib/sponsored-token-batch.ts
|
|
7339
7683
|
var memory = /* @__PURE__ */ new Map();
|
|
7684
|
+
var settledRecords = /* @__PURE__ */ new Map();
|
|
7685
|
+
var expiredRecords = /* @__PURE__ */ new Map();
|
|
7340
7686
|
var inflight = /* @__PURE__ */ new Map();
|
|
7341
7687
|
var planOf = (transfers) => JSON.stringify(
|
|
7342
7688
|
transfers.map((t) => ({
|
|
@@ -7344,32 +7690,109 @@ var planOf = (transfers) => JSON.stringify(
|
|
|
7344
7690
|
amount: BigInt(t.amount).toString()
|
|
7345
7691
|
}))
|
|
7346
7692
|
);
|
|
7347
|
-
var pendingKey = (i) => `owney.token-batch.v1:${(0,
|
|
7693
|
+
var pendingKey = (i) => `owney.token-batch.v1:${(0, import_viem16.keccak256)((0, import_viem16.toBytes)(i.apiKey))}:${i.baseUrl ?? "default"}:${i.chainId}:${i.owner.toLowerCase()}:${i.token.toLowerCase()}`;
|
|
7348
7694
|
function pendingTokenBatch(i) {
|
|
7349
7695
|
try {
|
|
7350
7696
|
const saved = read(pendingKey(i));
|
|
7351
7697
|
if (!saved) return;
|
|
7352
7698
|
const body = JSON.parse(saved);
|
|
7353
|
-
if (!body.serializedTransaction || body.chainId !== i.chainId || !(0,
|
|
7354
|
-
return { txHash: (0,
|
|
7699
|
+
if (!body.serializedTransaction || body.chainId !== i.chainId || !(0, import_viem16.isAddressEqual)(body.from, i.owner) || !(0, import_viem16.isAddressEqual)(body.token, i.token) || !body.transfers?.length) return;
|
|
7700
|
+
return { txHash: (0, import_viem16.keccak256)(body.serializedTransaction), transfers: body.transfers.map(({ to, amount }) => ({ to, amount })) };
|
|
7701
|
+
} catch {
|
|
7702
|
+
return;
|
|
7703
|
+
}
|
|
7704
|
+
}
|
|
7705
|
+
async function releaseExpiredTokenBatch(i) {
|
|
7706
|
+
const key2 = pendingKey(i);
|
|
7707
|
+
let timer;
|
|
7708
|
+
let expired = false;
|
|
7709
|
+
const check = async () => {
|
|
7710
|
+
let active = read(key2);
|
|
7711
|
+
if (active && i.expectedTxHash) {
|
|
7712
|
+
const current = JSON.parse(active);
|
|
7713
|
+
if (!current.serializedTransaction || (0, import_viem16.keccak256)(current.serializedTransaction).toLowerCase() !== i.expectedTxHash.toLowerCase())
|
|
7714
|
+
active = void 0;
|
|
7715
|
+
}
|
|
7716
|
+
const archiveKey = i.expectedTxHash ? `${key2}:expired:${i.expectedTxHash.toLowerCase()}` : void 0;
|
|
7717
|
+
const saved = active ?? (archiveKey && (expiredRecords.get(archiveKey) ?? (typeof window === "undefined" ? void 0 : window.localStorage.getItem(archiveKey))));
|
|
7718
|
+
if (!saved) return;
|
|
7719
|
+
const body = JSON.parse(saved);
|
|
7720
|
+
if (!body.serializedTransaction || body.chainId !== i.chainId || !(0, import_viem16.isAddressEqual)(body.from, i.owner) || !(0, import_viem16.isAddressEqual)(body.token, i.token) || !body.transfers?.length) return;
|
|
7721
|
+
const txHash = (0, import_viem16.keccak256)(body.serializedTransaction);
|
|
7722
|
+
if (i.expectedTxHash && txHash.toLowerCase() !== i.expectedTxHash.toLowerCase()) return;
|
|
7723
|
+
const transaction = (0, import_viem16.parseTransaction)(body.serializedTransaction);
|
|
7724
|
+
if (transaction.chainId !== i.chainId || !transaction.to || !(0, import_viem16.isAddressEqual)(transaction.to, BATCH_PERMIT2_ADDRESS) || (transaction.value ?? 0n) !== 0n || transaction.data !== (0, import_viem16.encodeFunctionData)({
|
|
7725
|
+
abi: PERMIT2_BATCH_ABI,
|
|
7726
|
+
functionName: "permitWitnessTransferFrom",
|
|
7727
|
+
args: batchArgs(body)
|
|
7728
|
+
})) return;
|
|
7729
|
+
const nonce = BigInt(body.nonce);
|
|
7730
|
+
const deadline = BigInt(body.deadline);
|
|
7731
|
+
if (nonce < 0n || nonce > MAX_UINT256 || deadline < 0n) return;
|
|
7732
|
+
const block = await i.pub.getBlock({ blockTag: "finalized" });
|
|
7733
|
+
if (expired || typeof block.number !== "bigint" || typeof block.timestamp !== "bigint" || block.timestamp <= deadline) return;
|
|
7734
|
+
const bitmap = await i.pub.readContract({
|
|
7735
|
+
address: BATCH_PERMIT2_ADDRESS,
|
|
7736
|
+
abi: PERMIT2_BATCH_ABI,
|
|
7737
|
+
functionName: "nonceBitmap",
|
|
7738
|
+
args: [i.owner, nonce >> 8n],
|
|
7739
|
+
blockNumber: block.number
|
|
7740
|
+
});
|
|
7741
|
+
if (expired || typeof bitmap !== "bigint" || bitmap < 0n || bitmap > MAX_UINT256 || (bitmap & 1n << (nonce & 255n)) !== 0n || active && read(key2) !== active) return;
|
|
7742
|
+
if (active) {
|
|
7743
|
+
const terminalKey = `${key2}:expired:${txHash.toLowerCase()}`;
|
|
7744
|
+
expiredRecords.set(terminalKey, saved);
|
|
7745
|
+
let persisted = typeof window === "undefined";
|
|
7746
|
+
try {
|
|
7747
|
+
if (typeof window !== "undefined") {
|
|
7748
|
+
window.localStorage.setItem(terminalKey, saved);
|
|
7749
|
+
persisted = window.localStorage.getItem(terminalKey) === saved;
|
|
7750
|
+
}
|
|
7751
|
+
} catch {
|
|
7752
|
+
}
|
|
7753
|
+
if (!persisted) settledRecords.set(key2, saved);
|
|
7754
|
+
else clear(key2, body);
|
|
7755
|
+
}
|
|
7756
|
+
return { txHash, transfers: body.transfers.map(({ to, amount }) => ({ to, amount })), blockNumber: block.number };
|
|
7757
|
+
};
|
|
7758
|
+
try {
|
|
7759
|
+
return await Promise.race([check(), new Promise((resolve) => {
|
|
7760
|
+
timer = setTimeout(() => {
|
|
7761
|
+
expired = true;
|
|
7762
|
+
resolve(void 0);
|
|
7763
|
+
}, 8e3);
|
|
7764
|
+
})]);
|
|
7355
7765
|
} catch {
|
|
7356
7766
|
return;
|
|
7767
|
+
} finally {
|
|
7768
|
+
expired = true;
|
|
7769
|
+
if (timer) clearTimeout(timer);
|
|
7357
7770
|
}
|
|
7358
7771
|
}
|
|
7359
7772
|
function read(key2) {
|
|
7360
|
-
|
|
7773
|
+
const value = typeof window === "undefined" ? memory.get(key2) : window.localStorage.getItem(key2);
|
|
7774
|
+
return value && settledRecords.get(key2) === value ? void 0 : value;
|
|
7361
7775
|
}
|
|
7362
|
-
function
|
|
7363
|
-
|
|
7776
|
+
function storedBody(body) {
|
|
7777
|
+
return JSON.stringify({
|
|
7364
7778
|
...body,
|
|
7365
7779
|
transfers: body.transfers.map(({ to, amount }) => ({ to, amount }))
|
|
7366
7780
|
});
|
|
7781
|
+
}
|
|
7782
|
+
function save(key2, body) {
|
|
7783
|
+
const value = storedBody(body);
|
|
7367
7784
|
if (typeof window === "undefined") memory.set(key2, value);
|
|
7368
7785
|
else window.localStorage.setItem(key2, value);
|
|
7786
|
+
settledRecords.delete(key2);
|
|
7369
7787
|
}
|
|
7370
|
-
function clear(key2) {
|
|
7371
|
-
|
|
7372
|
-
|
|
7788
|
+
function clear(key2, body) {
|
|
7789
|
+
try {
|
|
7790
|
+
if (typeof window === "undefined") memory.delete(key2);
|
|
7791
|
+
else window.localStorage.removeItem(key2);
|
|
7792
|
+
settledRecords.delete(key2);
|
|
7793
|
+
} catch {
|
|
7794
|
+
settledRecords.set(key2, storedBody(body));
|
|
7795
|
+
}
|
|
7373
7796
|
}
|
|
7374
7797
|
function sponsorTokenBatch(i) {
|
|
7375
7798
|
const key2 = pendingKey(i);
|
|
@@ -7436,7 +7859,7 @@ async function execute(i, key2, plan) {
|
|
|
7436
7859
|
baseUrl: i.baseUrl,
|
|
7437
7860
|
body
|
|
7438
7861
|
});
|
|
7439
|
-
if (!preparedPermit.serializedPermitTransaction || !preparedPermit.permitTxHash || (0,
|
|
7862
|
+
if (!preparedPermit.serializedPermitTransaction || !preparedPermit.permitTxHash || (0, import_viem16.keccak256)(preparedPermit.serializedPermitTransaction) !== preparedPermit.permitTxHash)
|
|
7440
7863
|
throw new Error(
|
|
7441
7864
|
"Sponsorship API did not return a valid prepared permit transaction."
|
|
7442
7865
|
);
|
|
@@ -7447,7 +7870,7 @@ async function execute(i, key2, plan) {
|
|
|
7447
7870
|
save(key2, body);
|
|
7448
7871
|
}
|
|
7449
7872
|
if (!body.serializedTransaction) {
|
|
7450
|
-
const permitHash = body.serializedPermitTransaction ? (0,
|
|
7873
|
+
const permitHash = body.serializedPermitTransaction ? (0, import_viem16.keccak256)(body.serializedPermitTransaction) : void 0;
|
|
7451
7874
|
let prepared = permitHash ? await postSigned("approval", permitHash) : await post();
|
|
7452
7875
|
if (prepared?.status === "pending") {
|
|
7453
7876
|
if (!permitHash || prepared.phase !== "approval" || prepared.txHash !== permitHash)
|
|
@@ -7458,7 +7881,7 @@ async function execute(i, key2, plan) {
|
|
|
7458
7881
|
if (!prepared) prepared = await post();
|
|
7459
7882
|
if (prepared.status === "pending" && permitHash && prepared.phase === "approval" && prepared.txHash === permitHash)
|
|
7460
7883
|
throw pendingError("approval", permitHash);
|
|
7461
|
-
if (!prepared.serializedTransaction || (0,
|
|
7884
|
+
if (!prepared.serializedTransaction || (0, import_viem16.keccak256)(prepared.serializedTransaction) !== prepared.txHash)
|
|
7462
7885
|
throw new Error(
|
|
7463
7886
|
"Sponsorship API did not return a valid prepared transaction."
|
|
7464
7887
|
);
|
|
@@ -7469,22 +7892,22 @@ async function execute(i, key2, plan) {
|
|
|
7469
7892
|
save(key2, body);
|
|
7470
7893
|
}
|
|
7471
7894
|
try {
|
|
7472
|
-
i.onSubmitted?.((0,
|
|
7895
|
+
i.onSubmitted?.((0, import_viem16.keccak256)(body.serializedTransaction));
|
|
7473
7896
|
} catch {
|
|
7474
7897
|
}
|
|
7475
|
-
const hash = (0,
|
|
7898
|
+
const hash = (0, import_viem16.keccak256)(body.serializedTransaction);
|
|
7476
7899
|
const existing = await i.pub.getTransactionReceipt({ hash }).catch(() => void 0);
|
|
7477
7900
|
if (existing) {
|
|
7478
7901
|
assertReceipt(existing, "deposit");
|
|
7479
7902
|
void post().catch(() => void 0);
|
|
7480
|
-
clear(key2);
|
|
7903
|
+
clear(key2, body);
|
|
7481
7904
|
return hash;
|
|
7482
7905
|
}
|
|
7483
7906
|
let result = await postSigned("deposit", hash);
|
|
7484
|
-
if (result?.status === "pending" && result.phase === "approval" && body.serializedPermitTransaction && result.txHash === (0,
|
|
7907
|
+
if (result?.status === "pending" && result.phase === "approval" && body.serializedPermitTransaction && result.txHash === (0, import_viem16.keccak256)(body.serializedPermitTransaction)) {
|
|
7485
7908
|
await waitForConfirmation("approval", result.txHash);
|
|
7486
7909
|
result = await postSigned("deposit", hash);
|
|
7487
|
-
if (result?.status === "pending" && result.phase === "approval" && result.txHash === (0,
|
|
7910
|
+
if (result?.status === "pending" && result.phase === "approval" && result.txHash === (0, import_viem16.keccak256)(body.serializedPermitTransaction)) throw pendingError("approval", result.txHash);
|
|
7488
7911
|
}
|
|
7489
7912
|
if (result) {
|
|
7490
7913
|
if (result.txHash !== hash || result.status === "pending" && result.phase !== "deposit")
|
|
@@ -7492,11 +7915,11 @@ async function execute(i, key2, plan) {
|
|
|
7492
7915
|
if (result.status === "pending") await waitForConfirmation("deposit", hash);
|
|
7493
7916
|
}
|
|
7494
7917
|
if (!result || result.status === "pending") void post().catch(() => void 0);
|
|
7495
|
-
clear(key2);
|
|
7918
|
+
clear(key2, body);
|
|
7496
7919
|
return hash;
|
|
7497
7920
|
} catch (error) {
|
|
7498
7921
|
if (!body.serializedTransaction && !body.serializedPermitTransaction || rejectedPreparation(error) || error instanceof OwneyError && error.details?.notSubmitted === true)
|
|
7499
|
-
clear(key2);
|
|
7922
|
+
clear(key2, body);
|
|
7500
7923
|
throw error;
|
|
7501
7924
|
}
|
|
7502
7925
|
};
|
|
@@ -7505,10 +7928,16 @@ async function execute(i, key2, plan) {
|
|
|
7505
7928
|
throw new OwneyError("DEPOSIT_IN_PROGRESS", "The saved deposit changed. Check its status before depositing again.");
|
|
7506
7929
|
if (saved) {
|
|
7507
7930
|
const previous = JSON.parse(saved);
|
|
7508
|
-
if (previous.chainId !== i.chainId || !(0,
|
|
7931
|
+
if (previous.chainId !== i.chainId || !(0, import_viem16.isAddressEqual)(previous.from, i.owner) || !(0, import_viem16.isAddressEqual)(previous.token, i.token) || planOf(previous.transfers) !== plan)
|
|
7509
7932
|
throw new Error(
|
|
7510
7933
|
"Retry the previous token deposit and agent split first to reconcile its status."
|
|
7511
7934
|
);
|
|
7935
|
+
if (await releaseExpiredTokenBatch({ ...i, expectedTxHash: previous.serializedTransaction ? (0, import_viem16.keccak256)(previous.serializedTransaction) : void 0 }))
|
|
7936
|
+
throw new OwneyError(
|
|
7937
|
+
"SPONSOR_REQUEST_FAILED",
|
|
7938
|
+
"The deposit authorization expired without transferring funds. Start a new deposit.",
|
|
7939
|
+
{ notSubmitted: true, safeToFallback: false }
|
|
7940
|
+
);
|
|
7512
7941
|
i.onApproved?.();
|
|
7513
7942
|
return send({ ...previous, transfers: i.transfers });
|
|
7514
7943
|
}
|
|
@@ -7522,7 +7951,7 @@ async function execute(i, key2, plan) {
|
|
|
7522
7951
|
"DEPOSIT_INSUFFICIENT_BALANCE",
|
|
7523
7952
|
"Insufficient token balance for this deposit."
|
|
7524
7953
|
);
|
|
7525
|
-
if (allowance < total && (i.chainId !== 8453 || !(0,
|
|
7954
|
+
if (allowance < total && (i.chainId !== 8453 || !(0, import_viem16.isAddressEqual)(i.token, BASE_USDC_ADDRESS)))
|
|
7526
7955
|
throw new OwneyError(
|
|
7527
7956
|
"PERMIT2_APPROVAL_REQUIRED",
|
|
7528
7957
|
"token deposits need a one-time Permit2 approval."
|
|
@@ -7701,7 +8130,7 @@ async function runAgentDepositBatch(chainId, legs, transfer) {
|
|
|
7701
8130
|
}
|
|
7702
8131
|
|
|
7703
8132
|
// src/lib/sponsored-calls-deposit.ts
|
|
7704
|
-
var
|
|
8133
|
+
var import_viem17 = require("viem");
|
|
7705
8134
|
var DEFAULT_POLL_INTERVAL_MS = 1500;
|
|
7706
8135
|
var DEFAULT_MAX_POLLS = 30;
|
|
7707
8136
|
async function paymasterSupported(provider, owner, chainId) {
|
|
@@ -7709,7 +8138,7 @@ async function paymasterSupported(provider, owner, chainId) {
|
|
|
7709
8138
|
method: "wallet_getCapabilities",
|
|
7710
8139
|
params: [owner]
|
|
7711
8140
|
});
|
|
7712
|
-
const forChain = caps?.[(0,
|
|
8141
|
+
const forChain = caps?.[(0, import_viem17.toHex)(chainId)] ?? caps?.[String(chainId)];
|
|
7713
8142
|
return Boolean(forChain?.paymasterService?.supported);
|
|
7714
8143
|
}
|
|
7715
8144
|
function makeSponsoredCallsCallback(deps) {
|
|
@@ -7746,8 +8175,8 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
7746
8175
|
const calls = transfers.map((transfer) => ({
|
|
7747
8176
|
to: token,
|
|
7748
8177
|
value: "0x0",
|
|
7749
|
-
data: (0,
|
|
7750
|
-
abi:
|
|
8178
|
+
data: (0, import_viem17.encodeFunctionData)({
|
|
8179
|
+
abi: import_viem17.erc20Abi,
|
|
7751
8180
|
functionName: "transfer",
|
|
7752
8181
|
args: [transfer.to, BigInt(transfer.amount)]
|
|
7753
8182
|
})
|
|
@@ -7779,7 +8208,7 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
7779
8208
|
url.searchParams.append("owneyIntent", intent);
|
|
7780
8209
|
paymasterUrl = url.toString();
|
|
7781
8210
|
}
|
|
7782
|
-
const requestedId = (0,
|
|
8211
|
+
const requestedId = (0, import_viem17.toHex)(globalThis.crypto.getRandomValues(new Uint8Array(32)));
|
|
7783
8212
|
const progress = (id, transfer) => {
|
|
7784
8213
|
try {
|
|
7785
8214
|
deps.onCallsProgress?.(id, transfers, transfer);
|
|
@@ -7796,7 +8225,7 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
7796
8225
|
version: "2.0.0",
|
|
7797
8226
|
id: requestedId,
|
|
7798
8227
|
from: deps.ownerAddress,
|
|
7799
|
-
chainId: (0,
|
|
8228
|
+
chainId: (0, import_viem17.toHex)(chainId),
|
|
7800
8229
|
atomicRequired: transfers.length > 1,
|
|
7801
8230
|
calls,
|
|
7802
8231
|
capabilities: {
|
|
@@ -7929,6 +8358,8 @@ var OwneySDK = class {
|
|
|
7929
8358
|
*/
|
|
7930
8359
|
disabledAgents = /* @__PURE__ */ new Set();
|
|
7931
8360
|
state = null;
|
|
8361
|
+
connectionRevision = 0;
|
|
8362
|
+
disconnectingAgents = null;
|
|
7932
8363
|
apiKey;
|
|
7933
8364
|
// The org's agent policy, fetched once per client. Applied to each agent on
|
|
7934
8365
|
// activation (ROUT-229). `undefined` means "not fetched yet", `null` means
|
|
@@ -7950,6 +8381,9 @@ var OwneySDK = class {
|
|
|
7950
8381
|
recoveredFundingReads = /* @__PURE__ */ new Set();
|
|
7951
8382
|
fundingBalanceChecks = /* @__PURE__ */ new WeakMap();
|
|
7952
8383
|
activationChecks = /* @__PURE__ */ new Map();
|
|
8384
|
+
// Protect the SDK entry point as well as the mini-app hook. This owns only
|
|
8385
|
+
// a running call, never a saved/pending provider outcome or a later retry.
|
|
8386
|
+
withdrawalSubmissions = /* @__PURE__ */ new Set();
|
|
7953
8387
|
readAgent(agent, method, fetch2, params = null) {
|
|
7954
8388
|
const key2 = JSON.stringify([
|
|
7955
8389
|
this.state?.walletAddress.toLowerCase() ?? null,
|
|
@@ -7982,9 +8416,10 @@ var OwneySDK = class {
|
|
|
7982
8416
|
*/
|
|
7983
8417
|
// TODO: replace with a proper EIP-1193 Provider type
|
|
7984
8418
|
async connect(provider) {
|
|
7985
|
-
const
|
|
7986
|
-
|
|
7987
|
-
|
|
8419
|
+
const revision = ++this.connectionRevision;
|
|
8420
|
+
const accounts = await provider.request({ method: "eth_accounts" });
|
|
8421
|
+
if (revision !== this.connectionRevision)
|
|
8422
|
+
throw new OwneyError("NOT_CONNECTED", "Wallet connection changed while connecting.");
|
|
7988
8423
|
const walletAddress = accounts[0];
|
|
7989
8424
|
if (!walletAddress) {
|
|
7990
8425
|
throw new OwneyError(
|
|
@@ -7992,33 +8427,46 @@ var OwneySDK = class {
|
|
|
7992
8427
|
"No accounts found. Ensure the wallet is unlocked and connected."
|
|
7993
8428
|
);
|
|
7994
8429
|
}
|
|
7995
|
-
this.
|
|
7996
|
-
this.
|
|
7997
|
-
|
|
8430
|
+
const replacingOwner = this.state !== null && this.state.walletAddress.toLowerCase() !== walletAddress.toLowerCase();
|
|
8431
|
+
this.clearConnectionState();
|
|
8432
|
+
await (replacingOwner ? this.disconnectAgents() : this.disconnectingAgents);
|
|
8433
|
+
if (revision !== this.connectionRevision)
|
|
8434
|
+
throw new OwneyError("NOT_CONNECTED", "Wallet connection changed while connecting.");
|
|
7998
8435
|
this.state = { provider, walletAddress, chainId: null };
|
|
7999
|
-
this.cachedSponsoredCallback = null;
|
|
8000
|
-
this.cachedWethSponsoredCallback = null;
|
|
8001
|
-
this.cachedSponsoredCallsCallbacks.clear();
|
|
8002
8436
|
}
|
|
8003
8437
|
/**
|
|
8004
8438
|
* Disconnect from all agents and clear connection state.
|
|
8005
8439
|
* After calling this, `connect()` must be called again before using agent methods.
|
|
8006
8440
|
*/
|
|
8007
8441
|
async disconnect() {
|
|
8442
|
+
++this.connectionRevision;
|
|
8443
|
+
this.clearConnectionState();
|
|
8444
|
+
await this.disconnectAgents();
|
|
8445
|
+
}
|
|
8446
|
+
clearConnectionState() {
|
|
8008
8447
|
this.state = null;
|
|
8009
8448
|
this.fundingBalanceChecks = /* @__PURE__ */ new WeakMap();
|
|
8010
|
-
for (const agent of this.agents.values()) {
|
|
8011
|
-
await agent.disconnect();
|
|
8012
|
-
}
|
|
8013
8449
|
this.activeAgents.clear();
|
|
8014
|
-
this.disabledAgents.clear();
|
|
8015
8450
|
this.agentReads.clearInFlight();
|
|
8016
8451
|
this.activationChecks.clear();
|
|
8017
|
-
this.state = null;
|
|
8018
8452
|
this.cachedSponsoredCallback = null;
|
|
8019
8453
|
this.cachedWethSponsoredCallback = null;
|
|
8020
8454
|
this.cachedSponsoredCallsCallbacks.clear();
|
|
8021
8455
|
}
|
|
8456
|
+
disconnectAgents() {
|
|
8457
|
+
if (this.disconnectingAgents) return this.disconnectingAgents;
|
|
8458
|
+
const pending = Promise.allSettled([...this.agents.values()].map(async (agent) => agent.disconnect())).then((results) => {
|
|
8459
|
+
const failure = results.find((result) => result.status === "rejected");
|
|
8460
|
+
if (failure?.status === "rejected") throw failure.reason;
|
|
8461
|
+
});
|
|
8462
|
+
this.disconnectingAgents = pending;
|
|
8463
|
+
void pending.then(() => {
|
|
8464
|
+
if (this.disconnectingAgents === pending) this.disconnectingAgents = null;
|
|
8465
|
+
}, () => {
|
|
8466
|
+
if (this.disconnectingAgents === pending) this.disconnectingAgents = null;
|
|
8467
|
+
});
|
|
8468
|
+
return pending;
|
|
8469
|
+
}
|
|
8022
8470
|
isAgentDisabled(agentId) {
|
|
8023
8471
|
return this.disabledAgents.has(agentId);
|
|
8024
8472
|
}
|
|
@@ -8081,14 +8529,14 @@ var OwneySDK = class {
|
|
|
8081
8529
|
// PublicClient/WalletClient param types — structurally identical at
|
|
8082
8530
|
// runtime, but the two share a name TS treats as unrelated.
|
|
8083
8531
|
getPublicClient: (cid) => this.getPaidRpcClient(cid),
|
|
8084
|
-
getWalletChainClient: (cid) => (0,
|
|
8532
|
+
getWalletChainClient: (cid) => (0, import_viem18.createPublicClient)({
|
|
8085
8533
|
chain: VIEM_CHAIN2[cid],
|
|
8086
|
-
transport: (0,
|
|
8534
|
+
transport: (0, import_viem18.custom)(provider)
|
|
8087
8535
|
}),
|
|
8088
|
-
getWalletClient: (cid) => (0,
|
|
8536
|
+
getWalletClient: (cid) => (0, import_viem18.createWalletClient)({
|
|
8089
8537
|
account: owner,
|
|
8090
8538
|
chain: VIEM_CHAIN2[cid],
|
|
8091
|
-
transport: (0,
|
|
8539
|
+
transport: (0, import_viem18.custom)(provider)
|
|
8092
8540
|
})
|
|
8093
8541
|
});
|
|
8094
8542
|
if (!onApproved && !onSubmitted && !resumeTxHash) this.cachedSponsoredCallback = callback;
|
|
@@ -8136,14 +8584,14 @@ var OwneySDK = class {
|
|
|
8136
8584
|
// PublicClient/WalletClient param types — structurally identical at
|
|
8137
8585
|
// runtime, but the two share a name TS treats as unrelated.
|
|
8138
8586
|
getPublicClient: (cid) => this.getPaidRpcClient(cid),
|
|
8139
|
-
getWalletChainClient: (cid) => (0,
|
|
8587
|
+
getWalletChainClient: (cid) => (0, import_viem18.createPublicClient)({
|
|
8140
8588
|
chain: VIEM_CHAIN2[cid],
|
|
8141
|
-
transport: (0,
|
|
8589
|
+
transport: (0, import_viem18.custom)(provider)
|
|
8142
8590
|
}),
|
|
8143
|
-
getWalletClient: (cid) => (0,
|
|
8591
|
+
getWalletClient: (cid) => (0, import_viem18.createWalletClient)({
|
|
8144
8592
|
account: owner,
|
|
8145
8593
|
chain: VIEM_CHAIN2[cid],
|
|
8146
|
-
transport: (0,
|
|
8594
|
+
transport: (0, import_viem18.custom)(provider)
|
|
8147
8595
|
})
|
|
8148
8596
|
});
|
|
8149
8597
|
if (!onApproved && !onSubmitted && !resumeTxHash) this.cachedWethSponsoredCallback = callback;
|
|
@@ -8454,6 +8902,12 @@ var OwneySDK = class {
|
|
|
8454
8902
|
*/
|
|
8455
8903
|
async deposit(options) {
|
|
8456
8904
|
const { amount, asset, depositCallback, agentId, onApproved } = options;
|
|
8905
|
+
if (!isFundingAmount(amount, true))
|
|
8906
|
+
throw new OwneyError(
|
|
8907
|
+
"DEPOSIT_INVALID_AMOUNT",
|
|
8908
|
+
"Deposit amount must be an unsigned base-unit integer.",
|
|
8909
|
+
{ phase: "prepare", rejectedBeforeSubmission: true }
|
|
8910
|
+
);
|
|
8457
8911
|
const prepared = /* @__PURE__ */ new Map();
|
|
8458
8912
|
const paidFallbackAgents = /* @__PURE__ */ new Set();
|
|
8459
8913
|
const onProgress = options.onProgress ? (evidence) => {
|
|
@@ -8481,6 +8935,47 @@ var OwneySDK = class {
|
|
|
8481
8935
|
throw new OwneyError("DEPOSIT_IN_PROGRESS", "This deposit cannot resume the saved relayer transaction.");
|
|
8482
8936
|
const effectiveCallback = depositCallback ?? (this.paymasterServiceUrl ? this.getDefaultSponsoredCallsCallback(asset, onApproved, onSubmitted, onCallsProgress) : asset === "WETH" ? this.getDefaultWethSponsoredCallback(onApproved, onSubmitted, options.resumeTxHash) : this.getDefaultSponsoredCallback(onApproved, onSubmitted, options.resumeTxHash));
|
|
8483
8937
|
try {
|
|
8938
|
+
if (options.resumeTxHash) {
|
|
8939
|
+
const token = SupportedAssets.find((value) => value.chainId === chainId && value.symbol === asset);
|
|
8940
|
+
const pending = token && pendingTokenBatch({
|
|
8941
|
+
apiKey: this.apiKey,
|
|
8942
|
+
baseUrl: this.routingApiBaseUrl,
|
|
8943
|
+
owner: state.walletAddress,
|
|
8944
|
+
chainId,
|
|
8945
|
+
token: token.address
|
|
8946
|
+
});
|
|
8947
|
+
const invalid2 = () => new OwneyError("DEPOSIT_IN_PROGRESS", "The saved deposit does not match this request. Check its status before depositing again.");
|
|
8948
|
+
if (!pending || pending.txHash.toLowerCase() !== options.resumeTxHash.toLowerCase() || pending.transfers.some((transfer) => !/^\d+$/.test(transfer.amount) || BigInt(transfer.amount) <= 0n) || pending.transfers.reduce((sum, transfer) => sum + BigInt(transfer.amount), 0n) !== BigInt(amount)) throw invalid2();
|
|
8949
|
+
const candidates = agentId ? [this.getAgent(agentId)] : this.getEligibleAgents(chainId, asset);
|
|
8950
|
+
const wallets = await Promise.all(candidates.map(async (agent) => {
|
|
8951
|
+
this.validateAssetSupport(agent, chainId, asset);
|
|
8952
|
+
const wallet = await (agent.getFundingWallet ? agent.getFundingWallet(state, chainId, asset) : agent.getUserProfile(state, chainId).then((profile) => profile.smartWallet)).catch(() => void 0);
|
|
8953
|
+
return { agent, wallet };
|
|
8954
|
+
}));
|
|
8955
|
+
if (this.state !== state || this.state.chainId !== chainId)
|
|
8956
|
+
throw new OwneyError("NOT_CONNECTED", "Wallet changed while recovering the deposit.");
|
|
8957
|
+
const usedAgents = /* @__PURE__ */ new Set();
|
|
8958
|
+
const legs = pending.transfers.map((transfer) => {
|
|
8959
|
+
const matches = wallets.filter((value) => value.wallet?.toLowerCase() === transfer.to.toLowerCase());
|
|
8960
|
+
if (matches.length !== 1 || usedAgents.has(matches[0].agent.id)) throw invalid2();
|
|
8961
|
+
const { agent } = matches[0];
|
|
8962
|
+
usedAgents.add(agent.id);
|
|
8963
|
+
return {
|
|
8964
|
+
id: agent.id,
|
|
8965
|
+
amount: transfer.amount,
|
|
8966
|
+
run: (callback) => withFailureReporting(
|
|
8967
|
+
this.apiKey,
|
|
8968
|
+
agent.id,
|
|
8969
|
+
() => agent.deposit(state, chainId, transfer.amount, asset, callback, onProgress),
|
|
8970
|
+
this.routingApiBaseUrl
|
|
8971
|
+
)
|
|
8972
|
+
};
|
|
8973
|
+
});
|
|
8974
|
+
const batchTransfer2 = getDepositBatchTransfer(effectiveCallback);
|
|
8975
|
+
if (!batchTransfer2) throw invalid2();
|
|
8976
|
+
const result = await runAgentDepositBatch(chainId, legs, batchTransfer2);
|
|
8977
|
+
return agentId ? result.agentResults[agentId] : result;
|
|
8978
|
+
}
|
|
8484
8979
|
if (agentId) {
|
|
8485
8980
|
if (this.isAgentDisabled(agentId)) {
|
|
8486
8981
|
throw new OwneyError(
|
|
@@ -8897,9 +9392,36 @@ var OwneySDK = class {
|
|
|
8897
9392
|
const token = SupportedAssets.find((t) => t.chainId === chainId && t.symbol === evidence.token);
|
|
8898
9393
|
if (!token) throw new OwneyError("CHAIN_UNSUPPORTED", "Unsupported funding asset.");
|
|
8899
9394
|
const rpc2 = this.getPaidRpcClient(chainId);
|
|
8900
|
-
|
|
9395
|
+
let receipt;
|
|
9396
|
+
try {
|
|
9397
|
+
receipt = await rpc2.getTransactionReceipt({ hash: evidence.txHash });
|
|
9398
|
+
} catch (error) {
|
|
9399
|
+
if (direction === "deposit") {
|
|
9400
|
+
const expired = await releaseExpiredTokenBatch({
|
|
9401
|
+
apiKey: this.apiKey,
|
|
9402
|
+
baseUrl: this.routingApiBaseUrl,
|
|
9403
|
+
owner: state.walletAddress,
|
|
9404
|
+
chainId,
|
|
9405
|
+
token: token.address,
|
|
9406
|
+
pub: rpc2,
|
|
9407
|
+
expectedTxHash: evidence.txHash
|
|
9408
|
+
});
|
|
9409
|
+
assertCurrent();
|
|
9410
|
+
if (expired?.transfers.some((transfer) => transfer.to.toLowerCase() === agentWallet.toLowerCase() && transfer.amount === evidence.intendedAmount))
|
|
9411
|
+
return {
|
|
9412
|
+
...evidence,
|
|
9413
|
+
agentWallet,
|
|
9414
|
+
transfer: "failed",
|
|
9415
|
+
delivery: "not-applicable",
|
|
9416
|
+
registration: "not-applicable",
|
|
9417
|
+
confirmedAmount: "0",
|
|
9418
|
+
blockNumber: expired.blockNumber.toString()
|
|
9419
|
+
};
|
|
9420
|
+
}
|
|
9421
|
+
throw error;
|
|
9422
|
+
}
|
|
8901
9423
|
assertCurrent();
|
|
8902
|
-
let verified = inspectFundingReceipt(receipt, { ...evidence, agentWallet }, token.address, direction);
|
|
9424
|
+
let verified = inspectFundingReceipt(receipt, { ...evidence, agentWallet }, token.address, direction, options);
|
|
8903
9425
|
if (direction === "withdraw" && evidence.agentId === "yieldseeker" && verified.transfer === "unknown" && verified.confirmedAmount && BigInt(verified.confirmedAmount) > 0n) {
|
|
8904
9426
|
const transaction = await rpc2.getTransaction({ hash: evidence.txHash });
|
|
8905
9427
|
assertCurrent();
|
|
@@ -9073,9 +9595,11 @@ var OwneySDK = class {
|
|
|
9073
9595
|
return page;
|
|
9074
9596
|
}
|
|
9075
9597
|
async recoverDepositRegistration(evidence) {
|
|
9598
|
+
const { state, assertCurrent } = this.captureReadScope(evidence.chainId);
|
|
9076
9599
|
const verified = await this.inspectFunding(evidence, "deposit");
|
|
9600
|
+
assertCurrent();
|
|
9077
9601
|
if (verified.agentId !== "zyfai") return verified;
|
|
9078
|
-
return this.getAgent("zyfai").retryDepositRegistration(
|
|
9602
|
+
return this.getAgent("zyfai").retryDepositRegistration(state, verified);
|
|
9079
9603
|
}
|
|
9080
9604
|
// --- Fund operations ---
|
|
9081
9605
|
/** On-chain version and ownership status for this owner's Yieldseeker agent. */
|
|
@@ -9121,10 +9645,24 @@ var OwneySDK = class {
|
|
|
9121
9645
|
* @returns {AgentWithdrawResult} for a single agent, or {OwneyWithdrawResult} with per-agent results
|
|
9122
9646
|
*/
|
|
9123
9647
|
async withdraw(options) {
|
|
9648
|
+
if (options.amount !== void 0 && !isFundingAmount(options.amount))
|
|
9649
|
+
throw new OwneyError(
|
|
9650
|
+
"WITHDRAW_INVALID_AMOUNT",
|
|
9651
|
+
"Withdrawal amount must be a positive base-unit integer.",
|
|
9652
|
+
{ phase: "prepare", rejectedBeforeSubmission: true }
|
|
9653
|
+
);
|
|
9124
9654
|
const state = this.requireState();
|
|
9125
9655
|
const chainId = this.requireChainId();
|
|
9656
|
+
const submissionKey = `${state.walletAddress.toLowerCase()}:${chainId}:${options.asset.toUpperCase()}`;
|
|
9657
|
+
if (this.withdrawalSubmissions.has(submissionKey))
|
|
9658
|
+
throw new OwneyError(
|
|
9659
|
+
"WITHDRAW_IN_PROGRESS",
|
|
9660
|
+
"A withdrawal request is already running.",
|
|
9661
|
+
{ chainId, asset: options.asset, phase: "prepare", rejectedBeforeSubmission: true }
|
|
9662
|
+
);
|
|
9126
9663
|
const ids = options.agentId ? [options.agentId] : this.getActiveAgentIds().filter((id) => !options.excludeAgentIds?.includes(id));
|
|
9127
9664
|
const attempted = /* @__PURE__ */ new Set();
|
|
9665
|
+
this.withdrawalSubmissions.add(submissionKey);
|
|
9128
9666
|
try {
|
|
9129
9667
|
return await this.withdrawFromAgents(options, state, chainId, attempted);
|
|
9130
9668
|
} catch (error) {
|
|
@@ -9141,6 +9679,8 @@ var OwneySDK = class {
|
|
|
9141
9679
|
});
|
|
9142
9680
|
}
|
|
9143
9681
|
throw error;
|
|
9682
|
+
} finally {
|
|
9683
|
+
this.withdrawalSubmissions.delete(submissionKey);
|
|
9144
9684
|
}
|
|
9145
9685
|
}
|
|
9146
9686
|
async withdrawFromAgents(options, state, chainId, attempted) {
|
|
@@ -9179,7 +9719,19 @@ var OwneySDK = class {
|
|
|
9179
9719
|
};
|
|
9180
9720
|
};
|
|
9181
9721
|
const submissionEvidence = /* @__PURE__ */ new Map();
|
|
9722
|
+
const pendingSubmissions = () => Object.fromEntries([...submissionEvidence].filter(([id, evidence]) => evidence.agentId === id && evidence.chainId === chainId && evidence.token === token && evidence.walletAddress.toLowerCase() === state.walletAddress.toLowerCase() && evidence.transfer !== "failed" && evidence.delivery !== "failed" && (evidence.transfer === "unknown" || evidence.txHash || evidence.userOpHash || evidence.callsId)));
|
|
9723
|
+
const throwUnconfirmed = (agentErrors2) => {
|
|
9724
|
+
const pending = pendingSubmissions();
|
|
9725
|
+
if (Object.keys(pending).length)
|
|
9726
|
+
throw new OwneyError(
|
|
9727
|
+
"WITHDRAW_UNCONFIRMED",
|
|
9728
|
+
"The withdrawal was submitted, but its outcome could not be confirmed yet.",
|
|
9729
|
+
{ asset, amount, agentErrors: agentErrors2, agentFailures, pendingSubmissions: pending }
|
|
9730
|
+
);
|
|
9731
|
+
};
|
|
9182
9732
|
const submit = async (agent, requested2) => {
|
|
9733
|
+
if (this.state !== state || this.state.chainId !== chainId)
|
|
9734
|
+
throw new OwneyError("NOT_CONNECTED", "Wallet connection changed before withdrawal submission.");
|
|
9183
9735
|
attempted.add(agent.id);
|
|
9184
9736
|
let evidence = {
|
|
9185
9737
|
agentId: agent.id,
|
|
@@ -9191,12 +9743,16 @@ var OwneySDK = class {
|
|
|
9191
9743
|
registration: "not-applicable",
|
|
9192
9744
|
delivery: "pending"
|
|
9193
9745
|
};
|
|
9746
|
+
let adapterReported = false;
|
|
9194
9747
|
const progress = (next) => {
|
|
9748
|
+
if (next.agentId !== agent.id || next.chainId !== chainId || next.token !== token || next.walletAddress.toLowerCase() !== state.walletAddress.toLowerCase()) return;
|
|
9749
|
+
adapterReported = true;
|
|
9195
9750
|
evidence = { ...evidence, ...next };
|
|
9196
9751
|
submissionEvidence.set(agent.id, evidence);
|
|
9197
9752
|
notifyFunding(options.onProgress, evidence);
|
|
9198
9753
|
};
|
|
9199
9754
|
progress(evidence);
|
|
9755
|
+
adapterReported = false;
|
|
9200
9756
|
try {
|
|
9201
9757
|
if (options.onBeforeSubmission)
|
|
9202
9758
|
return await agent.withdraw(
|
|
@@ -9210,7 +9766,7 @@ var OwneySDK = class {
|
|
|
9210
9766
|
);
|
|
9211
9767
|
return await (options.gasMode === void 0 ? agent.withdraw(state, chainId, token, requested2, progress) : agent.withdraw(state, chainId, token, requested2, progress, options.gasMode));
|
|
9212
9768
|
} catch (error) {
|
|
9213
|
-
if (!evidence.txHash && !evidence.userOpHash && !evidence.callsId && (this.isUserRejectedWithdrawal(error) || /insufficient (balance|funds)/i.test(error instanceof Error ? error.message : "")))
|
|
9769
|
+
if (!adapterReported && !evidence.txHash && !evidence.userOpHash && !evidence.callsId && (this.isUserRejectedWithdrawal(error) || /insufficient (balance|funds)/i.test(error instanceof Error ? error.message : "")))
|
|
9214
9770
|
progress({ ...evidence, transfer: "failed", delivery: "failed" });
|
|
9215
9771
|
throw error;
|
|
9216
9772
|
}
|
|
@@ -9271,6 +9827,7 @@ var OwneySDK = class {
|
|
|
9271
9827
|
}
|
|
9272
9828
|
}
|
|
9273
9829
|
if (Object.keys(results2).length === 0) {
|
|
9830
|
+
throwUnconfirmed(agentErrors2);
|
|
9274
9831
|
if (Object.keys(agentErrors2).length === 0)
|
|
9275
9832
|
throw new OwneyError(
|
|
9276
9833
|
"WITHDRAW_INSUFFICIENT_BALANCE",
|
|
@@ -9291,7 +9848,7 @@ var OwneySDK = class {
|
|
|
9291
9848
|
);
|
|
9292
9849
|
}
|
|
9293
9850
|
const amountsKnown = Object.values(results2).every(
|
|
9294
|
-
(result) =>
|
|
9851
|
+
(result) => confirmedWithdrawalAmount(result) !== void 0
|
|
9295
9852
|
);
|
|
9296
9853
|
return {
|
|
9297
9854
|
agentResult: results2,
|
|
@@ -9310,6 +9867,13 @@ var OwneySDK = class {
|
|
|
9310
9867
|
asset,
|
|
9311
9868
|
assetInfo.decimals
|
|
9312
9869
|
);
|
|
9870
|
+
for (const entry of balances) if (entry.invalidBalance) {
|
|
9871
|
+
if (!unavailableAgents.includes(entry.agent)) unavailableAgents.push(entry.agent);
|
|
9872
|
+
aggregated.agentErrors = {
|
|
9873
|
+
...aggregated.agentErrors,
|
|
9874
|
+
[entry.agent.id]: "Provider returned an invalid withdrawal balance."
|
|
9875
|
+
};
|
|
9876
|
+
}
|
|
9313
9877
|
const indexedAvailable = balances.reduce((sum, entry) => sum + entry.balance, 0n);
|
|
9314
9878
|
await Promise.all(balances.map(async (entry) => {
|
|
9315
9879
|
if (entry.balance !== 0n && indexedAvailable >= requested || !entry.agent.getWithdrawableBalance) return;
|
|
@@ -9322,7 +9886,7 @@ var OwneySDK = class {
|
|
|
9322
9886
|
if (this.isUserRejectedWithdrawal(originalFailure)) throw originalFailure;
|
|
9323
9887
|
if (entry.balance !== 0n && entry.agent.id !== "yieldseeker") {
|
|
9324
9888
|
const total = aggregated.agentBalances[entry.agent.id]?.assetBalances?.find((value) => value.chainId === chainId && value.asset.toUpperCase() === token);
|
|
9325
|
-
if (!total || (0,
|
|
9889
|
+
if (!total || (0, import_viem18.parseUnits)(total.amount, assetInfo.decimals) <= entry.balance) return;
|
|
9326
9890
|
}
|
|
9327
9891
|
try {
|
|
9328
9892
|
const otherAvailable = indexedAvailable - entry.balance;
|
|
@@ -9349,12 +9913,15 @@ var OwneySDK = class {
|
|
|
9349
9913
|
throw new OwneyError("NOT_CONNECTED", "Account changed while planning withdrawal.");
|
|
9350
9914
|
const unavailableAgentIds = unavailableAgents.map((agent) => agent.id);
|
|
9351
9915
|
const totalAvailable = balances.reduce((sum, x) => sum + x.balance, 0n);
|
|
9352
|
-
if (totalAvailable
|
|
9916
|
+
if (totalAvailable < requested && unavailableAgents.length > 0) {
|
|
9353
9917
|
throw new OwneyError(
|
|
9354
9918
|
"WITHDRAW_BALANCE_UNAVAILABLE",
|
|
9355
|
-
`Cannot
|
|
9919
|
+
`Cannot cover the requested withdrawal with verified available balances: ${unavailableAgentIds.join(", ")}.`,
|
|
9356
9920
|
{
|
|
9357
9921
|
asset,
|
|
9922
|
+
requested: amount,
|
|
9923
|
+
available: totalAvailable.toString(),
|
|
9924
|
+
rejectedBeforeSubmission: true,
|
|
9358
9925
|
unavailableAgents: unavailableAgentIds,
|
|
9359
9926
|
agentErrors: aggregated.agentErrors
|
|
9360
9927
|
}
|
|
@@ -9371,7 +9938,7 @@ var OwneySDK = class {
|
|
|
9371
9938
|
}
|
|
9372
9939
|
);
|
|
9373
9940
|
}
|
|
9374
|
-
const plannedTarget =
|
|
9941
|
+
const plannedTarget = requested;
|
|
9375
9942
|
const disabledBalances = balances.filter(
|
|
9376
9943
|
(b) => this.isAgentDisabled(b.agent.id)
|
|
9377
9944
|
);
|
|
@@ -9390,13 +9957,23 @@ var OwneySDK = class {
|
|
|
9390
9957
|
}));
|
|
9391
9958
|
const plans = [...disabledPlans, ...enabledPlans];
|
|
9392
9959
|
const orderedPlans = this.orderAgentsForWithdrawal(plans.map((p) => p.agent)).map((agent) => plans.find((plan) => plan.agent === agent));
|
|
9960
|
+
const assertPlan = () => {
|
|
9961
|
+
if (orderedPlans.some((plan) => plan.planned < 0n || plan.planned > plan.balance) || orderedPlans.reduce((sum, plan) => sum + plan.planned, 0n) > plannedTarget)
|
|
9962
|
+
throw new OwneyError(
|
|
9963
|
+
"WITHDRAW_BALANCE_UNAVAILABLE",
|
|
9964
|
+
"Withdrawal plan failed amount validation.",
|
|
9965
|
+
{ asset, rejectedBeforeSubmission: true }
|
|
9966
|
+
);
|
|
9967
|
+
};
|
|
9968
|
+
assertPlan();
|
|
9393
9969
|
const results = {};
|
|
9394
9970
|
const agentErrors = {
|
|
9395
9971
|
...aggregated.agentErrors ?? {}
|
|
9396
9972
|
};
|
|
9397
9973
|
for (let i = 0; i < orderedPlans.length; i++) {
|
|
9398
9974
|
const p = orderedPlans[i];
|
|
9399
|
-
|
|
9975
|
+
assertPlan();
|
|
9976
|
+
if (p.planned <= 0n) continue;
|
|
9400
9977
|
try {
|
|
9401
9978
|
results[p.agent.id] = await submit(p.agent, p.planned.toString());
|
|
9402
9979
|
notifyAgentResult(p.agent.id, results[p.agent.id]);
|
|
@@ -9420,6 +9997,7 @@ var OwneySDK = class {
|
|
|
9420
9997
|
}
|
|
9421
9998
|
}
|
|
9422
9999
|
if (Object.keys(results).length === 0) {
|
|
10000
|
+
throwUnconfirmed(agentErrors);
|
|
9423
10001
|
throw new OwneyError(
|
|
9424
10002
|
"WITHDRAW_ALL_FAILED",
|
|
9425
10003
|
`Failed to withdraw "${amount}" of "${asset}" from all eligible agents.`,
|
|
@@ -9437,13 +10015,17 @@ var OwneySDK = class {
|
|
|
9437
10015
|
const adjustment = result?.feeAdjustment;
|
|
9438
10016
|
const evidence = result?.evidence;
|
|
9439
10017
|
const submitted = submissionEvidence.get(plan.agent.id);
|
|
9440
|
-
if (plan.agent.id !== "yieldseeker" || !adjustment || !evidence || !submitted || typeof result.amount !== "string" || !/^\d+$/.test(result.amount) || typeof adjustment.grossAmount !== "string" || !/^\d+$/.test(adjustment.grossAmount) || typeof adjustment.feeAmount !== "string" || !/^\d+$/.test(adjustment.feeAmount) || evidence.agentId !== plan.agent.id || evidence.chainId !== chainId || evidence.token !== token || typeof evidence.walletAddress !== "string" || evidence.walletAddress.toLowerCase() !== state.walletAddress.toLowerCase() || typeof evidence.agentWallet !== "string" || !/^0x[\da-f]{40}$/i.test(evidence.agentWallet) || typeof result.txHash !== "string" || !/^0x[\da-f]{64}$/i.test(result.txHash) || typeof evidence.txHash !== "string" || typeof submitted.txHash !== "string" || evidence.txHash?.toLowerCase() !== result.txHash.toLowerCase() || submitted.txHash?.toLowerCase() !== result.txHash.toLowerCase() || submitted.agentId !== evidence.agentId || submitted.chainId !== chainId || submitted.token !== token || typeof submitted.walletAddress !== "string" || typeof submitted.agentWallet !== "string" || submitted.walletAddress.toLowerCase() !== state.walletAddress.toLowerCase() || submitted.agentWallet?.toLowerCase() !== evidence.agentWallet.toLowerCase() || evidence.transfer !== "confirmed" || evidence.delivery !== "confirmed" || submitted.transfer !== "confirmed" || submitted.delivery !== "confirmed" || evidence.confirmedAmount !== result.amount || submitted.confirmedAmount !== result.amount || evidence.intendedAmount
|
|
10018
|
+
if (plan.agent.id !== "yieldseeker" || !adjustment || !evidence || !submitted || typeof result.amount !== "string" || !/^\d+$/.test(result.amount) || typeof adjustment.grossAmount !== "string" || !/^\d+$/.test(adjustment.grossAmount) || typeof adjustment.feeAmount !== "string" || !/^\d+$/.test(adjustment.feeAmount) || evidence.agentId !== plan.agent.id || evidence.chainId !== chainId || evidence.token !== token || typeof evidence.walletAddress !== "string" || evidence.walletAddress.toLowerCase() !== state.walletAddress.toLowerCase() || typeof evidence.agentWallet !== "string" || !/^0x[\da-f]{40}$/i.test(evidence.agentWallet) || typeof result.txHash !== "string" || !/^0x[\da-f]{64}$/i.test(result.txHash) || typeof evidence.txHash !== "string" || typeof submitted.txHash !== "string" || evidence.txHash?.toLowerCase() !== result.txHash.toLowerCase() || submitted.txHash?.toLowerCase() !== result.txHash.toLowerCase() || submitted.agentId !== evidence.agentId || submitted.chainId !== chainId || submitted.token !== token || typeof submitted.walletAddress !== "string" || typeof submitted.agentWallet !== "string" || submitted.walletAddress.toLowerCase() !== state.walletAddress.toLowerCase() || submitted.agentWallet?.toLowerCase() !== evidence.agentWallet.toLowerCase() || evidence.transfer !== "confirmed" || evidence.delivery !== "confirmed" || submitted.transfer !== "confirmed" || submitted.delivery !== "confirmed" || evidence.confirmedAmount !== result.amount || submitted.confirmedAmount !== result.amount || ![result.amount, adjustment.grossAmount].includes(evidence.intendedAmount) || ![result.amount, adjustment.grossAmount].includes(submitted.intendedAmount)) return total;
|
|
9441
10019
|
const fee = BigInt(adjustment.feeAmount);
|
|
9442
10020
|
const net = BigInt(result.amount);
|
|
9443
10021
|
const gross = BigInt(adjustment.grossAmount);
|
|
9444
10022
|
return fee > 0n && net > 0n && gross === plan.planned && net + fee === gross ? total + fee : total;
|
|
9445
10023
|
}, 0n);
|
|
9446
|
-
|
|
10024
|
+
const pendingAmount = orderedPlans.reduce((sum, plan) => {
|
|
10025
|
+
const evidence = results[plan.agent.id]?.evidence;
|
|
10026
|
+
return evidence && (evidence.transfer === "pending" || evidence.transfer === "unknown") && evidence.delivery !== "failed" ? sum + plan.planned : sum;
|
|
10027
|
+
}, 0n);
|
|
10028
|
+
if (withdrawn + verifiedFeeDeductions + pendingAmount < requested) {
|
|
9447
10029
|
throw new OwneyError(
|
|
9448
10030
|
"WITHDRAW_PARTIAL_FAILURE",
|
|
9449
10031
|
`Withdrew "${withdrawn.toString()}" of requested "${amount}" of "${asset}". One or more agents failed; remaining balance could not cover the shortfall.`,
|
|
@@ -9451,6 +10033,7 @@ var OwneySDK = class {
|
|
|
9451
10033
|
asset,
|
|
9452
10034
|
requested: amount,
|
|
9453
10035
|
withdrawn: withdrawn.toString(),
|
|
10036
|
+
pendingAmount: pendingAmount.toString(),
|
|
9454
10037
|
partialResults: results,
|
|
9455
10038
|
agentErrors,
|
|
9456
10039
|
agentFailures,
|
|
@@ -9458,7 +10041,7 @@ var OwneySDK = class {
|
|
|
9458
10041
|
}
|
|
9459
10042
|
);
|
|
9460
10043
|
}
|
|
9461
|
-
return { agentResult: results, totalWithdrawn: withdrawn.toString() };
|
|
10044
|
+
return { agentResult: results, totalWithdrawn: Object.values(results).every((result) => confirmedWithdrawalAmount(result) !== void 0) ? withdrawn.toString() : null };
|
|
9462
10045
|
}
|
|
9463
10046
|
// --- Portfolio reads ---
|
|
9464
10047
|
/**
|
|
@@ -9625,10 +10208,8 @@ var OwneySDK = class {
|
|
|
9625
10208
|
* @returns {AccountAgentApy} for a single agent, or {OwneyAccountApy} with totalApy and per-agent breakdown
|
|
9626
10209
|
*/
|
|
9627
10210
|
/**
|
|
9628
|
-
* Daily cumulative
|
|
9629
|
-
* "recent earnings" subline.
|
|
9630
|
-
* `lifetime + unrealized + current x 0.9`, so the figure reconciles with the
|
|
9631
|
-
* balance headline rather than reading ~11% high. (ROUT-452)
|
|
10211
|
+
* Daily cumulative earnings in the selected asset's units, backing the
|
|
10212
|
+
* "recent earnings" subline. Each adapter uses its provider's earnings basis.
|
|
9632
10213
|
*
|
|
9633
10214
|
* Unlike getAccountApy this does NOT blend across agents: earnings are
|
|
9634
10215
|
* summed, not weighted, and an agent that fails to report must not silently
|
|
@@ -9661,7 +10242,7 @@ var OwneySDK = class {
|
|
|
9661
10242
|
const entries = [...this.getActiveAgents().entries()].filter(
|
|
9662
10243
|
([, agent]) => agent.getDailyEarnings
|
|
9663
10244
|
);
|
|
9664
|
-
const
|
|
10245
|
+
const settled = await Promise.allSettled(
|
|
9665
10246
|
entries.map(
|
|
9666
10247
|
([, agent]) => this.readAgent(
|
|
9667
10248
|
agent,
|
|
@@ -9671,23 +10252,15 @@ var OwneySDK = class {
|
|
|
9671
10252
|
)
|
|
9672
10253
|
)
|
|
9673
10254
|
);
|
|
9674
|
-
const
|
|
9675
|
-
|
|
9676
|
-
|
|
9677
|
-
|
|
9678
|
-
for (const point of points) {
|
|
9679
|
-
byDate.set(point.date, (byDate.get(point.date) ?? 0) + point.amount);
|
|
9680
|
-
}
|
|
9681
|
-
byAsset.set(asset, byDate);
|
|
9682
|
-
}
|
|
10255
|
+
const series = settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
|
|
10256
|
+
if (entries.length && !series.length) {
|
|
10257
|
+
const failure = settled.find((result) => result.status === "rejected");
|
|
10258
|
+
if (failure?.status === "rejected") throw failure.reason;
|
|
9683
10259
|
}
|
|
9684
10260
|
return {
|
|
9685
10261
|
walletAddress: series[0]?.walletAddress ?? state.walletAddress ?? "",
|
|
9686
10262
|
chainId,
|
|
9687
|
-
assets:
|
|
9688
|
-
asset,
|
|
9689
|
-
points: [...byDate.entries()].map(([date, amount]) => ({ date, amount })).sort((a, b) => a.date.localeCompare(b.date))
|
|
9690
|
-
})).sort((a, b) => a.asset.localeCompare(b.asset))
|
|
10263
|
+
assets: aggregateDailyEarnings(series, tokenSymbol)
|
|
9691
10264
|
};
|
|
9692
10265
|
}
|
|
9693
10266
|
async getAccountApy({
|
|
@@ -9926,16 +10499,16 @@ var OwneySDK = class {
|
|
|
9926
10499
|
);
|
|
9927
10500
|
}
|
|
9928
10501
|
const provider = this.requireConnectedProvider();
|
|
9929
|
-
const walletChainClient = (0,
|
|
10502
|
+
const walletChainClient = (0, import_viem18.createPublicClient)({
|
|
9930
10503
|
chain: VIEM_CHAIN2[chainId],
|
|
9931
|
-
transport: (0,
|
|
10504
|
+
transport: (0, import_viem18.custom)(provider)
|
|
9932
10505
|
});
|
|
9933
10506
|
const publicClient = this.getPaidRpcClient(chainId);
|
|
9934
10507
|
const approvalAmount = permit2ApprovalAmount(requiredAmount);
|
|
9935
|
-
const wallet = (0,
|
|
10508
|
+
const wallet = (0, import_viem18.createWalletClient)({
|
|
9936
10509
|
account: state.walletAddress,
|
|
9937
10510
|
chain: VIEM_CHAIN2[chainId],
|
|
9938
|
-
transport: (0,
|
|
10511
|
+
transport: (0, import_viem18.custom)(provider)
|
|
9939
10512
|
});
|
|
9940
10513
|
await ensureWalletOnChain(walletChainClient, wallet, chainId);
|
|
9941
10514
|
const hash = await wallet.writeContract({
|
|
@@ -10097,7 +10670,7 @@ var OwneySDK = class {
|
|
|
10097
10670
|
};
|
|
10098
10671
|
|
|
10099
10672
|
// src/agents/zyfai/zyfai.siwx.ts
|
|
10100
|
-
var
|
|
10673
|
+
var import_viem19 = require("viem");
|
|
10101
10674
|
var import_siwe2 = require("siwe");
|
|
10102
10675
|
var import_sdk2 = require("@zyfai/sdk");
|
|
10103
10676
|
|
|
@@ -10224,7 +10797,7 @@ function buildSIWXConfig(deps) {
|
|
|
10224
10797
|
issuedAt,
|
|
10225
10798
|
toString() {
|
|
10226
10799
|
return new import_siwe2.SiweMessage({
|
|
10227
|
-
address: (0,
|
|
10800
|
+
address: (0, import_viem19.getAddress)(accountAddress),
|
|
10228
10801
|
chainId: numericChainId(chainId),
|
|
10229
10802
|
domain,
|
|
10230
10803
|
uri,
|