@owney/sdk 0.7.25-beta.19 → 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 +897 -391
- package/dist/index.d.cts +19 -6
- package/dist/index.d.ts +19 -6
- package/dist/index.js +806 -298
- 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
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
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" };
|
|
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" };
|
|
2435
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,
|
|
@@ -3913,7 +4067,7 @@ function allocationEntry(action, context) {
|
|
|
3913
4067
|
const leg = deposit;
|
|
3914
4068
|
const symbol = typeof leg.assetSymbol === "string" ? leg.assetSymbol.toUpperCase() : "";
|
|
3915
4069
|
if (symbol !== context.asset && !(context.asset === "WETH" && symbol === "ETH")) return void 0;
|
|
3916
|
-
if (typeof leg.vaultAddress !== "string" || !(0,
|
|
4070
|
+
if (typeof leg.vaultAddress !== "string" || !(0, import_viem9.isAddress)(leg.vaultAddress)) return void 0;
|
|
3917
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;
|
|
3918
4072
|
if (rawAmount === void 0 || rawAmount <= 0n) return void 0;
|
|
3919
4073
|
const option = context.positions.find((position2) => position2.yieldOption.address.toLowerCase() === leg.vaultAddress.toLowerCase())?.yieldOption;
|
|
@@ -3921,7 +4075,7 @@ function allocationEntry(action, context) {
|
|
|
3921
4075
|
protocol: typeof leg.vaultProvider === "string" && leg.vaultProvider ? leg.vaultProvider : option?.provider || "Vault",
|
|
3922
4076
|
pool: typeof leg.vaultName === "string" && leg.vaultName ? leg.vaultName : option?.name,
|
|
3923
4077
|
tokenSymbol: context.asset,
|
|
3924
|
-
amount: (0,
|
|
4078
|
+
amount: (0, import_viem9.formatUnits)(rawAmount, YIELDSEEKER_ASSET_METADATA[context.asset].decimals)
|
|
3925
4079
|
});
|
|
3926
4080
|
amountRaw += rawAmount;
|
|
3927
4081
|
}
|
|
@@ -3940,7 +4094,7 @@ function allocationEntry(action, context) {
|
|
|
3940
4094
|
tokenSymbol: context.asset,
|
|
3941
4095
|
agentWallet: context.wallet.walletAddress,
|
|
3942
4096
|
amountRaw: String(amountRaw),
|
|
3943
|
-
amount: (0,
|
|
4097
|
+
amount: (0, import_viem9.formatUnits)(amountRaw, YIELDSEEKER_ASSET_METADATA[context.asset].decimals)
|
|
3944
4098
|
}]
|
|
3945
4099
|
};
|
|
3946
4100
|
}
|
|
@@ -4064,7 +4218,7 @@ function mapYieldseekerHistory(contexts, options) {
|
|
|
4064
4218
|
const known = new Set(target.logIndexes ?? []);
|
|
4065
4219
|
if (tx.logIndexes?.some((index) => !known.has(index))) {
|
|
4066
4220
|
target.amountRaw = String(BigInt(target.amountRaw ?? "0") + BigInt(tx.amountRaw));
|
|
4067
|
-
target.amount = (0,
|
|
4221
|
+
target.amount = (0, import_viem9.formatUnits)(
|
|
4068
4222
|
BigInt(target.amountRaw),
|
|
4069
4223
|
YIELDSEEKER_ASSET_METADATA[target.tokenSymbol].decimals
|
|
4070
4224
|
);
|
|
@@ -4145,7 +4299,7 @@ function mapYieldseekerAgentApy(options, days) {
|
|
|
4145
4299
|
}
|
|
4146
4300
|
|
|
4147
4301
|
// src/lib/remaining-vault-balance.ts
|
|
4148
|
-
var
|
|
4302
|
+
var import_viem10 = require("viem");
|
|
4149
4303
|
async function remainingVaultBalance(client, wallet, asset, vaults, blockNumber) {
|
|
4150
4304
|
const addresses = [...new Set(vaults.map((value) => value.toLowerCase()))];
|
|
4151
4305
|
if (addresses.length > 64) return void 0;
|
|
@@ -4156,8 +4310,8 @@ async function remainingVaultBalance(client, wallet, asset, vaults, blockNumber)
|
|
|
4156
4310
|
blockNumber,
|
|
4157
4311
|
allowFailure: true,
|
|
4158
4312
|
contracts: batch.map((address) => ({
|
|
4159
|
-
address: (0,
|
|
4160
|
-
abi:
|
|
4313
|
+
address: (0, import_viem10.getAddress)(address),
|
|
4314
|
+
abi: import_viem10.erc20Abi,
|
|
4161
4315
|
functionName: "balanceOf",
|
|
4162
4316
|
args: [wallet]
|
|
4163
4317
|
}))
|
|
@@ -4167,15 +4321,15 @@ async function remainingVaultBalance(client, wallet, asset, vaults, blockNumber)
|
|
|
4167
4321
|
for (let index = 0; index < batch.length; index++) {
|
|
4168
4322
|
const result = balances[index];
|
|
4169
4323
|
if (result?.status !== "success" || typeof result.result !== "bigint" || result.result < 0n) return void 0;
|
|
4170
|
-
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 });
|
|
4171
4325
|
}
|
|
4172
4326
|
if (!funded.length) return 0n;
|
|
4173
4327
|
const valuations = await client.multicall({
|
|
4174
4328
|
blockNumber,
|
|
4175
4329
|
allowFailure: true,
|
|
4176
4330
|
contracts: funded.flatMap(({ address, shares }) => [
|
|
4177
|
-
{ address, abi:
|
|
4178
|
-
{ address, abi:
|
|
4331
|
+
{ address, abi: import_viem10.erc4626Abi, functionName: "asset" },
|
|
4332
|
+
{ address, abi: import_viem10.erc4626Abi, functionName: "convertToAssets", args: [shares] }
|
|
4179
4333
|
])
|
|
4180
4334
|
});
|
|
4181
4335
|
if (valuations.length !== funded.length * 2) return void 0;
|
|
@@ -4191,12 +4345,12 @@ async function remainingVaultBalance(client, wallet, asset, vaults, blockNumber)
|
|
|
4191
4345
|
}
|
|
4192
4346
|
|
|
4193
4347
|
// src/agents/yieldseeker/yieldseeker.wallet-version.ts
|
|
4194
|
-
var
|
|
4348
|
+
var import_viem11 = require("viem");
|
|
4195
4349
|
var YIELDSEEKER_FACTORY = "0x9c7410a0faCAC60850C46eE5b58B518daec95130";
|
|
4196
4350
|
var YIELDSEEKER_V1_IMPLEMENTATION = "0x32403455357589523435dB18b414057D7cE05051";
|
|
4197
4351
|
var YIELDSEEKER_V2_IMPLEMENTATION = "0x613Db9c924ADB7A7A90c11b02Cce20c913E3Fe50";
|
|
4198
4352
|
var ERC1967_IMPLEMENTATION_SLOT = "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc";
|
|
4199
|
-
var walletAbi = (0,
|
|
4353
|
+
var walletAbi = (0, import_viem11.parseAbi)([
|
|
4200
4354
|
"function owner() view returns (address)",
|
|
4201
4355
|
"function ownerAgentIndex() view returns (uint256)",
|
|
4202
4356
|
"function baseAsset() view returns (address)",
|
|
@@ -4204,7 +4358,7 @@ var walletAbi = (0, import_viem10.parseAbi)([
|
|
|
4204
4358
|
"function upgradeToLatest()",
|
|
4205
4359
|
"event Upgraded(address indexed implementation)"
|
|
4206
4360
|
]);
|
|
4207
|
-
var factoryAbi = (0,
|
|
4361
|
+
var factoryAbi = (0, import_viem11.parseAbi)([
|
|
4208
4362
|
"function userWallets(address owner, uint256 index) view returns (address)",
|
|
4209
4363
|
"function agentWalletImplementation() view returns (address)"
|
|
4210
4364
|
]);
|
|
@@ -4212,9 +4366,9 @@ function yieldseekerOwnerPath(code) {
|
|
|
4212
4366
|
return !code || code === "0x" || /^0xef0100[0-9a-f]{40}$/i.test(code) ? "eoa" : "smart";
|
|
4213
4367
|
}
|
|
4214
4368
|
async function readYieldseekerWalletStatus(client, wallet, owner, asset, blockNumber) {
|
|
4215
|
-
const agentWallet = (0,
|
|
4216
|
-
const expectedOwner = (0,
|
|
4217
|
-
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);
|
|
4218
4372
|
const [code, ownerCode, slot, actualOwner, index, actualAsset, actualFactory, latest] = await Promise.all([
|
|
4219
4373
|
client.getBytecode({ address: agentWallet, blockNumber }),
|
|
4220
4374
|
client.getBytecode({ address: expectedOwner, blockNumber }),
|
|
@@ -4228,7 +4382,7 @@ async function readYieldseekerWalletStatus(client, wallet, owner, asset, blockNu
|
|
|
4228
4382
|
if (!code || code === "0x" || !slot || /^0x0+$/.test(slot)) {
|
|
4229
4383
|
throw new Error("Yieldseeker wallet is not a deployed ERC1967 proxy");
|
|
4230
4384
|
}
|
|
4231
|
-
const implementation = (0,
|
|
4385
|
+
const implementation = (0, import_viem11.getAddress)(`0x${slot.slice(-40)}`);
|
|
4232
4386
|
const mapped = await client.readContract({
|
|
4233
4387
|
address: YIELDSEEKER_FACTORY,
|
|
4234
4388
|
abi: factoryAbi,
|
|
@@ -4236,8 +4390,8 @@ async function readYieldseekerWalletStatus(client, wallet, owner, asset, blockNu
|
|
|
4236
4390
|
args: [expectedOwner, index],
|
|
4237
4391
|
blockNumber
|
|
4238
4392
|
});
|
|
4239
|
-
const verified = (0,
|
|
4240
|
-
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";
|
|
4241
4395
|
return {
|
|
4242
4396
|
agentWallet,
|
|
4243
4397
|
owner: actualOwner,
|
|
@@ -4246,13 +4400,13 @@ async function readYieldseekerWalletStatus(client, wallet, owner, asset, blockNu
|
|
|
4246
4400
|
implementation,
|
|
4247
4401
|
version,
|
|
4248
4402
|
verified,
|
|
4249
|
-
upgradeAvailable: version === "v1" && (0,
|
|
4403
|
+
upgradeAvailable: version === "v1" && (0, import_viem11.isAddressEqual)(latest, YIELDSEEKER_V2_IMPLEMENTATION)
|
|
4250
4404
|
};
|
|
4251
4405
|
}
|
|
4252
4406
|
var YIELDSEEKER_UPGRADE_ABI = walletAbi;
|
|
4253
4407
|
|
|
4254
4408
|
// src/agents/yieldseeker/yieldseeker.sponsored-withdraw.ts
|
|
4255
|
-
var
|
|
4409
|
+
var import_viem12 = require("viem");
|
|
4256
4410
|
var import_account_abstraction2 = require("viem/account-abstraction");
|
|
4257
4411
|
var import_accounts = require("viem/accounts");
|
|
4258
4412
|
var import_chains3 = require("viem/chains");
|
|
@@ -4339,7 +4493,7 @@ function rpcDiagnostics(data) {
|
|
|
4339
4493
|
details.revertName = data.revertName;
|
|
4340
4494
|
if (typeof data?.aaCode === "string" && /^AA[0-9]{2}$/.test(data.aaCode)) details.aaCode = data.aaCode;
|
|
4341
4495
|
if (typeof data?.panicCode === "string" && /^0x[0-9a-fA-F]{1,2}$/.test(data.panicCode)) {
|
|
4342
|
-
const panicCode = (0,
|
|
4496
|
+
const panicCode = (0, import_viem12.toHex)(BigInt(data.panicCode));
|
|
4343
4497
|
if (["0x0", "0x1", "0x11", "0x12", "0x21", "0x22", "0x31", "0x32", "0x41", "0x51"].includes(panicCode))
|
|
4344
4498
|
details.panicCode = panicCode;
|
|
4345
4499
|
}
|
|
@@ -4559,14 +4713,14 @@ async function submitEoa(input) {
|
|
|
4559
4713
|
throw sponsorError("Base did not return EIP-1559 gas fees.", true);
|
|
4560
4714
|
let operation = {
|
|
4561
4715
|
sender: input.agentWallet,
|
|
4562
|
-
nonce: (0,
|
|
4716
|
+
nonce: (0, import_viem12.toHex)(nonce),
|
|
4563
4717
|
initCode: "0x",
|
|
4564
4718
|
callData: input.callData,
|
|
4565
|
-
callGasLimit: (0,
|
|
4566
|
-
verificationGasLimit: (0,
|
|
4567
|
-
preVerificationGas: (0,
|
|
4568
|
-
maxFeePerGas: (0,
|
|
4569
|
-
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),
|
|
4570
4724
|
paymasterAndData: "0x",
|
|
4571
4725
|
signature: "0x"
|
|
4572
4726
|
};
|
|
@@ -4574,7 +4728,7 @@ async function submitEoa(input) {
|
|
|
4574
4728
|
const stub = await rpc(
|
|
4575
4729
|
input.rpcUrl,
|
|
4576
4730
|
"pm_getPaymasterStubData",
|
|
4577
|
-
[operation, ENTRY_POINT_V06, (0,
|
|
4731
|
+
[operation, ENTRY_POINT_V06, (0, import_viem12.toHex)(8453), {}],
|
|
4578
4732
|
"prepare"
|
|
4579
4733
|
);
|
|
4580
4734
|
if (!stub.paymasterAndData?.startsWith("0x"))
|
|
@@ -4589,7 +4743,7 @@ async function submitEoa(input) {
|
|
|
4589
4743
|
const final = await rpc(
|
|
4590
4744
|
input.rpcUrl,
|
|
4591
4745
|
"pm_getPaymasterData",
|
|
4592
|
-
[operation, ENTRY_POINT_V06, (0,
|
|
4746
|
+
[operation, ENTRY_POINT_V06, (0, import_viem12.toHex)(8453), {}],
|
|
4593
4747
|
"prepare"
|
|
4594
4748
|
);
|
|
4595
4749
|
if (!final.paymasterAndData?.startsWith("0x"))
|
|
@@ -4599,10 +4753,10 @@ async function submitEoa(input) {
|
|
|
4599
4753
|
const userOpHash = operationHash(operation);
|
|
4600
4754
|
await assertOwnerSession(input.state, input.owner);
|
|
4601
4755
|
assertIntentFresh(input.expiresAt);
|
|
4602
|
-
const wallet = (0,
|
|
4756
|
+
const wallet = (0, import_viem12.createWalletClient)({
|
|
4603
4757
|
account: input.owner,
|
|
4604
4758
|
chain: import_chains3.base,
|
|
4605
|
-
transport: (0,
|
|
4759
|
+
transport: (0, import_viem12.custom)(input.state.provider)
|
|
4606
4760
|
});
|
|
4607
4761
|
const signature = await wallet.signMessage({ message: { raw: userOpHash } });
|
|
4608
4762
|
operation = { ...operation, signature };
|
|
@@ -4680,13 +4834,13 @@ async function submitSmart(input) {
|
|
|
4680
4834
|
} catch {
|
|
4681
4835
|
throw sponsorError("This account cannot check paymaster support on Base.", true);
|
|
4682
4836
|
}
|
|
4683
|
-
const supportsPaymaster = capabilities?.[(0,
|
|
4837
|
+
const supportsPaymaster = capabilities?.[(0, import_viem12.toHex)(8453)]?.paymasterService?.supported ?? capabilities?.["8453"]?.paymasterService?.supported ?? capabilities?.["0x0"]?.paymasterService?.supported;
|
|
4684
4838
|
if (supportsPaymaster !== true)
|
|
4685
4839
|
throw sponsorError("This account cannot use a paymaster on Base.", true);
|
|
4686
4840
|
await assertOwnerSession(input.state, input.owner);
|
|
4687
4841
|
let sent;
|
|
4688
4842
|
assertIntentFresh(input.expiresAt);
|
|
4689
|
-
const requestedId = (0,
|
|
4843
|
+
const requestedId = (0, import_viem12.toHex)(globalThis.crypto.getRandomValues(new Uint8Array(32)));
|
|
4690
4844
|
savePending(input.onPending, { callsId: requestedId }, true);
|
|
4691
4845
|
await checkpoint(input.onBeforeSubmission, { callsId: requestedId });
|
|
4692
4846
|
try {
|
|
@@ -4695,7 +4849,7 @@ async function submitSmart(input) {
|
|
|
4695
4849
|
params: [{
|
|
4696
4850
|
version: "2.0.0",
|
|
4697
4851
|
from: input.owner,
|
|
4698
|
-
chainId: (0,
|
|
4852
|
+
chainId: (0, import_viem12.toHex)(8453),
|
|
4699
4853
|
id: requestedId,
|
|
4700
4854
|
atomicRequired: false,
|
|
4701
4855
|
calls: [{ to: input.agentWallet, value: "0x0", data: input.callData }],
|
|
@@ -4770,7 +4924,7 @@ async function submitSmart(input) {
|
|
|
4770
4924
|
);
|
|
4771
4925
|
}
|
|
4772
4926
|
async function submitYieldseekerSponsoredWithdrawal(input) {
|
|
4773
|
-
const owner = (0,
|
|
4927
|
+
const owner = (0, import_viem12.getAddress)(input.state.walletAddress);
|
|
4774
4928
|
const { intent, rpcUrl } = await requestIntent({
|
|
4775
4929
|
apiKey: input.apiKey,
|
|
4776
4930
|
routingApiBaseUrl: input.routingApiBaseUrl,
|
|
@@ -4789,7 +4943,7 @@ async function submitYieldseekerSponsoredWithdrawal(input) {
|
|
|
4789
4943
|
return intent.ownerPath === "eoa" ? submitEoa(args) : submitSmart(args);
|
|
4790
4944
|
}
|
|
4791
4945
|
async function submitYieldseekerSponsoredUpgrade(input) {
|
|
4792
|
-
const owner = (0,
|
|
4946
|
+
const owner = (0, import_viem12.getAddress)(input.state.walletAddress);
|
|
4793
4947
|
const { intent, rpcUrl } = await requestIntent({
|
|
4794
4948
|
apiKey: input.apiKey,
|
|
4795
4949
|
routingApiBaseUrl: input.routingApiBaseUrl,
|
|
@@ -4904,6 +5058,7 @@ var YieldseekerAgent = class {
|
|
|
4904
5058
|
receiptClient;
|
|
4905
5059
|
// A client preparation hint only; the routing API still checks live identity.
|
|
4906
5060
|
withdrawalVersionCache = /* @__PURE__ */ new Map();
|
|
5061
|
+
pendingUpgrades = /* @__PURE__ */ new Map();
|
|
4907
5062
|
transactionExecutor;
|
|
4908
5063
|
unwindReceiptWaiter;
|
|
4909
5064
|
agentContexts = /* @__PURE__ */ new Map();
|
|
@@ -4954,8 +5109,8 @@ var YieldseekerAgent = class {
|
|
|
4954
5109
|
if (useCachedV2 && cached && Date.now() - cached.at < 15 * 6e4) return { ...cached.status };
|
|
4955
5110
|
const status = await readYieldseekerWalletStatus(
|
|
4956
5111
|
this.getReceiptClient(),
|
|
4957
|
-
(0,
|
|
4958
|
-
(0,
|
|
5112
|
+
(0, import_viem13.getAddress)(context.wallet.walletAddress),
|
|
5113
|
+
(0, import_viem13.getAddress)(state.walletAddress),
|
|
4959
5114
|
YIELDSEEKER_ASSET_METADATA[asset].address
|
|
4960
5115
|
);
|
|
4961
5116
|
this.rememberWalletStatus(key2, status);
|
|
@@ -4985,12 +5140,12 @@ var YieldseekerAgent = class {
|
|
|
4985
5140
|
const pendingKey2 = `owney.yieldseeker.upgrade:${before.owner.toLowerCase()}:${before.agentWallet.toLowerCase()}`;
|
|
4986
5141
|
const confirmUpgrade = async (hash, receipt2) => {
|
|
4987
5142
|
this.withdrawalVersionCache.delete(versionKey);
|
|
4988
|
-
const upgradeTopic = (0,
|
|
5143
|
+
const upgradeTopic = (0, import_viem13.encodeEventTopics)({ abi: YIELDSEEKER_UPGRADE_ABI, eventName: "Upgraded" })[0];
|
|
4989
5144
|
const lastUpgrade = receipt2?.logs.filter((log) => log.address.toLowerCase() === before.agentWallet.toLowerCase() && log.topics[0] === upgradeTopic).at(-1);
|
|
4990
5145
|
const expectedUpgrade = (() => {
|
|
4991
5146
|
if (!lastUpgrade || lastUpgrade.removed) return false;
|
|
4992
5147
|
try {
|
|
4993
|
-
const event = (0,
|
|
5148
|
+
const event = (0, import_viem13.decodeEventLog)({ abi: YIELDSEEKER_UPGRADE_ABI, eventName: "Upgraded", data: lastUpgrade.data, topics: lastUpgrade.topics });
|
|
4994
5149
|
return event.args.implementation.toLowerCase() === YIELDSEEKER_V2_IMPLEMENTATION.toLowerCase();
|
|
4995
5150
|
} catch {
|
|
4996
5151
|
return false;
|
|
@@ -5019,10 +5174,30 @@ var YieldseekerAgent = class {
|
|
|
5019
5174
|
} catch {
|
|
5020
5175
|
storage5 = void 0;
|
|
5021
5176
|
}
|
|
5022
|
-
const
|
|
5177
|
+
const clearRecordedUpgrade = () => {
|
|
5178
|
+
this.pendingUpgrades.delete(pendingKey2);
|
|
5023
5179
|
try {
|
|
5024
5180
|
storage5?.removeItem(pendingKey2);
|
|
5025
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);
|
|
5026
5201
|
}
|
|
5027
5202
|
};
|
|
5028
5203
|
if (!storage5 && (gasMode === "sponsored" || before.ownerPath === "smart"))
|
|
@@ -5034,7 +5209,7 @@ var YieldseekerAgent = class {
|
|
|
5034
5209
|
);
|
|
5035
5210
|
let prior = null;
|
|
5036
5211
|
try {
|
|
5037
|
-
const saved = storage5?.getItem(pendingKey2);
|
|
5212
|
+
const saved = this.pendingUpgrades.has(pendingKey2) ? JSON.stringify(this.pendingUpgrades.get(pendingKey2)) : storage5?.getItem(pendingKey2);
|
|
5038
5213
|
try {
|
|
5039
5214
|
prior = JSON.parse(saved ?? "null");
|
|
5040
5215
|
} catch {
|
|
@@ -5078,7 +5253,7 @@ var YieldseekerAgent = class {
|
|
|
5078
5253
|
this.id
|
|
5079
5254
|
);
|
|
5080
5255
|
if (Number(callsStatus?.status) === 400 || Number(callsStatus?.status) === 500) {
|
|
5081
|
-
|
|
5256
|
+
clearRecordedUpgrade();
|
|
5082
5257
|
throw new OwneyError(
|
|
5083
5258
|
"SPONSOR_REQUEST_FAILED",
|
|
5084
5259
|
"The earlier sponsored upgrade failed.",
|
|
@@ -5090,8 +5265,8 @@ var YieldseekerAgent = class {
|
|
|
5090
5265
|
earlierHash = hashes.length === 1 ? hashes[0] : void 0;
|
|
5091
5266
|
}
|
|
5092
5267
|
if (earlierHash) {
|
|
5093
|
-
const recovered = await confirmUpgrade(earlierHash, await
|
|
5094
|
-
|
|
5268
|
+
const recovered = await confirmUpgrade(earlierHash, await readUpgradeReceipt(earlierHash));
|
|
5269
|
+
clearRecordedUpgrade();
|
|
5095
5270
|
return recovered;
|
|
5096
5271
|
}
|
|
5097
5272
|
throw new OwneyError(
|
|
@@ -5108,7 +5283,7 @@ var YieldseekerAgent = class {
|
|
|
5108
5283
|
{ version: before.version },
|
|
5109
5284
|
this.id
|
|
5110
5285
|
);
|
|
5111
|
-
const data = (0,
|
|
5286
|
+
const data = (0, import_viem13.encodeFunctionData)({ abi: YIELDSEEKER_UPGRADE_ABI, functionName: "upgradeToLatest" });
|
|
5112
5287
|
let txHash;
|
|
5113
5288
|
let receipt;
|
|
5114
5289
|
if (gasMode === "sponsored") {
|
|
@@ -5135,33 +5310,52 @@ var YieldseekerAgent = class {
|
|
|
5135
5310
|
asset: YIELDSEEKER_ASSET_METADATA[asset].address,
|
|
5136
5311
|
callData: data,
|
|
5137
5312
|
onPending: (pending) => {
|
|
5138
|
-
const current = storage5.getItem(pendingKey2);
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
...pending
|
|
5143
|
-
}));
|
|
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);
|
|
5144
5317
|
}
|
|
5145
5318
|
});
|
|
5146
5319
|
txHash = upgraded.txHash;
|
|
5147
5320
|
receipt = upgraded.receipt;
|
|
5148
5321
|
} catch (error) {
|
|
5149
|
-
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();
|
|
5150
5323
|
throw error;
|
|
5151
5324
|
}
|
|
5152
5325
|
} else {
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
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
|
+
}
|
|
5162
5356
|
}
|
|
5163
|
-
const confirmed = await confirmUpgrade(txHash, receipt ?? await
|
|
5164
|
-
|
|
5357
|
+
const confirmed = await confirmUpgrade(txHash, receipt ?? await readUpgradeReceipt(txHash));
|
|
5358
|
+
clearRecordedUpgrade();
|
|
5165
5359
|
return confirmed;
|
|
5166
5360
|
}
|
|
5167
5361
|
async disconnect() {
|
|
@@ -5238,12 +5432,12 @@ var YieldseekerAgent = class {
|
|
|
5238
5432
|
} else {
|
|
5239
5433
|
try {
|
|
5240
5434
|
txHash = await this.submitTransaction(state, chainId, {
|
|
5241
|
-
from: (0,
|
|
5435
|
+
from: (0, import_viem13.getAddress)(state.walletAddress),
|
|
5242
5436
|
to: YIELDSEEKER_ASSET_METADATA[asset].address,
|
|
5243
|
-
data: (0,
|
|
5244
|
-
abi:
|
|
5437
|
+
data: (0, import_viem13.encodeFunctionData)({
|
|
5438
|
+
abi: import_viem13.erc20Abi,
|
|
5245
5439
|
functionName: "transfer",
|
|
5246
|
-
args: [(0,
|
|
5440
|
+
args: [(0, import_viem13.getAddress)(context.wallet.walletAddress), BigInt(amount)]
|
|
5247
5441
|
}),
|
|
5248
5442
|
value: "0",
|
|
5249
5443
|
chainId
|
|
@@ -5377,7 +5571,7 @@ var YieldseekerAgent = class {
|
|
|
5377
5571
|
);
|
|
5378
5572
|
const positionsRead = this.readWithdrawalPositions(state, chainId, context);
|
|
5379
5573
|
const metadata = YIELDSEEKER_ASSET_METADATA[asset];
|
|
5380
|
-
const agentWallet = (0,
|
|
5574
|
+
const agentWallet = (0, import_viem13.getAddress)(context.wallet.walletAddress);
|
|
5381
5575
|
const readOwnerFunds = async (blockNumber) => {
|
|
5382
5576
|
const feeTracker = await withPaidRpcDiagnostics(() => this.getReceiptClient().readContract({
|
|
5383
5577
|
address: agentWallet,
|
|
@@ -5386,18 +5580,18 @@ var YieldseekerAgent = class {
|
|
|
5386
5580
|
blockNumber
|
|
5387
5581
|
}), chainId, "eth_call", this.id);
|
|
5388
5582
|
this.assertSession(generation, chainId, asset);
|
|
5389
|
-
if (!(0,
|
|
5583
|
+
if (!(0, import_viem13.isAddress)(feeTracker) || /^0x0{40}$/i.test(feeTracker))
|
|
5390
5584
|
throw this.invalidResponse("wallet fee tracker");
|
|
5391
5585
|
const [idle2, fees] = await Promise.all([
|
|
5392
5586
|
withPaidRpcDiagnostics(() => this.getReceiptClient().readContract({
|
|
5393
5587
|
address: metadata.address,
|
|
5394
|
-
abi:
|
|
5588
|
+
abi: import_viem13.erc20Abi,
|
|
5395
5589
|
functionName: "balanceOf",
|
|
5396
5590
|
args: [agentWallet],
|
|
5397
5591
|
blockNumber
|
|
5398
5592
|
}), chainId, "eth_call", this.id),
|
|
5399
5593
|
withPaidRpcDiagnostics(() => this.getReceiptClient().readContract({
|
|
5400
|
-
address: (0,
|
|
5594
|
+
address: (0, import_viem13.getAddress)(feeTracker),
|
|
5401
5595
|
abi: YIELDSEEKER_FEE_TRACKER_ABI,
|
|
5402
5596
|
functionName: "getFeesOwed",
|
|
5403
5597
|
args: [agentWallet],
|
|
@@ -5439,13 +5633,13 @@ var YieldseekerAgent = class {
|
|
|
5439
5633
|
let active = true;
|
|
5440
5634
|
const checks = this.readVaultLiquidity(values.map((position2) => position2.yieldOption), agentWallet, blockNumber).catch(() => []);
|
|
5441
5635
|
const reads = values.map(async (position2, index) => {
|
|
5442
|
-
const address = (0,
|
|
5636
|
+
const address = (0, import_viem13.getAddress)(position2.yieldOption.address);
|
|
5443
5637
|
try {
|
|
5444
5638
|
const group = (await checks).slice(index * 3, index * 3 + 3);
|
|
5445
5639
|
if (!active || group.length !== 3 || group.some((value) => value.status !== "success")) return null;
|
|
5446
5640
|
this.assertSession(generation, chainId, asset);
|
|
5447
5641
|
const [underlying, shares, withdrawable] = group.map((value) => value.result);
|
|
5448
|
-
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;
|
|
5449
5643
|
const verified = { ...position2, assetsRaw: shares.toString(), withdrawableAssetsRaw: withdrawable.toString() };
|
|
5450
5644
|
if (shares > 0n && withdrawable === 0n) {
|
|
5451
5645
|
let positiveValue = false;
|
|
@@ -5453,7 +5647,7 @@ var YieldseekerAgent = class {
|
|
|
5453
5647
|
try {
|
|
5454
5648
|
const value = await this.getReceiptClient().readContract({
|
|
5455
5649
|
address,
|
|
5456
|
-
abi:
|
|
5650
|
+
abi: import_viem13.erc4626Abi,
|
|
5457
5651
|
functionName,
|
|
5458
5652
|
args: [shares],
|
|
5459
5653
|
blockNumber
|
|
@@ -5543,6 +5737,18 @@ var YieldseekerAgent = class {
|
|
|
5543
5737
|
);
|
|
5544
5738
|
}
|
|
5545
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
|
+
);
|
|
5546
5752
|
throw new OwneyError(
|
|
5547
5753
|
"WITHDRAW_INSUFFICIENT_BALANCE",
|
|
5548
5754
|
`Requested withdrawal "${requested}" exceeds available Yieldseeker balance "${totalAvailable}" for asset "${asset}".`,
|
|
@@ -5557,6 +5763,7 @@ var YieldseekerAgent = class {
|
|
|
5557
5763
|
const requiredIdle = requested + initialFunds.fees;
|
|
5558
5764
|
let remaining = requiredIdle > idle ? requiredIdle - idle : 0n;
|
|
5559
5765
|
let grossUnwound = 0n;
|
|
5766
|
+
let confirmedUnwinds = 0n;
|
|
5560
5767
|
let latestUnwindBlock;
|
|
5561
5768
|
const unwind = async (position2, assetsRaw) => {
|
|
5562
5769
|
this.assertSession(generation, chainId, asset);
|
|
@@ -5574,7 +5781,10 @@ var YieldseekerAgent = class {
|
|
|
5574
5781
|
if (!this.isTransactionHash(response?.transactionHash)) throw this.invalidResponse("position withdrawal");
|
|
5575
5782
|
unwindTransactionHash = response.transactionHash;
|
|
5576
5783
|
const unwindReceipt = await this.waitForReceipt(state, chainId, unwindTransactionHash);
|
|
5577
|
-
if (unwindReceipt)
|
|
5784
|
+
if (unwindReceipt) {
|
|
5785
|
+
latestUnwindBlock = unwindReceipt.blockNumber;
|
|
5786
|
+
confirmedUnwinds++;
|
|
5787
|
+
}
|
|
5578
5788
|
} catch (error) {
|
|
5579
5789
|
this.invalidateFundingRead(state, chainId, asset);
|
|
5580
5790
|
throw new OwneyError(
|
|
@@ -5644,7 +5854,7 @@ var YieldseekerAgent = class {
|
|
|
5644
5854
|
const feeRate = feeRateBps ?? 0;
|
|
5645
5855
|
const maxFee = confirmedMovement && Number.isInteger(feeRate) && feeRate >= 0 && feeRate <= 1e3 ? (grossUnwound * BigInt(feeRate) + 9999n) / 10000n : 0n;
|
|
5646
5856
|
const shortfall = availableForOwner < requested ? requested - availableForOwner : 0n;
|
|
5647
|
-
if (availableForOwner === 0n || amount !== void 0 && shortfall > maxFee) {
|
|
5857
|
+
if (availableForOwner === 0n || amount !== void 0 && shortfall > maxFee + confirmedUnwinds) {
|
|
5648
5858
|
this.invalidateFundingRead(state, chainId, asset);
|
|
5649
5859
|
if (amount === void 0 && positionsStatus !== "empty")
|
|
5650
5860
|
throw new OwneyError(
|
|
@@ -5666,14 +5876,15 @@ var YieldseekerAgent = class {
|
|
|
5666
5876
|
delta: maxSettlementBasis.delta - payout,
|
|
5667
5877
|
expectedNetDeposits: maxSettlementBasis.expectedNetDeposits - payout
|
|
5668
5878
|
} : this.snapshotMovement(state, chainId, context, -payout);
|
|
5669
|
-
const account = (0,
|
|
5879
|
+
const account = (0, import_viem13.getAddress)(state.walletAddress);
|
|
5670
5880
|
let receipt;
|
|
5671
|
-
const base6 = { agentId: this.id, chainId, token: asset, walletAddress: state.walletAddress, agentWallet: context.wallet.walletAddress, intendedAmount: amount
|
|
5672
|
-
|
|
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)({
|
|
5673
5884
|
abi: YIELDSEEKER_AGENT_WALLET_ABI,
|
|
5674
5885
|
functionName: "withdrawAllAssetToUser",
|
|
5675
5886
|
args: [account, metadata.address]
|
|
5676
|
-
}) : (0,
|
|
5887
|
+
}) : (0, import_viem13.encodeFunctionData)({
|
|
5677
5888
|
abi: YIELDSEEKER_AGENT_WALLET_ABI,
|
|
5678
5889
|
functionName: "withdrawAssetToUser",
|
|
5679
5890
|
args: [account, metadata.address, payout]
|
|
@@ -5689,10 +5900,13 @@ var YieldseekerAgent = class {
|
|
|
5689
5900
|
refreshYieldseekerSignature: (rejected) => this.auth.refreshToken(state, chainId, rejected),
|
|
5690
5901
|
userId: context.user.userId,
|
|
5691
5902
|
agentId: context.agent.agentId,
|
|
5692
|
-
agentWallet: (0,
|
|
5903
|
+
agentWallet: (0, import_viem13.getAddress)(context.wallet.walletAddress),
|
|
5693
5904
|
asset: metadata.address,
|
|
5694
5905
|
callData: data,
|
|
5695
|
-
onPending: (pending) =>
|
|
5906
|
+
onPending: (pending) => {
|
|
5907
|
+
submissionEvidence = { ...submissionEvidence, ...pending };
|
|
5908
|
+
notifyFunding(onProgress, submissionEvidence);
|
|
5909
|
+
},
|
|
5696
5910
|
onBeforeSubmission: async (pending) => {
|
|
5697
5911
|
await onBeforeSubmission?.({ ...base6, ...pending });
|
|
5698
5912
|
onOwnerTransferAttempted?.();
|
|
@@ -5704,7 +5918,7 @@ var YieldseekerAgent = class {
|
|
|
5704
5918
|
onOwnerTransferAttempted?.();
|
|
5705
5919
|
txHash = await this.submitTransaction(state, chainId, {
|
|
5706
5920
|
from: account,
|
|
5707
|
-
to: (0,
|
|
5921
|
+
to: (0, import_viem13.getAddress)(context.wallet.walletAddress),
|
|
5708
5922
|
data,
|
|
5709
5923
|
value: "0",
|
|
5710
5924
|
chainId
|
|
@@ -5712,10 +5926,20 @@ var YieldseekerAgent = class {
|
|
|
5712
5926
|
receipt = value;
|
|
5713
5927
|
});
|
|
5714
5928
|
}
|
|
5715
|
-
|
|
5716
|
-
settlement = plannedMovement;
|
|
5717
|
-
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" };
|
|
5718
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;
|
|
5719
5943
|
let completion = maxLiquidity && !maxLiquidity.complete ? "unverified" : void 0;
|
|
5720
5944
|
if (amount === void 0) {
|
|
5721
5945
|
const verificationDeadline = Date.now() + YIELDSEEKER_MAX_POSITION_VERIFICATION_MS;
|
|
@@ -5736,7 +5960,7 @@ var YieldseekerAgent = class {
|
|
|
5736
5960
|
positions = proof.positions;
|
|
5737
5961
|
positionsStatus = hasPositions(positions) ? "remaining" : proof.verified ? "empty" : "unavailable";
|
|
5738
5962
|
if (positionsStatus === "remaining") {
|
|
5739
|
-
const result = { txHash, type: "partial", amount: evidence.confirmedAmount ??
|
|
5963
|
+
const result = { txHash, type: "partial", amount: evidence.confirmedAmount ?? "0", evidence };
|
|
5740
5964
|
throw new OwneyError(
|
|
5741
5965
|
"WITHDRAW_PARTIAL_FAILURE",
|
|
5742
5966
|
"Yieldseeker MAX could not confirm that all vault positions were cleared.",
|
|
@@ -5756,7 +5980,7 @@ var YieldseekerAgent = class {
|
|
|
5756
5980
|
}
|
|
5757
5981
|
if (!proof.verified) completion = "unverified";
|
|
5758
5982
|
}
|
|
5759
|
-
if (
|
|
5983
|
+
if (explicitEmptyPayout)
|
|
5760
5984
|
throw new OwneyError(
|
|
5761
5985
|
"WITHDRAW_INSUFFICIENT_BALANCE",
|
|
5762
5986
|
"The Yieldseeker withdrawal completed without transferring funds.",
|
|
@@ -5771,7 +5995,7 @@ var YieldseekerAgent = class {
|
|
|
5771
5995
|
type: amount === void 0 && !completion ? "full" : "partial",
|
|
5772
5996
|
...completion ? { completion } : {},
|
|
5773
5997
|
...feeAdjustment ? { feeAdjustment } : {},
|
|
5774
|
-
amount: evidence.confirmedAmount ??
|
|
5998
|
+
amount: evidence.confirmedAmount ?? "0",
|
|
5775
5999
|
evidence
|
|
5776
6000
|
};
|
|
5777
6001
|
} finally {
|
|
@@ -5812,17 +6036,17 @@ var YieldseekerAgent = class {
|
|
|
5812
6036
|
return proof.available;
|
|
5813
6037
|
}
|
|
5814
6038
|
async readVaultLiquidity(options, wallet, blockNumber) {
|
|
5815
|
-
const owner = (0,
|
|
6039
|
+
const owner = (0, import_viem13.getAddress)(wallet);
|
|
5816
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));
|
|
5817
6041
|
const results = await Promise.all(batches.map((batch) => this.getReceiptClient().multicall({
|
|
5818
6042
|
blockNumber,
|
|
5819
6043
|
allowFailure: true,
|
|
5820
6044
|
contracts: batch.flatMap((option) => {
|
|
5821
|
-
const address = (0,
|
|
6045
|
+
const address = (0, import_viem13.getAddress)(option.address);
|
|
5822
6046
|
return [
|
|
5823
|
-
{ address, abi:
|
|
5824
|
-
{ address, abi:
|
|
5825
|
-
{ 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] }
|
|
5826
6050
|
];
|
|
5827
6051
|
})
|
|
5828
6052
|
})));
|
|
@@ -5833,7 +6057,7 @@ var YieldseekerAgent = class {
|
|
|
5833
6057
|
const seen = /* @__PURE__ */ new Set();
|
|
5834
6058
|
for (const value of values) {
|
|
5835
6059
|
const option = value?.yieldOption;
|
|
5836
|
-
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))
|
|
5837
6061
|
throw this.invalidResponse("yield positions");
|
|
5838
6062
|
seen.add(option.address.toLowerCase());
|
|
5839
6063
|
}
|
|
@@ -5846,7 +6070,7 @@ var YieldseekerAgent = class {
|
|
|
5846
6070
|
const historic = this.readCache.get(`historic:${key2}`)?.value?.position;
|
|
5847
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()));
|
|
5848
6072
|
for (const option of this.yieldOptions.get(context.asset)?.value ?? []) {
|
|
5849
|
-
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;
|
|
5850
6074
|
hints.set(option.address.toLowerCase(), {
|
|
5851
6075
|
yieldOption: option,
|
|
5852
6076
|
assetsRaw: "0",
|
|
@@ -5898,7 +6122,7 @@ var YieldseekerAgent = class {
|
|
|
5898
6122
|
const read2 = async () => {
|
|
5899
6123
|
const client = this.getReceiptClient();
|
|
5900
6124
|
const blockNumber = await client.getBlockNumber({ cacheTime: 0 });
|
|
5901
|
-
const wallet = (0,
|
|
6125
|
+
const wallet = (0, import_viem13.getAddress)(context.wallet.walletAddress);
|
|
5902
6126
|
assertReadCurrent();
|
|
5903
6127
|
if (typeof blockNumber !== "bigint") throw unavailable();
|
|
5904
6128
|
const indexedPositions = this.validateWithdrawalPositions(positions ?? [], chainId, context.asset);
|
|
@@ -5908,11 +6132,11 @@ var YieldseekerAgent = class {
|
|
|
5908
6132
|
for (const position2 of indexedPositions) candidates.set(position2.yieldOption.address.toLowerCase(), position2.yieldOption);
|
|
5909
6133
|
const options = [...candidates.values()];
|
|
5910
6134
|
if (options.length > YIELDSEEKER_WITHDRAWAL_CANDIDATE_LIMIT) throw unavailable();
|
|
5911
|
-
const
|
|
5912
|
-
|
|
6135
|
+
const checksRead = this.readVaultLiquidity(options, wallet, blockNumber).then((value) => ({ value }), (error) => ({ error }));
|
|
6136
|
+
const [idle, feeTracker] = await Promise.all([
|
|
5913
6137
|
client.readContract({
|
|
5914
6138
|
address: metadata.address,
|
|
5915
|
-
abi:
|
|
6139
|
+
abi: import_viem13.erc20Abi,
|
|
5916
6140
|
functionName: "balanceOf",
|
|
5917
6141
|
args: [wallet],
|
|
5918
6142
|
blockNumber
|
|
@@ -5924,10 +6148,10 @@ var YieldseekerAgent = class {
|
|
|
5924
6148
|
blockNumber
|
|
5925
6149
|
})
|
|
5926
6150
|
]);
|
|
5927
|
-
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();
|
|
5928
6152
|
assertReadCurrent();
|
|
5929
6153
|
const fees = await client.readContract({
|
|
5930
|
-
address: (0,
|
|
6154
|
+
address: (0, import_viem13.getAddress)(feeTracker),
|
|
5931
6155
|
abi: YIELDSEEKER_FEE_TRACKER_ABI,
|
|
5932
6156
|
functionName: "getFeesOwed",
|
|
5933
6157
|
args: [wallet],
|
|
@@ -5937,6 +6161,18 @@ var YieldseekerAgent = class {
|
|
|
5937
6161
|
const verified = [];
|
|
5938
6162
|
const verifiedVaults = [];
|
|
5939
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);
|
|
5940
6176
|
const collect = (options2, results) => {
|
|
5941
6177
|
assertReadCurrent();
|
|
5942
6178
|
const known = this.balanceVaults.get(contextKey) ?? /* @__PURE__ */ new Set();
|
|
@@ -5952,7 +6188,7 @@ var YieldseekerAgent = class {
|
|
|
5952
6188
|
return;
|
|
5953
6189
|
}
|
|
5954
6190
|
const [underlying, shares, withdrawable] = group.map((value) => value.result);
|
|
5955
|
-
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) {
|
|
5956
6192
|
valid2 = false;
|
|
5957
6193
|
return;
|
|
5958
6194
|
}
|
|
@@ -5969,17 +6205,10 @@ var YieldseekerAgent = class {
|
|
|
5969
6205
|
});
|
|
5970
6206
|
return valid2;
|
|
5971
6207
|
};
|
|
5972
|
-
const
|
|
5973
|
-
|
|
5974
|
-
|
|
5975
|
-
|
|
5976
|
-
fees,
|
|
5977
|
-
available: idle + deployed > fees ? idle + deployed - fees : 0n,
|
|
5978
|
-
positions: [...verified],
|
|
5979
|
-
verifiedVaults: [...verifiedVaults],
|
|
5980
|
-
indexedPositions,
|
|
5981
|
-
complete
|
|
5982
|
-
});
|
|
6208
|
+
const checks = await checksRead;
|
|
6209
|
+
assertReadCurrent();
|
|
6210
|
+
if ("error" in checks) throw checks.error;
|
|
6211
|
+
const allKnownVerified = collect(options, checks.value);
|
|
5983
6212
|
knownProof = proof(false);
|
|
5984
6213
|
const indexed = new Map(indexedPositions.map((position2) => [position2.yieldOption.address.toLowerCase(), position2]));
|
|
5985
6214
|
const discrepancy = verified.some((position2) => {
|
|
@@ -5996,7 +6225,7 @@ var YieldseekerAgent = class {
|
|
|
5996
6225
|
assertReadCurrent();
|
|
5997
6226
|
const eligible = /* @__PURE__ */ new Map();
|
|
5998
6227
|
for (const option of catalog ?? []) {
|
|
5999
|
-
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))
|
|
6000
6229
|
eligible.set(option.address.toLowerCase(), option);
|
|
6001
6230
|
}
|
|
6002
6231
|
const extra = [...eligible].filter(([address]) => !candidates.has(address)).map(([, option]) => option);
|
|
@@ -6047,7 +6276,7 @@ var YieldseekerAgent = class {
|
|
|
6047
6276
|
const key2 = this.contextKey(state, evidence.chainId, evidence.token);
|
|
6048
6277
|
const generation = this.readGeneration, version = this.portfolioVersion(key2);
|
|
6049
6278
|
if (read2.readVersion !== version) return void 0;
|
|
6050
|
-
const wallet = (0,
|
|
6279
|
+
const wallet = (0, import_viem13.getAddress)(context.wallet.walletAddress);
|
|
6051
6280
|
const asset = YIELDSEEKER_ASSET_METADATA[evidence.token];
|
|
6052
6281
|
const client = this.getReceiptClient();
|
|
6053
6282
|
const blockNumber = await client.getBlockNumber({ cacheTime: 0 });
|
|
@@ -6055,10 +6284,10 @@ var YieldseekerAgent = class {
|
|
|
6055
6284
|
const vaults = [...this.balanceVaults.get(key2) ?? []];
|
|
6056
6285
|
const [invested, idle, tracker] = await Promise.all([
|
|
6057
6286
|
remainingVaultBalance(client, wallet, asset.address, vaults, blockNumber),
|
|
6058
|
-
client.readContract({ address: asset.address, abi:
|
|
6287
|
+
client.readContract({ address: asset.address, abi: import_viem13.erc20Abi, functionName: "balanceOf", args: [wallet], blockNumber }),
|
|
6059
6288
|
client.readContract({ address: wallet, abi: YIELDSEEKER_AGENT_WALLET_ABI, functionName: "feeTracker", blockNumber })
|
|
6060
6289
|
]);
|
|
6061
|
-
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;
|
|
6062
6291
|
const fees = await client.readContract({
|
|
6063
6292
|
address: tracker,
|
|
6064
6293
|
abi: YIELDSEEKER_FEE_TRACKER_ABI,
|
|
@@ -6071,7 +6300,7 @@ var YieldseekerAgent = class {
|
|
|
6071
6300
|
const total = idle + invested > fees ? idle + invested - fees : 0n;
|
|
6072
6301
|
const displayed = balance.assetBalances?.find((item) => item.chainId === evidence.chainId && item.asset === evidence.token);
|
|
6073
6302
|
if (!displayed || !evidence.confirmedAmount || !/^\d+$/.test(evidence.confirmedAmount)) return void 0;
|
|
6074
|
-
const amount = (0,
|
|
6303
|
+
const amount = (0, import_viem13.parseUnits)(displayed.amount, asset.decimals);
|
|
6075
6304
|
if (amount < 0n) return void 0;
|
|
6076
6305
|
const displayUnit = evidence.token === "USDC" ? 5000n : 500000000000n;
|
|
6077
6306
|
const movementUnit = BigInt(evidence.confirmedAmount) / 1000n;
|
|
@@ -6117,9 +6346,9 @@ var YieldseekerAgent = class {
|
|
|
6117
6346
|
if (!context) return void 0;
|
|
6118
6347
|
const idle = await withPaidRpcDiagnostics(() => this.getReceiptClient().readContract({
|
|
6119
6348
|
address: YIELDSEEKER_ASSET_METADATA[asset].address,
|
|
6120
|
-
abi:
|
|
6349
|
+
abi: import_viem13.erc20Abi,
|
|
6121
6350
|
functionName: "balanceOf",
|
|
6122
|
-
args: [(0,
|
|
6351
|
+
args: [(0, import_viem13.getAddress)(context.wallet.walletAddress)]
|
|
6123
6352
|
}), chainId, "eth_call", this.id);
|
|
6124
6353
|
this.assertSession(generation, chainId, asset);
|
|
6125
6354
|
if (typeof idle !== "bigint" || idle < 0n) throw this.invalidResponse("wallet deposit balance");
|
|
@@ -6127,7 +6356,7 @@ var YieldseekerAgent = class {
|
|
|
6127
6356
|
}
|
|
6128
6357
|
async getEarnings(state, chainId) {
|
|
6129
6358
|
this.assertChain(chainId);
|
|
6130
|
-
return mapYieldseekerEarnings(await this.loadPortfolio(state, chainId, {}));
|
|
6359
|
+
return mapYieldseekerEarnings(await this.loadPortfolio(state, chainId, { includePositions: false }));
|
|
6131
6360
|
}
|
|
6132
6361
|
async getAccountApy(state, chainId, days, tokenSymbol) {
|
|
6133
6362
|
this.assertChain(chainId);
|
|
@@ -6166,7 +6395,7 @@ var YieldseekerAgent = class {
|
|
|
6166
6395
|
);
|
|
6167
6396
|
const vaultAddresses = new Set(
|
|
6168
6397
|
catalog.flat().filter(
|
|
6169
|
-
(yieldOption) => yieldOption.chainId === chainId && (0,
|
|
6398
|
+
(yieldOption) => yieldOption.chainId === chainId && (0, import_viem13.isAddress)(yieldOption.address)
|
|
6170
6399
|
).map((yieldOption) => yieldOption.address.toLowerCase())
|
|
6171
6400
|
);
|
|
6172
6401
|
return mapYieldseekerHistory(contexts, {
|
|
@@ -6295,7 +6524,7 @@ var YieldseekerAgent = class {
|
|
|
6295
6524
|
`/users/${user.userId}/agents/${agent.agentId}/wallet`
|
|
6296
6525
|
).then((walletResponse) => {
|
|
6297
6526
|
this.assertSession(generation, chainId, asset);
|
|
6298
|
-
if (!walletResponse?.agentWallet || !(0,
|
|
6527
|
+
if (!walletResponse?.agentWallet || !(0, import_viem13.isAddress)(walletResponse.agentWallet.walletAddress)) {
|
|
6299
6528
|
throw this.invalidResponse("agent wallet");
|
|
6300
6529
|
}
|
|
6301
6530
|
const context = {
|
|
@@ -6325,7 +6554,7 @@ var YieldseekerAgent = class {
|
|
|
6325
6554
|
this.users.set(key2, persisted);
|
|
6326
6555
|
return persisted;
|
|
6327
6556
|
}
|
|
6328
|
-
const walletAddress = (0,
|
|
6557
|
+
const walletAddress = (0, import_viem13.getAddress)(state.walletAddress);
|
|
6329
6558
|
const generation = this.readGeneration;
|
|
6330
6559
|
let user = null;
|
|
6331
6560
|
try {
|
|
@@ -6709,7 +6938,7 @@ var YieldseekerAgent = class {
|
|
|
6709
6938
|
this.agentPath(context, "deploy"),
|
|
6710
6939
|
{ method: "POST", body: {} }
|
|
6711
6940
|
);
|
|
6712
|
-
if (!deployed?.agentWallet || !(0,
|
|
6941
|
+
if (!deployed?.agentWallet || !(0, import_viem13.isAddress)(deployed.agentWallet.walletAddress) || deployed.agentWallet.walletAddress.toLowerCase() !== walletAddress) {
|
|
6713
6942
|
throw this.invalidResponse("agent deployment", {
|
|
6714
6943
|
reason: "Deploy did not return the expected Agent Wallet."
|
|
6715
6944
|
});
|
|
@@ -6812,20 +7041,20 @@ var YieldseekerAgent = class {
|
|
|
6812
7041
|
}
|
|
6813
7042
|
async submitTransaction(state, chainId, transaction, onSubmitted, onReceipt) {
|
|
6814
7043
|
if (this.transactionExecutor) {
|
|
6815
|
-
const hash2 = await this.transactionExecutor(state, chainId, transaction);
|
|
7044
|
+
const hash2 = await this.transactionExecutor(state, chainId, transaction, onReceipt);
|
|
6816
7045
|
onSubmitted?.(hash2);
|
|
6817
7046
|
return hash2;
|
|
6818
7047
|
}
|
|
6819
7048
|
this.assertTransaction(transaction, state, chainId);
|
|
6820
|
-
const account = (0,
|
|
6821
|
-
const walletClient = (0,
|
|
7049
|
+
const account = (0, import_viem13.getAddress)(state.walletAddress);
|
|
7050
|
+
const walletClient = (0, import_viem13.createWalletClient)({
|
|
6822
7051
|
account,
|
|
6823
7052
|
chain: import_chains4.base,
|
|
6824
|
-
transport: (0,
|
|
7053
|
+
transport: (0, import_viem13.custom)(state.provider)
|
|
6825
7054
|
});
|
|
6826
|
-
const walletChainClient = (0,
|
|
7055
|
+
const walletChainClient = (0, import_viem13.createPublicClient)({
|
|
6827
7056
|
chain: import_chains4.base,
|
|
6828
|
-
transport: (0,
|
|
7057
|
+
transport: (0, import_viem13.custom)(state.provider)
|
|
6829
7058
|
});
|
|
6830
7059
|
await ensureWalletOnChain(
|
|
6831
7060
|
walletChainClient,
|
|
@@ -6835,7 +7064,7 @@ var YieldseekerAgent = class {
|
|
|
6835
7064
|
const hash = await walletClient.sendTransaction({
|
|
6836
7065
|
account,
|
|
6837
7066
|
chain: import_chains4.base,
|
|
6838
|
-
to: (0,
|
|
7067
|
+
to: (0, import_viem13.getAddress)(transaction.to),
|
|
6839
7068
|
data: transaction.data,
|
|
6840
7069
|
value: BigInt(transaction.value)
|
|
6841
7070
|
});
|
|
@@ -6939,12 +7168,12 @@ var YieldseekerAgent = class {
|
|
|
6939
7168
|
return receipt;
|
|
6940
7169
|
}
|
|
6941
7170
|
assertTransaction(transaction, state, chainId) {
|
|
6942
|
-
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)) {
|
|
6943
7172
|
throw this.invalidResponse("transaction");
|
|
6944
7173
|
}
|
|
6945
7174
|
}
|
|
6946
7175
|
assertAgent(agent) {
|
|
6947
|
-
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) {
|
|
6948
7177
|
throw this.invalidResponse("agent");
|
|
6949
7178
|
}
|
|
6950
7179
|
}
|
|
@@ -7098,15 +7327,24 @@ async function withFailureReporting(apiKey, agentType, fn, baseUrl) {
|
|
|
7098
7327
|
}
|
|
7099
7328
|
|
|
7100
7329
|
// src/lib/helpers/withdraw-helper.ts
|
|
7101
|
-
var
|
|
7330
|
+
var import_viem14 = require("viem");
|
|
7102
7331
|
function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
|
|
7103
7332
|
const target = asset.toUpperCase();
|
|
7104
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
|
+
};
|
|
7105
7343
|
const agentBalance = aggregated[agent.id];
|
|
7106
7344
|
const tokenBalance = agentBalance?.tokens.find(
|
|
7107
7345
|
(t) => t.chainId === chainId && t.asset.toUpperCase() === target
|
|
7108
7346
|
);
|
|
7109
|
-
let balance = tokenBalance ? (
|
|
7347
|
+
let balance = tokenBalance ? readAmount(tokenBalance.amount) : 0n;
|
|
7110
7348
|
if (agent.balanceComposition === "tokens-plus-positions") {
|
|
7111
7349
|
const chainNameById = {
|
|
7112
7350
|
1: "ETHEREUM",
|
|
@@ -7118,20 +7356,22 @@ function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decima
|
|
|
7118
7356
|
const positionChain = position2.chain.trim().toUpperCase();
|
|
7119
7357
|
const matchesChain = positionChain === String(chainId) || targetChain !== void 0 && positionChain === targetChain;
|
|
7120
7358
|
if (!matchesChain || position2.asset.toUpperCase() !== target) continue;
|
|
7121
|
-
balance += position2.withdrawableAmountRaw !== void 0 ?
|
|
7359
|
+
balance += position2.withdrawableAmountRaw !== void 0 ? readAmount(position2.withdrawableAmountRaw, true) : readAmount(position2.amount);
|
|
7122
7360
|
}
|
|
7123
7361
|
}
|
|
7124
7362
|
const assetTotal = agentBalance?.assetBalances?.find(
|
|
7125
7363
|
(t) => t.chainId === chainId && t.asset.toUpperCase() === target
|
|
7126
7364
|
);
|
|
7127
7365
|
if (assetTotal) {
|
|
7128
|
-
const total = (
|
|
7366
|
+
const total = readAmount(assetTotal.amount);
|
|
7129
7367
|
if (total < balance) balance = total > 0n ? total : 0n;
|
|
7130
7368
|
}
|
|
7131
|
-
return { agent, balance };
|
|
7369
|
+
return invalidBalance ? { agent, balance: 0n, invalidBalance: true } : { agent, balance };
|
|
7132
7370
|
});
|
|
7133
7371
|
}
|
|
7134
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.");
|
|
7135
7375
|
const plans = balances.map(({ agent, balance }) => ({
|
|
7136
7376
|
agent,
|
|
7137
7377
|
balance,
|
|
@@ -7154,6 +7394,8 @@ function planProportionalShares(balances, requested, totalAvailable) {
|
|
|
7154
7394
|
return plans;
|
|
7155
7395
|
}
|
|
7156
7396
|
function planDisabledDrain(disabled, requested) {
|
|
7397
|
+
if (requested < 0n || disabled.some((entry) => entry.balance < 0n))
|
|
7398
|
+
throw new Error("Invalid withdrawal planning amounts.");
|
|
7157
7399
|
const sorted = [...disabled].filter((d) => d.balance > 0n).sort(
|
|
7158
7400
|
(a, b) => b.balance > a.balance ? 1 : b.balance < a.balance ? -1 : 0
|
|
7159
7401
|
);
|
|
@@ -7171,6 +7413,7 @@ function planDisabledDrain(disabled, requested) {
|
|
|
7171
7413
|
return { plans, remaining };
|
|
7172
7414
|
}
|
|
7173
7415
|
function redistributeShare(plans, fromIndex, amount, candidatePool) {
|
|
7416
|
+
if (amount <= 0n) return;
|
|
7174
7417
|
const pool = candidatePool ?? plans.slice(fromIndex + 1);
|
|
7175
7418
|
const candidates = pool.filter((c) => c.balance - c.planned > 0n);
|
|
7176
7419
|
const totalHeadroom = candidates.reduce(
|
|
@@ -7197,7 +7440,13 @@ function redistributeShare(plans, fromIndex, amount, candidatePool) {
|
|
|
7197
7440
|
}
|
|
7198
7441
|
}
|
|
7199
7442
|
function sumWithdrawnAmount(results) {
|
|
7200
|
-
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;
|
|
7201
7450
|
}
|
|
7202
7451
|
|
|
7203
7452
|
// src/lib/helpers/account-apy-helper.ts
|
|
@@ -7321,14 +7570,14 @@ function aggregateDailyEarnings(series, tokenSymbol) {
|
|
|
7321
7570
|
}
|
|
7322
7571
|
|
|
7323
7572
|
// src/client.ts
|
|
7324
|
-
var
|
|
7573
|
+
var import_viem18 = require("viem");
|
|
7325
7574
|
var import_chains5 = require("viem/chains");
|
|
7326
7575
|
|
|
7327
7576
|
// src/lib/sponsored-token-batch.ts
|
|
7328
|
-
var
|
|
7577
|
+
var import_viem16 = require("viem");
|
|
7329
7578
|
|
|
7330
7579
|
// src/lib/permit2-batch.ts
|
|
7331
|
-
var
|
|
7580
|
+
var import_viem15 = require("viem");
|
|
7332
7581
|
var BATCH_PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
7333
7582
|
var BASE_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
|
|
7334
7583
|
var ERC2612_PERMIT_TYPES = {
|
|
@@ -7340,7 +7589,7 @@ var ERC2612_PERMIT_TYPES = {
|
|
|
7340
7589
|
{ name: "deadline", type: "uint256" }
|
|
7341
7590
|
]
|
|
7342
7591
|
};
|
|
7343
|
-
var ERC2612_READ_ABI = (0,
|
|
7592
|
+
var ERC2612_READ_ABI = (0, import_viem15.parseAbi)([
|
|
7344
7593
|
"function name() view returns (string)",
|
|
7345
7594
|
"function version() view returns (string)",
|
|
7346
7595
|
"function nonces(address owner) view returns (uint256)"
|
|
@@ -7378,7 +7627,7 @@ var PERMIT_BATCH_TYPES = {
|
|
|
7378
7627
|
{ name: "amount", type: "uint256" }
|
|
7379
7628
|
]
|
|
7380
7629
|
};
|
|
7381
|
-
var PERMIT2_BATCH_ABI = (0,
|
|
7630
|
+
var PERMIT2_BATCH_ABI = (0, import_viem15.parseAbi)([
|
|
7382
7631
|
"struct TokenPermissions { address token; uint256 amount; }",
|
|
7383
7632
|
"struct PermitBatchTransferFrom { TokenPermissions[] permitted; uint256 nonce; uint256 deadline; }",
|
|
7384
7633
|
"struct SignatureTransferDetails { address to; uint256 requestedAmount; }",
|
|
@@ -7411,9 +7660,29 @@ function batchTypedData(b, spender) {
|
|
|
7411
7660
|
}
|
|
7412
7661
|
};
|
|
7413
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
|
+
}
|
|
7414
7681
|
|
|
7415
7682
|
// src/lib/sponsored-token-batch.ts
|
|
7416
7683
|
var memory = /* @__PURE__ */ new Map();
|
|
7684
|
+
var settledRecords = /* @__PURE__ */ new Map();
|
|
7685
|
+
var expiredRecords = /* @__PURE__ */ new Map();
|
|
7417
7686
|
var inflight = /* @__PURE__ */ new Map();
|
|
7418
7687
|
var planOf = (transfers) => JSON.stringify(
|
|
7419
7688
|
transfers.map((t) => ({
|
|
@@ -7421,32 +7690,109 @@ var planOf = (transfers) => JSON.stringify(
|
|
|
7421
7690
|
amount: BigInt(t.amount).toString()
|
|
7422
7691
|
}))
|
|
7423
7692
|
);
|
|
7424
|
-
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()}`;
|
|
7425
7694
|
function pendingTokenBatch(i) {
|
|
7426
7695
|
try {
|
|
7427
7696
|
const saved = read(pendingKey(i));
|
|
7428
7697
|
if (!saved) return;
|
|
7429
7698
|
const body = JSON.parse(saved);
|
|
7430
|
-
if (!body.serializedTransaction || body.chainId !== i.chainId || !(0,
|
|
7431
|
-
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 })) };
|
|
7432
7701
|
} catch {
|
|
7433
7702
|
return;
|
|
7434
7703
|
}
|
|
7435
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
|
+
})]);
|
|
7765
|
+
} catch {
|
|
7766
|
+
return;
|
|
7767
|
+
} finally {
|
|
7768
|
+
expired = true;
|
|
7769
|
+
if (timer) clearTimeout(timer);
|
|
7770
|
+
}
|
|
7771
|
+
}
|
|
7436
7772
|
function read(key2) {
|
|
7437
|
-
|
|
7773
|
+
const value = typeof window === "undefined" ? memory.get(key2) : window.localStorage.getItem(key2);
|
|
7774
|
+
return value && settledRecords.get(key2) === value ? void 0 : value;
|
|
7438
7775
|
}
|
|
7439
|
-
function
|
|
7440
|
-
|
|
7776
|
+
function storedBody(body) {
|
|
7777
|
+
return JSON.stringify({
|
|
7441
7778
|
...body,
|
|
7442
7779
|
transfers: body.transfers.map(({ to, amount }) => ({ to, amount }))
|
|
7443
7780
|
});
|
|
7781
|
+
}
|
|
7782
|
+
function save(key2, body) {
|
|
7783
|
+
const value = storedBody(body);
|
|
7444
7784
|
if (typeof window === "undefined") memory.set(key2, value);
|
|
7445
7785
|
else window.localStorage.setItem(key2, value);
|
|
7786
|
+
settledRecords.delete(key2);
|
|
7446
7787
|
}
|
|
7447
|
-
function clear(key2) {
|
|
7448
|
-
|
|
7449
|
-
|
|
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
|
+
}
|
|
7450
7796
|
}
|
|
7451
7797
|
function sponsorTokenBatch(i) {
|
|
7452
7798
|
const key2 = pendingKey(i);
|
|
@@ -7513,7 +7859,7 @@ async function execute(i, key2, plan) {
|
|
|
7513
7859
|
baseUrl: i.baseUrl,
|
|
7514
7860
|
body
|
|
7515
7861
|
});
|
|
7516
|
-
if (!preparedPermit.serializedPermitTransaction || !preparedPermit.permitTxHash || (0,
|
|
7862
|
+
if (!preparedPermit.serializedPermitTransaction || !preparedPermit.permitTxHash || (0, import_viem16.keccak256)(preparedPermit.serializedPermitTransaction) !== preparedPermit.permitTxHash)
|
|
7517
7863
|
throw new Error(
|
|
7518
7864
|
"Sponsorship API did not return a valid prepared permit transaction."
|
|
7519
7865
|
);
|
|
@@ -7524,7 +7870,7 @@ async function execute(i, key2, plan) {
|
|
|
7524
7870
|
save(key2, body);
|
|
7525
7871
|
}
|
|
7526
7872
|
if (!body.serializedTransaction) {
|
|
7527
|
-
const permitHash = body.serializedPermitTransaction ? (0,
|
|
7873
|
+
const permitHash = body.serializedPermitTransaction ? (0, import_viem16.keccak256)(body.serializedPermitTransaction) : void 0;
|
|
7528
7874
|
let prepared = permitHash ? await postSigned("approval", permitHash) : await post();
|
|
7529
7875
|
if (prepared?.status === "pending") {
|
|
7530
7876
|
if (!permitHash || prepared.phase !== "approval" || prepared.txHash !== permitHash)
|
|
@@ -7535,7 +7881,7 @@ async function execute(i, key2, plan) {
|
|
|
7535
7881
|
if (!prepared) prepared = await post();
|
|
7536
7882
|
if (prepared.status === "pending" && permitHash && prepared.phase === "approval" && prepared.txHash === permitHash)
|
|
7537
7883
|
throw pendingError("approval", permitHash);
|
|
7538
|
-
if (!prepared.serializedTransaction || (0,
|
|
7884
|
+
if (!prepared.serializedTransaction || (0, import_viem16.keccak256)(prepared.serializedTransaction) !== prepared.txHash)
|
|
7539
7885
|
throw new Error(
|
|
7540
7886
|
"Sponsorship API did not return a valid prepared transaction."
|
|
7541
7887
|
);
|
|
@@ -7546,22 +7892,22 @@ async function execute(i, key2, plan) {
|
|
|
7546
7892
|
save(key2, body);
|
|
7547
7893
|
}
|
|
7548
7894
|
try {
|
|
7549
|
-
i.onSubmitted?.((0,
|
|
7895
|
+
i.onSubmitted?.((0, import_viem16.keccak256)(body.serializedTransaction));
|
|
7550
7896
|
} catch {
|
|
7551
7897
|
}
|
|
7552
|
-
const hash = (0,
|
|
7898
|
+
const hash = (0, import_viem16.keccak256)(body.serializedTransaction);
|
|
7553
7899
|
const existing = await i.pub.getTransactionReceipt({ hash }).catch(() => void 0);
|
|
7554
7900
|
if (existing) {
|
|
7555
7901
|
assertReceipt(existing, "deposit");
|
|
7556
7902
|
void post().catch(() => void 0);
|
|
7557
|
-
clear(key2);
|
|
7903
|
+
clear(key2, body);
|
|
7558
7904
|
return hash;
|
|
7559
7905
|
}
|
|
7560
7906
|
let result = await postSigned("deposit", hash);
|
|
7561
|
-
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)) {
|
|
7562
7908
|
await waitForConfirmation("approval", result.txHash);
|
|
7563
7909
|
result = await postSigned("deposit", hash);
|
|
7564
|
-
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);
|
|
7565
7911
|
}
|
|
7566
7912
|
if (result) {
|
|
7567
7913
|
if (result.txHash !== hash || result.status === "pending" && result.phase !== "deposit")
|
|
@@ -7569,11 +7915,11 @@ async function execute(i, key2, plan) {
|
|
|
7569
7915
|
if (result.status === "pending") await waitForConfirmation("deposit", hash);
|
|
7570
7916
|
}
|
|
7571
7917
|
if (!result || result.status === "pending") void post().catch(() => void 0);
|
|
7572
|
-
clear(key2);
|
|
7918
|
+
clear(key2, body);
|
|
7573
7919
|
return hash;
|
|
7574
7920
|
} catch (error) {
|
|
7575
7921
|
if (!body.serializedTransaction && !body.serializedPermitTransaction || rejectedPreparation(error) || error instanceof OwneyError && error.details?.notSubmitted === true)
|
|
7576
|
-
clear(key2);
|
|
7922
|
+
clear(key2, body);
|
|
7577
7923
|
throw error;
|
|
7578
7924
|
}
|
|
7579
7925
|
};
|
|
@@ -7582,10 +7928,16 @@ async function execute(i, key2, plan) {
|
|
|
7582
7928
|
throw new OwneyError("DEPOSIT_IN_PROGRESS", "The saved deposit changed. Check its status before depositing again.");
|
|
7583
7929
|
if (saved) {
|
|
7584
7930
|
const previous = JSON.parse(saved);
|
|
7585
|
-
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)
|
|
7586
7932
|
throw new Error(
|
|
7587
7933
|
"Retry the previous token deposit and agent split first to reconcile its status."
|
|
7588
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
|
+
);
|
|
7589
7941
|
i.onApproved?.();
|
|
7590
7942
|
return send({ ...previous, transfers: i.transfers });
|
|
7591
7943
|
}
|
|
@@ -7599,7 +7951,7 @@ async function execute(i, key2, plan) {
|
|
|
7599
7951
|
"DEPOSIT_INSUFFICIENT_BALANCE",
|
|
7600
7952
|
"Insufficient token balance for this deposit."
|
|
7601
7953
|
);
|
|
7602
|
-
if (allowance < total && (i.chainId !== 8453 || !(0,
|
|
7954
|
+
if (allowance < total && (i.chainId !== 8453 || !(0, import_viem16.isAddressEqual)(i.token, BASE_USDC_ADDRESS)))
|
|
7603
7955
|
throw new OwneyError(
|
|
7604
7956
|
"PERMIT2_APPROVAL_REQUIRED",
|
|
7605
7957
|
"token deposits need a one-time Permit2 approval."
|
|
@@ -7778,7 +8130,7 @@ async function runAgentDepositBatch(chainId, legs, transfer) {
|
|
|
7778
8130
|
}
|
|
7779
8131
|
|
|
7780
8132
|
// src/lib/sponsored-calls-deposit.ts
|
|
7781
|
-
var
|
|
8133
|
+
var import_viem17 = require("viem");
|
|
7782
8134
|
var DEFAULT_POLL_INTERVAL_MS = 1500;
|
|
7783
8135
|
var DEFAULT_MAX_POLLS = 30;
|
|
7784
8136
|
async function paymasterSupported(provider, owner, chainId) {
|
|
@@ -7786,7 +8138,7 @@ async function paymasterSupported(provider, owner, chainId) {
|
|
|
7786
8138
|
method: "wallet_getCapabilities",
|
|
7787
8139
|
params: [owner]
|
|
7788
8140
|
});
|
|
7789
|
-
const forChain = caps?.[(0,
|
|
8141
|
+
const forChain = caps?.[(0, import_viem17.toHex)(chainId)] ?? caps?.[String(chainId)];
|
|
7790
8142
|
return Boolean(forChain?.paymasterService?.supported);
|
|
7791
8143
|
}
|
|
7792
8144
|
function makeSponsoredCallsCallback(deps) {
|
|
@@ -7823,8 +8175,8 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
7823
8175
|
const calls = transfers.map((transfer) => ({
|
|
7824
8176
|
to: token,
|
|
7825
8177
|
value: "0x0",
|
|
7826
|
-
data: (0,
|
|
7827
|
-
abi:
|
|
8178
|
+
data: (0, import_viem17.encodeFunctionData)({
|
|
8179
|
+
abi: import_viem17.erc20Abi,
|
|
7828
8180
|
functionName: "transfer",
|
|
7829
8181
|
args: [transfer.to, BigInt(transfer.amount)]
|
|
7830
8182
|
})
|
|
@@ -7856,7 +8208,7 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
7856
8208
|
url.searchParams.append("owneyIntent", intent);
|
|
7857
8209
|
paymasterUrl = url.toString();
|
|
7858
8210
|
}
|
|
7859
|
-
const requestedId = (0,
|
|
8211
|
+
const requestedId = (0, import_viem17.toHex)(globalThis.crypto.getRandomValues(new Uint8Array(32)));
|
|
7860
8212
|
const progress = (id, transfer) => {
|
|
7861
8213
|
try {
|
|
7862
8214
|
deps.onCallsProgress?.(id, transfers, transfer);
|
|
@@ -7873,7 +8225,7 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
7873
8225
|
version: "2.0.0",
|
|
7874
8226
|
id: requestedId,
|
|
7875
8227
|
from: deps.ownerAddress,
|
|
7876
|
-
chainId: (0,
|
|
8228
|
+
chainId: (0, import_viem17.toHex)(chainId),
|
|
7877
8229
|
atomicRequired: transfers.length > 1,
|
|
7878
8230
|
calls,
|
|
7879
8231
|
capabilities: {
|
|
@@ -8006,6 +8358,8 @@ var OwneySDK = class {
|
|
|
8006
8358
|
*/
|
|
8007
8359
|
disabledAgents = /* @__PURE__ */ new Set();
|
|
8008
8360
|
state = null;
|
|
8361
|
+
connectionRevision = 0;
|
|
8362
|
+
disconnectingAgents = null;
|
|
8009
8363
|
apiKey;
|
|
8010
8364
|
// The org's agent policy, fetched once per client. Applied to each agent on
|
|
8011
8365
|
// activation (ROUT-229). `undefined` means "not fetched yet", `null` means
|
|
@@ -8027,6 +8381,9 @@ var OwneySDK = class {
|
|
|
8027
8381
|
recoveredFundingReads = /* @__PURE__ */ new Set();
|
|
8028
8382
|
fundingBalanceChecks = /* @__PURE__ */ new WeakMap();
|
|
8029
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();
|
|
8030
8387
|
readAgent(agent, method, fetch2, params = null) {
|
|
8031
8388
|
const key2 = JSON.stringify([
|
|
8032
8389
|
this.state?.walletAddress.toLowerCase() ?? null,
|
|
@@ -8059,9 +8416,10 @@ var OwneySDK = class {
|
|
|
8059
8416
|
*/
|
|
8060
8417
|
// TODO: replace with a proper EIP-1193 Provider type
|
|
8061
8418
|
async connect(provider) {
|
|
8062
|
-
const
|
|
8063
|
-
|
|
8064
|
-
|
|
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.");
|
|
8065
8423
|
const walletAddress = accounts[0];
|
|
8066
8424
|
if (!walletAddress) {
|
|
8067
8425
|
throw new OwneyError(
|
|
@@ -8069,33 +8427,46 @@ var OwneySDK = class {
|
|
|
8069
8427
|
"No accounts found. Ensure the wallet is unlocked and connected."
|
|
8070
8428
|
);
|
|
8071
8429
|
}
|
|
8072
|
-
this.
|
|
8073
|
-
this.
|
|
8074
|
-
|
|
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.");
|
|
8075
8435
|
this.state = { provider, walletAddress, chainId: null };
|
|
8076
|
-
this.cachedSponsoredCallback = null;
|
|
8077
|
-
this.cachedWethSponsoredCallback = null;
|
|
8078
|
-
this.cachedSponsoredCallsCallbacks.clear();
|
|
8079
8436
|
}
|
|
8080
8437
|
/**
|
|
8081
8438
|
* Disconnect from all agents and clear connection state.
|
|
8082
8439
|
* After calling this, `connect()` must be called again before using agent methods.
|
|
8083
8440
|
*/
|
|
8084
8441
|
async disconnect() {
|
|
8442
|
+
++this.connectionRevision;
|
|
8443
|
+
this.clearConnectionState();
|
|
8444
|
+
await this.disconnectAgents();
|
|
8445
|
+
}
|
|
8446
|
+
clearConnectionState() {
|
|
8085
8447
|
this.state = null;
|
|
8086
8448
|
this.fundingBalanceChecks = /* @__PURE__ */ new WeakMap();
|
|
8087
|
-
for (const agent of this.agents.values()) {
|
|
8088
|
-
await agent.disconnect();
|
|
8089
|
-
}
|
|
8090
8449
|
this.activeAgents.clear();
|
|
8091
|
-
this.disabledAgents.clear();
|
|
8092
8450
|
this.agentReads.clearInFlight();
|
|
8093
8451
|
this.activationChecks.clear();
|
|
8094
|
-
this.state = null;
|
|
8095
8452
|
this.cachedSponsoredCallback = null;
|
|
8096
8453
|
this.cachedWethSponsoredCallback = null;
|
|
8097
8454
|
this.cachedSponsoredCallsCallbacks.clear();
|
|
8098
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
|
+
}
|
|
8099
8470
|
isAgentDisabled(agentId) {
|
|
8100
8471
|
return this.disabledAgents.has(agentId);
|
|
8101
8472
|
}
|
|
@@ -8158,14 +8529,14 @@ var OwneySDK = class {
|
|
|
8158
8529
|
// PublicClient/WalletClient param types — structurally identical at
|
|
8159
8530
|
// runtime, but the two share a name TS treats as unrelated.
|
|
8160
8531
|
getPublicClient: (cid) => this.getPaidRpcClient(cid),
|
|
8161
|
-
getWalletChainClient: (cid) => (0,
|
|
8532
|
+
getWalletChainClient: (cid) => (0, import_viem18.createPublicClient)({
|
|
8162
8533
|
chain: VIEM_CHAIN2[cid],
|
|
8163
|
-
transport: (0,
|
|
8534
|
+
transport: (0, import_viem18.custom)(provider)
|
|
8164
8535
|
}),
|
|
8165
|
-
getWalletClient: (cid) => (0,
|
|
8536
|
+
getWalletClient: (cid) => (0, import_viem18.createWalletClient)({
|
|
8166
8537
|
account: owner,
|
|
8167
8538
|
chain: VIEM_CHAIN2[cid],
|
|
8168
|
-
transport: (0,
|
|
8539
|
+
transport: (0, import_viem18.custom)(provider)
|
|
8169
8540
|
})
|
|
8170
8541
|
});
|
|
8171
8542
|
if (!onApproved && !onSubmitted && !resumeTxHash) this.cachedSponsoredCallback = callback;
|
|
@@ -8213,14 +8584,14 @@ var OwneySDK = class {
|
|
|
8213
8584
|
// PublicClient/WalletClient param types — structurally identical at
|
|
8214
8585
|
// runtime, but the two share a name TS treats as unrelated.
|
|
8215
8586
|
getPublicClient: (cid) => this.getPaidRpcClient(cid),
|
|
8216
|
-
getWalletChainClient: (cid) => (0,
|
|
8587
|
+
getWalletChainClient: (cid) => (0, import_viem18.createPublicClient)({
|
|
8217
8588
|
chain: VIEM_CHAIN2[cid],
|
|
8218
|
-
transport: (0,
|
|
8589
|
+
transport: (0, import_viem18.custom)(provider)
|
|
8219
8590
|
}),
|
|
8220
|
-
getWalletClient: (cid) => (0,
|
|
8591
|
+
getWalletClient: (cid) => (0, import_viem18.createWalletClient)({
|
|
8221
8592
|
account: owner,
|
|
8222
8593
|
chain: VIEM_CHAIN2[cid],
|
|
8223
|
-
transport: (0,
|
|
8594
|
+
transport: (0, import_viem18.custom)(provider)
|
|
8224
8595
|
})
|
|
8225
8596
|
});
|
|
8226
8597
|
if (!onApproved && !onSubmitted && !resumeTxHash) this.cachedWethSponsoredCallback = callback;
|
|
@@ -8531,6 +8902,12 @@ var OwneySDK = class {
|
|
|
8531
8902
|
*/
|
|
8532
8903
|
async deposit(options) {
|
|
8533
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
|
+
);
|
|
8534
8911
|
const prepared = /* @__PURE__ */ new Map();
|
|
8535
8912
|
const paidFallbackAgents = /* @__PURE__ */ new Set();
|
|
8536
8913
|
const onProgress = options.onProgress ? (evidence) => {
|
|
@@ -8558,6 +8935,47 @@ var OwneySDK = class {
|
|
|
8558
8935
|
throw new OwneyError("DEPOSIT_IN_PROGRESS", "This deposit cannot resume the saved relayer transaction.");
|
|
8559
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));
|
|
8560
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
|
+
}
|
|
8561
8979
|
if (agentId) {
|
|
8562
8980
|
if (this.isAgentDisabled(agentId)) {
|
|
8563
8981
|
throw new OwneyError(
|
|
@@ -8974,9 +9392,36 @@ var OwneySDK = class {
|
|
|
8974
9392
|
const token = SupportedAssets.find((t) => t.chainId === chainId && t.symbol === evidence.token);
|
|
8975
9393
|
if (!token) throw new OwneyError("CHAIN_UNSUPPORTED", "Unsupported funding asset.");
|
|
8976
9394
|
const rpc2 = this.getPaidRpcClient(chainId);
|
|
8977
|
-
|
|
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
|
+
}
|
|
8978
9423
|
assertCurrent();
|
|
8979
|
-
let verified = inspectFundingReceipt(receipt, { ...evidence, agentWallet }, token.address, direction);
|
|
9424
|
+
let verified = inspectFundingReceipt(receipt, { ...evidence, agentWallet }, token.address, direction, options);
|
|
8980
9425
|
if (direction === "withdraw" && evidence.agentId === "yieldseeker" && verified.transfer === "unknown" && verified.confirmedAmount && BigInt(verified.confirmedAmount) > 0n) {
|
|
8981
9426
|
const transaction = await rpc2.getTransaction({ hash: evidence.txHash });
|
|
8982
9427
|
assertCurrent();
|
|
@@ -9150,9 +9595,11 @@ var OwneySDK = class {
|
|
|
9150
9595
|
return page;
|
|
9151
9596
|
}
|
|
9152
9597
|
async recoverDepositRegistration(evidence) {
|
|
9598
|
+
const { state, assertCurrent } = this.captureReadScope(evidence.chainId);
|
|
9153
9599
|
const verified = await this.inspectFunding(evidence, "deposit");
|
|
9600
|
+
assertCurrent();
|
|
9154
9601
|
if (verified.agentId !== "zyfai") return verified;
|
|
9155
|
-
return this.getAgent("zyfai").retryDepositRegistration(
|
|
9602
|
+
return this.getAgent("zyfai").retryDepositRegistration(state, verified);
|
|
9156
9603
|
}
|
|
9157
9604
|
// --- Fund operations ---
|
|
9158
9605
|
/** On-chain version and ownership status for this owner's Yieldseeker agent. */
|
|
@@ -9198,10 +9645,24 @@ var OwneySDK = class {
|
|
|
9198
9645
|
* @returns {AgentWithdrawResult} for a single agent, or {OwneyWithdrawResult} with per-agent results
|
|
9199
9646
|
*/
|
|
9200
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
|
+
);
|
|
9201
9654
|
const state = this.requireState();
|
|
9202
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
|
+
);
|
|
9203
9663
|
const ids = options.agentId ? [options.agentId] : this.getActiveAgentIds().filter((id) => !options.excludeAgentIds?.includes(id));
|
|
9204
9664
|
const attempted = /* @__PURE__ */ new Set();
|
|
9665
|
+
this.withdrawalSubmissions.add(submissionKey);
|
|
9205
9666
|
try {
|
|
9206
9667
|
return await this.withdrawFromAgents(options, state, chainId, attempted);
|
|
9207
9668
|
} catch (error) {
|
|
@@ -9218,6 +9679,8 @@ var OwneySDK = class {
|
|
|
9218
9679
|
});
|
|
9219
9680
|
}
|
|
9220
9681
|
throw error;
|
|
9682
|
+
} finally {
|
|
9683
|
+
this.withdrawalSubmissions.delete(submissionKey);
|
|
9221
9684
|
}
|
|
9222
9685
|
}
|
|
9223
9686
|
async withdrawFromAgents(options, state, chainId, attempted) {
|
|
@@ -9256,7 +9719,19 @@ var OwneySDK = class {
|
|
|
9256
9719
|
};
|
|
9257
9720
|
};
|
|
9258
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
|
+
};
|
|
9259
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.");
|
|
9260
9735
|
attempted.add(agent.id);
|
|
9261
9736
|
let evidence = {
|
|
9262
9737
|
agentId: agent.id,
|
|
@@ -9268,12 +9743,16 @@ var OwneySDK = class {
|
|
|
9268
9743
|
registration: "not-applicable",
|
|
9269
9744
|
delivery: "pending"
|
|
9270
9745
|
};
|
|
9746
|
+
let adapterReported = false;
|
|
9271
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;
|
|
9272
9750
|
evidence = { ...evidence, ...next };
|
|
9273
9751
|
submissionEvidence.set(agent.id, evidence);
|
|
9274
9752
|
notifyFunding(options.onProgress, evidence);
|
|
9275
9753
|
};
|
|
9276
9754
|
progress(evidence);
|
|
9755
|
+
adapterReported = false;
|
|
9277
9756
|
try {
|
|
9278
9757
|
if (options.onBeforeSubmission)
|
|
9279
9758
|
return await agent.withdraw(
|
|
@@ -9287,7 +9766,7 @@ var OwneySDK = class {
|
|
|
9287
9766
|
);
|
|
9288
9767
|
return await (options.gasMode === void 0 ? agent.withdraw(state, chainId, token, requested2, progress) : agent.withdraw(state, chainId, token, requested2, progress, options.gasMode));
|
|
9289
9768
|
} catch (error) {
|
|
9290
|
-
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 : "")))
|
|
9291
9770
|
progress({ ...evidence, transfer: "failed", delivery: "failed" });
|
|
9292
9771
|
throw error;
|
|
9293
9772
|
}
|
|
@@ -9348,6 +9827,7 @@ var OwneySDK = class {
|
|
|
9348
9827
|
}
|
|
9349
9828
|
}
|
|
9350
9829
|
if (Object.keys(results2).length === 0) {
|
|
9830
|
+
throwUnconfirmed(agentErrors2);
|
|
9351
9831
|
if (Object.keys(agentErrors2).length === 0)
|
|
9352
9832
|
throw new OwneyError(
|
|
9353
9833
|
"WITHDRAW_INSUFFICIENT_BALANCE",
|
|
@@ -9368,7 +9848,7 @@ var OwneySDK = class {
|
|
|
9368
9848
|
);
|
|
9369
9849
|
}
|
|
9370
9850
|
const amountsKnown = Object.values(results2).every(
|
|
9371
|
-
(result) =>
|
|
9851
|
+
(result) => confirmedWithdrawalAmount(result) !== void 0
|
|
9372
9852
|
);
|
|
9373
9853
|
return {
|
|
9374
9854
|
agentResult: results2,
|
|
@@ -9387,6 +9867,13 @@ var OwneySDK = class {
|
|
|
9387
9867
|
asset,
|
|
9388
9868
|
assetInfo.decimals
|
|
9389
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
|
+
}
|
|
9390
9877
|
const indexedAvailable = balances.reduce((sum, entry) => sum + entry.balance, 0n);
|
|
9391
9878
|
await Promise.all(balances.map(async (entry) => {
|
|
9392
9879
|
if (entry.balance !== 0n && indexedAvailable >= requested || !entry.agent.getWithdrawableBalance) return;
|
|
@@ -9399,7 +9886,7 @@ var OwneySDK = class {
|
|
|
9399
9886
|
if (this.isUserRejectedWithdrawal(originalFailure)) throw originalFailure;
|
|
9400
9887
|
if (entry.balance !== 0n && entry.agent.id !== "yieldseeker") {
|
|
9401
9888
|
const total = aggregated.agentBalances[entry.agent.id]?.assetBalances?.find((value) => value.chainId === chainId && value.asset.toUpperCase() === token);
|
|
9402
|
-
if (!total || (0,
|
|
9889
|
+
if (!total || (0, import_viem18.parseUnits)(total.amount, assetInfo.decimals) <= entry.balance) return;
|
|
9403
9890
|
}
|
|
9404
9891
|
try {
|
|
9405
9892
|
const otherAvailable = indexedAvailable - entry.balance;
|
|
@@ -9426,12 +9913,15 @@ var OwneySDK = class {
|
|
|
9426
9913
|
throw new OwneyError("NOT_CONNECTED", "Account changed while planning withdrawal.");
|
|
9427
9914
|
const unavailableAgentIds = unavailableAgents.map((agent) => agent.id);
|
|
9428
9915
|
const totalAvailable = balances.reduce((sum, x) => sum + x.balance, 0n);
|
|
9429
|
-
if (totalAvailable
|
|
9916
|
+
if (totalAvailable < requested && unavailableAgents.length > 0) {
|
|
9430
9917
|
throw new OwneyError(
|
|
9431
9918
|
"WITHDRAW_BALANCE_UNAVAILABLE",
|
|
9432
|
-
`Cannot
|
|
9919
|
+
`Cannot cover the requested withdrawal with verified available balances: ${unavailableAgentIds.join(", ")}.`,
|
|
9433
9920
|
{
|
|
9434
9921
|
asset,
|
|
9922
|
+
requested: amount,
|
|
9923
|
+
available: totalAvailable.toString(),
|
|
9924
|
+
rejectedBeforeSubmission: true,
|
|
9435
9925
|
unavailableAgents: unavailableAgentIds,
|
|
9436
9926
|
agentErrors: aggregated.agentErrors
|
|
9437
9927
|
}
|
|
@@ -9448,7 +9938,7 @@ var OwneySDK = class {
|
|
|
9448
9938
|
}
|
|
9449
9939
|
);
|
|
9450
9940
|
}
|
|
9451
|
-
const plannedTarget =
|
|
9941
|
+
const plannedTarget = requested;
|
|
9452
9942
|
const disabledBalances = balances.filter(
|
|
9453
9943
|
(b) => this.isAgentDisabled(b.agent.id)
|
|
9454
9944
|
);
|
|
@@ -9467,13 +9957,23 @@ var OwneySDK = class {
|
|
|
9467
9957
|
}));
|
|
9468
9958
|
const plans = [...disabledPlans, ...enabledPlans];
|
|
9469
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();
|
|
9470
9969
|
const results = {};
|
|
9471
9970
|
const agentErrors = {
|
|
9472
9971
|
...aggregated.agentErrors ?? {}
|
|
9473
9972
|
};
|
|
9474
9973
|
for (let i = 0; i < orderedPlans.length; i++) {
|
|
9475
9974
|
const p = orderedPlans[i];
|
|
9476
|
-
|
|
9975
|
+
assertPlan();
|
|
9976
|
+
if (p.planned <= 0n) continue;
|
|
9477
9977
|
try {
|
|
9478
9978
|
results[p.agent.id] = await submit(p.agent, p.planned.toString());
|
|
9479
9979
|
notifyAgentResult(p.agent.id, results[p.agent.id]);
|
|
@@ -9497,6 +9997,7 @@ var OwneySDK = class {
|
|
|
9497
9997
|
}
|
|
9498
9998
|
}
|
|
9499
9999
|
if (Object.keys(results).length === 0) {
|
|
10000
|
+
throwUnconfirmed(agentErrors);
|
|
9500
10001
|
throw new OwneyError(
|
|
9501
10002
|
"WITHDRAW_ALL_FAILED",
|
|
9502
10003
|
`Failed to withdraw "${amount}" of "${asset}" from all eligible agents.`,
|
|
@@ -9514,13 +10015,17 @@ var OwneySDK = class {
|
|
|
9514
10015
|
const adjustment = result?.feeAdjustment;
|
|
9515
10016
|
const evidence = result?.evidence;
|
|
9516
10017
|
const submitted = submissionEvidence.get(plan.agent.id);
|
|
9517
|
-
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;
|
|
9518
10019
|
const fee = BigInt(adjustment.feeAmount);
|
|
9519
10020
|
const net = BigInt(result.amount);
|
|
9520
10021
|
const gross = BigInt(adjustment.grossAmount);
|
|
9521
10022
|
return fee > 0n && net > 0n && gross === plan.planned && net + fee === gross ? total + fee : total;
|
|
9522
10023
|
}, 0n);
|
|
9523
|
-
|
|
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) {
|
|
9524
10029
|
throw new OwneyError(
|
|
9525
10030
|
"WITHDRAW_PARTIAL_FAILURE",
|
|
9526
10031
|
`Withdrew "${withdrawn.toString()}" of requested "${amount}" of "${asset}". One or more agents failed; remaining balance could not cover the shortfall.`,
|
|
@@ -9528,6 +10033,7 @@ var OwneySDK = class {
|
|
|
9528
10033
|
asset,
|
|
9529
10034
|
requested: amount,
|
|
9530
10035
|
withdrawn: withdrawn.toString(),
|
|
10036
|
+
pendingAmount: pendingAmount.toString(),
|
|
9531
10037
|
partialResults: results,
|
|
9532
10038
|
agentErrors,
|
|
9533
10039
|
agentFailures,
|
|
@@ -9535,7 +10041,7 @@ var OwneySDK = class {
|
|
|
9535
10041
|
}
|
|
9536
10042
|
);
|
|
9537
10043
|
}
|
|
9538
|
-
return { agentResult: results, totalWithdrawn: withdrawn.toString() };
|
|
10044
|
+
return { agentResult: results, totalWithdrawn: Object.values(results).every((result) => confirmedWithdrawalAmount(result) !== void 0) ? withdrawn.toString() : null };
|
|
9539
10045
|
}
|
|
9540
10046
|
// --- Portfolio reads ---
|
|
9541
10047
|
/**
|
|
@@ -9993,16 +10499,16 @@ var OwneySDK = class {
|
|
|
9993
10499
|
);
|
|
9994
10500
|
}
|
|
9995
10501
|
const provider = this.requireConnectedProvider();
|
|
9996
|
-
const walletChainClient = (0,
|
|
10502
|
+
const walletChainClient = (0, import_viem18.createPublicClient)({
|
|
9997
10503
|
chain: VIEM_CHAIN2[chainId],
|
|
9998
|
-
transport: (0,
|
|
10504
|
+
transport: (0, import_viem18.custom)(provider)
|
|
9999
10505
|
});
|
|
10000
10506
|
const publicClient = this.getPaidRpcClient(chainId);
|
|
10001
10507
|
const approvalAmount = permit2ApprovalAmount(requiredAmount);
|
|
10002
|
-
const wallet = (0,
|
|
10508
|
+
const wallet = (0, import_viem18.createWalletClient)({
|
|
10003
10509
|
account: state.walletAddress,
|
|
10004
10510
|
chain: VIEM_CHAIN2[chainId],
|
|
10005
|
-
transport: (0,
|
|
10511
|
+
transport: (0, import_viem18.custom)(provider)
|
|
10006
10512
|
});
|
|
10007
10513
|
await ensureWalletOnChain(walletChainClient, wallet, chainId);
|
|
10008
10514
|
const hash = await wallet.writeContract({
|
|
@@ -10164,7 +10670,7 @@ var OwneySDK = class {
|
|
|
10164
10670
|
};
|
|
10165
10671
|
|
|
10166
10672
|
// src/agents/zyfai/zyfai.siwx.ts
|
|
10167
|
-
var
|
|
10673
|
+
var import_viem19 = require("viem");
|
|
10168
10674
|
var import_siwe2 = require("siwe");
|
|
10169
10675
|
var import_sdk2 = require("@zyfai/sdk");
|
|
10170
10676
|
|
|
@@ -10291,7 +10797,7 @@ function buildSIWXConfig(deps) {
|
|
|
10291
10797
|
issuedAt,
|
|
10292
10798
|
toString() {
|
|
10293
10799
|
return new import_siwe2.SiweMessage({
|
|
10294
|
-
address: (0,
|
|
10800
|
+
address: (0, import_viem19.getAddress)(accountAddress),
|
|
10295
10801
|
chainId: numericChainId(chainId),
|
|
10296
10802
|
domain,
|
|
10297
10803
|
uri,
|