@owney/sdk 0.7.25-beta.16 → 0.7.25-beta.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1543,6 +1543,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
1543
1543
  earningsRefreshes = /* @__PURE__ */ new Map();
1544
1544
  earningsSnapshot = null;
1545
1545
  earningsGeneration = 0;
1546
+ balanceSnapshots = /* @__PURE__ */ new WeakMap();
1546
1547
  constructor(apiKey, rpcUrls, referralSource) {
1547
1548
  this.rpcUrls = resolveRpcUrls(rpcUrls);
1548
1549
  this.sdk = new ZyfaiSDK({
@@ -1746,7 +1747,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
1746
1747
  * chain/account switch fires the provider's `accountsChanged` →
1747
1748
  * `disconnectAccount` (nulls walletClient + authenticatedUserId) while our
1748
1749
  * own `connectAuth` guard still believes this chain is connected and
1749
- * early-returns. Without this, authenticated calls (depositFunds,
1750
+ * early-returns. Without this, authenticated calls (sendDeposit,
1750
1751
  * withdrawFunds) fail with "No account connected".
1751
1752
  */
1752
1753
  async ensureConnected(state, chainId) {
@@ -2368,7 +2369,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
2368
2369
  return { txHash, smartWallet, amount, evidence: evidence2 };
2369
2370
  }
2370
2371
  await this.ensureWalletDeployed(this.getAddress(), validChainId);
2371
- const raw2 = await this.sdk.depositFunds(
2372
+ const raw2 = await this.sdk.sendDeposit(
2372
2373
  this.getAddress(),
2373
2374
  validChainId,
2374
2375
  amount,
@@ -2384,7 +2385,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
2384
2385
  intendedAmount: amount,
2385
2386
  txHash: raw2.txHash,
2386
2387
  transfer: "unknown",
2387
- registration: "unknown",
2388
+ registration: raw2.registration ? "confirmed" : "unknown",
2388
2389
  delivery: "not-applicable"
2389
2390
  };
2390
2391
  notifyFunding(onProgress, evidence);
@@ -2692,10 +2693,37 @@ var ZyfaiAgent = class _ZyfaiAgent {
2692
2693
  }
2693
2694
  async getBalances(state, chainId) {
2694
2695
  const requestedAt = Date.now();
2696
+ const generation = this.earningsGeneration;
2695
2697
  const { smartWallet, chainId: validChainId } = await this.resolveSmartWallet(state, chainId);
2696
2698
  const raw2 = await this.sdk.getPortfolio(this.getAddress());
2697
2699
  const balance = mapBalances(raw2, validChainId, smartWallet);
2698
- return { ...balance, readMetadata: balance.readMetadata?.map((read2) => ({ ...read2, requestedAt })) };
2700
+ const reads = balance.readMetadata?.map((read2) => ({ ...read2, requestedAt })) ?? [];
2701
+ for (const asset of SupportedAssets.filter((item) => item.chainId === chainId)) {
2702
+ if (!reads.some((read2) => read2.chainId === chainId && read2.asset === asset.symbol) && hasEmptyWithdrawalSnapshot(raw2, chainId, asset.symbol)) {
2703
+ reads.push({ chainId, asset: asset.symbol, requestedAt, fetchedAt: Date.now(), positionsStatus: "available" });
2704
+ }
2705
+ }
2706
+ const result = { ...balance, readMetadata: reads };
2707
+ for (const read2 of reads) this.balanceSnapshots.set(read2, { raw: raw2, generation, owner: state.walletAddress.toLowerCase() });
2708
+ return result;
2709
+ }
2710
+ async verifyWithdrawalBalance(state, evidence, balance) {
2711
+ const read2 = balance.readMetadata?.find((item) => item.chainId === evidence.chainId && item.asset === evidence.token);
2712
+ const snapshot = read2 && this.balanceSnapshots.get(read2);
2713
+ const asset = SupportedAssets.find((item) => item.chainId === evidence.chainId && item.symbol === evidence.token);
2714
+ if (!snapshot || snapshot.generation !== this.earningsGeneration || snapshot.owner !== state.walletAddress.toLowerCase() || !read2 || !asset || !evidence.txHash || !evidence.blockNumber || !balance.smartWallet || balance.smartWallet.toLowerCase() !== evidence.agentWallet?.toLowerCase() || !hasEmptyWithdrawalSnapshot(snapshot.raw, evidence.chainId, evidence.token)) return void 0;
2715
+ const client = this.getPublicClient(evidence.chainId);
2716
+ const blockNumber = await client.getBlockNumber({ cacheTime: 0 });
2717
+ if (blockNumber < BigInt(evidence.blockNumber)) return void 0;
2718
+ const idle = await client.readContract({
2719
+ address: asset.address,
2720
+ abi: erc20Abi2,
2721
+ functionName: "balanceOf",
2722
+ args: [balance.smartWallet],
2723
+ blockNumber
2724
+ });
2725
+ if (idle !== 0n || snapshot.generation !== this.earningsGeneration || this.connectedAddress?.toLowerCase() !== snapshot.owner || this.connectedChainId !== evidence.chainId) return void 0;
2726
+ return { ...read2, withdrawalCheck: { txHash: evidence.txHash, blockNumber: blockNumber.toString() } };
2699
2727
  }
2700
2728
  earningsKey(state, chainId, smartWallet) {
2701
2729
  return JSON.stringify([
@@ -2901,10 +2929,11 @@ import {
2901
2929
  decodeEventLog as decodeEventLog2,
2902
2930
  encodeEventTopics,
2903
2931
  encodeFunctionData,
2904
- erc20Abi as erc20Abi3,
2905
- erc4626Abi,
2906
- getAddress as getAddress4,
2907
- isAddress as isAddress3
2932
+ erc20Abi as erc20Abi4,
2933
+ erc4626Abi as erc4626Abi2,
2934
+ getAddress as getAddress5,
2935
+ isAddress as isAddress3,
2936
+ parseUnits
2908
2937
  } from "viem";
2909
2938
  import { base as base4 } from "viem/chains";
2910
2939
 
@@ -3694,6 +3723,7 @@ function mapYieldseekerBalances(contexts) {
3694
3723
  chainId: context.agent.chainId,
3695
3724
  asset: context.asset,
3696
3725
  fetchedAt: context.fetchedAt,
3726
+ requestedAt: context.requestedAt,
3697
3727
  readVersion: context.readVersion,
3698
3728
  providerUpdatedAt: context.snapshot.updatedDate,
3699
3729
  snapshotId: String(context.snapshot.agentWalletSnapshotId),
@@ -4071,9 +4101,55 @@ function mapYieldseekerAgentApy(options, days) {
4071
4101
  };
4072
4102
  }
4073
4103
 
4104
+ // src/lib/remaining-vault-balance.ts
4105
+ import { erc20Abi as erc20Abi3, erc4626Abi, getAddress as getAddress2 } from "viem";
4106
+ async function remainingVaultBalance(client, wallet, asset, vaults, blockNumber) {
4107
+ const addresses = [...new Set(vaults.map((value) => value.toLowerCase()))];
4108
+ if (addresses.length > 64) return void 0;
4109
+ const batches = [];
4110
+ for (let index = 0; index < addresses.length; index += 10) batches.push(addresses.slice(index, index + 10));
4111
+ const values = await Promise.all(batches.map(async (batch) => {
4112
+ const balances = await client.multicall({
4113
+ blockNumber,
4114
+ allowFailure: true,
4115
+ contracts: batch.map((address) => ({
4116
+ address: getAddress2(address),
4117
+ abi: erc20Abi3,
4118
+ functionName: "balanceOf",
4119
+ args: [wallet]
4120
+ }))
4121
+ });
4122
+ if (balances.length !== batch.length) return void 0;
4123
+ const funded = [];
4124
+ for (let index = 0; index < batch.length; index++) {
4125
+ const result = balances[index];
4126
+ if (result?.status !== "success" || typeof result.result !== "bigint" || result.result < 0n) return void 0;
4127
+ if (result.result > 0n) funded.push({ address: getAddress2(batch[index]), shares: result.result });
4128
+ }
4129
+ if (!funded.length) return 0n;
4130
+ const valuations = await client.multicall({
4131
+ blockNumber,
4132
+ allowFailure: true,
4133
+ contracts: funded.flatMap(({ address, shares }) => [
4134
+ { address, abi: erc4626Abi, functionName: "asset" },
4135
+ { address, abi: erc4626Abi, functionName: "convertToAssets", args: [shares] }
4136
+ ])
4137
+ });
4138
+ if (valuations.length !== funded.length * 2) return void 0;
4139
+ let total = 0n;
4140
+ for (let index = 0; index < funded.length; index++) {
4141
+ const underlying = valuations[index * 2], value = valuations[index * 2 + 1];
4142
+ if (underlying?.status !== "success" || typeof underlying.result !== "string" || underlying.result.toLowerCase() !== asset.toLowerCase() || value?.status !== "success" || typeof value.result !== "bigint" || value.result < 0n) return void 0;
4143
+ total += value.result;
4144
+ }
4145
+ return total;
4146
+ }));
4147
+ return values.some((value) => value === void 0) ? void 0 : values.reduce((sum, value) => sum + value, 0n);
4148
+ }
4149
+
4074
4150
  // src/agents/yieldseeker/yieldseeker.wallet-version.ts
4075
4151
  import {
4076
- getAddress as getAddress2,
4152
+ getAddress as getAddress3,
4077
4153
  isAddressEqual,
4078
4154
  parseAbi as parseAbi3
4079
4155
  } from "viem";
@@ -4097,9 +4173,9 @@ function yieldseekerOwnerPath(code) {
4097
4173
  return !code || code === "0x" || /^0xef0100[0-9a-f]{40}$/i.test(code) ? "eoa" : "smart";
4098
4174
  }
4099
4175
  async function readYieldseekerWalletStatus(client, wallet, owner, asset, blockNumber) {
4100
- const agentWallet = getAddress2(wallet);
4101
- const expectedOwner = getAddress2(owner);
4102
- const expectedAsset = getAddress2(asset);
4176
+ const agentWallet = getAddress3(wallet);
4177
+ const expectedOwner = getAddress3(owner);
4178
+ const expectedAsset = getAddress3(asset);
4103
4179
  const [code, ownerCode, slot, actualOwner, index, actualAsset, actualFactory, latest] = await Promise.all([
4104
4180
  client.getBytecode({ address: agentWallet, blockNumber }),
4105
4181
  client.getBytecode({ address: expectedOwner, blockNumber }),
@@ -4113,7 +4189,7 @@ async function readYieldseekerWalletStatus(client, wallet, owner, asset, blockNu
4113
4189
  if (!code || code === "0x" || !slot || /^0x0+$/.test(slot)) {
4114
4190
  throw new Error("Yieldseeker wallet is not a deployed ERC1967 proxy");
4115
4191
  }
4116
- const implementation = getAddress2(`0x${slot.slice(-40)}`);
4192
+ const implementation = getAddress3(`0x${slot.slice(-40)}`);
4117
4193
  const mapped = await client.readContract({
4118
4194
  address: YIELDSEEKER_FACTORY,
4119
4195
  abi: factoryAbi,
@@ -4140,7 +4216,7 @@ var YIELDSEEKER_UPGRADE_ABI = walletAbi;
4140
4216
  import {
4141
4217
  createWalletClient as createWalletClient2,
4142
4218
  custom as custom2,
4143
- getAddress as getAddress3,
4219
+ getAddress as getAddress4,
4144
4220
  toHex
4145
4221
  } from "viem";
4146
4222
  import { getUserOperationHash as getUserOperationHash2 } from "viem/account-abstraction";
@@ -4192,6 +4268,14 @@ function sponsorError(message, safeToFallback, details = {}) {
4192
4268
  "yieldseeker"
4193
4269
  );
4194
4270
  }
4271
+ function assertIntentFresh(expiresAt) {
4272
+ if (!Number.isFinite(expiresAt) || Date.now() + 5e3 >= expiresAt * 1e3)
4273
+ throw sponsorError(
4274
+ "The withdrawal sponsorship request expired. Please try again.",
4275
+ true,
4276
+ { failureCode: "SPONSOR_INTENT_EXPIRED" }
4277
+ );
4278
+ }
4195
4279
  function providerReason(value) {
4196
4280
  if (typeof value !== "string") return void 0;
4197
4281
  return value.replace(/https?:\/\/\S+/gi, "[url]").replace(/0x[0-9a-fA-F]{40,}/g, "[hex]").replace(/[A-Za-z0-9_+=\/-]{48,}/g, "[token]").slice(0, 300);
@@ -4480,6 +4564,7 @@ async function submitEoa(input) {
4480
4564
  }
4481
4565
  const userOpHash = operationHash(operation);
4482
4566
  await assertOwnerSession(input.state, input.owner);
4567
+ assertIntentFresh(input.expiresAt);
4483
4568
  const wallet = createWalletClient2({
4484
4569
  account: input.owner,
4485
4570
  chain: base3,
@@ -4488,6 +4573,7 @@ async function submitEoa(input) {
4488
4573
  const signature = await wallet.signMessage({ message: { raw: userOpHash } });
4489
4574
  operation = { ...operation, signature };
4490
4575
  await assertOwnerSession(input.state, input.owner);
4576
+ assertIntentFresh(input.expiresAt);
4491
4577
  const userOperation = {
4492
4578
  sender: operation.sender,
4493
4579
  nonce: operation.nonce,
@@ -4565,6 +4651,7 @@ async function submitSmart(input) {
4565
4651
  throw sponsorError("This account cannot use a paymaster on Base.", true);
4566
4652
  await assertOwnerSession(input.state, input.owner);
4567
4653
  let sent;
4654
+ assertIntentFresh(input.expiresAt);
4568
4655
  const requestedId = toHex(globalThis.crypto.getRandomValues(new Uint8Array(32)));
4569
4656
  savePending(input.onPending, { callsId: requestedId }, true);
4570
4657
  await checkpoint(input.onBeforeSubmission, { callsId: requestedId });
@@ -4649,7 +4736,7 @@ async function submitSmart(input) {
4649
4736
  );
4650
4737
  }
4651
4738
  async function submitYieldseekerSponsoredWithdrawal(input) {
4652
- const owner = getAddress3(input.state.walletAddress);
4739
+ const owner = getAddress4(input.state.walletAddress);
4653
4740
  const { intent, rpcUrl } = await requestIntent({
4654
4741
  apiKey: input.apiKey,
4655
4742
  routingApiBaseUrl: input.routingApiBaseUrl,
@@ -4663,11 +4750,12 @@ async function submitYieldseekerSponsoredWithdrawal(input) {
4663
4750
  action: "withdraw",
4664
4751
  refreshYieldseekerSignature: input.refreshYieldseekerSignature
4665
4752
  });
4666
- const args = { ...input, owner, rpcUrl };
4753
+ assertIntentFresh(intent.expiresAt);
4754
+ const args = { ...input, owner, rpcUrl, expiresAt: intent.expiresAt };
4667
4755
  return intent.ownerPath === "eoa" ? submitEoa(args) : submitSmart(args);
4668
4756
  }
4669
4757
  async function submitYieldseekerSponsoredUpgrade(input) {
4670
- const owner = getAddress3(input.state.walletAddress);
4758
+ const owner = getAddress4(input.state.walletAddress);
4671
4759
  const { intent, rpcUrl } = await requestIntent({
4672
4760
  apiKey: input.apiKey,
4673
4761
  routingApiBaseUrl: input.routingApiBaseUrl,
@@ -4683,7 +4771,8 @@ async function submitYieldseekerSponsoredUpgrade(input) {
4683
4771
  });
4684
4772
  if (intent.ownerPath !== "smart")
4685
4773
  throw sponsorError("V1 upgrade sponsorship requires a Base Account owner.", true);
4686
- return submitSmart({ ...input, owner, rpcUrl });
4774
+ assertIntentFresh(intent.expiresAt);
4775
+ return submitSmart({ ...input, owner, rpcUrl, expiresAt: intent.expiresAt });
4687
4776
  }
4688
4777
 
4689
4778
  // src/agents/yieldseeker/yieldseeker.agent.ts
@@ -4784,6 +4873,8 @@ var YieldseekerAgent = class {
4784
4873
  transactionExecutor;
4785
4874
  unwindReceiptWaiter;
4786
4875
  agentContexts = /* @__PURE__ */ new Map();
4876
+ balanceContexts = /* @__PURE__ */ new WeakMap();
4877
+ balanceVaults = /* @__PURE__ */ new Map();
4787
4878
  users = /* @__PURE__ */ new Map();
4788
4879
  pendingAgents = /* @__PURE__ */ new Map();
4789
4880
  pendingWalletContexts = /* @__PURE__ */ new Map();
@@ -4829,8 +4920,8 @@ var YieldseekerAgent = class {
4829
4920
  if (useCachedV2 && cached && Date.now() - cached.at < 15 * 6e4) return { ...cached.status };
4830
4921
  const status = await readYieldseekerWalletStatus(
4831
4922
  this.getReceiptClient(),
4832
- getAddress4(context.wallet.walletAddress),
4833
- getAddress4(state.walletAddress),
4923
+ getAddress5(context.wallet.walletAddress),
4924
+ getAddress5(state.walletAddress),
4834
4925
  YIELDSEEKER_ASSET_METADATA[asset].address
4835
4926
  );
4836
4927
  this.rememberWalletStatus(key2, status);
@@ -5026,7 +5117,7 @@ var YieldseekerAgent = class {
5026
5117
  }
5027
5118
  } else {
5028
5119
  txHash = await this.submitTransaction(state, chainId, {
5029
- from: getAddress4(state.walletAddress),
5120
+ from: getAddress5(state.walletAddress),
5030
5121
  to: before.agentWallet,
5031
5122
  data,
5032
5123
  value: "0",
@@ -5049,6 +5140,7 @@ var YieldseekerAgent = class {
5049
5140
  }
5050
5141
  this.users.clear();
5051
5142
  this.agentContexts.clear();
5143
+ this.balanceVaults.clear();
5052
5144
  this.pendingAgents.clear();
5053
5145
  this.pendingWalletContexts.clear();
5054
5146
  this.readCache.clear();
@@ -5112,12 +5204,12 @@ var YieldseekerAgent = class {
5112
5204
  } else {
5113
5205
  try {
5114
5206
  txHash = await this.submitTransaction(state, chainId, {
5115
- from: getAddress4(state.walletAddress),
5207
+ from: getAddress5(state.walletAddress),
5116
5208
  to: YIELDSEEKER_ASSET_METADATA[asset].address,
5117
5209
  data: encodeFunctionData({
5118
- abi: erc20Abi3,
5210
+ abi: erc20Abi4,
5119
5211
  functionName: "transfer",
5120
- args: [getAddress4(context.wallet.walletAddress), BigInt(amount)]
5212
+ args: [getAddress5(context.wallet.walletAddress), BigInt(amount)]
5121
5213
  }),
5122
5214
  value: "0",
5123
5215
  chainId
@@ -5251,7 +5343,7 @@ var YieldseekerAgent = class {
5251
5343
  );
5252
5344
  const positionsRead = this.readWithdrawalPositions(state, chainId, context);
5253
5345
  const metadata = YIELDSEEKER_ASSET_METADATA[asset];
5254
- const agentWallet = getAddress4(context.wallet.walletAddress);
5346
+ const agentWallet = getAddress5(context.wallet.walletAddress);
5255
5347
  const readOwnerFunds = async (blockNumber) => {
5256
5348
  const feeTracker = await withPaidRpcDiagnostics(() => this.getReceiptClient().readContract({
5257
5349
  address: agentWallet,
@@ -5265,13 +5357,13 @@ var YieldseekerAgent = class {
5265
5357
  const [idle2, fees] = await Promise.all([
5266
5358
  withPaidRpcDiagnostics(() => this.getReceiptClient().readContract({
5267
5359
  address: metadata.address,
5268
- abi: erc20Abi3,
5360
+ abi: erc20Abi4,
5269
5361
  functionName: "balanceOf",
5270
5362
  args: [agentWallet],
5271
5363
  blockNumber
5272
5364
  }), chainId, "eth_call", this.id),
5273
5365
  withPaidRpcDiagnostics(() => this.getReceiptClient().readContract({
5274
- address: getAddress4(feeTracker),
5366
+ address: getAddress5(feeTracker),
5275
5367
  abi: YIELDSEEKER_FEE_TRACKER_ABI,
5276
5368
  functionName: "getFeesOwed",
5277
5369
  args: [agentWallet],
@@ -5313,7 +5405,7 @@ var YieldseekerAgent = class {
5313
5405
  let active = true;
5314
5406
  const checks = this.readVaultLiquidity(values.map((position2) => position2.yieldOption), agentWallet, blockNumber).catch(() => []);
5315
5407
  const reads = values.map(async (position2, index) => {
5316
- const address = getAddress4(position2.yieldOption.address);
5408
+ const address = getAddress5(position2.yieldOption.address);
5317
5409
  try {
5318
5410
  const group = (await checks).slice(index * 3, index * 3 + 3);
5319
5411
  if (!active || group.length !== 3 || group.some((value) => value.status !== "success")) return null;
@@ -5327,7 +5419,7 @@ var YieldseekerAgent = class {
5327
5419
  try {
5328
5420
  const value = await this.getReceiptClient().readContract({
5329
5421
  address,
5330
- abi: erc4626Abi,
5422
+ abi: erc4626Abi2,
5331
5423
  functionName,
5332
5424
  args: [shares],
5333
5425
  blockNumber
@@ -5540,7 +5632,7 @@ var YieldseekerAgent = class {
5540
5632
  delta: maxSettlementBasis.delta - payout,
5541
5633
  expectedNetDeposits: maxSettlementBasis.expectedNetDeposits - payout
5542
5634
  } : this.snapshotMovement(state, chainId, context, -payout);
5543
- const account = getAddress4(state.walletAddress);
5635
+ const account = getAddress5(state.walletAddress);
5544
5636
  let receipt;
5545
5637
  const base6 = { agentId: this.id, chainId, token: asset, walletAddress: state.walletAddress, agentWallet: context.wallet.walletAddress, intendedAmount: amount === void 0 ? "MAX" : payout.toString(), transfer: "pending", registration: "not-applicable", delivery: "pending" };
5546
5638
  const data = amount === void 0 ? encodeFunctionData({
@@ -5563,7 +5655,7 @@ var YieldseekerAgent = class {
5563
5655
  refreshYieldseekerSignature: (rejected) => this.auth.refreshToken(state, chainId, rejected),
5564
5656
  userId: context.user.userId,
5565
5657
  agentId: context.agent.agentId,
5566
- agentWallet: getAddress4(context.wallet.walletAddress),
5658
+ agentWallet: getAddress5(context.wallet.walletAddress),
5567
5659
  asset: metadata.address,
5568
5660
  callData: data,
5569
5661
  onPending: (pending) => notifyFunding(onProgress, { ...base6, ...pending }),
@@ -5578,7 +5670,7 @@ var YieldseekerAgent = class {
5578
5670
  onOwnerTransferAttempted?.();
5579
5671
  txHash = await this.submitTransaction(state, chainId, {
5580
5672
  from: account,
5581
- to: getAddress4(context.wallet.walletAddress),
5673
+ to: getAddress5(context.wallet.walletAddress),
5582
5674
  data,
5583
5675
  value: "0",
5584
5676
  chainId
@@ -5686,17 +5778,17 @@ var YieldseekerAgent = class {
5686
5778
  return proof.available;
5687
5779
  }
5688
5780
  async readVaultLiquidity(options, wallet, blockNumber) {
5689
- const owner = getAddress4(wallet);
5781
+ const owner = getAddress5(wallet);
5690
5782
  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));
5691
5783
  const results = await Promise.all(batches.map((batch) => this.getReceiptClient().multicall({
5692
5784
  blockNumber,
5693
5785
  allowFailure: true,
5694
5786
  contracts: batch.flatMap((option) => {
5695
- const address = getAddress4(option.address);
5787
+ const address = getAddress5(option.address);
5696
5788
  return [
5697
- { address, abi: erc4626Abi, functionName: "asset" },
5698
- { address, abi: erc20Abi3, functionName: "balanceOf", args: [owner] },
5699
- { address, abi: erc4626Abi, functionName: "maxWithdraw", args: [owner] }
5789
+ { address, abi: erc4626Abi2, functionName: "asset" },
5790
+ { address, abi: erc20Abi4, functionName: "balanceOf", args: [owner] },
5791
+ { address, abi: erc4626Abi2, functionName: "maxWithdraw", args: [owner] }
5700
5792
  ];
5701
5793
  })
5702
5794
  })));
@@ -5772,7 +5864,7 @@ var YieldseekerAgent = class {
5772
5864
  const read2 = async () => {
5773
5865
  const client = this.getReceiptClient();
5774
5866
  const blockNumber = await client.getBlockNumber({ cacheTime: 0 });
5775
- const wallet = getAddress4(context.wallet.walletAddress);
5867
+ const wallet = getAddress5(context.wallet.walletAddress);
5776
5868
  assertReadCurrent();
5777
5869
  if (typeof blockNumber !== "bigint") throw unavailable();
5778
5870
  const indexedPositions = this.validateWithdrawalPositions(positions ?? [], chainId, context.asset);
@@ -5786,7 +5878,7 @@ var YieldseekerAgent = class {
5786
5878
  this.readVaultLiquidity(options, wallet, blockNumber),
5787
5879
  client.readContract({
5788
5880
  address: metadata.address,
5789
- abi: erc20Abi3,
5881
+ abi: erc20Abi4,
5790
5882
  functionName: "balanceOf",
5791
5883
  args: [wallet],
5792
5884
  blockNumber
@@ -5801,7 +5893,7 @@ var YieldseekerAgent = class {
5801
5893
  if (typeof idle !== "bigint" || idle < 0n || !isAddress3(feeTracker) || /^0x0{40}$/i.test(feeTracker)) throw unavailable();
5802
5894
  assertReadCurrent();
5803
5895
  const fees = await client.readContract({
5804
- address: getAddress4(feeTracker),
5896
+ address: getAddress5(feeTracker),
5805
5897
  abi: YIELDSEEKER_FEE_TRACKER_ABI,
5806
5898
  functionName: "getFeesOwed",
5807
5899
  args: [wallet],
@@ -5812,9 +5904,15 @@ var YieldseekerAgent = class {
5812
5904
  const verifiedVaults = [];
5813
5905
  let deployed = 0n;
5814
5906
  const collect = (options2, results) => {
5907
+ assertReadCurrent();
5908
+ const known = this.balanceVaults.get(contextKey) ?? /* @__PURE__ */ new Set();
5909
+ this.balanceVaults.set(contextKey, known);
5815
5910
  let valid2 = true;
5816
5911
  options2.forEach((option, index) => {
5817
5912
  const group = results.slice(index * 3, index * 3 + 3);
5913
+ const shareProbe = group[1];
5914
+ if (shareProbe?.status === "success" && typeof shareProbe.result === "bigint" && shareProbe.result > 0n)
5915
+ known.add(option.address.toLowerCase());
5818
5916
  if (group.length !== 3 || group.some((value) => value.status !== "success")) {
5819
5917
  valid2 = false;
5820
5918
  return;
@@ -5893,7 +5991,59 @@ var YieldseekerAgent = class {
5893
5991
  async getBalances(state, chainId, asset) {
5894
5992
  this.assertChain(chainId);
5895
5993
  if (asset !== void 0) this.assertAsset(asset);
5896
- return mapYieldseekerBalances(await this.loadPortfolio(state, chainId, { asset, allowMissingPositions: true }));
5994
+ const contexts = await this.loadPortfolio(state, chainId, { asset, allowMissingPositions: true });
5995
+ const balance = mapYieldseekerBalances(contexts);
5996
+ for (const context of contexts) {
5997
+ const read2 = balance.readMetadata.find((item) => item.asset === context.asset);
5998
+ this.balanceContexts.set(read2, { context, generation: this.readGeneration });
5999
+ const key2 = this.contextKey(state, chainId, context.asset);
6000
+ const known = this.balanceVaults.get(key2) ?? /* @__PURE__ */ new Set();
6001
+ for (const position2 of context.positions) known.add(position2.yieldOption.address.toLowerCase());
6002
+ this.balanceVaults.set(key2, known);
6003
+ }
6004
+ return balance;
6005
+ }
6006
+ async verifyWithdrawalBalance(state, evidence, balance) {
6007
+ this.assertAsset(evidence.token);
6008
+ this.assertChain(evidence.chainId);
6009
+ const read2 = balance.readMetadata?.find((item) => item.chainId === evidence.chainId && item.asset === evidence.token);
6010
+ const cached = read2 && this.balanceContexts.get(read2);
6011
+ const context = cached?.generation === this.readGeneration ? cached.context : void 0;
6012
+ if (!context || context.positionsUnavailable || !read2 || !evidence.blockNumber || !evidence.txHash || context.wallet.walletAddress.toLowerCase() !== evidence.agentWallet?.toLowerCase()) return void 0;
6013
+ const key2 = this.contextKey(state, evidence.chainId, evidence.token);
6014
+ const generation = this.readGeneration, version = this.portfolioVersion(key2);
6015
+ if (read2.readVersion !== version) return void 0;
6016
+ const wallet = getAddress5(context.wallet.walletAddress);
6017
+ const asset = YIELDSEEKER_ASSET_METADATA[evidence.token];
6018
+ const client = this.getReceiptClient();
6019
+ const blockNumber = await client.getBlockNumber({ cacheTime: 0 });
6020
+ if (blockNumber < BigInt(evidence.blockNumber)) return void 0;
6021
+ const vaults = [...this.balanceVaults.get(key2) ?? []];
6022
+ const [invested, idle, tracker] = await Promise.all([
6023
+ remainingVaultBalance(client, wallet, asset.address, vaults, blockNumber),
6024
+ client.readContract({ address: asset.address, abi: erc20Abi4, functionName: "balanceOf", args: [wallet], blockNumber }),
6025
+ client.readContract({ address: wallet, abi: YIELDSEEKER_AGENT_WALLET_ABI, functionName: "feeTracker", blockNumber })
6026
+ ]);
6027
+ if (invested === void 0 || typeof idle !== "bigint" || idle < 0n || !isAddress3(tracker) || /^0x0{40}$/i.test(tracker)) return void 0;
6028
+ const fees = await client.readContract({
6029
+ address: tracker,
6030
+ abi: YIELDSEEKER_FEE_TRACKER_ABI,
6031
+ functionName: "getFeesOwed",
6032
+ args: [wallet],
6033
+ blockNumber
6034
+ });
6035
+ this.assertSession(generation, evidence.chainId, evidence.token);
6036
+ if (version !== this.portfolioVersion(key2) || typeof fees !== "bigint" || fees < 0n) return void 0;
6037
+ const total = idle + invested > fees ? idle + invested - fees : 0n;
6038
+ const displayed = balance.assetBalances?.find((item) => item.chainId === evidence.chainId && item.asset === evidence.token);
6039
+ if (!displayed || !evidence.confirmedAmount || !/^\d+$/.test(evidence.confirmedAmount)) return void 0;
6040
+ const amount = parseUnits(displayed.amount, asset.decimals);
6041
+ if (amount < 0n) return void 0;
6042
+ const displayUnit = evidence.token === "USDC" ? 5000n : 500000000000n;
6043
+ const movementUnit = BigInt(evidence.confirmedAmount) / 1000n;
6044
+ const tolerance = movementUnit < displayUnit ? movementUnit : displayUnit;
6045
+ if ((total > amount ? total - amount : amount - total) > tolerance) return void 0;
6046
+ return { ...read2, withdrawalCheck: { txHash: evidence.txHash, blockNumber: blockNumber.toString() } };
5897
6047
  }
5898
6048
  invalidateFundingRead(state, chainId, asset, refreshUntil = Date.now() + YIELDSEEKER_SETTLEMENT_WINDOW_MS) {
5899
6049
  this.assertAsset(asset);
@@ -5933,9 +6083,9 @@ var YieldseekerAgent = class {
5933
6083
  if (!context) return void 0;
5934
6084
  const idle = await withPaidRpcDiagnostics(() => this.getReceiptClient().readContract({
5935
6085
  address: YIELDSEEKER_ASSET_METADATA[asset].address,
5936
- abi: erc20Abi3,
6086
+ abi: erc20Abi4,
5937
6087
  functionName: "balanceOf",
5938
- args: [getAddress4(context.wallet.walletAddress)]
6088
+ args: [getAddress5(context.wallet.walletAddress)]
5939
6089
  }), chainId, "eth_call", this.id);
5940
6090
  this.assertSession(generation, chainId, asset);
5941
6091
  if (typeof idle !== "bigint" || idle < 0n) throw this.invalidResponse("wallet deposit balance");
@@ -6047,11 +6197,13 @@ var YieldseekerAgent = class {
6047
6197
  const pending = this.pendingReads.get(key2);
6048
6198
  if (pending) return pending;
6049
6199
  const generation = this.readGeneration;
6200
+ const requestedAt = Date.now();
6050
6201
  const request = Promise.resolve().then(read2).then((value) => {
6051
6202
  if (this.readGeneration === generation && this.pendingReads.get(key2) === request) {
6052
6203
  this.readCache.set(key2, {
6053
6204
  expiresAt: Date.now() + ttlMs,
6054
6205
  fetchedAt: Date.now(),
6206
+ requestedAt,
6055
6207
  value
6056
6208
  });
6057
6209
  }
@@ -6128,7 +6280,7 @@ var YieldseekerAgent = class {
6128
6280
  this.users.set(key2, persisted);
6129
6281
  return persisted;
6130
6282
  }
6131
- const walletAddress = getAddress4(state.walletAddress);
6283
+ const walletAddress = getAddress5(state.walletAddress);
6132
6284
  const generation = this.readGeneration;
6133
6285
  let user = null;
6134
6286
  try {
@@ -6420,6 +6572,7 @@ var YieldseekerAgent = class {
6420
6572
  ...context,
6421
6573
  snapshot: snapshot.agentSnapshot,
6422
6574
  fetchedAt: this.readCache.get(`snapshot:${contextKey}`)?.fetchedAt,
6575
+ requestedAt: this.readCache.get(`snapshot:${contextKey}`)?.requestedAt,
6423
6576
  readVersion: version,
6424
6577
  positionsUnavailable,
6425
6578
  ...portfolioParts
@@ -6619,7 +6772,7 @@ var YieldseekerAgent = class {
6619
6772
  return hash2;
6620
6773
  }
6621
6774
  this.assertTransaction(transaction, state, chainId);
6622
- const account = getAddress4(state.walletAddress);
6775
+ const account = getAddress5(state.walletAddress);
6623
6776
  const walletClient = createWalletClient3({
6624
6777
  account,
6625
6778
  chain: base4,
@@ -6637,7 +6790,7 @@ var YieldseekerAgent = class {
6637
6790
  const hash = await walletClient.sendTransaction({
6638
6791
  account,
6639
6792
  chain: base4,
6640
- to: getAddress4(transaction.to),
6793
+ to: getAddress5(transaction.to),
6641
6794
  data: transaction.data,
6642
6795
  value: BigInt(transaction.value)
6643
6796
  });
@@ -6741,7 +6894,7 @@ var YieldseekerAgent = class {
6741
6894
  return receipt;
6742
6895
  }
6743
6896
  assertTransaction(transaction, state, chainId) {
6744
- if (!transaction || typeof transaction.from !== "string" || !isAddress3(transaction.from) || typeof transaction.to !== "string" || !isAddress3(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 || getAddress4(transaction.from) !== getAddress4(state.walletAddress)) {
6897
+ if (!transaction || typeof transaction.from !== "string" || !isAddress3(transaction.from) || typeof transaction.to !== "string" || !isAddress3(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 || getAddress5(transaction.from) !== getAddress5(state.walletAddress)) {
6745
6898
  throw this.invalidResponse("transaction");
6746
6899
  }
6747
6900
  }
@@ -6900,7 +7053,7 @@ async function withFailureReporting(apiKey, agentType, fn, baseUrl) {
6900
7053
  }
6901
7054
 
6902
7055
  // src/lib/helpers/withdraw-helper.ts
6903
- import { parseUnits } from "viem";
7056
+ import { parseUnits as parseUnits2 } from "viem";
6904
7057
  function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
6905
7058
  const target = asset.toUpperCase();
6906
7059
  return agents.map((agent) => {
@@ -6908,7 +7061,7 @@ function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decima
6908
7061
  const tokenBalance = agentBalance?.tokens.find(
6909
7062
  (t) => t.chainId === chainId && t.asset.toUpperCase() === target
6910
7063
  );
6911
- let balance = tokenBalance ? parseUnits(tokenBalance.amount, decimals) : 0n;
7064
+ let balance = tokenBalance ? parseUnits2(tokenBalance.amount, decimals) : 0n;
6912
7065
  if (agent.balanceComposition === "tokens-plus-positions") {
6913
7066
  const chainNameById = {
6914
7067
  1: "ETHEREUM",
@@ -6920,14 +7073,14 @@ function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decima
6920
7073
  const positionChain = position2.chain.trim().toUpperCase();
6921
7074
  const matchesChain = positionChain === String(chainId) || targetChain !== void 0 && positionChain === targetChain;
6922
7075
  if (!matchesChain || position2.asset.toUpperCase() !== target) continue;
6923
- balance += position2.withdrawableAmountRaw !== void 0 ? BigInt(position2.withdrawableAmountRaw) : parseUnits(position2.amount, decimals);
7076
+ balance += position2.withdrawableAmountRaw !== void 0 ? BigInt(position2.withdrawableAmountRaw) : parseUnits2(position2.amount, decimals);
6924
7077
  }
6925
7078
  }
6926
7079
  const assetTotal = agentBalance?.assetBalances?.find(
6927
7080
  (t) => t.chainId === chainId && t.asset.toUpperCase() === target
6928
7081
  );
6929
7082
  if (assetTotal) {
6930
- const total = parseUnits(assetTotal.amount, decimals);
7083
+ const total = parseUnits2(assetTotal.amount, decimals);
6931
7084
  if (total < balance) balance = total > 0n ? total : 0n;
6932
7085
  }
6933
7086
  return { agent, balance };
@@ -7087,7 +7240,7 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
7087
7240
 
7088
7241
  // src/client.ts
7089
7242
  import {
7090
- parseUnits as parseUnits2,
7243
+ parseUnits as parseUnits3,
7091
7244
  createPublicClient as createPublicClient4,
7092
7245
  createWalletClient as createWalletClient4,
7093
7246
  custom as custom4
@@ -7247,7 +7400,40 @@ async function execute(i, key2, plan) {
7247
7400
  const send = async (initial) => {
7248
7401
  let body = initial;
7249
7402
  save(key2, body);
7403
+ const rejectedPreparation = (error) => !body.serializedTransaction && error instanceof OwneyError && typeof error.details?.statusCode === "number" && error.details.statusCode >= 400 && error.details.statusCode < 500 && ![408, 429].includes(error.details.statusCode);
7250
7404
  try {
7405
+ const post = () => postSponsorBatchTransfer({ apiKey: i.apiKey, baseUrl: i.baseUrl, body });
7406
+ const pendingError = (phase, txHash) => new OwneyError(
7407
+ "DEPOSIT_IN_PROGRESS",
7408
+ phase === "approval" ? "Deposit approval is awaiting confirmation. Retry the same amount to continue it." : "Deposit is awaiting confirmation. Its transaction is still being checked.",
7409
+ { sponsorPending: true, phase, txHash, safeToFallback: false }
7410
+ );
7411
+ const assertReceipt = (receipt, phase) => {
7412
+ if (receipt.status !== "success") throw new OwneyError(
7413
+ "SPONSOR_REQUEST_FAILED",
7414
+ `Sponsored ${phase} transaction reverted. Please retry.`,
7415
+ { notSubmitted: true, safeToFallback: false }
7416
+ );
7417
+ };
7418
+ const waitForConfirmation = async (phase, hash2) => {
7419
+ let receipt;
7420
+ try {
7421
+ receipt = await i.pub.waitForTransactionReceipt({ hash: hash2, confirmations: 1, timeout: 9e4, checkReplacement: false });
7422
+ } catch {
7423
+ receipt = await i.pub.getTransactionReceipt({ hash: hash2 }).catch(() => void 0);
7424
+ }
7425
+ if (!receipt) throw pendingError(phase, hash2);
7426
+ assertReceipt(receipt, phase);
7427
+ };
7428
+ const postSigned = async (phase, hash2) => {
7429
+ try {
7430
+ return await post();
7431
+ } catch (error) {
7432
+ if (rejectedPreparation(error) || error instanceof OwneyError && error.details?.notSubmitted === true) throw error;
7433
+ await waitForConfirmation(phase, hash2);
7434
+ return void 0;
7435
+ }
7436
+ };
7251
7437
  if (body.erc2612Permit && !body.serializedPermitTransaction) {
7252
7438
  const preparedPermit = await postSponsorBatchTransfer({
7253
7439
  apiKey: i.apiKey,
@@ -7265,11 +7451,17 @@ async function execute(i, key2, plan) {
7265
7451
  save(key2, body);
7266
7452
  }
7267
7453
  if (!body.serializedTransaction) {
7268
- const prepared = await postSponsorBatchTransfer({
7269
- apiKey: i.apiKey,
7270
- baseUrl: i.baseUrl,
7271
- body
7272
- });
7454
+ const permitHash = body.serializedPermitTransaction ? keccak256(body.serializedPermitTransaction) : void 0;
7455
+ let prepared = permitHash ? await postSigned("approval", permitHash) : await post();
7456
+ if (prepared?.status === "pending") {
7457
+ if (!permitHash || prepared.phase !== "approval" || prepared.txHash !== permitHash)
7458
+ throw new Error("Sponsorship approval does not match the pending transaction.");
7459
+ await waitForConfirmation("approval", permitHash);
7460
+ prepared = void 0;
7461
+ }
7462
+ if (!prepared) prepared = await post();
7463
+ if (prepared.status === "pending" && permitHash && prepared.phase === "approval" && prepared.txHash === permitHash)
7464
+ throw pendingError("approval", permitHash);
7273
7465
  if (!prepared.serializedTransaction || keccak256(prepared.serializedTransaction) !== prepared.txHash)
7274
7466
  throw new Error(
7275
7467
  "Sponsorship API did not return a valid prepared transaction."
@@ -7284,19 +7476,30 @@ async function execute(i, key2, plan) {
7284
7476
  i.onSubmitted?.(keccak256(body.serializedTransaction));
7285
7477
  } catch {
7286
7478
  }
7287
- const result = await postSponsorBatchTransfer({
7288
- apiKey: i.apiKey,
7289
- baseUrl: i.baseUrl,
7290
- body
7291
- });
7292
- if (result.txHash !== keccak256(body.serializedTransaction))
7293
- throw new Error(
7294
- "Sponsorship receipt does not match the pending transaction."
7295
- );
7479
+ const hash = keccak256(body.serializedTransaction);
7480
+ const existing = await i.pub.getTransactionReceipt({ hash }).catch(() => void 0);
7481
+ if (existing) {
7482
+ assertReceipt(existing, "deposit");
7483
+ void post().catch(() => void 0);
7484
+ clear(key2);
7485
+ return hash;
7486
+ }
7487
+ let result = await postSigned("deposit", hash);
7488
+ if (result?.status === "pending" && result.phase === "approval" && body.serializedPermitTransaction && result.txHash === keccak256(body.serializedPermitTransaction)) {
7489
+ await waitForConfirmation("approval", result.txHash);
7490
+ result = await postSigned("deposit", hash);
7491
+ if (result?.status === "pending" && result.phase === "approval" && result.txHash === keccak256(body.serializedPermitTransaction)) throw pendingError("approval", result.txHash);
7492
+ }
7493
+ if (result) {
7494
+ if (result.txHash !== hash || result.status === "pending" && result.phase !== "deposit")
7495
+ throw new Error("Sponsorship receipt does not match the pending transaction.");
7496
+ if (result.status === "pending") await waitForConfirmation("deposit", hash);
7497
+ }
7498
+ if (!result || result.status === "pending") void post().catch(() => void 0);
7296
7499
  clear(key2);
7297
- return result.txHash;
7500
+ return hash;
7298
7501
  } catch (error) {
7299
- if (!body.serializedTransaction || error instanceof OwneyError && error.details?.notSubmitted === true)
7502
+ if (!body.serializedTransaction && !body.serializedPermitTransaction || rejectedPreparation(error) || error instanceof OwneyError && error.details?.notSubmitted === true)
7300
7503
  clear(key2);
7301
7504
  throw error;
7302
7505
  }
@@ -7502,7 +7705,7 @@ async function runAgentDepositBatch(chainId, legs, transfer) {
7502
7705
  }
7503
7706
 
7504
7707
  // src/lib/sponsored-calls-deposit.ts
7505
- import { encodeFunctionData as encodeFunctionData2, erc20Abi as erc20Abi4, toHex as toHex2 } from "viem";
7708
+ import { encodeFunctionData as encodeFunctionData2, erc20Abi as erc20Abi5, toHex as toHex2 } from "viem";
7506
7709
  var DEFAULT_POLL_INTERVAL_MS = 1500;
7507
7710
  var DEFAULT_MAX_POLLS = 30;
7508
7711
  async function paymasterSupported(provider, owner, chainId) {
@@ -7548,7 +7751,7 @@ function makeSponsoredCallsCallback(deps) {
7548
7751
  to: token,
7549
7752
  value: "0x0",
7550
7753
  data: encodeFunctionData2({
7551
- abi: erc20Abi4,
7754
+ abi: erc20Abi5,
7552
7755
  functionName: "transfer",
7553
7756
  args: [transfer.to, BigInt(transfer.amount)]
7554
7757
  })
@@ -7749,6 +7952,7 @@ var OwneySDK = class {
7749
7952
  cachedSponsoredCallsCallbacks = /* @__PURE__ */ new Map();
7750
7953
  agentReads = new AgentReads();
7751
7954
  recoveredFundingReads = /* @__PURE__ */ new Set();
7955
+ fundingBalanceChecks = /* @__PURE__ */ new WeakMap();
7752
7956
  activationChecks = /* @__PURE__ */ new Map();
7753
7957
  readAgent(agent, method, fetch2, params = null) {
7754
7958
  const key2 = JSON.stringify([
@@ -7794,6 +7998,7 @@ var OwneySDK = class {
7794
7998
  }
7795
7999
  this.agentReads.clearInFlight();
7796
8000
  this.activationChecks.clear();
8001
+ this.fundingBalanceChecks = /* @__PURE__ */ new WeakMap();
7797
8002
  this.state = { provider, walletAddress, chainId: null };
7798
8003
  this.cachedSponsoredCallback = null;
7799
8004
  this.cachedWethSponsoredCallback = null;
@@ -7805,6 +8010,7 @@ var OwneySDK = class {
7805
8010
  */
7806
8011
  async disconnect() {
7807
8012
  this.state = null;
8013
+ this.fundingBalanceChecks = /* @__PURE__ */ new WeakMap();
7808
8014
  for (const agent of this.agents.values()) {
7809
8015
  await agent.disconnect();
7810
8016
  }
@@ -8705,9 +8911,8 @@ var OwneySDK = class {
8705
8911
  verified = inspectFundingReceipt(receipt, { ...evidence, agentWallet, intendedAmount: "MAX" }, token.address, direction);
8706
8912
  }
8707
8913
  const key2 = `${state.walletAddress.toLowerCase()}:${chainId}:${evidence.agentId}:${evidence.token}:${evidence.txHash}`;
8708
- if ((verified.transfer === "confirmed" || verified.transfer === "failed" && verified.confirmedAmount === "0") && !this.recoveredFundingReads.has(key2)) {
8709
- if (options.refreshBalance !== false)
8710
- agent.invalidateFundingRead?.(state, chainId, evidence.token, options.balanceRefreshUntil);
8914
+ if (options.refreshBalance !== false && (verified.transfer === "confirmed" || verified.transfer === "failed" && verified.confirmedAmount === "0") && !this.recoveredFundingReads.has(key2)) {
8915
+ agent.invalidateFundingRead?.(state, chainId, evidence.token, options.balanceRefreshUntil);
8711
8916
  this.recoveredFundingReads.add(key2);
8712
8917
  if (this.recoveredFundingReads.size > 256) this.recoveredFundingReads.delete(this.recoveredFundingReads.values().next().value);
8713
8918
  }
@@ -8815,6 +9020,44 @@ var OwneySDK = class {
8815
9020
  assertCurrent();
8816
9021
  return true;
8817
9022
  }
9023
+ /** Optional post-payout display proof; receipt verification and the provider
9024
+ * adapter must agree before attaching it to this exact balance object. */
9025
+ async verifyWithdrawalBalance(evidence, balance) {
9026
+ const { state, chainId, assertCurrent } = this.captureReadScope(evidence.chainId);
9027
+ const agent = this.getAgent(evidence.agentId);
9028
+ if (!agent.verifyWithdrawalBalance || !evidence.txHash || state.walletAddress.toLowerCase() !== evidence.walletAddress.toLowerCase()) return balance;
9029
+ const key2 = `${state.walletAddress.toLowerCase()}:${chainId}:${evidence.agentId}:${evidence.token}:${evidence.txHash}:${evidence.intendedAmount}`;
9030
+ const checks = this.fundingBalanceChecks.get(balance) ?? /* @__PURE__ */ new Map();
9031
+ this.fundingBalanceChecks.set(balance, checks);
9032
+ const previous = checks.get(key2);
9033
+ if (previous) {
9034
+ const result2 = await previous;
9035
+ assertCurrent();
9036
+ return result2;
9037
+ }
9038
+ let timer;
9039
+ const read2 = async () => {
9040
+ const verified = await this.inspectFunding(evidence, "withdraw", { refreshBalance: false });
9041
+ assertCurrent();
9042
+ if (verified.transfer !== "confirmed" || verified.delivery !== "confirmed" || !verified.blockNumber) return balance;
9043
+ const metadata = await agent.verifyWithdrawalBalance(state, verified, balance);
9044
+ assertCurrent();
9045
+ if (!metadata || metadata.chainId !== chainId || metadata.asset.toUpperCase() !== evidence.token || !metadata.withdrawalCheck || metadata.withdrawalCheck.txHash.toLowerCase() !== verified.txHash?.toLowerCase() || BigInt(metadata.withdrawalCheck.blockNumber) < BigInt(verified.blockNumber)) return balance;
9046
+ return { ...balance, readMetadata: [
9047
+ ...(balance.readMetadata ?? []).filter((item) => !(item.chainId === chainId && item.asset.toUpperCase() === evidence.token)),
9048
+ metadata
9049
+ ] };
9050
+ };
9051
+ const pending = Promise.race([read2(), new Promise((resolve) => {
9052
+ timer = setTimeout(() => resolve(balance), 2e3);
9053
+ })]).catch(() => balance).finally(() => {
9054
+ if (timer) clearTimeout(timer);
9055
+ });
9056
+ checks.set(key2, pending);
9057
+ const result = await pending;
9058
+ assertCurrent();
9059
+ return result;
9060
+ }
8818
9061
  /** A display acknowledgement controls polling only; it never confirms a financial outcome. */
8819
9062
  endFundingBalanceRefresh(evidence, read2) {
8820
9063
  const { state, chainId } = this.captureReadScope(evidence.chainId);
@@ -9083,7 +9326,7 @@ var OwneySDK = class {
9083
9326
  if (this.isUserRejectedWithdrawal(originalFailure)) throw originalFailure;
9084
9327
  if (entry.balance !== 0n && entry.agent.id !== "yieldseeker") {
9085
9328
  const total = aggregated.agentBalances[entry.agent.id]?.assetBalances?.find((value) => value.chainId === chainId && value.asset.toUpperCase() === token);
9086
- if (!total || parseUnits2(total.amount, assetInfo.decimals) <= entry.balance) return;
9329
+ if (!total || parseUnits3(total.amount, assetInfo.decimals) <= entry.balance) return;
9087
9330
  }
9088
9331
  try {
9089
9332
  const otherAvailable = indexedAvailable - entry.balance;
@@ -9858,7 +10101,7 @@ var OwneySDK = class {
9858
10101
  };
9859
10102
 
9860
10103
  // src/agents/zyfai/zyfai.siwx.ts
9861
- import { getAddress as getAddress5 } from "viem";
10104
+ import { getAddress as getAddress6 } from "viem";
9862
10105
  import { SiweMessage as SiweMessage2 } from "siwe";
9863
10106
  import { ZyfaiSDK as ZyfaiSDK2 } from "@zyfai/sdk";
9864
10107
 
@@ -9985,7 +10228,7 @@ function buildSIWXConfig(deps) {
9985
10228
  issuedAt,
9986
10229
  toString() {
9987
10230
  return new SiweMessage2({
9988
- address: getAddress5(accountAddress),
10231
+ address: getAddress6(accountAddress),
9989
10232
  chainId: numericChainId(chainId),
9990
10233
  domain,
9991
10234
  uri,