@owney/sdk 0.7.25-beta.11 → 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/README.md +1 -1
- package/dist/index.cjs +811 -101
- package/dist/index.d.cts +47 -4
- package/dist/index.d.ts +47 -4
- package/dist/index.js +800 -81
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2632,8 +2632,8 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2632
2632
|
};
|
|
2633
2633
|
|
|
2634
2634
|
// src/agents/yieldseeker/yieldseeker.agent.ts
|
|
2635
|
-
var
|
|
2636
|
-
var
|
|
2635
|
+
var import_viem10 = require("viem");
|
|
2636
|
+
var import_chains4 = require("viem/chains");
|
|
2637
2637
|
|
|
2638
2638
|
// src/lib/chain-guard.ts
|
|
2639
2639
|
var CHAIN_NAMES = {
|
|
@@ -2676,10 +2676,10 @@ var import_viem4 = require("viem");
|
|
|
2676
2676
|
// src/lib/sponsor-client.ts
|
|
2677
2677
|
var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
2678
2678
|
async function postPaymasterIntent(input) {
|
|
2679
|
-
const
|
|
2679
|
+
const base6 = input.baseUrl ?? ROUTING_API_BASE_URL;
|
|
2680
2680
|
let res;
|
|
2681
2681
|
try {
|
|
2682
|
-
res = await fetch(`${
|
|
2682
|
+
res = await fetch(`${base6}/api/v1/sponsor/paymaster-intent`, {
|
|
2683
2683
|
method: "POST",
|
|
2684
2684
|
headers: {
|
|
2685
2685
|
"content-type": "application/json",
|
|
@@ -2715,11 +2715,11 @@ async function postPaymasterIntent(input) {
|
|
|
2715
2715
|
return parsed.data;
|
|
2716
2716
|
}
|
|
2717
2717
|
async function getSponsorRelayerAddress(input) {
|
|
2718
|
-
const
|
|
2718
|
+
const base6 = input.baseUrl ?? ROUTING_API_BASE_URL;
|
|
2719
2719
|
let res;
|
|
2720
2720
|
try {
|
|
2721
2721
|
res = await fetch(
|
|
2722
|
-
`${
|
|
2722
|
+
`${base6}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
|
|
2723
2723
|
{
|
|
2724
2724
|
headers: { "x-owney-api-key": input.apiKey }
|
|
2725
2725
|
}
|
|
@@ -3740,6 +3740,395 @@ function mapYieldseekerAgentApy(options, days) {
|
|
|
3740
3740
|
};
|
|
3741
3741
|
}
|
|
3742
3742
|
|
|
3743
|
+
// src/agents/yieldseeker/yieldseeker.wallet-version.ts
|
|
3744
|
+
var import_viem8 = require("viem");
|
|
3745
|
+
var YIELDSEEKER_FACTORY = "0x9c7410a0faCAC60850C46eE5b58B518daec95130";
|
|
3746
|
+
var YIELDSEEKER_V1_IMPLEMENTATION = "0x32403455357589523435dB18b414057D7cE05051";
|
|
3747
|
+
var YIELDSEEKER_V2_IMPLEMENTATION = "0x613Db9c924ADB7A7A90c11b02Cce20c913E3Fe50";
|
|
3748
|
+
var ERC1967_IMPLEMENTATION_SLOT = "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc";
|
|
3749
|
+
var walletAbi = (0, import_viem8.parseAbi)([
|
|
3750
|
+
"function owner() view returns (address)",
|
|
3751
|
+
"function ownerAgentIndex() view returns (uint256)",
|
|
3752
|
+
"function baseAsset() view returns (address)",
|
|
3753
|
+
"function FACTORY() view returns (address)",
|
|
3754
|
+
"function upgradeToLatest()"
|
|
3755
|
+
]);
|
|
3756
|
+
var factoryAbi = (0, import_viem8.parseAbi)([
|
|
3757
|
+
"function userWallets(address owner, uint256 index) view returns (address)",
|
|
3758
|
+
"function agentWalletImplementation() view returns (address)"
|
|
3759
|
+
]);
|
|
3760
|
+
function yieldseekerOwnerPath(code) {
|
|
3761
|
+
return !code || code === "0x" || /^0xef0100[0-9a-f]{40}$/i.test(code) ? "eoa" : "smart";
|
|
3762
|
+
}
|
|
3763
|
+
async function readYieldseekerWalletStatus(client, wallet, owner, asset) {
|
|
3764
|
+
const agentWallet = (0, import_viem8.getAddress)(wallet);
|
|
3765
|
+
const expectedOwner = (0, import_viem8.getAddress)(owner);
|
|
3766
|
+
const expectedAsset = (0, import_viem8.getAddress)(asset);
|
|
3767
|
+
const [code, ownerCode, slot, actualOwner, index, actualAsset, actualFactory, latest] = await Promise.all([
|
|
3768
|
+
client.getBytecode({ address: agentWallet }),
|
|
3769
|
+
client.getBytecode({ address: expectedOwner }),
|
|
3770
|
+
client.getStorageAt({ address: agentWallet, slot: ERC1967_IMPLEMENTATION_SLOT }),
|
|
3771
|
+
client.readContract({ address: agentWallet, abi: walletAbi, functionName: "owner" }),
|
|
3772
|
+
client.readContract({ address: agentWallet, abi: walletAbi, functionName: "ownerAgentIndex" }),
|
|
3773
|
+
client.readContract({ address: agentWallet, abi: walletAbi, functionName: "baseAsset" }),
|
|
3774
|
+
client.readContract({ address: agentWallet, abi: walletAbi, functionName: "FACTORY" }),
|
|
3775
|
+
client.readContract({ address: YIELDSEEKER_FACTORY, abi: factoryAbi, functionName: "agentWalletImplementation" })
|
|
3776
|
+
]);
|
|
3777
|
+
if (!code || code === "0x" || !slot || /^0x0+$/.test(slot)) {
|
|
3778
|
+
throw new Error("Yieldseeker wallet is not a deployed ERC1967 proxy");
|
|
3779
|
+
}
|
|
3780
|
+
const implementation = (0, import_viem8.getAddress)(`0x${slot.slice(-40)}`);
|
|
3781
|
+
const mapped = await client.readContract({
|
|
3782
|
+
address: YIELDSEEKER_FACTORY,
|
|
3783
|
+
abi: factoryAbi,
|
|
3784
|
+
functionName: "userWallets",
|
|
3785
|
+
args: [expectedOwner, index]
|
|
3786
|
+
});
|
|
3787
|
+
const verified = (0, import_viem8.isAddressEqual)(actualOwner, expectedOwner) && (0, import_viem8.isAddressEqual)(actualAsset, expectedAsset) && (0, import_viem8.isAddressEqual)(actualFactory, YIELDSEEKER_FACTORY) && (0, import_viem8.isAddressEqual)(mapped, agentWallet);
|
|
3788
|
+
const version = !verified ? "unknown" : (0, import_viem8.isAddressEqual)(implementation, YIELDSEEKER_V2_IMPLEMENTATION) ? "v2" : (0, import_viem8.isAddressEqual)(implementation, YIELDSEEKER_V1_IMPLEMENTATION) ? "v1" : "unknown";
|
|
3789
|
+
return {
|
|
3790
|
+
agentWallet,
|
|
3791
|
+
owner: actualOwner,
|
|
3792
|
+
ownerPath: yieldseekerOwnerPath(ownerCode),
|
|
3793
|
+
asset: actualAsset,
|
|
3794
|
+
implementation,
|
|
3795
|
+
version,
|
|
3796
|
+
verified,
|
|
3797
|
+
upgradeAvailable: version === "v1" && (0, import_viem8.isAddressEqual)(latest, YIELDSEEKER_V2_IMPLEMENTATION)
|
|
3798
|
+
};
|
|
3799
|
+
}
|
|
3800
|
+
var YIELDSEEKER_UPGRADE_ABI = walletAbi;
|
|
3801
|
+
|
|
3802
|
+
// src/agents/yieldseeker/yieldseeker.sponsored-withdraw.ts
|
|
3803
|
+
var import_viem9 = require("viem");
|
|
3804
|
+
var import_account_abstraction = require("viem/account-abstraction");
|
|
3805
|
+
var import_accounts = require("viem/accounts");
|
|
3806
|
+
var import_chains3 = require("viem/chains");
|
|
3807
|
+
var ENTRY_POINT_V06 = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789";
|
|
3808
|
+
var USER_OP_FEE_HEADROOM = 2n;
|
|
3809
|
+
var ENTRY_POINT_NONCE_ABI = [
|
|
3810
|
+
{ type: "function", name: "getNonce", stateMutability: "view", inputs: [
|
|
3811
|
+
{ name: "sender", type: "address" },
|
|
3812
|
+
{ name: "key", type: "uint192" }
|
|
3813
|
+
], outputs: [{ type: "uint256" }] }
|
|
3814
|
+
];
|
|
3815
|
+
var DEFAULT_ROUTING_API = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
3816
|
+
var SIMULATION_ACCOUNT = (0, import_accounts.privateKeyToAccount)((0, import_accounts.generatePrivateKey)());
|
|
3817
|
+
function operationHash(operation) {
|
|
3818
|
+
return (0, import_account_abstraction.getUserOperationHash)({
|
|
3819
|
+
chainId: 8453,
|
|
3820
|
+
entryPointAddress: ENTRY_POINT_V06,
|
|
3821
|
+
entryPointVersion: "0.6",
|
|
3822
|
+
userOperation: {
|
|
3823
|
+
sender: operation.sender,
|
|
3824
|
+
nonce: BigInt(operation.nonce),
|
|
3825
|
+
initCode: operation.initCode,
|
|
3826
|
+
callData: operation.callData,
|
|
3827
|
+
callGasLimit: BigInt(operation.callGasLimit),
|
|
3828
|
+
verificationGasLimit: BigInt(operation.verificationGasLimit),
|
|
3829
|
+
preVerificationGas: BigInt(operation.preVerificationGas),
|
|
3830
|
+
maxFeePerGas: BigInt(operation.maxFeePerGas),
|
|
3831
|
+
maxPriorityFeePerGas: BigInt(operation.maxPriorityFeePerGas),
|
|
3832
|
+
paymasterAndData: operation.paymasterAndData,
|
|
3833
|
+
signature: operation.signature
|
|
3834
|
+
}
|
|
3835
|
+
});
|
|
3836
|
+
}
|
|
3837
|
+
function sponsorError(message, safeToFallback, details = {}) {
|
|
3838
|
+
return new OwneyError(
|
|
3839
|
+
"SPONSOR_REQUEST_FAILED",
|
|
3840
|
+
message,
|
|
3841
|
+
{ safeToFallback, ...details },
|
|
3842
|
+
"yieldseeker"
|
|
3843
|
+
);
|
|
3844
|
+
}
|
|
3845
|
+
async function requestIntent(input) {
|
|
3846
|
+
const baseUrl = (input.routingApiBaseUrl ?? DEFAULT_ROUTING_API).replace(/\/$/, "");
|
|
3847
|
+
let response;
|
|
3848
|
+
try {
|
|
3849
|
+
response = await fetch(`${baseUrl}/api/v1/sponsor/yieldseeker-withdraw/intent`, {
|
|
3850
|
+
method: "POST",
|
|
3851
|
+
headers: {
|
|
3852
|
+
"content-type": "application/json",
|
|
3853
|
+
"x-owney-api-key": input.apiKey,
|
|
3854
|
+
Authorization: `Signature ${input.yieldseekerSignature}`
|
|
3855
|
+
},
|
|
3856
|
+
body: JSON.stringify({
|
|
3857
|
+
chainId: 8453,
|
|
3858
|
+
owner: input.owner,
|
|
3859
|
+
recipient: input.owner,
|
|
3860
|
+
agentWallet: input.agentWallet,
|
|
3861
|
+
asset: input.asset,
|
|
3862
|
+
callData: input.callData,
|
|
3863
|
+
action: input.action,
|
|
3864
|
+
yieldseekerUserId: input.userId,
|
|
3865
|
+
yieldseekerAgentId: input.agentId
|
|
3866
|
+
})
|
|
3867
|
+
});
|
|
3868
|
+
} catch {
|
|
3869
|
+
throw sponsorError("Withdrawal sponsorship could not be requested.", true);
|
|
3870
|
+
}
|
|
3871
|
+
const envelope = await response.json().catch(() => null);
|
|
3872
|
+
const intent = envelope?.data;
|
|
3873
|
+
if (!response.ok || !envelope?.success || !intent?.intent || !["eoa", "smart"].includes(intent.ownerPath)) {
|
|
3874
|
+
throw sponsorError(
|
|
3875
|
+
"Withdrawal sponsorship is currently unavailable.",
|
|
3876
|
+
true,
|
|
3877
|
+
{ statusCode: response.status }
|
|
3878
|
+
);
|
|
3879
|
+
}
|
|
3880
|
+
const url = new URL(`${baseUrl}/api/v1/sponsor/yieldseeker-withdraw/rpc`);
|
|
3881
|
+
url.searchParams.set("intent", intent.intent);
|
|
3882
|
+
return { intent, rpcUrl: url.toString() };
|
|
3883
|
+
}
|
|
3884
|
+
async function rpc(url, method, params, phase) {
|
|
3885
|
+
let response;
|
|
3886
|
+
try {
|
|
3887
|
+
response = await fetch(url, {
|
|
3888
|
+
method: "POST",
|
|
3889
|
+
headers: { "content-type": "application/json" },
|
|
3890
|
+
body: JSON.stringify({ jsonrpc: "2.0", id: 1, method, params })
|
|
3891
|
+
});
|
|
3892
|
+
} catch {
|
|
3893
|
+
throw sponsorError("Withdrawal sponsorship request status is unknown.", phase === "prepare");
|
|
3894
|
+
}
|
|
3895
|
+
const payload = await response.json().catch(() => null);
|
|
3896
|
+
if (!response.ok || payload?.error || payload?.result === void 0) {
|
|
3897
|
+
const rejection = payload?.error;
|
|
3898
|
+
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 ?? ""));
|
|
3899
|
+
throw sponsorError(
|
|
3900
|
+
phase !== "prepare" && !definitiveRejection ? "Sponsored withdrawal submission status is unknown." : "Withdrawal sponsorship was declined before submission.",
|
|
3901
|
+
phase === "prepare" || definitiveRejection,
|
|
3902
|
+
{ statusCode: response.status, rpcCode: payload?.error?.code, rpcMethod: method }
|
|
3903
|
+
);
|
|
3904
|
+
}
|
|
3905
|
+
return payload.result;
|
|
3906
|
+
}
|
|
3907
|
+
async function waitForTransaction(client, txHash) {
|
|
3908
|
+
const receipt = await client.waitForTransactionReceipt({ hash: txHash, confirmations: 1 });
|
|
3909
|
+
if (receipt.status !== "success")
|
|
3910
|
+
throw new OwneyError(
|
|
3911
|
+
"AGENT_TRANSACTION_REVERTED",
|
|
3912
|
+
`Yieldseeker withdrawal reverted (${txHash}).`,
|
|
3913
|
+
{ transactionHash: txHash },
|
|
3914
|
+
"yieldseeker"
|
|
3915
|
+
);
|
|
3916
|
+
return receipt;
|
|
3917
|
+
}
|
|
3918
|
+
async function submitEoa(input) {
|
|
3919
|
+
let nonce;
|
|
3920
|
+
let fees;
|
|
3921
|
+
try {
|
|
3922
|
+
nonce = await input.client.readContract({
|
|
3923
|
+
address: ENTRY_POINT_V06,
|
|
3924
|
+
abi: ENTRY_POINT_NONCE_ABI,
|
|
3925
|
+
functionName: "getNonce",
|
|
3926
|
+
args: [input.agentWallet, 0n]
|
|
3927
|
+
});
|
|
3928
|
+
fees = await input.client.estimateFeesPerGas();
|
|
3929
|
+
} catch {
|
|
3930
|
+
throw sponsorError("Could not prepare the sponsored withdrawal.", true);
|
|
3931
|
+
}
|
|
3932
|
+
if (fees.maxFeePerGas === void 0 || fees.maxPriorityFeePerGas === void 0)
|
|
3933
|
+
throw sponsorError("Base did not return EIP-1559 gas fees.", true);
|
|
3934
|
+
let operation = {
|
|
3935
|
+
sender: input.agentWallet,
|
|
3936
|
+
nonce: (0, import_viem9.toHex)(nonce),
|
|
3937
|
+
initCode: "0x",
|
|
3938
|
+
callData: input.callData,
|
|
3939
|
+
callGasLimit: (0, import_viem9.toHex)(3e5),
|
|
3940
|
+
verificationGasLimit: (0, import_viem9.toHex)(3e5),
|
|
3941
|
+
preVerificationGas: (0, import_viem9.toHex)(6e4),
|
|
3942
|
+
maxFeePerGas: (0, import_viem9.toHex)(fees.maxFeePerGas * USER_OP_FEE_HEADROOM),
|
|
3943
|
+
maxPriorityFeePerGas: (0, import_viem9.toHex)(fees.maxPriorityFeePerGas),
|
|
3944
|
+
paymasterAndData: "0x",
|
|
3945
|
+
signature: "0x"
|
|
3946
|
+
};
|
|
3947
|
+
operation.signature = await SIMULATION_ACCOUNT.signMessage({ message: { raw: operationHash(operation) } });
|
|
3948
|
+
const stub = await rpc(
|
|
3949
|
+
input.rpcUrl,
|
|
3950
|
+
"pm_getPaymasterStubData",
|
|
3951
|
+
[operation, ENTRY_POINT_V06, (0, import_viem9.toHex)(8453), {}],
|
|
3952
|
+
"prepare"
|
|
3953
|
+
);
|
|
3954
|
+
if (!stub.paymasterAndData?.startsWith("0x"))
|
|
3955
|
+
throw sponsorError("CDP did not return v0.6 paymaster data.", true);
|
|
3956
|
+
operation = { ...operation, paymasterAndData: stub.paymasterAndData };
|
|
3957
|
+
operation.signature = await SIMULATION_ACCOUNT.signMessage({ message: { raw: operationHash(operation) } });
|
|
3958
|
+
const gas = await rpc(input.rpcUrl, "eth_estimateUserOperationGas", [operation, ENTRY_POINT_V06], "prepare");
|
|
3959
|
+
if (!gas.callGasLimit || !gas.verificationGasLimit || !gas.preVerificationGas)
|
|
3960
|
+
throw sponsorError("CDP did not return UserOperation gas estimates.", true);
|
|
3961
|
+
operation = { ...operation, ...gas };
|
|
3962
|
+
if (!stub.isFinal) {
|
|
3963
|
+
const final = await rpc(
|
|
3964
|
+
input.rpcUrl,
|
|
3965
|
+
"pm_getPaymasterData",
|
|
3966
|
+
[operation, ENTRY_POINT_V06, (0, import_viem9.toHex)(8453), {}],
|
|
3967
|
+
"prepare"
|
|
3968
|
+
);
|
|
3969
|
+
if (!final.paymasterAndData?.startsWith("0x"))
|
|
3970
|
+
throw sponsorError("CDP did not return final paymaster data.", true);
|
|
3971
|
+
operation = { ...operation, paymasterAndData: final.paymasterAndData };
|
|
3972
|
+
}
|
|
3973
|
+
const userOpHash = operationHash(operation);
|
|
3974
|
+
const wallet = (0, import_viem9.createWalletClient)({
|
|
3975
|
+
account: input.owner,
|
|
3976
|
+
chain: import_chains3.base,
|
|
3977
|
+
transport: (0, import_viem9.custom)(input.state.provider)
|
|
3978
|
+
});
|
|
3979
|
+
const signature = await wallet.signMessage({ message: { raw: userOpHash } });
|
|
3980
|
+
operation = { ...operation, signature };
|
|
3981
|
+
input.onPending?.({ userOpHash });
|
|
3982
|
+
const submittedHash = await rpc(
|
|
3983
|
+
input.rpcUrl,
|
|
3984
|
+
"eth_sendUserOperation",
|
|
3985
|
+
[operation, ENTRY_POINT_V06],
|
|
3986
|
+
"send"
|
|
3987
|
+
);
|
|
3988
|
+
if (submittedHash.toLowerCase() !== userOpHash.toLowerCase())
|
|
3989
|
+
throw sponsorError(
|
|
3990
|
+
"Bundler returned a different UserOperation hash.",
|
|
3991
|
+
false,
|
|
3992
|
+
{ userOpHash, submittedHash }
|
|
3993
|
+
);
|
|
3994
|
+
for (let poll = 0; poll < 40; poll++) {
|
|
3995
|
+
const response = await rpc(input.rpcUrl, "eth_getUserOperationReceipt", [userOpHash], "observe");
|
|
3996
|
+
const txHash = response?.receipt?.transactionHash;
|
|
3997
|
+
if (txHash) {
|
|
3998
|
+
input.onPending?.({ userOpHash, txHash });
|
|
3999
|
+
if (response?.success === false)
|
|
4000
|
+
throw new OwneyError(
|
|
4001
|
+
"AGENT_TRANSACTION_REVERTED",
|
|
4002
|
+
"Sponsored withdrawal execution reverted.",
|
|
4003
|
+
{ userOpHash, transactionHash: txHash },
|
|
4004
|
+
"yieldseeker"
|
|
4005
|
+
);
|
|
4006
|
+
return { txHash, receipt: await waitForTransaction(input.client, txHash) };
|
|
4007
|
+
}
|
|
4008
|
+
await new Promise((resolve) => setTimeout(resolve, 1500));
|
|
4009
|
+
}
|
|
4010
|
+
throw sponsorError(
|
|
4011
|
+
"Sponsored withdrawal is still pending; check status before retrying.",
|
|
4012
|
+
false,
|
|
4013
|
+
{ userOpHash }
|
|
4014
|
+
);
|
|
4015
|
+
}
|
|
4016
|
+
async function submitSmart(input) {
|
|
4017
|
+
let capabilities;
|
|
4018
|
+
try {
|
|
4019
|
+
capabilities = await input.state.provider.request({
|
|
4020
|
+
method: "wallet_getCapabilities",
|
|
4021
|
+
params: [input.owner]
|
|
4022
|
+
});
|
|
4023
|
+
} catch {
|
|
4024
|
+
throw sponsorError("This account cannot check paymaster support on Base.", true);
|
|
4025
|
+
}
|
|
4026
|
+
if (!capabilities?.[(0, import_viem9.toHex)(8453)]?.paymasterService?.supported && !capabilities?.["8453"]?.paymasterService?.supported)
|
|
4027
|
+
throw sponsorError("This account cannot use a paymaster on Base.", true);
|
|
4028
|
+
let sent;
|
|
4029
|
+
try {
|
|
4030
|
+
input.onPending?.({});
|
|
4031
|
+
} catch {
|
|
4032
|
+
throw sponsorError("Upgrade or withdrawal status cannot be saved.", true);
|
|
4033
|
+
}
|
|
4034
|
+
try {
|
|
4035
|
+
sent = await input.state.provider.request({
|
|
4036
|
+
method: "wallet_sendCalls",
|
|
4037
|
+
params: [{
|
|
4038
|
+
version: "2.0.0",
|
|
4039
|
+
from: input.owner,
|
|
4040
|
+
chainId: (0, import_viem9.toHex)(8453),
|
|
4041
|
+
atomicRequired: false,
|
|
4042
|
+
calls: [{ to: input.agentWallet, value: "0x0", data: input.callData }],
|
|
4043
|
+
capabilities: { paymasterService: { url: input.rpcUrl } }
|
|
4044
|
+
}]
|
|
4045
|
+
});
|
|
4046
|
+
} catch (error) {
|
|
4047
|
+
if (error?.code === 4001) throw error;
|
|
4048
|
+
if ([4200, -32601].includes(Number(error?.code)))
|
|
4049
|
+
throw sponsorError("This account does not support sponsored calls.", true);
|
|
4050
|
+
throw sponsorError("Wallet submission status is unknown. Check activity before retrying.", false);
|
|
4051
|
+
}
|
|
4052
|
+
const callsId = typeof sent === "string" ? sent : sent?.id;
|
|
4053
|
+
if (!callsId) throw sponsorError("Wallet returned no calls ID; submission status is unknown.", false);
|
|
4054
|
+
try {
|
|
4055
|
+
input.onPending?.({ callsId });
|
|
4056
|
+
} catch {
|
|
4057
|
+
throw sponsorError("Submitted call status could not be saved.", false, { callsId });
|
|
4058
|
+
}
|
|
4059
|
+
for (let poll = 0; poll < 40; poll++) {
|
|
4060
|
+
let status;
|
|
4061
|
+
try {
|
|
4062
|
+
status = await input.state.provider.request({
|
|
4063
|
+
method: "wallet_getCallsStatus",
|
|
4064
|
+
params: [callsId]
|
|
4065
|
+
});
|
|
4066
|
+
} catch {
|
|
4067
|
+
throw sponsorError("Sponsored withdrawal status is unknown.", false, { callsId });
|
|
4068
|
+
}
|
|
4069
|
+
if (status?.status === 400 || status?.status === 500)
|
|
4070
|
+
throw sponsorError(
|
|
4071
|
+
"Sponsored withdrawal failed in the wallet.",
|
|
4072
|
+
false,
|
|
4073
|
+
{ callsId, executionFailed: true }
|
|
4074
|
+
);
|
|
4075
|
+
const txHash = status?.receipts?.[0]?.transactionHash;
|
|
4076
|
+
if (txHash) {
|
|
4077
|
+
try {
|
|
4078
|
+
input.onPending?.({ callsId, txHash });
|
|
4079
|
+
} catch {
|
|
4080
|
+
throw sponsorError(
|
|
4081
|
+
"Submitted call receipt could not be saved.",
|
|
4082
|
+
false,
|
|
4083
|
+
{ callsId, txHash }
|
|
4084
|
+
);
|
|
4085
|
+
}
|
|
4086
|
+
return { txHash, receipt: await waitForTransaction(input.client, txHash) };
|
|
4087
|
+
}
|
|
4088
|
+
await new Promise((resolve) => setTimeout(resolve, 1500));
|
|
4089
|
+
}
|
|
4090
|
+
throw sponsorError(
|
|
4091
|
+
"Sponsored withdrawal is still pending; check status before retrying.",
|
|
4092
|
+
false,
|
|
4093
|
+
{ callsId }
|
|
4094
|
+
);
|
|
4095
|
+
}
|
|
4096
|
+
async function submitYieldseekerSponsoredWithdrawal(input) {
|
|
4097
|
+
const owner = (0, import_viem9.getAddress)(input.state.walletAddress);
|
|
4098
|
+
const { intent, rpcUrl } = await requestIntent({
|
|
4099
|
+
apiKey: input.apiKey,
|
|
4100
|
+
routingApiBaseUrl: input.routingApiBaseUrl,
|
|
4101
|
+
yieldseekerSignature: input.yieldseekerSignature,
|
|
4102
|
+
userId: input.userId,
|
|
4103
|
+
agentId: input.agentId,
|
|
4104
|
+
owner,
|
|
4105
|
+
agentWallet: input.agentWallet,
|
|
4106
|
+
asset: input.asset,
|
|
4107
|
+
callData: input.callData,
|
|
4108
|
+
action: "withdraw"
|
|
4109
|
+
});
|
|
4110
|
+
const args = { ...input, owner, rpcUrl };
|
|
4111
|
+
return intent.ownerPath === "eoa" ? submitEoa(args) : submitSmart(args);
|
|
4112
|
+
}
|
|
4113
|
+
async function submitYieldseekerSponsoredUpgrade(input) {
|
|
4114
|
+
const owner = (0, import_viem9.getAddress)(input.state.walletAddress);
|
|
4115
|
+
const { intent, rpcUrl } = await requestIntent({
|
|
4116
|
+
apiKey: input.apiKey,
|
|
4117
|
+
routingApiBaseUrl: input.routingApiBaseUrl,
|
|
4118
|
+
yieldseekerSignature: input.yieldseekerSignature,
|
|
4119
|
+
userId: input.userId,
|
|
4120
|
+
agentId: input.agentId,
|
|
4121
|
+
owner,
|
|
4122
|
+
agentWallet: input.agentWallet,
|
|
4123
|
+
asset: input.asset,
|
|
4124
|
+
callData: input.callData,
|
|
4125
|
+
action: "upgrade"
|
|
4126
|
+
});
|
|
4127
|
+
if (intent.ownerPath !== "smart")
|
|
4128
|
+
throw sponsorError("V1 upgrade sponsorship requires a Base Account owner.", true);
|
|
4129
|
+
return submitSmart({ ...input, owner, rpcUrl });
|
|
4130
|
+
}
|
|
4131
|
+
|
|
3743
4132
|
// src/agents/yieldseeker/yieldseeker.agent.ts
|
|
3744
4133
|
var OWNEY_AGENT_NAME = "owney";
|
|
3745
4134
|
var OWNEY_AGENT_RULE_PRESET = "explorative";
|
|
@@ -3812,7 +4201,11 @@ var YieldseekerAgent = class {
|
|
|
3812
4201
|
api;
|
|
3813
4202
|
auth;
|
|
3814
4203
|
rpcUrls;
|
|
4204
|
+
owneyApiKey;
|
|
4205
|
+
routingApiBaseUrl;
|
|
3815
4206
|
receiptClient;
|
|
4207
|
+
// A client preparation hint only; the routing API still checks live identity.
|
|
4208
|
+
withdrawalVersionCache = /* @__PURE__ */ new Map();
|
|
3816
4209
|
transactionExecutor;
|
|
3817
4210
|
unwindReceiptWaiter;
|
|
3818
4211
|
agentContexts = /* @__PURE__ */ new Map();
|
|
@@ -3834,6 +4227,8 @@ var YieldseekerAgent = class {
|
|
|
3834
4227
|
yieldOptions = /* @__PURE__ */ new Map();
|
|
3835
4228
|
pendingYieldOptions = /* @__PURE__ */ new Map();
|
|
3836
4229
|
constructor(owneyApiKey, options = {}) {
|
|
4230
|
+
this.owneyApiKey = owneyApiKey;
|
|
4231
|
+
this.routingApiBaseUrl = options.routingApiBaseUrl;
|
|
3837
4232
|
this.api = new YieldseekerApiClient(
|
|
3838
4233
|
owneyApiKey,
|
|
3839
4234
|
options.baseUrl ?? getYieldseekerProxyBaseUrl(),
|
|
@@ -3845,10 +4240,182 @@ var YieldseekerAgent = class {
|
|
|
3845
4240
|
this.unwindReceiptWaiter = options.unwindReceiptWaiter;
|
|
3846
4241
|
}
|
|
3847
4242
|
getReceiptClient() {
|
|
3848
|
-
this.receiptClient ??= createPaidRpcClient(
|
|
4243
|
+
this.receiptClient ??= createPaidRpcClient(import_chains4.base, this.rpcUrls);
|
|
3849
4244
|
return this.receiptClient;
|
|
3850
4245
|
}
|
|
4246
|
+
/** Reads the actual proxy implementation; Yieldseeker's API walletType is not a version check. */
|
|
4247
|
+
async getWalletStatus(state, chainId, asset, useCachedV2 = false) {
|
|
4248
|
+
this.assertChain(chainId);
|
|
4249
|
+
this.assertAsset(asset);
|
|
4250
|
+
const context = await this.findAgent(state, chainId, asset);
|
|
4251
|
+
if (!context) return null;
|
|
4252
|
+
const key2 = `${chainId}:${state.walletAddress.toLowerCase()}:${context.wallet.walletAddress.toLowerCase()}:${asset}`;
|
|
4253
|
+
const cached = this.withdrawalVersionCache.get(key2);
|
|
4254
|
+
if (useCachedV2 && cached && Date.now() - cached.at < 15 * 6e4) return { ...cached.status };
|
|
4255
|
+
const status = await readYieldseekerWalletStatus(
|
|
4256
|
+
this.getReceiptClient(),
|
|
4257
|
+
(0, import_viem10.getAddress)(context.wallet.walletAddress),
|
|
4258
|
+
(0, import_viem10.getAddress)(state.walletAddress),
|
|
4259
|
+
YIELDSEEKER_ASSET_METADATA[asset].address
|
|
4260
|
+
);
|
|
4261
|
+
if (status.verified && status.version === "v2") {
|
|
4262
|
+
this.withdrawalVersionCache.set(key2, { at: Date.now(), status: { ...status } });
|
|
4263
|
+
if (this.withdrawalVersionCache.size > 128)
|
|
4264
|
+
this.withdrawalVersionCache.delete(this.withdrawalVersionCache.keys().next().value);
|
|
4265
|
+
} else this.withdrawalVersionCache.delete(key2);
|
|
4266
|
+
return status;
|
|
4267
|
+
}
|
|
4268
|
+
/** Explicit owner action. This never runs as a side effect of withdrawal. */
|
|
4269
|
+
async upgradeWallet(state, chainId, asset, gasMode = "paid") {
|
|
4270
|
+
const before = await this.getWalletStatus(state, chainId, asset);
|
|
4271
|
+
if (!before?.verified || !before.upgradeAvailable) {
|
|
4272
|
+
throw new OwneyError(
|
|
4273
|
+
"WITHDRAW_FAILED",
|
|
4274
|
+
"This Yieldseeker wallet cannot be upgraded to the reviewed V2 implementation.",
|
|
4275
|
+
{ version: before?.version ?? "missing" },
|
|
4276
|
+
this.id
|
|
4277
|
+
);
|
|
4278
|
+
}
|
|
4279
|
+
const data = (0, import_viem10.encodeFunctionData)({ abi: YIELDSEEKER_UPGRADE_ABI, functionName: "upgradeToLatest" });
|
|
4280
|
+
let txHash;
|
|
4281
|
+
if (gasMode === "sponsored") {
|
|
4282
|
+
if (before.ownerPath !== "smart")
|
|
4283
|
+
throw new OwneyError(
|
|
4284
|
+
"SPONSOR_REQUEST_FAILED",
|
|
4285
|
+
"EOA owners pay Base gas for the V1 upgrade.",
|
|
4286
|
+
{ safeToFallback: true },
|
|
4287
|
+
this.id
|
|
4288
|
+
);
|
|
4289
|
+
let storage5;
|
|
4290
|
+
try {
|
|
4291
|
+
storage5 = typeof window === "undefined" ? void 0 : window.localStorage;
|
|
4292
|
+
} catch {
|
|
4293
|
+
storage5 = void 0;
|
|
4294
|
+
}
|
|
4295
|
+
if (!storage5)
|
|
4296
|
+
throw new OwneyError(
|
|
4297
|
+
"SPONSOR_REQUEST_FAILED",
|
|
4298
|
+
"Upgrade status cannot be saved in this browser.",
|
|
4299
|
+
{ safeToFallback: true },
|
|
4300
|
+
this.id
|
|
4301
|
+
);
|
|
4302
|
+
const pendingKey = `owney.yieldseeker.upgrade:${state.walletAddress.toLowerCase()}:${before.agentWallet.toLowerCase()}`;
|
|
4303
|
+
let prior = null;
|
|
4304
|
+
let saved;
|
|
4305
|
+
try {
|
|
4306
|
+
saved = storage5.getItem(pendingKey);
|
|
4307
|
+
} catch {
|
|
4308
|
+
throw new OwneyError(
|
|
4309
|
+
"SPONSOR_REQUEST_FAILED",
|
|
4310
|
+
"Upgrade status cannot be read in this browser.",
|
|
4311
|
+
{ safeToFallback: true },
|
|
4312
|
+
this.id
|
|
4313
|
+
);
|
|
4314
|
+
}
|
|
4315
|
+
try {
|
|
4316
|
+
prior = JSON.parse(saved ?? "null");
|
|
4317
|
+
} catch {
|
|
4318
|
+
prior = { callsId: void 0 };
|
|
4319
|
+
}
|
|
4320
|
+
if (prior) {
|
|
4321
|
+
if (!prior.callsId)
|
|
4322
|
+
throw new OwneyError(
|
|
4323
|
+
"SPONSOR_REQUEST_FAILED",
|
|
4324
|
+
"An earlier upgrade submission is unresolved. Check wallet activity before retrying.",
|
|
4325
|
+
{ safeToFallback: false },
|
|
4326
|
+
this.id
|
|
4327
|
+
);
|
|
4328
|
+
let callsStatus;
|
|
4329
|
+
try {
|
|
4330
|
+
callsStatus = await state.provider.request({
|
|
4331
|
+
method: "wallet_getCallsStatus",
|
|
4332
|
+
params: [prior.callsId]
|
|
4333
|
+
});
|
|
4334
|
+
} catch {
|
|
4335
|
+
throw new OwneyError(
|
|
4336
|
+
"SPONSOR_REQUEST_FAILED",
|
|
4337
|
+
"The earlier upgrade status could not be checked.",
|
|
4338
|
+
{ safeToFallback: false, callsId: prior.callsId },
|
|
4339
|
+
this.id
|
|
4340
|
+
);
|
|
4341
|
+
}
|
|
4342
|
+
if (callsStatus?.status === 400 || callsStatus?.status === 500) {
|
|
4343
|
+
storage5.removeItem(pendingKey);
|
|
4344
|
+
throw new OwneyError(
|
|
4345
|
+
"SPONSOR_REQUEST_FAILED",
|
|
4346
|
+
"The earlier sponsored upgrade failed.",
|
|
4347
|
+
{ safeToFallback: true, callsId: prior.callsId },
|
|
4348
|
+
this.id
|
|
4349
|
+
);
|
|
4350
|
+
}
|
|
4351
|
+
const earlierHash = callsStatus?.receipts?.[0]?.transactionHash;
|
|
4352
|
+
if (earlierHash) {
|
|
4353
|
+
await this.waitForReceipt(state, chainId, earlierHash);
|
|
4354
|
+
const earlierStatus = await this.getWalletStatus(state, chainId, asset);
|
|
4355
|
+
if (earlierStatus?.version === "v2" && earlierStatus.verified) {
|
|
4356
|
+
storage5.removeItem(pendingKey);
|
|
4357
|
+
return { txHash: earlierHash, status: earlierStatus };
|
|
4358
|
+
}
|
|
4359
|
+
}
|
|
4360
|
+
throw new OwneyError(
|
|
4361
|
+
"SPONSOR_REQUEST_FAILED",
|
|
4362
|
+
"An earlier upgrade is still pending.",
|
|
4363
|
+
{ safeToFallback: false, callsId: prior.callsId },
|
|
4364
|
+
this.id
|
|
4365
|
+
);
|
|
4366
|
+
}
|
|
4367
|
+
const context = await this.findAgent(state, chainId, asset);
|
|
4368
|
+
if (!context) throw new OwneyError("NOT_CONNECTED", "Yieldseeker agent is unavailable.");
|
|
4369
|
+
try {
|
|
4370
|
+
const upgraded = await submitYieldseekerSponsoredUpgrade({
|
|
4371
|
+
state,
|
|
4372
|
+
client: this.getReceiptClient(),
|
|
4373
|
+
apiKey: this.owneyApiKey,
|
|
4374
|
+
routingApiBaseUrl: this.routingApiBaseUrl,
|
|
4375
|
+
yieldseekerSignature: await this.auth.getToken(state, chainId),
|
|
4376
|
+
userId: context.user.userId,
|
|
4377
|
+
agentId: context.agent.agentId,
|
|
4378
|
+
agentWallet: before.agentWallet,
|
|
4379
|
+
asset: YIELDSEEKER_ASSET_METADATA[asset].address,
|
|
4380
|
+
callData: data,
|
|
4381
|
+
onPending: (pending) => {
|
|
4382
|
+
const current = storage5.getItem(pendingKey);
|
|
4383
|
+
storage5.setItem(pendingKey, JSON.stringify({
|
|
4384
|
+
startedAt: Date.now(),
|
|
4385
|
+
...current ? JSON.parse(current) : {},
|
|
4386
|
+
...pending
|
|
4387
|
+
}));
|
|
4388
|
+
}
|
|
4389
|
+
});
|
|
4390
|
+
txHash = upgraded.txHash;
|
|
4391
|
+
} catch (error) {
|
|
4392
|
+
if (error?.code === 4001 || error instanceof OwneyError && error.code === "SPONSOR_REQUEST_FAILED" && (error.details?.safeToFallback === true || error.details?.executionFailed === true)) storage5.removeItem(pendingKey);
|
|
4393
|
+
throw error;
|
|
4394
|
+
}
|
|
4395
|
+
} else {
|
|
4396
|
+
txHash = await this.submitTransaction(state, chainId, {
|
|
4397
|
+
from: (0, import_viem10.getAddress)(state.walletAddress),
|
|
4398
|
+
to: before.agentWallet,
|
|
4399
|
+
data,
|
|
4400
|
+
value: "0",
|
|
4401
|
+
chainId
|
|
4402
|
+
});
|
|
4403
|
+
}
|
|
4404
|
+
const status = await this.getWalletStatus(state, chainId, asset);
|
|
4405
|
+
if (!status?.verified || status.version !== "v2") {
|
|
4406
|
+
throw new OwneyError(
|
|
4407
|
+
"WITHDRAW_FAILED",
|
|
4408
|
+
"Yieldseeker wallet upgrade was not confirmed as V2.",
|
|
4409
|
+
{ txHash, version: status?.version ?? "missing" },
|
|
4410
|
+
this.id
|
|
4411
|
+
);
|
|
4412
|
+
}
|
|
4413
|
+
if (gasMode === "sponsored" && typeof window !== "undefined")
|
|
4414
|
+
window.localStorage.removeItem(`owney.yieldseeker.upgrade:${state.walletAddress.toLowerCase()}:${before.agentWallet.toLowerCase()}`);
|
|
4415
|
+
return { txHash, status };
|
|
4416
|
+
}
|
|
3851
4417
|
async disconnect() {
|
|
4418
|
+
this.withdrawalVersionCache.clear();
|
|
3852
4419
|
this.readGeneration += 1;
|
|
3853
4420
|
this.auth.clear();
|
|
3854
4421
|
for (const key2 of this.users.keys()) {
|
|
@@ -3919,12 +4486,12 @@ var YieldseekerAgent = class {
|
|
|
3919
4486
|
receipt = await this.waitForReceipt(state, chainId, txHash);
|
|
3920
4487
|
} else {
|
|
3921
4488
|
txHash = await this.submitTransaction(state, chainId, {
|
|
3922
|
-
from: (0,
|
|
4489
|
+
from: (0, import_viem10.getAddress)(state.walletAddress),
|
|
3923
4490
|
to: YIELDSEEKER_ASSET_METADATA[asset].address,
|
|
3924
|
-
data: (0,
|
|
3925
|
-
abi:
|
|
4491
|
+
data: (0, import_viem10.encodeFunctionData)({
|
|
4492
|
+
abi: import_viem10.erc20Abi,
|
|
3926
4493
|
functionName: "transfer",
|
|
3927
|
-
args: [(0,
|
|
4494
|
+
args: [(0, import_viem10.getAddress)(context.wallet.walletAddress), BigInt(amount)]
|
|
3928
4495
|
}),
|
|
3929
4496
|
value: "0",
|
|
3930
4497
|
chainId
|
|
@@ -3935,12 +4502,12 @@ var YieldseekerAgent = class {
|
|
|
3935
4502
|
if (this.readGeneration === generation) {
|
|
3936
4503
|
void this.refreshSnapshotAfterMovement(state, chainId, context, "deposit", movement);
|
|
3937
4504
|
}
|
|
3938
|
-
const
|
|
3939
|
-
const evidence = receipt ? inspectFundingReceipt(receipt,
|
|
4505
|
+
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" };
|
|
4506
|
+
const evidence = receipt ? inspectFundingReceipt(receipt, base6, YIELDSEEKER_ASSET_METADATA[asset].address, "deposit") : base6;
|
|
3940
4507
|
notifyFunding(onProgress, evidence);
|
|
3941
4508
|
return { txHash, smartWallet: context.wallet.walletAddress, amount, evidence };
|
|
3942
4509
|
}
|
|
3943
|
-
async withdraw(state, chainId, asset, amount, onProgress) {
|
|
4510
|
+
async withdraw(state, chainId, asset, amount, onProgress, gasMode = "auto") {
|
|
3944
4511
|
let ownerTransferAttempted = false;
|
|
3945
4512
|
let evidence = {
|
|
3946
4513
|
agentId: this.id,
|
|
@@ -3958,14 +4525,20 @@ var YieldseekerAgent = class {
|
|
|
3958
4525
|
notifyFunding(onProgress, evidence);
|
|
3959
4526
|
}, () => {
|
|
3960
4527
|
ownerTransferAttempted = true;
|
|
3961
|
-
});
|
|
4528
|
+
}, gasMode);
|
|
3962
4529
|
} catch (error) {
|
|
3963
|
-
if (
|
|
3964
|
-
|
|
4530
|
+
if (error instanceof OwneyError && error.code === "SPONSOR_REQUEST_FAILED") this.withdrawalVersionCache.clear();
|
|
4531
|
+
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)))
|
|
4532
|
+
notifyFunding(onProgress, {
|
|
4533
|
+
...evidence,
|
|
4534
|
+
...error instanceof OwneyError && error.code === "SPONSOR_REQUEST_FAILED" && error.details?.safeToFallback === true ? { userOpHash: void 0, callsId: void 0 } : {},
|
|
4535
|
+
transfer: "failed",
|
|
4536
|
+
delivery: "failed"
|
|
4537
|
+
});
|
|
3965
4538
|
throw error;
|
|
3966
4539
|
}
|
|
3967
4540
|
}
|
|
3968
|
-
async withdrawInternal(state, chainId, asset, amount, onProgress, onOwnerTransferAttempted) {
|
|
4541
|
+
async withdrawInternal(state, chainId, asset, amount, onProgress, onOwnerTransferAttempted, gasMode = "auto") {
|
|
3969
4542
|
this.assertChain(chainId);
|
|
3970
4543
|
this.assertAsset(asset);
|
|
3971
4544
|
if (amount !== void 0 && BigInt(amount) <= 0n) {
|
|
@@ -3985,6 +4558,27 @@ var YieldseekerAgent = class {
|
|
|
3985
4558
|
this.id
|
|
3986
4559
|
);
|
|
3987
4560
|
}
|
|
4561
|
+
let sponsor = false;
|
|
4562
|
+
if (gasMode !== "paid") {
|
|
4563
|
+
const status = await this.getWalletStatus(state, chainId, asset, true).catch(() => {
|
|
4564
|
+
if (gasMode === "sponsored")
|
|
4565
|
+
throw new OwneyError(
|
|
4566
|
+
"SPONSOR_REQUEST_FAILED",
|
|
4567
|
+
"Could not verify the Yieldseeker wallet for sponsorship.",
|
|
4568
|
+
{ safeToFallback: true, version: "unknown" },
|
|
4569
|
+
this.id
|
|
4570
|
+
);
|
|
4571
|
+
return null;
|
|
4572
|
+
});
|
|
4573
|
+
sponsor = !!status?.verified && status.version === "v2";
|
|
4574
|
+
if (gasMode === "sponsored" && !sponsor)
|
|
4575
|
+
throw new OwneyError(
|
|
4576
|
+
"SPONSOR_REQUEST_FAILED",
|
|
4577
|
+
"Only a verified Yieldseeker V2 Agent Wallet can use sponsored withdrawals.",
|
|
4578
|
+
{ safeToFallback: true, version: status?.version ?? "unknown" },
|
|
4579
|
+
this.id
|
|
4580
|
+
);
|
|
4581
|
+
}
|
|
3988
4582
|
const generation = this.readGeneration;
|
|
3989
4583
|
let confirmedMovement = false;
|
|
3990
4584
|
let settlement = null;
|
|
@@ -3998,9 +4592,9 @@ var YieldseekerAgent = class {
|
|
|
3998
4592
|
const readIdle = async () => {
|
|
3999
4593
|
const balance = await withPaidRpcDiagnostics(() => this.getReceiptClient().readContract({
|
|
4000
4594
|
address: metadata.address,
|
|
4001
|
-
abi:
|
|
4595
|
+
abi: import_viem10.erc20Abi,
|
|
4002
4596
|
functionName: "balanceOf",
|
|
4003
|
-
args: [(0,
|
|
4597
|
+
args: [(0, import_viem10.getAddress)(context.wallet.walletAddress)]
|
|
4004
4598
|
}), chainId, "eth_call", this.id);
|
|
4005
4599
|
this.assertSession(generation, chainId, asset);
|
|
4006
4600
|
return balance;
|
|
@@ -4034,6 +4628,7 @@ var YieldseekerAgent = class {
|
|
|
4034
4628
|
);
|
|
4035
4629
|
}
|
|
4036
4630
|
let remaining = requested > idle ? requested - idle : 0n;
|
|
4631
|
+
let grossUnwound = 0n;
|
|
4037
4632
|
for (const position2 of portfolio.positions) {
|
|
4038
4633
|
if (remaining === 0n) break;
|
|
4039
4634
|
const available = BigInt(position2.withdrawableAssetsRaw);
|
|
@@ -4057,6 +4652,7 @@ var YieldseekerAgent = class {
|
|
|
4057
4652
|
}
|
|
4058
4653
|
await this.waitForReceipt(state, chainId, response.transactionHash);
|
|
4059
4654
|
confirmedMovement = true;
|
|
4655
|
+
grossUnwound += assetsRaw;
|
|
4060
4656
|
remaining -= assetsRaw;
|
|
4061
4657
|
}
|
|
4062
4658
|
if (remaining > 0n) {
|
|
@@ -4066,7 +4662,10 @@ var YieldseekerAgent = class {
|
|
|
4066
4662
|
});
|
|
4067
4663
|
}
|
|
4068
4664
|
const availableForOwner = confirmedMovement ? await readIdle() : idle;
|
|
4069
|
-
|
|
4665
|
+
const feeRate = portfolio.snapshot.feeRateBps;
|
|
4666
|
+
const maxFee = confirmedMovement && Number.isInteger(feeRate) && feeRate >= 0 && feeRate <= 1e3 ? (grossUnwound * BigInt(feeRate) + 9999n) / 10000n : 0n;
|
|
4667
|
+
const shortfall = availableForOwner < requested ? requested - availableForOwner : 0n;
|
|
4668
|
+
if (availableForOwner === 0n || amount !== void 0 && shortfall > maxFee) {
|
|
4070
4669
|
this.invalidateFundingRead(state, chainId, asset);
|
|
4071
4670
|
throw new OwneyError(
|
|
4072
4671
|
"WITHDRAW_INSUFFICIENT_BALANCE",
|
|
@@ -4075,32 +4674,52 @@ var YieldseekerAgent = class {
|
|
|
4075
4674
|
this.id
|
|
4076
4675
|
);
|
|
4077
4676
|
}
|
|
4078
|
-
const payout = amount === void 0 ? availableForOwner : requested;
|
|
4677
|
+
const payout = amount === void 0 || availableForOwner < requested ? availableForOwner : requested;
|
|
4079
4678
|
const plannedMovement = this.snapshotMovement(state, chainId, context, -payout);
|
|
4080
|
-
const account = (0,
|
|
4679
|
+
const account = (0, import_viem10.getAddress)(state.walletAddress);
|
|
4081
4680
|
let receipt;
|
|
4082
|
-
const
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
}) : (0, import_viem8.encodeFunctionData)({
|
|
4092
|
-
abi: YIELDSEEKER_AGENT_WALLET_ABI,
|
|
4093
|
-
functionName: "withdrawAssetToUser",
|
|
4094
|
-
args: [account, metadata.address, requested]
|
|
4095
|
-
}),
|
|
4096
|
-
value: "0",
|
|
4097
|
-
chainId
|
|
4098
|
-
}, (hash) => notifyFunding(onProgress, { ...base5, txHash: hash }), (value) => {
|
|
4099
|
-
receipt = value;
|
|
4681
|
+
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" };
|
|
4682
|
+
const data = amount === void 0 ? (0, import_viem10.encodeFunctionData)({
|
|
4683
|
+
abi: YIELDSEEKER_AGENT_WALLET_ABI,
|
|
4684
|
+
functionName: "withdrawAllAssetToUser",
|
|
4685
|
+
args: [account, metadata.address]
|
|
4686
|
+
}) : (0, import_viem10.encodeFunctionData)({
|
|
4687
|
+
abi: YIELDSEEKER_AGENT_WALLET_ABI,
|
|
4688
|
+
functionName: "withdrawAssetToUser",
|
|
4689
|
+
args: [account, metadata.address, payout]
|
|
4100
4690
|
});
|
|
4691
|
+
onOwnerTransferAttempted?.();
|
|
4692
|
+
let txHash;
|
|
4693
|
+
if (sponsor) {
|
|
4694
|
+
const submitted = await submitYieldseekerSponsoredWithdrawal({
|
|
4695
|
+
state,
|
|
4696
|
+
client: this.getReceiptClient(),
|
|
4697
|
+
apiKey: this.owneyApiKey,
|
|
4698
|
+
routingApiBaseUrl: this.routingApiBaseUrl,
|
|
4699
|
+
yieldseekerSignature: await this.auth.getToken(state, chainId),
|
|
4700
|
+
userId: context.user.userId,
|
|
4701
|
+
agentId: context.agent.agentId,
|
|
4702
|
+
agentWallet: (0, import_viem10.getAddress)(context.wallet.walletAddress),
|
|
4703
|
+
asset: metadata.address,
|
|
4704
|
+
callData: data,
|
|
4705
|
+
onPending: (pending) => notifyFunding(onProgress, { ...base6, ...pending })
|
|
4706
|
+
});
|
|
4707
|
+
txHash = submitted.txHash;
|
|
4708
|
+
receipt = submitted.receipt;
|
|
4709
|
+
} else {
|
|
4710
|
+
txHash = await this.submitTransaction(state, chainId, {
|
|
4711
|
+
from: account,
|
|
4712
|
+
to: (0, import_viem10.getAddress)(context.wallet.walletAddress),
|
|
4713
|
+
data,
|
|
4714
|
+
value: "0",
|
|
4715
|
+
chainId
|
|
4716
|
+
}, (hash) => notifyFunding(onProgress, { ...base6, txHash: hash }), (value) => {
|
|
4717
|
+
receipt = value;
|
|
4718
|
+
});
|
|
4719
|
+
}
|
|
4101
4720
|
confirmedMovement = true;
|
|
4102
4721
|
settlement = plannedMovement;
|
|
4103
|
-
const evidence = receipt ? inspectFundingReceipt(receipt, { ...
|
|
4722
|
+
const evidence = receipt ? inspectFundingReceipt(receipt, { ...base6, txHash }, metadata.address, "withdraw") : { ...base6, txHash, confirmedAmount: payout.toString(), transfer: "confirmed", delivery: "confirmed" };
|
|
4104
4723
|
notifyFunding(onProgress, evidence);
|
|
4105
4724
|
if (evidence.transfer === "failed" && evidence.confirmedAmount === "0")
|
|
4106
4725
|
throw new OwneyError(
|
|
@@ -4186,7 +4805,7 @@ var YieldseekerAgent = class {
|
|
|
4186
4805
|
);
|
|
4187
4806
|
const vaultAddresses = new Set(
|
|
4188
4807
|
catalog.flat().filter(
|
|
4189
|
-
(yieldOption) => yieldOption.chainId === chainId && (0,
|
|
4808
|
+
(yieldOption) => yieldOption.chainId === chainId && (0, import_viem10.isAddress)(yieldOption.address)
|
|
4190
4809
|
).map((yieldOption) => yieldOption.address.toLowerCase())
|
|
4191
4810
|
);
|
|
4192
4811
|
return mapYieldseekerHistory(contexts, {
|
|
@@ -4313,7 +4932,7 @@ var YieldseekerAgent = class {
|
|
|
4313
4932
|
`/users/${user.userId}/agents/${agent.agentId}/wallet`
|
|
4314
4933
|
).then((walletResponse) => {
|
|
4315
4934
|
this.assertSession(generation, chainId, asset);
|
|
4316
|
-
if (!walletResponse?.agentWallet || !(0,
|
|
4935
|
+
if (!walletResponse?.agentWallet || !(0, import_viem10.isAddress)(walletResponse.agentWallet.walletAddress)) {
|
|
4317
4936
|
throw this.invalidResponse("agent wallet");
|
|
4318
4937
|
}
|
|
4319
4938
|
const context = {
|
|
@@ -4343,7 +4962,7 @@ var YieldseekerAgent = class {
|
|
|
4343
4962
|
this.users.set(key2, persisted);
|
|
4344
4963
|
return persisted;
|
|
4345
4964
|
}
|
|
4346
|
-
const walletAddress = (0,
|
|
4965
|
+
const walletAddress = (0, import_viem10.getAddress)(state.walletAddress);
|
|
4347
4966
|
const generation = this.readGeneration;
|
|
4348
4967
|
let user = null;
|
|
4349
4968
|
try {
|
|
@@ -4726,7 +5345,7 @@ var YieldseekerAgent = class {
|
|
|
4726
5345
|
this.agentPath(context, "deploy"),
|
|
4727
5346
|
{ method: "POST", body: {} }
|
|
4728
5347
|
);
|
|
4729
|
-
if (!deployed?.agentWallet || !(0,
|
|
5348
|
+
if (!deployed?.agentWallet || !(0, import_viem10.isAddress)(deployed.agentWallet.walletAddress) || deployed.agentWallet.walletAddress.toLowerCase() !== walletAddress) {
|
|
4730
5349
|
throw this.invalidResponse("agent deployment", {
|
|
4731
5350
|
reason: "Deploy did not return the expected Agent Wallet."
|
|
4732
5351
|
});
|
|
@@ -4834,15 +5453,15 @@ var YieldseekerAgent = class {
|
|
|
4834
5453
|
return hash2;
|
|
4835
5454
|
}
|
|
4836
5455
|
this.assertTransaction(transaction, state, chainId);
|
|
4837
|
-
const account = (0,
|
|
4838
|
-
const walletClient = (0,
|
|
5456
|
+
const account = (0, import_viem10.getAddress)(state.walletAddress);
|
|
5457
|
+
const walletClient = (0, import_viem10.createWalletClient)({
|
|
4839
5458
|
account,
|
|
4840
|
-
chain:
|
|
4841
|
-
transport: (0,
|
|
5459
|
+
chain: import_chains4.base,
|
|
5460
|
+
transport: (0, import_viem10.custom)(state.provider)
|
|
4842
5461
|
});
|
|
4843
|
-
const walletChainClient = (0,
|
|
4844
|
-
chain:
|
|
4845
|
-
transport: (0,
|
|
5462
|
+
const walletChainClient = (0, import_viem10.createPublicClient)({
|
|
5463
|
+
chain: import_chains4.base,
|
|
5464
|
+
transport: (0, import_viem10.custom)(state.provider)
|
|
4846
5465
|
});
|
|
4847
5466
|
await ensureWalletOnChain(
|
|
4848
5467
|
walletChainClient,
|
|
@@ -4851,8 +5470,8 @@ var YieldseekerAgent = class {
|
|
|
4851
5470
|
);
|
|
4852
5471
|
const hash = await walletClient.sendTransaction({
|
|
4853
5472
|
account,
|
|
4854
|
-
chain:
|
|
4855
|
-
to: (0,
|
|
5473
|
+
chain: import_chains4.base,
|
|
5474
|
+
to: (0, import_viem10.getAddress)(transaction.to),
|
|
4856
5475
|
data: transaction.data,
|
|
4857
5476
|
value: BigInt(transaction.value)
|
|
4858
5477
|
});
|
|
@@ -4902,12 +5521,12 @@ var YieldseekerAgent = class {
|
|
|
4902
5521
|
return receipt;
|
|
4903
5522
|
}
|
|
4904
5523
|
assertTransaction(transaction, state, chainId) {
|
|
4905
|
-
if (!transaction || typeof transaction.from !== "string" || !(0,
|
|
5524
|
+
if (!transaction || typeof transaction.from !== "string" || !(0, import_viem10.isAddress)(transaction.from) || typeof transaction.to !== "string" || !(0, import_viem10.isAddress)(transaction.to) || typeof transaction.data !== "string" || !/^0x[a-fA-F0-9]*$/.test(transaction.data) || typeof transaction.value !== "string" || !/^[0-9]+$/.test(transaction.value) || transaction.chainId !== chainId || (0, import_viem10.getAddress)(transaction.from) !== (0, import_viem10.getAddress)(state.walletAddress)) {
|
|
4906
5525
|
throw this.invalidResponse("transaction");
|
|
4907
5526
|
}
|
|
4908
5527
|
}
|
|
4909
5528
|
assertAgent(agent) {
|
|
4910
|
-
if (typeof agent.agentId !== "string" || typeof agent.assetAddress !== "string" || !(0,
|
|
5529
|
+
if (typeof agent.agentId !== "string" || typeof agent.assetAddress !== "string" || !(0, import_viem10.isAddress)(agent.assetAddress) || agent.chainId !== 8453) {
|
|
4911
5530
|
throw this.invalidResponse("agent");
|
|
4912
5531
|
}
|
|
4913
5532
|
}
|
|
@@ -4964,6 +5583,7 @@ var YieldseekerAgent = class {
|
|
|
4964
5583
|
|
|
4965
5584
|
// src/lib/routing-api.ts
|
|
4966
5585
|
var ROUTING_API_BASE_URL2 = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
5586
|
+
var getRoutingApiBaseUrl = (override) => override ?? ROUTING_API_BASE_URL2;
|
|
4967
5587
|
async function fetchOrgAgentConfig(apiKey, baseUrl = ROUTING_API_BASE_URL2) {
|
|
4968
5588
|
const url = `${baseUrl}/api/v1/agent/org-config`;
|
|
4969
5589
|
try {
|
|
@@ -5060,7 +5680,7 @@ async function withFailureReporting(apiKey, agentType, fn, baseUrl) {
|
|
|
5060
5680
|
}
|
|
5061
5681
|
|
|
5062
5682
|
// src/lib/helpers/withdraw-helper.ts
|
|
5063
|
-
var
|
|
5683
|
+
var import_viem11 = require("viem");
|
|
5064
5684
|
function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
|
|
5065
5685
|
const target = asset.toUpperCase();
|
|
5066
5686
|
return agents.map((agent) => {
|
|
@@ -5068,7 +5688,7 @@ function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decima
|
|
|
5068
5688
|
const tokenBalance = agentBalance?.tokens.find(
|
|
5069
5689
|
(t) => t.chainId === chainId && t.asset.toUpperCase() === target
|
|
5070
5690
|
);
|
|
5071
|
-
let balance = tokenBalance ? (0,
|
|
5691
|
+
let balance = tokenBalance ? (0, import_viem11.parseUnits)(tokenBalance.amount, decimals) : 0n;
|
|
5072
5692
|
if (agent.balanceComposition === "tokens-plus-positions") {
|
|
5073
5693
|
const chainNameById = {
|
|
5074
5694
|
1: "ETHEREUM",
|
|
@@ -5080,14 +5700,14 @@ function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decima
|
|
|
5080
5700
|
const positionChain = position2.chain.trim().toUpperCase();
|
|
5081
5701
|
const matchesChain = positionChain === String(chainId) || targetChain !== void 0 && positionChain === targetChain;
|
|
5082
5702
|
if (!matchesChain || position2.asset.toUpperCase() !== target) continue;
|
|
5083
|
-
balance += position2.withdrawableAmountRaw !== void 0 ? BigInt(position2.withdrawableAmountRaw) : (0,
|
|
5703
|
+
balance += position2.withdrawableAmountRaw !== void 0 ? BigInt(position2.withdrawableAmountRaw) : (0, import_viem11.parseUnits)(position2.amount, decimals);
|
|
5084
5704
|
}
|
|
5085
5705
|
}
|
|
5086
5706
|
const assetTotal = agentBalance?.assetBalances?.find(
|
|
5087
5707
|
(t) => t.chainId === chainId && t.asset.toUpperCase() === target
|
|
5088
5708
|
);
|
|
5089
5709
|
if (assetTotal) {
|
|
5090
|
-
const total = (0,
|
|
5710
|
+
const total = (0, import_viem11.parseUnits)(assetTotal.amount, decimals);
|
|
5091
5711
|
if (total < balance) balance = total > 0n ? total : 0n;
|
|
5092
5712
|
}
|
|
5093
5713
|
return { agent, balance };
|
|
@@ -5246,17 +5866,16 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
|
|
|
5246
5866
|
}
|
|
5247
5867
|
|
|
5248
5868
|
// src/client.ts
|
|
5249
|
-
var
|
|
5250
|
-
var
|
|
5869
|
+
var import_viem15 = require("viem");
|
|
5870
|
+
var import_chains5 = require("viem/chains");
|
|
5251
5871
|
|
|
5252
5872
|
// src/lib/sponsored-token-batch.ts
|
|
5253
|
-
var
|
|
5873
|
+
var import_viem13 = require("viem");
|
|
5254
5874
|
|
|
5255
5875
|
// src/lib/permit2-batch.ts
|
|
5256
|
-
var
|
|
5876
|
+
var import_viem12 = require("viem");
|
|
5257
5877
|
var BATCH_PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
5258
5878
|
var BASE_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
|
|
5259
|
-
var MULTICALL3_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976CA11";
|
|
5260
5879
|
var ERC2612_PERMIT_TYPES = {
|
|
5261
5880
|
Permit: [
|
|
5262
5881
|
{ name: "owner", type: "address" },
|
|
@@ -5266,7 +5885,7 @@ var ERC2612_PERMIT_TYPES = {
|
|
|
5266
5885
|
{ name: "deadline", type: "uint256" }
|
|
5267
5886
|
]
|
|
5268
5887
|
};
|
|
5269
|
-
var ERC2612_READ_ABI = (0,
|
|
5888
|
+
var ERC2612_READ_ABI = (0, import_viem12.parseAbi)([
|
|
5270
5889
|
"function name() view returns (string)",
|
|
5271
5890
|
"function version() view returns (string)",
|
|
5272
5891
|
"function nonces(address owner) view returns (uint256)"
|
|
@@ -5304,7 +5923,7 @@ var PERMIT_BATCH_TYPES = {
|
|
|
5304
5923
|
{ name: "amount", type: "uint256" }
|
|
5305
5924
|
]
|
|
5306
5925
|
};
|
|
5307
|
-
var PERMIT2_BATCH_ABI = (0,
|
|
5926
|
+
var PERMIT2_BATCH_ABI = (0, import_viem12.parseAbi)([
|
|
5308
5927
|
"struct TokenPermissions { address token; uint256 amount; }",
|
|
5309
5928
|
"struct PermitBatchTransferFrom { TokenPermissions[] permitted; uint256 nonce; uint256 deadline; }",
|
|
5310
5929
|
"struct SignatureTransferDetails { address to; uint256 requestedAmount; }",
|
|
@@ -5363,7 +5982,7 @@ function clear(key2) {
|
|
|
5363
5982
|
else window.localStorage.removeItem(key2);
|
|
5364
5983
|
}
|
|
5365
5984
|
function sponsorTokenBatch(i) {
|
|
5366
|
-
const key2 = `owney.token-batch.v1:${(0,
|
|
5985
|
+
const key2 = `owney.token-batch.v1:${(0, import_viem13.keccak256)((0, import_viem13.toBytes)(i.apiKey))}:${i.baseUrl ?? "default"}:${i.chainId}:${i.owner.toLowerCase()}:${i.token.toLowerCase()}`;
|
|
5367
5986
|
const plan = planOf(i.transfers);
|
|
5368
5987
|
const active = inflight.get(key2);
|
|
5369
5988
|
if (active) {
|
|
@@ -5388,13 +6007,29 @@ async function execute(i, key2, plan) {
|
|
|
5388
6007
|
let body = initial;
|
|
5389
6008
|
save(key2, body);
|
|
5390
6009
|
try {
|
|
6010
|
+
if (body.erc2612Permit && !body.serializedPermitTransaction) {
|
|
6011
|
+
const preparedPermit = await postSponsorBatchTransfer({
|
|
6012
|
+
apiKey: i.apiKey,
|
|
6013
|
+
baseUrl: i.baseUrl,
|
|
6014
|
+
body
|
|
6015
|
+
});
|
|
6016
|
+
if (!preparedPermit.serializedPermitTransaction || !preparedPermit.permitTxHash || (0, import_viem13.keccak256)(preparedPermit.serializedPermitTransaction) !== preparedPermit.permitTxHash)
|
|
6017
|
+
throw new Error(
|
|
6018
|
+
"Sponsorship API did not return a valid prepared permit transaction."
|
|
6019
|
+
);
|
|
6020
|
+
body = {
|
|
6021
|
+
...body,
|
|
6022
|
+
serializedPermitTransaction: preparedPermit.serializedPermitTransaction
|
|
6023
|
+
};
|
|
6024
|
+
save(key2, body);
|
|
6025
|
+
}
|
|
5391
6026
|
if (!body.serializedTransaction) {
|
|
5392
6027
|
const prepared = await postSponsorBatchTransfer({
|
|
5393
6028
|
apiKey: i.apiKey,
|
|
5394
6029
|
baseUrl: i.baseUrl,
|
|
5395
6030
|
body
|
|
5396
6031
|
});
|
|
5397
|
-
if (!prepared.serializedTransaction || (0,
|
|
6032
|
+
if (!prepared.serializedTransaction || (0, import_viem13.keccak256)(prepared.serializedTransaction) !== prepared.txHash)
|
|
5398
6033
|
throw new Error(
|
|
5399
6034
|
"Sponsorship API did not return a valid prepared transaction."
|
|
5400
6035
|
);
|
|
@@ -5405,7 +6040,7 @@ async function execute(i, key2, plan) {
|
|
|
5405
6040
|
save(key2, body);
|
|
5406
6041
|
}
|
|
5407
6042
|
try {
|
|
5408
|
-
i.onSubmitted?.((0,
|
|
6043
|
+
i.onSubmitted?.((0, import_viem13.keccak256)(body.serializedTransaction));
|
|
5409
6044
|
} catch {
|
|
5410
6045
|
}
|
|
5411
6046
|
const result = await postSponsorBatchTransfer({
|
|
@@ -5413,7 +6048,7 @@ async function execute(i, key2, plan) {
|
|
|
5413
6048
|
baseUrl: i.baseUrl,
|
|
5414
6049
|
body
|
|
5415
6050
|
});
|
|
5416
|
-
if (result.txHash !== (0,
|
|
6051
|
+
if (result.txHash !== (0, import_viem13.keccak256)(body.serializedTransaction))
|
|
5417
6052
|
throw new Error(
|
|
5418
6053
|
"Sponsorship receipt does not match the pending transaction."
|
|
5419
6054
|
);
|
|
@@ -5428,7 +6063,7 @@ async function execute(i, key2, plan) {
|
|
|
5428
6063
|
const saved = read(key2);
|
|
5429
6064
|
if (saved) {
|
|
5430
6065
|
const previous = JSON.parse(saved);
|
|
5431
|
-
if (previous.chainId !== i.chainId || !(0,
|
|
6066
|
+
if (previous.chainId !== i.chainId || !(0, import_viem13.isAddressEqual)(previous.from, i.owner) || !(0, import_viem13.isAddressEqual)(previous.token, i.token) || planOf(previous.transfers) !== plan)
|
|
5432
6067
|
throw new Error(
|
|
5433
6068
|
"Retry the previous token deposit and agent split first to reconcile its status."
|
|
5434
6069
|
);
|
|
@@ -5445,7 +6080,7 @@ async function execute(i, key2, plan) {
|
|
|
5445
6080
|
"DEPOSIT_INSUFFICIENT_BALANCE",
|
|
5446
6081
|
"Insufficient token balance for this deposit."
|
|
5447
6082
|
);
|
|
5448
|
-
if (allowance < total && (i.chainId !== 8453 || !(0,
|
|
6083
|
+
if (allowance < total && (i.chainId !== 8453 || !(0, import_viem13.isAddressEqual)(i.token, BASE_USDC_ADDRESS)))
|
|
5449
6084
|
throw new OwneyError(
|
|
5450
6085
|
"PERMIT2_APPROVAL_REQUIRED",
|
|
5451
6086
|
"token deposits need a one-time Permit2 approval."
|
|
@@ -5489,7 +6124,7 @@ async function execute(i, key2, plan) {
|
|
|
5489
6124
|
});
|
|
5490
6125
|
erc2612Permit = { ...unsignedPermit, signature: signature2 };
|
|
5491
6126
|
}
|
|
5492
|
-
const spender =
|
|
6127
|
+
const spender = await getSponsorRelayerAddress({
|
|
5493
6128
|
apiKey: i.apiKey,
|
|
5494
6129
|
baseUrl: i.baseUrl,
|
|
5495
6130
|
chainId: i.chainId
|
|
@@ -5623,7 +6258,7 @@ async function runAgentDepositBatch(chainId, legs, transfer) {
|
|
|
5623
6258
|
}
|
|
5624
6259
|
|
|
5625
6260
|
// src/lib/sponsored-calls-deposit.ts
|
|
5626
|
-
var
|
|
6261
|
+
var import_viem14 = require("viem");
|
|
5627
6262
|
var DEFAULT_POLL_INTERVAL_MS = 1500;
|
|
5628
6263
|
var DEFAULT_MAX_POLLS = 30;
|
|
5629
6264
|
async function paymasterSupported(provider, owner, chainId) {
|
|
@@ -5631,7 +6266,7 @@ async function paymasterSupported(provider, owner, chainId) {
|
|
|
5631
6266
|
method: "wallet_getCapabilities",
|
|
5632
6267
|
params: [owner]
|
|
5633
6268
|
});
|
|
5634
|
-
const forChain = caps?.[(0,
|
|
6269
|
+
const forChain = caps?.[(0, import_viem14.toHex)(chainId)] ?? caps?.[String(chainId)];
|
|
5635
6270
|
return Boolean(forChain?.paymasterService?.supported);
|
|
5636
6271
|
}
|
|
5637
6272
|
function makeSponsoredCallsCallback(deps) {
|
|
@@ -5668,8 +6303,8 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
5668
6303
|
const calls = transfers.map((transfer) => ({
|
|
5669
6304
|
to: token,
|
|
5670
6305
|
value: "0x0",
|
|
5671
|
-
data: (0,
|
|
5672
|
-
abi:
|
|
6306
|
+
data: (0, import_viem14.encodeFunctionData)({
|
|
6307
|
+
abi: import_viem14.erc20Abi,
|
|
5673
6308
|
functionName: "transfer",
|
|
5674
6309
|
args: [transfer.to, BigInt(transfer.amount)]
|
|
5675
6310
|
})
|
|
@@ -5707,7 +6342,7 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
5707
6342
|
{
|
|
5708
6343
|
version: "2.0.0",
|
|
5709
6344
|
from: deps.ownerAddress,
|
|
5710
|
-
chainId: (0,
|
|
6345
|
+
chainId: (0, import_viem14.toHex)(chainId),
|
|
5711
6346
|
atomicRequired: transfers.length > 1,
|
|
5712
6347
|
calls,
|
|
5713
6348
|
capabilities: {
|
|
@@ -5801,9 +6436,9 @@ var SPONSORED_USDC_BY_CHAIN = {
|
|
|
5801
6436
|
1: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
|
|
5802
6437
|
};
|
|
5803
6438
|
var VIEM_CHAIN2 = {
|
|
5804
|
-
8453:
|
|
5805
|
-
42161:
|
|
5806
|
-
1:
|
|
6439
|
+
8453: import_chains5.base,
|
|
6440
|
+
42161: import_chains5.arbitrum,
|
|
6441
|
+
1: import_chains5.mainnet
|
|
5807
6442
|
};
|
|
5808
6443
|
var SPONSORED_WETH_BY_CHAIN = {
|
|
5809
6444
|
8453: "0x4200000000000000000000000000000000000006",
|
|
@@ -5976,14 +6611,14 @@ var OwneySDK = class {
|
|
|
5976
6611
|
// PublicClient/WalletClient param types — structurally identical at
|
|
5977
6612
|
// runtime, but the two share a name TS treats as unrelated.
|
|
5978
6613
|
getPublicClient: (cid) => this.getPaidRpcClient(cid),
|
|
5979
|
-
getWalletChainClient: (cid) => (0,
|
|
6614
|
+
getWalletChainClient: (cid) => (0, import_viem15.createPublicClient)({
|
|
5980
6615
|
chain: VIEM_CHAIN2[cid],
|
|
5981
|
-
transport: (0,
|
|
6616
|
+
transport: (0, import_viem15.custom)(provider)
|
|
5982
6617
|
}),
|
|
5983
|
-
getWalletClient: (cid) => (0,
|
|
6618
|
+
getWalletClient: (cid) => (0, import_viem15.createWalletClient)({
|
|
5984
6619
|
account: owner,
|
|
5985
6620
|
chain: VIEM_CHAIN2[cid],
|
|
5986
|
-
transport: (0,
|
|
6621
|
+
transport: (0, import_viem15.custom)(provider)
|
|
5987
6622
|
})
|
|
5988
6623
|
});
|
|
5989
6624
|
if (!onApproved && !onSubmitted) this.cachedSponsoredCallback = callback;
|
|
@@ -6029,14 +6664,14 @@ var OwneySDK = class {
|
|
|
6029
6664
|
// PublicClient/WalletClient param types — structurally identical at
|
|
6030
6665
|
// runtime, but the two share a name TS treats as unrelated.
|
|
6031
6666
|
getPublicClient: (cid) => this.getPaidRpcClient(cid),
|
|
6032
|
-
getWalletChainClient: (cid) => (0,
|
|
6667
|
+
getWalletChainClient: (cid) => (0, import_viem15.createPublicClient)({
|
|
6033
6668
|
chain: VIEM_CHAIN2[cid],
|
|
6034
|
-
transport: (0,
|
|
6669
|
+
transport: (0, import_viem15.custom)(provider)
|
|
6035
6670
|
}),
|
|
6036
|
-
getWalletClient: (cid) => (0,
|
|
6671
|
+
getWalletClient: (cid) => (0, import_viem15.createWalletClient)({
|
|
6037
6672
|
account: owner,
|
|
6038
6673
|
chain: VIEM_CHAIN2[cid],
|
|
6039
|
-
transport: (0,
|
|
6674
|
+
transport: (0, import_viem15.custom)(provider)
|
|
6040
6675
|
})
|
|
6041
6676
|
});
|
|
6042
6677
|
if (!onApproved && !onSubmitted) this.cachedWethSponsoredCallback = callback;
|
|
@@ -6157,6 +6792,7 @@ var OwneySDK = class {
|
|
|
6157
6792
|
}
|
|
6158
6793
|
if (agentId === "yieldseeker") {
|
|
6159
6794
|
return new YieldseekerAgent(this.apiKey, {
|
|
6795
|
+
routingApiBaseUrl: this.routingApiBaseUrl,
|
|
6160
6796
|
auth: { origin: this.yieldseekerSiweOrigin },
|
|
6161
6797
|
baseUrl: this.yieldseekerApiBaseUrl ?? getYieldseekerProxyBaseUrl(this.routingApiBaseUrl),
|
|
6162
6798
|
rpcUrls: this.rpcUrls
|
|
@@ -6748,12 +7384,12 @@ var OwneySDK = class {
|
|
|
6748
7384
|
throw new OwneyError("AGENT_API_ERROR", "Funding wallet does not match this account.");
|
|
6749
7385
|
const token = SupportedAssets.find((t) => t.chainId === chainId && t.symbol === evidence.token);
|
|
6750
7386
|
if (!token) throw new OwneyError("CHAIN_UNSUPPORTED", "Unsupported funding asset.");
|
|
6751
|
-
const
|
|
6752
|
-
const receipt = await
|
|
7387
|
+
const rpc2 = this.getPaidRpcClient(chainId);
|
|
7388
|
+
const receipt = await rpc2.getTransactionReceipt({ hash: evidence.txHash });
|
|
6753
7389
|
assertCurrent();
|
|
6754
7390
|
let verified = inspectFundingReceipt(receipt, { ...evidence, agentWallet }, token.address, direction);
|
|
6755
7391
|
if (direction === "withdraw" && evidence.agentId === "yieldseeker" && verified.transfer === "unknown" && verified.confirmedAmount && BigInt(verified.confirmedAmount) > 0n) {
|
|
6756
|
-
const transaction = await
|
|
7392
|
+
const transaction = await rpc2.getTransaction({ hash: evidence.txHash });
|
|
6757
7393
|
assertCurrent();
|
|
6758
7394
|
if (isFullYieldseekerWithdrawal(transaction, { ...evidence, agentWallet }, token.address))
|
|
6759
7395
|
verified = inspectFundingReceipt(receipt, { ...evidence, agentWallet, intendedAmount: "MAX" }, token.address, direction);
|
|
@@ -6767,6 +7403,45 @@ var OwneySDK = class {
|
|
|
6767
7403
|
}
|
|
6768
7404
|
return verified;
|
|
6769
7405
|
}
|
|
7406
|
+
/** Resolve a saved sponsored-withdrawal ID without opening a wallet prompt. */
|
|
7407
|
+
async resolveSponsoredWithdrawalEvidence(evidence) {
|
|
7408
|
+
const { state, chainId, assertCurrent } = this.captureReadScope(evidence.chainId);
|
|
7409
|
+
if (evidence.agentId !== "yieldseeker" || chainId !== 8453 || evidence.txHash || state.walletAddress.toLowerCase() !== evidence.walletAddress.toLowerCase()) return evidence;
|
|
7410
|
+
const agent = this.getAgent("yieldseeker");
|
|
7411
|
+
const wallet = await agent.getFundingWallet?.(state, chainId, evidence.token);
|
|
7412
|
+
if (!wallet || wallet.toLowerCase() !== evidence.agentWallet?.toLowerCase()) return evidence;
|
|
7413
|
+
let txHash;
|
|
7414
|
+
let executionFailed = false;
|
|
7415
|
+
if (evidence.userOpHash && /^0x[0-9a-fA-F]{64}$/.test(evidence.userOpHash)) {
|
|
7416
|
+
const response = await fetch(`${getRoutingApiBaseUrl(this.routingApiBaseUrl).replace(/\/$/, "")}/api/v1/sponsor/yieldseeker-withdraw/resolve`, {
|
|
7417
|
+
method: "POST",
|
|
7418
|
+
headers: { "content-type": "application/json", "x-owney-api-key": this.apiKey },
|
|
7419
|
+
body: JSON.stringify({
|
|
7420
|
+
owner: state.walletAddress,
|
|
7421
|
+
agentWallet: wallet,
|
|
7422
|
+
asset: SupportedAssets.find((t) => t.chainId === chainId && t.symbol === evidence.token)?.address,
|
|
7423
|
+
userOpHash: evidence.userOpHash
|
|
7424
|
+
})
|
|
7425
|
+
});
|
|
7426
|
+
if (!response.ok) throw new OwneyError("AGENT_API_ERROR", "Could not resolve sponsored withdrawal status.");
|
|
7427
|
+
const payload = await response.json();
|
|
7428
|
+
txHash = payload.data?.txHash ?? void 0;
|
|
7429
|
+
executionFailed = payload.data?.executionFailed === true;
|
|
7430
|
+
} else if (evidence.callsId) {
|
|
7431
|
+
const status = await state.provider.request({ method: "wallet_getCallsStatus", params: [evidence.callsId] });
|
|
7432
|
+
if (status?.id && status.id !== evidence.callsId || status?.chainId && Number(status.chainId) !== chainId) return evidence;
|
|
7433
|
+
executionFailed = status?.status === 400 || status?.status === 500;
|
|
7434
|
+
txHash = status?.receipts?.[0]?.transactionHash;
|
|
7435
|
+
}
|
|
7436
|
+
assertCurrent();
|
|
7437
|
+
if (executionFailed) return {
|
|
7438
|
+
...evidence,
|
|
7439
|
+
...txHash && /^0x[0-9a-fA-F]{64}$/.test(txHash) ? { txHash } : {},
|
|
7440
|
+
transfer: "failed",
|
|
7441
|
+
delivery: "failed"
|
|
7442
|
+
};
|
|
7443
|
+
return txHash && /^0x[0-9a-fA-F]{64}$/.test(txHash) ? { ...evidence, txHash } : evidence;
|
|
7444
|
+
}
|
|
6770
7445
|
/** A display acknowledgement controls polling only; it never confirms a financial outcome. */
|
|
6771
7446
|
endFundingBalanceRefresh(evidence, read2) {
|
|
6772
7447
|
const { state, chainId } = this.captureReadScope(evidence.chainId);
|
|
@@ -6791,6 +7466,39 @@ var OwneySDK = class {
|
|
|
6791
7466
|
return this.getAgent("zyfai").retryDepositRegistration(this.requireState(), verified);
|
|
6792
7467
|
}
|
|
6793
7468
|
// --- Fund operations ---
|
|
7469
|
+
/** On-chain version and ownership status for this owner's Yieldseeker agent. */
|
|
7470
|
+
async getYieldseekerWalletStatus(asset) {
|
|
7471
|
+
const state = this.requireState();
|
|
7472
|
+
const chainId = this.requireChainId();
|
|
7473
|
+
const agent = this.getAgent("yieldseeker");
|
|
7474
|
+
return agent.getWalletStatus(state, chainId, asset);
|
|
7475
|
+
}
|
|
7476
|
+
/** Deployment gate; an unavailable response keeps the current paid path. */
|
|
7477
|
+
async isYieldseekerWithdrawalSponsorshipAvailable() {
|
|
7478
|
+
return this.isYieldseekerSponsorshipAvailable("withdraw");
|
|
7479
|
+
}
|
|
7480
|
+
async isYieldseekerUpgradeSponsorshipAvailable() {
|
|
7481
|
+
return this.isYieldseekerSponsorshipAvailable("upgrade");
|
|
7482
|
+
}
|
|
7483
|
+
async isYieldseekerSponsorshipAvailable(action) {
|
|
7484
|
+
const baseUrl = getRoutingApiBaseUrl(this.routingApiBaseUrl).replace(/\/$/, "");
|
|
7485
|
+
try {
|
|
7486
|
+
const owner = this.requireState().walletAddress;
|
|
7487
|
+
const response = await fetch(`${baseUrl}/api/v1/sponsor/yieldseeker-withdraw/availability?owner=${encodeURIComponent(owner)}&action=${action}`);
|
|
7488
|
+
if (!response.ok) return false;
|
|
7489
|
+
const payload = await response.json();
|
|
7490
|
+
return payload.data?.enabled === true;
|
|
7491
|
+
} catch {
|
|
7492
|
+
return false;
|
|
7493
|
+
}
|
|
7494
|
+
}
|
|
7495
|
+
/** Explicit V1-to-V2 upgrade, confirmed on chain before returning. */
|
|
7496
|
+
async upgradeYieldseekerWallet(asset, gasMode = "paid") {
|
|
7497
|
+
const state = this.requireState();
|
|
7498
|
+
const chainId = this.requireChainId();
|
|
7499
|
+
const agent = this.getAgent("yieldseeker");
|
|
7500
|
+
return agent.upgradeWallet(state, chainId, asset, gasMode);
|
|
7501
|
+
}
|
|
6794
7502
|
/**
|
|
6795
7503
|
* Withdraw funds from a specific agent, or all agents that support the active chain+asset if agentId is omitted.
|
|
6796
7504
|
* Validates that the asset is supported by the target agent(s) on the active chain.
|
|
@@ -6854,7 +7562,7 @@ var OwneySDK = class {
|
|
|
6854
7562
|
};
|
|
6855
7563
|
progress(evidence);
|
|
6856
7564
|
try {
|
|
6857
|
-
return await agent.withdraw(state, chainId, token, requested2, progress);
|
|
7565
|
+
return await (options.gasMode === void 0 ? agent.withdraw(state, chainId, token, requested2, progress) : agent.withdraw(state, chainId, token, requested2, progress, options.gasMode));
|
|
6858
7566
|
} catch (error) {
|
|
6859
7567
|
if (!evidence.txHash && (this.isUserRejectedWithdrawal(error) || /insufficient (balance|funds)/i.test(error instanceof Error ? error.message : "")))
|
|
6860
7568
|
progress({ ...evidence, transfer: "failed", delivery: "failed" });
|
|
@@ -6892,6 +7600,7 @@ var OwneySDK = class {
|
|
|
6892
7600
|
results2[agent.id] = await submit(agent);
|
|
6893
7601
|
notifyAgentResult(agent.id, results2[agent.id]);
|
|
6894
7602
|
} catch (err) {
|
|
7603
|
+
if (err instanceof OwneyError && err.code === "SPONSOR_REQUEST_FAILED" && err.details?.safeToFallback === true) throw err;
|
|
6895
7604
|
if (this.isUserRejectedWithdrawal(err)) throw err;
|
|
6896
7605
|
if (err instanceof OwneyError && err.code === "WITHDRAW_INSUFFICIENT_BALANCE" && err.details?.available === "0" && submissionEvidence.get(agent.id)?.transfer === "failed") continue;
|
|
6897
7606
|
console.error(`withdraw failed for agent "${agent.id}":`, err);
|
|
@@ -6993,6 +7702,7 @@ var OwneySDK = class {
|
|
|
6993
7702
|
results[p.agent.id] = await submit(p.agent, p.planned.toString());
|
|
6994
7703
|
notifyAgentResult(p.agent.id, results[p.agent.id]);
|
|
6995
7704
|
} catch (err) {
|
|
7705
|
+
if (err instanceof OwneyError && err.code === "SPONSOR_REQUEST_FAILED" && err.details?.safeToFallback === true) throw err;
|
|
6996
7706
|
if (this.isUserRejectedWithdrawal(err)) throw err;
|
|
6997
7707
|
console.error(`withdraw failed for agent "${p.agent.id}":`, err);
|
|
6998
7708
|
agentErrors[p.agent.id] = err instanceof Error ? err.message : String(err);
|
|
@@ -7490,16 +8200,16 @@ var OwneySDK = class {
|
|
|
7490
8200
|
);
|
|
7491
8201
|
}
|
|
7492
8202
|
const provider = this.requireConnectedProvider();
|
|
7493
|
-
const walletChainClient = (0,
|
|
8203
|
+
const walletChainClient = (0, import_viem15.createPublicClient)({
|
|
7494
8204
|
chain: VIEM_CHAIN2[chainId],
|
|
7495
|
-
transport: (0,
|
|
8205
|
+
transport: (0, import_viem15.custom)(provider)
|
|
7496
8206
|
});
|
|
7497
8207
|
const publicClient = this.getPaidRpcClient(chainId);
|
|
7498
8208
|
const approvalAmount = permit2ApprovalAmount(requiredAmount);
|
|
7499
|
-
const wallet = (0,
|
|
8209
|
+
const wallet = (0, import_viem15.createWalletClient)({
|
|
7500
8210
|
account: state.walletAddress,
|
|
7501
8211
|
chain: VIEM_CHAIN2[chainId],
|
|
7502
|
-
transport: (0,
|
|
8212
|
+
transport: (0, import_viem15.custom)(provider)
|
|
7503
8213
|
});
|
|
7504
8214
|
await ensureWalletOnChain(walletChainClient, wallet, chainId);
|
|
7505
8215
|
const hash = await wallet.writeContract({
|
|
@@ -7661,7 +8371,7 @@ var OwneySDK = class {
|
|
|
7661
8371
|
};
|
|
7662
8372
|
|
|
7663
8373
|
// src/agents/zyfai/zyfai.siwx.ts
|
|
7664
|
-
var
|
|
8374
|
+
var import_viem16 = require("viem");
|
|
7665
8375
|
var import_siwe2 = require("siwe");
|
|
7666
8376
|
var import_sdk2 = require("@zyfai/sdk");
|
|
7667
8377
|
|
|
@@ -7788,7 +8498,7 @@ function buildSIWXConfig(deps) {
|
|
|
7788
8498
|
issuedAt,
|
|
7789
8499
|
toString() {
|
|
7790
8500
|
return new import_siwe2.SiweMessage({
|
|
7791
|
-
address: (0,
|
|
8501
|
+
address: (0, import_viem16.getAddress)(accountAddress),
|
|
7792
8502
|
chainId: numericChainId(chainId),
|
|
7793
8503
|
domain,
|
|
7794
8504
|
uri,
|