@owney/sdk 0.7.25-beta.19 → 0.7.25-beta.21
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 +1254 -656
- package/dist/index.d.cts +26 -8
- package/dist/index.d.ts +26 -8
- package/dist/index.js +1176 -576
- 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;
|
|
@@ -232,6 +286,240 @@ var AgentChainIncompatibleError = class extends OwneyError {
|
|
|
232
286
|
}
|
|
233
287
|
};
|
|
234
288
|
|
|
289
|
+
// src/lib/transfer-auth.ts
|
|
290
|
+
var import_viem2 = require("viem");
|
|
291
|
+
|
|
292
|
+
// src/lib/sponsor-client.ts
|
|
293
|
+
var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
294
|
+
async function postPaymasterIntent(input) {
|
|
295
|
+
const base6 = input.baseUrl ?? ROUTING_API_BASE_URL;
|
|
296
|
+
let res;
|
|
297
|
+
try {
|
|
298
|
+
res = await fetch(`${base6}/api/v1/sponsor/paymaster-intent`, {
|
|
299
|
+
method: "POST",
|
|
300
|
+
headers: {
|
|
301
|
+
"content-type": "application/json",
|
|
302
|
+
"x-owney-api-key": input.apiKey,
|
|
303
|
+
Authorization: `Signature ${input.yieldseekerSignature}`
|
|
304
|
+
},
|
|
305
|
+
body: JSON.stringify(input.body)
|
|
306
|
+
});
|
|
307
|
+
} catch (networkError) {
|
|
308
|
+
throw new OwneyError(
|
|
309
|
+
"SPONSOR_REQUEST_FAILED",
|
|
310
|
+
`Paymaster intent network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
|
|
311
|
+
{ cause: String(networkError), safeToFallback: true }
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
const text = await res.text();
|
|
315
|
+
let parsed = null;
|
|
316
|
+
try {
|
|
317
|
+
parsed = JSON.parse(text);
|
|
318
|
+
} catch {
|
|
319
|
+
}
|
|
320
|
+
if (!res.ok || !parsed?.success || typeof parsed.data?.intent !== "string" || typeof parsed.data.expiresAt !== "number") {
|
|
321
|
+
throw new OwneyError(
|
|
322
|
+
"SPONSOR_REQUEST_FAILED",
|
|
323
|
+
`Paymaster intent API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
|
|
324
|
+
{
|
|
325
|
+
statusCode: res.status,
|
|
326
|
+
responseBody: text.slice(0, 500),
|
|
327
|
+
safeToFallback: true
|
|
328
|
+
}
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
return parsed.data;
|
|
332
|
+
}
|
|
333
|
+
async function getSponsorRelayerAddress(input) {
|
|
334
|
+
const base6 = input.baseUrl ?? ROUTING_API_BASE_URL;
|
|
335
|
+
let res;
|
|
336
|
+
try {
|
|
337
|
+
res = await fetch(
|
|
338
|
+
`${base6}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
|
|
339
|
+
{
|
|
340
|
+
headers: { "x-owney-api-key": input.apiKey }
|
|
341
|
+
}
|
|
342
|
+
);
|
|
343
|
+
} catch (networkError) {
|
|
344
|
+
throw new OwneyError(
|
|
345
|
+
"SPONSOR_REQUEST_FAILED",
|
|
346
|
+
`Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
|
|
347
|
+
{ cause: String(networkError), safeToFallback: true }
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
const text = await res.text();
|
|
351
|
+
let parsed = null;
|
|
352
|
+
try {
|
|
353
|
+
parsed = JSON.parse(text);
|
|
354
|
+
} catch {
|
|
355
|
+
}
|
|
356
|
+
if (!res.ok || !parsed?.success || !parsed.data?.relayer) {
|
|
357
|
+
throw new OwneyError(
|
|
358
|
+
"SPONSOR_REQUEST_FAILED",
|
|
359
|
+
`Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
|
|
360
|
+
{
|
|
361
|
+
statusCode: res.status,
|
|
362
|
+
responseBody: text.slice(0, 500),
|
|
363
|
+
safeToFallback: true
|
|
364
|
+
}
|
|
365
|
+
);
|
|
366
|
+
}
|
|
367
|
+
return parsed.data.relayer;
|
|
368
|
+
}
|
|
369
|
+
async function postSponsorBatchTransfer(input) {
|
|
370
|
+
let res;
|
|
371
|
+
try {
|
|
372
|
+
res = await fetch(
|
|
373
|
+
`${input.baseUrl ?? ROUTING_API_BASE_URL}/api/v1/sponsor/permit2-batch`,
|
|
374
|
+
{
|
|
375
|
+
method: "POST",
|
|
376
|
+
headers: {
|
|
377
|
+
"content-type": "application/json",
|
|
378
|
+
"x-owney-api-key": input.apiKey
|
|
379
|
+
},
|
|
380
|
+
body: JSON.stringify(input.body)
|
|
381
|
+
}
|
|
382
|
+
);
|
|
383
|
+
} catch {
|
|
384
|
+
throw new OwneyError(
|
|
385
|
+
"SPONSOR_REQUEST_FAILED",
|
|
386
|
+
"Deposit status is unknown. Retry the same amount to check it.",
|
|
387
|
+
{ safeToFallback: false }
|
|
388
|
+
);
|
|
389
|
+
}
|
|
390
|
+
const parsed = await res.json().catch(() => null);
|
|
391
|
+
if (!res.ok || !parsed?.success || !/^0x[0-9a-fA-F]{64}$/.test(parsed.data?.txHash ?? "")) {
|
|
392
|
+
throw new OwneyError(
|
|
393
|
+
"SPONSOR_REQUEST_FAILED",
|
|
394
|
+
"Deposit could not be confirmed. Retry the same amount to check its status.",
|
|
395
|
+
{
|
|
396
|
+
statusCode: res.status,
|
|
397
|
+
safeToFallback: false,
|
|
398
|
+
notSubmitted: parsed?.notSubmitted === true || parsed?.error?.notSubmitted === true || parsed?.error?.details?.notSubmitted === true
|
|
399
|
+
}
|
|
400
|
+
);
|
|
401
|
+
}
|
|
402
|
+
return parsed.data;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// src/lib/permit2.ts
|
|
406
|
+
var import_viem3 = require("viem");
|
|
407
|
+
var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
408
|
+
var MAX_UINT256 = 2n ** 256n - 1n;
|
|
409
|
+
function permit2ApprovalAmount(requiredAmount) {
|
|
410
|
+
if (requiredAmount <= 0n) {
|
|
411
|
+
throw new Error("Permit2 approval requires a positive deposit amount");
|
|
412
|
+
}
|
|
413
|
+
return MAX_UINT256;
|
|
414
|
+
}
|
|
415
|
+
var ERC20_ALLOWANCE_ABI = [
|
|
416
|
+
{
|
|
417
|
+
type: "function",
|
|
418
|
+
name: "allowance",
|
|
419
|
+
stateMutability: "view",
|
|
420
|
+
inputs: [
|
|
421
|
+
{ name: "owner", type: "address" },
|
|
422
|
+
{ name: "spender", type: "address" }
|
|
423
|
+
],
|
|
424
|
+
outputs: [{ name: "", type: "uint256" }]
|
|
425
|
+
},
|
|
426
|
+
{
|
|
427
|
+
type: "function",
|
|
428
|
+
name: "approve",
|
|
429
|
+
stateMutability: "nonpayable",
|
|
430
|
+
inputs: [
|
|
431
|
+
{ name: "spender", type: "address" },
|
|
432
|
+
{ name: "amount", type: "uint256" }
|
|
433
|
+
],
|
|
434
|
+
outputs: [{ name: "", type: "bool" }]
|
|
435
|
+
},
|
|
436
|
+
{
|
|
437
|
+
type: "function",
|
|
438
|
+
name: "balanceOf",
|
|
439
|
+
stateMutability: "view",
|
|
440
|
+
inputs: [{ name: "account", type: "address" }],
|
|
441
|
+
outputs: [{ name: "", type: "uint256" }]
|
|
442
|
+
}
|
|
443
|
+
];
|
|
444
|
+
function randomPermit2Nonce() {
|
|
445
|
+
const bytes = new Uint8Array(32);
|
|
446
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
447
|
+
return BigInt((0, import_viem3.bytesToHex)(bytes));
|
|
448
|
+
}
|
|
449
|
+
async function readPermit2Allowance(publicClient, token, owner, blockNumber) {
|
|
450
|
+
return publicClient.readContract({
|
|
451
|
+
address: token,
|
|
452
|
+
abi: ERC20_ALLOWANCE_ABI,
|
|
453
|
+
functionName: "allowance",
|
|
454
|
+
args: [owner, PERMIT2_ADDRESS],
|
|
455
|
+
...blockNumber === void 0 ? {} : { blockNumber }
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
async function readErc20Balance(publicClient, token, owner) {
|
|
459
|
+
return publicClient.readContract({
|
|
460
|
+
address: token,
|
|
461
|
+
abi: ERC20_ALLOWANCE_ABI,
|
|
462
|
+
functionName: "balanceOf",
|
|
463
|
+
args: [owner]
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// src/lib/chain-guard.ts
|
|
468
|
+
var CHAIN_NAMES = {
|
|
469
|
+
1: "Ethereum",
|
|
470
|
+
8453: "Base",
|
|
471
|
+
42161: "Arbitrum"
|
|
472
|
+
};
|
|
473
|
+
function chainName(chainId) {
|
|
474
|
+
return CHAIN_NAMES[chainId] ?? `chain ${chainId}`;
|
|
475
|
+
}
|
|
476
|
+
async function ensureWalletOnChain(pub, wallet, expected) {
|
|
477
|
+
const actual = await pub.getChainId();
|
|
478
|
+
if (actual === expected) return;
|
|
479
|
+
try {
|
|
480
|
+
await wallet.switchChain({ id: expected });
|
|
481
|
+
} catch (error) {
|
|
482
|
+
throw new OwneyError(
|
|
483
|
+
"CHAIN_MISMATCH",
|
|
484
|
+
`Your wallet is on ${chainName(actual)}. Switch it to ${chainName(expected)} and try again.`,
|
|
485
|
+
{
|
|
486
|
+
expectedChainId: expected,
|
|
487
|
+
actualChainId: actual,
|
|
488
|
+
cause: error instanceof Error ? error.message : String(error)
|
|
489
|
+
}
|
|
490
|
+
);
|
|
491
|
+
}
|
|
492
|
+
const after = await pub.getChainId();
|
|
493
|
+
if (after !== expected) {
|
|
494
|
+
throw new OwneyError(
|
|
495
|
+
"CHAIN_MISMATCH",
|
|
496
|
+
`Your wallet is still on ${chainName(after)}. Switch it to ${chainName(expected)} and try again.`,
|
|
497
|
+
{ expectedChainId: expected, actualChainId: after }
|
|
498
|
+
);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// src/lib/sponsored-deposit.ts
|
|
503
|
+
var AUTH_WINDOW_SECONDS = 15 * 60;
|
|
504
|
+
var verificationSetter = /* @__PURE__ */ Symbol("owney.depositVerificationSetter");
|
|
505
|
+
function provideDepositVerificationContext(callback, context) {
|
|
506
|
+
callback[verificationSetter]?.(context);
|
|
507
|
+
}
|
|
508
|
+
function makeVerificationAwareDepositCallback(implementation) {
|
|
509
|
+
let nextVerification;
|
|
510
|
+
const callback = async (smartWallet, chainId, amount) => {
|
|
511
|
+
const verification = nextVerification;
|
|
512
|
+
nextVerification = void 0;
|
|
513
|
+
return implementation(smartWallet, chainId, amount, verification);
|
|
514
|
+
};
|
|
515
|
+
Object.defineProperty(callback, verificationSetter, {
|
|
516
|
+
value: (context) => {
|
|
517
|
+
nextVerification = context;
|
|
518
|
+
}
|
|
519
|
+
});
|
|
520
|
+
return callback;
|
|
521
|
+
}
|
|
522
|
+
|
|
235
523
|
// src/lib/rate-limit.ts
|
|
236
524
|
function rateLimitDelay(error, now = Date.now()) {
|
|
237
525
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -379,7 +667,7 @@ var AgentReads = class {
|
|
|
379
667
|
|
|
380
668
|
// src/agents/zyfai/zyfai.withdraw-submission.ts
|
|
381
669
|
var listenersByClient = /* @__PURE__ */ new WeakMap();
|
|
382
|
-
function observeWithdrawalSubmission(sdk, chainId, token) {
|
|
670
|
+
function observeWithdrawalSubmission(sdk, chainId, token, assertCurrent) {
|
|
383
671
|
const client = sdk.httpClient;
|
|
384
672
|
if (!client || typeof client.get !== "function" || typeof client.post !== "function")
|
|
385
673
|
return { attempted: () => void 0, rejected: () => false, request: () => void 0, stop: () => {
|
|
@@ -396,6 +684,7 @@ function observeWithdrawalSubmission(sdk, chainId, token) {
|
|
|
396
684
|
const withdrawal = method === "get" && url === "/users/withdraw" || method === "post" && url === "/users/partial-withdraw";
|
|
397
685
|
const payload = method === "get" ? options?.params : options;
|
|
398
686
|
const matching = withdrawal ? [...observers].filter((observer) => observer.chainId === payload?.chainId && observer.token === payload?.tokenSymbol) : [];
|
|
687
|
+
for (const observer of matching) observer.assertCurrent?.();
|
|
399
688
|
const startedAt = Date.now();
|
|
400
689
|
const request2 = {
|
|
401
690
|
attempted: true,
|
|
@@ -440,7 +729,7 @@ function observeWithdrawalSubmission(sdk, chainId, token) {
|
|
|
440
729
|
const status = error?.response?.status;
|
|
441
730
|
if (request2.httpStatus === void 0 && typeof status === "number" && Number.isInteger(status) && status >= 100 && status <= 599)
|
|
442
731
|
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";
|
|
732
|
+
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
733
|
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
734
|
throw error;
|
|
446
735
|
} finally {
|
|
@@ -453,7 +742,7 @@ function observeWithdrawalSubmission(sdk, chainId, token) {
|
|
|
453
742
|
let submitted = false;
|
|
454
743
|
let rejected = false;
|
|
455
744
|
let request = { attempted: false };
|
|
456
|
-
const listener = { chainId, token, notify: (outcome, evidence) => {
|
|
745
|
+
const listener = { chainId, token, assertCurrent, notify: (outcome, evidence) => {
|
|
457
746
|
request = evidence;
|
|
458
747
|
if (outcome === "attempted") submitted = true;
|
|
459
748
|
else if (outcome === "rejected") rejected = true;
|
|
@@ -504,10 +793,8 @@ function hasEmptyWithdrawalSnapshot(raw2, chainId, token) {
|
|
|
504
793
|
return true;
|
|
505
794
|
}
|
|
506
795
|
|
|
507
|
-
// src/agents/zyfai/zyfai.
|
|
508
|
-
var import_sdk = require("@zyfai/sdk");
|
|
796
|
+
// src/agents/zyfai/zyfai.deposit.ts
|
|
509
797
|
var import_viem4 = require("viem");
|
|
510
|
-
var import_chains = require("viem/chains");
|
|
511
798
|
|
|
512
799
|
// src/types/config.ts
|
|
513
800
|
var P_SUPPORTED_CHAINS = {
|
|
@@ -556,12 +843,51 @@ var SupportedAssets = [
|
|
|
556
843
|
}
|
|
557
844
|
];
|
|
558
845
|
|
|
559
|
-
// src/
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
846
|
+
// src/agents/zyfai/zyfai.deposit.ts
|
|
847
|
+
async function submitZyfaiDeposit({ sdk, state, chain, amount, asset, smartWallet, assertCurrent, onBeforeSubmission }) {
|
|
848
|
+
const owner = state.walletAddress;
|
|
849
|
+
const provider = state.provider;
|
|
850
|
+
const token = SupportedAssets.find((value) => value.chainId === chain.id && value.symbol === asset);
|
|
851
|
+
if (!token || !(0, import_viem4.isAddress)(owner) || !(0, import_viem4.isAddress)(smartWallet) || !/^\d+$/.test(amount) || BigInt(amount) <= 0n)
|
|
852
|
+
throw new OwneyError("AGENT_INVALID_RESPONSE", "Invalid Zyfai deposit transfer.", { chainId: chain.id, asset }, "zyfai");
|
|
853
|
+
assertCurrent();
|
|
854
|
+
const prepared = await sdk.prepareEnterPosition({ userAddress: owner, chainId: chain.id, amount, asset, strategy: "aggressive" });
|
|
855
|
+
assertCurrent();
|
|
856
|
+
const expectedData = (0, import_viem4.encodeFunctionData)({ abi: import_viem4.erc20Abi, functionName: "transfer", args: [smartWallet, BigInt(amount)] });
|
|
857
|
+
const transfer = prepared?.transfer;
|
|
858
|
+
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")
|
|
859
|
+
throw new OwneyError("AGENT_INVALID_RESPONSE", "Zyfai prepared a different deposit transfer.", { chainId: chain.id, asset }, "zyfai");
|
|
860
|
+
const wallet = (0, import_viem4.createWalletClient)({ account: owner, chain, transport: (0, import_viem4.custom)({
|
|
861
|
+
request: async (args) => {
|
|
862
|
+
assertCurrent();
|
|
863
|
+
if (args.method === "eth_sendTransaction") {
|
|
864
|
+
const [accounts, chainId] = await Promise.all([
|
|
865
|
+
provider.request({ method: "eth_accounts" }),
|
|
866
|
+
provider.request({ method: "eth_chainId" })
|
|
867
|
+
]);
|
|
868
|
+
assertCurrent();
|
|
869
|
+
if (!Array.isArray(accounts) || typeof accounts[0] !== "string" || accounts[0].toLowerCase() !== owner.toLowerCase() || Number(chainId) !== chain.id)
|
|
870
|
+
throw new OwneyError("NOT_CONNECTED", "Wallet changed while preparing Zyfai deposit.", void 0, "zyfai");
|
|
871
|
+
await onBeforeSubmission?.();
|
|
872
|
+
assertCurrent();
|
|
873
|
+
}
|
|
874
|
+
return provider.request(args);
|
|
875
|
+
}
|
|
876
|
+
}, { retryCount: 0 }) });
|
|
877
|
+
return wallet.sendTransaction({ account: owner, chain, to: token.address, data: expectedData, value: 0n });
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
// src/agents/zyfai/zyfai.agent.ts
|
|
881
|
+
var import_sdk = require("@zyfai/sdk");
|
|
882
|
+
var import_viem7 = require("viem");
|
|
883
|
+
var import_chains = require("viem/chains");
|
|
884
|
+
|
|
885
|
+
// src/lib/debug.ts
|
|
886
|
+
var configuredDebug = false;
|
|
887
|
+
function setOwneyDebug(enabled) {
|
|
888
|
+
configuredDebug = enabled;
|
|
889
|
+
}
|
|
890
|
+
function isOwneyDebug() {
|
|
565
891
|
return globalThis.__OWNEY_DEBUG__ === true || configuredDebug;
|
|
566
892
|
}
|
|
567
893
|
function debugLog(scope, message, data) {
|
|
@@ -600,8 +926,8 @@ var DayFilterMapping = {
|
|
|
600
926
|
};
|
|
601
927
|
|
|
602
928
|
// src/agents/zyfai/zyfai.mapper.ts
|
|
603
|
-
var
|
|
604
|
-
var exactHexAmount = (raw2, decimals) => (0,
|
|
929
|
+
var import_viem5 = require("viem");
|
|
930
|
+
var exactHexAmount = (raw2, decimals) => (0, import_viem5.formatUnits)(BigInt(/^0x/i.test(raw2) ? raw2 : `0x${raw2}`), decimals);
|
|
605
931
|
var DECIMALS_BY_SYMBOL = {
|
|
606
932
|
usdc: 6,
|
|
607
933
|
weth: 18,
|
|
@@ -615,13 +941,6 @@ function tokenDecimals(symbol, explicit) {
|
|
|
615
941
|
return explicit;
|
|
616
942
|
return DECIMALS_BY_SYMBOL[(symbol ?? "").toLowerCase()] ?? 6;
|
|
617
943
|
}
|
|
618
|
-
function mapDeposit(raw2) {
|
|
619
|
-
return {
|
|
620
|
-
txHash: raw2.txHash,
|
|
621
|
-
smartWallet: raw2.smartWallet,
|
|
622
|
-
amount: raw2.amount
|
|
623
|
-
};
|
|
624
|
-
}
|
|
625
944
|
function mapWithdraw(raw2) {
|
|
626
945
|
return {
|
|
627
946
|
txHash: raw2.txHash,
|
|
@@ -707,7 +1026,7 @@ function mapBalances(raw2, _chainId, smartWallet) {
|
|
|
707
1026
|
// legacy `amount` fallback is hex. Runtime
|
|
708
1027
|
// getBalances payloads often carry one (e.g. 18 for WETH) — prefer that
|
|
709
1028
|
// when present, otherwise fall back to the per-symbol lookup.
|
|
710
|
-
amount: p.underlyingAmountWithFee ?? p.underlyingAmount ? (0,
|
|
1029
|
+
amount: p.underlyingAmountWithFee ?? p.underlyingAmount ? (0, import_viem5.formatUnits)(
|
|
711
1030
|
BigInt(p.underlyingAmountWithFee ?? p.underlyingAmount ?? "0"),
|
|
712
1031
|
tokenDecimals(
|
|
713
1032
|
p.token_symbol,
|
|
@@ -1372,7 +1691,7 @@ function protocolsPolicyNeedsUpdate(current, desiredProtocols, desiredAutoSelect
|
|
|
1372
1691
|
}
|
|
1373
1692
|
|
|
1374
1693
|
// src/lib/paid-rpc.ts
|
|
1375
|
-
var
|
|
1694
|
+
var import_viem6 = require("viem");
|
|
1376
1695
|
var PAID_RPC_RETRY_COUNT = 3;
|
|
1377
1696
|
var PAID_RPC_RETRY_DELAY_MS = 1e3;
|
|
1378
1697
|
function configuredRpcProxyBaseUrl(baseUrl) {
|
|
@@ -1408,9 +1727,9 @@ function createPaidRpcClient(chain, rpcUrls) {
|
|
|
1408
1727
|
rpcUrls,
|
|
1409
1728
|
chain.id
|
|
1410
1729
|
);
|
|
1411
|
-
return (0,
|
|
1730
|
+
return (0, import_viem6.createPublicClient)({
|
|
1412
1731
|
chain,
|
|
1413
|
-
transport: (0,
|
|
1732
|
+
transport: (0, import_viem6.http)(url, {
|
|
1414
1733
|
retryCount: PAID_RPC_RETRY_COUNT,
|
|
1415
1734
|
retryDelay: PAID_RPC_RETRY_DELAY_MS
|
|
1416
1735
|
})
|
|
@@ -1507,7 +1826,7 @@ async function withPaidRpcDiagnostics(operation, chainId, rpcMethod, agentId) {
|
|
|
1507
1826
|
}
|
|
1508
1827
|
|
|
1509
1828
|
// src/agents/zyfai/zyfai.agent.ts
|
|
1510
|
-
var ERC7579_IS_MODULE_INSTALLED_ABI = (0,
|
|
1829
|
+
var ERC7579_IS_MODULE_INSTALLED_ABI = (0, import_viem7.parseAbi)([
|
|
1511
1830
|
"function isModuleInstalled(uint256 moduleTypeId, address module, bytes additionalContext) view returns (bool)"
|
|
1512
1831
|
]);
|
|
1513
1832
|
var WETH_ADDRESS_BY_CHAIN = {
|
|
@@ -1521,6 +1840,14 @@ var POOL_POLICY_CHAIN_IDS = [8453, 42161, 1];
|
|
|
1521
1840
|
var EARNINGS_REFRESH_COOLDOWN_MS = 60 * 60 * 1e3;
|
|
1522
1841
|
var WITHDRAW_BALANCE_TIMEOUT_MS = 2e3;
|
|
1523
1842
|
var ZyfaiAgent = class _ZyfaiAgent {
|
|
1843
|
+
constructor(apiKey, rpcUrls, referralSource) {
|
|
1844
|
+
this.apiKey = apiKey;
|
|
1845
|
+
this.referralSource = referralSource;
|
|
1846
|
+
this.rpcUrls = resolveRpcUrls(rpcUrls);
|
|
1847
|
+
this.sdk = this.createSdk();
|
|
1848
|
+
}
|
|
1849
|
+
apiKey;
|
|
1850
|
+
referralSource;
|
|
1524
1851
|
id = "zyfai";
|
|
1525
1852
|
supportedChainIds = [8453, 42161, 1];
|
|
1526
1853
|
supportedAssets = [
|
|
@@ -1565,6 +1892,9 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1565
1892
|
*/
|
|
1566
1893
|
sessionKeyAttempts = /* @__PURE__ */ new Set();
|
|
1567
1894
|
connectAuthPromise = null;
|
|
1895
|
+
connectAuthScope = null;
|
|
1896
|
+
connectionGeneration = 0;
|
|
1897
|
+
sdkHasConnected = false;
|
|
1568
1898
|
rpcUrls;
|
|
1569
1899
|
publicClients = /* @__PURE__ */ new Map();
|
|
1570
1900
|
// Receipt-derived amounts and log identities, scoped to the owner and asset.
|
|
@@ -1575,17 +1905,20 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1575
1905
|
earningsSnapshot = null;
|
|
1576
1906
|
earningsGeneration = 0;
|
|
1577
1907
|
balanceSnapshots = /* @__PURE__ */ new WeakMap();
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1908
|
+
/** A replaced wallet session gets its own vendor client. In-flight calls
|
|
1909
|
+
* keep their original client; authentication must never change owners under
|
|
1910
|
+
* an operation that is waiting for provider reads or an HTTP response. */
|
|
1911
|
+
createSdk() {
|
|
1912
|
+
const sdk = new import_sdk.ZyfaiSDK({
|
|
1913
|
+
apiKey: this.apiKey,
|
|
1582
1914
|
rpcUrls: this.rpcUrls,
|
|
1583
1915
|
// Forwarded to /auth/login by the SDK's own SIWE handshake, so
|
|
1584
1916
|
// attribution survives without the AppKit SIWX config (which carried it
|
|
1585
1917
|
// via `createOwneySIWX({ referralSource })` when apps used the modal).
|
|
1586
|
-
referralSource
|
|
1918
|
+
referralSource: this.referralSource
|
|
1587
1919
|
});
|
|
1588
|
-
this.installAuthCache();
|
|
1920
|
+
this.installAuthCache(sdk);
|
|
1921
|
+
return sdk;
|
|
1589
1922
|
}
|
|
1590
1923
|
getPublicClient(chainId) {
|
|
1591
1924
|
const cached = this.publicClients.get(chainId);
|
|
@@ -1660,7 +1993,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1660
1993
|
}, asset.address, entry.action === "Withdraw" ? "withdraw" : "deposit");
|
|
1661
1994
|
if (evidence.transfer === "confirmed" && evidence.confirmedAmount) {
|
|
1662
1995
|
Object.assign(tx, {
|
|
1663
|
-
amount: (0,
|
|
1996
|
+
amount: (0, import_viem7.formatUnits)(BigInt(evidence.confirmedAmount), asset.decimals),
|
|
1664
1997
|
amountRaw: evidence.confirmedAmount,
|
|
1665
1998
|
blockNumber: evidence.blockNumber,
|
|
1666
1999
|
logIndexes: evidence.logIndexes,
|
|
@@ -1684,9 +2017,9 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1684
2017
|
* No-op on the server (no `window`) — the SDK is constructed during SSR
|
|
1685
2018
|
* for some apps and the patch only matters in the browser anyway.
|
|
1686
2019
|
*/
|
|
1687
|
-
installAuthCache() {
|
|
2020
|
+
installAuthCache(sdk = this.sdk) {
|
|
1688
2021
|
if (typeof window === "undefined") return;
|
|
1689
|
-
const internals =
|
|
2022
|
+
const internals = sdk;
|
|
1690
2023
|
const original = internals.authenticateUser.bind(internals);
|
|
1691
2024
|
internals.authenticateUser = async () => {
|
|
1692
2025
|
if (internals.authenticatedUserId !== null) return;
|
|
@@ -1731,25 +2064,41 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1731
2064
|
/** Light connect: SIWE auth only. Re-auths if chain changed. */
|
|
1732
2065
|
async connectAuth(state, chainId) {
|
|
1733
2066
|
const validChainId = isValidChainId(chainId);
|
|
1734
|
-
|
|
2067
|
+
const owner = state.walletAddress.toLowerCase();
|
|
2068
|
+
const scope = `${owner}:${validChainId}`;
|
|
2069
|
+
if (this.connectedAddress?.toLowerCase() === owner && this.connectedChainId === validChainId) {
|
|
1735
2070
|
return;
|
|
1736
2071
|
}
|
|
1737
|
-
if (this.connectAuthPromise) {
|
|
2072
|
+
if (this.connectAuthPromise && this.connectAuthScope === scope) {
|
|
1738
2073
|
await this.connectAuthPromise;
|
|
1739
|
-
return;
|
|
2074
|
+
return this.connectAuth(state, chainId);
|
|
1740
2075
|
}
|
|
1741
|
-
this.
|
|
2076
|
+
if (this.sdkHasConnected || this.connectedAddress) this.sdk = this.createSdk();
|
|
2077
|
+
this.sdkHasConnected = true;
|
|
2078
|
+
const executionSdk = this.sdk;
|
|
2079
|
+
const generation = ++this.connectionGeneration;
|
|
2080
|
+
this.connectedAddress = null;
|
|
2081
|
+
this.connectedChainId = null;
|
|
2082
|
+
const pending = (async () => {
|
|
1742
2083
|
const address = await this.connectAccountWithRetry(
|
|
1743
2084
|
state.provider,
|
|
1744
|
-
validChainId
|
|
2085
|
+
validChainId,
|
|
2086
|
+
executionSdk
|
|
1745
2087
|
);
|
|
2088
|
+
if (generation !== this.connectionGeneration || address.toLowerCase() !== owner)
|
|
2089
|
+
throw new OwneyError("NOT_CONNECTED", "Wallet changed while connecting Zyfai.", void 0, this.id);
|
|
1746
2090
|
this.connectedAddress = address;
|
|
1747
2091
|
this.connectedChainId = validChainId;
|
|
1748
2092
|
})();
|
|
2093
|
+
this.connectAuthPromise = pending;
|
|
2094
|
+
this.connectAuthScope = scope;
|
|
1749
2095
|
try {
|
|
1750
|
-
await
|
|
2096
|
+
await pending;
|
|
1751
2097
|
} finally {
|
|
1752
|
-
this.connectAuthPromise
|
|
2098
|
+
if (this.connectAuthPromise === pending) {
|
|
2099
|
+
this.connectAuthPromise = null;
|
|
2100
|
+
this.connectAuthScope = null;
|
|
2101
|
+
}
|
|
1753
2102
|
}
|
|
1754
2103
|
}
|
|
1755
2104
|
/**
|
|
@@ -1761,16 +2110,16 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1761
2110
|
* JWT from a misconfigured API key; we retry once either way, and if the
|
|
1762
2111
|
* second attempt still fails the original error propagates.
|
|
1763
2112
|
*/
|
|
1764
|
-
async connectAccountWithRetry(provider, chainId) {
|
|
2113
|
+
async connectAccountWithRetry(provider, chainId, executionSdk = this.sdk) {
|
|
1765
2114
|
try {
|
|
1766
|
-
return await
|
|
2115
|
+
return await executionSdk.connectAccount(provider, chainId);
|
|
1767
2116
|
} catch (error) {
|
|
1768
2117
|
const message = error instanceof Error ? error.message : String(error);
|
|
1769
2118
|
if (!message.toLowerCase().includes("unauthorized")) throw error;
|
|
1770
|
-
const internals =
|
|
2119
|
+
const internals = executionSdk;
|
|
1771
2120
|
const address = internals.walletClient?.account?.address;
|
|
1772
2121
|
if (address) clearSession(address, chainId);
|
|
1773
|
-
return await
|
|
2122
|
+
return await executionSdk.connectAccount(provider, chainId);
|
|
1774
2123
|
}
|
|
1775
2124
|
}
|
|
1776
2125
|
/**
|
|
@@ -1782,11 +2131,17 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1782
2131
|
* withdrawFunds) fail with "No account connected".
|
|
1783
2132
|
*/
|
|
1784
2133
|
async ensureConnected(state, chainId) {
|
|
2134
|
+
const assertOwner = () => {
|
|
2135
|
+
if (this.connectedAddress?.toLowerCase() !== state.walletAddress.toLowerCase() || this.connectedChainId !== chainId)
|
|
2136
|
+
throw new OwneyError("NOT_CONNECTED", "Wallet changed while connecting Zyfai.", void 0, this.id);
|
|
2137
|
+
};
|
|
1785
2138
|
await this.connectAuth(state, chainId);
|
|
2139
|
+
assertOwner();
|
|
1786
2140
|
const internals = this.sdk;
|
|
1787
2141
|
if (!internals.walletClient || internals.authenticatedUserId === null) {
|
|
1788
2142
|
this.connectedChainId = null;
|
|
1789
2143
|
await this.connectAuth(state, chainId);
|
|
2144
|
+
assertOwner();
|
|
1790
2145
|
}
|
|
1791
2146
|
}
|
|
1792
2147
|
/** A rejected execution session must not be reused by the next foreground attempt. */
|
|
@@ -1847,6 +2202,8 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1847
2202
|
}
|
|
1848
2203
|
// --- IAgent: Connection lifecycle ---
|
|
1849
2204
|
async disconnect() {
|
|
2205
|
+
const executionSdk = this.sdk;
|
|
2206
|
+
this.connectionGeneration++;
|
|
1850
2207
|
this.earningsGeneration++;
|
|
1851
2208
|
this.earningsReads.clear();
|
|
1852
2209
|
this.earningsRefreshes.clear();
|
|
@@ -1854,10 +2211,14 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1854
2211
|
if (this.connectedAddress && this.connectedChainId !== null) {
|
|
1855
2212
|
clearSession(this.connectedAddress, this.connectedChainId);
|
|
1856
2213
|
}
|
|
1857
|
-
await this.sdk.disconnectAccount();
|
|
1858
2214
|
this.connectedAddress = null;
|
|
1859
2215
|
this.connectedChainId = null;
|
|
2216
|
+
this.connectAuthPromise = null;
|
|
2217
|
+
this.connectAuthScope = null;
|
|
1860
2218
|
this.smartWalletCache.clear();
|
|
2219
|
+
this.sdk = this.createSdk();
|
|
2220
|
+
this.sdkHasConnected = false;
|
|
2221
|
+
await executionSdk.disconnectAccount();
|
|
1861
2222
|
}
|
|
1862
2223
|
// --- IAgent: Account lifecycle ---
|
|
1863
2224
|
async activateAgent(state, chainId) {
|
|
@@ -2345,94 +2706,91 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2345
2706
|
await this.ensureSessionKey(ownerAddress, chainId, redeployed.address);
|
|
2346
2707
|
return redeployed.address;
|
|
2347
2708
|
}
|
|
2348
|
-
async deposit(state, chainId, amount, asset, depositCallback, onProgress) {
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
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 = {
|
|
2709
|
+
async deposit(state, chainId, amount, asset, depositCallback, onProgress, onBeforeSubmission) {
|
|
2710
|
+
const validChainId = isValidChainId(chainId);
|
|
2711
|
+
const owner = state.walletAddress;
|
|
2712
|
+
const provider = state.provider;
|
|
2713
|
+
await this.ensureConnected(state, validChainId);
|
|
2714
|
+
const executionSdk = this.sdk;
|
|
2715
|
+
const generation = this.connectionGeneration;
|
|
2716
|
+
const assertCurrent = () => {
|
|
2717
|
+
const account = executionSdk.walletClient?.account?.address;
|
|
2718
|
+
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())
|
|
2719
|
+
throw new OwneyError("NOT_CONNECTED", "Wallet changed while preparing Zyfai deposit.", void 0, this.id);
|
|
2720
|
+
};
|
|
2721
|
+
assertCurrent();
|
|
2722
|
+
const smartWallet = await this.ensureWalletDeployed(owner, validChainId);
|
|
2723
|
+
assertCurrent();
|
|
2724
|
+
notifyFunding(onProgress, {
|
|
2725
|
+
agentId: this.id,
|
|
2726
|
+
chainId,
|
|
2727
|
+
token: asset,
|
|
2728
|
+
walletAddress: owner,
|
|
2729
|
+
agentWallet: smartWallet,
|
|
2730
|
+
intendedAmount: amount,
|
|
2731
|
+
transfer: "pending",
|
|
2732
|
+
registration: "pending",
|
|
2733
|
+
delivery: "not-applicable"
|
|
2734
|
+
});
|
|
2735
|
+
const txHash = depositCallback ? await depositCallback(smartWallet, validChainId, amount) : await submitZyfaiDeposit({
|
|
2736
|
+
sdk: executionSdk,
|
|
2737
|
+
state: { ...state, walletAddress: owner, provider },
|
|
2738
|
+
chain: VIEM_CHAIN[validChainId],
|
|
2739
|
+
amount,
|
|
2740
|
+
asset,
|
|
2741
|
+
smartWallet,
|
|
2742
|
+
assertCurrent,
|
|
2743
|
+
onBeforeSubmission: onBeforeSubmission ? () => onBeforeSubmission({
|
|
2411
2744
|
agentId: this.id,
|
|
2412
2745
|
chainId,
|
|
2413
2746
|
token: asset,
|
|
2414
|
-
walletAddress:
|
|
2415
|
-
agentWallet:
|
|
2747
|
+
walletAddress: owner,
|
|
2748
|
+
agentWallet: smartWallet,
|
|
2416
2749
|
intendedAmount: amount,
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
registration: raw2.registration ? "confirmed" : "unknown",
|
|
2750
|
+
transfer: "pending",
|
|
2751
|
+
registration: "pending",
|
|
2420
2752
|
delivery: "not-applicable"
|
|
2421
|
-
}
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2753
|
+
}) : void 0
|
|
2754
|
+
});
|
|
2755
|
+
let evidence = {
|
|
2756
|
+
agentId: this.id,
|
|
2757
|
+
chainId,
|
|
2758
|
+
token: asset,
|
|
2759
|
+
walletAddress: owner,
|
|
2760
|
+
agentWallet: smartWallet,
|
|
2761
|
+
intendedAmount: amount,
|
|
2762
|
+
txHash,
|
|
2763
|
+
transfer: "pending",
|
|
2764
|
+
registration: "pending",
|
|
2765
|
+
delivery: "not-applicable"
|
|
2766
|
+
};
|
|
2767
|
+
notifyFunding(onProgress, evidence);
|
|
2768
|
+
try {
|
|
2769
|
+
const receipt = await this.getPublicClient(validChainId).waitForTransactionReceipt({
|
|
2770
|
+
hash: txHash,
|
|
2771
|
+
confirmations: 1,
|
|
2772
|
+
timeout: 9e4,
|
|
2773
|
+
checkReplacement: false
|
|
2774
|
+
});
|
|
2775
|
+
const token = SupportedAssets.find((value) => value.chainId === chainId && value.symbol === asset);
|
|
2776
|
+
evidence = inspectFundingReceipt(receipt, evidence, token.address, "deposit");
|
|
2777
|
+
} catch {
|
|
2778
|
+
evidence = { ...evidence, transfer: "unknown" };
|
|
2779
|
+
}
|
|
2780
|
+
notifyFunding(onProgress, evidence);
|
|
2781
|
+
if (evidence.transfer === "failed")
|
|
2782
|
+
throw new OwneyError("AGENT_TRANSACTION_REVERTED", "Zyfai deposit transaction reverted.", { txHash }, this.id);
|
|
2783
|
+
if (evidence.transfer !== "confirmed") return { txHash, smartWallet, amount, evidence };
|
|
2784
|
+
try {
|
|
2785
|
+
assertCurrent();
|
|
2786
|
+
const tokenAddress = asset === "WETH" ? WETH_ADDRESS_BY_CHAIN[validChainId] : void 0;
|
|
2787
|
+
await (tokenAddress ? executionSdk.logDeposit(validChainId, txHash, amount, tokenAddress) : executionSdk.logDeposit(validChainId, txHash, amount));
|
|
2788
|
+
evidence = { ...evidence, registration: "confirmed" };
|
|
2789
|
+
} catch {
|
|
2790
|
+
evidence = { ...evidence, registration: "unknown" };
|
|
2435
2791
|
}
|
|
2792
|
+
notifyFunding(onProgress, evidence);
|
|
2793
|
+
return { txHash, smartWallet, amount, evidence };
|
|
2436
2794
|
}
|
|
2437
2795
|
// --- IAgent: Fund operations ---
|
|
2438
2796
|
/** Only after a definitive endpoint rejection, combine a new provider
|
|
@@ -2462,7 +2820,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2462
2820
|
this.sdk.getPortfolio(owner).catch(() => void 0)
|
|
2463
2821
|
]);
|
|
2464
2822
|
assertScope();
|
|
2465
|
-
if (!(0,
|
|
2823
|
+
if (!(0, import_viem7.isAddress)(wallet.address) || !registered.smartWallet || registered.smartWallet.toLowerCase() !== wallet.address.toLowerCase())
|
|
2466
2824
|
throw new OwneyError(
|
|
2467
2825
|
"AGENT_AUTH_FAILED",
|
|
2468
2826
|
"Could not verify Zyfai's withdrawal wallet.",
|
|
@@ -2473,7 +2831,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2473
2831
|
const asset = SupportedAssets.find((value) => value.chainId === chainId && value.symbol === token);
|
|
2474
2832
|
const idle = asset ? await this.getPublicClient(chainId).readContract({
|
|
2475
2833
|
address: asset.address,
|
|
2476
|
-
abi:
|
|
2834
|
+
abi: import_viem7.erc20Abi,
|
|
2477
2835
|
functionName: "balanceOf",
|
|
2478
2836
|
args: [wallet.address]
|
|
2479
2837
|
}).catch(() => void 0) : void 0;
|
|
@@ -2502,11 +2860,12 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2502
2860
|
/** Called only after the execution endpoint explicitly rejected a request.
|
|
2503
2861
|
* A timeout or an accepted request never authorizes repair and resubmission. */
|
|
2504
2862
|
async recoverWithdrawalSession(state, chainId, token, owner) {
|
|
2863
|
+
const generation = this.connectionGeneration;
|
|
2505
2864
|
await this.assertNotEmptyRejectedWithdrawal(state, chainId, token, owner);
|
|
2506
2865
|
const internals = this.sdk;
|
|
2507
2866
|
const assertScope = () => {
|
|
2508
2867
|
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())
|
|
2868
|
+
if (generation !== this.connectionGeneration || state.walletAddress.toLowerCase() !== owner.toLowerCase() || this.connectedAddress?.toLowerCase() !== owner.toLowerCase() || this.connectedChainId !== chainId || account && account.toLowerCase() !== owner.toLowerCase())
|
|
2510
2869
|
throw new OwneyError("NOT_CONNECTED", "Wallet changed while preparing Zyfai withdrawal.", void 0, this.id);
|
|
2511
2870
|
};
|
|
2512
2871
|
assertScope();
|
|
@@ -2535,6 +2894,8 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2535
2894
|
}
|
|
2536
2895
|
}
|
|
2537
2896
|
async withdraw(state, chainId, token, amount, onProgress) {
|
|
2897
|
+
if (amount !== void 0 && (typeof amount !== "string" || !/^[0-9]+$/.test(amount) || BigInt(amount) <= 0n))
|
|
2898
|
+
throw new OwneyError("WITHDRAW_INVALID_AMOUNT", "Withdrawal amount must be a positive integer in token base units.", void 0, this.id);
|
|
2538
2899
|
const validChainId = isValidChainId(chainId);
|
|
2539
2900
|
try {
|
|
2540
2901
|
await this.ensureConnected(state, validChainId);
|
|
@@ -2551,16 +2912,40 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2551
2912
|
});
|
|
2552
2913
|
throw error;
|
|
2553
2914
|
}
|
|
2554
|
-
|
|
2555
|
-
const
|
|
2556
|
-
const
|
|
2915
|
+
const executionSdk = this.sdk;
|
|
2916
|
+
const internals = executionSdk;
|
|
2917
|
+
const generation = this.connectionGeneration;
|
|
2918
|
+
const owner = state.walletAddress;
|
|
2919
|
+
let staleSessionError;
|
|
2920
|
+
const assertCurrent = () => {
|
|
2921
|
+
const account = internals.walletClient?.account?.address;
|
|
2922
|
+
if (generation !== this.connectionGeneration || this.connectedAddress?.toLowerCase() !== owner.toLowerCase() || this.connectedChainId !== validChainId || state.chainId !== null && state.chainId !== validChainId || account && account.toLowerCase() !== owner.toLowerCase()) {
|
|
2923
|
+
staleSessionError = new OwneyError(
|
|
2924
|
+
"NOT_CONNECTED",
|
|
2925
|
+
"Wallet changed before Zyfai withdrawal submission.",
|
|
2926
|
+
{ phase: "prepare", rejectedBeforeSubmission: true },
|
|
2927
|
+
this.id
|
|
2928
|
+
);
|
|
2929
|
+
throw staleSessionError;
|
|
2930
|
+
}
|
|
2931
|
+
};
|
|
2932
|
+
let observation = observeWithdrawalSubmission(executionSdk, validChainId, token, assertCurrent);
|
|
2933
|
+
const authToken = internals.httpClient?.authToken;
|
|
2557
2934
|
let raw2;
|
|
2558
2935
|
try {
|
|
2559
2936
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
2560
2937
|
try {
|
|
2561
|
-
|
|
2938
|
+
assertCurrent();
|
|
2939
|
+
raw2 = await executionSdk.withdrawFunds(owner, validChainId, amount, token);
|
|
2562
2940
|
break;
|
|
2563
2941
|
} catch (error) {
|
|
2942
|
+
if (observation.rejected()) {
|
|
2943
|
+
try {
|
|
2944
|
+
assertCurrent();
|
|
2945
|
+
} catch {
|
|
2946
|
+
throw error;
|
|
2947
|
+
}
|
|
2948
|
+
}
|
|
2564
2949
|
if (!amount && observation.rejected() && observation.request()?.failure === "insufficient-balance") {
|
|
2565
2950
|
try {
|
|
2566
2951
|
await this.assertNotEmptyRejectedWithdrawal(state, validChainId, token, owner);
|
|
@@ -2578,7 +2963,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2578
2963
|
);
|
|
2579
2964
|
await this.recoverWithdrawalSession(state, validChainId, token, owner);
|
|
2580
2965
|
observation.stop();
|
|
2581
|
-
observation = observeWithdrawalSubmission(
|
|
2966
|
+
observation = observeWithdrawalSubmission(executionSdk, validChainId, token, assertCurrent);
|
|
2582
2967
|
}
|
|
2583
2968
|
}
|
|
2584
2969
|
if (!raw2) throw new OwneyError(
|
|
@@ -2588,6 +2973,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2588
2973
|
this.id
|
|
2589
2974
|
);
|
|
2590
2975
|
} catch (error) {
|
|
2976
|
+
if (staleSessionError && observation.attempted() === false) error = staleSessionError;
|
|
2591
2977
|
this.invalidateRejectedWithdrawalSession(error, state, validChainId, authToken);
|
|
2592
2978
|
if (observation.attempted() !== void 0) {
|
|
2593
2979
|
const failed = observation.attempted() === false || observation.rejected();
|
|
@@ -2608,7 +2994,6 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2608
2994
|
observation.stop();
|
|
2609
2995
|
}
|
|
2610
2996
|
if (!raw2.success) {
|
|
2611
|
-
const unresolved = !!raw2.txHash || /already|pending|queued|in.progress/i.test(raw2.message ?? "");
|
|
2612
2997
|
notifyFunding(onProgress, {
|
|
2613
2998
|
agentId: this.id,
|
|
2614
2999
|
chainId,
|
|
@@ -2616,9 +3001,9 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2616
3001
|
walletAddress: state.walletAddress,
|
|
2617
3002
|
intendedAmount: amount ?? "MAX",
|
|
2618
3003
|
txHash: raw2.txHash,
|
|
2619
|
-
transfer:
|
|
3004
|
+
transfer: "unknown",
|
|
2620
3005
|
registration: "not-applicable",
|
|
2621
|
-
delivery:
|
|
3006
|
+
delivery: "unknown",
|
|
2622
3007
|
withdrawalRequest: observation.request()
|
|
2623
3008
|
});
|
|
2624
3009
|
throw new OwneyError(
|
|
@@ -2645,8 +3030,9 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2645
3030
|
}
|
|
2646
3031
|
/** Registration recovery never signs, transfers, activates, or refreshes authentication. */
|
|
2647
3032
|
async retryDepositRegistration(state, evidence) {
|
|
2648
|
-
const
|
|
2649
|
-
|
|
3033
|
+
const executionSdk = this.sdk;
|
|
3034
|
+
const internals = executionSdk;
|
|
3035
|
+
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
3036
|
throw new OwneyError("NOT_CONNECTED", "Reconnect the wallet before recovering deposit registration.");
|
|
2651
3037
|
}
|
|
2652
3038
|
if (evidence.transfer !== "confirmed" || !evidence.txHash) {
|
|
@@ -2654,16 +3040,16 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2654
3040
|
}
|
|
2655
3041
|
const cid = isValidChainId(evidence.chainId);
|
|
2656
3042
|
const tokenAddress = evidence.token === "WETH" ? WETH_ADDRESS_BY_CHAIN[cid] : void 0;
|
|
2657
|
-
await
|
|
3043
|
+
await executionSdk.logDeposit(cid, evidence.txHash, evidence.intendedAmount, tokenAddress);
|
|
2658
3044
|
return { ...evidence, registration: "confirmed" };
|
|
2659
3045
|
}
|
|
2660
3046
|
// --- IAgent: Portfolio reads ---
|
|
2661
3047
|
async getFundingWallet(state, chainId) {
|
|
2662
3048
|
return (await this.sdk.getSmartWalletAddress(state.walletAddress, isValidChainId(chainId))).address;
|
|
2663
3049
|
}
|
|
2664
|
-
/** A positive Safe balance is a
|
|
2665
|
-
*
|
|
2666
|
-
*
|
|
3050
|
+
/** A positive deployed Safe balance is a conservative planning floor. Zero
|
|
3051
|
+
* requires both the mapped Safe's exact idle balance and a fresh complete
|
|
3052
|
+
* empty portfolio, including for an undeployed counterfactual Safe. */
|
|
2667
3053
|
async getWithdrawableBalance(state, chainId, token) {
|
|
2668
3054
|
const validChainId = isValidChainId(chainId);
|
|
2669
3055
|
const asset = SupportedAssets.find((value) => value.chainId === validChainId && value.symbol === token);
|
|
@@ -2692,20 +3078,27 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2692
3078
|
this.sdk.getSmartWalletByEOA(owner)
|
|
2693
3079
|
]);
|
|
2694
3080
|
assertScope();
|
|
2695
|
-
if (!(0,
|
|
3081
|
+
if (!(0, import_viem7.isAddress)(wallet.address) || wallet.isDeployed !== false && (wallet.isDeployed !== true || wallet.isOwner !== true) || !registered.smartWallet || registered.smartWallet.toLowerCase() !== wallet.address.toLowerCase()) throw unavailable();
|
|
2696
3082
|
const client = this.getPublicClient(validChainId);
|
|
2697
3083
|
const blockNumber = await client.getBlockNumber({ cacheTime: 0 });
|
|
2698
3084
|
assertScope();
|
|
2699
3085
|
const idle = await client.readContract({
|
|
2700
3086
|
address: asset.address,
|
|
2701
|
-
abi:
|
|
3087
|
+
abi: import_viem7.erc20Abi,
|
|
2702
3088
|
functionName: "balanceOf",
|
|
2703
3089
|
args: [wallet.address],
|
|
2704
3090
|
blockNumber
|
|
2705
3091
|
});
|
|
2706
3092
|
assertScope();
|
|
2707
|
-
if (typeof idle !== "bigint" || idle
|
|
2708
|
-
|
|
3093
|
+
if (typeof idle !== "bigint" || idle < 0n) throw unavailable();
|
|
3094
|
+
if (idle > 0n) {
|
|
3095
|
+
if (wallet.isDeployed !== true || wallet.isOwner !== true) throw unavailable();
|
|
3096
|
+
return idle;
|
|
3097
|
+
}
|
|
3098
|
+
const portfolio = await this.sdk.getPortfolio(owner);
|
|
3099
|
+
assertScope();
|
|
3100
|
+
if (!hasEmptyWithdrawalSnapshot(portfolio, validChainId, token)) throw unavailable();
|
|
3101
|
+
return 0n;
|
|
2709
3102
|
};
|
|
2710
3103
|
try {
|
|
2711
3104
|
return await Promise.race([read2(), new Promise((_, reject) => {
|
|
@@ -2748,7 +3141,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2748
3141
|
if (blockNumber < BigInt(evidence.blockNumber)) return void 0;
|
|
2749
3142
|
const idle = await client.readContract({
|
|
2750
3143
|
address: asset.address,
|
|
2751
|
-
abi:
|
|
3144
|
+
abi: import_viem7.erc20Abi,
|
|
2752
3145
|
functionName: "balanceOf",
|
|
2753
3146
|
args: [balance.smartWallet],
|
|
2754
3147
|
blockNumber
|
|
@@ -2940,259 +3333,25 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2940
3333
|
return true;
|
|
2941
3334
|
}
|
|
2942
3335
|
// --- IAgent: Discovery (no wallet required) ---
|
|
2943
|
-
async getAgentApy(days, options) {
|
|
2944
|
-
const raw2 = await this.sdk.getAPYPerStrategy(
|
|
2945
|
-
false,
|
|
2946
|
-
DayFilterMapping[days],
|
|
2947
|
-
"aggressive",
|
|
2948
|
-
options?.chainId,
|
|
2949
|
-
options?.tokenSymbol
|
|
2950
|
-
);
|
|
2951
|
-
return mapApyByStrategy(raw2);
|
|
2952
|
-
}
|
|
2953
|
-
};
|
|
2954
|
-
|
|
2955
|
-
// src/agents/yieldseeker/yieldseeker.agent.ts
|
|
2956
|
-
var import_viem12 = require("viem");
|
|
2957
|
-
var import_chains4 = require("viem/chains");
|
|
2958
|
-
|
|
2959
|
-
// src/lib/chain-guard.ts
|
|
2960
|
-
var CHAIN_NAMES = {
|
|
2961
|
-
1: "Ethereum",
|
|
2962
|
-
8453: "Base",
|
|
2963
|
-
42161: "Arbitrum"
|
|
2964
|
-
};
|
|
2965
|
-
function chainName(chainId) {
|
|
2966
|
-
return CHAIN_NAMES[chainId] ?? `chain ${chainId}`;
|
|
2967
|
-
}
|
|
2968
|
-
async function ensureWalletOnChain(pub, wallet, expected) {
|
|
2969
|
-
const actual = await pub.getChainId();
|
|
2970
|
-
if (actual === expected) return;
|
|
2971
|
-
try {
|
|
2972
|
-
await wallet.switchChain({ id: expected });
|
|
2973
|
-
} catch (error) {
|
|
2974
|
-
throw new OwneyError(
|
|
2975
|
-
"CHAIN_MISMATCH",
|
|
2976
|
-
`Your wallet is on ${chainName(actual)}. Switch it to ${chainName(expected)} and try again.`,
|
|
2977
|
-
{
|
|
2978
|
-
expectedChainId: expected,
|
|
2979
|
-
actualChainId: actual,
|
|
2980
|
-
cause: error instanceof Error ? error.message : String(error)
|
|
2981
|
-
}
|
|
2982
|
-
);
|
|
2983
|
-
}
|
|
2984
|
-
const after = await pub.getChainId();
|
|
2985
|
-
if (after !== expected) {
|
|
2986
|
-
throw new OwneyError(
|
|
2987
|
-
"CHAIN_MISMATCH",
|
|
2988
|
-
`Your wallet is still on ${chainName(after)}. Switch it to ${chainName(expected)} and try again.`,
|
|
2989
|
-
{ expectedChainId: expected, actualChainId: after }
|
|
2990
|
-
);
|
|
2991
|
-
}
|
|
2992
|
-
}
|
|
2993
|
-
|
|
2994
|
-
// src/lib/transfer-auth.ts
|
|
2995
|
-
var import_viem5 = require("viem");
|
|
2996
|
-
|
|
2997
|
-
// src/lib/sponsor-client.ts
|
|
2998
|
-
var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
2999
|
-
async function postPaymasterIntent(input) {
|
|
3000
|
-
const base6 = input.baseUrl ?? ROUTING_API_BASE_URL;
|
|
3001
|
-
let res;
|
|
3002
|
-
try {
|
|
3003
|
-
res = await fetch(`${base6}/api/v1/sponsor/paymaster-intent`, {
|
|
3004
|
-
method: "POST",
|
|
3005
|
-
headers: {
|
|
3006
|
-
"content-type": "application/json",
|
|
3007
|
-
"x-owney-api-key": input.apiKey,
|
|
3008
|
-
Authorization: `Signature ${input.yieldseekerSignature}`
|
|
3009
|
-
},
|
|
3010
|
-
body: JSON.stringify(input.body)
|
|
3011
|
-
});
|
|
3012
|
-
} catch (networkError) {
|
|
3013
|
-
throw new OwneyError(
|
|
3014
|
-
"SPONSOR_REQUEST_FAILED",
|
|
3015
|
-
`Paymaster intent network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
|
|
3016
|
-
{ cause: String(networkError), safeToFallback: true }
|
|
3017
|
-
);
|
|
3018
|
-
}
|
|
3019
|
-
const text = await res.text();
|
|
3020
|
-
let parsed = null;
|
|
3021
|
-
try {
|
|
3022
|
-
parsed = JSON.parse(text);
|
|
3023
|
-
} catch {
|
|
3024
|
-
}
|
|
3025
|
-
if (!res.ok || !parsed?.success || typeof parsed.data?.intent !== "string" || typeof parsed.data.expiresAt !== "number") {
|
|
3026
|
-
throw new OwneyError(
|
|
3027
|
-
"SPONSOR_REQUEST_FAILED",
|
|
3028
|
-
`Paymaster intent API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
|
|
3029
|
-
{
|
|
3030
|
-
statusCode: res.status,
|
|
3031
|
-
responseBody: text.slice(0, 500),
|
|
3032
|
-
safeToFallback: true
|
|
3033
|
-
}
|
|
3034
|
-
);
|
|
3035
|
-
}
|
|
3036
|
-
return parsed.data;
|
|
3037
|
-
}
|
|
3038
|
-
async function getSponsorRelayerAddress(input) {
|
|
3039
|
-
const base6 = input.baseUrl ?? ROUTING_API_BASE_URL;
|
|
3040
|
-
let res;
|
|
3041
|
-
try {
|
|
3042
|
-
res = await fetch(
|
|
3043
|
-
`${base6}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
|
|
3044
|
-
{
|
|
3045
|
-
headers: { "x-owney-api-key": input.apiKey }
|
|
3046
|
-
}
|
|
3047
|
-
);
|
|
3048
|
-
} catch (networkError) {
|
|
3049
|
-
throw new OwneyError(
|
|
3050
|
-
"SPONSOR_REQUEST_FAILED",
|
|
3051
|
-
`Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
|
|
3052
|
-
{ cause: String(networkError), safeToFallback: true }
|
|
3053
|
-
);
|
|
3054
|
-
}
|
|
3055
|
-
const text = await res.text();
|
|
3056
|
-
let parsed = null;
|
|
3057
|
-
try {
|
|
3058
|
-
parsed = JSON.parse(text);
|
|
3059
|
-
} catch {
|
|
3060
|
-
}
|
|
3061
|
-
if (!res.ok || !parsed?.success || !parsed.data?.relayer) {
|
|
3062
|
-
throw new OwneyError(
|
|
3063
|
-
"SPONSOR_REQUEST_FAILED",
|
|
3064
|
-
`Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
|
|
3065
|
-
{
|
|
3066
|
-
statusCode: res.status,
|
|
3067
|
-
responseBody: text.slice(0, 500),
|
|
3068
|
-
safeToFallback: true
|
|
3069
|
-
}
|
|
3070
|
-
);
|
|
3071
|
-
}
|
|
3072
|
-
return parsed.data.relayer;
|
|
3073
|
-
}
|
|
3074
|
-
async function postSponsorBatchTransfer(input) {
|
|
3075
|
-
let res;
|
|
3076
|
-
try {
|
|
3077
|
-
res = await fetch(
|
|
3078
|
-
`${input.baseUrl ?? ROUTING_API_BASE_URL}/api/v1/sponsor/permit2-batch`,
|
|
3079
|
-
{
|
|
3080
|
-
method: "POST",
|
|
3081
|
-
headers: {
|
|
3082
|
-
"content-type": "application/json",
|
|
3083
|
-
"x-owney-api-key": input.apiKey
|
|
3084
|
-
},
|
|
3085
|
-
body: JSON.stringify(input.body)
|
|
3086
|
-
}
|
|
3087
|
-
);
|
|
3088
|
-
} catch {
|
|
3089
|
-
throw new OwneyError(
|
|
3090
|
-
"SPONSOR_REQUEST_FAILED",
|
|
3091
|
-
"Deposit status is unknown. Retry the same amount to check it.",
|
|
3092
|
-
{ safeToFallback: false }
|
|
3093
|
-
);
|
|
3094
|
-
}
|
|
3095
|
-
const parsed = await res.json().catch(() => null);
|
|
3096
|
-
if (!res.ok || !parsed?.success || !/^0x[0-9a-fA-F]{64}$/.test(parsed.data?.txHash ?? "")) {
|
|
3097
|
-
throw new OwneyError(
|
|
3098
|
-
"SPONSOR_REQUEST_FAILED",
|
|
3099
|
-
"Deposit could not be confirmed. Retry the same amount to check its status.",
|
|
3100
|
-
{
|
|
3101
|
-
statusCode: res.status,
|
|
3102
|
-
safeToFallback: false,
|
|
3103
|
-
notSubmitted: parsed?.notSubmitted === true || parsed?.error?.notSubmitted === true || parsed?.error?.details?.notSubmitted === true
|
|
3104
|
-
}
|
|
3105
|
-
);
|
|
3106
|
-
}
|
|
3107
|
-
return parsed.data;
|
|
3108
|
-
}
|
|
3109
|
-
|
|
3110
|
-
// src/lib/permit2.ts
|
|
3111
|
-
var import_viem6 = require("viem");
|
|
3112
|
-
var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
3113
|
-
var MAX_UINT256 = 2n ** 256n - 1n;
|
|
3114
|
-
function permit2ApprovalAmount(requiredAmount) {
|
|
3115
|
-
if (requiredAmount <= 0n) {
|
|
3116
|
-
throw new Error("Permit2 approval requires a positive deposit amount");
|
|
3117
|
-
}
|
|
3118
|
-
return MAX_UINT256;
|
|
3119
|
-
}
|
|
3120
|
-
var ERC20_ALLOWANCE_ABI = [
|
|
3121
|
-
{
|
|
3122
|
-
type: "function",
|
|
3123
|
-
name: "allowance",
|
|
3124
|
-
stateMutability: "view",
|
|
3125
|
-
inputs: [
|
|
3126
|
-
{ name: "owner", type: "address" },
|
|
3127
|
-
{ name: "spender", type: "address" }
|
|
3128
|
-
],
|
|
3129
|
-
outputs: [{ name: "", type: "uint256" }]
|
|
3130
|
-
},
|
|
3131
|
-
{
|
|
3132
|
-
type: "function",
|
|
3133
|
-
name: "approve",
|
|
3134
|
-
stateMutability: "nonpayable",
|
|
3135
|
-
inputs: [
|
|
3136
|
-
{ name: "spender", type: "address" },
|
|
3137
|
-
{ name: "amount", type: "uint256" }
|
|
3138
|
-
],
|
|
3139
|
-
outputs: [{ name: "", type: "bool" }]
|
|
3140
|
-
},
|
|
3141
|
-
{
|
|
3142
|
-
type: "function",
|
|
3143
|
-
name: "balanceOf",
|
|
3144
|
-
stateMutability: "view",
|
|
3145
|
-
inputs: [{ name: "account", type: "address" }],
|
|
3146
|
-
outputs: [{ name: "", type: "uint256" }]
|
|
3336
|
+
async getAgentApy(days, options) {
|
|
3337
|
+
const raw2 = await this.sdk.getAPYPerStrategy(
|
|
3338
|
+
false,
|
|
3339
|
+
DayFilterMapping[days],
|
|
3340
|
+
"aggressive",
|
|
3341
|
+
options?.chainId,
|
|
3342
|
+
options?.tokenSymbol
|
|
3343
|
+
);
|
|
3344
|
+
return mapApyByStrategy(raw2);
|
|
3147
3345
|
}
|
|
3148
|
-
|
|
3149
|
-
function randomPermit2Nonce() {
|
|
3150
|
-
const bytes = new Uint8Array(32);
|
|
3151
|
-
globalThis.crypto.getRandomValues(bytes);
|
|
3152
|
-
return BigInt((0, import_viem6.bytesToHex)(bytes));
|
|
3153
|
-
}
|
|
3154
|
-
async function readPermit2Allowance(publicClient, token, owner, blockNumber) {
|
|
3155
|
-
return publicClient.readContract({
|
|
3156
|
-
address: token,
|
|
3157
|
-
abi: ERC20_ALLOWANCE_ABI,
|
|
3158
|
-
functionName: "allowance",
|
|
3159
|
-
args: [owner, PERMIT2_ADDRESS],
|
|
3160
|
-
...blockNumber === void 0 ? {} : { blockNumber }
|
|
3161
|
-
});
|
|
3162
|
-
}
|
|
3163
|
-
async function readErc20Balance(publicClient, token, owner) {
|
|
3164
|
-
return publicClient.readContract({
|
|
3165
|
-
address: token,
|
|
3166
|
-
abi: ERC20_ALLOWANCE_ABI,
|
|
3167
|
-
functionName: "balanceOf",
|
|
3168
|
-
args: [owner]
|
|
3169
|
-
});
|
|
3170
|
-
}
|
|
3346
|
+
};
|
|
3171
3347
|
|
|
3172
|
-
// src/
|
|
3173
|
-
var
|
|
3174
|
-
var
|
|
3175
|
-
function provideDepositVerificationContext(callback, context) {
|
|
3176
|
-
callback[verificationSetter]?.(context);
|
|
3177
|
-
}
|
|
3178
|
-
function makeVerificationAwareDepositCallback(implementation) {
|
|
3179
|
-
let nextVerification;
|
|
3180
|
-
const callback = async (smartWallet, chainId, amount) => {
|
|
3181
|
-
const verification = nextVerification;
|
|
3182
|
-
nextVerification = void 0;
|
|
3183
|
-
return implementation(smartWallet, chainId, amount, verification);
|
|
3184
|
-
};
|
|
3185
|
-
Object.defineProperty(callback, verificationSetter, {
|
|
3186
|
-
value: (context) => {
|
|
3187
|
-
nextVerification = context;
|
|
3188
|
-
}
|
|
3189
|
-
});
|
|
3190
|
-
return callback;
|
|
3191
|
-
}
|
|
3348
|
+
// src/agents/yieldseeker/yieldseeker.agent.ts
|
|
3349
|
+
var import_viem13 = require("viem");
|
|
3350
|
+
var import_chains4 = require("viem/chains");
|
|
3192
3351
|
|
|
3193
3352
|
// src/agents/yieldseeker/yieldseeker.auth.ts
|
|
3194
3353
|
var import_siwe = require("siwe");
|
|
3195
|
-
var
|
|
3354
|
+
var import_viem8 = require("viem");
|
|
3196
3355
|
var import_chains2 = require("viem/chains");
|
|
3197
3356
|
|
|
3198
3357
|
// src/agents/yieldseeker/yieldseeker.auth-cache.ts
|
|
@@ -3305,7 +3464,7 @@ function createYieldseekerSiweMessage(address, chainId, dependencies = {}) {
|
|
|
3305
3464
|
return new import_siwe.SiweMessage({
|
|
3306
3465
|
scheme: url.protocol.slice(0, -1),
|
|
3307
3466
|
domain: url.host,
|
|
3308
|
-
address: (0,
|
|
3467
|
+
address: (0, import_viem8.getAddress)(address),
|
|
3309
3468
|
uri: url.origin,
|
|
3310
3469
|
version: "1",
|
|
3311
3470
|
chainId,
|
|
@@ -3391,15 +3550,15 @@ var YieldseekerAuth = class {
|
|
|
3391
3550
|
clearYieldseekerSession(state.walletAddress, chainId);
|
|
3392
3551
|
}
|
|
3393
3552
|
async sign(state, chainId) {
|
|
3394
|
-
const account = (0,
|
|
3395
|
-
const publicClient = (0,
|
|
3553
|
+
const account = (0, import_viem8.getAddress)(state.walletAddress);
|
|
3554
|
+
const publicClient = (0, import_viem8.createPublicClient)({
|
|
3396
3555
|
chain: import_chains2.base,
|
|
3397
|
-
transport: (0,
|
|
3556
|
+
transport: (0, import_viem8.custom)(state.provider)
|
|
3398
3557
|
});
|
|
3399
|
-
const walletClient = (0,
|
|
3558
|
+
const walletClient = (0, import_viem8.createWalletClient)({
|
|
3400
3559
|
account,
|
|
3401
3560
|
chain: import_chains2.base,
|
|
3402
|
-
transport: (0,
|
|
3561
|
+
transport: (0, import_viem8.custom)(state.provider)
|
|
3403
3562
|
});
|
|
3404
3563
|
await ensureWalletOnChain(
|
|
3405
3564
|
publicClient,
|
|
@@ -3566,7 +3725,7 @@ var YieldseekerApiClient = class {
|
|
|
3566
3725
|
};
|
|
3567
3726
|
|
|
3568
3727
|
// src/agents/yieldseeker/yieldseeker.mapper.ts
|
|
3569
|
-
var
|
|
3728
|
+
var import_viem9 = require("viem");
|
|
3570
3729
|
|
|
3571
3730
|
// src/lib/helpers/snapshot-apy.ts
|
|
3572
3731
|
var DAY_MS = 864e5;
|
|
@@ -3633,10 +3792,18 @@ function raw(value, endpoint) {
|
|
|
3633
3792
|
return BigInt(value);
|
|
3634
3793
|
}
|
|
3635
3794
|
function decimal(value, decimals, endpoint) {
|
|
3636
|
-
return (0,
|
|
3795
|
+
return (0, import_viem9.formatUnits)(raw(value, endpoint), decimals);
|
|
3796
|
+
}
|
|
3797
|
+
function balanceRaw(value, endpoint) {
|
|
3798
|
+
const amount = raw(value, endpoint);
|
|
3799
|
+
if (amount < 0n) return invalid(endpoint, "expected a non-negative balance");
|
|
3800
|
+
return amount;
|
|
3801
|
+
}
|
|
3802
|
+
function balanceDecimal(value, decimals, endpoint) {
|
|
3803
|
+
return (0, import_viem9.formatUnits)(balanceRaw(value, endpoint), decimals);
|
|
3637
3804
|
}
|
|
3638
3805
|
function usd(rawAmount, decimals, price) {
|
|
3639
|
-
return Number((0,
|
|
3806
|
+
return Number((0, import_viem9.formatUnits)(rawAmount, decimals)) * price;
|
|
3640
3807
|
}
|
|
3641
3808
|
function percent(value) {
|
|
3642
3809
|
const result = Number(value);
|
|
@@ -3662,7 +3829,7 @@ function assetAddressValue(record, address) {
|
|
|
3662
3829
|
}
|
|
3663
3830
|
function position(value, asset, baseAssetDecimals) {
|
|
3664
3831
|
const option = value?.yieldOption;
|
|
3665
|
-
if (!option || typeof option.provider !== "string" || typeof option.name !== "string" || typeof option.address !== "string" || !(0,
|
|
3832
|
+
if (!option || typeof option.provider !== "string" || typeof option.name !== "string" || typeof option.address !== "string" || !(0, import_viem9.isAddress)(option.address)) {
|
|
3666
3833
|
return invalid("yield positions", "missing vault metadata");
|
|
3667
3834
|
}
|
|
3668
3835
|
return {
|
|
@@ -3676,13 +3843,13 @@ function position(value, asset, baseAssetDecimals) {
|
|
|
3676
3843
|
// underlying base-asset units in `assetsBase`; pair that value with the
|
|
3677
3844
|
// snapshot's corresponding `baseAssetDecimals` for display. Keep the raw
|
|
3678
3845
|
// share quantity separate from the withdrawable underlying asset amount.
|
|
3679
|
-
amount:
|
|
3846
|
+
amount: balanceDecimal(
|
|
3680
3847
|
value.assetsBase,
|
|
3681
3848
|
baseAssetDecimals,
|
|
3682
3849
|
"yield positions"
|
|
3683
3850
|
),
|
|
3684
|
-
amountRaw:
|
|
3685
|
-
withdrawableAmountRaw:
|
|
3851
|
+
amountRaw: balanceRaw(value.assetsRaw, "yield positions").toString(),
|
|
3852
|
+
withdrawableAmountRaw: balanceRaw(value.withdrawableAssetsRaw, "yield positions").toString(),
|
|
3686
3853
|
apy: percent(option.riskAdjustedApy),
|
|
3687
3854
|
tvl: Number(option.totalDepositsUsd),
|
|
3688
3855
|
liquidity: Number(option.withdrawableDepositsUsd)
|
|
@@ -3699,7 +3866,7 @@ function mapYieldseekerBalances(contexts) {
|
|
|
3699
3866
|
chain: "BASE",
|
|
3700
3867
|
chainId: 8453,
|
|
3701
3868
|
asset: context.asset,
|
|
3702
|
-
amount:
|
|
3869
|
+
amount: balanceDecimal(context.snapshot.totalValueBase, context.snapshot.baseAssetDecimals, "snapshot")
|
|
3703
3870
|
});
|
|
3704
3871
|
const idle = assetAddressValue(
|
|
3705
3872
|
context.snapshot.tokenBalances,
|
|
@@ -3709,7 +3876,7 @@ function mapYieldseekerBalances(contexts) {
|
|
|
3709
3876
|
chain: "BASE",
|
|
3710
3877
|
chainId: 8453,
|
|
3711
3878
|
asset: context.asset,
|
|
3712
|
-
amount:
|
|
3879
|
+
amount: balanceDecimal(idle, metadata.decimals, "snapshot")
|
|
3713
3880
|
});
|
|
3714
3881
|
positions.push(
|
|
3715
3882
|
...context.positions.map(
|
|
@@ -3721,7 +3888,7 @@ function mapYieldseekerBalances(contexts) {
|
|
|
3721
3888
|
)
|
|
3722
3889
|
);
|
|
3723
3890
|
totalUsd += usd(
|
|
3724
|
-
|
|
3891
|
+
balanceRaw(context.snapshot.totalValueBase, "snapshot"),
|
|
3725
3892
|
context.snapshot.baseAssetDecimals,
|
|
3726
3893
|
context.snapshot.baseAssetPriceUsd
|
|
3727
3894
|
);
|
|
@@ -3755,7 +3922,7 @@ function mapYieldseekerEarnings(contexts) {
|
|
|
3755
3922
|
chain: "BASE",
|
|
3756
3923
|
chainId: 8453,
|
|
3757
3924
|
asset: context.asset,
|
|
3758
|
-
amount: (0,
|
|
3925
|
+
amount: (0, import_viem9.formatUnits)(amount, context.snapshot.baseAssetDecimals)
|
|
3759
3926
|
});
|
|
3760
3927
|
lifetimeEarnings += usd(
|
|
3761
3928
|
amount,
|
|
@@ -3913,7 +4080,7 @@ function allocationEntry(action, context) {
|
|
|
3913
4080
|
const leg = deposit;
|
|
3914
4081
|
const symbol = typeof leg.assetSymbol === "string" ? leg.assetSymbol.toUpperCase() : "";
|
|
3915
4082
|
if (symbol !== context.asset && !(context.asset === "WETH" && symbol === "ETH")) return void 0;
|
|
3916
|
-
if (typeof leg.vaultAddress !== "string" || !(0,
|
|
4083
|
+
if (typeof leg.vaultAddress !== "string" || !(0, import_viem9.isAddress)(leg.vaultAddress)) return void 0;
|
|
3917
4084
|
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
4085
|
if (rawAmount === void 0 || rawAmount <= 0n) return void 0;
|
|
3919
4086
|
const option = context.positions.find((position2) => position2.yieldOption.address.toLowerCase() === leg.vaultAddress.toLowerCase())?.yieldOption;
|
|
@@ -3921,7 +4088,7 @@ function allocationEntry(action, context) {
|
|
|
3921
4088
|
protocol: typeof leg.vaultProvider === "string" && leg.vaultProvider ? leg.vaultProvider : option?.provider || "Vault",
|
|
3922
4089
|
pool: typeof leg.vaultName === "string" && leg.vaultName ? leg.vaultName : option?.name,
|
|
3923
4090
|
tokenSymbol: context.asset,
|
|
3924
|
-
amount: (0,
|
|
4091
|
+
amount: (0, import_viem9.formatUnits)(rawAmount, YIELDSEEKER_ASSET_METADATA[context.asset].decimals)
|
|
3925
4092
|
});
|
|
3926
4093
|
amountRaw += rawAmount;
|
|
3927
4094
|
}
|
|
@@ -3940,7 +4107,7 @@ function allocationEntry(action, context) {
|
|
|
3940
4107
|
tokenSymbol: context.asset,
|
|
3941
4108
|
agentWallet: context.wallet.walletAddress,
|
|
3942
4109
|
amountRaw: String(amountRaw),
|
|
3943
|
-
amount: (0,
|
|
4110
|
+
amount: (0, import_viem9.formatUnits)(amountRaw, YIELDSEEKER_ASSET_METADATA[context.asset].decimals)
|
|
3944
4111
|
}]
|
|
3945
4112
|
};
|
|
3946
4113
|
}
|
|
@@ -4064,7 +4231,7 @@ function mapYieldseekerHistory(contexts, options) {
|
|
|
4064
4231
|
const known = new Set(target.logIndexes ?? []);
|
|
4065
4232
|
if (tx.logIndexes?.some((index) => !known.has(index))) {
|
|
4066
4233
|
target.amountRaw = String(BigInt(target.amountRaw ?? "0") + BigInt(tx.amountRaw));
|
|
4067
|
-
target.amount = (0,
|
|
4234
|
+
target.amount = (0, import_viem9.formatUnits)(
|
|
4068
4235
|
BigInt(target.amountRaw),
|
|
4069
4236
|
YIELDSEEKER_ASSET_METADATA[target.tokenSymbol].decimals
|
|
4070
4237
|
);
|
|
@@ -4145,7 +4312,7 @@ function mapYieldseekerAgentApy(options, days) {
|
|
|
4145
4312
|
}
|
|
4146
4313
|
|
|
4147
4314
|
// src/lib/remaining-vault-balance.ts
|
|
4148
|
-
var
|
|
4315
|
+
var import_viem10 = require("viem");
|
|
4149
4316
|
async function remainingVaultBalance(client, wallet, asset, vaults, blockNumber) {
|
|
4150
4317
|
const addresses = [...new Set(vaults.map((value) => value.toLowerCase()))];
|
|
4151
4318
|
if (addresses.length > 64) return void 0;
|
|
@@ -4156,8 +4323,8 @@ async function remainingVaultBalance(client, wallet, asset, vaults, blockNumber)
|
|
|
4156
4323
|
blockNumber,
|
|
4157
4324
|
allowFailure: true,
|
|
4158
4325
|
contracts: batch.map((address) => ({
|
|
4159
|
-
address: (0,
|
|
4160
|
-
abi:
|
|
4326
|
+
address: (0, import_viem10.getAddress)(address),
|
|
4327
|
+
abi: import_viem10.erc20Abi,
|
|
4161
4328
|
functionName: "balanceOf",
|
|
4162
4329
|
args: [wallet]
|
|
4163
4330
|
}))
|
|
@@ -4167,15 +4334,15 @@ async function remainingVaultBalance(client, wallet, asset, vaults, blockNumber)
|
|
|
4167
4334
|
for (let index = 0; index < batch.length; index++) {
|
|
4168
4335
|
const result = balances[index];
|
|
4169
4336
|
if (result?.status !== "success" || typeof result.result !== "bigint" || result.result < 0n) return void 0;
|
|
4170
|
-
if (result.result > 0n) funded.push({ address: (0,
|
|
4337
|
+
if (result.result > 0n) funded.push({ address: (0, import_viem10.getAddress)(batch[index]), shares: result.result });
|
|
4171
4338
|
}
|
|
4172
4339
|
if (!funded.length) return 0n;
|
|
4173
4340
|
const valuations = await client.multicall({
|
|
4174
4341
|
blockNumber,
|
|
4175
4342
|
allowFailure: true,
|
|
4176
4343
|
contracts: funded.flatMap(({ address, shares }) => [
|
|
4177
|
-
{ address, abi:
|
|
4178
|
-
{ address, abi:
|
|
4344
|
+
{ address, abi: import_viem10.erc4626Abi, functionName: "asset" },
|
|
4345
|
+
{ address, abi: import_viem10.erc4626Abi, functionName: "convertToAssets", args: [shares] }
|
|
4179
4346
|
])
|
|
4180
4347
|
});
|
|
4181
4348
|
if (valuations.length !== funded.length * 2) return void 0;
|
|
@@ -4191,12 +4358,12 @@ async function remainingVaultBalance(client, wallet, asset, vaults, blockNumber)
|
|
|
4191
4358
|
}
|
|
4192
4359
|
|
|
4193
4360
|
// src/agents/yieldseeker/yieldseeker.wallet-version.ts
|
|
4194
|
-
var
|
|
4361
|
+
var import_viem11 = require("viem");
|
|
4195
4362
|
var YIELDSEEKER_FACTORY = "0x9c7410a0faCAC60850C46eE5b58B518daec95130";
|
|
4196
4363
|
var YIELDSEEKER_V1_IMPLEMENTATION = "0x32403455357589523435dB18b414057D7cE05051";
|
|
4197
4364
|
var YIELDSEEKER_V2_IMPLEMENTATION = "0x613Db9c924ADB7A7A90c11b02Cce20c913E3Fe50";
|
|
4198
4365
|
var ERC1967_IMPLEMENTATION_SLOT = "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc";
|
|
4199
|
-
var walletAbi = (0,
|
|
4366
|
+
var walletAbi = (0, import_viem11.parseAbi)([
|
|
4200
4367
|
"function owner() view returns (address)",
|
|
4201
4368
|
"function ownerAgentIndex() view returns (uint256)",
|
|
4202
4369
|
"function baseAsset() view returns (address)",
|
|
@@ -4204,7 +4371,7 @@ var walletAbi = (0, import_viem10.parseAbi)([
|
|
|
4204
4371
|
"function upgradeToLatest()",
|
|
4205
4372
|
"event Upgraded(address indexed implementation)"
|
|
4206
4373
|
]);
|
|
4207
|
-
var factoryAbi = (0,
|
|
4374
|
+
var factoryAbi = (0, import_viem11.parseAbi)([
|
|
4208
4375
|
"function userWallets(address owner, uint256 index) view returns (address)",
|
|
4209
4376
|
"function agentWalletImplementation() view returns (address)"
|
|
4210
4377
|
]);
|
|
@@ -4212,9 +4379,9 @@ function yieldseekerOwnerPath(code) {
|
|
|
4212
4379
|
return !code || code === "0x" || /^0xef0100[0-9a-f]{40}$/i.test(code) ? "eoa" : "smart";
|
|
4213
4380
|
}
|
|
4214
4381
|
async function readYieldseekerWalletStatus(client, wallet, owner, asset, blockNumber) {
|
|
4215
|
-
const agentWallet = (0,
|
|
4216
|
-
const expectedOwner = (0,
|
|
4217
|
-
const expectedAsset = (0,
|
|
4382
|
+
const agentWallet = (0, import_viem11.getAddress)(wallet);
|
|
4383
|
+
const expectedOwner = (0, import_viem11.getAddress)(owner);
|
|
4384
|
+
const expectedAsset = (0, import_viem11.getAddress)(asset);
|
|
4218
4385
|
const [code, ownerCode, slot, actualOwner, index, actualAsset, actualFactory, latest] = await Promise.all([
|
|
4219
4386
|
client.getBytecode({ address: agentWallet, blockNumber }),
|
|
4220
4387
|
client.getBytecode({ address: expectedOwner, blockNumber }),
|
|
@@ -4228,7 +4395,7 @@ async function readYieldseekerWalletStatus(client, wallet, owner, asset, blockNu
|
|
|
4228
4395
|
if (!code || code === "0x" || !slot || /^0x0+$/.test(slot)) {
|
|
4229
4396
|
throw new Error("Yieldseeker wallet is not a deployed ERC1967 proxy");
|
|
4230
4397
|
}
|
|
4231
|
-
const implementation = (0,
|
|
4398
|
+
const implementation = (0, import_viem11.getAddress)(`0x${slot.slice(-40)}`);
|
|
4232
4399
|
const mapped = await client.readContract({
|
|
4233
4400
|
address: YIELDSEEKER_FACTORY,
|
|
4234
4401
|
abi: factoryAbi,
|
|
@@ -4236,8 +4403,8 @@ async function readYieldseekerWalletStatus(client, wallet, owner, asset, blockNu
|
|
|
4236
4403
|
args: [expectedOwner, index],
|
|
4237
4404
|
blockNumber
|
|
4238
4405
|
});
|
|
4239
|
-
const verified = (0,
|
|
4240
|
-
const version = !verified ? "unknown" : (0,
|
|
4406
|
+
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);
|
|
4407
|
+
const version = !verified ? "unknown" : (0, import_viem11.isAddressEqual)(implementation, YIELDSEEKER_V2_IMPLEMENTATION) ? "v2" : (0, import_viem11.isAddressEqual)(implementation, YIELDSEEKER_V1_IMPLEMENTATION) ? "v1" : "unknown";
|
|
4241
4408
|
return {
|
|
4242
4409
|
agentWallet,
|
|
4243
4410
|
owner: actualOwner,
|
|
@@ -4246,13 +4413,13 @@ async function readYieldseekerWalletStatus(client, wallet, owner, asset, blockNu
|
|
|
4246
4413
|
implementation,
|
|
4247
4414
|
version,
|
|
4248
4415
|
verified,
|
|
4249
|
-
upgradeAvailable: version === "v1" && (0,
|
|
4416
|
+
upgradeAvailable: version === "v1" && (0, import_viem11.isAddressEqual)(latest, YIELDSEEKER_V2_IMPLEMENTATION)
|
|
4250
4417
|
};
|
|
4251
4418
|
}
|
|
4252
4419
|
var YIELDSEEKER_UPGRADE_ABI = walletAbi;
|
|
4253
4420
|
|
|
4254
4421
|
// src/agents/yieldseeker/yieldseeker.sponsored-withdraw.ts
|
|
4255
|
-
var
|
|
4422
|
+
var import_viem12 = require("viem");
|
|
4256
4423
|
var import_account_abstraction2 = require("viem/account-abstraction");
|
|
4257
4424
|
var import_accounts = require("viem/accounts");
|
|
4258
4425
|
var import_chains3 = require("viem/chains");
|
|
@@ -4339,7 +4506,7 @@ function rpcDiagnostics(data) {
|
|
|
4339
4506
|
details.revertName = data.revertName;
|
|
4340
4507
|
if (typeof data?.aaCode === "string" && /^AA[0-9]{2}$/.test(data.aaCode)) details.aaCode = data.aaCode;
|
|
4341
4508
|
if (typeof data?.panicCode === "string" && /^0x[0-9a-fA-F]{1,2}$/.test(data.panicCode)) {
|
|
4342
|
-
const panicCode = (0,
|
|
4509
|
+
const panicCode = (0, import_viem12.toHex)(BigInt(data.panicCode));
|
|
4343
4510
|
if (["0x0", "0x1", "0x11", "0x12", "0x21", "0x22", "0x31", "0x32", "0x41", "0x51"].includes(panicCode))
|
|
4344
4511
|
details.panicCode = panicCode;
|
|
4345
4512
|
}
|
|
@@ -4559,14 +4726,14 @@ async function submitEoa(input) {
|
|
|
4559
4726
|
throw sponsorError("Base did not return EIP-1559 gas fees.", true);
|
|
4560
4727
|
let operation = {
|
|
4561
4728
|
sender: input.agentWallet,
|
|
4562
|
-
nonce: (0,
|
|
4729
|
+
nonce: (0, import_viem12.toHex)(nonce),
|
|
4563
4730
|
initCode: "0x",
|
|
4564
4731
|
callData: input.callData,
|
|
4565
|
-
callGasLimit: (0,
|
|
4566
|
-
verificationGasLimit: (0,
|
|
4567
|
-
preVerificationGas: (0,
|
|
4568
|
-
maxFeePerGas: (0,
|
|
4569
|
-
maxPriorityFeePerGas: (0,
|
|
4732
|
+
callGasLimit: (0, import_viem12.toHex)(3e5),
|
|
4733
|
+
verificationGasLimit: (0, import_viem12.toHex)(3e5),
|
|
4734
|
+
preVerificationGas: (0, import_viem12.toHex)(6e4),
|
|
4735
|
+
maxFeePerGas: (0, import_viem12.toHex)(fees.maxFeePerGas * USER_OP_FEE_HEADROOM),
|
|
4736
|
+
maxPriorityFeePerGas: (0, import_viem12.toHex)(fees.maxPriorityFeePerGas),
|
|
4570
4737
|
paymasterAndData: "0x",
|
|
4571
4738
|
signature: "0x"
|
|
4572
4739
|
};
|
|
@@ -4574,7 +4741,7 @@ async function submitEoa(input) {
|
|
|
4574
4741
|
const stub = await rpc(
|
|
4575
4742
|
input.rpcUrl,
|
|
4576
4743
|
"pm_getPaymasterStubData",
|
|
4577
|
-
[operation, ENTRY_POINT_V06, (0,
|
|
4744
|
+
[operation, ENTRY_POINT_V06, (0, import_viem12.toHex)(8453), {}],
|
|
4578
4745
|
"prepare"
|
|
4579
4746
|
);
|
|
4580
4747
|
if (!stub.paymasterAndData?.startsWith("0x"))
|
|
@@ -4589,7 +4756,7 @@ async function submitEoa(input) {
|
|
|
4589
4756
|
const final = await rpc(
|
|
4590
4757
|
input.rpcUrl,
|
|
4591
4758
|
"pm_getPaymasterData",
|
|
4592
|
-
[operation, ENTRY_POINT_V06, (0,
|
|
4759
|
+
[operation, ENTRY_POINT_V06, (0, import_viem12.toHex)(8453), {}],
|
|
4593
4760
|
"prepare"
|
|
4594
4761
|
);
|
|
4595
4762
|
if (!final.paymasterAndData?.startsWith("0x"))
|
|
@@ -4599,10 +4766,10 @@ async function submitEoa(input) {
|
|
|
4599
4766
|
const userOpHash = operationHash(operation);
|
|
4600
4767
|
await assertOwnerSession(input.state, input.owner);
|
|
4601
4768
|
assertIntentFresh(input.expiresAt);
|
|
4602
|
-
const wallet = (0,
|
|
4769
|
+
const wallet = (0, import_viem12.createWalletClient)({
|
|
4603
4770
|
account: input.owner,
|
|
4604
4771
|
chain: import_chains3.base,
|
|
4605
|
-
transport: (0,
|
|
4772
|
+
transport: (0, import_viem12.custom)(input.state.provider)
|
|
4606
4773
|
});
|
|
4607
4774
|
const signature = await wallet.signMessage({ message: { raw: userOpHash } });
|
|
4608
4775
|
operation = { ...operation, signature };
|
|
@@ -4680,13 +4847,13 @@ async function submitSmart(input) {
|
|
|
4680
4847
|
} catch {
|
|
4681
4848
|
throw sponsorError("This account cannot check paymaster support on Base.", true);
|
|
4682
4849
|
}
|
|
4683
|
-
const supportsPaymaster = capabilities?.[(0,
|
|
4850
|
+
const supportsPaymaster = capabilities?.[(0, import_viem12.toHex)(8453)]?.paymasterService?.supported ?? capabilities?.["8453"]?.paymasterService?.supported ?? capabilities?.["0x0"]?.paymasterService?.supported;
|
|
4684
4851
|
if (supportsPaymaster !== true)
|
|
4685
4852
|
throw sponsorError("This account cannot use a paymaster on Base.", true);
|
|
4686
4853
|
await assertOwnerSession(input.state, input.owner);
|
|
4687
4854
|
let sent;
|
|
4688
4855
|
assertIntentFresh(input.expiresAt);
|
|
4689
|
-
const requestedId = (0,
|
|
4856
|
+
const requestedId = (0, import_viem12.toHex)(globalThis.crypto.getRandomValues(new Uint8Array(32)));
|
|
4690
4857
|
savePending(input.onPending, { callsId: requestedId }, true);
|
|
4691
4858
|
await checkpoint(input.onBeforeSubmission, { callsId: requestedId });
|
|
4692
4859
|
try {
|
|
@@ -4695,7 +4862,7 @@ async function submitSmart(input) {
|
|
|
4695
4862
|
params: [{
|
|
4696
4863
|
version: "2.0.0",
|
|
4697
4864
|
from: input.owner,
|
|
4698
|
-
chainId: (0,
|
|
4865
|
+
chainId: (0, import_viem12.toHex)(8453),
|
|
4699
4866
|
id: requestedId,
|
|
4700
4867
|
atomicRequired: false,
|
|
4701
4868
|
calls: [{ to: input.agentWallet, value: "0x0", data: input.callData }],
|
|
@@ -4770,7 +4937,7 @@ async function submitSmart(input) {
|
|
|
4770
4937
|
);
|
|
4771
4938
|
}
|
|
4772
4939
|
async function submitYieldseekerSponsoredWithdrawal(input) {
|
|
4773
|
-
const owner = (0,
|
|
4940
|
+
const owner = (0, import_viem12.getAddress)(input.state.walletAddress);
|
|
4774
4941
|
const { intent, rpcUrl } = await requestIntent({
|
|
4775
4942
|
apiKey: input.apiKey,
|
|
4776
4943
|
routingApiBaseUrl: input.routingApiBaseUrl,
|
|
@@ -4789,7 +4956,7 @@ async function submitYieldseekerSponsoredWithdrawal(input) {
|
|
|
4789
4956
|
return intent.ownerPath === "eoa" ? submitEoa(args) : submitSmart(args);
|
|
4790
4957
|
}
|
|
4791
4958
|
async function submitYieldseekerSponsoredUpgrade(input) {
|
|
4792
|
-
const owner = (0,
|
|
4959
|
+
const owner = (0, import_viem12.getAddress)(input.state.walletAddress);
|
|
4793
4960
|
const { intent, rpcUrl } = await requestIntent({
|
|
4794
4961
|
apiKey: input.apiKey,
|
|
4795
4962
|
routingApiBaseUrl: input.routingApiBaseUrl,
|
|
@@ -4904,6 +5071,7 @@ var YieldseekerAgent = class {
|
|
|
4904
5071
|
receiptClient;
|
|
4905
5072
|
// A client preparation hint only; the routing API still checks live identity.
|
|
4906
5073
|
withdrawalVersionCache = /* @__PURE__ */ new Map();
|
|
5074
|
+
pendingUpgrades = /* @__PURE__ */ new Map();
|
|
4907
5075
|
transactionExecutor;
|
|
4908
5076
|
unwindReceiptWaiter;
|
|
4909
5077
|
agentContexts = /* @__PURE__ */ new Map();
|
|
@@ -4954,8 +5122,8 @@ var YieldseekerAgent = class {
|
|
|
4954
5122
|
if (useCachedV2 && cached && Date.now() - cached.at < 15 * 6e4) return { ...cached.status };
|
|
4955
5123
|
const status = await readYieldseekerWalletStatus(
|
|
4956
5124
|
this.getReceiptClient(),
|
|
4957
|
-
(0,
|
|
4958
|
-
(0,
|
|
5125
|
+
(0, import_viem13.getAddress)(context.wallet.walletAddress),
|
|
5126
|
+
(0, import_viem13.getAddress)(state.walletAddress),
|
|
4959
5127
|
YIELDSEEKER_ASSET_METADATA[asset].address
|
|
4960
5128
|
);
|
|
4961
5129
|
this.rememberWalletStatus(key2, status);
|
|
@@ -4985,12 +5153,12 @@ var YieldseekerAgent = class {
|
|
|
4985
5153
|
const pendingKey2 = `owney.yieldseeker.upgrade:${before.owner.toLowerCase()}:${before.agentWallet.toLowerCase()}`;
|
|
4986
5154
|
const confirmUpgrade = async (hash, receipt2) => {
|
|
4987
5155
|
this.withdrawalVersionCache.delete(versionKey);
|
|
4988
|
-
const upgradeTopic = (0,
|
|
5156
|
+
const upgradeTopic = (0, import_viem13.encodeEventTopics)({ abi: YIELDSEEKER_UPGRADE_ABI, eventName: "Upgraded" })[0];
|
|
4989
5157
|
const lastUpgrade = receipt2?.logs.filter((log) => log.address.toLowerCase() === before.agentWallet.toLowerCase() && log.topics[0] === upgradeTopic).at(-1);
|
|
4990
5158
|
const expectedUpgrade = (() => {
|
|
4991
5159
|
if (!lastUpgrade || lastUpgrade.removed) return false;
|
|
4992
5160
|
try {
|
|
4993
|
-
const event = (0,
|
|
5161
|
+
const event = (0, import_viem13.decodeEventLog)({ abi: YIELDSEEKER_UPGRADE_ABI, eventName: "Upgraded", data: lastUpgrade.data, topics: lastUpgrade.topics });
|
|
4994
5162
|
return event.args.implementation.toLowerCase() === YIELDSEEKER_V2_IMPLEMENTATION.toLowerCase();
|
|
4995
5163
|
} catch {
|
|
4996
5164
|
return false;
|
|
@@ -5019,10 +5187,30 @@ var YieldseekerAgent = class {
|
|
|
5019
5187
|
} catch {
|
|
5020
5188
|
storage5 = void 0;
|
|
5021
5189
|
}
|
|
5022
|
-
const
|
|
5190
|
+
const clearRecordedUpgrade = () => {
|
|
5191
|
+
this.pendingUpgrades.delete(pendingKey2);
|
|
5023
5192
|
try {
|
|
5024
5193
|
storage5?.removeItem(pendingKey2);
|
|
5025
5194
|
} catch {
|
|
5195
|
+
this.pendingUpgrades.set(pendingKey2, null);
|
|
5196
|
+
}
|
|
5197
|
+
};
|
|
5198
|
+
const pendingUpgrade = (hash) => new OwneyError(
|
|
5199
|
+
"WITHDRAW_IN_PROGRESS",
|
|
5200
|
+
"Yieldseeker wallet upgrade is awaiting confirmation. Retry to check its status.",
|
|
5201
|
+
{ txHash: hash, reason: "UPGRADE_CONFIRMATION_PENDING", phase: "observe", safeToFallback: false },
|
|
5202
|
+
this.id
|
|
5203
|
+
);
|
|
5204
|
+
const terminalUpgradeFailure = (error) => error instanceof OwneyError && (error.code === "AGENT_TRANSACTION_REVERTED" || error.details?.reason === "TRANSACTION_REPLACED_WITH_DIFFERENT_CALL");
|
|
5205
|
+
const readUpgradeReceipt = async (hash) => {
|
|
5206
|
+
try {
|
|
5207
|
+
return await this.waitForReceipt(state, chainId, hash);
|
|
5208
|
+
} catch (error) {
|
|
5209
|
+
if (terminalUpgradeFailure(error)) {
|
|
5210
|
+
clearRecordedUpgrade();
|
|
5211
|
+
throw error;
|
|
5212
|
+
}
|
|
5213
|
+
throw pendingUpgrade(hash);
|
|
5026
5214
|
}
|
|
5027
5215
|
};
|
|
5028
5216
|
if (!storage5 && (gasMode === "sponsored" || before.ownerPath === "smart"))
|
|
@@ -5034,7 +5222,7 @@ var YieldseekerAgent = class {
|
|
|
5034
5222
|
);
|
|
5035
5223
|
let prior = null;
|
|
5036
5224
|
try {
|
|
5037
|
-
const saved = storage5?.getItem(pendingKey2);
|
|
5225
|
+
const saved = this.pendingUpgrades.has(pendingKey2) ? JSON.stringify(this.pendingUpgrades.get(pendingKey2)) : storage5?.getItem(pendingKey2);
|
|
5038
5226
|
try {
|
|
5039
5227
|
prior = JSON.parse(saved ?? "null");
|
|
5040
5228
|
} catch {
|
|
@@ -5078,7 +5266,7 @@ var YieldseekerAgent = class {
|
|
|
5078
5266
|
this.id
|
|
5079
5267
|
);
|
|
5080
5268
|
if (Number(callsStatus?.status) === 400 || Number(callsStatus?.status) === 500) {
|
|
5081
|
-
|
|
5269
|
+
clearRecordedUpgrade();
|
|
5082
5270
|
throw new OwneyError(
|
|
5083
5271
|
"SPONSOR_REQUEST_FAILED",
|
|
5084
5272
|
"The earlier sponsored upgrade failed.",
|
|
@@ -5090,8 +5278,8 @@ var YieldseekerAgent = class {
|
|
|
5090
5278
|
earlierHash = hashes.length === 1 ? hashes[0] : void 0;
|
|
5091
5279
|
}
|
|
5092
5280
|
if (earlierHash) {
|
|
5093
|
-
const recovered = await confirmUpgrade(earlierHash, await
|
|
5094
|
-
|
|
5281
|
+
const recovered = await confirmUpgrade(earlierHash, await readUpgradeReceipt(earlierHash));
|
|
5282
|
+
clearRecordedUpgrade();
|
|
5095
5283
|
return recovered;
|
|
5096
5284
|
}
|
|
5097
5285
|
throw new OwneyError(
|
|
@@ -5108,7 +5296,7 @@ var YieldseekerAgent = class {
|
|
|
5108
5296
|
{ version: before.version },
|
|
5109
5297
|
this.id
|
|
5110
5298
|
);
|
|
5111
|
-
const data = (0,
|
|
5299
|
+
const data = (0, import_viem13.encodeFunctionData)({ abi: YIELDSEEKER_UPGRADE_ABI, functionName: "upgradeToLatest" });
|
|
5112
5300
|
let txHash;
|
|
5113
5301
|
let receipt;
|
|
5114
5302
|
if (gasMode === "sponsored") {
|
|
@@ -5135,33 +5323,52 @@ var YieldseekerAgent = class {
|
|
|
5135
5323
|
asset: YIELDSEEKER_ASSET_METADATA[asset].address,
|
|
5136
5324
|
callData: data,
|
|
5137
5325
|
onPending: (pending) => {
|
|
5138
|
-
const current = storage5.getItem(pendingKey2);
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
...pending
|
|
5143
|
-
}));
|
|
5326
|
+
const current = this.pendingUpgrades.has(pendingKey2) ? this.pendingUpgrades.get(pendingKey2) : JSON.parse(storage5.getItem(pendingKey2) ?? "null");
|
|
5327
|
+
const next = { startedAt: Date.now(), ...current, ...pending };
|
|
5328
|
+
storage5.setItem(pendingKey2, JSON.stringify(next));
|
|
5329
|
+
this.pendingUpgrades.delete(pendingKey2);
|
|
5144
5330
|
}
|
|
5145
5331
|
});
|
|
5146
5332
|
txHash = upgraded.txHash;
|
|
5147
5333
|
receipt = upgraded.receipt;
|
|
5148
5334
|
} catch (error) {
|
|
5149
|
-
if (error?.code === 4001 || error instanceof OwneyError && error.code === "SPONSOR_REQUEST_FAILED" && (error.details?.safeToFallback === true || error.details?.executionFailed === true))
|
|
5335
|
+
if (error?.code === 4001 || terminalUpgradeFailure(error) || error instanceof OwneyError && error.code === "SPONSOR_REQUEST_FAILED" && (error.details?.safeToFallback === true || error.details?.executionFailed === true)) clearRecordedUpgrade();
|
|
5150
5336
|
throw error;
|
|
5151
5337
|
}
|
|
5152
5338
|
} else {
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
5339
|
+
let submittedHash;
|
|
5340
|
+
try {
|
|
5341
|
+
txHash = await this.submitTransaction(state, chainId, {
|
|
5342
|
+
from: (0, import_viem13.getAddress)(state.walletAddress),
|
|
5343
|
+
to: before.agentWallet,
|
|
5344
|
+
data,
|
|
5345
|
+
value: "0",
|
|
5346
|
+
chainId
|
|
5347
|
+
}, (hash) => {
|
|
5348
|
+
submittedHash = hash;
|
|
5349
|
+
const pending = { txHash: hash };
|
|
5350
|
+
this.pendingUpgrades.set(pendingKey2, pending);
|
|
5351
|
+
try {
|
|
5352
|
+
if (storage5) {
|
|
5353
|
+
storage5.setItem(pendingKey2, JSON.stringify(pending));
|
|
5354
|
+
this.pendingUpgrades.delete(pendingKey2);
|
|
5355
|
+
}
|
|
5356
|
+
} catch {
|
|
5357
|
+
}
|
|
5358
|
+
}, (value) => {
|
|
5359
|
+
receipt = value;
|
|
5360
|
+
});
|
|
5361
|
+
} catch (error) {
|
|
5362
|
+
if (terminalUpgradeFailure(error)) {
|
|
5363
|
+
clearRecordedUpgrade();
|
|
5364
|
+
throw error;
|
|
5365
|
+
}
|
|
5366
|
+
if (submittedHash) throw pendingUpgrade(submittedHash);
|
|
5367
|
+
throw error;
|
|
5368
|
+
}
|
|
5162
5369
|
}
|
|
5163
|
-
const confirmed = await confirmUpgrade(txHash, receipt ?? await
|
|
5164
|
-
|
|
5370
|
+
const confirmed = await confirmUpgrade(txHash, receipt ?? await readUpgradeReceipt(txHash));
|
|
5371
|
+
clearRecordedUpgrade();
|
|
5165
5372
|
return confirmed;
|
|
5166
5373
|
}
|
|
5167
5374
|
async disconnect() {
|
|
@@ -5193,7 +5400,7 @@ var YieldseekerAgent = class {
|
|
|
5193
5400
|
this.assertAsset(targetAsset);
|
|
5194
5401
|
await this.ensureAgent(state, chainId, targetAsset);
|
|
5195
5402
|
}
|
|
5196
|
-
async deposit(state, chainId, amount, asset, depositCallback, onProgress) {
|
|
5403
|
+
async deposit(state, chainId, amount, asset, depositCallback, onProgress, onBeforeSubmission) {
|
|
5197
5404
|
this.assertChain(chainId);
|
|
5198
5405
|
this.assertAsset(asset);
|
|
5199
5406
|
if (BigInt(amount) <= 0n) {
|
|
@@ -5238,18 +5445,28 @@ var YieldseekerAgent = class {
|
|
|
5238
5445
|
} else {
|
|
5239
5446
|
try {
|
|
5240
5447
|
txHash = await this.submitTransaction(state, chainId, {
|
|
5241
|
-
from: (0,
|
|
5448
|
+
from: (0, import_viem13.getAddress)(state.walletAddress),
|
|
5242
5449
|
to: YIELDSEEKER_ASSET_METADATA[asset].address,
|
|
5243
|
-
data: (0,
|
|
5244
|
-
abi:
|
|
5450
|
+
data: (0, import_viem13.encodeFunctionData)({
|
|
5451
|
+
abi: import_viem13.erc20Abi,
|
|
5245
5452
|
functionName: "transfer",
|
|
5246
|
-
args: [(0,
|
|
5453
|
+
args: [(0, import_viem13.getAddress)(context.wallet.walletAddress), BigInt(amount)]
|
|
5247
5454
|
}),
|
|
5248
5455
|
value: "0",
|
|
5249
5456
|
chainId
|
|
5250
5457
|
}, submitted, (value) => {
|
|
5251
5458
|
receipt = value;
|
|
5252
|
-
})
|
|
5459
|
+
}, onBeforeSubmission ? () => onBeforeSubmission({
|
|
5460
|
+
agentId: this.id,
|
|
5461
|
+
chainId,
|
|
5462
|
+
token: asset,
|
|
5463
|
+
walletAddress: state.walletAddress,
|
|
5464
|
+
agentWallet: context.wallet.walletAddress,
|
|
5465
|
+
intendedAmount: amount,
|
|
5466
|
+
transfer: "pending",
|
|
5467
|
+
registration: "not-applicable",
|
|
5468
|
+
delivery: "not-applicable"
|
|
5469
|
+
}) : void 0);
|
|
5253
5470
|
} catch (error) {
|
|
5254
5471
|
if (error instanceof OwneyError && error.details?.ownerTransferNotExecuted === true && error.details.reason === "TRANSACTION_REPLACED_WITH_DIFFERENT_CALL") {
|
|
5255
5472
|
notifyFunding(onProgress, {
|
|
@@ -5377,7 +5594,7 @@ var YieldseekerAgent = class {
|
|
|
5377
5594
|
);
|
|
5378
5595
|
const positionsRead = this.readWithdrawalPositions(state, chainId, context);
|
|
5379
5596
|
const metadata = YIELDSEEKER_ASSET_METADATA[asset];
|
|
5380
|
-
const agentWallet = (0,
|
|
5597
|
+
const agentWallet = (0, import_viem13.getAddress)(context.wallet.walletAddress);
|
|
5381
5598
|
const readOwnerFunds = async (blockNumber) => {
|
|
5382
5599
|
const feeTracker = await withPaidRpcDiagnostics(() => this.getReceiptClient().readContract({
|
|
5383
5600
|
address: agentWallet,
|
|
@@ -5386,18 +5603,18 @@ var YieldseekerAgent = class {
|
|
|
5386
5603
|
blockNumber
|
|
5387
5604
|
}), chainId, "eth_call", this.id);
|
|
5388
5605
|
this.assertSession(generation, chainId, asset);
|
|
5389
|
-
if (!(0,
|
|
5606
|
+
if (!(0, import_viem13.isAddress)(feeTracker) || /^0x0{40}$/i.test(feeTracker))
|
|
5390
5607
|
throw this.invalidResponse("wallet fee tracker");
|
|
5391
5608
|
const [idle2, fees] = await Promise.all([
|
|
5392
5609
|
withPaidRpcDiagnostics(() => this.getReceiptClient().readContract({
|
|
5393
5610
|
address: metadata.address,
|
|
5394
|
-
abi:
|
|
5611
|
+
abi: import_viem13.erc20Abi,
|
|
5395
5612
|
functionName: "balanceOf",
|
|
5396
5613
|
args: [agentWallet],
|
|
5397
5614
|
blockNumber
|
|
5398
5615
|
}), chainId, "eth_call", this.id),
|
|
5399
5616
|
withPaidRpcDiagnostics(() => this.getReceiptClient().readContract({
|
|
5400
|
-
address: (0,
|
|
5617
|
+
address: (0, import_viem13.getAddress)(feeTracker),
|
|
5401
5618
|
abi: YIELDSEEKER_FEE_TRACKER_ABI,
|
|
5402
5619
|
functionName: "getFeesOwed",
|
|
5403
5620
|
args: [agentWallet],
|
|
@@ -5439,13 +5656,13 @@ var YieldseekerAgent = class {
|
|
|
5439
5656
|
let active = true;
|
|
5440
5657
|
const checks = this.readVaultLiquidity(values.map((position2) => position2.yieldOption), agentWallet, blockNumber).catch(() => []);
|
|
5441
5658
|
const reads = values.map(async (position2, index) => {
|
|
5442
|
-
const address = (0,
|
|
5659
|
+
const address = (0, import_viem13.getAddress)(position2.yieldOption.address);
|
|
5443
5660
|
try {
|
|
5444
5661
|
const group = (await checks).slice(index * 3, index * 3 + 3);
|
|
5445
5662
|
if (!active || group.length !== 3 || group.some((value) => value.status !== "success")) return null;
|
|
5446
5663
|
this.assertSession(generation, chainId, asset);
|
|
5447
5664
|
const [underlying, shares, withdrawable] = group.map((value) => value.result);
|
|
5448
|
-
if (typeof underlying !== "string" || !(0,
|
|
5665
|
+
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
5666
|
const verified = { ...position2, assetsRaw: shares.toString(), withdrawableAssetsRaw: withdrawable.toString() };
|
|
5450
5667
|
if (shares > 0n && withdrawable === 0n) {
|
|
5451
5668
|
let positiveValue = false;
|
|
@@ -5453,7 +5670,7 @@ var YieldseekerAgent = class {
|
|
|
5453
5670
|
try {
|
|
5454
5671
|
const value = await this.getReceiptClient().readContract({
|
|
5455
5672
|
address,
|
|
5456
|
-
abi:
|
|
5673
|
+
abi: import_viem13.erc4626Abi,
|
|
5457
5674
|
functionName,
|
|
5458
5675
|
args: [shares],
|
|
5459
5676
|
blockNumber
|
|
@@ -5543,6 +5760,18 @@ var YieldseekerAgent = class {
|
|
|
5543
5760
|
);
|
|
5544
5761
|
}
|
|
5545
5762
|
if (requested > totalAvailable) {
|
|
5763
|
+
if (!funds.complete)
|
|
5764
|
+
throw new OwneyError(
|
|
5765
|
+
"WITHDRAW_BALANCE_UNAVAILABLE",
|
|
5766
|
+
"Yieldseeker withdrawal liquidity could not be verified for the requested amount.",
|
|
5767
|
+
{
|
|
5768
|
+
asset,
|
|
5769
|
+
requested: requested.toString(),
|
|
5770
|
+
verifiedAvailable: totalAvailable.toString(),
|
|
5771
|
+
reason: "YIELDSEEKER_LIQUIDITY_UNVERIFIED"
|
|
5772
|
+
},
|
|
5773
|
+
this.id
|
|
5774
|
+
);
|
|
5546
5775
|
throw new OwneyError(
|
|
5547
5776
|
"WITHDRAW_INSUFFICIENT_BALANCE",
|
|
5548
5777
|
`Requested withdrawal "${requested}" exceeds available Yieldseeker balance "${totalAvailable}" for asset "${asset}".`,
|
|
@@ -5557,6 +5786,7 @@ var YieldseekerAgent = class {
|
|
|
5557
5786
|
const requiredIdle = requested + initialFunds.fees;
|
|
5558
5787
|
let remaining = requiredIdle > idle ? requiredIdle - idle : 0n;
|
|
5559
5788
|
let grossUnwound = 0n;
|
|
5789
|
+
let confirmedUnwinds = 0n;
|
|
5560
5790
|
let latestUnwindBlock;
|
|
5561
5791
|
const unwind = async (position2, assetsRaw) => {
|
|
5562
5792
|
this.assertSession(generation, chainId, asset);
|
|
@@ -5574,7 +5804,10 @@ var YieldseekerAgent = class {
|
|
|
5574
5804
|
if (!this.isTransactionHash(response?.transactionHash)) throw this.invalidResponse("position withdrawal");
|
|
5575
5805
|
unwindTransactionHash = response.transactionHash;
|
|
5576
5806
|
const unwindReceipt = await this.waitForReceipt(state, chainId, unwindTransactionHash);
|
|
5577
|
-
if (unwindReceipt)
|
|
5807
|
+
if (unwindReceipt) {
|
|
5808
|
+
latestUnwindBlock = unwindReceipt.blockNumber;
|
|
5809
|
+
confirmedUnwinds++;
|
|
5810
|
+
}
|
|
5578
5811
|
} catch (error) {
|
|
5579
5812
|
this.invalidateFundingRead(state, chainId, asset);
|
|
5580
5813
|
throw new OwneyError(
|
|
@@ -5644,7 +5877,7 @@ var YieldseekerAgent = class {
|
|
|
5644
5877
|
const feeRate = feeRateBps ?? 0;
|
|
5645
5878
|
const maxFee = confirmedMovement && Number.isInteger(feeRate) && feeRate >= 0 && feeRate <= 1e3 ? (grossUnwound * BigInt(feeRate) + 9999n) / 10000n : 0n;
|
|
5646
5879
|
const shortfall = availableForOwner < requested ? requested - availableForOwner : 0n;
|
|
5647
|
-
if (availableForOwner === 0n || amount !== void 0 && shortfall > maxFee) {
|
|
5880
|
+
if (availableForOwner === 0n || amount !== void 0 && shortfall > maxFee + confirmedUnwinds) {
|
|
5648
5881
|
this.invalidateFundingRead(state, chainId, asset);
|
|
5649
5882
|
if (amount === void 0 && positionsStatus !== "empty")
|
|
5650
5883
|
throw new OwneyError(
|
|
@@ -5666,14 +5899,15 @@ var YieldseekerAgent = class {
|
|
|
5666
5899
|
delta: maxSettlementBasis.delta - payout,
|
|
5667
5900
|
expectedNetDeposits: maxSettlementBasis.expectedNetDeposits - payout
|
|
5668
5901
|
} : this.snapshotMovement(state, chainId, context, -payout);
|
|
5669
|
-
const account = (0,
|
|
5902
|
+
const account = (0, import_viem13.getAddress)(state.walletAddress);
|
|
5670
5903
|
let receipt;
|
|
5671
|
-
const base6 = { agentId: this.id, chainId, token: asset, walletAddress: state.walletAddress, agentWallet: context.wallet.walletAddress, intendedAmount: amount
|
|
5672
|
-
|
|
5904
|
+
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" };
|
|
5905
|
+
let submissionEvidence = base6;
|
|
5906
|
+
const data = amount === void 0 ? (0, import_viem13.encodeFunctionData)({
|
|
5673
5907
|
abi: YIELDSEEKER_AGENT_WALLET_ABI,
|
|
5674
5908
|
functionName: "withdrawAllAssetToUser",
|
|
5675
5909
|
args: [account, metadata.address]
|
|
5676
|
-
}) : (0,
|
|
5910
|
+
}) : (0, import_viem13.encodeFunctionData)({
|
|
5677
5911
|
abi: YIELDSEEKER_AGENT_WALLET_ABI,
|
|
5678
5912
|
functionName: "withdrawAssetToUser",
|
|
5679
5913
|
args: [account, metadata.address, payout]
|
|
@@ -5689,10 +5923,13 @@ var YieldseekerAgent = class {
|
|
|
5689
5923
|
refreshYieldseekerSignature: (rejected) => this.auth.refreshToken(state, chainId, rejected),
|
|
5690
5924
|
userId: context.user.userId,
|
|
5691
5925
|
agentId: context.agent.agentId,
|
|
5692
|
-
agentWallet: (0,
|
|
5926
|
+
agentWallet: (0, import_viem13.getAddress)(context.wallet.walletAddress),
|
|
5693
5927
|
asset: metadata.address,
|
|
5694
5928
|
callData: data,
|
|
5695
|
-
onPending: (pending) =>
|
|
5929
|
+
onPending: (pending) => {
|
|
5930
|
+
submissionEvidence = { ...submissionEvidence, ...pending };
|
|
5931
|
+
notifyFunding(onProgress, submissionEvidence);
|
|
5932
|
+
},
|
|
5696
5933
|
onBeforeSubmission: async (pending) => {
|
|
5697
5934
|
await onBeforeSubmission?.({ ...base6, ...pending });
|
|
5698
5935
|
onOwnerTransferAttempted?.();
|
|
@@ -5704,7 +5941,7 @@ var YieldseekerAgent = class {
|
|
|
5704
5941
|
onOwnerTransferAttempted?.();
|
|
5705
5942
|
txHash = await this.submitTransaction(state, chainId, {
|
|
5706
5943
|
from: account,
|
|
5707
|
-
to: (0,
|
|
5944
|
+
to: (0, import_viem13.getAddress)(context.wallet.walletAddress),
|
|
5708
5945
|
data,
|
|
5709
5946
|
value: "0",
|
|
5710
5947
|
chainId
|
|
@@ -5712,10 +5949,20 @@ var YieldseekerAgent = class {
|
|
|
5712
5949
|
receipt = value;
|
|
5713
5950
|
});
|
|
5714
5951
|
}
|
|
5715
|
-
|
|
5716
|
-
settlement = plannedMovement;
|
|
5717
|
-
const evidence = receipt ? inspectFundingReceipt(receipt, { ...base6, txHash }, metadata.address, "withdraw") : { ...base6, txHash, confirmedAmount: payout.toString(), transfer: "confirmed", delivery: "confirmed" };
|
|
5952
|
+
const evidence = receipt ? inspectFundingReceipt(receipt, { ...submissionEvidence, txHash }, metadata.address, "withdraw") : { ...submissionEvidence, txHash, transfer: "pending", delivery: "pending" };
|
|
5718
5953
|
notifyFunding(onProgress, evidence);
|
|
5954
|
+
const explicitEmptyPayout = evidence.transfer === "failed" && evidence.confirmedAmount === "0" && evidence.transferLogs?.some((log) => log.amountRaw === "0");
|
|
5955
|
+
if (evidence.transfer === "failed" && !explicitEmptyPayout)
|
|
5956
|
+
throw new OwneyError(
|
|
5957
|
+
"AGENT_TRANSACTION_REVERTED",
|
|
5958
|
+
"The Yieldseeker withdrawal completed without transferring funds.",
|
|
5959
|
+
{ asset, available: "0", txHash },
|
|
5960
|
+
this.id
|
|
5961
|
+
);
|
|
5962
|
+
if (!explicitEmptyPayout && (evidence.transfer !== "confirmed" || evidence.delivery !== "confirmed" || !evidence.confirmedAmount))
|
|
5963
|
+
return { txHash, type: "partial", completion: "unverified", amount: "0", evidence };
|
|
5964
|
+
confirmedMovement = true;
|
|
5965
|
+
settlement = evidence.confirmedAmount === payout.toString() ? plannedMovement : null;
|
|
5719
5966
|
let completion = maxLiquidity && !maxLiquidity.complete ? "unverified" : void 0;
|
|
5720
5967
|
if (amount === void 0) {
|
|
5721
5968
|
const verificationDeadline = Date.now() + YIELDSEEKER_MAX_POSITION_VERIFICATION_MS;
|
|
@@ -5736,7 +5983,7 @@ var YieldseekerAgent = class {
|
|
|
5736
5983
|
positions = proof.positions;
|
|
5737
5984
|
positionsStatus = hasPositions(positions) ? "remaining" : proof.verified ? "empty" : "unavailable";
|
|
5738
5985
|
if (positionsStatus === "remaining") {
|
|
5739
|
-
const result = { txHash, type: "partial", amount: evidence.confirmedAmount ??
|
|
5986
|
+
const result = { txHash, type: "partial", amount: evidence.confirmedAmount ?? "0", evidence };
|
|
5740
5987
|
throw new OwneyError(
|
|
5741
5988
|
"WITHDRAW_PARTIAL_FAILURE",
|
|
5742
5989
|
"Yieldseeker MAX could not confirm that all vault positions were cleared.",
|
|
@@ -5756,7 +6003,7 @@ var YieldseekerAgent = class {
|
|
|
5756
6003
|
}
|
|
5757
6004
|
if (!proof.verified) completion = "unverified";
|
|
5758
6005
|
}
|
|
5759
|
-
if (
|
|
6006
|
+
if (explicitEmptyPayout)
|
|
5760
6007
|
throw new OwneyError(
|
|
5761
6008
|
"WITHDRAW_INSUFFICIENT_BALANCE",
|
|
5762
6009
|
"The Yieldseeker withdrawal completed without transferring funds.",
|
|
@@ -5771,7 +6018,7 @@ var YieldseekerAgent = class {
|
|
|
5771
6018
|
type: amount === void 0 && !completion ? "full" : "partial",
|
|
5772
6019
|
...completion ? { completion } : {},
|
|
5773
6020
|
...feeAdjustment ? { feeAdjustment } : {},
|
|
5774
|
-
amount: evidence.confirmedAmount ??
|
|
6021
|
+
amount: evidence.confirmedAmount ?? "0",
|
|
5775
6022
|
evidence
|
|
5776
6023
|
};
|
|
5777
6024
|
} finally {
|
|
@@ -5812,17 +6059,17 @@ var YieldseekerAgent = class {
|
|
|
5812
6059
|
return proof.available;
|
|
5813
6060
|
}
|
|
5814
6061
|
async readVaultLiquidity(options, wallet, blockNumber) {
|
|
5815
|
-
const owner = (0,
|
|
6062
|
+
const owner = (0, import_viem13.getAddress)(wallet);
|
|
5816
6063
|
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
6064
|
const results = await Promise.all(batches.map((batch) => this.getReceiptClient().multicall({
|
|
5818
6065
|
blockNumber,
|
|
5819
6066
|
allowFailure: true,
|
|
5820
6067
|
contracts: batch.flatMap((option) => {
|
|
5821
|
-
const address = (0,
|
|
6068
|
+
const address = (0, import_viem13.getAddress)(option.address);
|
|
5822
6069
|
return [
|
|
5823
|
-
{ address, abi:
|
|
5824
|
-
{ address, abi:
|
|
5825
|
-
{ address, abi:
|
|
6070
|
+
{ address, abi: import_viem13.erc4626Abi, functionName: "asset" },
|
|
6071
|
+
{ address, abi: import_viem13.erc20Abi, functionName: "balanceOf", args: [owner] },
|
|
6072
|
+
{ address, abi: import_viem13.erc4626Abi, functionName: "maxWithdraw", args: [owner] }
|
|
5826
6073
|
];
|
|
5827
6074
|
})
|
|
5828
6075
|
})));
|
|
@@ -5833,7 +6080,7 @@ var YieldseekerAgent = class {
|
|
|
5833
6080
|
const seen = /* @__PURE__ */ new Set();
|
|
5834
6081
|
for (const value of values) {
|
|
5835
6082
|
const option = value?.yieldOption;
|
|
5836
|
-
if (!option || typeof option.address !== "string" || !(0,
|
|
6083
|
+
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
6084
|
throw this.invalidResponse("yield positions");
|
|
5838
6085
|
seen.add(option.address.toLowerCase());
|
|
5839
6086
|
}
|
|
@@ -5846,7 +6093,7 @@ var YieldseekerAgent = class {
|
|
|
5846
6093
|
const historic = this.readCache.get(`historic:${key2}`)?.value?.position;
|
|
5847
6094
|
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
6095
|
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,
|
|
6096
|
+
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
6097
|
hints.set(option.address.toLowerCase(), {
|
|
5851
6098
|
yieldOption: option,
|
|
5852
6099
|
assetsRaw: "0",
|
|
@@ -5898,7 +6145,7 @@ var YieldseekerAgent = class {
|
|
|
5898
6145
|
const read2 = async () => {
|
|
5899
6146
|
const client = this.getReceiptClient();
|
|
5900
6147
|
const blockNumber = await client.getBlockNumber({ cacheTime: 0 });
|
|
5901
|
-
const wallet = (0,
|
|
6148
|
+
const wallet = (0, import_viem13.getAddress)(context.wallet.walletAddress);
|
|
5902
6149
|
assertReadCurrent();
|
|
5903
6150
|
if (typeof blockNumber !== "bigint") throw unavailable();
|
|
5904
6151
|
const indexedPositions = this.validateWithdrawalPositions(positions ?? [], chainId, context.asset);
|
|
@@ -5908,11 +6155,11 @@ var YieldseekerAgent = class {
|
|
|
5908
6155
|
for (const position2 of indexedPositions) candidates.set(position2.yieldOption.address.toLowerCase(), position2.yieldOption);
|
|
5909
6156
|
const options = [...candidates.values()];
|
|
5910
6157
|
if (options.length > YIELDSEEKER_WITHDRAWAL_CANDIDATE_LIMIT) throw unavailable();
|
|
5911
|
-
const
|
|
5912
|
-
|
|
6158
|
+
const checksRead = this.readVaultLiquidity(options, wallet, blockNumber).then((value) => ({ value }), (error) => ({ error }));
|
|
6159
|
+
const [idle, feeTracker] = await Promise.all([
|
|
5913
6160
|
client.readContract({
|
|
5914
6161
|
address: metadata.address,
|
|
5915
|
-
abi:
|
|
6162
|
+
abi: import_viem13.erc20Abi,
|
|
5916
6163
|
functionName: "balanceOf",
|
|
5917
6164
|
args: [wallet],
|
|
5918
6165
|
blockNumber
|
|
@@ -5924,10 +6171,10 @@ var YieldseekerAgent = class {
|
|
|
5924
6171
|
blockNumber
|
|
5925
6172
|
})
|
|
5926
6173
|
]);
|
|
5927
|
-
if (typeof idle !== "bigint" || idle < 0n || !(0,
|
|
6174
|
+
if (typeof idle !== "bigint" || idle < 0n || !(0, import_viem13.isAddress)(feeTracker) || /^0x0{40}$/i.test(feeTracker)) throw unavailable();
|
|
5928
6175
|
assertReadCurrent();
|
|
5929
6176
|
const fees = await client.readContract({
|
|
5930
|
-
address: (0,
|
|
6177
|
+
address: (0, import_viem13.getAddress)(feeTracker),
|
|
5931
6178
|
abi: YIELDSEEKER_FEE_TRACKER_ABI,
|
|
5932
6179
|
functionName: "getFeesOwed",
|
|
5933
6180
|
args: [wallet],
|
|
@@ -5937,6 +6184,18 @@ var YieldseekerAgent = class {
|
|
|
5937
6184
|
const verified = [];
|
|
5938
6185
|
const verifiedVaults = [];
|
|
5939
6186
|
let deployed = 0n;
|
|
6187
|
+
const proof = (complete) => ({
|
|
6188
|
+
blockNumber,
|
|
6189
|
+
idle,
|
|
6190
|
+
fees,
|
|
6191
|
+
available: idle + deployed > fees ? idle + deployed - fees : 0n,
|
|
6192
|
+
positions: [...verified],
|
|
6193
|
+
verifiedVaults: [...verifiedVaults],
|
|
6194
|
+
indexedPositions,
|
|
6195
|
+
complete
|
|
6196
|
+
});
|
|
6197
|
+
assertReadCurrent();
|
|
6198
|
+
knownProof = proof(false);
|
|
5940
6199
|
const collect = (options2, results) => {
|
|
5941
6200
|
assertReadCurrent();
|
|
5942
6201
|
const known = this.balanceVaults.get(contextKey) ?? /* @__PURE__ */ new Set();
|
|
@@ -5952,7 +6211,7 @@ var YieldseekerAgent = class {
|
|
|
5952
6211
|
return;
|
|
5953
6212
|
}
|
|
5954
6213
|
const [underlying, shares, withdrawable] = group.map((value) => value.result);
|
|
5955
|
-
if (typeof underlying !== "string" || !(0,
|
|
6214
|
+
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
6215
|
valid2 = false;
|
|
5957
6216
|
return;
|
|
5958
6217
|
}
|
|
@@ -5969,17 +6228,10 @@ var YieldseekerAgent = class {
|
|
|
5969
6228
|
});
|
|
5970
6229
|
return valid2;
|
|
5971
6230
|
};
|
|
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
|
-
});
|
|
6231
|
+
const checks = await checksRead;
|
|
6232
|
+
assertReadCurrent();
|
|
6233
|
+
if ("error" in checks) throw checks.error;
|
|
6234
|
+
const allKnownVerified = collect(options, checks.value);
|
|
5983
6235
|
knownProof = proof(false);
|
|
5984
6236
|
const indexed = new Map(indexedPositions.map((position2) => [position2.yieldOption.address.toLowerCase(), position2]));
|
|
5985
6237
|
const discrepancy = verified.some((position2) => {
|
|
@@ -5996,7 +6248,7 @@ var YieldseekerAgent = class {
|
|
|
5996
6248
|
assertReadCurrent();
|
|
5997
6249
|
const eligible = /* @__PURE__ */ new Map();
|
|
5998
6250
|
for (const option of catalog ?? []) {
|
|
5999
|
-
if (option?.chainId === chainId && typeof option.assetAddress === "string" && option.assetAddress.toLowerCase() === metadata.address.toLowerCase() && (0,
|
|
6251
|
+
if (option?.chainId === chainId && typeof option.assetAddress === "string" && option.assetAddress.toLowerCase() === metadata.address.toLowerCase() && (0, import_viem13.isAddress)(option.address))
|
|
6000
6252
|
eligible.set(option.address.toLowerCase(), option);
|
|
6001
6253
|
}
|
|
6002
6254
|
const extra = [...eligible].filter(([address]) => !candidates.has(address)).map(([, option]) => option);
|
|
@@ -6047,7 +6299,7 @@ var YieldseekerAgent = class {
|
|
|
6047
6299
|
const key2 = this.contextKey(state, evidence.chainId, evidence.token);
|
|
6048
6300
|
const generation = this.readGeneration, version = this.portfolioVersion(key2);
|
|
6049
6301
|
if (read2.readVersion !== version) return void 0;
|
|
6050
|
-
const wallet = (0,
|
|
6302
|
+
const wallet = (0, import_viem13.getAddress)(context.wallet.walletAddress);
|
|
6051
6303
|
const asset = YIELDSEEKER_ASSET_METADATA[evidence.token];
|
|
6052
6304
|
const client = this.getReceiptClient();
|
|
6053
6305
|
const blockNumber = await client.getBlockNumber({ cacheTime: 0 });
|
|
@@ -6055,10 +6307,10 @@ var YieldseekerAgent = class {
|
|
|
6055
6307
|
const vaults = [...this.balanceVaults.get(key2) ?? []];
|
|
6056
6308
|
const [invested, idle, tracker] = await Promise.all([
|
|
6057
6309
|
remainingVaultBalance(client, wallet, asset.address, vaults, blockNumber),
|
|
6058
|
-
client.readContract({ address: asset.address, abi:
|
|
6310
|
+
client.readContract({ address: asset.address, abi: import_viem13.erc20Abi, functionName: "balanceOf", args: [wallet], blockNumber }),
|
|
6059
6311
|
client.readContract({ address: wallet, abi: YIELDSEEKER_AGENT_WALLET_ABI, functionName: "feeTracker", blockNumber })
|
|
6060
6312
|
]);
|
|
6061
|
-
if (invested === void 0 || typeof idle !== "bigint" || idle < 0n || !(0,
|
|
6313
|
+
if (invested === void 0 || typeof idle !== "bigint" || idle < 0n || !(0, import_viem13.isAddress)(tracker) || /^0x0{40}$/i.test(tracker)) return void 0;
|
|
6062
6314
|
const fees = await client.readContract({
|
|
6063
6315
|
address: tracker,
|
|
6064
6316
|
abi: YIELDSEEKER_FEE_TRACKER_ABI,
|
|
@@ -6071,7 +6323,7 @@ var YieldseekerAgent = class {
|
|
|
6071
6323
|
const total = idle + invested > fees ? idle + invested - fees : 0n;
|
|
6072
6324
|
const displayed = balance.assetBalances?.find((item) => item.chainId === evidence.chainId && item.asset === evidence.token);
|
|
6073
6325
|
if (!displayed || !evidence.confirmedAmount || !/^\d+$/.test(evidence.confirmedAmount)) return void 0;
|
|
6074
|
-
const amount = (0,
|
|
6326
|
+
const amount = (0, import_viem13.parseUnits)(displayed.amount, asset.decimals);
|
|
6075
6327
|
if (amount < 0n) return void 0;
|
|
6076
6328
|
const displayUnit = evidence.token === "USDC" ? 5000n : 500000000000n;
|
|
6077
6329
|
const movementUnit = BigInt(evidence.confirmedAmount) / 1000n;
|
|
@@ -6117,9 +6369,9 @@ var YieldseekerAgent = class {
|
|
|
6117
6369
|
if (!context) return void 0;
|
|
6118
6370
|
const idle = await withPaidRpcDiagnostics(() => this.getReceiptClient().readContract({
|
|
6119
6371
|
address: YIELDSEEKER_ASSET_METADATA[asset].address,
|
|
6120
|
-
abi:
|
|
6372
|
+
abi: import_viem13.erc20Abi,
|
|
6121
6373
|
functionName: "balanceOf",
|
|
6122
|
-
args: [(0,
|
|
6374
|
+
args: [(0, import_viem13.getAddress)(context.wallet.walletAddress)]
|
|
6123
6375
|
}), chainId, "eth_call", this.id);
|
|
6124
6376
|
this.assertSession(generation, chainId, asset);
|
|
6125
6377
|
if (typeof idle !== "bigint" || idle < 0n) throw this.invalidResponse("wallet deposit balance");
|
|
@@ -6127,7 +6379,7 @@ var YieldseekerAgent = class {
|
|
|
6127
6379
|
}
|
|
6128
6380
|
async getEarnings(state, chainId) {
|
|
6129
6381
|
this.assertChain(chainId);
|
|
6130
|
-
return mapYieldseekerEarnings(await this.loadPortfolio(state, chainId, {}));
|
|
6382
|
+
return mapYieldseekerEarnings(await this.loadPortfolio(state, chainId, { includePositions: false }));
|
|
6131
6383
|
}
|
|
6132
6384
|
async getAccountApy(state, chainId, days, tokenSymbol) {
|
|
6133
6385
|
this.assertChain(chainId);
|
|
@@ -6166,7 +6418,7 @@ var YieldseekerAgent = class {
|
|
|
6166
6418
|
);
|
|
6167
6419
|
const vaultAddresses = new Set(
|
|
6168
6420
|
catalog.flat().filter(
|
|
6169
|
-
(yieldOption) => yieldOption.chainId === chainId && (0,
|
|
6421
|
+
(yieldOption) => yieldOption.chainId === chainId && (0, import_viem13.isAddress)(yieldOption.address)
|
|
6170
6422
|
).map((yieldOption) => yieldOption.address.toLowerCase())
|
|
6171
6423
|
);
|
|
6172
6424
|
return mapYieldseekerHistory(contexts, {
|
|
@@ -6295,7 +6547,7 @@ var YieldseekerAgent = class {
|
|
|
6295
6547
|
`/users/${user.userId}/agents/${agent.agentId}/wallet`
|
|
6296
6548
|
).then((walletResponse) => {
|
|
6297
6549
|
this.assertSession(generation, chainId, asset);
|
|
6298
|
-
if (!walletResponse?.agentWallet || !(0,
|
|
6550
|
+
if (!walletResponse?.agentWallet || !(0, import_viem13.isAddress)(walletResponse.agentWallet.walletAddress)) {
|
|
6299
6551
|
throw this.invalidResponse("agent wallet");
|
|
6300
6552
|
}
|
|
6301
6553
|
const context = {
|
|
@@ -6325,7 +6577,7 @@ var YieldseekerAgent = class {
|
|
|
6325
6577
|
this.users.set(key2, persisted);
|
|
6326
6578
|
return persisted;
|
|
6327
6579
|
}
|
|
6328
|
-
const walletAddress = (0,
|
|
6580
|
+
const walletAddress = (0, import_viem13.getAddress)(state.walletAddress);
|
|
6329
6581
|
const generation = this.readGeneration;
|
|
6330
6582
|
let user = null;
|
|
6331
6583
|
try {
|
|
@@ -6709,7 +6961,7 @@ var YieldseekerAgent = class {
|
|
|
6709
6961
|
this.agentPath(context, "deploy"),
|
|
6710
6962
|
{ method: "POST", body: {} }
|
|
6711
6963
|
);
|
|
6712
|
-
if (!deployed?.agentWallet || !(0,
|
|
6964
|
+
if (!deployed?.agentWallet || !(0, import_viem13.isAddress)(deployed.agentWallet.walletAddress) || deployed.agentWallet.walletAddress.toLowerCase() !== walletAddress) {
|
|
6713
6965
|
throw this.invalidResponse("agent deployment", {
|
|
6714
6966
|
reason: "Deploy did not return the expected Agent Wallet."
|
|
6715
6967
|
});
|
|
@@ -6810,22 +7062,26 @@ var YieldseekerAgent = class {
|
|
|
6810
7062
|
this.id
|
|
6811
7063
|
);
|
|
6812
7064
|
}
|
|
6813
|
-
async submitTransaction(state, chainId, transaction, onSubmitted, onReceipt) {
|
|
7065
|
+
async submitTransaction(state, chainId, transaction, onSubmitted, onReceipt, onBeforeSubmission) {
|
|
6814
7066
|
if (this.transactionExecutor) {
|
|
6815
|
-
|
|
7067
|
+
await onBeforeSubmission?.();
|
|
7068
|
+
const hash2 = await this.transactionExecutor(state, chainId, transaction, onReceipt);
|
|
6816
7069
|
onSubmitted?.(hash2);
|
|
6817
7070
|
return hash2;
|
|
6818
7071
|
}
|
|
6819
7072
|
this.assertTransaction(transaction, state, chainId);
|
|
6820
|
-
const account = (0,
|
|
6821
|
-
const walletClient = (0,
|
|
7073
|
+
const account = (0, import_viem13.getAddress)(state.walletAddress);
|
|
7074
|
+
const walletClient = (0, import_viem13.createWalletClient)({
|
|
6822
7075
|
account,
|
|
6823
7076
|
chain: import_chains4.base,
|
|
6824
|
-
transport: (0,
|
|
7077
|
+
transport: onBeforeSubmission ? (0, import_viem13.custom)({ request: async (args) => {
|
|
7078
|
+
if (args.method === "eth_sendTransaction") await onBeforeSubmission();
|
|
7079
|
+
return state.provider.request(args);
|
|
7080
|
+
} }, { retryCount: 0 }) : (0, import_viem13.custom)(state.provider)
|
|
6825
7081
|
});
|
|
6826
|
-
const walletChainClient = (0,
|
|
7082
|
+
const walletChainClient = (0, import_viem13.createPublicClient)({
|
|
6827
7083
|
chain: import_chains4.base,
|
|
6828
|
-
transport: (0,
|
|
7084
|
+
transport: (0, import_viem13.custom)(state.provider)
|
|
6829
7085
|
});
|
|
6830
7086
|
await ensureWalletOnChain(
|
|
6831
7087
|
walletChainClient,
|
|
@@ -6835,7 +7091,7 @@ var YieldseekerAgent = class {
|
|
|
6835
7091
|
const hash = await walletClient.sendTransaction({
|
|
6836
7092
|
account,
|
|
6837
7093
|
chain: import_chains4.base,
|
|
6838
|
-
to: (0,
|
|
7094
|
+
to: (0, import_viem13.getAddress)(transaction.to),
|
|
6839
7095
|
data: transaction.data,
|
|
6840
7096
|
value: BigInt(transaction.value)
|
|
6841
7097
|
});
|
|
@@ -6939,12 +7195,12 @@ var YieldseekerAgent = class {
|
|
|
6939
7195
|
return receipt;
|
|
6940
7196
|
}
|
|
6941
7197
|
assertTransaction(transaction, state, chainId) {
|
|
6942
|
-
if (!transaction || typeof transaction.from !== "string" || !(0,
|
|
7198
|
+
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
7199
|
throw this.invalidResponse("transaction");
|
|
6944
7200
|
}
|
|
6945
7201
|
}
|
|
6946
7202
|
assertAgent(agent) {
|
|
6947
|
-
if (typeof agent.agentId !== "string" || typeof agent.assetAddress !== "string" || !(0,
|
|
7203
|
+
if (typeof agent.agentId !== "string" || typeof agent.assetAddress !== "string" || !(0, import_viem13.isAddress)(agent.assetAddress) || agent.chainId !== 8453) {
|
|
6948
7204
|
throw this.invalidResponse("agent");
|
|
6949
7205
|
}
|
|
6950
7206
|
}
|
|
@@ -7098,15 +7354,24 @@ async function withFailureReporting(apiKey, agentType, fn, baseUrl) {
|
|
|
7098
7354
|
}
|
|
7099
7355
|
|
|
7100
7356
|
// src/lib/helpers/withdraw-helper.ts
|
|
7101
|
-
var
|
|
7357
|
+
var import_viem14 = require("viem");
|
|
7102
7358
|
function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
|
|
7103
7359
|
const target = asset.toUpperCase();
|
|
7104
7360
|
return agents.map((agent) => {
|
|
7361
|
+
let invalidBalance = false;
|
|
7362
|
+
const readAmount = (value, raw2 = false) => {
|
|
7363
|
+
if (typeof value !== "string" || !(raw2 ? /^\d+$/ : /^\d+(?:\.\d+)?$/).test(value)) {
|
|
7364
|
+
invalidBalance = true;
|
|
7365
|
+
return 0n;
|
|
7366
|
+
}
|
|
7367
|
+
const [whole, fraction] = value.split(".");
|
|
7368
|
+
return raw2 ? BigInt(value) : (0, import_viem14.parseUnits)(fraction === void 0 ? whole : `${whole}.${fraction.slice(0, decimals)}`, decimals);
|
|
7369
|
+
};
|
|
7105
7370
|
const agentBalance = aggregated[agent.id];
|
|
7106
7371
|
const tokenBalance = agentBalance?.tokens.find(
|
|
7107
7372
|
(t) => t.chainId === chainId && t.asset.toUpperCase() === target
|
|
7108
7373
|
);
|
|
7109
|
-
let balance = tokenBalance ? (
|
|
7374
|
+
let balance = tokenBalance ? readAmount(tokenBalance.amount) : 0n;
|
|
7110
7375
|
if (agent.balanceComposition === "tokens-plus-positions") {
|
|
7111
7376
|
const chainNameById = {
|
|
7112
7377
|
1: "ETHEREUM",
|
|
@@ -7118,20 +7383,22 @@ function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decima
|
|
|
7118
7383
|
const positionChain = position2.chain.trim().toUpperCase();
|
|
7119
7384
|
const matchesChain = positionChain === String(chainId) || targetChain !== void 0 && positionChain === targetChain;
|
|
7120
7385
|
if (!matchesChain || position2.asset.toUpperCase() !== target) continue;
|
|
7121
|
-
balance += position2.withdrawableAmountRaw !== void 0 ?
|
|
7386
|
+
balance += position2.withdrawableAmountRaw !== void 0 ? readAmount(position2.withdrawableAmountRaw, true) : readAmount(position2.amount);
|
|
7122
7387
|
}
|
|
7123
7388
|
}
|
|
7124
7389
|
const assetTotal = agentBalance?.assetBalances?.find(
|
|
7125
7390
|
(t) => t.chainId === chainId && t.asset.toUpperCase() === target
|
|
7126
7391
|
);
|
|
7127
7392
|
if (assetTotal) {
|
|
7128
|
-
const total = (
|
|
7393
|
+
const total = readAmount(assetTotal.amount);
|
|
7129
7394
|
if (total < balance) balance = total > 0n ? total : 0n;
|
|
7130
7395
|
}
|
|
7131
|
-
return { agent, balance };
|
|
7396
|
+
return invalidBalance ? { agent, balance: 0n, invalidBalance: true } : { agent, balance };
|
|
7132
7397
|
});
|
|
7133
7398
|
}
|
|
7134
7399
|
function planProportionalShares(balances, requested, totalAvailable) {
|
|
7400
|
+
if (requested < 0n || totalAvailable < 0n || balances.some((entry) => entry.balance < 0n) || balances.reduce((sum, entry) => sum + entry.balance, 0n) !== totalAvailable || requested > totalAvailable)
|
|
7401
|
+
throw new Error("Invalid withdrawal planning amounts.");
|
|
7135
7402
|
const plans = balances.map(({ agent, balance }) => ({
|
|
7136
7403
|
agent,
|
|
7137
7404
|
balance,
|
|
@@ -7154,6 +7421,8 @@ function planProportionalShares(balances, requested, totalAvailable) {
|
|
|
7154
7421
|
return plans;
|
|
7155
7422
|
}
|
|
7156
7423
|
function planDisabledDrain(disabled, requested) {
|
|
7424
|
+
if (requested < 0n || disabled.some((entry) => entry.balance < 0n))
|
|
7425
|
+
throw new Error("Invalid withdrawal planning amounts.");
|
|
7157
7426
|
const sorted = [...disabled].filter((d) => d.balance > 0n).sort(
|
|
7158
7427
|
(a, b) => b.balance > a.balance ? 1 : b.balance < a.balance ? -1 : 0
|
|
7159
7428
|
);
|
|
@@ -7171,6 +7440,7 @@ function planDisabledDrain(disabled, requested) {
|
|
|
7171
7440
|
return { plans, remaining };
|
|
7172
7441
|
}
|
|
7173
7442
|
function redistributeShare(plans, fromIndex, amount, candidatePool) {
|
|
7443
|
+
if (amount <= 0n) return;
|
|
7174
7444
|
const pool = candidatePool ?? plans.slice(fromIndex + 1);
|
|
7175
7445
|
const candidates = pool.filter((c) => c.balance - c.planned > 0n);
|
|
7176
7446
|
const totalHeadroom = candidates.reduce(
|
|
@@ -7197,7 +7467,13 @@ function redistributeShare(plans, fromIndex, amount, candidatePool) {
|
|
|
7197
7467
|
}
|
|
7198
7468
|
}
|
|
7199
7469
|
function sumWithdrawnAmount(results) {
|
|
7200
|
-
return Object.values(results).reduce((sum,
|
|
7470
|
+
return Object.values(results).reduce((sum, result) => sum + (confirmedWithdrawalAmount(result) ?? 0n), 0n);
|
|
7471
|
+
}
|
|
7472
|
+
function confirmedWithdrawalAmount(result) {
|
|
7473
|
+
const evidence = result.evidence;
|
|
7474
|
+
if (evidence && (evidence.transfer !== "confirmed" || evidence.delivery !== "confirmed")) return void 0;
|
|
7475
|
+
const value = evidence ? evidence.confirmedAmount : result.amount;
|
|
7476
|
+
return typeof value === "string" && /^\d+$/.test(value) ? BigInt(value) : void 0;
|
|
7201
7477
|
}
|
|
7202
7478
|
|
|
7203
7479
|
// src/lib/helpers/account-apy-helper.ts
|
|
@@ -7321,14 +7597,14 @@ function aggregateDailyEarnings(series, tokenSymbol) {
|
|
|
7321
7597
|
}
|
|
7322
7598
|
|
|
7323
7599
|
// src/client.ts
|
|
7324
|
-
var
|
|
7600
|
+
var import_viem18 = require("viem");
|
|
7325
7601
|
var import_chains5 = require("viem/chains");
|
|
7326
7602
|
|
|
7327
7603
|
// src/lib/sponsored-token-batch.ts
|
|
7328
|
-
var
|
|
7604
|
+
var import_viem16 = require("viem");
|
|
7329
7605
|
|
|
7330
7606
|
// src/lib/permit2-batch.ts
|
|
7331
|
-
var
|
|
7607
|
+
var import_viem15 = require("viem");
|
|
7332
7608
|
var BATCH_PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
7333
7609
|
var BASE_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
|
|
7334
7610
|
var ERC2612_PERMIT_TYPES = {
|
|
@@ -7340,7 +7616,7 @@ var ERC2612_PERMIT_TYPES = {
|
|
|
7340
7616
|
{ name: "deadline", type: "uint256" }
|
|
7341
7617
|
]
|
|
7342
7618
|
};
|
|
7343
|
-
var ERC2612_READ_ABI = (0,
|
|
7619
|
+
var ERC2612_READ_ABI = (0, import_viem15.parseAbi)([
|
|
7344
7620
|
"function name() view returns (string)",
|
|
7345
7621
|
"function version() view returns (string)",
|
|
7346
7622
|
"function nonces(address owner) view returns (uint256)"
|
|
@@ -7378,7 +7654,7 @@ var PERMIT_BATCH_TYPES = {
|
|
|
7378
7654
|
{ name: "amount", type: "uint256" }
|
|
7379
7655
|
]
|
|
7380
7656
|
};
|
|
7381
|
-
var PERMIT2_BATCH_ABI = (0,
|
|
7657
|
+
var PERMIT2_BATCH_ABI = (0, import_viem15.parseAbi)([
|
|
7382
7658
|
"struct TokenPermissions { address token; uint256 amount; }",
|
|
7383
7659
|
"struct PermitBatchTransferFrom { TokenPermissions[] permitted; uint256 nonce; uint256 deadline; }",
|
|
7384
7660
|
"struct SignatureTransferDetails { address to; uint256 requestedAmount; }",
|
|
@@ -7411,9 +7687,29 @@ function batchTypedData(b, spender) {
|
|
|
7411
7687
|
}
|
|
7412
7688
|
};
|
|
7413
7689
|
}
|
|
7690
|
+
var BATCH_WITNESS_TYPE = "Deposit witness)Deposit(address[] recipients)TokenPermissions(address token,uint256 amount)";
|
|
7691
|
+
function batchWitness(b) {
|
|
7692
|
+
return (0, import_viem15.hashStruct)({
|
|
7693
|
+
types: PERMIT_BATCH_TYPES,
|
|
7694
|
+
primaryType: "Deposit",
|
|
7695
|
+
data: { recipients: b.transfers.map((t) => t.to) }
|
|
7696
|
+
});
|
|
7697
|
+
}
|
|
7698
|
+
function batchArgs(b) {
|
|
7699
|
+
return [
|
|
7700
|
+
batchPermit(b),
|
|
7701
|
+
b.transfers.map((t) => ({ to: t.to, requestedAmount: BigInt(t.amount) })),
|
|
7702
|
+
b.from,
|
|
7703
|
+
batchWitness(b),
|
|
7704
|
+
BATCH_WITNESS_TYPE,
|
|
7705
|
+
b.signature
|
|
7706
|
+
];
|
|
7707
|
+
}
|
|
7414
7708
|
|
|
7415
7709
|
// src/lib/sponsored-token-batch.ts
|
|
7416
7710
|
var memory = /* @__PURE__ */ new Map();
|
|
7711
|
+
var settledRecords = /* @__PURE__ */ new Map();
|
|
7712
|
+
var expiredRecords = /* @__PURE__ */ new Map();
|
|
7417
7713
|
var inflight = /* @__PURE__ */ new Map();
|
|
7418
7714
|
var planOf = (transfers) => JSON.stringify(
|
|
7419
7715
|
transfers.map((t) => ({
|
|
@@ -7421,32 +7717,109 @@ var planOf = (transfers) => JSON.stringify(
|
|
|
7421
7717
|
amount: BigInt(t.amount).toString()
|
|
7422
7718
|
}))
|
|
7423
7719
|
);
|
|
7424
|
-
var pendingKey = (i) => `owney.token-batch.v1:${(0,
|
|
7720
|
+
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
7721
|
function pendingTokenBatch(i) {
|
|
7426
7722
|
try {
|
|
7427
7723
|
const saved = read(pendingKey(i));
|
|
7428
7724
|
if (!saved) return;
|
|
7429
7725
|
const body = JSON.parse(saved);
|
|
7430
|
-
if (!body.serializedTransaction || body.chainId !== i.chainId || !(0,
|
|
7431
|
-
return { txHash: (0,
|
|
7726
|
+
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;
|
|
7727
|
+
return { txHash: (0, import_viem16.keccak256)(body.serializedTransaction), transfers: body.transfers.map(({ to, amount }) => ({ to, amount })) };
|
|
7728
|
+
} catch {
|
|
7729
|
+
return;
|
|
7730
|
+
}
|
|
7731
|
+
}
|
|
7732
|
+
async function releaseExpiredTokenBatch(i) {
|
|
7733
|
+
const key2 = pendingKey(i);
|
|
7734
|
+
let timer;
|
|
7735
|
+
let expired = false;
|
|
7736
|
+
const check = async () => {
|
|
7737
|
+
let active = read(key2);
|
|
7738
|
+
if (active && i.expectedTxHash) {
|
|
7739
|
+
const current = JSON.parse(active);
|
|
7740
|
+
if (!current.serializedTransaction || (0, import_viem16.keccak256)(current.serializedTransaction).toLowerCase() !== i.expectedTxHash.toLowerCase())
|
|
7741
|
+
active = void 0;
|
|
7742
|
+
}
|
|
7743
|
+
const archiveKey = i.expectedTxHash ? `${key2}:expired:${i.expectedTxHash.toLowerCase()}` : void 0;
|
|
7744
|
+
const saved = active ?? (archiveKey && (expiredRecords.get(archiveKey) ?? (typeof window === "undefined" ? void 0 : window.localStorage.getItem(archiveKey))));
|
|
7745
|
+
if (!saved) return;
|
|
7746
|
+
const body = JSON.parse(saved);
|
|
7747
|
+
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;
|
|
7748
|
+
const txHash = (0, import_viem16.keccak256)(body.serializedTransaction);
|
|
7749
|
+
if (i.expectedTxHash && txHash.toLowerCase() !== i.expectedTxHash.toLowerCase()) return;
|
|
7750
|
+
const transaction = (0, import_viem16.parseTransaction)(body.serializedTransaction);
|
|
7751
|
+
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)({
|
|
7752
|
+
abi: PERMIT2_BATCH_ABI,
|
|
7753
|
+
functionName: "permitWitnessTransferFrom",
|
|
7754
|
+
args: batchArgs(body)
|
|
7755
|
+
})) return;
|
|
7756
|
+
const nonce = BigInt(body.nonce);
|
|
7757
|
+
const deadline = BigInt(body.deadline);
|
|
7758
|
+
if (nonce < 0n || nonce > MAX_UINT256 || deadline < 0n) return;
|
|
7759
|
+
const block = await i.pub.getBlock({ blockTag: "finalized" });
|
|
7760
|
+
if (expired || typeof block.number !== "bigint" || typeof block.timestamp !== "bigint" || block.timestamp <= deadline) return;
|
|
7761
|
+
const bitmap = await i.pub.readContract({
|
|
7762
|
+
address: BATCH_PERMIT2_ADDRESS,
|
|
7763
|
+
abi: PERMIT2_BATCH_ABI,
|
|
7764
|
+
functionName: "nonceBitmap",
|
|
7765
|
+
args: [i.owner, nonce >> 8n],
|
|
7766
|
+
blockNumber: block.number
|
|
7767
|
+
});
|
|
7768
|
+
if (expired || typeof bitmap !== "bigint" || bitmap < 0n || bitmap > MAX_UINT256 || (bitmap & 1n << (nonce & 255n)) !== 0n || active && read(key2) !== active) return;
|
|
7769
|
+
if (active) {
|
|
7770
|
+
const terminalKey = `${key2}:expired:${txHash.toLowerCase()}`;
|
|
7771
|
+
expiredRecords.set(terminalKey, saved);
|
|
7772
|
+
let persisted = typeof window === "undefined";
|
|
7773
|
+
try {
|
|
7774
|
+
if (typeof window !== "undefined") {
|
|
7775
|
+
window.localStorage.setItem(terminalKey, saved);
|
|
7776
|
+
persisted = window.localStorage.getItem(terminalKey) === saved;
|
|
7777
|
+
}
|
|
7778
|
+
} catch {
|
|
7779
|
+
}
|
|
7780
|
+
if (!persisted) settledRecords.set(key2, saved);
|
|
7781
|
+
else clear(key2, body);
|
|
7782
|
+
}
|
|
7783
|
+
return { txHash, transfers: body.transfers.map(({ to, amount }) => ({ to, amount })), blockNumber: block.number };
|
|
7784
|
+
};
|
|
7785
|
+
try {
|
|
7786
|
+
return await Promise.race([check(), new Promise((resolve) => {
|
|
7787
|
+
timer = setTimeout(() => {
|
|
7788
|
+
expired = true;
|
|
7789
|
+
resolve(void 0);
|
|
7790
|
+
}, 8e3);
|
|
7791
|
+
})]);
|
|
7432
7792
|
} catch {
|
|
7433
7793
|
return;
|
|
7794
|
+
} finally {
|
|
7795
|
+
expired = true;
|
|
7796
|
+
if (timer) clearTimeout(timer);
|
|
7434
7797
|
}
|
|
7435
7798
|
}
|
|
7436
7799
|
function read(key2) {
|
|
7437
|
-
|
|
7800
|
+
const value = typeof window === "undefined" ? memory.get(key2) : window.localStorage.getItem(key2);
|
|
7801
|
+
return value && settledRecords.get(key2) === value ? void 0 : value;
|
|
7438
7802
|
}
|
|
7439
|
-
function
|
|
7440
|
-
|
|
7803
|
+
function storedBody(body) {
|
|
7804
|
+
return JSON.stringify({
|
|
7441
7805
|
...body,
|
|
7442
7806
|
transfers: body.transfers.map(({ to, amount }) => ({ to, amount }))
|
|
7443
7807
|
});
|
|
7808
|
+
}
|
|
7809
|
+
function save(key2, body) {
|
|
7810
|
+
const value = storedBody(body);
|
|
7444
7811
|
if (typeof window === "undefined") memory.set(key2, value);
|
|
7445
7812
|
else window.localStorage.setItem(key2, value);
|
|
7813
|
+
settledRecords.delete(key2);
|
|
7446
7814
|
}
|
|
7447
|
-
function clear(key2) {
|
|
7448
|
-
|
|
7449
|
-
|
|
7815
|
+
function clear(key2, body) {
|
|
7816
|
+
try {
|
|
7817
|
+
if (typeof window === "undefined") memory.delete(key2);
|
|
7818
|
+
else window.localStorage.removeItem(key2);
|
|
7819
|
+
settledRecords.delete(key2);
|
|
7820
|
+
} catch {
|
|
7821
|
+
settledRecords.set(key2, storedBody(body));
|
|
7822
|
+
}
|
|
7450
7823
|
}
|
|
7451
7824
|
function sponsorTokenBatch(i) {
|
|
7452
7825
|
const key2 = pendingKey(i);
|
|
@@ -7513,7 +7886,7 @@ async function execute(i, key2, plan) {
|
|
|
7513
7886
|
baseUrl: i.baseUrl,
|
|
7514
7887
|
body
|
|
7515
7888
|
});
|
|
7516
|
-
if (!preparedPermit.serializedPermitTransaction || !preparedPermit.permitTxHash || (0,
|
|
7889
|
+
if (!preparedPermit.serializedPermitTransaction || !preparedPermit.permitTxHash || (0, import_viem16.keccak256)(preparedPermit.serializedPermitTransaction) !== preparedPermit.permitTxHash)
|
|
7517
7890
|
throw new Error(
|
|
7518
7891
|
"Sponsorship API did not return a valid prepared permit transaction."
|
|
7519
7892
|
);
|
|
@@ -7524,7 +7897,7 @@ async function execute(i, key2, plan) {
|
|
|
7524
7897
|
save(key2, body);
|
|
7525
7898
|
}
|
|
7526
7899
|
if (!body.serializedTransaction) {
|
|
7527
|
-
const permitHash = body.serializedPermitTransaction ? (0,
|
|
7900
|
+
const permitHash = body.serializedPermitTransaction ? (0, import_viem16.keccak256)(body.serializedPermitTransaction) : void 0;
|
|
7528
7901
|
let prepared = permitHash ? await postSigned("approval", permitHash) : await post();
|
|
7529
7902
|
if (prepared?.status === "pending") {
|
|
7530
7903
|
if (!permitHash || prepared.phase !== "approval" || prepared.txHash !== permitHash)
|
|
@@ -7535,7 +7908,7 @@ async function execute(i, key2, plan) {
|
|
|
7535
7908
|
if (!prepared) prepared = await post();
|
|
7536
7909
|
if (prepared.status === "pending" && permitHash && prepared.phase === "approval" && prepared.txHash === permitHash)
|
|
7537
7910
|
throw pendingError("approval", permitHash);
|
|
7538
|
-
if (!prepared.serializedTransaction || (0,
|
|
7911
|
+
if (!prepared.serializedTransaction || (0, import_viem16.keccak256)(prepared.serializedTransaction) !== prepared.txHash)
|
|
7539
7912
|
throw new Error(
|
|
7540
7913
|
"Sponsorship API did not return a valid prepared transaction."
|
|
7541
7914
|
);
|
|
@@ -7545,23 +7918,24 @@ async function execute(i, key2, plan) {
|
|
|
7545
7918
|
};
|
|
7546
7919
|
save(key2, body);
|
|
7547
7920
|
}
|
|
7921
|
+
await i.onBeforeSubmission?.((0, import_viem16.keccak256)(body.serializedTransaction));
|
|
7548
7922
|
try {
|
|
7549
|
-
i.onSubmitted?.((0,
|
|
7923
|
+
i.onSubmitted?.((0, import_viem16.keccak256)(body.serializedTransaction));
|
|
7550
7924
|
} catch {
|
|
7551
7925
|
}
|
|
7552
|
-
const hash = (0,
|
|
7926
|
+
const hash = (0, import_viem16.keccak256)(body.serializedTransaction);
|
|
7553
7927
|
const existing = await i.pub.getTransactionReceipt({ hash }).catch(() => void 0);
|
|
7554
7928
|
if (existing) {
|
|
7555
7929
|
assertReceipt(existing, "deposit");
|
|
7556
7930
|
void post().catch(() => void 0);
|
|
7557
|
-
clear(key2);
|
|
7931
|
+
clear(key2, body);
|
|
7558
7932
|
return hash;
|
|
7559
7933
|
}
|
|
7560
7934
|
let result = await postSigned("deposit", hash);
|
|
7561
|
-
if (result?.status === "pending" && result.phase === "approval" && body.serializedPermitTransaction && result.txHash === (0,
|
|
7935
|
+
if (result?.status === "pending" && result.phase === "approval" && body.serializedPermitTransaction && result.txHash === (0, import_viem16.keccak256)(body.serializedPermitTransaction)) {
|
|
7562
7936
|
await waitForConfirmation("approval", result.txHash);
|
|
7563
7937
|
result = await postSigned("deposit", hash);
|
|
7564
|
-
if (result?.status === "pending" && result.phase === "approval" && result.txHash === (0,
|
|
7938
|
+
if (result?.status === "pending" && result.phase === "approval" && result.txHash === (0, import_viem16.keccak256)(body.serializedPermitTransaction)) throw pendingError("approval", result.txHash);
|
|
7565
7939
|
}
|
|
7566
7940
|
if (result) {
|
|
7567
7941
|
if (result.txHash !== hash || result.status === "pending" && result.phase !== "deposit")
|
|
@@ -7569,11 +7943,18 @@ async function execute(i, key2, plan) {
|
|
|
7569
7943
|
if (result.status === "pending") await waitForConfirmation("deposit", hash);
|
|
7570
7944
|
}
|
|
7571
7945
|
if (!result || result.status === "pending") void post().catch(() => void 0);
|
|
7572
|
-
clear(key2);
|
|
7946
|
+
clear(key2, body);
|
|
7573
7947
|
return hash;
|
|
7574
7948
|
} catch (error) {
|
|
7949
|
+
if (initial.serializedTransaction && error instanceof OwneyError && error.code === "DEPOSIT_CHECKPOINT_FAILED") {
|
|
7950
|
+
throw new OwneyError(
|
|
7951
|
+
error.code,
|
|
7952
|
+
"Could not save recovery of the existing deposit.",
|
|
7953
|
+
{ ...error.details, notSubmitted: false, safeToFallback: false }
|
|
7954
|
+
);
|
|
7955
|
+
}
|
|
7575
7956
|
if (!body.serializedTransaction && !body.serializedPermitTransaction || rejectedPreparation(error) || error instanceof OwneyError && error.details?.notSubmitted === true)
|
|
7576
|
-
clear(key2);
|
|
7957
|
+
clear(key2, body);
|
|
7577
7958
|
throw error;
|
|
7578
7959
|
}
|
|
7579
7960
|
};
|
|
@@ -7582,10 +7963,16 @@ async function execute(i, key2, plan) {
|
|
|
7582
7963
|
throw new OwneyError("DEPOSIT_IN_PROGRESS", "The saved deposit changed. Check its status before depositing again.");
|
|
7583
7964
|
if (saved) {
|
|
7584
7965
|
const previous = JSON.parse(saved);
|
|
7585
|
-
if (previous.chainId !== i.chainId || !(0,
|
|
7966
|
+
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
7967
|
throw new Error(
|
|
7587
7968
|
"Retry the previous token deposit and agent split first to reconcile its status."
|
|
7588
7969
|
);
|
|
7970
|
+
if (await releaseExpiredTokenBatch({ ...i, expectedTxHash: previous.serializedTransaction ? (0, import_viem16.keccak256)(previous.serializedTransaction) : void 0 }))
|
|
7971
|
+
throw new OwneyError(
|
|
7972
|
+
"SPONSOR_REQUEST_FAILED",
|
|
7973
|
+
"The deposit authorization expired without transferring funds. Start a new deposit.",
|
|
7974
|
+
{ notSubmitted: true, safeToFallback: false }
|
|
7975
|
+
);
|
|
7589
7976
|
i.onApproved?.();
|
|
7590
7977
|
return send({ ...previous, transfers: i.transfers });
|
|
7591
7978
|
}
|
|
@@ -7599,7 +7986,7 @@ async function execute(i, key2, plan) {
|
|
|
7599
7986
|
"DEPOSIT_INSUFFICIENT_BALANCE",
|
|
7600
7987
|
"Insufficient token balance for this deposit."
|
|
7601
7988
|
);
|
|
7602
|
-
if (allowance < total && (i.chainId !== 8453 || !(0,
|
|
7989
|
+
if (allowance < total && (i.chainId !== 8453 || !(0, import_viem16.isAddressEqual)(i.token, BASE_USDC_ADDRESS)))
|
|
7603
7990
|
throw new OwneyError(
|
|
7604
7991
|
"PERMIT2_APPROVAL_REQUIRED",
|
|
7605
7992
|
"token deposits need a one-time Permit2 approval."
|
|
@@ -7692,6 +8079,7 @@ function makeSponsoredTokenCallback(deps) {
|
|
|
7692
8079
|
wallet,
|
|
7693
8080
|
onApproved: deps.onApproved,
|
|
7694
8081
|
onSubmitted: (hash) => deps.onSubmitted?.(hash, transfers),
|
|
8082
|
+
onBeforeSubmission: (hash) => deps.onBeforeSubmission?.(hash, transfers),
|
|
7695
8083
|
resumeTxHash: deps.resumeTxHash
|
|
7696
8084
|
});
|
|
7697
8085
|
};
|
|
@@ -7778,7 +8166,7 @@ async function runAgentDepositBatch(chainId, legs, transfer) {
|
|
|
7778
8166
|
}
|
|
7779
8167
|
|
|
7780
8168
|
// src/lib/sponsored-calls-deposit.ts
|
|
7781
|
-
var
|
|
8169
|
+
var import_viem17 = require("viem");
|
|
7782
8170
|
var DEFAULT_POLL_INTERVAL_MS = 1500;
|
|
7783
8171
|
var DEFAULT_MAX_POLLS = 30;
|
|
7784
8172
|
async function paymasterSupported(provider, owner, chainId) {
|
|
@@ -7786,7 +8174,7 @@ async function paymasterSupported(provider, owner, chainId) {
|
|
|
7786
8174
|
method: "wallet_getCapabilities",
|
|
7787
8175
|
params: [owner]
|
|
7788
8176
|
});
|
|
7789
|
-
const forChain = caps?.[(0,
|
|
8177
|
+
const forChain = caps?.[(0, import_viem17.toHex)(chainId)] ?? caps?.[String(chainId)];
|
|
7790
8178
|
return Boolean(forChain?.paymasterService?.supported);
|
|
7791
8179
|
}
|
|
7792
8180
|
function makeSponsoredCallsCallback(deps) {
|
|
@@ -7823,8 +8211,8 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
7823
8211
|
const calls = transfers.map((transfer) => ({
|
|
7824
8212
|
to: token,
|
|
7825
8213
|
value: "0x0",
|
|
7826
|
-
data: (0,
|
|
7827
|
-
abi:
|
|
8214
|
+
data: (0, import_viem17.encodeFunctionData)({
|
|
8215
|
+
abi: import_viem17.erc20Abi,
|
|
7828
8216
|
functionName: "transfer",
|
|
7829
8217
|
args: [transfer.to, BigInt(transfer.amount)]
|
|
7830
8218
|
})
|
|
@@ -7856,13 +8244,14 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
7856
8244
|
url.searchParams.append("owneyIntent", intent);
|
|
7857
8245
|
paymasterUrl = url.toString();
|
|
7858
8246
|
}
|
|
7859
|
-
const requestedId = (0,
|
|
8247
|
+
const requestedId = (0, import_viem17.toHex)(globalThis.crypto.getRandomValues(new Uint8Array(32)));
|
|
7860
8248
|
const progress = (id, transfer) => {
|
|
7861
8249
|
try {
|
|
7862
8250
|
deps.onCallsProgress?.(id, transfers, transfer);
|
|
7863
8251
|
} catch {
|
|
7864
8252
|
}
|
|
7865
8253
|
};
|
|
8254
|
+
await deps.onBeforeSubmission?.(requestedId, transfers);
|
|
7866
8255
|
progress(requestedId, "pending");
|
|
7867
8256
|
let sendResult;
|
|
7868
8257
|
try {
|
|
@@ -7873,7 +8262,7 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
7873
8262
|
version: "2.0.0",
|
|
7874
8263
|
id: requestedId,
|
|
7875
8264
|
from: deps.ownerAddress,
|
|
7876
|
-
chainId: (0,
|
|
8265
|
+
chainId: (0, import_viem17.toHex)(chainId),
|
|
7877
8266
|
atomicRequired: transfers.length > 1,
|
|
7878
8267
|
calls,
|
|
7879
8268
|
capabilities: {
|
|
@@ -8006,6 +8395,8 @@ var OwneySDK = class {
|
|
|
8006
8395
|
*/
|
|
8007
8396
|
disabledAgents = /* @__PURE__ */ new Set();
|
|
8008
8397
|
state = null;
|
|
8398
|
+
connectionRevision = 0;
|
|
8399
|
+
disconnectingAgents = null;
|
|
8009
8400
|
apiKey;
|
|
8010
8401
|
// The org's agent policy, fetched once per client. Applied to each agent on
|
|
8011
8402
|
// activation (ROUT-229). `undefined` means "not fetched yet", `null` means
|
|
@@ -8027,6 +8418,9 @@ var OwneySDK = class {
|
|
|
8027
8418
|
recoveredFundingReads = /* @__PURE__ */ new Set();
|
|
8028
8419
|
fundingBalanceChecks = /* @__PURE__ */ new WeakMap();
|
|
8029
8420
|
activationChecks = /* @__PURE__ */ new Map();
|
|
8421
|
+
// Protect the SDK entry point as well as the mini-app hook. This owns only
|
|
8422
|
+
// a running call, never a saved/pending provider outcome or a later retry.
|
|
8423
|
+
withdrawalSubmissions = /* @__PURE__ */ new Set();
|
|
8030
8424
|
readAgent(agent, method, fetch2, params = null) {
|
|
8031
8425
|
const key2 = JSON.stringify([
|
|
8032
8426
|
this.state?.walletAddress.toLowerCase() ?? null,
|
|
@@ -8059,9 +8453,10 @@ var OwneySDK = class {
|
|
|
8059
8453
|
*/
|
|
8060
8454
|
// TODO: replace with a proper EIP-1193 Provider type
|
|
8061
8455
|
async connect(provider) {
|
|
8062
|
-
const
|
|
8063
|
-
|
|
8064
|
-
|
|
8456
|
+
const revision = ++this.connectionRevision;
|
|
8457
|
+
const accounts = await provider.request({ method: "eth_accounts" });
|
|
8458
|
+
if (revision !== this.connectionRevision)
|
|
8459
|
+
throw new OwneyError("NOT_CONNECTED", "Wallet connection changed while connecting.");
|
|
8065
8460
|
const walletAddress = accounts[0];
|
|
8066
8461
|
if (!walletAddress) {
|
|
8067
8462
|
throw new OwneyError(
|
|
@@ -8069,33 +8464,46 @@ var OwneySDK = class {
|
|
|
8069
8464
|
"No accounts found. Ensure the wallet is unlocked and connected."
|
|
8070
8465
|
);
|
|
8071
8466
|
}
|
|
8072
|
-
this.
|
|
8073
|
-
this.
|
|
8074
|
-
|
|
8467
|
+
const replacingOwner = this.state !== null && this.state.walletAddress.toLowerCase() !== walletAddress.toLowerCase();
|
|
8468
|
+
this.clearConnectionState();
|
|
8469
|
+
await (replacingOwner ? this.disconnectAgents() : this.disconnectingAgents);
|
|
8470
|
+
if (revision !== this.connectionRevision)
|
|
8471
|
+
throw new OwneyError("NOT_CONNECTED", "Wallet connection changed while connecting.");
|
|
8075
8472
|
this.state = { provider, walletAddress, chainId: null };
|
|
8076
|
-
this.cachedSponsoredCallback = null;
|
|
8077
|
-
this.cachedWethSponsoredCallback = null;
|
|
8078
|
-
this.cachedSponsoredCallsCallbacks.clear();
|
|
8079
8473
|
}
|
|
8080
8474
|
/**
|
|
8081
8475
|
* Disconnect from all agents and clear connection state.
|
|
8082
8476
|
* After calling this, `connect()` must be called again before using agent methods.
|
|
8083
8477
|
*/
|
|
8084
8478
|
async disconnect() {
|
|
8479
|
+
++this.connectionRevision;
|
|
8480
|
+
this.clearConnectionState();
|
|
8481
|
+
await this.disconnectAgents();
|
|
8482
|
+
}
|
|
8483
|
+
clearConnectionState() {
|
|
8085
8484
|
this.state = null;
|
|
8086
8485
|
this.fundingBalanceChecks = /* @__PURE__ */ new WeakMap();
|
|
8087
|
-
for (const agent of this.agents.values()) {
|
|
8088
|
-
await agent.disconnect();
|
|
8089
|
-
}
|
|
8090
8486
|
this.activeAgents.clear();
|
|
8091
|
-
this.disabledAgents.clear();
|
|
8092
8487
|
this.agentReads.clearInFlight();
|
|
8093
8488
|
this.activationChecks.clear();
|
|
8094
|
-
this.state = null;
|
|
8095
8489
|
this.cachedSponsoredCallback = null;
|
|
8096
8490
|
this.cachedWethSponsoredCallback = null;
|
|
8097
8491
|
this.cachedSponsoredCallsCallbacks.clear();
|
|
8098
8492
|
}
|
|
8493
|
+
disconnectAgents() {
|
|
8494
|
+
if (this.disconnectingAgents) return this.disconnectingAgents;
|
|
8495
|
+
const pending = Promise.allSettled([...this.agents.values()].map(async (agent) => agent.disconnect())).then((results) => {
|
|
8496
|
+
const failure = results.find((result) => result.status === "rejected");
|
|
8497
|
+
if (failure?.status === "rejected") throw failure.reason;
|
|
8498
|
+
});
|
|
8499
|
+
this.disconnectingAgents = pending;
|
|
8500
|
+
void pending.then(() => {
|
|
8501
|
+
if (this.disconnectingAgents === pending) this.disconnectingAgents = null;
|
|
8502
|
+
}, () => {
|
|
8503
|
+
if (this.disconnectingAgents === pending) this.disconnectingAgents = null;
|
|
8504
|
+
});
|
|
8505
|
+
return pending;
|
|
8506
|
+
}
|
|
8099
8507
|
isAgentDisabled(agentId) {
|
|
8100
8508
|
return this.disabledAgents.has(agentId);
|
|
8101
8509
|
}
|
|
@@ -8141,8 +8549,8 @@ var OwneySDK = class {
|
|
|
8141
8549
|
return createPaidRpcClient(VIEM_CHAIN2[chainId], this.rpcUrls);
|
|
8142
8550
|
}
|
|
8143
8551
|
/** Builds the default USDC batch callback for the connected wallet. */
|
|
8144
|
-
getDefaultSponsoredCallback(onApproved, onSubmitted, resumeTxHash) {
|
|
8145
|
-
if (!onApproved && !onSubmitted && !resumeTxHash && this.cachedSponsoredCallback)
|
|
8552
|
+
getDefaultSponsoredCallback(onApproved, onSubmitted, resumeTxHash, onBeforeSubmission) {
|
|
8553
|
+
if (!onApproved && !onSubmitted && !resumeTxHash && !onBeforeSubmission && this.cachedSponsoredCallback)
|
|
8146
8554
|
return this.cachedSponsoredCallback;
|
|
8147
8555
|
const provider = this.requireConnectedProvider();
|
|
8148
8556
|
const owner = this.state.walletAddress;
|
|
@@ -8152,29 +8560,30 @@ var OwneySDK = class {
|
|
|
8152
8560
|
ownerAddress: owner,
|
|
8153
8561
|
onApproved,
|
|
8154
8562
|
onSubmitted,
|
|
8563
|
+
onBeforeSubmission,
|
|
8155
8564
|
resumeTxHash,
|
|
8156
8565
|
tokenAddressByChain: SPONSORED_USDC_BY_CHAIN,
|
|
8157
8566
|
// Casts work around viem's chain-narrowed Client vs the generic
|
|
8158
8567
|
// PublicClient/WalletClient param types — structurally identical at
|
|
8159
8568
|
// runtime, but the two share a name TS treats as unrelated.
|
|
8160
8569
|
getPublicClient: (cid) => this.getPaidRpcClient(cid),
|
|
8161
|
-
getWalletChainClient: (cid) => (0,
|
|
8570
|
+
getWalletChainClient: (cid) => (0, import_viem18.createPublicClient)({
|
|
8162
8571
|
chain: VIEM_CHAIN2[cid],
|
|
8163
|
-
transport: (0,
|
|
8572
|
+
transport: (0, import_viem18.custom)(provider)
|
|
8164
8573
|
}),
|
|
8165
|
-
getWalletClient: (cid) => (0,
|
|
8574
|
+
getWalletClient: (cid) => (0, import_viem18.createWalletClient)({
|
|
8166
8575
|
account: owner,
|
|
8167
8576
|
chain: VIEM_CHAIN2[cid],
|
|
8168
|
-
transport: (0,
|
|
8577
|
+
transport: (0, import_viem18.custom)(provider)
|
|
8169
8578
|
})
|
|
8170
8579
|
});
|
|
8171
|
-
if (!onApproved && !onSubmitted && !resumeTxHash) this.cachedSponsoredCallback = callback;
|
|
8580
|
+
if (!onApproved && !onSubmitted && !resumeTxHash && !onBeforeSubmission) this.cachedSponsoredCallback = callback;
|
|
8172
8581
|
return callback;
|
|
8173
8582
|
}
|
|
8174
8583
|
/** Builds the wallet-native sponsored calls callback for compatible paymasters. */
|
|
8175
|
-
getDefaultSponsoredCallsCallback(asset, onApproved, onSubmitted, onCallsProgress) {
|
|
8584
|
+
getDefaultSponsoredCallsCallback(asset, onApproved, onSubmitted, onCallsProgress, onBeforeSubmission) {
|
|
8176
8585
|
const cached = this.cachedSponsoredCallsCallbacks.get(asset);
|
|
8177
|
-
if (!onApproved && !onSubmitted && !onCallsProgress && cached) return cached;
|
|
8586
|
+
if (!onApproved && !onSubmitted && !onCallsProgress && !onBeforeSubmission && cached) return cached;
|
|
8178
8587
|
const provider = this.requireConnectedProvider();
|
|
8179
8588
|
const callback = makeSponsoredCallsCallback({
|
|
8180
8589
|
apiKey: this.apiKey,
|
|
@@ -8185,9 +8594,10 @@ var OwneySDK = class {
|
|
|
8185
8594
|
onApproved,
|
|
8186
8595
|
onSubmitted,
|
|
8187
8596
|
onCallsProgress,
|
|
8597
|
+
onBeforeSubmission,
|
|
8188
8598
|
tokenAddressByChain: sponsoredTokensFor(asset)
|
|
8189
8599
|
});
|
|
8190
|
-
if (!onApproved && !onSubmitted && !onCallsProgress) this.cachedSponsoredCallsCallbacks.set(asset, callback);
|
|
8600
|
+
if (!onApproved && !onSubmitted && !onCallsProgress && !onBeforeSubmission) this.cachedSponsoredCallsCallbacks.set(asset, callback);
|
|
8191
8601
|
return callback;
|
|
8192
8602
|
}
|
|
8193
8603
|
/**
|
|
@@ -8196,8 +8606,8 @@ var OwneySDK = class {
|
|
|
8196
8606
|
* Mirrors `getDefaultSponsoredCallback()` but signs a Permit2
|
|
8197
8607
|
* single-use batch authorization instead of an EIP-3009 authorization.
|
|
8198
8608
|
*/
|
|
8199
|
-
getDefaultWethSponsoredCallback(onApproved, onSubmitted, resumeTxHash) {
|
|
8200
|
-
if (!onApproved && !onSubmitted && !resumeTxHash && this.cachedWethSponsoredCallback)
|
|
8609
|
+
getDefaultWethSponsoredCallback(onApproved, onSubmitted, resumeTxHash, onBeforeSubmission) {
|
|
8610
|
+
if (!onApproved && !onSubmitted && !resumeTxHash && !onBeforeSubmission && this.cachedWethSponsoredCallback)
|
|
8201
8611
|
return this.cachedWethSponsoredCallback;
|
|
8202
8612
|
const provider = this.requireConnectedProvider();
|
|
8203
8613
|
const owner = this.state.walletAddress;
|
|
@@ -8207,23 +8617,24 @@ var OwneySDK = class {
|
|
|
8207
8617
|
ownerAddress: owner,
|
|
8208
8618
|
onApproved,
|
|
8209
8619
|
onSubmitted,
|
|
8620
|
+
onBeforeSubmission,
|
|
8210
8621
|
resumeTxHash,
|
|
8211
8622
|
tokenAddressByChain: SPONSORED_WETH_BY_CHAIN,
|
|
8212
8623
|
// Casts work around viem's chain-narrowed Client vs the generic
|
|
8213
8624
|
// PublicClient/WalletClient param types — structurally identical at
|
|
8214
8625
|
// runtime, but the two share a name TS treats as unrelated.
|
|
8215
8626
|
getPublicClient: (cid) => this.getPaidRpcClient(cid),
|
|
8216
|
-
getWalletChainClient: (cid) => (0,
|
|
8627
|
+
getWalletChainClient: (cid) => (0, import_viem18.createPublicClient)({
|
|
8217
8628
|
chain: VIEM_CHAIN2[cid],
|
|
8218
|
-
transport: (0,
|
|
8629
|
+
transport: (0, import_viem18.custom)(provider)
|
|
8219
8630
|
}),
|
|
8220
|
-
getWalletClient: (cid) => (0,
|
|
8631
|
+
getWalletClient: (cid) => (0, import_viem18.createWalletClient)({
|
|
8221
8632
|
account: owner,
|
|
8222
8633
|
chain: VIEM_CHAIN2[cid],
|
|
8223
|
-
transport: (0,
|
|
8634
|
+
transport: (0, import_viem18.custom)(provider)
|
|
8224
8635
|
})
|
|
8225
8636
|
});
|
|
8226
|
-
if (!onApproved && !onSubmitted && !resumeTxHash) this.cachedWethSponsoredCallback = callback;
|
|
8637
|
+
if (!onApproved && !onSubmitted && !resumeTxHash && !onBeforeSubmission) this.cachedWethSponsoredCallback = callback;
|
|
8227
8638
|
return callback;
|
|
8228
8639
|
}
|
|
8229
8640
|
getAgent(agentId) {
|
|
@@ -8531,10 +8942,20 @@ var OwneySDK = class {
|
|
|
8531
8942
|
*/
|
|
8532
8943
|
async deposit(options) {
|
|
8533
8944
|
const { amount, asset, depositCallback, agentId, onApproved } = options;
|
|
8945
|
+
if (!isFundingAmount(amount, true))
|
|
8946
|
+
throw new OwneyError(
|
|
8947
|
+
"DEPOSIT_INVALID_AMOUNT",
|
|
8948
|
+
"Deposit amount must be an unsigned base-unit integer.",
|
|
8949
|
+
{ phase: "prepare", rejectedBeforeSubmission: true }
|
|
8950
|
+
);
|
|
8534
8951
|
const prepared = /* @__PURE__ */ new Map();
|
|
8535
8952
|
const paidFallbackAgents = /* @__PURE__ */ new Set();
|
|
8536
|
-
const onProgress = options.onProgress ? (evidence) => {
|
|
8537
|
-
if (evidence.agentWallet)
|
|
8953
|
+
const onProgress = options.onProgress || options.onBeforeSubmission ? (evidence) => {
|
|
8954
|
+
if (evidence.agentWallet) {
|
|
8955
|
+
const wallet = evidence.agentWallet.toLowerCase();
|
|
8956
|
+
evidence = { ...prepared.get(wallet), ...evidence };
|
|
8957
|
+
prepared.set(wallet, evidence);
|
|
8958
|
+
}
|
|
8538
8959
|
notifyFunding(options.onProgress, evidence);
|
|
8539
8960
|
} : void 0;
|
|
8540
8961
|
const onSubmitted = onProgress ? (hash, destinations) => {
|
|
@@ -8554,10 +8975,87 @@ var OwneySDK = class {
|
|
|
8554
8975
|
}
|
|
8555
8976
|
const state = this.requireState();
|
|
8556
8977
|
const chainId = this.requireChainId();
|
|
8978
|
+
let checkpointFailure;
|
|
8979
|
+
let checkpointFailedEvidence = [];
|
|
8980
|
+
const checkpoint2 = options.onBeforeSubmission ? async (evidence) => {
|
|
8981
|
+
try {
|
|
8982
|
+
if (this.state !== state || state.chainId !== chainId) throw new Error("Wallet changed before deposit submission.");
|
|
8983
|
+
const submitting = evidence.map((leg) => ({ ...leg, depositSubmission: "started" }));
|
|
8984
|
+
await options.onBeforeSubmission(submitting);
|
|
8985
|
+
if (this.state !== state || state.chainId !== chainId) throw new Error("Wallet changed before deposit submission.");
|
|
8986
|
+
submitting.forEach((leg) => notifyFunding(onProgress, leg));
|
|
8987
|
+
} catch (cause) {
|
|
8988
|
+
checkpointFailedEvidence = evidence;
|
|
8989
|
+
checkpointFailure = new OwneyError(
|
|
8990
|
+
"DEPOSIT_CHECKPOINT_FAILED",
|
|
8991
|
+
"Could not safely save this deposit before submission.",
|
|
8992
|
+
{ notSubmitted: !options.resumeTxHash, safeToFallback: false, cause }
|
|
8993
|
+
);
|
|
8994
|
+
throw checkpointFailure;
|
|
8995
|
+
}
|
|
8996
|
+
} : void 0;
|
|
8997
|
+
const checkpointDestinations = checkpoint2 ? async (destinations, identifier) => {
|
|
8998
|
+
const evidence = destinations.map((destination) => {
|
|
8999
|
+
const leg = prepared.get(destination.to.toLowerCase());
|
|
9000
|
+
if (!leg || leg.intendedAmount !== destination.amount)
|
|
9001
|
+
throw new OwneyError("DEPOSIT_CHECKPOINT_FAILED", "Missing prepared deposit destination.", { notSubmitted: true, safeToFallback: false });
|
|
9002
|
+
return { ...leg, ...identifier, transfer: "pending" };
|
|
9003
|
+
});
|
|
9004
|
+
await checkpoint2(evidence);
|
|
9005
|
+
} : void 0;
|
|
9006
|
+
const checkpointHash = checkpointDestinations ? (hash, destinations) => checkpointDestinations(destinations, { txHash: hash }) : void 0;
|
|
9007
|
+
const checkpointCalls = checkpointDestinations ? (id, destinations) => checkpointDestinations(destinations, { callsId: id }) : void 0;
|
|
9008
|
+
const checkpointPaid = checkpoint2 ? (evidence) => checkpoint2([evidence]) : void 0;
|
|
9009
|
+
const customCallback = depositCallback && checkpointDestinations ? makeVerificationAwareDepositCallback(async (to, cid, value, verification) => {
|
|
9010
|
+
if (verification) provideDepositVerificationContext(depositCallback, verification);
|
|
9011
|
+
await checkpointDestinations([{ to, amount: value }], {});
|
|
9012
|
+
return depositCallback(to, cid, value);
|
|
9013
|
+
}) : depositCallback;
|
|
8557
9014
|
if (options.resumeTxHash && (depositCallback || this.paymasterServiceUrl || !/^0x[\da-f]{64}$/i.test(options.resumeTxHash)))
|
|
8558
9015
|
throw new OwneyError("DEPOSIT_IN_PROGRESS", "This deposit cannot resume the saved relayer transaction.");
|
|
8559
|
-
const effectiveCallback =
|
|
9016
|
+
const effectiveCallback = customCallback ?? (this.paymasterServiceUrl ? this.getDefaultSponsoredCallsCallback(asset, onApproved, onSubmitted, onCallsProgress, checkpointCalls) : asset === "WETH" ? this.getDefaultWethSponsoredCallback(onApproved, onSubmitted, options.resumeTxHash, checkpointHash) : this.getDefaultSponsoredCallback(onApproved, onSubmitted, options.resumeTxHash, checkpointHash));
|
|
8560
9017
|
try {
|
|
9018
|
+
if (options.resumeTxHash) {
|
|
9019
|
+
const token = SupportedAssets.find((value) => value.chainId === chainId && value.symbol === asset);
|
|
9020
|
+
const pending = token && pendingTokenBatch({
|
|
9021
|
+
apiKey: this.apiKey,
|
|
9022
|
+
baseUrl: this.routingApiBaseUrl,
|
|
9023
|
+
owner: state.walletAddress,
|
|
9024
|
+
chainId,
|
|
9025
|
+
token: token.address
|
|
9026
|
+
});
|
|
9027
|
+
const invalid2 = () => new OwneyError("DEPOSIT_IN_PROGRESS", "The saved deposit does not match this request. Check its status before depositing again.");
|
|
9028
|
+
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();
|
|
9029
|
+
const candidates = agentId ? [this.getAgent(agentId)] : this.getEligibleAgents(chainId, asset);
|
|
9030
|
+
const wallets = await Promise.all(candidates.map(async (agent) => {
|
|
9031
|
+
this.validateAssetSupport(agent, chainId, asset);
|
|
9032
|
+
const wallet = await (agent.getFundingWallet ? agent.getFundingWallet(state, chainId, asset) : agent.getUserProfile(state, chainId).then((profile) => profile.smartWallet)).catch(() => void 0);
|
|
9033
|
+
return { agent, wallet };
|
|
9034
|
+
}));
|
|
9035
|
+
if (this.state !== state || this.state.chainId !== chainId)
|
|
9036
|
+
throw new OwneyError("NOT_CONNECTED", "Wallet changed while recovering the deposit.");
|
|
9037
|
+
const usedAgents = /* @__PURE__ */ new Set();
|
|
9038
|
+
const legs = pending.transfers.map((transfer) => {
|
|
9039
|
+
const matches = wallets.filter((value) => value.wallet?.toLowerCase() === transfer.to.toLowerCase());
|
|
9040
|
+
if (matches.length !== 1 || usedAgents.has(matches[0].agent.id)) throw invalid2();
|
|
9041
|
+
const { agent } = matches[0];
|
|
9042
|
+
usedAgents.add(agent.id);
|
|
9043
|
+
return {
|
|
9044
|
+
id: agent.id,
|
|
9045
|
+
amount: transfer.amount,
|
|
9046
|
+
run: (callback) => withFailureReporting(
|
|
9047
|
+
this.apiKey,
|
|
9048
|
+
agent.id,
|
|
9049
|
+
() => agent.deposit(state, chainId, transfer.amount, asset, callback, onProgress),
|
|
9050
|
+
this.routingApiBaseUrl
|
|
9051
|
+
)
|
|
9052
|
+
};
|
|
9053
|
+
});
|
|
9054
|
+
const batchTransfer2 = getDepositBatchTransfer(effectiveCallback);
|
|
9055
|
+
if (!batchTransfer2) throw invalid2();
|
|
9056
|
+
const result = await runAgentDepositBatch(chainId, legs, batchTransfer2);
|
|
9057
|
+
return agentId ? result.agentResults[agentId] : result;
|
|
9058
|
+
}
|
|
8561
9059
|
if (agentId) {
|
|
8562
9060
|
if (this.isAgentDisabled(agentId)) {
|
|
8563
9061
|
throw new OwneyError(
|
|
@@ -8579,7 +9077,8 @@ var OwneySDK = class {
|
|
|
8579
9077
|
depositCallback,
|
|
8580
9078
|
onProgress,
|
|
8581
9079
|
() => paidFallbackAgents.add(agent.id),
|
|
8582
|
-
!!options.resumeTxHash
|
|
9080
|
+
!!options.resumeTxHash,
|
|
9081
|
+
checkpointPaid
|
|
8583
9082
|
);
|
|
8584
9083
|
}
|
|
8585
9084
|
const totalAmount = BigInt(amount);
|
|
@@ -8681,7 +9180,8 @@ var OwneySDK = class {
|
|
|
8681
9180
|
depositCallback,
|
|
8682
9181
|
onProgress,
|
|
8683
9182
|
() => paidFallbackAgents.add(agent.id),
|
|
8684
|
-
!!options.resumeTxHash
|
|
9183
|
+
!!options.resumeTxHash,
|
|
9184
|
+
checkpointPaid
|
|
8685
9185
|
);
|
|
8686
9186
|
} catch (error) {
|
|
8687
9187
|
if (Object.keys(agentResults).length === 0) throw error;
|
|
@@ -8701,12 +9201,22 @@ var OwneySDK = class {
|
|
|
8701
9201
|
}
|
|
8702
9202
|
return { agentResults };
|
|
8703
9203
|
} catch (error) {
|
|
9204
|
+
if (checkpointFailure && !(error instanceof OwneyError && error.details?.notSubmitted === false)) {
|
|
9205
|
+
error = error instanceof OwneyError && error.code === "DEPOSIT_PARTIAL_FAILURE" ? new OwneyError(
|
|
9206
|
+
error.code,
|
|
9207
|
+
"Some deposits completed before another agent could be submitted.",
|
|
9208
|
+
{ ...error.details, cause: checkpointFailure },
|
|
9209
|
+
error.agentId
|
|
9210
|
+
) : checkpointFailure;
|
|
9211
|
+
if (!options.resumeTxHash) for (const evidence of checkpointFailedEvidence)
|
|
9212
|
+
notifyFunding(onProgress, { ...evidence, transfer: "failed" });
|
|
9213
|
+
}
|
|
8704
9214
|
if (!depositCallback && onProgress && !options.resumeTxHash) {
|
|
8705
9215
|
const ids = agentId ? [agentId] : this.getEligibleAgents(chainId, asset).map((agent) => agent.id);
|
|
8706
9216
|
for (const id of ids) {
|
|
8707
9217
|
const evidence = [...prepared.values()].find((value) => value.agentId === id);
|
|
8708
|
-
if (paidFallbackAgents.has(id) || evidence?.transfer === "confirmed" || evidence?.transfer === "failed") continue;
|
|
8709
9218
|
const rejected = error instanceof OwneyError && error.details?.notSubmitted === true;
|
|
9219
|
+
if (!rejected && paidFallbackAgents.has(id) || evidence?.transfer === "confirmed" || evidence?.transfer === "failed") continue;
|
|
8710
9220
|
if (!rejected && (evidence?.txHash || evidence?.userOpHash || evidence?.callsId)) continue;
|
|
8711
9221
|
notifyFunding(onProgress, { ...evidence ?? {
|
|
8712
9222
|
agentId: id,
|
|
@@ -8749,11 +9259,11 @@ var OwneySDK = class {
|
|
|
8749
9259
|
* propagates unchanged. Scoped per agent invocation so one agent's failure
|
|
8750
9260
|
* doesn't force a retry of sibling agents in a multi-agent split.
|
|
8751
9261
|
*/
|
|
8752
|
-
async depositWithFallback(agent, state, chainId, amount, asset, effectiveCallback, appCallback, onProgress, onPaidFallback, resumeOnly = false) {
|
|
9262
|
+
async depositWithFallback(agent, state, chainId, amount, asset, effectiveCallback, appCallback, onProgress, onPaidFallback, resumeOnly = false, onBeforeSubmission) {
|
|
8753
9263
|
const attempt = (callback) => withFailureReporting(
|
|
8754
9264
|
this.apiKey,
|
|
8755
9265
|
agent.id,
|
|
8756
|
-
() => onProgress ? agent.deposit(state, chainId, amount, asset, callback, onProgress) : agent.deposit(state, chainId, amount, asset, callback),
|
|
9266
|
+
() => onBeforeSubmission ? agent.deposit(state, chainId, amount, asset, callback, onProgress, onBeforeSubmission) : onProgress ? agent.deposit(state, chainId, amount, asset, callback, onProgress) : agent.deposit(state, chainId, amount, asset, callback),
|
|
8757
9267
|
this.routingApiBaseUrl
|
|
8758
9268
|
);
|
|
8759
9269
|
let approvalAttempted = false;
|
|
@@ -8974,9 +9484,36 @@ var OwneySDK = class {
|
|
|
8974
9484
|
const token = SupportedAssets.find((t) => t.chainId === chainId && t.symbol === evidence.token);
|
|
8975
9485
|
if (!token) throw new OwneyError("CHAIN_UNSUPPORTED", "Unsupported funding asset.");
|
|
8976
9486
|
const rpc2 = this.getPaidRpcClient(chainId);
|
|
8977
|
-
|
|
9487
|
+
let receipt;
|
|
9488
|
+
try {
|
|
9489
|
+
receipt = await rpc2.getTransactionReceipt({ hash: evidence.txHash });
|
|
9490
|
+
} catch (error) {
|
|
9491
|
+
if (direction === "deposit") {
|
|
9492
|
+
const expired = await releaseExpiredTokenBatch({
|
|
9493
|
+
apiKey: this.apiKey,
|
|
9494
|
+
baseUrl: this.routingApiBaseUrl,
|
|
9495
|
+
owner: state.walletAddress,
|
|
9496
|
+
chainId,
|
|
9497
|
+
token: token.address,
|
|
9498
|
+
pub: rpc2,
|
|
9499
|
+
expectedTxHash: evidence.txHash
|
|
9500
|
+
});
|
|
9501
|
+
assertCurrent();
|
|
9502
|
+
if (expired?.transfers.some((transfer) => transfer.to.toLowerCase() === agentWallet.toLowerCase() && transfer.amount === evidence.intendedAmount))
|
|
9503
|
+
return {
|
|
9504
|
+
...evidence,
|
|
9505
|
+
agentWallet,
|
|
9506
|
+
transfer: "failed",
|
|
9507
|
+
delivery: "not-applicable",
|
|
9508
|
+
registration: "not-applicable",
|
|
9509
|
+
confirmedAmount: "0",
|
|
9510
|
+
blockNumber: expired.blockNumber.toString()
|
|
9511
|
+
};
|
|
9512
|
+
}
|
|
9513
|
+
throw error;
|
|
9514
|
+
}
|
|
8978
9515
|
assertCurrent();
|
|
8979
|
-
let verified = inspectFundingReceipt(receipt, { ...evidence, agentWallet }, token.address, direction);
|
|
9516
|
+
let verified = inspectFundingReceipt(receipt, { ...evidence, agentWallet }, token.address, direction, options);
|
|
8980
9517
|
if (direction === "withdraw" && evidence.agentId === "yieldseeker" && verified.transfer === "unknown" && verified.confirmedAmount && BigInt(verified.confirmedAmount) > 0n) {
|
|
8981
9518
|
const transaction = await rpc2.getTransaction({ hash: evidence.txHash });
|
|
8982
9519
|
assertCurrent();
|
|
@@ -9150,9 +9687,11 @@ var OwneySDK = class {
|
|
|
9150
9687
|
return page;
|
|
9151
9688
|
}
|
|
9152
9689
|
async recoverDepositRegistration(evidence) {
|
|
9690
|
+
const { state, assertCurrent } = this.captureReadScope(evidence.chainId);
|
|
9153
9691
|
const verified = await this.inspectFunding(evidence, "deposit");
|
|
9692
|
+
assertCurrent();
|
|
9154
9693
|
if (verified.agentId !== "zyfai") return verified;
|
|
9155
|
-
return this.getAgent("zyfai").retryDepositRegistration(
|
|
9694
|
+
return this.getAgent("zyfai").retryDepositRegistration(state, verified);
|
|
9156
9695
|
}
|
|
9157
9696
|
// --- Fund operations ---
|
|
9158
9697
|
/** On-chain version and ownership status for this owner's Yieldseeker agent. */
|
|
@@ -9198,10 +9737,24 @@ var OwneySDK = class {
|
|
|
9198
9737
|
* @returns {AgentWithdrawResult} for a single agent, or {OwneyWithdrawResult} with per-agent results
|
|
9199
9738
|
*/
|
|
9200
9739
|
async withdraw(options) {
|
|
9740
|
+
if (options.amount !== void 0 && !isFundingAmount(options.amount))
|
|
9741
|
+
throw new OwneyError(
|
|
9742
|
+
"WITHDRAW_INVALID_AMOUNT",
|
|
9743
|
+
"Withdrawal amount must be a positive base-unit integer.",
|
|
9744
|
+
{ phase: "prepare", rejectedBeforeSubmission: true }
|
|
9745
|
+
);
|
|
9201
9746
|
const state = this.requireState();
|
|
9202
9747
|
const chainId = this.requireChainId();
|
|
9748
|
+
const submissionKey = `${state.walletAddress.toLowerCase()}:${chainId}:${options.asset.toUpperCase()}`;
|
|
9749
|
+
if (this.withdrawalSubmissions.has(submissionKey))
|
|
9750
|
+
throw new OwneyError(
|
|
9751
|
+
"WITHDRAW_IN_PROGRESS",
|
|
9752
|
+
"A withdrawal request is already running.",
|
|
9753
|
+
{ chainId, asset: options.asset, phase: "prepare", rejectedBeforeSubmission: true }
|
|
9754
|
+
);
|
|
9203
9755
|
const ids = options.agentId ? [options.agentId] : this.getActiveAgentIds().filter((id) => !options.excludeAgentIds?.includes(id));
|
|
9204
9756
|
const attempted = /* @__PURE__ */ new Set();
|
|
9757
|
+
this.withdrawalSubmissions.add(submissionKey);
|
|
9205
9758
|
try {
|
|
9206
9759
|
return await this.withdrawFromAgents(options, state, chainId, attempted);
|
|
9207
9760
|
} catch (error) {
|
|
@@ -9218,6 +9771,8 @@ var OwneySDK = class {
|
|
|
9218
9771
|
});
|
|
9219
9772
|
}
|
|
9220
9773
|
throw error;
|
|
9774
|
+
} finally {
|
|
9775
|
+
this.withdrawalSubmissions.delete(submissionKey);
|
|
9221
9776
|
}
|
|
9222
9777
|
}
|
|
9223
9778
|
async withdrawFromAgents(options, state, chainId, attempted) {
|
|
@@ -9256,7 +9811,19 @@ var OwneySDK = class {
|
|
|
9256
9811
|
};
|
|
9257
9812
|
};
|
|
9258
9813
|
const submissionEvidence = /* @__PURE__ */ new Map();
|
|
9814
|
+
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)));
|
|
9815
|
+
const throwUnconfirmed = (agentErrors2) => {
|
|
9816
|
+
const pending = pendingSubmissions();
|
|
9817
|
+
if (Object.keys(pending).length)
|
|
9818
|
+
throw new OwneyError(
|
|
9819
|
+
"WITHDRAW_UNCONFIRMED",
|
|
9820
|
+
"The withdrawal was submitted, but its outcome could not be confirmed yet.",
|
|
9821
|
+
{ asset, amount, agentErrors: agentErrors2, agentFailures, pendingSubmissions: pending }
|
|
9822
|
+
);
|
|
9823
|
+
};
|
|
9259
9824
|
const submit = async (agent, requested2) => {
|
|
9825
|
+
if (this.state !== state || this.state.chainId !== chainId)
|
|
9826
|
+
throw new OwneyError("NOT_CONNECTED", "Wallet connection changed before withdrawal submission.");
|
|
9260
9827
|
attempted.add(agent.id);
|
|
9261
9828
|
let evidence = {
|
|
9262
9829
|
agentId: agent.id,
|
|
@@ -9268,12 +9835,16 @@ var OwneySDK = class {
|
|
|
9268
9835
|
registration: "not-applicable",
|
|
9269
9836
|
delivery: "pending"
|
|
9270
9837
|
};
|
|
9838
|
+
let adapterReported = false;
|
|
9271
9839
|
const progress = (next) => {
|
|
9840
|
+
if (next.agentId !== agent.id || next.chainId !== chainId || next.token !== token || next.walletAddress.toLowerCase() !== state.walletAddress.toLowerCase()) return;
|
|
9841
|
+
adapterReported = true;
|
|
9272
9842
|
evidence = { ...evidence, ...next };
|
|
9273
9843
|
submissionEvidence.set(agent.id, evidence);
|
|
9274
9844
|
notifyFunding(options.onProgress, evidence);
|
|
9275
9845
|
};
|
|
9276
9846
|
progress(evidence);
|
|
9847
|
+
adapterReported = false;
|
|
9277
9848
|
try {
|
|
9278
9849
|
if (options.onBeforeSubmission)
|
|
9279
9850
|
return await agent.withdraw(
|
|
@@ -9287,7 +9858,7 @@ var OwneySDK = class {
|
|
|
9287
9858
|
);
|
|
9288
9859
|
return await (options.gasMode === void 0 ? agent.withdraw(state, chainId, token, requested2, progress) : agent.withdraw(state, chainId, token, requested2, progress, options.gasMode));
|
|
9289
9860
|
} catch (error) {
|
|
9290
|
-
if (!evidence.txHash && !evidence.userOpHash && !evidence.callsId && (this.isUserRejectedWithdrawal(error) || /insufficient (balance|funds)/i.test(error instanceof Error ? error.message : "")))
|
|
9861
|
+
if (!adapterReported && !evidence.txHash && !evidence.userOpHash && !evidence.callsId && (this.isUserRejectedWithdrawal(error) || /insufficient (balance|funds)/i.test(error instanceof Error ? error.message : "")))
|
|
9291
9862
|
progress({ ...evidence, transfer: "failed", delivery: "failed" });
|
|
9292
9863
|
throw error;
|
|
9293
9864
|
}
|
|
@@ -9348,6 +9919,7 @@ var OwneySDK = class {
|
|
|
9348
9919
|
}
|
|
9349
9920
|
}
|
|
9350
9921
|
if (Object.keys(results2).length === 0) {
|
|
9922
|
+
throwUnconfirmed(agentErrors2);
|
|
9351
9923
|
if (Object.keys(agentErrors2).length === 0)
|
|
9352
9924
|
throw new OwneyError(
|
|
9353
9925
|
"WITHDRAW_INSUFFICIENT_BALANCE",
|
|
@@ -9368,7 +9940,7 @@ var OwneySDK = class {
|
|
|
9368
9940
|
);
|
|
9369
9941
|
}
|
|
9370
9942
|
const amountsKnown = Object.values(results2).every(
|
|
9371
|
-
(result) =>
|
|
9943
|
+
(result) => confirmedWithdrawalAmount(result) !== void 0
|
|
9372
9944
|
);
|
|
9373
9945
|
return {
|
|
9374
9946
|
agentResult: results2,
|
|
@@ -9387,6 +9959,13 @@ var OwneySDK = class {
|
|
|
9387
9959
|
asset,
|
|
9388
9960
|
assetInfo.decimals
|
|
9389
9961
|
);
|
|
9962
|
+
for (const entry of balances) if (entry.invalidBalance) {
|
|
9963
|
+
if (!unavailableAgents.includes(entry.agent)) unavailableAgents.push(entry.agent);
|
|
9964
|
+
aggregated.agentErrors = {
|
|
9965
|
+
...aggregated.agentErrors,
|
|
9966
|
+
[entry.agent.id]: "Provider returned an invalid withdrawal balance."
|
|
9967
|
+
};
|
|
9968
|
+
}
|
|
9390
9969
|
const indexedAvailable = balances.reduce((sum, entry) => sum + entry.balance, 0n);
|
|
9391
9970
|
await Promise.all(balances.map(async (entry) => {
|
|
9392
9971
|
if (entry.balance !== 0n && indexedAvailable >= requested || !entry.agent.getWithdrawableBalance) return;
|
|
@@ -9399,7 +9978,7 @@ var OwneySDK = class {
|
|
|
9399
9978
|
if (this.isUserRejectedWithdrawal(originalFailure)) throw originalFailure;
|
|
9400
9979
|
if (entry.balance !== 0n && entry.agent.id !== "yieldseeker") {
|
|
9401
9980
|
const total = aggregated.agentBalances[entry.agent.id]?.assetBalances?.find((value) => value.chainId === chainId && value.asset.toUpperCase() === token);
|
|
9402
|
-
if (!total || (0,
|
|
9981
|
+
if (!total || (0, import_viem18.parseUnits)(total.amount, assetInfo.decimals) <= entry.balance) return;
|
|
9403
9982
|
}
|
|
9404
9983
|
try {
|
|
9405
9984
|
const otherAvailable = indexedAvailable - entry.balance;
|
|
@@ -9426,12 +10005,15 @@ var OwneySDK = class {
|
|
|
9426
10005
|
throw new OwneyError("NOT_CONNECTED", "Account changed while planning withdrawal.");
|
|
9427
10006
|
const unavailableAgentIds = unavailableAgents.map((agent) => agent.id);
|
|
9428
10007
|
const totalAvailable = balances.reduce((sum, x) => sum + x.balance, 0n);
|
|
9429
|
-
if (totalAvailable
|
|
10008
|
+
if (totalAvailable < requested && unavailableAgents.length > 0) {
|
|
9430
10009
|
throw new OwneyError(
|
|
9431
10010
|
"WITHDRAW_BALANCE_UNAVAILABLE",
|
|
9432
|
-
`Cannot
|
|
10011
|
+
`Cannot cover the requested withdrawal with verified available balances: ${unavailableAgentIds.join(", ")}.`,
|
|
9433
10012
|
{
|
|
9434
10013
|
asset,
|
|
10014
|
+
requested: amount,
|
|
10015
|
+
available: totalAvailable.toString(),
|
|
10016
|
+
rejectedBeforeSubmission: true,
|
|
9435
10017
|
unavailableAgents: unavailableAgentIds,
|
|
9436
10018
|
agentErrors: aggregated.agentErrors
|
|
9437
10019
|
}
|
|
@@ -9448,7 +10030,7 @@ var OwneySDK = class {
|
|
|
9448
10030
|
}
|
|
9449
10031
|
);
|
|
9450
10032
|
}
|
|
9451
|
-
const plannedTarget =
|
|
10033
|
+
const plannedTarget = requested;
|
|
9452
10034
|
const disabledBalances = balances.filter(
|
|
9453
10035
|
(b) => this.isAgentDisabled(b.agent.id)
|
|
9454
10036
|
);
|
|
@@ -9467,13 +10049,23 @@ var OwneySDK = class {
|
|
|
9467
10049
|
}));
|
|
9468
10050
|
const plans = [...disabledPlans, ...enabledPlans];
|
|
9469
10051
|
const orderedPlans = this.orderAgentsForWithdrawal(plans.map((p) => p.agent)).map((agent) => plans.find((plan) => plan.agent === agent));
|
|
10052
|
+
const assertPlan = () => {
|
|
10053
|
+
if (orderedPlans.some((plan) => plan.planned < 0n || plan.planned > plan.balance) || orderedPlans.reduce((sum, plan) => sum + plan.planned, 0n) > plannedTarget)
|
|
10054
|
+
throw new OwneyError(
|
|
10055
|
+
"WITHDRAW_BALANCE_UNAVAILABLE",
|
|
10056
|
+
"Withdrawal plan failed amount validation.",
|
|
10057
|
+
{ asset, rejectedBeforeSubmission: true }
|
|
10058
|
+
);
|
|
10059
|
+
};
|
|
10060
|
+
assertPlan();
|
|
9470
10061
|
const results = {};
|
|
9471
10062
|
const agentErrors = {
|
|
9472
10063
|
...aggregated.agentErrors ?? {}
|
|
9473
10064
|
};
|
|
9474
10065
|
for (let i = 0; i < orderedPlans.length; i++) {
|
|
9475
10066
|
const p = orderedPlans[i];
|
|
9476
|
-
|
|
10067
|
+
assertPlan();
|
|
10068
|
+
if (p.planned <= 0n) continue;
|
|
9477
10069
|
try {
|
|
9478
10070
|
results[p.agent.id] = await submit(p.agent, p.planned.toString());
|
|
9479
10071
|
notifyAgentResult(p.agent.id, results[p.agent.id]);
|
|
@@ -9497,6 +10089,7 @@ var OwneySDK = class {
|
|
|
9497
10089
|
}
|
|
9498
10090
|
}
|
|
9499
10091
|
if (Object.keys(results).length === 0) {
|
|
10092
|
+
throwUnconfirmed(agentErrors);
|
|
9500
10093
|
throw new OwneyError(
|
|
9501
10094
|
"WITHDRAW_ALL_FAILED",
|
|
9502
10095
|
`Failed to withdraw "${amount}" of "${asset}" from all eligible agents.`,
|
|
@@ -9514,13 +10107,17 @@ var OwneySDK = class {
|
|
|
9514
10107
|
const adjustment = result?.feeAdjustment;
|
|
9515
10108
|
const evidence = result?.evidence;
|
|
9516
10109
|
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
|
|
10110
|
+
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
10111
|
const fee = BigInt(adjustment.feeAmount);
|
|
9519
10112
|
const net = BigInt(result.amount);
|
|
9520
10113
|
const gross = BigInt(adjustment.grossAmount);
|
|
9521
10114
|
return fee > 0n && net > 0n && gross === plan.planned && net + fee === gross ? total + fee : total;
|
|
9522
10115
|
}, 0n);
|
|
9523
|
-
|
|
10116
|
+
const pendingAmount = orderedPlans.reduce((sum, plan) => {
|
|
10117
|
+
const evidence = results[plan.agent.id]?.evidence;
|
|
10118
|
+
return evidence && (evidence.transfer === "pending" || evidence.transfer === "unknown") && evidence.delivery !== "failed" ? sum + plan.planned : sum;
|
|
10119
|
+
}, 0n);
|
|
10120
|
+
if (withdrawn + verifiedFeeDeductions + pendingAmount < requested) {
|
|
9524
10121
|
throw new OwneyError(
|
|
9525
10122
|
"WITHDRAW_PARTIAL_FAILURE",
|
|
9526
10123
|
`Withdrew "${withdrawn.toString()}" of requested "${amount}" of "${asset}". One or more agents failed; remaining balance could not cover the shortfall.`,
|
|
@@ -9528,6 +10125,7 @@ var OwneySDK = class {
|
|
|
9528
10125
|
asset,
|
|
9529
10126
|
requested: amount,
|
|
9530
10127
|
withdrawn: withdrawn.toString(),
|
|
10128
|
+
pendingAmount: pendingAmount.toString(),
|
|
9531
10129
|
partialResults: results,
|
|
9532
10130
|
agentErrors,
|
|
9533
10131
|
agentFailures,
|
|
@@ -9535,7 +10133,7 @@ var OwneySDK = class {
|
|
|
9535
10133
|
}
|
|
9536
10134
|
);
|
|
9537
10135
|
}
|
|
9538
|
-
return { agentResult: results, totalWithdrawn: withdrawn.toString() };
|
|
10136
|
+
return { agentResult: results, totalWithdrawn: Object.values(results).every((result) => confirmedWithdrawalAmount(result) !== void 0) ? withdrawn.toString() : null };
|
|
9539
10137
|
}
|
|
9540
10138
|
// --- Portfolio reads ---
|
|
9541
10139
|
/**
|
|
@@ -9993,16 +10591,16 @@ var OwneySDK = class {
|
|
|
9993
10591
|
);
|
|
9994
10592
|
}
|
|
9995
10593
|
const provider = this.requireConnectedProvider();
|
|
9996
|
-
const walletChainClient = (0,
|
|
10594
|
+
const walletChainClient = (0, import_viem18.createPublicClient)({
|
|
9997
10595
|
chain: VIEM_CHAIN2[chainId],
|
|
9998
|
-
transport: (0,
|
|
10596
|
+
transport: (0, import_viem18.custom)(provider)
|
|
9999
10597
|
});
|
|
10000
10598
|
const publicClient = this.getPaidRpcClient(chainId);
|
|
10001
10599
|
const approvalAmount = permit2ApprovalAmount(requiredAmount);
|
|
10002
|
-
const wallet = (0,
|
|
10600
|
+
const wallet = (0, import_viem18.createWalletClient)({
|
|
10003
10601
|
account: state.walletAddress,
|
|
10004
10602
|
chain: VIEM_CHAIN2[chainId],
|
|
10005
|
-
transport: (0,
|
|
10603
|
+
transport: (0, import_viem18.custom)(provider)
|
|
10006
10604
|
});
|
|
10007
10605
|
await ensureWalletOnChain(walletChainClient, wallet, chainId);
|
|
10008
10606
|
const hash = await wallet.writeContract({
|
|
@@ -10164,7 +10762,7 @@ var OwneySDK = class {
|
|
|
10164
10762
|
};
|
|
10165
10763
|
|
|
10166
10764
|
// src/agents/zyfai/zyfai.siwx.ts
|
|
10167
|
-
var
|
|
10765
|
+
var import_viem19 = require("viem");
|
|
10168
10766
|
var import_siwe2 = require("siwe");
|
|
10169
10767
|
var import_sdk2 = require("@zyfai/sdk");
|
|
10170
10768
|
|
|
@@ -10291,7 +10889,7 @@ function buildSIWXConfig(deps) {
|
|
|
10291
10889
|
issuedAt,
|
|
10292
10890
|
toString() {
|
|
10293
10891
|
return new import_siwe2.SiweMessage({
|
|
10294
|
-
address: (0,
|
|
10892
|
+
address: (0, import_viem19.getAddress)(accountAddress),
|
|
10295
10893
|
chainId: numericChainId(chainId),
|
|
10296
10894
|
domain,
|
|
10297
10895
|
uri,
|