@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.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
|
|
2607
|
-
custom as
|
|
2606
|
+
createWalletClient as createWalletClient3,
|
|
2607
|
+
custom as custom3,
|
|
2608
2608
|
encodeFunctionData,
|
|
2609
2609
|
erc20Abi as erc20Abi2,
|
|
2610
|
-
getAddress as
|
|
2610
|
+
getAddress as getAddress4,
|
|
2611
2611
|
isAddress as isAddress2
|
|
2612
2612
|
} from "viem";
|
|
2613
|
-
import { base as
|
|
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
|
|
2656
|
+
const base6 = input.baseUrl ?? ROUTING_API_BASE_URL;
|
|
2657
2657
|
let res;
|
|
2658
2658
|
try {
|
|
2659
|
-
res = await fetch(`${
|
|
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
|
|
2695
|
+
const base6 = input.baseUrl ?? ROUTING_API_BASE_URL;
|
|
2696
2696
|
let res;
|
|
2697
2697
|
try {
|
|
2698
2698
|
res = await fetch(
|
|
2699
|
-
`${
|
|
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(
|
|
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:
|
|
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: [
|
|
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
|
|
3921
|
-
const evidence = receipt ? inspectFundingReceipt(receipt,
|
|
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 (
|
|
3946
|
-
|
|
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: [
|
|
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
|
-
|
|
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 =
|
|
4670
|
+
const account = getAddress4(state.walletAddress);
|
|
4063
4671
|
let receipt;
|
|
4064
|
-
const
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
|
|
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, { ...
|
|
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 =
|
|
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 =
|
|
4820
|
-
const walletClient =
|
|
5447
|
+
const account = getAddress4(state.walletAddress);
|
|
5448
|
+
const walletClient = createWalletClient3({
|
|
4821
5449
|
account,
|
|
4822
|
-
chain:
|
|
4823
|
-
transport:
|
|
5450
|
+
chain: base4,
|
|
5451
|
+
transport: custom3(state.provider)
|
|
4824
5452
|
});
|
|
4825
5453
|
const walletChainClient = createPublicClient3({
|
|
4826
|
-
chain:
|
|
4827
|
-
transport:
|
|
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:
|
|
4837
|
-
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 ||
|
|
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,23 +5859,22 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
|
|
|
5230
5859
|
// src/client.ts
|
|
5231
5860
|
import {
|
|
5232
5861
|
createPublicClient as createPublicClient4,
|
|
5233
|
-
createWalletClient as
|
|
5234
|
-
custom as
|
|
5862
|
+
createWalletClient as createWalletClient4,
|
|
5863
|
+
custom as custom4
|
|
5235
5864
|
} from "viem";
|
|
5236
|
-
import { base as
|
|
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
|
|
5875
|
+
import { parseAbi as parseAbi4, hashStruct } from "viem";
|
|
5247
5876
|
var BATCH_PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
5248
5877
|
var BASE_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
|
|
5249
|
-
var MULTICALL3_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976CA11";
|
|
5250
5878
|
var ERC2612_PERMIT_TYPES = {
|
|
5251
5879
|
Permit: [
|
|
5252
5880
|
{ name: "owner", type: "address" },
|
|
@@ -5256,7 +5884,7 @@ var ERC2612_PERMIT_TYPES = {
|
|
|
5256
5884
|
{ name: "deadline", type: "uint256" }
|
|
5257
5885
|
]
|
|
5258
5886
|
};
|
|
5259
|
-
var ERC2612_READ_ABI =
|
|
5887
|
+
var ERC2612_READ_ABI = parseAbi4([
|
|
5260
5888
|
"function name() view returns (string)",
|
|
5261
5889
|
"function version() view returns (string)",
|
|
5262
5890
|
"function nonces(address owner) view returns (uint256)"
|
|
@@ -5294,7 +5922,7 @@ var PERMIT_BATCH_TYPES = {
|
|
|
5294
5922
|
{ name: "amount", type: "uint256" }
|
|
5295
5923
|
]
|
|
5296
5924
|
};
|
|
5297
|
-
var PERMIT2_BATCH_ABI =
|
|
5925
|
+
var PERMIT2_BATCH_ABI = parseAbi4([
|
|
5298
5926
|
"struct TokenPermissions { address token; uint256 amount; }",
|
|
5299
5927
|
"struct PermitBatchTransferFrom { TokenPermissions[] permitted; uint256 nonce; uint256 deadline; }",
|
|
5300
5928
|
"struct SignatureTransferDetails { address to; uint256 requestedAmount; }",
|
|
@@ -5378,6 +6006,22 @@ async function execute(i, key2, plan) {
|
|
|
5378
6006
|
let body = initial;
|
|
5379
6007
|
save(key2, body);
|
|
5380
6008
|
try {
|
|
6009
|
+
if (body.erc2612Permit && !body.serializedPermitTransaction) {
|
|
6010
|
+
const preparedPermit = await postSponsorBatchTransfer({
|
|
6011
|
+
apiKey: i.apiKey,
|
|
6012
|
+
baseUrl: i.baseUrl,
|
|
6013
|
+
body
|
|
6014
|
+
});
|
|
6015
|
+
if (!preparedPermit.serializedPermitTransaction || !preparedPermit.permitTxHash || keccak256(preparedPermit.serializedPermitTransaction) !== preparedPermit.permitTxHash)
|
|
6016
|
+
throw new Error(
|
|
6017
|
+
"Sponsorship API did not return a valid prepared permit transaction."
|
|
6018
|
+
);
|
|
6019
|
+
body = {
|
|
6020
|
+
...body,
|
|
6021
|
+
serializedPermitTransaction: preparedPermit.serializedPermitTransaction
|
|
6022
|
+
};
|
|
6023
|
+
save(key2, body);
|
|
6024
|
+
}
|
|
5381
6025
|
if (!body.serializedTransaction) {
|
|
5382
6026
|
const prepared = await postSponsorBatchTransfer({
|
|
5383
6027
|
apiKey: i.apiKey,
|
|
@@ -5418,7 +6062,7 @@ async function execute(i, key2, plan) {
|
|
|
5418
6062
|
const saved = read(key2);
|
|
5419
6063
|
if (saved) {
|
|
5420
6064
|
const previous = JSON.parse(saved);
|
|
5421
|
-
if (previous.chainId !== i.chainId || !
|
|
6065
|
+
if (previous.chainId !== i.chainId || !isAddressEqual2(previous.from, i.owner) || !isAddressEqual2(previous.token, i.token) || planOf(previous.transfers) !== plan)
|
|
5422
6066
|
throw new Error(
|
|
5423
6067
|
"Retry the previous token deposit and agent split first to reconcile its status."
|
|
5424
6068
|
);
|
|
@@ -5435,7 +6079,7 @@ async function execute(i, key2, plan) {
|
|
|
5435
6079
|
"DEPOSIT_INSUFFICIENT_BALANCE",
|
|
5436
6080
|
"Insufficient token balance for this deposit."
|
|
5437
6081
|
);
|
|
5438
|
-
if (allowance < total && (i.chainId !== 8453 || !
|
|
6082
|
+
if (allowance < total && (i.chainId !== 8453 || !isAddressEqual2(i.token, BASE_USDC_ADDRESS)))
|
|
5439
6083
|
throw new OwneyError(
|
|
5440
6084
|
"PERMIT2_APPROVAL_REQUIRED",
|
|
5441
6085
|
"token deposits need a one-time Permit2 approval."
|
|
@@ -5479,7 +6123,7 @@ async function execute(i, key2, plan) {
|
|
|
5479
6123
|
});
|
|
5480
6124
|
erc2612Permit = { ...unsignedPermit, signature: signature2 };
|
|
5481
6125
|
}
|
|
5482
|
-
const spender =
|
|
6126
|
+
const spender = await getSponsorRelayerAddress({
|
|
5483
6127
|
apiKey: i.apiKey,
|
|
5484
6128
|
baseUrl: i.baseUrl,
|
|
5485
6129
|
chainId: i.chainId
|
|
@@ -5613,7 +6257,7 @@ async function runAgentDepositBatch(chainId, legs, transfer) {
|
|
|
5613
6257
|
}
|
|
5614
6258
|
|
|
5615
6259
|
// src/lib/sponsored-calls-deposit.ts
|
|
5616
|
-
import { encodeFunctionData as encodeFunctionData2, erc20Abi as erc20Abi3, toHex } from "viem";
|
|
6260
|
+
import { encodeFunctionData as encodeFunctionData2, erc20Abi as erc20Abi3, toHex as toHex2 } from "viem";
|
|
5617
6261
|
var DEFAULT_POLL_INTERVAL_MS = 1500;
|
|
5618
6262
|
var DEFAULT_MAX_POLLS = 30;
|
|
5619
6263
|
async function paymasterSupported(provider, owner, chainId) {
|
|
@@ -5621,7 +6265,7 @@ async function paymasterSupported(provider, owner, chainId) {
|
|
|
5621
6265
|
method: "wallet_getCapabilities",
|
|
5622
6266
|
params: [owner]
|
|
5623
6267
|
});
|
|
5624
|
-
const forChain = caps?.[
|
|
6268
|
+
const forChain = caps?.[toHex2(chainId)] ?? caps?.[String(chainId)];
|
|
5625
6269
|
return Boolean(forChain?.paymasterService?.supported);
|
|
5626
6270
|
}
|
|
5627
6271
|
function makeSponsoredCallsCallback(deps) {
|
|
@@ -5697,7 +6341,7 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
5697
6341
|
{
|
|
5698
6342
|
version: "2.0.0",
|
|
5699
6343
|
from: deps.ownerAddress,
|
|
5700
|
-
chainId:
|
|
6344
|
+
chainId: toHex2(chainId),
|
|
5701
6345
|
atomicRequired: transfers.length > 1,
|
|
5702
6346
|
calls,
|
|
5703
6347
|
capabilities: {
|
|
@@ -5791,7 +6435,7 @@ var SPONSORED_USDC_BY_CHAIN = {
|
|
|
5791
6435
|
1: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
|
|
5792
6436
|
};
|
|
5793
6437
|
var VIEM_CHAIN2 = {
|
|
5794
|
-
8453:
|
|
6438
|
+
8453: base5,
|
|
5795
6439
|
42161: arbitrum2,
|
|
5796
6440
|
1: mainnet2
|
|
5797
6441
|
};
|
|
@@ -5968,12 +6612,12 @@ var OwneySDK = class {
|
|
|
5968
6612
|
getPublicClient: (cid) => this.getPaidRpcClient(cid),
|
|
5969
6613
|
getWalletChainClient: (cid) => createPublicClient4({
|
|
5970
6614
|
chain: VIEM_CHAIN2[cid],
|
|
5971
|
-
transport:
|
|
6615
|
+
transport: custom4(provider)
|
|
5972
6616
|
}),
|
|
5973
|
-
getWalletClient: (cid) =>
|
|
6617
|
+
getWalletClient: (cid) => createWalletClient4({
|
|
5974
6618
|
account: owner,
|
|
5975
6619
|
chain: VIEM_CHAIN2[cid],
|
|
5976
|
-
transport:
|
|
6620
|
+
transport: custom4(provider)
|
|
5977
6621
|
})
|
|
5978
6622
|
});
|
|
5979
6623
|
if (!onApproved && !onSubmitted) this.cachedSponsoredCallback = callback;
|
|
@@ -6021,12 +6665,12 @@ var OwneySDK = class {
|
|
|
6021
6665
|
getPublicClient: (cid) => this.getPaidRpcClient(cid),
|
|
6022
6666
|
getWalletChainClient: (cid) => createPublicClient4({
|
|
6023
6667
|
chain: VIEM_CHAIN2[cid],
|
|
6024
|
-
transport:
|
|
6668
|
+
transport: custom4(provider)
|
|
6025
6669
|
}),
|
|
6026
|
-
getWalletClient: (cid) =>
|
|
6670
|
+
getWalletClient: (cid) => createWalletClient4({
|
|
6027
6671
|
account: owner,
|
|
6028
6672
|
chain: VIEM_CHAIN2[cid],
|
|
6029
|
-
transport:
|
|
6673
|
+
transport: custom4(provider)
|
|
6030
6674
|
})
|
|
6031
6675
|
});
|
|
6032
6676
|
if (!onApproved && !onSubmitted) this.cachedWethSponsoredCallback = callback;
|
|
@@ -6147,6 +6791,7 @@ var OwneySDK = class {
|
|
|
6147
6791
|
}
|
|
6148
6792
|
if (agentId === "yieldseeker") {
|
|
6149
6793
|
return new YieldseekerAgent(this.apiKey, {
|
|
6794
|
+
routingApiBaseUrl: this.routingApiBaseUrl,
|
|
6150
6795
|
auth: { origin: this.yieldseekerSiweOrigin },
|
|
6151
6796
|
baseUrl: this.yieldseekerApiBaseUrl ?? getYieldseekerProxyBaseUrl(this.routingApiBaseUrl),
|
|
6152
6797
|
rpcUrls: this.rpcUrls
|
|
@@ -6738,12 +7383,12 @@ var OwneySDK = class {
|
|
|
6738
7383
|
throw new OwneyError("AGENT_API_ERROR", "Funding wallet does not match this account.");
|
|
6739
7384
|
const token = SupportedAssets.find((t) => t.chainId === chainId && t.symbol === evidence.token);
|
|
6740
7385
|
if (!token) throw new OwneyError("CHAIN_UNSUPPORTED", "Unsupported funding asset.");
|
|
6741
|
-
const
|
|
6742
|
-
const receipt = await
|
|
7386
|
+
const rpc2 = this.getPaidRpcClient(chainId);
|
|
7387
|
+
const receipt = await rpc2.getTransactionReceipt({ hash: evidence.txHash });
|
|
6743
7388
|
assertCurrent();
|
|
6744
7389
|
let verified = inspectFundingReceipt(receipt, { ...evidence, agentWallet }, token.address, direction);
|
|
6745
7390
|
if (direction === "withdraw" && evidence.agentId === "yieldseeker" && verified.transfer === "unknown" && verified.confirmedAmount && BigInt(verified.confirmedAmount) > 0n) {
|
|
6746
|
-
const transaction = await
|
|
7391
|
+
const transaction = await rpc2.getTransaction({ hash: evidence.txHash });
|
|
6747
7392
|
assertCurrent();
|
|
6748
7393
|
if (isFullYieldseekerWithdrawal(transaction, { ...evidence, agentWallet }, token.address))
|
|
6749
7394
|
verified = inspectFundingReceipt(receipt, { ...evidence, agentWallet, intendedAmount: "MAX" }, token.address, direction);
|
|
@@ -6757,6 +7402,45 @@ var OwneySDK = class {
|
|
|
6757
7402
|
}
|
|
6758
7403
|
return verified;
|
|
6759
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
|
+
}
|
|
6760
7444
|
/** A display acknowledgement controls polling only; it never confirms a financial outcome. */
|
|
6761
7445
|
endFundingBalanceRefresh(evidence, read2) {
|
|
6762
7446
|
const { state, chainId } = this.captureReadScope(evidence.chainId);
|
|
@@ -6781,6 +7465,39 @@ var OwneySDK = class {
|
|
|
6781
7465
|
return this.getAgent("zyfai").retryDepositRegistration(this.requireState(), verified);
|
|
6782
7466
|
}
|
|
6783
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
|
+
}
|
|
6784
7501
|
/**
|
|
6785
7502
|
* Withdraw funds from a specific agent, or all agents that support the active chain+asset if agentId is omitted.
|
|
6786
7503
|
* Validates that the asset is supported by the target agent(s) on the active chain.
|
|
@@ -6844,7 +7561,7 @@ var OwneySDK = class {
|
|
|
6844
7561
|
};
|
|
6845
7562
|
progress(evidence);
|
|
6846
7563
|
try {
|
|
6847
|
-
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));
|
|
6848
7565
|
} catch (error) {
|
|
6849
7566
|
if (!evidence.txHash && (this.isUserRejectedWithdrawal(error) || /insufficient (balance|funds)/i.test(error instanceof Error ? error.message : "")))
|
|
6850
7567
|
progress({ ...evidence, transfer: "failed", delivery: "failed" });
|
|
@@ -6882,6 +7599,7 @@ var OwneySDK = class {
|
|
|
6882
7599
|
results2[agent.id] = await submit(agent);
|
|
6883
7600
|
notifyAgentResult(agent.id, results2[agent.id]);
|
|
6884
7601
|
} catch (err) {
|
|
7602
|
+
if (err instanceof OwneyError && err.code === "SPONSOR_REQUEST_FAILED" && err.details?.safeToFallback === true) throw err;
|
|
6885
7603
|
if (this.isUserRejectedWithdrawal(err)) throw err;
|
|
6886
7604
|
if (err instanceof OwneyError && err.code === "WITHDRAW_INSUFFICIENT_BALANCE" && err.details?.available === "0" && submissionEvidence.get(agent.id)?.transfer === "failed") continue;
|
|
6887
7605
|
console.error(`withdraw failed for agent "${agent.id}":`, err);
|
|
@@ -6983,6 +7701,7 @@ var OwneySDK = class {
|
|
|
6983
7701
|
results[p.agent.id] = await submit(p.agent, p.planned.toString());
|
|
6984
7702
|
notifyAgentResult(p.agent.id, results[p.agent.id]);
|
|
6985
7703
|
} catch (err) {
|
|
7704
|
+
if (err instanceof OwneyError && err.code === "SPONSOR_REQUEST_FAILED" && err.details?.safeToFallback === true) throw err;
|
|
6986
7705
|
if (this.isUserRejectedWithdrawal(err)) throw err;
|
|
6987
7706
|
console.error(`withdraw failed for agent "${p.agent.id}":`, err);
|
|
6988
7707
|
agentErrors[p.agent.id] = err instanceof Error ? err.message : String(err);
|
|
@@ -7482,14 +8201,14 @@ var OwneySDK = class {
|
|
|
7482
8201
|
const provider = this.requireConnectedProvider();
|
|
7483
8202
|
const walletChainClient = createPublicClient4({
|
|
7484
8203
|
chain: VIEM_CHAIN2[chainId],
|
|
7485
|
-
transport:
|
|
8204
|
+
transport: custom4(provider)
|
|
7486
8205
|
});
|
|
7487
8206
|
const publicClient = this.getPaidRpcClient(chainId);
|
|
7488
8207
|
const approvalAmount = permit2ApprovalAmount(requiredAmount);
|
|
7489
|
-
const wallet =
|
|
8208
|
+
const wallet = createWalletClient4({
|
|
7490
8209
|
account: state.walletAddress,
|
|
7491
8210
|
chain: VIEM_CHAIN2[chainId],
|
|
7492
|
-
transport:
|
|
8211
|
+
transport: custom4(provider)
|
|
7493
8212
|
});
|
|
7494
8213
|
await ensureWalletOnChain(walletChainClient, wallet, chainId);
|
|
7495
8214
|
const hash = await wallet.writeContract({
|
|
@@ -7651,7 +8370,7 @@ var OwneySDK = class {
|
|
|
7651
8370
|
};
|
|
7652
8371
|
|
|
7653
8372
|
// src/agents/zyfai/zyfai.siwx.ts
|
|
7654
|
-
import { getAddress as
|
|
8373
|
+
import { getAddress as getAddress5 } from "viem";
|
|
7655
8374
|
import { SiweMessage as SiweMessage2 } from "siwe";
|
|
7656
8375
|
import { ZyfaiSDK as ZyfaiSDK2 } from "@zyfai/sdk";
|
|
7657
8376
|
|
|
@@ -7778,7 +8497,7 @@ function buildSIWXConfig(deps) {
|
|
|
7778
8497
|
issuedAt,
|
|
7779
8498
|
toString() {
|
|
7780
8499
|
return new SiweMessage2({
|
|
7781
|
-
address:
|
|
8500
|
+
address: getAddress5(accountAddress),
|
|
7782
8501
|
chainId: numericChainId(chainId),
|
|
7783
8502
|
domain,
|
|
7784
8503
|
uri,
|