@owney/sdk 0.7.25-beta.12 → 0.7.25-beta.13

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
@@ -2603,14 +2603,14 @@ var ZyfaiAgent = class _ZyfaiAgent {
2603
2603
  // src/agents/yieldseeker/yieldseeker.agent.ts
2604
2604
  import {
2605
2605
  createPublicClient as createPublicClient3,
2606
- createWalletClient as createWalletClient2,
2607
- custom as custom2,
2606
+ createWalletClient as createWalletClient3,
2607
+ custom as custom3,
2608
2608
  encodeFunctionData,
2609
2609
  erc20Abi as erc20Abi2,
2610
- getAddress as getAddress2,
2610
+ getAddress as getAddress4,
2611
2611
  isAddress as isAddress2
2612
2612
  } from "viem";
2613
- import { base as base3 } from "viem/chains";
2613
+ import { base as base4 } from "viem/chains";
2614
2614
 
2615
2615
  // src/lib/chain-guard.ts
2616
2616
  var CHAIN_NAMES = {
@@ -2653,10 +2653,10 @@ import { bytesToHex } from "viem";
2653
2653
  // src/lib/sponsor-client.ts
2654
2654
  var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
2655
2655
  async function postPaymasterIntent(input) {
2656
- const base5 = input.baseUrl ?? ROUTING_API_BASE_URL;
2656
+ const base6 = input.baseUrl ?? ROUTING_API_BASE_URL;
2657
2657
  let res;
2658
2658
  try {
2659
- res = await fetch(`${base5}/api/v1/sponsor/paymaster-intent`, {
2659
+ res = await fetch(`${base6}/api/v1/sponsor/paymaster-intent`, {
2660
2660
  method: "POST",
2661
2661
  headers: {
2662
2662
  "content-type": "application/json",
@@ -2692,11 +2692,11 @@ async function postPaymasterIntent(input) {
2692
2692
  return parsed.data;
2693
2693
  }
2694
2694
  async function getSponsorRelayerAddress(input) {
2695
- const base5 = input.baseUrl ?? ROUTING_API_BASE_URL;
2695
+ const base6 = input.baseUrl ?? ROUTING_API_BASE_URL;
2696
2696
  let res;
2697
2697
  try {
2698
2698
  res = await fetch(
2699
- `${base5}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
2699
+ `${base6}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
2700
2700
  {
2701
2701
  headers: { "x-owney-api-key": input.apiKey }
2702
2702
  }
@@ -3722,6 +3722,404 @@ function mapYieldseekerAgentApy(options, days) {
3722
3722
  };
3723
3723
  }
3724
3724
 
3725
+ // src/agents/yieldseeker/yieldseeker.wallet-version.ts
3726
+ import {
3727
+ getAddress as getAddress2,
3728
+ isAddressEqual,
3729
+ parseAbi as parseAbi3
3730
+ } from "viem";
3731
+ var YIELDSEEKER_FACTORY = "0x9c7410a0faCAC60850C46eE5b58B518daec95130";
3732
+ var YIELDSEEKER_V1_IMPLEMENTATION = "0x32403455357589523435dB18b414057D7cE05051";
3733
+ var YIELDSEEKER_V2_IMPLEMENTATION = "0x613Db9c924ADB7A7A90c11b02Cce20c913E3Fe50";
3734
+ var ERC1967_IMPLEMENTATION_SLOT = "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc";
3735
+ var walletAbi = parseAbi3([
3736
+ "function owner() view returns (address)",
3737
+ "function ownerAgentIndex() view returns (uint256)",
3738
+ "function baseAsset() view returns (address)",
3739
+ "function FACTORY() view returns (address)",
3740
+ "function upgradeToLatest()"
3741
+ ]);
3742
+ var factoryAbi = parseAbi3([
3743
+ "function userWallets(address owner, uint256 index) view returns (address)",
3744
+ "function agentWalletImplementation() view returns (address)"
3745
+ ]);
3746
+ function yieldseekerOwnerPath(code) {
3747
+ return !code || code === "0x" || /^0xef0100[0-9a-f]{40}$/i.test(code) ? "eoa" : "smart";
3748
+ }
3749
+ async function readYieldseekerWalletStatus(client, wallet, owner, asset) {
3750
+ const agentWallet = getAddress2(wallet);
3751
+ const expectedOwner = getAddress2(owner);
3752
+ const expectedAsset = getAddress2(asset);
3753
+ const [code, ownerCode, slot, actualOwner, index, actualAsset, actualFactory, latest] = await Promise.all([
3754
+ client.getBytecode({ address: agentWallet }),
3755
+ client.getBytecode({ address: expectedOwner }),
3756
+ client.getStorageAt({ address: agentWallet, slot: ERC1967_IMPLEMENTATION_SLOT }),
3757
+ client.readContract({ address: agentWallet, abi: walletAbi, functionName: "owner" }),
3758
+ client.readContract({ address: agentWallet, abi: walletAbi, functionName: "ownerAgentIndex" }),
3759
+ client.readContract({ address: agentWallet, abi: walletAbi, functionName: "baseAsset" }),
3760
+ client.readContract({ address: agentWallet, abi: walletAbi, functionName: "FACTORY" }),
3761
+ client.readContract({ address: YIELDSEEKER_FACTORY, abi: factoryAbi, functionName: "agentWalletImplementation" })
3762
+ ]);
3763
+ if (!code || code === "0x" || !slot || /^0x0+$/.test(slot)) {
3764
+ throw new Error("Yieldseeker wallet is not a deployed ERC1967 proxy");
3765
+ }
3766
+ const implementation = getAddress2(`0x${slot.slice(-40)}`);
3767
+ const mapped = await client.readContract({
3768
+ address: YIELDSEEKER_FACTORY,
3769
+ abi: factoryAbi,
3770
+ functionName: "userWallets",
3771
+ args: [expectedOwner, index]
3772
+ });
3773
+ const verified = isAddressEqual(actualOwner, expectedOwner) && isAddressEqual(actualAsset, expectedAsset) && isAddressEqual(actualFactory, YIELDSEEKER_FACTORY) && isAddressEqual(mapped, agentWallet);
3774
+ const version = !verified ? "unknown" : isAddressEqual(implementation, YIELDSEEKER_V2_IMPLEMENTATION) ? "v2" : isAddressEqual(implementation, YIELDSEEKER_V1_IMPLEMENTATION) ? "v1" : "unknown";
3775
+ return {
3776
+ agentWallet,
3777
+ owner: actualOwner,
3778
+ ownerPath: yieldseekerOwnerPath(ownerCode),
3779
+ asset: actualAsset,
3780
+ implementation,
3781
+ version,
3782
+ verified,
3783
+ upgradeAvailable: version === "v1" && isAddressEqual(latest, YIELDSEEKER_V2_IMPLEMENTATION)
3784
+ };
3785
+ }
3786
+ var YIELDSEEKER_UPGRADE_ABI = walletAbi;
3787
+
3788
+ // src/agents/yieldseeker/yieldseeker.sponsored-withdraw.ts
3789
+ import {
3790
+ createWalletClient as createWalletClient2,
3791
+ custom as custom2,
3792
+ getAddress as getAddress3,
3793
+ toHex
3794
+ } from "viem";
3795
+ import { getUserOperationHash } from "viem/account-abstraction";
3796
+ import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
3797
+ import { base as base3 } from "viem/chains";
3798
+ var ENTRY_POINT_V06 = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789";
3799
+ var USER_OP_FEE_HEADROOM = 2n;
3800
+ var ENTRY_POINT_NONCE_ABI = [
3801
+ { type: "function", name: "getNonce", stateMutability: "view", inputs: [
3802
+ { name: "sender", type: "address" },
3803
+ { name: "key", type: "uint192" }
3804
+ ], outputs: [{ type: "uint256" }] }
3805
+ ];
3806
+ var DEFAULT_ROUTING_API = "https://owney-routing-api-243946518160.europe-west4.run.app";
3807
+ var SIMULATION_ACCOUNT = privateKeyToAccount(generatePrivateKey());
3808
+ function operationHash(operation) {
3809
+ return getUserOperationHash({
3810
+ chainId: 8453,
3811
+ entryPointAddress: ENTRY_POINT_V06,
3812
+ entryPointVersion: "0.6",
3813
+ userOperation: {
3814
+ sender: operation.sender,
3815
+ nonce: BigInt(operation.nonce),
3816
+ initCode: operation.initCode,
3817
+ callData: operation.callData,
3818
+ callGasLimit: BigInt(operation.callGasLimit),
3819
+ verificationGasLimit: BigInt(operation.verificationGasLimit),
3820
+ preVerificationGas: BigInt(operation.preVerificationGas),
3821
+ maxFeePerGas: BigInt(operation.maxFeePerGas),
3822
+ maxPriorityFeePerGas: BigInt(operation.maxPriorityFeePerGas),
3823
+ paymasterAndData: operation.paymasterAndData,
3824
+ signature: operation.signature
3825
+ }
3826
+ });
3827
+ }
3828
+ function sponsorError(message, safeToFallback, details = {}) {
3829
+ return new OwneyError(
3830
+ "SPONSOR_REQUEST_FAILED",
3831
+ message,
3832
+ { safeToFallback, ...details },
3833
+ "yieldseeker"
3834
+ );
3835
+ }
3836
+ async function requestIntent(input) {
3837
+ const baseUrl = (input.routingApiBaseUrl ?? DEFAULT_ROUTING_API).replace(/\/$/, "");
3838
+ let response;
3839
+ try {
3840
+ response = await fetch(`${baseUrl}/api/v1/sponsor/yieldseeker-withdraw/intent`, {
3841
+ method: "POST",
3842
+ headers: {
3843
+ "content-type": "application/json",
3844
+ "x-owney-api-key": input.apiKey,
3845
+ Authorization: `Signature ${input.yieldseekerSignature}`
3846
+ },
3847
+ body: JSON.stringify({
3848
+ chainId: 8453,
3849
+ owner: input.owner,
3850
+ recipient: input.owner,
3851
+ agentWallet: input.agentWallet,
3852
+ asset: input.asset,
3853
+ callData: input.callData,
3854
+ action: input.action,
3855
+ yieldseekerUserId: input.userId,
3856
+ yieldseekerAgentId: input.agentId
3857
+ })
3858
+ });
3859
+ } catch {
3860
+ throw sponsorError("Withdrawal sponsorship could not be requested.", true);
3861
+ }
3862
+ const envelope = await response.json().catch(() => null);
3863
+ const intent = envelope?.data;
3864
+ if (!response.ok || !envelope?.success || !intent?.intent || !["eoa", "smart"].includes(intent.ownerPath)) {
3865
+ throw sponsorError(
3866
+ "Withdrawal sponsorship is currently unavailable.",
3867
+ true,
3868
+ { statusCode: response.status }
3869
+ );
3870
+ }
3871
+ const url = new URL(`${baseUrl}/api/v1/sponsor/yieldseeker-withdraw/rpc`);
3872
+ url.searchParams.set("intent", intent.intent);
3873
+ return { intent, rpcUrl: url.toString() };
3874
+ }
3875
+ async function rpc(url, method, params, phase) {
3876
+ let response;
3877
+ try {
3878
+ response = await fetch(url, {
3879
+ method: "POST",
3880
+ headers: { "content-type": "application/json" },
3881
+ body: JSON.stringify({ jsonrpc: "2.0", id: 1, method, params })
3882
+ });
3883
+ } catch {
3884
+ throw sponsorError("Withdrawal sponsorship request status is unknown.", phase === "prepare");
3885
+ }
3886
+ const payload = await response.json().catch(() => null);
3887
+ if (!response.ok || payload?.error || payload?.result === void 0) {
3888
+ const rejection = payload?.error;
3889
+ const definitiveRejection = phase === "send" && response.status < 500 && !!rejection && (rejection.data?.rejectedBeforeSubmission === true || [-32501, -32502, -32503, -32504, -32505, -32507].includes(rejection.code ?? 0) || /maxFeePerGas.*(?:too low|lower than|less than|must be at least)/i.test(rejection.message ?? ""));
3890
+ throw sponsorError(
3891
+ phase !== "prepare" && !definitiveRejection ? "Sponsored withdrawal submission status is unknown." : "Withdrawal sponsorship was declined before submission.",
3892
+ phase === "prepare" || definitiveRejection,
3893
+ { statusCode: response.status, rpcCode: payload?.error?.code, rpcMethod: method }
3894
+ );
3895
+ }
3896
+ return payload.result;
3897
+ }
3898
+ async function waitForTransaction(client, txHash) {
3899
+ const receipt = await client.waitForTransactionReceipt({ hash: txHash, confirmations: 1 });
3900
+ if (receipt.status !== "success")
3901
+ throw new OwneyError(
3902
+ "AGENT_TRANSACTION_REVERTED",
3903
+ `Yieldseeker withdrawal reverted (${txHash}).`,
3904
+ { transactionHash: txHash },
3905
+ "yieldseeker"
3906
+ );
3907
+ return receipt;
3908
+ }
3909
+ async function submitEoa(input) {
3910
+ let nonce;
3911
+ let fees;
3912
+ try {
3913
+ nonce = await input.client.readContract({
3914
+ address: ENTRY_POINT_V06,
3915
+ abi: ENTRY_POINT_NONCE_ABI,
3916
+ functionName: "getNonce",
3917
+ args: [input.agentWallet, 0n]
3918
+ });
3919
+ fees = await input.client.estimateFeesPerGas();
3920
+ } catch {
3921
+ throw sponsorError("Could not prepare the sponsored withdrawal.", true);
3922
+ }
3923
+ if (fees.maxFeePerGas === void 0 || fees.maxPriorityFeePerGas === void 0)
3924
+ throw sponsorError("Base did not return EIP-1559 gas fees.", true);
3925
+ let operation = {
3926
+ sender: input.agentWallet,
3927
+ nonce: toHex(nonce),
3928
+ initCode: "0x",
3929
+ callData: input.callData,
3930
+ callGasLimit: toHex(3e5),
3931
+ verificationGasLimit: toHex(3e5),
3932
+ preVerificationGas: toHex(6e4),
3933
+ maxFeePerGas: toHex(fees.maxFeePerGas * USER_OP_FEE_HEADROOM),
3934
+ maxPriorityFeePerGas: toHex(fees.maxPriorityFeePerGas),
3935
+ paymasterAndData: "0x",
3936
+ signature: "0x"
3937
+ };
3938
+ operation.signature = await SIMULATION_ACCOUNT.signMessage({ message: { raw: operationHash(operation) } });
3939
+ const stub = await rpc(
3940
+ input.rpcUrl,
3941
+ "pm_getPaymasterStubData",
3942
+ [operation, ENTRY_POINT_V06, toHex(8453), {}],
3943
+ "prepare"
3944
+ );
3945
+ if (!stub.paymasterAndData?.startsWith("0x"))
3946
+ throw sponsorError("CDP did not return v0.6 paymaster data.", true);
3947
+ operation = { ...operation, paymasterAndData: stub.paymasterAndData };
3948
+ operation.signature = await SIMULATION_ACCOUNT.signMessage({ message: { raw: operationHash(operation) } });
3949
+ const gas = await rpc(input.rpcUrl, "eth_estimateUserOperationGas", [operation, ENTRY_POINT_V06], "prepare");
3950
+ if (!gas.callGasLimit || !gas.verificationGasLimit || !gas.preVerificationGas)
3951
+ throw sponsorError("CDP did not return UserOperation gas estimates.", true);
3952
+ operation = { ...operation, ...gas };
3953
+ if (!stub.isFinal) {
3954
+ const final = await rpc(
3955
+ input.rpcUrl,
3956
+ "pm_getPaymasterData",
3957
+ [operation, ENTRY_POINT_V06, toHex(8453), {}],
3958
+ "prepare"
3959
+ );
3960
+ if (!final.paymasterAndData?.startsWith("0x"))
3961
+ throw sponsorError("CDP did not return final paymaster data.", true);
3962
+ operation = { ...operation, paymasterAndData: final.paymasterAndData };
3963
+ }
3964
+ const userOpHash = operationHash(operation);
3965
+ const wallet = createWalletClient2({
3966
+ account: input.owner,
3967
+ chain: base3,
3968
+ transport: custom2(input.state.provider)
3969
+ });
3970
+ const signature = await wallet.signMessage({ message: { raw: userOpHash } });
3971
+ operation = { ...operation, signature };
3972
+ input.onPending?.({ userOpHash });
3973
+ const submittedHash = await rpc(
3974
+ input.rpcUrl,
3975
+ "eth_sendUserOperation",
3976
+ [operation, ENTRY_POINT_V06],
3977
+ "send"
3978
+ );
3979
+ if (submittedHash.toLowerCase() !== userOpHash.toLowerCase())
3980
+ throw sponsorError(
3981
+ "Bundler returned a different UserOperation hash.",
3982
+ false,
3983
+ { userOpHash, submittedHash }
3984
+ );
3985
+ for (let poll = 0; poll < 40; poll++) {
3986
+ const response = await rpc(input.rpcUrl, "eth_getUserOperationReceipt", [userOpHash], "observe");
3987
+ const txHash = response?.receipt?.transactionHash;
3988
+ if (txHash) {
3989
+ input.onPending?.({ userOpHash, txHash });
3990
+ if (response?.success === false)
3991
+ throw new OwneyError(
3992
+ "AGENT_TRANSACTION_REVERTED",
3993
+ "Sponsored withdrawal execution reverted.",
3994
+ { userOpHash, transactionHash: txHash },
3995
+ "yieldseeker"
3996
+ );
3997
+ return { txHash, receipt: await waitForTransaction(input.client, txHash) };
3998
+ }
3999
+ await new Promise((resolve) => setTimeout(resolve, 1500));
4000
+ }
4001
+ throw sponsorError(
4002
+ "Sponsored withdrawal is still pending; check status before retrying.",
4003
+ false,
4004
+ { userOpHash }
4005
+ );
4006
+ }
4007
+ async function submitSmart(input) {
4008
+ let capabilities;
4009
+ try {
4010
+ capabilities = await input.state.provider.request({
4011
+ method: "wallet_getCapabilities",
4012
+ params: [input.owner]
4013
+ });
4014
+ } catch {
4015
+ throw sponsorError("This account cannot check paymaster support on Base.", true);
4016
+ }
4017
+ if (!capabilities?.[toHex(8453)]?.paymasterService?.supported && !capabilities?.["8453"]?.paymasterService?.supported)
4018
+ throw sponsorError("This account cannot use a paymaster on Base.", true);
4019
+ let sent;
4020
+ try {
4021
+ input.onPending?.({});
4022
+ } catch {
4023
+ throw sponsorError("Upgrade or withdrawal status cannot be saved.", true);
4024
+ }
4025
+ try {
4026
+ sent = await input.state.provider.request({
4027
+ method: "wallet_sendCalls",
4028
+ params: [{
4029
+ version: "2.0.0",
4030
+ from: input.owner,
4031
+ chainId: toHex(8453),
4032
+ atomicRequired: false,
4033
+ calls: [{ to: input.agentWallet, value: "0x0", data: input.callData }],
4034
+ capabilities: { paymasterService: { url: input.rpcUrl } }
4035
+ }]
4036
+ });
4037
+ } catch (error) {
4038
+ if (error?.code === 4001) throw error;
4039
+ if ([4200, -32601].includes(Number(error?.code)))
4040
+ throw sponsorError("This account does not support sponsored calls.", true);
4041
+ throw sponsorError("Wallet submission status is unknown. Check activity before retrying.", false);
4042
+ }
4043
+ const callsId = typeof sent === "string" ? sent : sent?.id;
4044
+ if (!callsId) throw sponsorError("Wallet returned no calls ID; submission status is unknown.", false);
4045
+ try {
4046
+ input.onPending?.({ callsId });
4047
+ } catch {
4048
+ throw sponsorError("Submitted call status could not be saved.", false, { callsId });
4049
+ }
4050
+ for (let poll = 0; poll < 40; poll++) {
4051
+ let status;
4052
+ try {
4053
+ status = await input.state.provider.request({
4054
+ method: "wallet_getCallsStatus",
4055
+ params: [callsId]
4056
+ });
4057
+ } catch {
4058
+ throw sponsorError("Sponsored withdrawal status is unknown.", false, { callsId });
4059
+ }
4060
+ if (status?.status === 400 || status?.status === 500)
4061
+ throw sponsorError(
4062
+ "Sponsored withdrawal failed in the wallet.",
4063
+ false,
4064
+ { callsId, executionFailed: true }
4065
+ );
4066
+ const txHash = status?.receipts?.[0]?.transactionHash;
4067
+ if (txHash) {
4068
+ try {
4069
+ input.onPending?.({ callsId, txHash });
4070
+ } catch {
4071
+ throw sponsorError(
4072
+ "Submitted call receipt could not be saved.",
4073
+ false,
4074
+ { callsId, txHash }
4075
+ );
4076
+ }
4077
+ return { txHash, receipt: await waitForTransaction(input.client, txHash) };
4078
+ }
4079
+ await new Promise((resolve) => setTimeout(resolve, 1500));
4080
+ }
4081
+ throw sponsorError(
4082
+ "Sponsored withdrawal is still pending; check status before retrying.",
4083
+ false,
4084
+ { callsId }
4085
+ );
4086
+ }
4087
+ async function submitYieldseekerSponsoredWithdrawal(input) {
4088
+ const owner = getAddress3(input.state.walletAddress);
4089
+ const { intent, rpcUrl } = await requestIntent({
4090
+ apiKey: input.apiKey,
4091
+ routingApiBaseUrl: input.routingApiBaseUrl,
4092
+ yieldseekerSignature: input.yieldseekerSignature,
4093
+ userId: input.userId,
4094
+ agentId: input.agentId,
4095
+ owner,
4096
+ agentWallet: input.agentWallet,
4097
+ asset: input.asset,
4098
+ callData: input.callData,
4099
+ action: "withdraw"
4100
+ });
4101
+ const args = { ...input, owner, rpcUrl };
4102
+ return intent.ownerPath === "eoa" ? submitEoa(args) : submitSmart(args);
4103
+ }
4104
+ async function submitYieldseekerSponsoredUpgrade(input) {
4105
+ const owner = getAddress3(input.state.walletAddress);
4106
+ const { intent, rpcUrl } = await requestIntent({
4107
+ apiKey: input.apiKey,
4108
+ routingApiBaseUrl: input.routingApiBaseUrl,
4109
+ yieldseekerSignature: input.yieldseekerSignature,
4110
+ userId: input.userId,
4111
+ agentId: input.agentId,
4112
+ owner,
4113
+ agentWallet: input.agentWallet,
4114
+ asset: input.asset,
4115
+ callData: input.callData,
4116
+ action: "upgrade"
4117
+ });
4118
+ if (intent.ownerPath !== "smart")
4119
+ throw sponsorError("V1 upgrade sponsorship requires a Base Account owner.", true);
4120
+ return submitSmart({ ...input, owner, rpcUrl });
4121
+ }
4122
+
3725
4123
  // src/agents/yieldseeker/yieldseeker.agent.ts
3726
4124
  var OWNEY_AGENT_NAME = "owney";
3727
4125
  var OWNEY_AGENT_RULE_PRESET = "explorative";
@@ -3794,7 +4192,11 @@ var YieldseekerAgent = class {
3794
4192
  api;
3795
4193
  auth;
3796
4194
  rpcUrls;
4195
+ owneyApiKey;
4196
+ routingApiBaseUrl;
3797
4197
  receiptClient;
4198
+ // A client preparation hint only; the routing API still checks live identity.
4199
+ withdrawalVersionCache = /* @__PURE__ */ new Map();
3798
4200
  transactionExecutor;
3799
4201
  unwindReceiptWaiter;
3800
4202
  agentContexts = /* @__PURE__ */ new Map();
@@ -3816,6 +4218,8 @@ var YieldseekerAgent = class {
3816
4218
  yieldOptions = /* @__PURE__ */ new Map();
3817
4219
  pendingYieldOptions = /* @__PURE__ */ new Map();
3818
4220
  constructor(owneyApiKey, options = {}) {
4221
+ this.owneyApiKey = owneyApiKey;
4222
+ this.routingApiBaseUrl = options.routingApiBaseUrl;
3819
4223
  this.api = new YieldseekerApiClient(
3820
4224
  owneyApiKey,
3821
4225
  options.baseUrl ?? getYieldseekerProxyBaseUrl(),
@@ -3827,10 +4231,182 @@ var YieldseekerAgent = class {
3827
4231
  this.unwindReceiptWaiter = options.unwindReceiptWaiter;
3828
4232
  }
3829
4233
  getReceiptClient() {
3830
- this.receiptClient ??= createPaidRpcClient(base3, this.rpcUrls);
4234
+ this.receiptClient ??= createPaidRpcClient(base4, this.rpcUrls);
3831
4235
  return this.receiptClient;
3832
4236
  }
4237
+ /** Reads the actual proxy implementation; Yieldseeker's API walletType is not a version check. */
4238
+ async getWalletStatus(state, chainId, asset, useCachedV2 = false) {
4239
+ this.assertChain(chainId);
4240
+ this.assertAsset(asset);
4241
+ const context = await this.findAgent(state, chainId, asset);
4242
+ if (!context) return null;
4243
+ const key2 = `${chainId}:${state.walletAddress.toLowerCase()}:${context.wallet.walletAddress.toLowerCase()}:${asset}`;
4244
+ const cached = this.withdrawalVersionCache.get(key2);
4245
+ if (useCachedV2 && cached && Date.now() - cached.at < 15 * 6e4) return { ...cached.status };
4246
+ const status = await readYieldseekerWalletStatus(
4247
+ this.getReceiptClient(),
4248
+ getAddress4(context.wallet.walletAddress),
4249
+ getAddress4(state.walletAddress),
4250
+ YIELDSEEKER_ASSET_METADATA[asset].address
4251
+ );
4252
+ if (status.verified && status.version === "v2") {
4253
+ this.withdrawalVersionCache.set(key2, { at: Date.now(), status: { ...status } });
4254
+ if (this.withdrawalVersionCache.size > 128)
4255
+ this.withdrawalVersionCache.delete(this.withdrawalVersionCache.keys().next().value);
4256
+ } else this.withdrawalVersionCache.delete(key2);
4257
+ return status;
4258
+ }
4259
+ /** Explicit owner action. This never runs as a side effect of withdrawal. */
4260
+ async upgradeWallet(state, chainId, asset, gasMode = "paid") {
4261
+ const before = await this.getWalletStatus(state, chainId, asset);
4262
+ if (!before?.verified || !before.upgradeAvailable) {
4263
+ throw new OwneyError(
4264
+ "WITHDRAW_FAILED",
4265
+ "This Yieldseeker wallet cannot be upgraded to the reviewed V2 implementation.",
4266
+ { version: before?.version ?? "missing" },
4267
+ this.id
4268
+ );
4269
+ }
4270
+ const data = encodeFunctionData({ abi: YIELDSEEKER_UPGRADE_ABI, functionName: "upgradeToLatest" });
4271
+ let txHash;
4272
+ if (gasMode === "sponsored") {
4273
+ if (before.ownerPath !== "smart")
4274
+ throw new OwneyError(
4275
+ "SPONSOR_REQUEST_FAILED",
4276
+ "EOA owners pay Base gas for the V1 upgrade.",
4277
+ { safeToFallback: true },
4278
+ this.id
4279
+ );
4280
+ let storage5;
4281
+ try {
4282
+ storage5 = typeof window === "undefined" ? void 0 : window.localStorage;
4283
+ } catch {
4284
+ storage5 = void 0;
4285
+ }
4286
+ if (!storage5)
4287
+ throw new OwneyError(
4288
+ "SPONSOR_REQUEST_FAILED",
4289
+ "Upgrade status cannot be saved in this browser.",
4290
+ { safeToFallback: true },
4291
+ this.id
4292
+ );
4293
+ const pendingKey = `owney.yieldseeker.upgrade:${state.walletAddress.toLowerCase()}:${before.agentWallet.toLowerCase()}`;
4294
+ let prior = null;
4295
+ let saved;
4296
+ try {
4297
+ saved = storage5.getItem(pendingKey);
4298
+ } catch {
4299
+ throw new OwneyError(
4300
+ "SPONSOR_REQUEST_FAILED",
4301
+ "Upgrade status cannot be read in this browser.",
4302
+ { safeToFallback: true },
4303
+ this.id
4304
+ );
4305
+ }
4306
+ try {
4307
+ prior = JSON.parse(saved ?? "null");
4308
+ } catch {
4309
+ prior = { callsId: void 0 };
4310
+ }
4311
+ if (prior) {
4312
+ if (!prior.callsId)
4313
+ throw new OwneyError(
4314
+ "SPONSOR_REQUEST_FAILED",
4315
+ "An earlier upgrade submission is unresolved. Check wallet activity before retrying.",
4316
+ { safeToFallback: false },
4317
+ this.id
4318
+ );
4319
+ let callsStatus;
4320
+ try {
4321
+ callsStatus = await state.provider.request({
4322
+ method: "wallet_getCallsStatus",
4323
+ params: [prior.callsId]
4324
+ });
4325
+ } catch {
4326
+ throw new OwneyError(
4327
+ "SPONSOR_REQUEST_FAILED",
4328
+ "The earlier upgrade status could not be checked.",
4329
+ { safeToFallback: false, callsId: prior.callsId },
4330
+ this.id
4331
+ );
4332
+ }
4333
+ if (callsStatus?.status === 400 || callsStatus?.status === 500) {
4334
+ storage5.removeItem(pendingKey);
4335
+ throw new OwneyError(
4336
+ "SPONSOR_REQUEST_FAILED",
4337
+ "The earlier sponsored upgrade failed.",
4338
+ { safeToFallback: true, callsId: prior.callsId },
4339
+ this.id
4340
+ );
4341
+ }
4342
+ const earlierHash = callsStatus?.receipts?.[0]?.transactionHash;
4343
+ if (earlierHash) {
4344
+ await this.waitForReceipt(state, chainId, earlierHash);
4345
+ const earlierStatus = await this.getWalletStatus(state, chainId, asset);
4346
+ if (earlierStatus?.version === "v2" && earlierStatus.verified) {
4347
+ storage5.removeItem(pendingKey);
4348
+ return { txHash: earlierHash, status: earlierStatus };
4349
+ }
4350
+ }
4351
+ throw new OwneyError(
4352
+ "SPONSOR_REQUEST_FAILED",
4353
+ "An earlier upgrade is still pending.",
4354
+ { safeToFallback: false, callsId: prior.callsId },
4355
+ this.id
4356
+ );
4357
+ }
4358
+ const context = await this.findAgent(state, chainId, asset);
4359
+ if (!context) throw new OwneyError("NOT_CONNECTED", "Yieldseeker agent is unavailable.");
4360
+ try {
4361
+ const upgraded = await submitYieldseekerSponsoredUpgrade({
4362
+ state,
4363
+ client: this.getReceiptClient(),
4364
+ apiKey: this.owneyApiKey,
4365
+ routingApiBaseUrl: this.routingApiBaseUrl,
4366
+ yieldseekerSignature: await this.auth.getToken(state, chainId),
4367
+ userId: context.user.userId,
4368
+ agentId: context.agent.agentId,
4369
+ agentWallet: before.agentWallet,
4370
+ asset: YIELDSEEKER_ASSET_METADATA[asset].address,
4371
+ callData: data,
4372
+ onPending: (pending) => {
4373
+ const current = storage5.getItem(pendingKey);
4374
+ storage5.setItem(pendingKey, JSON.stringify({
4375
+ startedAt: Date.now(),
4376
+ ...current ? JSON.parse(current) : {},
4377
+ ...pending
4378
+ }));
4379
+ }
4380
+ });
4381
+ txHash = upgraded.txHash;
4382
+ } catch (error) {
4383
+ if (error?.code === 4001 || error instanceof OwneyError && error.code === "SPONSOR_REQUEST_FAILED" && (error.details?.safeToFallback === true || error.details?.executionFailed === true)) storage5.removeItem(pendingKey);
4384
+ throw error;
4385
+ }
4386
+ } else {
4387
+ txHash = await this.submitTransaction(state, chainId, {
4388
+ from: getAddress4(state.walletAddress),
4389
+ to: before.agentWallet,
4390
+ data,
4391
+ value: "0",
4392
+ chainId
4393
+ });
4394
+ }
4395
+ const status = await this.getWalletStatus(state, chainId, asset);
4396
+ if (!status?.verified || status.version !== "v2") {
4397
+ throw new OwneyError(
4398
+ "WITHDRAW_FAILED",
4399
+ "Yieldseeker wallet upgrade was not confirmed as V2.",
4400
+ { txHash, version: status?.version ?? "missing" },
4401
+ this.id
4402
+ );
4403
+ }
4404
+ if (gasMode === "sponsored" && typeof window !== "undefined")
4405
+ window.localStorage.removeItem(`owney.yieldseeker.upgrade:${state.walletAddress.toLowerCase()}:${before.agentWallet.toLowerCase()}`);
4406
+ return { txHash, status };
4407
+ }
3833
4408
  async disconnect() {
4409
+ this.withdrawalVersionCache.clear();
3834
4410
  this.readGeneration += 1;
3835
4411
  this.auth.clear();
3836
4412
  for (const key2 of this.users.keys()) {
@@ -3901,12 +4477,12 @@ var YieldseekerAgent = class {
3901
4477
  receipt = await this.waitForReceipt(state, chainId, txHash);
3902
4478
  } else {
3903
4479
  txHash = await this.submitTransaction(state, chainId, {
3904
- from: getAddress2(state.walletAddress),
4480
+ from: getAddress4(state.walletAddress),
3905
4481
  to: YIELDSEEKER_ASSET_METADATA[asset].address,
3906
4482
  data: encodeFunctionData({
3907
4483
  abi: erc20Abi2,
3908
4484
  functionName: "transfer",
3909
- args: [getAddress2(context.wallet.walletAddress), BigInt(amount)]
4485
+ args: [getAddress4(context.wallet.walletAddress), BigInt(amount)]
3910
4486
  }),
3911
4487
  value: "0",
3912
4488
  chainId
@@ -3917,12 +4493,12 @@ var YieldseekerAgent = class {
3917
4493
  if (this.readGeneration === generation) {
3918
4494
  void this.refreshSnapshotAfterMovement(state, chainId, context, "deposit", movement);
3919
4495
  }
3920
- const base5 = { agentId: this.id, chainId, token: asset, walletAddress: state.walletAddress, agentWallet: context.wallet.walletAddress, intendedAmount: amount, confirmedAmount: amount, txHash, transfer: "confirmed", registration: "not-applicable", delivery: "not-applicable" };
3921
- const evidence = receipt ? inspectFundingReceipt(receipt, base5, YIELDSEEKER_ASSET_METADATA[asset].address, "deposit") : base5;
4496
+ const base6 = { agentId: this.id, chainId, token: asset, walletAddress: state.walletAddress, agentWallet: context.wallet.walletAddress, intendedAmount: amount, confirmedAmount: amount, txHash, transfer: "confirmed", registration: "not-applicable", delivery: "not-applicable" };
4497
+ const evidence = receipt ? inspectFundingReceipt(receipt, base6, YIELDSEEKER_ASSET_METADATA[asset].address, "deposit") : base6;
3922
4498
  notifyFunding(onProgress, evidence);
3923
4499
  return { txHash, smartWallet: context.wallet.walletAddress, amount, evidence };
3924
4500
  }
3925
- async withdraw(state, chainId, asset, amount, onProgress) {
4501
+ async withdraw(state, chainId, asset, amount, onProgress, gasMode = "auto") {
3926
4502
  let ownerTransferAttempted = false;
3927
4503
  let evidence = {
3928
4504
  agentId: this.id,
@@ -3940,14 +4516,20 @@ var YieldseekerAgent = class {
3940
4516
  notifyFunding(onProgress, evidence);
3941
4517
  }, () => {
3942
4518
  ownerTransferAttempted = true;
3943
- });
4519
+ }, gasMode);
3944
4520
  } catch (error) {
3945
- if (!ownerTransferAttempted || error instanceof OwneyError && error.code === "AGENT_TRANSACTION_REVERTED")
3946
- notifyFunding(onProgress, { ...evidence, transfer: "failed", delivery: "failed" });
4521
+ if (error instanceof OwneyError && error.code === "SPONSOR_REQUEST_FAILED") this.withdrawalVersionCache.clear();
4522
+ if (!ownerTransferAttempted || error?.code === 4001 || error instanceof OwneyError && (error.code === "AGENT_TRANSACTION_REVERTED" || error.code === "SPONSOR_REQUEST_FAILED" && (error.details?.safeToFallback === true || error.details?.executionFailed === true)))
4523
+ notifyFunding(onProgress, {
4524
+ ...evidence,
4525
+ ...error instanceof OwneyError && error.code === "SPONSOR_REQUEST_FAILED" && error.details?.safeToFallback === true ? { userOpHash: void 0, callsId: void 0 } : {},
4526
+ transfer: "failed",
4527
+ delivery: "failed"
4528
+ });
3947
4529
  throw error;
3948
4530
  }
3949
4531
  }
3950
- async withdrawInternal(state, chainId, asset, amount, onProgress, onOwnerTransferAttempted) {
4532
+ async withdrawInternal(state, chainId, asset, amount, onProgress, onOwnerTransferAttempted, gasMode = "auto") {
3951
4533
  this.assertChain(chainId);
3952
4534
  this.assertAsset(asset);
3953
4535
  if (amount !== void 0 && BigInt(amount) <= 0n) {
@@ -3967,6 +4549,27 @@ var YieldseekerAgent = class {
3967
4549
  this.id
3968
4550
  );
3969
4551
  }
4552
+ let sponsor = false;
4553
+ if (gasMode !== "paid") {
4554
+ const status = await this.getWalletStatus(state, chainId, asset, true).catch(() => {
4555
+ if (gasMode === "sponsored")
4556
+ throw new OwneyError(
4557
+ "SPONSOR_REQUEST_FAILED",
4558
+ "Could not verify the Yieldseeker wallet for sponsorship.",
4559
+ { safeToFallback: true, version: "unknown" },
4560
+ this.id
4561
+ );
4562
+ return null;
4563
+ });
4564
+ sponsor = !!status?.verified && status.version === "v2";
4565
+ if (gasMode === "sponsored" && !sponsor)
4566
+ throw new OwneyError(
4567
+ "SPONSOR_REQUEST_FAILED",
4568
+ "Only a verified Yieldseeker V2 Agent Wallet can use sponsored withdrawals.",
4569
+ { safeToFallback: true, version: status?.version ?? "unknown" },
4570
+ this.id
4571
+ );
4572
+ }
3970
4573
  const generation = this.readGeneration;
3971
4574
  let confirmedMovement = false;
3972
4575
  let settlement = null;
@@ -3982,7 +4585,7 @@ var YieldseekerAgent = class {
3982
4585
  address: metadata.address,
3983
4586
  abi: erc20Abi2,
3984
4587
  functionName: "balanceOf",
3985
- args: [getAddress2(context.wallet.walletAddress)]
4588
+ args: [getAddress4(context.wallet.walletAddress)]
3986
4589
  }), chainId, "eth_call", this.id);
3987
4590
  this.assertSession(generation, chainId, asset);
3988
4591
  return balance;
@@ -4016,6 +4619,7 @@ var YieldseekerAgent = class {
4016
4619
  );
4017
4620
  }
4018
4621
  let remaining = requested > idle ? requested - idle : 0n;
4622
+ let grossUnwound = 0n;
4019
4623
  for (const position2 of portfolio.positions) {
4020
4624
  if (remaining === 0n) break;
4021
4625
  const available = BigInt(position2.withdrawableAssetsRaw);
@@ -4039,6 +4643,7 @@ var YieldseekerAgent = class {
4039
4643
  }
4040
4644
  await this.waitForReceipt(state, chainId, response.transactionHash);
4041
4645
  confirmedMovement = true;
4646
+ grossUnwound += assetsRaw;
4042
4647
  remaining -= assetsRaw;
4043
4648
  }
4044
4649
  if (remaining > 0n) {
@@ -4048,7 +4653,10 @@ var YieldseekerAgent = class {
4048
4653
  });
4049
4654
  }
4050
4655
  const availableForOwner = confirmedMovement ? await readIdle() : idle;
4051
- if (availableForOwner === 0n || amount !== void 0 && availableForOwner < requested) {
4656
+ const feeRate = portfolio.snapshot.feeRateBps;
4657
+ const maxFee = confirmedMovement && Number.isInteger(feeRate) && feeRate >= 0 && feeRate <= 1e3 ? (grossUnwound * BigInt(feeRate) + 9999n) / 10000n : 0n;
4658
+ const shortfall = availableForOwner < requested ? requested - availableForOwner : 0n;
4659
+ if (availableForOwner === 0n || amount !== void 0 && shortfall > maxFee) {
4052
4660
  this.invalidateFundingRead(state, chainId, asset);
4053
4661
  throw new OwneyError(
4054
4662
  "WITHDRAW_INSUFFICIENT_BALANCE",
@@ -4057,32 +4665,52 @@ var YieldseekerAgent = class {
4057
4665
  this.id
4058
4666
  );
4059
4667
  }
4060
- const payout = amount === void 0 ? availableForOwner : requested;
4668
+ const payout = amount === void 0 || availableForOwner < requested ? availableForOwner : requested;
4061
4669
  const plannedMovement = this.snapshotMovement(state, chainId, context, -payout);
4062
- const account = getAddress2(state.walletAddress);
4670
+ const account = getAddress4(state.walletAddress);
4063
4671
  let receipt;
4064
- const base5 = { agentId: this.id, chainId, token: asset, walletAddress: state.walletAddress, agentWallet: context.wallet.walletAddress, intendedAmount: amount === void 0 ? "MAX" : requested.toString(), transfer: "pending", registration: "not-applicable", delivery: "pending" };
4065
- onOwnerTransferAttempted?.();
4066
- const txHash = await this.submitTransaction(state, chainId, {
4067
- from: account,
4068
- to: getAddress2(context.wallet.walletAddress),
4069
- data: amount === void 0 ? encodeFunctionData({
4070
- abi: YIELDSEEKER_AGENT_WALLET_ABI,
4071
- functionName: "withdrawAllAssetToUser",
4072
- args: [account, metadata.address]
4073
- }) : encodeFunctionData({
4074
- abi: YIELDSEEKER_AGENT_WALLET_ABI,
4075
- functionName: "withdrawAssetToUser",
4076
- args: [account, metadata.address, requested]
4077
- }),
4078
- value: "0",
4079
- chainId
4080
- }, (hash) => notifyFunding(onProgress, { ...base5, txHash: hash }), (value) => {
4081
- receipt = value;
4672
+ 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" };
4673
+ const data = amount === void 0 ? encodeFunctionData({
4674
+ abi: YIELDSEEKER_AGENT_WALLET_ABI,
4675
+ functionName: "withdrawAllAssetToUser",
4676
+ args: [account, metadata.address]
4677
+ }) : encodeFunctionData({
4678
+ abi: YIELDSEEKER_AGENT_WALLET_ABI,
4679
+ functionName: "withdrawAssetToUser",
4680
+ args: [account, metadata.address, payout]
4082
4681
  });
4682
+ onOwnerTransferAttempted?.();
4683
+ let txHash;
4684
+ if (sponsor) {
4685
+ const submitted = await submitYieldseekerSponsoredWithdrawal({
4686
+ state,
4687
+ client: this.getReceiptClient(),
4688
+ apiKey: this.owneyApiKey,
4689
+ routingApiBaseUrl: this.routingApiBaseUrl,
4690
+ yieldseekerSignature: await this.auth.getToken(state, chainId),
4691
+ userId: context.user.userId,
4692
+ agentId: context.agent.agentId,
4693
+ agentWallet: getAddress4(context.wallet.walletAddress),
4694
+ asset: metadata.address,
4695
+ callData: data,
4696
+ onPending: (pending) => notifyFunding(onProgress, { ...base6, ...pending })
4697
+ });
4698
+ txHash = submitted.txHash;
4699
+ receipt = submitted.receipt;
4700
+ } else {
4701
+ txHash = await this.submitTransaction(state, chainId, {
4702
+ from: account,
4703
+ to: getAddress4(context.wallet.walletAddress),
4704
+ data,
4705
+ value: "0",
4706
+ chainId
4707
+ }, (hash) => notifyFunding(onProgress, { ...base6, txHash: hash }), (value) => {
4708
+ receipt = value;
4709
+ });
4710
+ }
4083
4711
  confirmedMovement = true;
4084
4712
  settlement = plannedMovement;
4085
- const evidence = receipt ? inspectFundingReceipt(receipt, { ...base5, txHash }, metadata.address, "withdraw") : { ...base5, txHash, confirmedAmount: payout.toString(), transfer: "confirmed", delivery: "confirmed" };
4713
+ const evidence = receipt ? inspectFundingReceipt(receipt, { ...base6, txHash }, metadata.address, "withdraw") : { ...base6, txHash, confirmedAmount: payout.toString(), transfer: "confirmed", delivery: "confirmed" };
4086
4714
  notifyFunding(onProgress, evidence);
4087
4715
  if (evidence.transfer === "failed" && evidence.confirmedAmount === "0")
4088
4716
  throw new OwneyError(
@@ -4325,7 +4953,7 @@ var YieldseekerAgent = class {
4325
4953
  this.users.set(key2, persisted);
4326
4954
  return persisted;
4327
4955
  }
4328
- const walletAddress = getAddress2(state.walletAddress);
4956
+ const walletAddress = getAddress4(state.walletAddress);
4329
4957
  const generation = this.readGeneration;
4330
4958
  let user = null;
4331
4959
  try {
@@ -4816,15 +5444,15 @@ var YieldseekerAgent = class {
4816
5444
  return hash2;
4817
5445
  }
4818
5446
  this.assertTransaction(transaction, state, chainId);
4819
- const account = getAddress2(state.walletAddress);
4820
- const walletClient = createWalletClient2({
5447
+ const account = getAddress4(state.walletAddress);
5448
+ const walletClient = createWalletClient3({
4821
5449
  account,
4822
- chain: base3,
4823
- transport: custom2(state.provider)
5450
+ chain: base4,
5451
+ transport: custom3(state.provider)
4824
5452
  });
4825
5453
  const walletChainClient = createPublicClient3({
4826
- chain: base3,
4827
- transport: custom2(state.provider)
5454
+ chain: base4,
5455
+ transport: custom3(state.provider)
4828
5456
  });
4829
5457
  await ensureWalletOnChain(
4830
5458
  walletChainClient,
@@ -4833,8 +5461,8 @@ var YieldseekerAgent = class {
4833
5461
  );
4834
5462
  const hash = await walletClient.sendTransaction({
4835
5463
  account,
4836
- chain: base3,
4837
- to: getAddress2(transaction.to),
5464
+ chain: base4,
5465
+ to: getAddress4(transaction.to),
4838
5466
  data: transaction.data,
4839
5467
  value: BigInt(transaction.value)
4840
5468
  });
@@ -4884,7 +5512,7 @@ var YieldseekerAgent = class {
4884
5512
  return receipt;
4885
5513
  }
4886
5514
  assertTransaction(transaction, state, chainId) {
4887
- if (!transaction || typeof transaction.from !== "string" || !isAddress2(transaction.from) || typeof transaction.to !== "string" || !isAddress2(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 || getAddress2(transaction.from) !== getAddress2(state.walletAddress)) {
5515
+ if (!transaction || typeof transaction.from !== "string" || !isAddress2(transaction.from) || typeof transaction.to !== "string" || !isAddress2(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)) {
4888
5516
  throw this.invalidResponse("transaction");
4889
5517
  }
4890
5518
  }
@@ -4946,6 +5574,7 @@ var YieldseekerAgent = class {
4946
5574
 
4947
5575
  // src/lib/routing-api.ts
4948
5576
  var ROUTING_API_BASE_URL2 = "https://owney-routing-api-243946518160.europe-west4.run.app";
5577
+ var getRoutingApiBaseUrl = (override) => override ?? ROUTING_API_BASE_URL2;
4949
5578
  async function fetchOrgAgentConfig(apiKey, baseUrl = ROUTING_API_BASE_URL2) {
4950
5579
  const url = `${baseUrl}/api/v1/agent/org-config`;
4951
5580
  try {
@@ -5230,20 +5859,20 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
5230
5859
  // src/client.ts
5231
5860
  import {
5232
5861
  createPublicClient as createPublicClient4,
5233
- createWalletClient as createWalletClient3,
5234
- custom as custom3
5862
+ createWalletClient as createWalletClient4,
5863
+ custom as custom4
5235
5864
  } from "viem";
5236
- import { base as base4, arbitrum as arbitrum2, mainnet as mainnet2 } from "viem/chains";
5865
+ import { base as base5, arbitrum as arbitrum2, mainnet as mainnet2 } from "viem/chains";
5237
5866
 
5238
5867
  // src/lib/sponsored-token-batch.ts
5239
5868
  import {
5240
- isAddressEqual,
5869
+ isAddressEqual as isAddressEqual2,
5241
5870
  keccak256,
5242
5871
  toBytes
5243
5872
  } from "viem";
5244
5873
 
5245
5874
  // src/lib/permit2-batch.ts
5246
- import { parseAbi as parseAbi3, hashStruct } from "viem";
5875
+ import { parseAbi as parseAbi4, hashStruct } from "viem";
5247
5876
  var BATCH_PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
5248
5877
  var BASE_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
5249
5878
  var ERC2612_PERMIT_TYPES = {
@@ -5255,7 +5884,7 @@ var ERC2612_PERMIT_TYPES = {
5255
5884
  { name: "deadline", type: "uint256" }
5256
5885
  ]
5257
5886
  };
5258
- var ERC2612_READ_ABI = parseAbi3([
5887
+ var ERC2612_READ_ABI = parseAbi4([
5259
5888
  "function name() view returns (string)",
5260
5889
  "function version() view returns (string)",
5261
5890
  "function nonces(address owner) view returns (uint256)"
@@ -5293,7 +5922,7 @@ var PERMIT_BATCH_TYPES = {
5293
5922
  { name: "amount", type: "uint256" }
5294
5923
  ]
5295
5924
  };
5296
- var PERMIT2_BATCH_ABI = parseAbi3([
5925
+ var PERMIT2_BATCH_ABI = parseAbi4([
5297
5926
  "struct TokenPermissions { address token; uint256 amount; }",
5298
5927
  "struct PermitBatchTransferFrom { TokenPermissions[] permitted; uint256 nonce; uint256 deadline; }",
5299
5928
  "struct SignatureTransferDetails { address to; uint256 requestedAmount; }",
@@ -5433,7 +6062,7 @@ async function execute(i, key2, plan) {
5433
6062
  const saved = read(key2);
5434
6063
  if (saved) {
5435
6064
  const previous = JSON.parse(saved);
5436
- if (previous.chainId !== i.chainId || !isAddressEqual(previous.from, i.owner) || !isAddressEqual(previous.token, i.token) || planOf(previous.transfers) !== plan)
6065
+ if (previous.chainId !== i.chainId || !isAddressEqual2(previous.from, i.owner) || !isAddressEqual2(previous.token, i.token) || planOf(previous.transfers) !== plan)
5437
6066
  throw new Error(
5438
6067
  "Retry the previous token deposit and agent split first to reconcile its status."
5439
6068
  );
@@ -5450,7 +6079,7 @@ async function execute(i, key2, plan) {
5450
6079
  "DEPOSIT_INSUFFICIENT_BALANCE",
5451
6080
  "Insufficient token balance for this deposit."
5452
6081
  );
5453
- if (allowance < total && (i.chainId !== 8453 || !isAddressEqual(i.token, BASE_USDC_ADDRESS)))
6082
+ if (allowance < total && (i.chainId !== 8453 || !isAddressEqual2(i.token, BASE_USDC_ADDRESS)))
5454
6083
  throw new OwneyError(
5455
6084
  "PERMIT2_APPROVAL_REQUIRED",
5456
6085
  "token deposits need a one-time Permit2 approval."
@@ -5628,7 +6257,7 @@ async function runAgentDepositBatch(chainId, legs, transfer) {
5628
6257
  }
5629
6258
 
5630
6259
  // src/lib/sponsored-calls-deposit.ts
5631
- import { encodeFunctionData as encodeFunctionData2, erc20Abi as erc20Abi3, toHex } from "viem";
6260
+ import { encodeFunctionData as encodeFunctionData2, erc20Abi as erc20Abi3, toHex as toHex2 } from "viem";
5632
6261
  var DEFAULT_POLL_INTERVAL_MS = 1500;
5633
6262
  var DEFAULT_MAX_POLLS = 30;
5634
6263
  async function paymasterSupported(provider, owner, chainId) {
@@ -5636,7 +6265,7 @@ async function paymasterSupported(provider, owner, chainId) {
5636
6265
  method: "wallet_getCapabilities",
5637
6266
  params: [owner]
5638
6267
  });
5639
- const forChain = caps?.[toHex(chainId)] ?? caps?.[String(chainId)];
6268
+ const forChain = caps?.[toHex2(chainId)] ?? caps?.[String(chainId)];
5640
6269
  return Boolean(forChain?.paymasterService?.supported);
5641
6270
  }
5642
6271
  function makeSponsoredCallsCallback(deps) {
@@ -5712,7 +6341,7 @@ function makeSponsoredCallsCallback(deps) {
5712
6341
  {
5713
6342
  version: "2.0.0",
5714
6343
  from: deps.ownerAddress,
5715
- chainId: toHex(chainId),
6344
+ chainId: toHex2(chainId),
5716
6345
  atomicRequired: transfers.length > 1,
5717
6346
  calls,
5718
6347
  capabilities: {
@@ -5806,7 +6435,7 @@ var SPONSORED_USDC_BY_CHAIN = {
5806
6435
  1: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
5807
6436
  };
5808
6437
  var VIEM_CHAIN2 = {
5809
- 8453: base4,
6438
+ 8453: base5,
5810
6439
  42161: arbitrum2,
5811
6440
  1: mainnet2
5812
6441
  };
@@ -5983,12 +6612,12 @@ var OwneySDK = class {
5983
6612
  getPublicClient: (cid) => this.getPaidRpcClient(cid),
5984
6613
  getWalletChainClient: (cid) => createPublicClient4({
5985
6614
  chain: VIEM_CHAIN2[cid],
5986
- transport: custom3(provider)
6615
+ transport: custom4(provider)
5987
6616
  }),
5988
- getWalletClient: (cid) => createWalletClient3({
6617
+ getWalletClient: (cid) => createWalletClient4({
5989
6618
  account: owner,
5990
6619
  chain: VIEM_CHAIN2[cid],
5991
- transport: custom3(provider)
6620
+ transport: custom4(provider)
5992
6621
  })
5993
6622
  });
5994
6623
  if (!onApproved && !onSubmitted) this.cachedSponsoredCallback = callback;
@@ -6036,12 +6665,12 @@ var OwneySDK = class {
6036
6665
  getPublicClient: (cid) => this.getPaidRpcClient(cid),
6037
6666
  getWalletChainClient: (cid) => createPublicClient4({
6038
6667
  chain: VIEM_CHAIN2[cid],
6039
- transport: custom3(provider)
6668
+ transport: custom4(provider)
6040
6669
  }),
6041
- getWalletClient: (cid) => createWalletClient3({
6670
+ getWalletClient: (cid) => createWalletClient4({
6042
6671
  account: owner,
6043
6672
  chain: VIEM_CHAIN2[cid],
6044
- transport: custom3(provider)
6673
+ transport: custom4(provider)
6045
6674
  })
6046
6675
  });
6047
6676
  if (!onApproved && !onSubmitted) this.cachedWethSponsoredCallback = callback;
@@ -6162,6 +6791,7 @@ var OwneySDK = class {
6162
6791
  }
6163
6792
  if (agentId === "yieldseeker") {
6164
6793
  return new YieldseekerAgent(this.apiKey, {
6794
+ routingApiBaseUrl: this.routingApiBaseUrl,
6165
6795
  auth: { origin: this.yieldseekerSiweOrigin },
6166
6796
  baseUrl: this.yieldseekerApiBaseUrl ?? getYieldseekerProxyBaseUrl(this.routingApiBaseUrl),
6167
6797
  rpcUrls: this.rpcUrls
@@ -6753,12 +7383,12 @@ var OwneySDK = class {
6753
7383
  throw new OwneyError("AGENT_API_ERROR", "Funding wallet does not match this account.");
6754
7384
  const token = SupportedAssets.find((t) => t.chainId === chainId && t.symbol === evidence.token);
6755
7385
  if (!token) throw new OwneyError("CHAIN_UNSUPPORTED", "Unsupported funding asset.");
6756
- const rpc = this.getPaidRpcClient(chainId);
6757
- const receipt = await rpc.getTransactionReceipt({ hash: evidence.txHash });
7386
+ const rpc2 = this.getPaidRpcClient(chainId);
7387
+ const receipt = await rpc2.getTransactionReceipt({ hash: evidence.txHash });
6758
7388
  assertCurrent();
6759
7389
  let verified = inspectFundingReceipt(receipt, { ...evidence, agentWallet }, token.address, direction);
6760
7390
  if (direction === "withdraw" && evidence.agentId === "yieldseeker" && verified.transfer === "unknown" && verified.confirmedAmount && BigInt(verified.confirmedAmount) > 0n) {
6761
- const transaction = await rpc.getTransaction({ hash: evidence.txHash });
7391
+ const transaction = await rpc2.getTransaction({ hash: evidence.txHash });
6762
7392
  assertCurrent();
6763
7393
  if (isFullYieldseekerWithdrawal(transaction, { ...evidence, agentWallet }, token.address))
6764
7394
  verified = inspectFundingReceipt(receipt, { ...evidence, agentWallet, intendedAmount: "MAX" }, token.address, direction);
@@ -6772,6 +7402,45 @@ var OwneySDK = class {
6772
7402
  }
6773
7403
  return verified;
6774
7404
  }
7405
+ /** Resolve a saved sponsored-withdrawal ID without opening a wallet prompt. */
7406
+ async resolveSponsoredWithdrawalEvidence(evidence) {
7407
+ const { state, chainId, assertCurrent } = this.captureReadScope(evidence.chainId);
7408
+ if (evidence.agentId !== "yieldseeker" || chainId !== 8453 || evidence.txHash || state.walletAddress.toLowerCase() !== evidence.walletAddress.toLowerCase()) return evidence;
7409
+ const agent = this.getAgent("yieldseeker");
7410
+ const wallet = await agent.getFundingWallet?.(state, chainId, evidence.token);
7411
+ if (!wallet || wallet.toLowerCase() !== evidence.agentWallet?.toLowerCase()) return evidence;
7412
+ let txHash;
7413
+ let executionFailed = false;
7414
+ if (evidence.userOpHash && /^0x[0-9a-fA-F]{64}$/.test(evidence.userOpHash)) {
7415
+ const response = await fetch(`${getRoutingApiBaseUrl(this.routingApiBaseUrl).replace(/\/$/, "")}/api/v1/sponsor/yieldseeker-withdraw/resolve`, {
7416
+ method: "POST",
7417
+ headers: { "content-type": "application/json", "x-owney-api-key": this.apiKey },
7418
+ body: JSON.stringify({
7419
+ owner: state.walletAddress,
7420
+ agentWallet: wallet,
7421
+ asset: SupportedAssets.find((t) => t.chainId === chainId && t.symbol === evidence.token)?.address,
7422
+ userOpHash: evidence.userOpHash
7423
+ })
7424
+ });
7425
+ if (!response.ok) throw new OwneyError("AGENT_API_ERROR", "Could not resolve sponsored withdrawal status.");
7426
+ const payload = await response.json();
7427
+ txHash = payload.data?.txHash ?? void 0;
7428
+ executionFailed = payload.data?.executionFailed === true;
7429
+ } else if (evidence.callsId) {
7430
+ const status = await state.provider.request({ method: "wallet_getCallsStatus", params: [evidence.callsId] });
7431
+ if (status?.id && status.id !== evidence.callsId || status?.chainId && Number(status.chainId) !== chainId) return evidence;
7432
+ executionFailed = status?.status === 400 || status?.status === 500;
7433
+ txHash = status?.receipts?.[0]?.transactionHash;
7434
+ }
7435
+ assertCurrent();
7436
+ if (executionFailed) return {
7437
+ ...evidence,
7438
+ ...txHash && /^0x[0-9a-fA-F]{64}$/.test(txHash) ? { txHash } : {},
7439
+ transfer: "failed",
7440
+ delivery: "failed"
7441
+ };
7442
+ return txHash && /^0x[0-9a-fA-F]{64}$/.test(txHash) ? { ...evidence, txHash } : evidence;
7443
+ }
6775
7444
  /** A display acknowledgement controls polling only; it never confirms a financial outcome. */
6776
7445
  endFundingBalanceRefresh(evidence, read2) {
6777
7446
  const { state, chainId } = this.captureReadScope(evidence.chainId);
@@ -6796,6 +7465,39 @@ var OwneySDK = class {
6796
7465
  return this.getAgent("zyfai").retryDepositRegistration(this.requireState(), verified);
6797
7466
  }
6798
7467
  // --- Fund operations ---
7468
+ /** On-chain version and ownership status for this owner's Yieldseeker agent. */
7469
+ async getYieldseekerWalletStatus(asset) {
7470
+ const state = this.requireState();
7471
+ const chainId = this.requireChainId();
7472
+ const agent = this.getAgent("yieldseeker");
7473
+ return agent.getWalletStatus(state, chainId, asset);
7474
+ }
7475
+ /** Deployment gate; an unavailable response keeps the current paid path. */
7476
+ async isYieldseekerWithdrawalSponsorshipAvailable() {
7477
+ return this.isYieldseekerSponsorshipAvailable("withdraw");
7478
+ }
7479
+ async isYieldseekerUpgradeSponsorshipAvailable() {
7480
+ return this.isYieldseekerSponsorshipAvailable("upgrade");
7481
+ }
7482
+ async isYieldseekerSponsorshipAvailable(action) {
7483
+ const baseUrl = getRoutingApiBaseUrl(this.routingApiBaseUrl).replace(/\/$/, "");
7484
+ try {
7485
+ const owner = this.requireState().walletAddress;
7486
+ const response = await fetch(`${baseUrl}/api/v1/sponsor/yieldseeker-withdraw/availability?owner=${encodeURIComponent(owner)}&action=${action}`);
7487
+ if (!response.ok) return false;
7488
+ const payload = await response.json();
7489
+ return payload.data?.enabled === true;
7490
+ } catch {
7491
+ return false;
7492
+ }
7493
+ }
7494
+ /** Explicit V1-to-V2 upgrade, confirmed on chain before returning. */
7495
+ async upgradeYieldseekerWallet(asset, gasMode = "paid") {
7496
+ const state = this.requireState();
7497
+ const chainId = this.requireChainId();
7498
+ const agent = this.getAgent("yieldseeker");
7499
+ return agent.upgradeWallet(state, chainId, asset, gasMode);
7500
+ }
6799
7501
  /**
6800
7502
  * Withdraw funds from a specific agent, or all agents that support the active chain+asset if agentId is omitted.
6801
7503
  * Validates that the asset is supported by the target agent(s) on the active chain.
@@ -6859,7 +7561,7 @@ var OwneySDK = class {
6859
7561
  };
6860
7562
  progress(evidence);
6861
7563
  try {
6862
- return await agent.withdraw(state, chainId, token, requested2, progress);
7564
+ return await (options.gasMode === void 0 ? agent.withdraw(state, chainId, token, requested2, progress) : agent.withdraw(state, chainId, token, requested2, progress, options.gasMode));
6863
7565
  } catch (error) {
6864
7566
  if (!evidence.txHash && (this.isUserRejectedWithdrawal(error) || /insufficient (balance|funds)/i.test(error instanceof Error ? error.message : "")))
6865
7567
  progress({ ...evidence, transfer: "failed", delivery: "failed" });
@@ -6897,6 +7599,7 @@ var OwneySDK = class {
6897
7599
  results2[agent.id] = await submit(agent);
6898
7600
  notifyAgentResult(agent.id, results2[agent.id]);
6899
7601
  } catch (err) {
7602
+ if (err instanceof OwneyError && err.code === "SPONSOR_REQUEST_FAILED" && err.details?.safeToFallback === true) throw err;
6900
7603
  if (this.isUserRejectedWithdrawal(err)) throw err;
6901
7604
  if (err instanceof OwneyError && err.code === "WITHDRAW_INSUFFICIENT_BALANCE" && err.details?.available === "0" && submissionEvidence.get(agent.id)?.transfer === "failed") continue;
6902
7605
  console.error(`withdraw failed for agent "${agent.id}":`, err);
@@ -6998,6 +7701,7 @@ var OwneySDK = class {
6998
7701
  results[p.agent.id] = await submit(p.agent, p.planned.toString());
6999
7702
  notifyAgentResult(p.agent.id, results[p.agent.id]);
7000
7703
  } catch (err) {
7704
+ if (err instanceof OwneyError && err.code === "SPONSOR_REQUEST_FAILED" && err.details?.safeToFallback === true) throw err;
7001
7705
  if (this.isUserRejectedWithdrawal(err)) throw err;
7002
7706
  console.error(`withdraw failed for agent "${p.agent.id}":`, err);
7003
7707
  agentErrors[p.agent.id] = err instanceof Error ? err.message : String(err);
@@ -7497,14 +8201,14 @@ var OwneySDK = class {
7497
8201
  const provider = this.requireConnectedProvider();
7498
8202
  const walletChainClient = createPublicClient4({
7499
8203
  chain: VIEM_CHAIN2[chainId],
7500
- transport: custom3(provider)
8204
+ transport: custom4(provider)
7501
8205
  });
7502
8206
  const publicClient = this.getPaidRpcClient(chainId);
7503
8207
  const approvalAmount = permit2ApprovalAmount(requiredAmount);
7504
- const wallet = createWalletClient3({
8208
+ const wallet = createWalletClient4({
7505
8209
  account: state.walletAddress,
7506
8210
  chain: VIEM_CHAIN2[chainId],
7507
- transport: custom3(provider)
8211
+ transport: custom4(provider)
7508
8212
  });
7509
8213
  await ensureWalletOnChain(walletChainClient, wallet, chainId);
7510
8214
  const hash = await wallet.writeContract({
@@ -7666,7 +8370,7 @@ var OwneySDK = class {
7666
8370
  };
7667
8371
 
7668
8372
  // src/agents/zyfai/zyfai.siwx.ts
7669
- import { getAddress as getAddress3 } from "viem";
8373
+ import { getAddress as getAddress5 } from "viem";
7670
8374
  import { SiweMessage as SiweMessage2 } from "siwe";
7671
8375
  import { ZyfaiSDK as ZyfaiSDK2 } from "@zyfai/sdk";
7672
8376
 
@@ -7793,7 +8497,7 @@ function buildSIWXConfig(deps) {
7793
8497
  issuedAt,
7794
8498
  toString() {
7795
8499
  return new SiweMessage2({
7796
- address: getAddress3(accountAddress),
8500
+ address: getAddress5(accountAddress),
7797
8501
  chainId: numericChainId(chainId),
7798
8502
  domain,
7799
8503
  uri,