@owney/sdk 0.7.25-beta.12 → 0.7.25-beta.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1029 -136
- package/dist/index.d.cts +47 -4
- package/dist/index.d.ts +47 -4
- package/dist/index.js +1017 -115
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -34,6 +34,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
34
34
|
|
|
35
35
|
// src/lib/funding-evidence.ts
|
|
36
36
|
var import_viem = require("viem");
|
|
37
|
+
var import_account_abstraction = require("viem/account-abstraction");
|
|
37
38
|
function notifyFunding(callback, evidence) {
|
|
38
39
|
try {
|
|
39
40
|
void Promise.resolve(callback?.({ ...evidence })).catch(() => {
|
|
@@ -43,11 +44,53 @@ function notifyFunding(callback, evidence) {
|
|
|
43
44
|
}
|
|
44
45
|
var fullWithdrawalAbi = (0, import_viem.parseAbi)(["function withdrawAllAssetToUser(address recipient, address asset)"]);
|
|
45
46
|
var withdrawalEventAbi = (0, import_viem.parseAbi)(["event WithdrewTokenToUser(address indexed owner, address indexed recipient, address indexed token, uint256 amount)"]);
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
var accountExecutionAbi = (0, import_viem.parseAbi)([
|
|
48
|
+
"function execute(address target,uint256 value,bytes data)",
|
|
49
|
+
"function executeBatch((address target,uint256 value,bytes data)[] calls)"
|
|
50
|
+
]);
|
|
51
|
+
var entryPoint06 = "0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789";
|
|
52
|
+
var entryPoint07 = "0x0000000071727de22e5e9d8baf0edac6f37da032";
|
|
53
|
+
function isFullYieldseekerWithdrawal(transaction, evidence, tokenAddress, receipt) {
|
|
54
|
+
if (evidence.agentId !== "yieldseeker" || transaction.chainId !== evidence.chainId || transaction.hash.toLowerCase() !== evidence.txHash?.toLowerCase() || !evidence.agentWallet) return false;
|
|
55
|
+
const matchesFullCall = (data) => {
|
|
56
|
+
try {
|
|
57
|
+
const decoded = (0, import_viem.decodeFunctionData)({ abi: fullWithdrawalAbi, data });
|
|
58
|
+
return decoded.args[0].toLowerCase() === evidence.walletAddress.toLowerCase() && decoded.args[1].toLowerCase() === tokenAddress.toLowerCase();
|
|
59
|
+
} catch {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
if (transaction.to?.toLowerCase() === evidence.agentWallet.toLowerCase() && transaction.from.toLowerCase() === evidence.walletAddress.toLowerCase()) return matchesFullCall(transaction.input);
|
|
48
64
|
try {
|
|
49
|
-
const
|
|
50
|
-
|
|
65
|
+
const address = transaction.to?.toLowerCase();
|
|
66
|
+
if (address !== entryPoint06 && address !== entryPoint07) return false;
|
|
67
|
+
const version = address === entryPoint06 ? "0.6" : "0.7";
|
|
68
|
+
const decoded = (0, import_viem.decodeFunctionData)({ abi: version === "0.6" ? import_account_abstraction.entryPoint06Abi : import_account_abstraction.entryPoint07Abi, data: transaction.input });
|
|
69
|
+
if (decoded.functionName !== "handleOps") return false;
|
|
70
|
+
const operations = decoded.args[0].filter((operation2) => [evidence.agentWallet.toLowerCase(), evidence.walletAddress.toLowerCase()].includes(operation2.sender.toLowerCase()));
|
|
71
|
+
if (operations.length !== 1) return false;
|
|
72
|
+
const operation = operations[0];
|
|
73
|
+
const userOperation = (0, import_account_abstraction.toUserOperation)(operation);
|
|
74
|
+
const hash = (0, import_account_abstraction.getUserOperationHash)({
|
|
75
|
+
chainId: evidence.chainId,
|
|
76
|
+
entryPointAddress: transaction.to,
|
|
77
|
+
entryPointVersion: version,
|
|
78
|
+
userOperation
|
|
79
|
+
});
|
|
80
|
+
if (evidence.userOpHash && hash.toLowerCase() !== evidence.userOpHash.toLowerCase()) return false;
|
|
81
|
+
if (!receipt?.logs.some((log) => {
|
|
82
|
+
if (log.address.toLowerCase() !== address) return false;
|
|
83
|
+
try {
|
|
84
|
+
const event = (0, import_viem.decodeEventLog)({ abi: import_account_abstraction.entryPoint06Abi, data: log.data, topics: log.topics });
|
|
85
|
+
return event.eventName === "UserOperationEvent" && event.args.userOpHash.toLowerCase() === hash.toLowerCase() && event.args.sender.toLowerCase() === operation.sender.toLowerCase() && event.args.success;
|
|
86
|
+
} catch {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
})) return false;
|
|
90
|
+
if (operation.sender.toLowerCase() === evidence.agentWallet.toLowerCase()) return matchesFullCall(operation.callData);
|
|
91
|
+
const execution = (0, import_viem.decodeFunctionData)({ abi: accountExecutionAbi, data: operation.callData });
|
|
92
|
+
const calls = execution.functionName === "execute" ? [{ target: execution.args[0], value: execution.args[1], data: execution.args[2] }] : execution.args[0];
|
|
93
|
+
return calls.length === 1 && calls[0].value === 0n && calls[0].target.toLowerCase() === evidence.agentWallet.toLowerCase() && matchesFullCall(calls[0].data);
|
|
51
94
|
} catch {
|
|
52
95
|
return false;
|
|
53
96
|
}
|
|
@@ -2632,8 +2675,8 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2632
2675
|
};
|
|
2633
2676
|
|
|
2634
2677
|
// src/agents/yieldseeker/yieldseeker.agent.ts
|
|
2635
|
-
var
|
|
2636
|
-
var
|
|
2678
|
+
var import_viem10 = require("viem");
|
|
2679
|
+
var import_chains4 = require("viem/chains");
|
|
2637
2680
|
|
|
2638
2681
|
// src/lib/chain-guard.ts
|
|
2639
2682
|
var CHAIN_NAMES = {
|
|
@@ -2676,10 +2719,10 @@ var import_viem4 = require("viem");
|
|
|
2676
2719
|
// src/lib/sponsor-client.ts
|
|
2677
2720
|
var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
2678
2721
|
async function postPaymasterIntent(input) {
|
|
2679
|
-
const
|
|
2722
|
+
const base6 = input.baseUrl ?? ROUTING_API_BASE_URL;
|
|
2680
2723
|
let res;
|
|
2681
2724
|
try {
|
|
2682
|
-
res = await fetch(`${
|
|
2725
|
+
res = await fetch(`${base6}/api/v1/sponsor/paymaster-intent`, {
|
|
2683
2726
|
method: "POST",
|
|
2684
2727
|
headers: {
|
|
2685
2728
|
"content-type": "application/json",
|
|
@@ -2715,11 +2758,11 @@ async function postPaymasterIntent(input) {
|
|
|
2715
2758
|
return parsed.data;
|
|
2716
2759
|
}
|
|
2717
2760
|
async function getSponsorRelayerAddress(input) {
|
|
2718
|
-
const
|
|
2761
|
+
const base6 = input.baseUrl ?? ROUTING_API_BASE_URL;
|
|
2719
2762
|
let res;
|
|
2720
2763
|
try {
|
|
2721
2764
|
res = await fetch(
|
|
2722
|
-
`${
|
|
2765
|
+
`${base6}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
|
|
2723
2766
|
{
|
|
2724
2767
|
headers: { "x-owney-api-key": input.apiKey }
|
|
2725
2768
|
}
|
|
@@ -3550,6 +3593,49 @@ function actionEntry(action) {
|
|
|
3550
3593
|
rebalanceLog: []
|
|
3551
3594
|
};
|
|
3552
3595
|
}
|
|
3596
|
+
function allocationEntry(action, context) {
|
|
3597
|
+
if (action.actionType.toLowerCase() !== "autoseek") return void 0;
|
|
3598
|
+
const hash = action.details?.depositTransactionHash;
|
|
3599
|
+
const deposits = action.details?.deposits;
|
|
3600
|
+
if (typeof hash !== "string" || !/^0x[a-fA-F0-9]{64}$/.test(hash) || !Array.isArray(deposits) || deposits.length === 0) return void 0;
|
|
3601
|
+
const positions = [];
|
|
3602
|
+
let amountRaw = 0n;
|
|
3603
|
+
for (const deposit of deposits) {
|
|
3604
|
+
if (!deposit || typeof deposit !== "object") return void 0;
|
|
3605
|
+
const leg = deposit;
|
|
3606
|
+
const symbol = typeof leg.assetSymbol === "string" ? leg.assetSymbol.toUpperCase() : "";
|
|
3607
|
+
if (symbol !== context.asset && !(context.asset === "WETH" && symbol === "ETH")) return void 0;
|
|
3608
|
+
if (typeof leg.vaultAddress !== "string" || !(0, import_viem7.isAddress)(leg.vaultAddress)) return void 0;
|
|
3609
|
+
const rawAmount = typeof leg.rawAmount === "string" && /^\d+$/.test(leg.rawAmount) ? BigInt(leg.rawAmount) : typeof leg.rawAmount === "number" && Number.isSafeInteger(leg.rawAmount) ? BigInt(leg.rawAmount) : void 0;
|
|
3610
|
+
if (rawAmount === void 0 || rawAmount <= 0n) return void 0;
|
|
3611
|
+
const option = context.positions.find((position2) => position2.yieldOption.address.toLowerCase() === leg.vaultAddress.toLowerCase())?.yieldOption;
|
|
3612
|
+
positions.push({
|
|
3613
|
+
protocol: typeof leg.vaultProvider === "string" && leg.vaultProvider ? leg.vaultProvider : option?.provider || "Vault",
|
|
3614
|
+
pool: typeof leg.vaultName === "string" && leg.vaultName ? leg.vaultName : option?.name,
|
|
3615
|
+
tokenSymbol: context.asset,
|
|
3616
|
+
amount: (0, import_viem7.formatUnits)(rawAmount, YIELDSEEKER_ASSET_METADATA[context.asset].decimals)
|
|
3617
|
+
});
|
|
3618
|
+
amountRaw += rawAmount;
|
|
3619
|
+
}
|
|
3620
|
+
return {
|
|
3621
|
+
agent: "yieldseeker",
|
|
3622
|
+
action: "Deposit",
|
|
3623
|
+
date: action.createdDate,
|
|
3624
|
+
oldApy: null,
|
|
3625
|
+
newApy: null,
|
|
3626
|
+
positions,
|
|
3627
|
+
rebalanceLog: [],
|
|
3628
|
+
transactions: [{
|
|
3629
|
+
txHashes: [hash],
|
|
3630
|
+
chainId: context.agent.chainId,
|
|
3631
|
+
tokenAddress: context.agent.assetAddress,
|
|
3632
|
+
tokenSymbol: context.asset,
|
|
3633
|
+
agentWallet: context.wallet.walletAddress,
|
|
3634
|
+
amountRaw: String(amountRaw),
|
|
3635
|
+
amount: (0, import_viem7.formatUnits)(amountRaw, YIELDSEEKER_ASSET_METADATA[context.asset].decimals)
|
|
3636
|
+
}]
|
|
3637
|
+
};
|
|
3638
|
+
}
|
|
3553
3639
|
function depositDestination(context, movement) {
|
|
3554
3640
|
const to = movement.toAddress.toLowerCase();
|
|
3555
3641
|
const option = context.positions.find(({ yieldOption }) => yieldOption.chainId === movement.chainId && yieldOption.assetAddress.toLowerCase() === context.agent.assetAddress.toLowerCase() && yieldOption.address.toLowerCase() === to)?.yieldOption;
|
|
@@ -3617,20 +3703,30 @@ function mapYieldseekerHistory(contexts, options) {
|
|
|
3617
3703
|
seenMovements.add(key2);
|
|
3618
3704
|
return true;
|
|
3619
3705
|
});
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
|
|
3706
|
+
const movementEntries = movements.map(
|
|
3707
|
+
(movement) => movementEntry(
|
|
3708
|
+
movement,
|
|
3709
|
+
context.wallet,
|
|
3710
|
+
context.agent,
|
|
3711
|
+
context.asset,
|
|
3712
|
+
options.ownerAddress,
|
|
3713
|
+
options.vaultAddresses,
|
|
3714
|
+
depositDestination(context, movement)
|
|
3715
|
+
)
|
|
3716
|
+
).filter((entry) => entry !== void 0);
|
|
3717
|
+
const deposits = new Set(movementEntries.filter((entry) => entry.action === "Deposit").map((entry) => entry.transactions[0]?.txHashes[0]?.toLowerCase()));
|
|
3718
|
+
const actions = (context.actions ?? []).flatMap((action) => {
|
|
3719
|
+
const allocation = allocationEntry(action, context);
|
|
3720
|
+
if (allocation) {
|
|
3721
|
+
const hash = allocation.transactions[0].txHashes[0].toLowerCase();
|
|
3722
|
+
if (deposits.has(hash)) return [];
|
|
3723
|
+
deposits.add(hash);
|
|
3724
|
+
return [allocation];
|
|
3725
|
+
}
|
|
3726
|
+
const entry = actionEntry(action);
|
|
3727
|
+
return entry ? [entry] : [];
|
|
3728
|
+
});
|
|
3729
|
+
return [...movementEntries, ...actions];
|
|
3634
3730
|
});
|
|
3635
3731
|
const grouped = /* @__PURE__ */ new Map();
|
|
3636
3732
|
const ungrouped = [];
|
|
@@ -3740,6 +3836,395 @@ function mapYieldseekerAgentApy(options, days) {
|
|
|
3740
3836
|
};
|
|
3741
3837
|
}
|
|
3742
3838
|
|
|
3839
|
+
// src/agents/yieldseeker/yieldseeker.wallet-version.ts
|
|
3840
|
+
var import_viem8 = require("viem");
|
|
3841
|
+
var YIELDSEEKER_FACTORY = "0x9c7410a0faCAC60850C46eE5b58B518daec95130";
|
|
3842
|
+
var YIELDSEEKER_V1_IMPLEMENTATION = "0x32403455357589523435dB18b414057D7cE05051";
|
|
3843
|
+
var YIELDSEEKER_V2_IMPLEMENTATION = "0x613Db9c924ADB7A7A90c11b02Cce20c913E3Fe50";
|
|
3844
|
+
var ERC1967_IMPLEMENTATION_SLOT = "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc";
|
|
3845
|
+
var walletAbi = (0, import_viem8.parseAbi)([
|
|
3846
|
+
"function owner() view returns (address)",
|
|
3847
|
+
"function ownerAgentIndex() view returns (uint256)",
|
|
3848
|
+
"function baseAsset() view returns (address)",
|
|
3849
|
+
"function FACTORY() view returns (address)",
|
|
3850
|
+
"function upgradeToLatest()"
|
|
3851
|
+
]);
|
|
3852
|
+
var factoryAbi = (0, import_viem8.parseAbi)([
|
|
3853
|
+
"function userWallets(address owner, uint256 index) view returns (address)",
|
|
3854
|
+
"function agentWalletImplementation() view returns (address)"
|
|
3855
|
+
]);
|
|
3856
|
+
function yieldseekerOwnerPath(code) {
|
|
3857
|
+
return !code || code === "0x" || /^0xef0100[0-9a-f]{40}$/i.test(code) ? "eoa" : "smart";
|
|
3858
|
+
}
|
|
3859
|
+
async function readYieldseekerWalletStatus(client, wallet, owner, asset) {
|
|
3860
|
+
const agentWallet = (0, import_viem8.getAddress)(wallet);
|
|
3861
|
+
const expectedOwner = (0, import_viem8.getAddress)(owner);
|
|
3862
|
+
const expectedAsset = (0, import_viem8.getAddress)(asset);
|
|
3863
|
+
const [code, ownerCode, slot, actualOwner, index, actualAsset, actualFactory, latest] = await Promise.all([
|
|
3864
|
+
client.getBytecode({ address: agentWallet }),
|
|
3865
|
+
client.getBytecode({ address: expectedOwner }),
|
|
3866
|
+
client.getStorageAt({ address: agentWallet, slot: ERC1967_IMPLEMENTATION_SLOT }),
|
|
3867
|
+
client.readContract({ address: agentWallet, abi: walletAbi, functionName: "owner" }),
|
|
3868
|
+
client.readContract({ address: agentWallet, abi: walletAbi, functionName: "ownerAgentIndex" }),
|
|
3869
|
+
client.readContract({ address: agentWallet, abi: walletAbi, functionName: "baseAsset" }),
|
|
3870
|
+
client.readContract({ address: agentWallet, abi: walletAbi, functionName: "FACTORY" }),
|
|
3871
|
+
client.readContract({ address: YIELDSEEKER_FACTORY, abi: factoryAbi, functionName: "agentWalletImplementation" })
|
|
3872
|
+
]);
|
|
3873
|
+
if (!code || code === "0x" || !slot || /^0x0+$/.test(slot)) {
|
|
3874
|
+
throw new Error("Yieldseeker wallet is not a deployed ERC1967 proxy");
|
|
3875
|
+
}
|
|
3876
|
+
const implementation = (0, import_viem8.getAddress)(`0x${slot.slice(-40)}`);
|
|
3877
|
+
const mapped = await client.readContract({
|
|
3878
|
+
address: YIELDSEEKER_FACTORY,
|
|
3879
|
+
abi: factoryAbi,
|
|
3880
|
+
functionName: "userWallets",
|
|
3881
|
+
args: [expectedOwner, index]
|
|
3882
|
+
});
|
|
3883
|
+
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);
|
|
3884
|
+
const version = !verified ? "unknown" : (0, import_viem8.isAddressEqual)(implementation, YIELDSEEKER_V2_IMPLEMENTATION) ? "v2" : (0, import_viem8.isAddressEqual)(implementation, YIELDSEEKER_V1_IMPLEMENTATION) ? "v1" : "unknown";
|
|
3885
|
+
return {
|
|
3886
|
+
agentWallet,
|
|
3887
|
+
owner: actualOwner,
|
|
3888
|
+
ownerPath: yieldseekerOwnerPath(ownerCode),
|
|
3889
|
+
asset: actualAsset,
|
|
3890
|
+
implementation,
|
|
3891
|
+
version,
|
|
3892
|
+
verified,
|
|
3893
|
+
upgradeAvailable: version === "v1" && (0, import_viem8.isAddressEqual)(latest, YIELDSEEKER_V2_IMPLEMENTATION)
|
|
3894
|
+
};
|
|
3895
|
+
}
|
|
3896
|
+
var YIELDSEEKER_UPGRADE_ABI = walletAbi;
|
|
3897
|
+
|
|
3898
|
+
// src/agents/yieldseeker/yieldseeker.sponsored-withdraw.ts
|
|
3899
|
+
var import_viem9 = require("viem");
|
|
3900
|
+
var import_account_abstraction2 = require("viem/account-abstraction");
|
|
3901
|
+
var import_accounts = require("viem/accounts");
|
|
3902
|
+
var import_chains3 = require("viem/chains");
|
|
3903
|
+
var ENTRY_POINT_V06 = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789";
|
|
3904
|
+
var USER_OP_FEE_HEADROOM = 2n;
|
|
3905
|
+
var ENTRY_POINT_NONCE_ABI = [
|
|
3906
|
+
{ type: "function", name: "getNonce", stateMutability: "view", inputs: [
|
|
3907
|
+
{ name: "sender", type: "address" },
|
|
3908
|
+
{ name: "key", type: "uint192" }
|
|
3909
|
+
], outputs: [{ type: "uint256" }] }
|
|
3910
|
+
];
|
|
3911
|
+
var DEFAULT_ROUTING_API = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
3912
|
+
var SIMULATION_ACCOUNT = (0, import_accounts.privateKeyToAccount)((0, import_accounts.generatePrivateKey)());
|
|
3913
|
+
function operationHash(operation) {
|
|
3914
|
+
return (0, import_account_abstraction2.getUserOperationHash)({
|
|
3915
|
+
chainId: 8453,
|
|
3916
|
+
entryPointAddress: ENTRY_POINT_V06,
|
|
3917
|
+
entryPointVersion: "0.6",
|
|
3918
|
+
userOperation: {
|
|
3919
|
+
sender: operation.sender,
|
|
3920
|
+
nonce: BigInt(operation.nonce),
|
|
3921
|
+
initCode: operation.initCode,
|
|
3922
|
+
callData: operation.callData,
|
|
3923
|
+
callGasLimit: BigInt(operation.callGasLimit),
|
|
3924
|
+
verificationGasLimit: BigInt(operation.verificationGasLimit),
|
|
3925
|
+
preVerificationGas: BigInt(operation.preVerificationGas),
|
|
3926
|
+
maxFeePerGas: BigInt(operation.maxFeePerGas),
|
|
3927
|
+
maxPriorityFeePerGas: BigInt(operation.maxPriorityFeePerGas),
|
|
3928
|
+
paymasterAndData: operation.paymasterAndData,
|
|
3929
|
+
signature: operation.signature
|
|
3930
|
+
}
|
|
3931
|
+
});
|
|
3932
|
+
}
|
|
3933
|
+
function sponsorError(message, safeToFallback, details = {}) {
|
|
3934
|
+
return new OwneyError(
|
|
3935
|
+
"SPONSOR_REQUEST_FAILED",
|
|
3936
|
+
message,
|
|
3937
|
+
{ safeToFallback, ...details },
|
|
3938
|
+
"yieldseeker"
|
|
3939
|
+
);
|
|
3940
|
+
}
|
|
3941
|
+
async function requestIntent(input) {
|
|
3942
|
+
const baseUrl = (input.routingApiBaseUrl ?? DEFAULT_ROUTING_API).replace(/\/$/, "");
|
|
3943
|
+
let response;
|
|
3944
|
+
try {
|
|
3945
|
+
response = await fetch(`${baseUrl}/api/v1/sponsor/yieldseeker-withdraw/intent`, {
|
|
3946
|
+
method: "POST",
|
|
3947
|
+
headers: {
|
|
3948
|
+
"content-type": "application/json",
|
|
3949
|
+
"x-owney-api-key": input.apiKey,
|
|
3950
|
+
Authorization: `Signature ${input.yieldseekerSignature}`
|
|
3951
|
+
},
|
|
3952
|
+
body: JSON.stringify({
|
|
3953
|
+
chainId: 8453,
|
|
3954
|
+
owner: input.owner,
|
|
3955
|
+
recipient: input.owner,
|
|
3956
|
+
agentWallet: input.agentWallet,
|
|
3957
|
+
asset: input.asset,
|
|
3958
|
+
callData: input.callData,
|
|
3959
|
+
action: input.action,
|
|
3960
|
+
yieldseekerUserId: input.userId,
|
|
3961
|
+
yieldseekerAgentId: input.agentId
|
|
3962
|
+
})
|
|
3963
|
+
});
|
|
3964
|
+
} catch {
|
|
3965
|
+
throw sponsorError("Withdrawal sponsorship could not be requested.", true);
|
|
3966
|
+
}
|
|
3967
|
+
const envelope = await response.json().catch(() => null);
|
|
3968
|
+
const intent = envelope?.data;
|
|
3969
|
+
if (!response.ok || !envelope?.success || !intent?.intent || !["eoa", "smart"].includes(intent.ownerPath)) {
|
|
3970
|
+
throw sponsorError(
|
|
3971
|
+
"Withdrawal sponsorship is currently unavailable.",
|
|
3972
|
+
true,
|
|
3973
|
+
{ statusCode: response.status }
|
|
3974
|
+
);
|
|
3975
|
+
}
|
|
3976
|
+
const url = new URL(`${baseUrl}/api/v1/sponsor/yieldseeker-withdraw/rpc`);
|
|
3977
|
+
url.searchParams.set("intent", intent.intent);
|
|
3978
|
+
return { intent, rpcUrl: url.toString() };
|
|
3979
|
+
}
|
|
3980
|
+
async function rpc(url, method, params, phase) {
|
|
3981
|
+
let response;
|
|
3982
|
+
try {
|
|
3983
|
+
response = await fetch(url, {
|
|
3984
|
+
method: "POST",
|
|
3985
|
+
headers: { "content-type": "application/json" },
|
|
3986
|
+
body: JSON.stringify({ jsonrpc: "2.0", id: 1, method, params })
|
|
3987
|
+
});
|
|
3988
|
+
} catch {
|
|
3989
|
+
throw sponsorError("Withdrawal sponsorship request status is unknown.", phase === "prepare");
|
|
3990
|
+
}
|
|
3991
|
+
const payload = await response.json().catch(() => null);
|
|
3992
|
+
if (!response.ok || payload?.error || payload?.result === void 0) {
|
|
3993
|
+
const rejection = payload?.error;
|
|
3994
|
+
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 ?? ""));
|
|
3995
|
+
throw sponsorError(
|
|
3996
|
+
phase !== "prepare" && !definitiveRejection ? "Sponsored withdrawal submission status is unknown." : "Withdrawal sponsorship was declined before submission.",
|
|
3997
|
+
phase === "prepare" || definitiveRejection,
|
|
3998
|
+
{ statusCode: response.status, rpcCode: payload?.error?.code, rpcMethod: method }
|
|
3999
|
+
);
|
|
4000
|
+
}
|
|
4001
|
+
return payload.result;
|
|
4002
|
+
}
|
|
4003
|
+
async function waitForTransaction(client, txHash) {
|
|
4004
|
+
const receipt = await client.waitForTransactionReceipt({ hash: txHash, confirmations: 1 });
|
|
4005
|
+
if (receipt.status !== "success")
|
|
4006
|
+
throw new OwneyError(
|
|
4007
|
+
"AGENT_TRANSACTION_REVERTED",
|
|
4008
|
+
`Yieldseeker withdrawal reverted (${txHash}).`,
|
|
4009
|
+
{ transactionHash: txHash },
|
|
4010
|
+
"yieldseeker"
|
|
4011
|
+
);
|
|
4012
|
+
return receipt;
|
|
4013
|
+
}
|
|
4014
|
+
async function submitEoa(input) {
|
|
4015
|
+
let nonce;
|
|
4016
|
+
let fees;
|
|
4017
|
+
try {
|
|
4018
|
+
nonce = await input.client.readContract({
|
|
4019
|
+
address: ENTRY_POINT_V06,
|
|
4020
|
+
abi: ENTRY_POINT_NONCE_ABI,
|
|
4021
|
+
functionName: "getNonce",
|
|
4022
|
+
args: [input.agentWallet, 0n]
|
|
4023
|
+
});
|
|
4024
|
+
fees = await input.client.estimateFeesPerGas();
|
|
4025
|
+
} catch {
|
|
4026
|
+
throw sponsorError("Could not prepare the sponsored withdrawal.", true);
|
|
4027
|
+
}
|
|
4028
|
+
if (fees.maxFeePerGas === void 0 || fees.maxPriorityFeePerGas === void 0)
|
|
4029
|
+
throw sponsorError("Base did not return EIP-1559 gas fees.", true);
|
|
4030
|
+
let operation = {
|
|
4031
|
+
sender: input.agentWallet,
|
|
4032
|
+
nonce: (0, import_viem9.toHex)(nonce),
|
|
4033
|
+
initCode: "0x",
|
|
4034
|
+
callData: input.callData,
|
|
4035
|
+
callGasLimit: (0, import_viem9.toHex)(3e5),
|
|
4036
|
+
verificationGasLimit: (0, import_viem9.toHex)(3e5),
|
|
4037
|
+
preVerificationGas: (0, import_viem9.toHex)(6e4),
|
|
4038
|
+
maxFeePerGas: (0, import_viem9.toHex)(fees.maxFeePerGas * USER_OP_FEE_HEADROOM),
|
|
4039
|
+
maxPriorityFeePerGas: (0, import_viem9.toHex)(fees.maxPriorityFeePerGas),
|
|
4040
|
+
paymasterAndData: "0x",
|
|
4041
|
+
signature: "0x"
|
|
4042
|
+
};
|
|
4043
|
+
operation.signature = await SIMULATION_ACCOUNT.signMessage({ message: { raw: operationHash(operation) } });
|
|
4044
|
+
const stub = await rpc(
|
|
4045
|
+
input.rpcUrl,
|
|
4046
|
+
"pm_getPaymasterStubData",
|
|
4047
|
+
[operation, ENTRY_POINT_V06, (0, import_viem9.toHex)(8453), {}],
|
|
4048
|
+
"prepare"
|
|
4049
|
+
);
|
|
4050
|
+
if (!stub.paymasterAndData?.startsWith("0x"))
|
|
4051
|
+
throw sponsorError("CDP did not return v0.6 paymaster data.", true);
|
|
4052
|
+
operation = { ...operation, paymasterAndData: stub.paymasterAndData };
|
|
4053
|
+
operation.signature = await SIMULATION_ACCOUNT.signMessage({ message: { raw: operationHash(operation) } });
|
|
4054
|
+
const gas = await rpc(input.rpcUrl, "eth_estimateUserOperationGas", [operation, ENTRY_POINT_V06], "prepare");
|
|
4055
|
+
if (!gas.callGasLimit || !gas.verificationGasLimit || !gas.preVerificationGas)
|
|
4056
|
+
throw sponsorError("CDP did not return UserOperation gas estimates.", true);
|
|
4057
|
+
operation = { ...operation, ...gas };
|
|
4058
|
+
if (!stub.isFinal) {
|
|
4059
|
+
const final = await rpc(
|
|
4060
|
+
input.rpcUrl,
|
|
4061
|
+
"pm_getPaymasterData",
|
|
4062
|
+
[operation, ENTRY_POINT_V06, (0, import_viem9.toHex)(8453), {}],
|
|
4063
|
+
"prepare"
|
|
4064
|
+
);
|
|
4065
|
+
if (!final.paymasterAndData?.startsWith("0x"))
|
|
4066
|
+
throw sponsorError("CDP did not return final paymaster data.", true);
|
|
4067
|
+
operation = { ...operation, paymasterAndData: final.paymasterAndData };
|
|
4068
|
+
}
|
|
4069
|
+
const userOpHash = operationHash(operation);
|
|
4070
|
+
const wallet = (0, import_viem9.createWalletClient)({
|
|
4071
|
+
account: input.owner,
|
|
4072
|
+
chain: import_chains3.base,
|
|
4073
|
+
transport: (0, import_viem9.custom)(input.state.provider)
|
|
4074
|
+
});
|
|
4075
|
+
const signature = await wallet.signMessage({ message: { raw: userOpHash } });
|
|
4076
|
+
operation = { ...operation, signature };
|
|
4077
|
+
input.onPending?.({ userOpHash });
|
|
4078
|
+
const submittedHash = await rpc(
|
|
4079
|
+
input.rpcUrl,
|
|
4080
|
+
"eth_sendUserOperation",
|
|
4081
|
+
[operation, ENTRY_POINT_V06],
|
|
4082
|
+
"send"
|
|
4083
|
+
);
|
|
4084
|
+
if (submittedHash.toLowerCase() !== userOpHash.toLowerCase())
|
|
4085
|
+
throw sponsorError(
|
|
4086
|
+
"Bundler returned a different UserOperation hash.",
|
|
4087
|
+
false,
|
|
4088
|
+
{ userOpHash, submittedHash }
|
|
4089
|
+
);
|
|
4090
|
+
for (let poll = 0; poll < 40; poll++) {
|
|
4091
|
+
const response = await rpc(input.rpcUrl, "eth_getUserOperationReceipt", [userOpHash], "observe");
|
|
4092
|
+
const txHash = response?.receipt?.transactionHash;
|
|
4093
|
+
if (txHash) {
|
|
4094
|
+
input.onPending?.({ userOpHash, txHash });
|
|
4095
|
+
if (response?.success === false)
|
|
4096
|
+
throw new OwneyError(
|
|
4097
|
+
"AGENT_TRANSACTION_REVERTED",
|
|
4098
|
+
"Sponsored withdrawal execution reverted.",
|
|
4099
|
+
{ userOpHash, transactionHash: txHash },
|
|
4100
|
+
"yieldseeker"
|
|
4101
|
+
);
|
|
4102
|
+
return { txHash, receipt: await waitForTransaction(input.client, txHash) };
|
|
4103
|
+
}
|
|
4104
|
+
await new Promise((resolve) => setTimeout(resolve, 1500));
|
|
4105
|
+
}
|
|
4106
|
+
throw sponsorError(
|
|
4107
|
+
"Sponsored withdrawal is still pending; check status before retrying.",
|
|
4108
|
+
false,
|
|
4109
|
+
{ userOpHash }
|
|
4110
|
+
);
|
|
4111
|
+
}
|
|
4112
|
+
async function submitSmart(input) {
|
|
4113
|
+
let capabilities;
|
|
4114
|
+
try {
|
|
4115
|
+
capabilities = await input.state.provider.request({
|
|
4116
|
+
method: "wallet_getCapabilities",
|
|
4117
|
+
params: [input.owner]
|
|
4118
|
+
});
|
|
4119
|
+
} catch {
|
|
4120
|
+
throw sponsorError("This account cannot check paymaster support on Base.", true);
|
|
4121
|
+
}
|
|
4122
|
+
if (!capabilities?.[(0, import_viem9.toHex)(8453)]?.paymasterService?.supported && !capabilities?.["8453"]?.paymasterService?.supported)
|
|
4123
|
+
throw sponsorError("This account cannot use a paymaster on Base.", true);
|
|
4124
|
+
let sent;
|
|
4125
|
+
try {
|
|
4126
|
+
input.onPending?.({});
|
|
4127
|
+
} catch {
|
|
4128
|
+
throw sponsorError("Upgrade or withdrawal status cannot be saved.", true);
|
|
4129
|
+
}
|
|
4130
|
+
try {
|
|
4131
|
+
sent = await input.state.provider.request({
|
|
4132
|
+
method: "wallet_sendCalls",
|
|
4133
|
+
params: [{
|
|
4134
|
+
version: "2.0.0",
|
|
4135
|
+
from: input.owner,
|
|
4136
|
+
chainId: (0, import_viem9.toHex)(8453),
|
|
4137
|
+
atomicRequired: false,
|
|
4138
|
+
calls: [{ to: input.agentWallet, value: "0x0", data: input.callData }],
|
|
4139
|
+
capabilities: { paymasterService: { url: input.rpcUrl } }
|
|
4140
|
+
}]
|
|
4141
|
+
});
|
|
4142
|
+
} catch (error) {
|
|
4143
|
+
if (error?.code === 4001) throw error;
|
|
4144
|
+
if ([4200, -32601].includes(Number(error?.code)))
|
|
4145
|
+
throw sponsorError("This account does not support sponsored calls.", true);
|
|
4146
|
+
throw sponsorError("Wallet submission status is unknown. Check activity before retrying.", false);
|
|
4147
|
+
}
|
|
4148
|
+
const callsId = typeof sent === "string" ? sent : sent?.id;
|
|
4149
|
+
if (!callsId) throw sponsorError("Wallet returned no calls ID; submission status is unknown.", false);
|
|
4150
|
+
try {
|
|
4151
|
+
input.onPending?.({ callsId });
|
|
4152
|
+
} catch {
|
|
4153
|
+
throw sponsorError("Submitted call status could not be saved.", false, { callsId });
|
|
4154
|
+
}
|
|
4155
|
+
for (let poll = 0; poll < 40; poll++) {
|
|
4156
|
+
let status;
|
|
4157
|
+
try {
|
|
4158
|
+
status = await input.state.provider.request({
|
|
4159
|
+
method: "wallet_getCallsStatus",
|
|
4160
|
+
params: [callsId]
|
|
4161
|
+
});
|
|
4162
|
+
} catch {
|
|
4163
|
+
throw sponsorError("Sponsored withdrawal status is unknown.", false, { callsId });
|
|
4164
|
+
}
|
|
4165
|
+
if (status?.status === 400 || status?.status === 500)
|
|
4166
|
+
throw sponsorError(
|
|
4167
|
+
"Sponsored withdrawal failed in the wallet.",
|
|
4168
|
+
false,
|
|
4169
|
+
{ callsId, executionFailed: true }
|
|
4170
|
+
);
|
|
4171
|
+
const txHash = status?.receipts?.[0]?.transactionHash;
|
|
4172
|
+
if (txHash) {
|
|
4173
|
+
try {
|
|
4174
|
+
input.onPending?.({ callsId, txHash });
|
|
4175
|
+
} catch {
|
|
4176
|
+
throw sponsorError(
|
|
4177
|
+
"Submitted call receipt could not be saved.",
|
|
4178
|
+
false,
|
|
4179
|
+
{ callsId, txHash }
|
|
4180
|
+
);
|
|
4181
|
+
}
|
|
4182
|
+
return { txHash, receipt: await waitForTransaction(input.client, txHash) };
|
|
4183
|
+
}
|
|
4184
|
+
await new Promise((resolve) => setTimeout(resolve, 1500));
|
|
4185
|
+
}
|
|
4186
|
+
throw sponsorError(
|
|
4187
|
+
"Sponsored withdrawal is still pending; check status before retrying.",
|
|
4188
|
+
false,
|
|
4189
|
+
{ callsId }
|
|
4190
|
+
);
|
|
4191
|
+
}
|
|
4192
|
+
async function submitYieldseekerSponsoredWithdrawal(input) {
|
|
4193
|
+
const owner = (0, import_viem9.getAddress)(input.state.walletAddress);
|
|
4194
|
+
const { intent, rpcUrl } = await requestIntent({
|
|
4195
|
+
apiKey: input.apiKey,
|
|
4196
|
+
routingApiBaseUrl: input.routingApiBaseUrl,
|
|
4197
|
+
yieldseekerSignature: input.yieldseekerSignature,
|
|
4198
|
+
userId: input.userId,
|
|
4199
|
+
agentId: input.agentId,
|
|
4200
|
+
owner,
|
|
4201
|
+
agentWallet: input.agentWallet,
|
|
4202
|
+
asset: input.asset,
|
|
4203
|
+
callData: input.callData,
|
|
4204
|
+
action: "withdraw"
|
|
4205
|
+
});
|
|
4206
|
+
const args = { ...input, owner, rpcUrl };
|
|
4207
|
+
return intent.ownerPath === "eoa" ? submitEoa(args) : submitSmart(args);
|
|
4208
|
+
}
|
|
4209
|
+
async function submitYieldseekerSponsoredUpgrade(input) {
|
|
4210
|
+
const owner = (0, import_viem9.getAddress)(input.state.walletAddress);
|
|
4211
|
+
const { intent, rpcUrl } = await requestIntent({
|
|
4212
|
+
apiKey: input.apiKey,
|
|
4213
|
+
routingApiBaseUrl: input.routingApiBaseUrl,
|
|
4214
|
+
yieldseekerSignature: input.yieldseekerSignature,
|
|
4215
|
+
userId: input.userId,
|
|
4216
|
+
agentId: input.agentId,
|
|
4217
|
+
owner,
|
|
4218
|
+
agentWallet: input.agentWallet,
|
|
4219
|
+
asset: input.asset,
|
|
4220
|
+
callData: input.callData,
|
|
4221
|
+
action: "upgrade"
|
|
4222
|
+
});
|
|
4223
|
+
if (intent.ownerPath !== "smart")
|
|
4224
|
+
throw sponsorError("V1 upgrade sponsorship requires a Base Account owner.", true);
|
|
4225
|
+
return submitSmart({ ...input, owner, rpcUrl });
|
|
4226
|
+
}
|
|
4227
|
+
|
|
3743
4228
|
// src/agents/yieldseeker/yieldseeker.agent.ts
|
|
3744
4229
|
var OWNEY_AGENT_NAME = "owney";
|
|
3745
4230
|
var OWNEY_AGENT_RULE_PRESET = "explorative";
|
|
@@ -3754,6 +4239,7 @@ var YIELDSEEKER_SETTLEMENT_ACTIVITY_CACHE_MS = 15e3;
|
|
|
3754
4239
|
var YIELDSEEKER_READ_FAILURE_COOLDOWN_MS = 6e4;
|
|
3755
4240
|
var YIELDSEEKER_SETTLEMENT_WINDOW_MS = 5 * 6e4;
|
|
3756
4241
|
var YIELDSEEKER_ACTIVITY_CACHE_MS = 6e4;
|
|
4242
|
+
var YIELDSEEKER_MAX_WITHDRAW_SWEEPS = 3;
|
|
3757
4243
|
function generateYieldseekerUsername() {
|
|
3758
4244
|
const suffix = globalThis.crypto.randomUUID().replaceAll("-", "").slice(0, YIELDSEEKER_USERNAME_RANDOM_LENGTH).toLowerCase();
|
|
3759
4245
|
return `${YIELDSEEKER_USERNAME_PREFIX}${suffix}`;
|
|
@@ -3812,7 +4298,11 @@ var YieldseekerAgent = class {
|
|
|
3812
4298
|
api;
|
|
3813
4299
|
auth;
|
|
3814
4300
|
rpcUrls;
|
|
4301
|
+
owneyApiKey;
|
|
4302
|
+
routingApiBaseUrl;
|
|
3815
4303
|
receiptClient;
|
|
4304
|
+
// A client preparation hint only; the routing API still checks live identity.
|
|
4305
|
+
withdrawalVersionCache = /* @__PURE__ */ new Map();
|
|
3816
4306
|
transactionExecutor;
|
|
3817
4307
|
unwindReceiptWaiter;
|
|
3818
4308
|
agentContexts = /* @__PURE__ */ new Map();
|
|
@@ -3834,6 +4324,8 @@ var YieldseekerAgent = class {
|
|
|
3834
4324
|
yieldOptions = /* @__PURE__ */ new Map();
|
|
3835
4325
|
pendingYieldOptions = /* @__PURE__ */ new Map();
|
|
3836
4326
|
constructor(owneyApiKey, options = {}) {
|
|
4327
|
+
this.owneyApiKey = owneyApiKey;
|
|
4328
|
+
this.routingApiBaseUrl = options.routingApiBaseUrl;
|
|
3837
4329
|
this.api = new YieldseekerApiClient(
|
|
3838
4330
|
owneyApiKey,
|
|
3839
4331
|
options.baseUrl ?? getYieldseekerProxyBaseUrl(),
|
|
@@ -3845,10 +4337,182 @@ var YieldseekerAgent = class {
|
|
|
3845
4337
|
this.unwindReceiptWaiter = options.unwindReceiptWaiter;
|
|
3846
4338
|
}
|
|
3847
4339
|
getReceiptClient() {
|
|
3848
|
-
this.receiptClient ??= createPaidRpcClient(
|
|
4340
|
+
this.receiptClient ??= createPaidRpcClient(import_chains4.base, this.rpcUrls);
|
|
3849
4341
|
return this.receiptClient;
|
|
3850
4342
|
}
|
|
4343
|
+
/** Reads the actual proxy implementation; Yieldseeker's API walletType is not a version check. */
|
|
4344
|
+
async getWalletStatus(state, chainId, asset, useCachedV2 = false) {
|
|
4345
|
+
this.assertChain(chainId);
|
|
4346
|
+
this.assertAsset(asset);
|
|
4347
|
+
const context = await this.findAgent(state, chainId, asset);
|
|
4348
|
+
if (!context) return null;
|
|
4349
|
+
const key2 = `${chainId}:${state.walletAddress.toLowerCase()}:${context.wallet.walletAddress.toLowerCase()}:${asset}`;
|
|
4350
|
+
const cached = this.withdrawalVersionCache.get(key2);
|
|
4351
|
+
if (useCachedV2 && cached && Date.now() - cached.at < 15 * 6e4) return { ...cached.status };
|
|
4352
|
+
const status = await readYieldseekerWalletStatus(
|
|
4353
|
+
this.getReceiptClient(),
|
|
4354
|
+
(0, import_viem10.getAddress)(context.wallet.walletAddress),
|
|
4355
|
+
(0, import_viem10.getAddress)(state.walletAddress),
|
|
4356
|
+
YIELDSEEKER_ASSET_METADATA[asset].address
|
|
4357
|
+
);
|
|
4358
|
+
if (status.verified && status.version === "v2") {
|
|
4359
|
+
this.withdrawalVersionCache.set(key2, { at: Date.now(), status: { ...status } });
|
|
4360
|
+
if (this.withdrawalVersionCache.size > 128)
|
|
4361
|
+
this.withdrawalVersionCache.delete(this.withdrawalVersionCache.keys().next().value);
|
|
4362
|
+
} else this.withdrawalVersionCache.delete(key2);
|
|
4363
|
+
return status;
|
|
4364
|
+
}
|
|
4365
|
+
/** Explicit owner action. This never runs as a side effect of withdrawal. */
|
|
4366
|
+
async upgradeWallet(state, chainId, asset, gasMode = "paid") {
|
|
4367
|
+
const before = await this.getWalletStatus(state, chainId, asset);
|
|
4368
|
+
if (!before?.verified || !before.upgradeAvailable) {
|
|
4369
|
+
throw new OwneyError(
|
|
4370
|
+
"WITHDRAW_FAILED",
|
|
4371
|
+
"This Yieldseeker wallet cannot be upgraded to the reviewed V2 implementation.",
|
|
4372
|
+
{ version: before?.version ?? "missing" },
|
|
4373
|
+
this.id
|
|
4374
|
+
);
|
|
4375
|
+
}
|
|
4376
|
+
const data = (0, import_viem10.encodeFunctionData)({ abi: YIELDSEEKER_UPGRADE_ABI, functionName: "upgradeToLatest" });
|
|
4377
|
+
let txHash;
|
|
4378
|
+
if (gasMode === "sponsored") {
|
|
4379
|
+
if (before.ownerPath !== "smart")
|
|
4380
|
+
throw new OwneyError(
|
|
4381
|
+
"SPONSOR_REQUEST_FAILED",
|
|
4382
|
+
"EOA owners pay Base gas for the V1 upgrade.",
|
|
4383
|
+
{ safeToFallback: true },
|
|
4384
|
+
this.id
|
|
4385
|
+
);
|
|
4386
|
+
let storage5;
|
|
4387
|
+
try {
|
|
4388
|
+
storage5 = typeof window === "undefined" ? void 0 : window.localStorage;
|
|
4389
|
+
} catch {
|
|
4390
|
+
storage5 = void 0;
|
|
4391
|
+
}
|
|
4392
|
+
if (!storage5)
|
|
4393
|
+
throw new OwneyError(
|
|
4394
|
+
"SPONSOR_REQUEST_FAILED",
|
|
4395
|
+
"Upgrade status cannot be saved in this browser.",
|
|
4396
|
+
{ safeToFallback: true },
|
|
4397
|
+
this.id
|
|
4398
|
+
);
|
|
4399
|
+
const pendingKey = `owney.yieldseeker.upgrade:${state.walletAddress.toLowerCase()}:${before.agentWallet.toLowerCase()}`;
|
|
4400
|
+
let prior = null;
|
|
4401
|
+
let saved;
|
|
4402
|
+
try {
|
|
4403
|
+
saved = storage5.getItem(pendingKey);
|
|
4404
|
+
} catch {
|
|
4405
|
+
throw new OwneyError(
|
|
4406
|
+
"SPONSOR_REQUEST_FAILED",
|
|
4407
|
+
"Upgrade status cannot be read in this browser.",
|
|
4408
|
+
{ safeToFallback: true },
|
|
4409
|
+
this.id
|
|
4410
|
+
);
|
|
4411
|
+
}
|
|
4412
|
+
try {
|
|
4413
|
+
prior = JSON.parse(saved ?? "null");
|
|
4414
|
+
} catch {
|
|
4415
|
+
prior = { callsId: void 0 };
|
|
4416
|
+
}
|
|
4417
|
+
if (prior) {
|
|
4418
|
+
if (!prior.callsId)
|
|
4419
|
+
throw new OwneyError(
|
|
4420
|
+
"SPONSOR_REQUEST_FAILED",
|
|
4421
|
+
"An earlier upgrade submission is unresolved. Check wallet activity before retrying.",
|
|
4422
|
+
{ safeToFallback: false },
|
|
4423
|
+
this.id
|
|
4424
|
+
);
|
|
4425
|
+
let callsStatus;
|
|
4426
|
+
try {
|
|
4427
|
+
callsStatus = await state.provider.request({
|
|
4428
|
+
method: "wallet_getCallsStatus",
|
|
4429
|
+
params: [prior.callsId]
|
|
4430
|
+
});
|
|
4431
|
+
} catch {
|
|
4432
|
+
throw new OwneyError(
|
|
4433
|
+
"SPONSOR_REQUEST_FAILED",
|
|
4434
|
+
"The earlier upgrade status could not be checked.",
|
|
4435
|
+
{ safeToFallback: false, callsId: prior.callsId },
|
|
4436
|
+
this.id
|
|
4437
|
+
);
|
|
4438
|
+
}
|
|
4439
|
+
if (callsStatus?.status === 400 || callsStatus?.status === 500) {
|
|
4440
|
+
storage5.removeItem(pendingKey);
|
|
4441
|
+
throw new OwneyError(
|
|
4442
|
+
"SPONSOR_REQUEST_FAILED",
|
|
4443
|
+
"The earlier sponsored upgrade failed.",
|
|
4444
|
+
{ safeToFallback: true, callsId: prior.callsId },
|
|
4445
|
+
this.id
|
|
4446
|
+
);
|
|
4447
|
+
}
|
|
4448
|
+
const earlierHash = callsStatus?.receipts?.[0]?.transactionHash;
|
|
4449
|
+
if (earlierHash) {
|
|
4450
|
+
await this.waitForReceipt(state, chainId, earlierHash);
|
|
4451
|
+
const earlierStatus = await this.getWalletStatus(state, chainId, asset);
|
|
4452
|
+
if (earlierStatus?.version === "v2" && earlierStatus.verified) {
|
|
4453
|
+
storage5.removeItem(pendingKey);
|
|
4454
|
+
return { txHash: earlierHash, status: earlierStatus };
|
|
4455
|
+
}
|
|
4456
|
+
}
|
|
4457
|
+
throw new OwneyError(
|
|
4458
|
+
"SPONSOR_REQUEST_FAILED",
|
|
4459
|
+
"An earlier upgrade is still pending.",
|
|
4460
|
+
{ safeToFallback: false, callsId: prior.callsId },
|
|
4461
|
+
this.id
|
|
4462
|
+
);
|
|
4463
|
+
}
|
|
4464
|
+
const context = await this.findAgent(state, chainId, asset);
|
|
4465
|
+
if (!context) throw new OwneyError("NOT_CONNECTED", "Yieldseeker agent is unavailable.");
|
|
4466
|
+
try {
|
|
4467
|
+
const upgraded = await submitYieldseekerSponsoredUpgrade({
|
|
4468
|
+
state,
|
|
4469
|
+
client: this.getReceiptClient(),
|
|
4470
|
+
apiKey: this.owneyApiKey,
|
|
4471
|
+
routingApiBaseUrl: this.routingApiBaseUrl,
|
|
4472
|
+
yieldseekerSignature: await this.auth.getToken(state, chainId),
|
|
4473
|
+
userId: context.user.userId,
|
|
4474
|
+
agentId: context.agent.agentId,
|
|
4475
|
+
agentWallet: before.agentWallet,
|
|
4476
|
+
asset: YIELDSEEKER_ASSET_METADATA[asset].address,
|
|
4477
|
+
callData: data,
|
|
4478
|
+
onPending: (pending) => {
|
|
4479
|
+
const current = storage5.getItem(pendingKey);
|
|
4480
|
+
storage5.setItem(pendingKey, JSON.stringify({
|
|
4481
|
+
startedAt: Date.now(),
|
|
4482
|
+
...current ? JSON.parse(current) : {},
|
|
4483
|
+
...pending
|
|
4484
|
+
}));
|
|
4485
|
+
}
|
|
4486
|
+
});
|
|
4487
|
+
txHash = upgraded.txHash;
|
|
4488
|
+
} catch (error) {
|
|
4489
|
+
if (error?.code === 4001 || error instanceof OwneyError && error.code === "SPONSOR_REQUEST_FAILED" && (error.details?.safeToFallback === true || error.details?.executionFailed === true)) storage5.removeItem(pendingKey);
|
|
4490
|
+
throw error;
|
|
4491
|
+
}
|
|
4492
|
+
} else {
|
|
4493
|
+
txHash = await this.submitTransaction(state, chainId, {
|
|
4494
|
+
from: (0, import_viem10.getAddress)(state.walletAddress),
|
|
4495
|
+
to: before.agentWallet,
|
|
4496
|
+
data,
|
|
4497
|
+
value: "0",
|
|
4498
|
+
chainId
|
|
4499
|
+
});
|
|
4500
|
+
}
|
|
4501
|
+
const status = await this.getWalletStatus(state, chainId, asset);
|
|
4502
|
+
if (!status?.verified || status.version !== "v2") {
|
|
4503
|
+
throw new OwneyError(
|
|
4504
|
+
"WITHDRAW_FAILED",
|
|
4505
|
+
"Yieldseeker wallet upgrade was not confirmed as V2.",
|
|
4506
|
+
{ txHash, version: status?.version ?? "missing" },
|
|
4507
|
+
this.id
|
|
4508
|
+
);
|
|
4509
|
+
}
|
|
4510
|
+
if (gasMode === "sponsored" && typeof window !== "undefined")
|
|
4511
|
+
window.localStorage.removeItem(`owney.yieldseeker.upgrade:${state.walletAddress.toLowerCase()}:${before.agentWallet.toLowerCase()}`);
|
|
4512
|
+
return { txHash, status };
|
|
4513
|
+
}
|
|
3851
4514
|
async disconnect() {
|
|
4515
|
+
this.withdrawalVersionCache.clear();
|
|
3852
4516
|
this.readGeneration += 1;
|
|
3853
4517
|
this.auth.clear();
|
|
3854
4518
|
for (const key2 of this.users.keys()) {
|
|
@@ -3919,12 +4583,12 @@ var YieldseekerAgent = class {
|
|
|
3919
4583
|
receipt = await this.waitForReceipt(state, chainId, txHash);
|
|
3920
4584
|
} else {
|
|
3921
4585
|
txHash = await this.submitTransaction(state, chainId, {
|
|
3922
|
-
from: (0,
|
|
4586
|
+
from: (0, import_viem10.getAddress)(state.walletAddress),
|
|
3923
4587
|
to: YIELDSEEKER_ASSET_METADATA[asset].address,
|
|
3924
|
-
data: (0,
|
|
3925
|
-
abi:
|
|
4588
|
+
data: (0, import_viem10.encodeFunctionData)({
|
|
4589
|
+
abi: import_viem10.erc20Abi,
|
|
3926
4590
|
functionName: "transfer",
|
|
3927
|
-
args: [(0,
|
|
4591
|
+
args: [(0, import_viem10.getAddress)(context.wallet.walletAddress), BigInt(amount)]
|
|
3928
4592
|
}),
|
|
3929
4593
|
value: "0",
|
|
3930
4594
|
chainId
|
|
@@ -3935,12 +4599,12 @@ var YieldseekerAgent = class {
|
|
|
3935
4599
|
if (this.readGeneration === generation) {
|
|
3936
4600
|
void this.refreshSnapshotAfterMovement(state, chainId, context, "deposit", movement);
|
|
3937
4601
|
}
|
|
3938
|
-
const
|
|
3939
|
-
const evidence = receipt ? inspectFundingReceipt(receipt,
|
|
4602
|
+
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" };
|
|
4603
|
+
const evidence = receipt ? inspectFundingReceipt(receipt, base6, YIELDSEEKER_ASSET_METADATA[asset].address, "deposit") : base6;
|
|
3940
4604
|
notifyFunding(onProgress, evidence);
|
|
3941
4605
|
return { txHash, smartWallet: context.wallet.walletAddress, amount, evidence };
|
|
3942
4606
|
}
|
|
3943
|
-
async withdraw(state, chainId, asset, amount, onProgress) {
|
|
4607
|
+
async withdraw(state, chainId, asset, amount, onProgress, gasMode = "auto") {
|
|
3944
4608
|
let ownerTransferAttempted = false;
|
|
3945
4609
|
let evidence = {
|
|
3946
4610
|
agentId: this.id,
|
|
@@ -3958,14 +4622,20 @@ var YieldseekerAgent = class {
|
|
|
3958
4622
|
notifyFunding(onProgress, evidence);
|
|
3959
4623
|
}, () => {
|
|
3960
4624
|
ownerTransferAttempted = true;
|
|
3961
|
-
});
|
|
4625
|
+
}, gasMode);
|
|
3962
4626
|
} catch (error) {
|
|
3963
|
-
if (
|
|
3964
|
-
|
|
4627
|
+
if (error instanceof OwneyError && error.code === "SPONSOR_REQUEST_FAILED") this.withdrawalVersionCache.clear();
|
|
4628
|
+
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)))
|
|
4629
|
+
notifyFunding(onProgress, {
|
|
4630
|
+
...evidence,
|
|
4631
|
+
...error instanceof OwneyError && error.code === "SPONSOR_REQUEST_FAILED" && error.details?.safeToFallback === true ? { userOpHash: void 0, callsId: void 0 } : {},
|
|
4632
|
+
transfer: "failed",
|
|
4633
|
+
delivery: "failed"
|
|
4634
|
+
});
|
|
3965
4635
|
throw error;
|
|
3966
4636
|
}
|
|
3967
4637
|
}
|
|
3968
|
-
async withdrawInternal(state, chainId, asset, amount, onProgress, onOwnerTransferAttempted) {
|
|
4638
|
+
async withdrawInternal(state, chainId, asset, amount, onProgress, onOwnerTransferAttempted, gasMode = "auto") {
|
|
3969
4639
|
this.assertChain(chainId);
|
|
3970
4640
|
this.assertAsset(asset);
|
|
3971
4641
|
if (amount !== void 0 && BigInt(amount) <= 0n) {
|
|
@@ -3985,10 +4655,32 @@ var YieldseekerAgent = class {
|
|
|
3985
4655
|
this.id
|
|
3986
4656
|
);
|
|
3987
4657
|
}
|
|
4658
|
+
let sponsor = false;
|
|
4659
|
+
if (gasMode !== "paid") {
|
|
4660
|
+
const status = await this.getWalletStatus(state, chainId, asset, true).catch(() => {
|
|
4661
|
+
if (gasMode === "sponsored")
|
|
4662
|
+
throw new OwneyError(
|
|
4663
|
+
"SPONSOR_REQUEST_FAILED",
|
|
4664
|
+
"Could not verify the Yieldseeker wallet for sponsorship.",
|
|
4665
|
+
{ safeToFallback: true, version: "unknown" },
|
|
4666
|
+
this.id
|
|
4667
|
+
);
|
|
4668
|
+
return null;
|
|
4669
|
+
});
|
|
4670
|
+
sponsor = !!status?.verified && status.version === "v2";
|
|
4671
|
+
if (gasMode === "sponsored" && !sponsor)
|
|
4672
|
+
throw new OwneyError(
|
|
4673
|
+
"SPONSOR_REQUEST_FAILED",
|
|
4674
|
+
"Only a verified Yieldseeker V2 Agent Wallet can use sponsored withdrawals.",
|
|
4675
|
+
{ safeToFallback: true, version: status?.version ?? "unknown" },
|
|
4676
|
+
this.id
|
|
4677
|
+
);
|
|
4678
|
+
}
|
|
3988
4679
|
const generation = this.readGeneration;
|
|
3989
4680
|
let confirmedMovement = false;
|
|
3990
4681
|
let settlement = null;
|
|
3991
4682
|
try {
|
|
4683
|
+
if (amount === void 0) this.advancePortfolioVersion(this.contextKey(state, chainId, asset));
|
|
3992
4684
|
const portfolio = await this.loadPortfolioContext(
|
|
3993
4685
|
state,
|
|
3994
4686
|
chainId,
|
|
@@ -3998,15 +4690,43 @@ var YieldseekerAgent = class {
|
|
|
3998
4690
|
const readIdle = async () => {
|
|
3999
4691
|
const balance = await withPaidRpcDiagnostics(() => this.getReceiptClient().readContract({
|
|
4000
4692
|
address: metadata.address,
|
|
4001
|
-
abi:
|
|
4693
|
+
abi: import_viem10.erc20Abi,
|
|
4002
4694
|
functionName: "balanceOf",
|
|
4003
|
-
args: [(0,
|
|
4695
|
+
args: [(0, import_viem10.getAddress)(context.wallet.walletAddress)]
|
|
4004
4696
|
}), chainId, "eth_call", this.id);
|
|
4005
4697
|
this.assertSession(generation, chainId, asset);
|
|
4006
4698
|
return balance;
|
|
4007
4699
|
};
|
|
4008
4700
|
const idle = await readIdle();
|
|
4009
|
-
|
|
4701
|
+
let positions = portfolio.positions;
|
|
4702
|
+
let positionsStatus = "empty";
|
|
4703
|
+
const validatePositions = (values) => {
|
|
4704
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4705
|
+
for (const value of values) {
|
|
4706
|
+
const address = value?.yieldOption?.address;
|
|
4707
|
+
if (typeof address !== "string" || !(0, import_viem10.isAddress)(address) || seen.has(address.toLowerCase()) || typeof value.assetsRaw !== "string" || !/^\d+$/.test(value.assetsRaw) || typeof value.withdrawableAssetsRaw !== "string" || !/^\d+$/.test(value.withdrawableAssetsRaw))
|
|
4708
|
+
throw this.invalidResponse("yield positions");
|
|
4709
|
+
seen.add(address.toLowerCase());
|
|
4710
|
+
}
|
|
4711
|
+
return values;
|
|
4712
|
+
};
|
|
4713
|
+
const hasPositions = (values) => values.some((position2) => BigInt(position2.assetsRaw) > 0n || BigInt(position2.withdrawableAssetsRaw) > 0n);
|
|
4714
|
+
const refreshPositions = async () => {
|
|
4715
|
+
this.assertSession(generation, chainId, asset);
|
|
4716
|
+
const response = await this.walletRequest(
|
|
4717
|
+
state,
|
|
4718
|
+
chainId,
|
|
4719
|
+
this.agentPath(context, "yield-positions")
|
|
4720
|
+
);
|
|
4721
|
+
this.assertSession(generation, chainId, asset);
|
|
4722
|
+
if (!Array.isArray(response?.yieldPositions)) throw this.invalidResponse("yield positions");
|
|
4723
|
+
return validatePositions(response.yieldPositions);
|
|
4724
|
+
};
|
|
4725
|
+
if (amount === void 0) {
|
|
4726
|
+
validatePositions(positions);
|
|
4727
|
+
positionsStatus = hasPositions(positions) ? "remaining" : "empty";
|
|
4728
|
+
}
|
|
4729
|
+
const deployed = positions.reduce(
|
|
4010
4730
|
(total, position2) => total + BigInt(position2.withdrawableAssetsRaw),
|
|
4011
4731
|
0n
|
|
4012
4732
|
);
|
|
@@ -4014,6 +4734,13 @@ var YieldseekerAgent = class {
|
|
|
4014
4734
|
const requested = amount === void 0 ? totalAvailable : BigInt(amount);
|
|
4015
4735
|
if (requested === 0n) {
|
|
4016
4736
|
this.invalidateFundingRead(state, chainId, asset);
|
|
4737
|
+
if (amount === void 0 && positionsStatus === "remaining")
|
|
4738
|
+
throw new OwneyError(
|
|
4739
|
+
"WITHDRAW_FAILED",
|
|
4740
|
+
"Yieldseeker vault funds are not currently withdrawable.",
|
|
4741
|
+
{ asset, remainingPositions: positions.map((position2) => position2.yieldOption.address) },
|
|
4742
|
+
this.id
|
|
4743
|
+
);
|
|
4017
4744
|
throw new OwneyError(
|
|
4018
4745
|
"WITHDRAW_INSUFFICIENT_BALANCE",
|
|
4019
4746
|
"No Yieldseeker funds are available to withdraw.",
|
|
@@ -4034,40 +4761,74 @@ var YieldseekerAgent = class {
|
|
|
4034
4761
|
);
|
|
4035
4762
|
}
|
|
4036
4763
|
let remaining = requested > idle ? requested - idle : 0n;
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
|
|
4040
|
-
if (available <= 0n) continue;
|
|
4041
|
-
const assetsRaw = available < remaining ? available : remaining;
|
|
4764
|
+
let grossUnwound = 0n;
|
|
4765
|
+
const unwind = async (position2, assetsRaw) => {
|
|
4766
|
+
this.assertSession(generation, chainId, asset);
|
|
4042
4767
|
const response = await this.walletRequest(
|
|
4043
4768
|
state,
|
|
4044
4769
|
chainId,
|
|
4045
4770
|
this.agentPath(context, "withdraw-from-position"),
|
|
4046
4771
|
{
|
|
4047
4772
|
method: "POST",
|
|
4048
|
-
body: {
|
|
4049
|
-
chainId,
|
|
4050
|
-
vaultAddress: position2.yieldOption.address,
|
|
4051
|
-
assetsRaw: assetsRaw.toString()
|
|
4052
|
-
}
|
|
4773
|
+
body: { chainId, vaultAddress: position2.yieldOption.address, assetsRaw: assetsRaw.toString() }
|
|
4053
4774
|
}
|
|
4054
4775
|
);
|
|
4055
|
-
if (!this.isTransactionHash(response?.transactionHash))
|
|
4056
|
-
throw this.invalidResponse("position withdrawal");
|
|
4057
|
-
}
|
|
4776
|
+
if (!this.isTransactionHash(response?.transactionHash)) throw this.invalidResponse("position withdrawal");
|
|
4058
4777
|
await this.waitForReceipt(state, chainId, response.transactionHash);
|
|
4059
4778
|
confirmedMovement = true;
|
|
4060
|
-
|
|
4779
|
+
this.assertSession(generation, chainId, asset);
|
|
4780
|
+
grossUnwound += assetsRaw;
|
|
4781
|
+
};
|
|
4782
|
+
if (amount === void 0) {
|
|
4783
|
+
for (let sweep = 0; sweep < YIELDSEEKER_MAX_WITHDRAW_SWEEPS && hasPositions(positions); sweep++) {
|
|
4784
|
+
const before = new Map(positions.map((position2) => [position2.yieldOption.address.toLowerCase(), BigInt(position2.assetsRaw)]));
|
|
4785
|
+
let unwound = false;
|
|
4786
|
+
for (const position2 of positions) {
|
|
4787
|
+
const available = BigInt(position2.withdrawableAssetsRaw);
|
|
4788
|
+
if (available <= 0n) continue;
|
|
4789
|
+
await unwind(position2, available);
|
|
4790
|
+
unwound = true;
|
|
4791
|
+
}
|
|
4792
|
+
if (!unwound) break;
|
|
4793
|
+
try {
|
|
4794
|
+
positions = await refreshPositions();
|
|
4795
|
+
positionsStatus = hasPositions(positions) ? "remaining" : "empty";
|
|
4796
|
+
} catch {
|
|
4797
|
+
this.assertSession(generation, chainId, asset);
|
|
4798
|
+
positionsStatus = "unavailable";
|
|
4799
|
+
break;
|
|
4800
|
+
}
|
|
4801
|
+
if (positions.some((position2) => BigInt(position2.assetsRaw) > 0n && before.has(position2.yieldOption.address.toLowerCase()) && BigInt(position2.assetsRaw) >= before.get(position2.yieldOption.address.toLowerCase()))) break;
|
|
4802
|
+
}
|
|
4803
|
+
} else {
|
|
4804
|
+
for (const position2 of positions) {
|
|
4805
|
+
if (remaining === 0n) break;
|
|
4806
|
+
const available = BigInt(position2.withdrawableAssetsRaw);
|
|
4807
|
+
if (available <= 0n) continue;
|
|
4808
|
+
const assetsRaw = available < remaining ? available : remaining;
|
|
4809
|
+
await unwind(position2, assetsRaw);
|
|
4810
|
+
remaining -= assetsRaw;
|
|
4811
|
+
}
|
|
4061
4812
|
}
|
|
4062
|
-
if (remaining > 0n) {
|
|
4813
|
+
if (amount !== void 0 && remaining > 0n) {
|
|
4063
4814
|
throw this.invalidResponse("yield positions", {
|
|
4064
4815
|
reason: "Withdrawable positions could not cover the request.",
|
|
4065
4816
|
remaining: remaining.toString()
|
|
4066
4817
|
});
|
|
4067
4818
|
}
|
|
4068
4819
|
const availableForOwner = confirmedMovement ? await readIdle() : idle;
|
|
4069
|
-
|
|
4820
|
+
const feeRate = portfolio.snapshot.feeRateBps;
|
|
4821
|
+
const maxFee = confirmedMovement && Number.isInteger(feeRate) && feeRate >= 0 && feeRate <= 1e3 ? (grossUnwound * BigInt(feeRate) + 9999n) / 10000n : 0n;
|
|
4822
|
+
const shortfall = availableForOwner < requested ? requested - availableForOwner : 0n;
|
|
4823
|
+
if (availableForOwner === 0n || amount !== void 0 && shortfall > maxFee) {
|
|
4070
4824
|
this.invalidateFundingRead(state, chainId, asset);
|
|
4825
|
+
if (amount === void 0 && positionsStatus !== "empty")
|
|
4826
|
+
throw new OwneyError(
|
|
4827
|
+
"WITHDRAW_FAILED",
|
|
4828
|
+
"Yieldseeker vault funds could not be cleared for the owner transfer.",
|
|
4829
|
+
{ asset, positionsStatus },
|
|
4830
|
+
this.id
|
|
4831
|
+
);
|
|
4071
4832
|
throw new OwneyError(
|
|
4072
4833
|
"WITHDRAW_INSUFFICIENT_BALANCE",
|
|
4073
4834
|
"Yieldseeker funds are not available for the owner transfer.",
|
|
@@ -4075,33 +4836,80 @@ var YieldseekerAgent = class {
|
|
|
4075
4836
|
this.id
|
|
4076
4837
|
);
|
|
4077
4838
|
}
|
|
4078
|
-
const payout = amount === void 0 ? availableForOwner : requested;
|
|
4839
|
+
const payout = amount === void 0 || availableForOwner < requested ? availableForOwner : requested;
|
|
4079
4840
|
const plannedMovement = this.snapshotMovement(state, chainId, context, -payout);
|
|
4080
|
-
const account = (0,
|
|
4841
|
+
const account = (0, import_viem10.getAddress)(state.walletAddress);
|
|
4081
4842
|
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;
|
|
4843
|
+
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" };
|
|
4844
|
+
const data = amount === void 0 ? (0, import_viem10.encodeFunctionData)({
|
|
4845
|
+
abi: YIELDSEEKER_AGENT_WALLET_ABI,
|
|
4846
|
+
functionName: "withdrawAllAssetToUser",
|
|
4847
|
+
args: [account, metadata.address]
|
|
4848
|
+
}) : (0, import_viem10.encodeFunctionData)({
|
|
4849
|
+
abi: YIELDSEEKER_AGENT_WALLET_ABI,
|
|
4850
|
+
functionName: "withdrawAssetToUser",
|
|
4851
|
+
args: [account, metadata.address, payout]
|
|
4100
4852
|
});
|
|
4853
|
+
onOwnerTransferAttempted?.();
|
|
4854
|
+
let txHash;
|
|
4855
|
+
if (sponsor) {
|
|
4856
|
+
const submitted = await submitYieldseekerSponsoredWithdrawal({
|
|
4857
|
+
state,
|
|
4858
|
+
client: this.getReceiptClient(),
|
|
4859
|
+
apiKey: this.owneyApiKey,
|
|
4860
|
+
routingApiBaseUrl: this.routingApiBaseUrl,
|
|
4861
|
+
yieldseekerSignature: await this.auth.getToken(state, chainId),
|
|
4862
|
+
userId: context.user.userId,
|
|
4863
|
+
agentId: context.agent.agentId,
|
|
4864
|
+
agentWallet: (0, import_viem10.getAddress)(context.wallet.walletAddress),
|
|
4865
|
+
asset: metadata.address,
|
|
4866
|
+
callData: data,
|
|
4867
|
+
onPending: (pending) => notifyFunding(onProgress, { ...base6, ...pending })
|
|
4868
|
+
});
|
|
4869
|
+
txHash = submitted.txHash;
|
|
4870
|
+
receipt = submitted.receipt;
|
|
4871
|
+
} else {
|
|
4872
|
+
txHash = await this.submitTransaction(state, chainId, {
|
|
4873
|
+
from: account,
|
|
4874
|
+
to: (0, import_viem10.getAddress)(context.wallet.walletAddress),
|
|
4875
|
+
data,
|
|
4876
|
+
value: "0",
|
|
4877
|
+
chainId
|
|
4878
|
+
}, (hash) => notifyFunding(onProgress, { ...base6, txHash: hash }), (value) => {
|
|
4879
|
+
receipt = value;
|
|
4880
|
+
});
|
|
4881
|
+
}
|
|
4101
4882
|
confirmedMovement = true;
|
|
4102
4883
|
settlement = plannedMovement;
|
|
4103
|
-
const evidence = receipt ? inspectFundingReceipt(receipt, { ...
|
|
4884
|
+
const evidence = receipt ? inspectFundingReceipt(receipt, { ...base6, txHash }, metadata.address, "withdraw") : { ...base6, txHash, confirmedAmount: payout.toString(), transfer: "confirmed", delivery: "confirmed" };
|
|
4104
4885
|
notifyFunding(onProgress, evidence);
|
|
4886
|
+
if (amount === void 0) {
|
|
4887
|
+
try {
|
|
4888
|
+
positions = await refreshPositions();
|
|
4889
|
+
positionsStatus = hasPositions(positions) ? "remaining" : "empty";
|
|
4890
|
+
} catch {
|
|
4891
|
+
positionsStatus = "unavailable";
|
|
4892
|
+
}
|
|
4893
|
+
if (positionsStatus !== "empty") {
|
|
4894
|
+
const result = { txHash, type: "partial", amount: evidence.confirmedAmount ?? payout.toString(), evidence };
|
|
4895
|
+
throw new OwneyError(
|
|
4896
|
+
"WITHDRAW_PARTIAL_FAILURE",
|
|
4897
|
+
"Yieldseeker MAX could not confirm that all vault positions were cleared.",
|
|
4898
|
+
{
|
|
4899
|
+
reason: "YIELDSEEKER_MAX_INCOMPLETE",
|
|
4900
|
+
asset,
|
|
4901
|
+
positionsStatus,
|
|
4902
|
+
remainingPositions: positionsStatus === "remaining" ? positions.map((position2) => ({
|
|
4903
|
+
vaultAddress: position2.yieldOption.address,
|
|
4904
|
+
sharesRaw: position2.assetsRaw,
|
|
4905
|
+
withdrawableAmountRaw: position2.withdrawableAssetsRaw
|
|
4906
|
+
})) : void 0,
|
|
4907
|
+
partialResults: { [this.id]: result }
|
|
4908
|
+
},
|
|
4909
|
+
this.id
|
|
4910
|
+
);
|
|
4911
|
+
}
|
|
4912
|
+
}
|
|
4105
4913
|
if (evidence.transfer === "failed" && evidence.confirmedAmount === "0")
|
|
4106
4914
|
throw new OwneyError(
|
|
4107
4915
|
"WITHDRAW_INSUFFICIENT_BALANCE",
|
|
@@ -4186,7 +4994,7 @@ var YieldseekerAgent = class {
|
|
|
4186
4994
|
);
|
|
4187
4995
|
const vaultAddresses = new Set(
|
|
4188
4996
|
catalog.flat().filter(
|
|
4189
|
-
(yieldOption) => yieldOption.chainId === chainId && (0,
|
|
4997
|
+
(yieldOption) => yieldOption.chainId === chainId && (0, import_viem10.isAddress)(yieldOption.address)
|
|
4190
4998
|
).map((yieldOption) => yieldOption.address.toLowerCase())
|
|
4191
4999
|
);
|
|
4192
5000
|
return mapYieldseekerHistory(contexts, {
|
|
@@ -4313,7 +5121,7 @@ var YieldseekerAgent = class {
|
|
|
4313
5121
|
`/users/${user.userId}/agents/${agent.agentId}/wallet`
|
|
4314
5122
|
).then((walletResponse) => {
|
|
4315
5123
|
this.assertSession(generation, chainId, asset);
|
|
4316
|
-
if (!walletResponse?.agentWallet || !(0,
|
|
5124
|
+
if (!walletResponse?.agentWallet || !(0, import_viem10.isAddress)(walletResponse.agentWallet.walletAddress)) {
|
|
4317
5125
|
throw this.invalidResponse("agent wallet");
|
|
4318
5126
|
}
|
|
4319
5127
|
const context = {
|
|
@@ -4343,7 +5151,7 @@ var YieldseekerAgent = class {
|
|
|
4343
5151
|
this.users.set(key2, persisted);
|
|
4344
5152
|
return persisted;
|
|
4345
5153
|
}
|
|
4346
|
-
const walletAddress = (0,
|
|
5154
|
+
const walletAddress = (0, import_viem10.getAddress)(state.walletAddress);
|
|
4347
5155
|
const generation = this.readGeneration;
|
|
4348
5156
|
let user = null;
|
|
4349
5157
|
try {
|
|
@@ -4726,7 +5534,7 @@ var YieldseekerAgent = class {
|
|
|
4726
5534
|
this.agentPath(context, "deploy"),
|
|
4727
5535
|
{ method: "POST", body: {} }
|
|
4728
5536
|
);
|
|
4729
|
-
if (!deployed?.agentWallet || !(0,
|
|
5537
|
+
if (!deployed?.agentWallet || !(0, import_viem10.isAddress)(deployed.agentWallet.walletAddress) || deployed.agentWallet.walletAddress.toLowerCase() !== walletAddress) {
|
|
4730
5538
|
throw this.invalidResponse("agent deployment", {
|
|
4731
5539
|
reason: "Deploy did not return the expected Agent Wallet."
|
|
4732
5540
|
});
|
|
@@ -4834,15 +5642,15 @@ var YieldseekerAgent = class {
|
|
|
4834
5642
|
return hash2;
|
|
4835
5643
|
}
|
|
4836
5644
|
this.assertTransaction(transaction, state, chainId);
|
|
4837
|
-
const account = (0,
|
|
4838
|
-
const walletClient = (0,
|
|
5645
|
+
const account = (0, import_viem10.getAddress)(state.walletAddress);
|
|
5646
|
+
const walletClient = (0, import_viem10.createWalletClient)({
|
|
4839
5647
|
account,
|
|
4840
|
-
chain:
|
|
4841
|
-
transport: (0,
|
|
5648
|
+
chain: import_chains4.base,
|
|
5649
|
+
transport: (0, import_viem10.custom)(state.provider)
|
|
4842
5650
|
});
|
|
4843
|
-
const walletChainClient = (0,
|
|
4844
|
-
chain:
|
|
4845
|
-
transport: (0,
|
|
5651
|
+
const walletChainClient = (0, import_viem10.createPublicClient)({
|
|
5652
|
+
chain: import_chains4.base,
|
|
5653
|
+
transport: (0, import_viem10.custom)(state.provider)
|
|
4846
5654
|
});
|
|
4847
5655
|
await ensureWalletOnChain(
|
|
4848
5656
|
walletChainClient,
|
|
@@ -4851,8 +5659,8 @@ var YieldseekerAgent = class {
|
|
|
4851
5659
|
);
|
|
4852
5660
|
const hash = await walletClient.sendTransaction({
|
|
4853
5661
|
account,
|
|
4854
|
-
chain:
|
|
4855
|
-
to: (0,
|
|
5662
|
+
chain: import_chains4.base,
|
|
5663
|
+
to: (0, import_viem10.getAddress)(transaction.to),
|
|
4856
5664
|
data: transaction.data,
|
|
4857
5665
|
value: BigInt(transaction.value)
|
|
4858
5666
|
});
|
|
@@ -4902,12 +5710,12 @@ var YieldseekerAgent = class {
|
|
|
4902
5710
|
return receipt;
|
|
4903
5711
|
}
|
|
4904
5712
|
assertTransaction(transaction, state, chainId) {
|
|
4905
|
-
if (!transaction || typeof transaction.from !== "string" || !(0,
|
|
5713
|
+
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
5714
|
throw this.invalidResponse("transaction");
|
|
4907
5715
|
}
|
|
4908
5716
|
}
|
|
4909
5717
|
assertAgent(agent) {
|
|
4910
|
-
if (typeof agent.agentId !== "string" || typeof agent.assetAddress !== "string" || !(0,
|
|
5718
|
+
if (typeof agent.agentId !== "string" || typeof agent.assetAddress !== "string" || !(0, import_viem10.isAddress)(agent.assetAddress) || agent.chainId !== 8453) {
|
|
4911
5719
|
throw this.invalidResponse("agent");
|
|
4912
5720
|
}
|
|
4913
5721
|
}
|
|
@@ -4964,6 +5772,7 @@ var YieldseekerAgent = class {
|
|
|
4964
5772
|
|
|
4965
5773
|
// src/lib/routing-api.ts
|
|
4966
5774
|
var ROUTING_API_BASE_URL2 = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
5775
|
+
var getRoutingApiBaseUrl = (override) => override ?? ROUTING_API_BASE_URL2;
|
|
4967
5776
|
async function fetchOrgAgentConfig(apiKey, baseUrl = ROUTING_API_BASE_URL2) {
|
|
4968
5777
|
const url = `${baseUrl}/api/v1/agent/org-config`;
|
|
4969
5778
|
try {
|
|
@@ -5060,7 +5869,7 @@ async function withFailureReporting(apiKey, agentType, fn, baseUrl) {
|
|
|
5060
5869
|
}
|
|
5061
5870
|
|
|
5062
5871
|
// src/lib/helpers/withdraw-helper.ts
|
|
5063
|
-
var
|
|
5872
|
+
var import_viem11 = require("viem");
|
|
5064
5873
|
function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
|
|
5065
5874
|
const target = asset.toUpperCase();
|
|
5066
5875
|
return agents.map((agent) => {
|
|
@@ -5068,7 +5877,7 @@ function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decima
|
|
|
5068
5877
|
const tokenBalance = agentBalance?.tokens.find(
|
|
5069
5878
|
(t) => t.chainId === chainId && t.asset.toUpperCase() === target
|
|
5070
5879
|
);
|
|
5071
|
-
let balance = tokenBalance ? (0,
|
|
5880
|
+
let balance = tokenBalance ? (0, import_viem11.parseUnits)(tokenBalance.amount, decimals) : 0n;
|
|
5072
5881
|
if (agent.balanceComposition === "tokens-plus-positions") {
|
|
5073
5882
|
const chainNameById = {
|
|
5074
5883
|
1: "ETHEREUM",
|
|
@@ -5080,14 +5889,14 @@ function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decima
|
|
|
5080
5889
|
const positionChain = position2.chain.trim().toUpperCase();
|
|
5081
5890
|
const matchesChain = positionChain === String(chainId) || targetChain !== void 0 && positionChain === targetChain;
|
|
5082
5891
|
if (!matchesChain || position2.asset.toUpperCase() !== target) continue;
|
|
5083
|
-
balance += position2.withdrawableAmountRaw !== void 0 ? BigInt(position2.withdrawableAmountRaw) : (0,
|
|
5892
|
+
balance += position2.withdrawableAmountRaw !== void 0 ? BigInt(position2.withdrawableAmountRaw) : (0, import_viem11.parseUnits)(position2.amount, decimals);
|
|
5084
5893
|
}
|
|
5085
5894
|
}
|
|
5086
5895
|
const assetTotal = agentBalance?.assetBalances?.find(
|
|
5087
5896
|
(t) => t.chainId === chainId && t.asset.toUpperCase() === target
|
|
5088
5897
|
);
|
|
5089
5898
|
if (assetTotal) {
|
|
5090
|
-
const total = (0,
|
|
5899
|
+
const total = (0, import_viem11.parseUnits)(assetTotal.amount, decimals);
|
|
5091
5900
|
if (total < balance) balance = total > 0n ? total : 0n;
|
|
5092
5901
|
}
|
|
5093
5902
|
return { agent, balance };
|
|
@@ -5246,14 +6055,14 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
|
|
|
5246
6055
|
}
|
|
5247
6056
|
|
|
5248
6057
|
// src/client.ts
|
|
5249
|
-
var
|
|
5250
|
-
var
|
|
6058
|
+
var import_viem15 = require("viem");
|
|
6059
|
+
var import_chains5 = require("viem/chains");
|
|
5251
6060
|
|
|
5252
6061
|
// src/lib/sponsored-token-batch.ts
|
|
5253
|
-
var
|
|
6062
|
+
var import_viem13 = require("viem");
|
|
5254
6063
|
|
|
5255
6064
|
// src/lib/permit2-batch.ts
|
|
5256
|
-
var
|
|
6065
|
+
var import_viem12 = require("viem");
|
|
5257
6066
|
var BATCH_PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
5258
6067
|
var BASE_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
|
|
5259
6068
|
var ERC2612_PERMIT_TYPES = {
|
|
@@ -5265,7 +6074,7 @@ var ERC2612_PERMIT_TYPES = {
|
|
|
5265
6074
|
{ name: "deadline", type: "uint256" }
|
|
5266
6075
|
]
|
|
5267
6076
|
};
|
|
5268
|
-
var ERC2612_READ_ABI = (0,
|
|
6077
|
+
var ERC2612_READ_ABI = (0, import_viem12.parseAbi)([
|
|
5269
6078
|
"function name() view returns (string)",
|
|
5270
6079
|
"function version() view returns (string)",
|
|
5271
6080
|
"function nonces(address owner) view returns (uint256)"
|
|
@@ -5303,7 +6112,7 @@ var PERMIT_BATCH_TYPES = {
|
|
|
5303
6112
|
{ name: "amount", type: "uint256" }
|
|
5304
6113
|
]
|
|
5305
6114
|
};
|
|
5306
|
-
var PERMIT2_BATCH_ABI = (0,
|
|
6115
|
+
var PERMIT2_BATCH_ABI = (0, import_viem12.parseAbi)([
|
|
5307
6116
|
"struct TokenPermissions { address token; uint256 amount; }",
|
|
5308
6117
|
"struct PermitBatchTransferFrom { TokenPermissions[] permitted; uint256 nonce; uint256 deadline; }",
|
|
5309
6118
|
"struct SignatureTransferDetails { address to; uint256 requestedAmount; }",
|
|
@@ -5362,7 +6171,7 @@ function clear(key2) {
|
|
|
5362
6171
|
else window.localStorage.removeItem(key2);
|
|
5363
6172
|
}
|
|
5364
6173
|
function sponsorTokenBatch(i) {
|
|
5365
|
-
const key2 = `owney.token-batch.v1:${(0,
|
|
6174
|
+
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()}`;
|
|
5366
6175
|
const plan = planOf(i.transfers);
|
|
5367
6176
|
const active = inflight.get(key2);
|
|
5368
6177
|
if (active) {
|
|
@@ -5393,7 +6202,7 @@ async function execute(i, key2, plan) {
|
|
|
5393
6202
|
baseUrl: i.baseUrl,
|
|
5394
6203
|
body
|
|
5395
6204
|
});
|
|
5396
|
-
if (!preparedPermit.serializedPermitTransaction || !preparedPermit.permitTxHash || (0,
|
|
6205
|
+
if (!preparedPermit.serializedPermitTransaction || !preparedPermit.permitTxHash || (0, import_viem13.keccak256)(preparedPermit.serializedPermitTransaction) !== preparedPermit.permitTxHash)
|
|
5397
6206
|
throw new Error(
|
|
5398
6207
|
"Sponsorship API did not return a valid prepared permit transaction."
|
|
5399
6208
|
);
|
|
@@ -5409,7 +6218,7 @@ async function execute(i, key2, plan) {
|
|
|
5409
6218
|
baseUrl: i.baseUrl,
|
|
5410
6219
|
body
|
|
5411
6220
|
});
|
|
5412
|
-
if (!prepared.serializedTransaction || (0,
|
|
6221
|
+
if (!prepared.serializedTransaction || (0, import_viem13.keccak256)(prepared.serializedTransaction) !== prepared.txHash)
|
|
5413
6222
|
throw new Error(
|
|
5414
6223
|
"Sponsorship API did not return a valid prepared transaction."
|
|
5415
6224
|
);
|
|
@@ -5420,7 +6229,7 @@ async function execute(i, key2, plan) {
|
|
|
5420
6229
|
save(key2, body);
|
|
5421
6230
|
}
|
|
5422
6231
|
try {
|
|
5423
|
-
i.onSubmitted?.((0,
|
|
6232
|
+
i.onSubmitted?.((0, import_viem13.keccak256)(body.serializedTransaction));
|
|
5424
6233
|
} catch {
|
|
5425
6234
|
}
|
|
5426
6235
|
const result = await postSponsorBatchTransfer({
|
|
@@ -5428,7 +6237,7 @@ async function execute(i, key2, plan) {
|
|
|
5428
6237
|
baseUrl: i.baseUrl,
|
|
5429
6238
|
body
|
|
5430
6239
|
});
|
|
5431
|
-
if (result.txHash !== (0,
|
|
6240
|
+
if (result.txHash !== (0, import_viem13.keccak256)(body.serializedTransaction))
|
|
5432
6241
|
throw new Error(
|
|
5433
6242
|
"Sponsorship receipt does not match the pending transaction."
|
|
5434
6243
|
);
|
|
@@ -5443,7 +6252,7 @@ async function execute(i, key2, plan) {
|
|
|
5443
6252
|
const saved = read(key2);
|
|
5444
6253
|
if (saved) {
|
|
5445
6254
|
const previous = JSON.parse(saved);
|
|
5446
|
-
if (previous.chainId !== i.chainId || !(0,
|
|
6255
|
+
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)
|
|
5447
6256
|
throw new Error(
|
|
5448
6257
|
"Retry the previous token deposit and agent split first to reconcile its status."
|
|
5449
6258
|
);
|
|
@@ -5460,7 +6269,7 @@ async function execute(i, key2, plan) {
|
|
|
5460
6269
|
"DEPOSIT_INSUFFICIENT_BALANCE",
|
|
5461
6270
|
"Insufficient token balance for this deposit."
|
|
5462
6271
|
);
|
|
5463
|
-
if (allowance < total && (i.chainId !== 8453 || !(0,
|
|
6272
|
+
if (allowance < total && (i.chainId !== 8453 || !(0, import_viem13.isAddressEqual)(i.token, BASE_USDC_ADDRESS)))
|
|
5464
6273
|
throw new OwneyError(
|
|
5465
6274
|
"PERMIT2_APPROVAL_REQUIRED",
|
|
5466
6275
|
"token deposits need a one-time Permit2 approval."
|
|
@@ -5638,7 +6447,7 @@ async function runAgentDepositBatch(chainId, legs, transfer) {
|
|
|
5638
6447
|
}
|
|
5639
6448
|
|
|
5640
6449
|
// src/lib/sponsored-calls-deposit.ts
|
|
5641
|
-
var
|
|
6450
|
+
var import_viem14 = require("viem");
|
|
5642
6451
|
var DEFAULT_POLL_INTERVAL_MS = 1500;
|
|
5643
6452
|
var DEFAULT_MAX_POLLS = 30;
|
|
5644
6453
|
async function paymasterSupported(provider, owner, chainId) {
|
|
@@ -5646,7 +6455,7 @@ async function paymasterSupported(provider, owner, chainId) {
|
|
|
5646
6455
|
method: "wallet_getCapabilities",
|
|
5647
6456
|
params: [owner]
|
|
5648
6457
|
});
|
|
5649
|
-
const forChain = caps?.[(0,
|
|
6458
|
+
const forChain = caps?.[(0, import_viem14.toHex)(chainId)] ?? caps?.[String(chainId)];
|
|
5650
6459
|
return Boolean(forChain?.paymasterService?.supported);
|
|
5651
6460
|
}
|
|
5652
6461
|
function makeSponsoredCallsCallback(deps) {
|
|
@@ -5683,8 +6492,8 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
5683
6492
|
const calls = transfers.map((transfer) => ({
|
|
5684
6493
|
to: token,
|
|
5685
6494
|
value: "0x0",
|
|
5686
|
-
data: (0,
|
|
5687
|
-
abi:
|
|
6495
|
+
data: (0, import_viem14.encodeFunctionData)({
|
|
6496
|
+
abi: import_viem14.erc20Abi,
|
|
5688
6497
|
functionName: "transfer",
|
|
5689
6498
|
args: [transfer.to, BigInt(transfer.amount)]
|
|
5690
6499
|
})
|
|
@@ -5722,7 +6531,7 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
5722
6531
|
{
|
|
5723
6532
|
version: "2.0.0",
|
|
5724
6533
|
from: deps.ownerAddress,
|
|
5725
|
-
chainId: (0,
|
|
6534
|
+
chainId: (0, import_viem14.toHex)(chainId),
|
|
5726
6535
|
atomicRequired: transfers.length > 1,
|
|
5727
6536
|
calls,
|
|
5728
6537
|
capabilities: {
|
|
@@ -5816,9 +6625,9 @@ var SPONSORED_USDC_BY_CHAIN = {
|
|
|
5816
6625
|
1: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
|
|
5817
6626
|
};
|
|
5818
6627
|
var VIEM_CHAIN2 = {
|
|
5819
|
-
8453:
|
|
5820
|
-
42161:
|
|
5821
|
-
1:
|
|
6628
|
+
8453: import_chains5.base,
|
|
6629
|
+
42161: import_chains5.arbitrum,
|
|
6630
|
+
1: import_chains5.mainnet
|
|
5822
6631
|
};
|
|
5823
6632
|
var SPONSORED_WETH_BY_CHAIN = {
|
|
5824
6633
|
8453: "0x4200000000000000000000000000000000000006",
|
|
@@ -5991,14 +6800,14 @@ var OwneySDK = class {
|
|
|
5991
6800
|
// PublicClient/WalletClient param types — structurally identical at
|
|
5992
6801
|
// runtime, but the two share a name TS treats as unrelated.
|
|
5993
6802
|
getPublicClient: (cid) => this.getPaidRpcClient(cid),
|
|
5994
|
-
getWalletChainClient: (cid) => (0,
|
|
6803
|
+
getWalletChainClient: (cid) => (0, import_viem15.createPublicClient)({
|
|
5995
6804
|
chain: VIEM_CHAIN2[cid],
|
|
5996
|
-
transport: (0,
|
|
6805
|
+
transport: (0, import_viem15.custom)(provider)
|
|
5997
6806
|
}),
|
|
5998
|
-
getWalletClient: (cid) => (0,
|
|
6807
|
+
getWalletClient: (cid) => (0, import_viem15.createWalletClient)({
|
|
5999
6808
|
account: owner,
|
|
6000
6809
|
chain: VIEM_CHAIN2[cid],
|
|
6001
|
-
transport: (0,
|
|
6810
|
+
transport: (0, import_viem15.custom)(provider)
|
|
6002
6811
|
})
|
|
6003
6812
|
});
|
|
6004
6813
|
if (!onApproved && !onSubmitted) this.cachedSponsoredCallback = callback;
|
|
@@ -6044,14 +6853,14 @@ var OwneySDK = class {
|
|
|
6044
6853
|
// PublicClient/WalletClient param types — structurally identical at
|
|
6045
6854
|
// runtime, but the two share a name TS treats as unrelated.
|
|
6046
6855
|
getPublicClient: (cid) => this.getPaidRpcClient(cid),
|
|
6047
|
-
getWalletChainClient: (cid) => (0,
|
|
6856
|
+
getWalletChainClient: (cid) => (0, import_viem15.createPublicClient)({
|
|
6048
6857
|
chain: VIEM_CHAIN2[cid],
|
|
6049
|
-
transport: (0,
|
|
6858
|
+
transport: (0, import_viem15.custom)(provider)
|
|
6050
6859
|
}),
|
|
6051
|
-
getWalletClient: (cid) => (0,
|
|
6860
|
+
getWalletClient: (cid) => (0, import_viem15.createWalletClient)({
|
|
6052
6861
|
account: owner,
|
|
6053
6862
|
chain: VIEM_CHAIN2[cid],
|
|
6054
|
-
transport: (0,
|
|
6863
|
+
transport: (0, import_viem15.custom)(provider)
|
|
6055
6864
|
})
|
|
6056
6865
|
});
|
|
6057
6866
|
if (!onApproved && !onSubmitted) this.cachedWethSponsoredCallback = callback;
|
|
@@ -6172,6 +6981,7 @@ var OwneySDK = class {
|
|
|
6172
6981
|
}
|
|
6173
6982
|
if (agentId === "yieldseeker") {
|
|
6174
6983
|
return new YieldseekerAgent(this.apiKey, {
|
|
6984
|
+
routingApiBaseUrl: this.routingApiBaseUrl,
|
|
6175
6985
|
auth: { origin: this.yieldseekerSiweOrigin },
|
|
6176
6986
|
baseUrl: this.yieldseekerApiBaseUrl ?? getYieldseekerProxyBaseUrl(this.routingApiBaseUrl),
|
|
6177
6987
|
rpcUrls: this.rpcUrls
|
|
@@ -6763,14 +7573,14 @@ var OwneySDK = class {
|
|
|
6763
7573
|
throw new OwneyError("AGENT_API_ERROR", "Funding wallet does not match this account.");
|
|
6764
7574
|
const token = SupportedAssets.find((t) => t.chainId === chainId && t.symbol === evidence.token);
|
|
6765
7575
|
if (!token) throw new OwneyError("CHAIN_UNSUPPORTED", "Unsupported funding asset.");
|
|
6766
|
-
const
|
|
6767
|
-
const receipt = await
|
|
7576
|
+
const rpc2 = this.getPaidRpcClient(chainId);
|
|
7577
|
+
const receipt = await rpc2.getTransactionReceipt({ hash: evidence.txHash });
|
|
6768
7578
|
assertCurrent();
|
|
6769
7579
|
let verified = inspectFundingReceipt(receipt, { ...evidence, agentWallet }, token.address, direction);
|
|
6770
7580
|
if (direction === "withdraw" && evidence.agentId === "yieldseeker" && verified.transfer === "unknown" && verified.confirmedAmount && BigInt(verified.confirmedAmount) > 0n) {
|
|
6771
|
-
const transaction = await
|
|
7581
|
+
const transaction = await rpc2.getTransaction({ hash: evidence.txHash });
|
|
6772
7582
|
assertCurrent();
|
|
6773
|
-
if (isFullYieldseekerWithdrawal(transaction, { ...evidence, agentWallet }, token.address))
|
|
7583
|
+
if (isFullYieldseekerWithdrawal(transaction, { ...evidence, agentWallet }, token.address, receipt))
|
|
6774
7584
|
verified = inspectFundingReceipt(receipt, { ...evidence, agentWallet, intendedAmount: "MAX" }, token.address, direction);
|
|
6775
7585
|
}
|
|
6776
7586
|
const key2 = `${state.walletAddress.toLowerCase()}:${chainId}:${evidence.agentId}:${evidence.token}:${evidence.txHash}`;
|
|
@@ -6782,6 +7592,45 @@ var OwneySDK = class {
|
|
|
6782
7592
|
}
|
|
6783
7593
|
return verified;
|
|
6784
7594
|
}
|
|
7595
|
+
/** Resolve a saved sponsored-withdrawal ID without opening a wallet prompt. */
|
|
7596
|
+
async resolveSponsoredWithdrawalEvidence(evidence) {
|
|
7597
|
+
const { state, chainId, assertCurrent } = this.captureReadScope(evidence.chainId);
|
|
7598
|
+
if (evidence.agentId !== "yieldseeker" || chainId !== 8453 || evidence.txHash || state.walletAddress.toLowerCase() !== evidence.walletAddress.toLowerCase()) return evidence;
|
|
7599
|
+
const agent = this.getAgent("yieldseeker");
|
|
7600
|
+
const wallet = await agent.getFundingWallet?.(state, chainId, evidence.token);
|
|
7601
|
+
if (!wallet || wallet.toLowerCase() !== evidence.agentWallet?.toLowerCase()) return evidence;
|
|
7602
|
+
let txHash;
|
|
7603
|
+
let executionFailed = false;
|
|
7604
|
+
if (evidence.userOpHash && /^0x[0-9a-fA-F]{64}$/.test(evidence.userOpHash)) {
|
|
7605
|
+
const response = await fetch(`${getRoutingApiBaseUrl(this.routingApiBaseUrl).replace(/\/$/, "")}/api/v1/sponsor/yieldseeker-withdraw/resolve`, {
|
|
7606
|
+
method: "POST",
|
|
7607
|
+
headers: { "content-type": "application/json", "x-owney-api-key": this.apiKey },
|
|
7608
|
+
body: JSON.stringify({
|
|
7609
|
+
owner: state.walletAddress,
|
|
7610
|
+
agentWallet: wallet,
|
|
7611
|
+
asset: SupportedAssets.find((t) => t.chainId === chainId && t.symbol === evidence.token)?.address,
|
|
7612
|
+
userOpHash: evidence.userOpHash
|
|
7613
|
+
})
|
|
7614
|
+
});
|
|
7615
|
+
if (!response.ok) throw new OwneyError("AGENT_API_ERROR", "Could not resolve sponsored withdrawal status.");
|
|
7616
|
+
const payload = await response.json();
|
|
7617
|
+
txHash = payload.data?.txHash ?? void 0;
|
|
7618
|
+
executionFailed = payload.data?.executionFailed === true;
|
|
7619
|
+
} else if (evidence.callsId) {
|
|
7620
|
+
const status = await state.provider.request({ method: "wallet_getCallsStatus", params: [evidence.callsId] });
|
|
7621
|
+
if (status?.id && status.id !== evidence.callsId || status?.chainId && Number(status.chainId) !== chainId) return evidence;
|
|
7622
|
+
executionFailed = status?.status === 400 || status?.status === 500;
|
|
7623
|
+
txHash = status?.receipts?.[0]?.transactionHash;
|
|
7624
|
+
}
|
|
7625
|
+
assertCurrent();
|
|
7626
|
+
if (executionFailed) return {
|
|
7627
|
+
...evidence,
|
|
7628
|
+
...txHash && /^0x[0-9a-fA-F]{64}$/.test(txHash) ? { txHash } : {},
|
|
7629
|
+
transfer: "failed",
|
|
7630
|
+
delivery: "failed"
|
|
7631
|
+
};
|
|
7632
|
+
return txHash && /^0x[0-9a-fA-F]{64}$/.test(txHash) ? { ...evidence, txHash } : evidence;
|
|
7633
|
+
}
|
|
6785
7634
|
/** A display acknowledgement controls polling only; it never confirms a financial outcome. */
|
|
6786
7635
|
endFundingBalanceRefresh(evidence, read2) {
|
|
6787
7636
|
const { state, chainId } = this.captureReadScope(evidence.chainId);
|
|
@@ -6806,6 +7655,39 @@ var OwneySDK = class {
|
|
|
6806
7655
|
return this.getAgent("zyfai").retryDepositRegistration(this.requireState(), verified);
|
|
6807
7656
|
}
|
|
6808
7657
|
// --- Fund operations ---
|
|
7658
|
+
/** On-chain version and ownership status for this owner's Yieldseeker agent. */
|
|
7659
|
+
async getYieldseekerWalletStatus(asset) {
|
|
7660
|
+
const state = this.requireState();
|
|
7661
|
+
const chainId = this.requireChainId();
|
|
7662
|
+
const agent = this.getAgent("yieldseeker");
|
|
7663
|
+
return agent.getWalletStatus(state, chainId, asset);
|
|
7664
|
+
}
|
|
7665
|
+
/** Deployment gate; an unavailable response keeps the current paid path. */
|
|
7666
|
+
async isYieldseekerWithdrawalSponsorshipAvailable() {
|
|
7667
|
+
return this.isYieldseekerSponsorshipAvailable("withdraw");
|
|
7668
|
+
}
|
|
7669
|
+
async isYieldseekerUpgradeSponsorshipAvailable() {
|
|
7670
|
+
return this.isYieldseekerSponsorshipAvailable("upgrade");
|
|
7671
|
+
}
|
|
7672
|
+
async isYieldseekerSponsorshipAvailable(action) {
|
|
7673
|
+
const baseUrl = getRoutingApiBaseUrl(this.routingApiBaseUrl).replace(/\/$/, "");
|
|
7674
|
+
try {
|
|
7675
|
+
const owner = this.requireState().walletAddress;
|
|
7676
|
+
const response = await fetch(`${baseUrl}/api/v1/sponsor/yieldseeker-withdraw/availability?owner=${encodeURIComponent(owner)}&action=${action}`);
|
|
7677
|
+
if (!response.ok) return false;
|
|
7678
|
+
const payload = await response.json();
|
|
7679
|
+
return payload.data?.enabled === true;
|
|
7680
|
+
} catch {
|
|
7681
|
+
return false;
|
|
7682
|
+
}
|
|
7683
|
+
}
|
|
7684
|
+
/** Explicit V1-to-V2 upgrade, confirmed on chain before returning. */
|
|
7685
|
+
async upgradeYieldseekerWallet(asset, gasMode = "paid") {
|
|
7686
|
+
const state = this.requireState();
|
|
7687
|
+
const chainId = this.requireChainId();
|
|
7688
|
+
const agent = this.getAgent("yieldseeker");
|
|
7689
|
+
return agent.upgradeWallet(state, chainId, asset, gasMode);
|
|
7690
|
+
}
|
|
6809
7691
|
/**
|
|
6810
7692
|
* Withdraw funds from a specific agent, or all agents that support the active chain+asset if agentId is omitted.
|
|
6811
7693
|
* Validates that the asset is supported by the target agent(s) on the active chain.
|
|
@@ -6869,7 +7751,7 @@ var OwneySDK = class {
|
|
|
6869
7751
|
};
|
|
6870
7752
|
progress(evidence);
|
|
6871
7753
|
try {
|
|
6872
|
-
return await agent.withdraw(state, chainId, token, requested2, progress);
|
|
7754
|
+
return await (options.gasMode === void 0 ? agent.withdraw(state, chainId, token, requested2, progress) : agent.withdraw(state, chainId, token, requested2, progress, options.gasMode));
|
|
6873
7755
|
} catch (error) {
|
|
6874
7756
|
if (!evidence.txHash && (this.isUserRejectedWithdrawal(error) || /insufficient (balance|funds)/i.test(error instanceof Error ? error.message : "")))
|
|
6875
7757
|
progress({ ...evidence, transfer: "failed", delivery: "failed" });
|
|
@@ -6902,13 +7784,23 @@ var OwneySDK = class {
|
|
|
6902
7784
|
if (!amount) {
|
|
6903
7785
|
const results2 = {};
|
|
6904
7786
|
const agentErrors2 = {};
|
|
7787
|
+
const incompleteWithdrawals = {};
|
|
6905
7788
|
for (const agent of withdrawalAgents) {
|
|
6906
7789
|
try {
|
|
6907
7790
|
results2[agent.id] = await submit(agent);
|
|
6908
7791
|
notifyAgentResult(agent.id, results2[agent.id]);
|
|
6909
7792
|
} catch (err) {
|
|
7793
|
+
if (err instanceof OwneyError && err.code === "SPONSOR_REQUEST_FAILED" && err.details?.safeToFallback === true) throw err;
|
|
6910
7794
|
if (this.isUserRejectedWithdrawal(err)) throw err;
|
|
6911
7795
|
if (err instanceof OwneyError && err.code === "WITHDRAW_INSUFFICIENT_BALANCE" && err.details?.available === "0" && submissionEvidence.get(agent.id)?.transfer === "failed") continue;
|
|
7796
|
+
if (agent.id === "yieldseeker" && err instanceof OwneyError && err.code === "WITHDRAW_PARTIAL_FAILURE" && err.details?.reason === "YIELDSEEKER_MAX_INCOMPLETE") {
|
|
7797
|
+
incompleteWithdrawals[agent.id] = { positionsStatus: err.details.positionsStatus };
|
|
7798
|
+
const evidence = submissionEvidence.get(agent.id);
|
|
7799
|
+
if (evidence?.agentId === agent.id && evidence.chainId === chainId && evidence.token === token && evidence.walletAddress.toLowerCase() === state.walletAddress.toLowerCase() && evidence.intendedAmount === "MAX" && evidence.transfer === "confirmed" && evidence.delivery === "confirmed" && evidence.txHash && /^0x[\da-f]{64}$/i.test(evidence.txHash) && evidence.confirmedAmount && /^\d+$/.test(evidence.confirmedAmount) && BigInt(evidence.confirmedAmount) > 0n) {
|
|
7800
|
+
results2[agent.id] = { txHash: evidence.txHash, type: "partial", amount: evidence.confirmedAmount, evidence };
|
|
7801
|
+
notifyAgentResult(agent.id, results2[agent.id]);
|
|
7802
|
+
}
|
|
7803
|
+
}
|
|
6912
7804
|
console.error(`withdraw failed for agent "${agent.id}":`, err);
|
|
6913
7805
|
agentErrors2[agent.id] = err instanceof Error ? err.message : String(err);
|
|
6914
7806
|
const code = err instanceof OwneyError ? err.code : "SDK_AGENT_FAILURE";
|
|
@@ -6931,7 +7823,7 @@ var OwneySDK = class {
|
|
|
6931
7823
|
throw new OwneyError(
|
|
6932
7824
|
"WITHDRAW_PARTIAL_FAILURE",
|
|
6933
7825
|
"Some agents could not complete the withdrawal.",
|
|
6934
|
-
{ asset, partialResults: results2, agentErrors: agentErrors2 }
|
|
7826
|
+
{ asset, partialResults: results2, agentErrors: agentErrors2, ...Object.keys(incompleteWithdrawals).length ? { incompleteWithdrawals } : {} }
|
|
6935
7827
|
);
|
|
6936
7828
|
}
|
|
6937
7829
|
const amountsKnown = Object.values(results2).every(
|
|
@@ -7008,6 +7900,7 @@ var OwneySDK = class {
|
|
|
7008
7900
|
results[p.agent.id] = await submit(p.agent, p.planned.toString());
|
|
7009
7901
|
notifyAgentResult(p.agent.id, results[p.agent.id]);
|
|
7010
7902
|
} catch (err) {
|
|
7903
|
+
if (err instanceof OwneyError && err.code === "SPONSOR_REQUEST_FAILED" && err.details?.safeToFallback === true) throw err;
|
|
7011
7904
|
if (this.isUserRejectedWithdrawal(err)) throw err;
|
|
7012
7905
|
console.error(`withdraw failed for agent "${p.agent.id}":`, err);
|
|
7013
7906
|
agentErrors[p.agent.id] = err instanceof Error ? err.message : String(err);
|
|
@@ -7505,16 +8398,16 @@ var OwneySDK = class {
|
|
|
7505
8398
|
);
|
|
7506
8399
|
}
|
|
7507
8400
|
const provider = this.requireConnectedProvider();
|
|
7508
|
-
const walletChainClient = (0,
|
|
8401
|
+
const walletChainClient = (0, import_viem15.createPublicClient)({
|
|
7509
8402
|
chain: VIEM_CHAIN2[chainId],
|
|
7510
|
-
transport: (0,
|
|
8403
|
+
transport: (0, import_viem15.custom)(provider)
|
|
7511
8404
|
});
|
|
7512
8405
|
const publicClient = this.getPaidRpcClient(chainId);
|
|
7513
8406
|
const approvalAmount = permit2ApprovalAmount(requiredAmount);
|
|
7514
|
-
const wallet = (0,
|
|
8407
|
+
const wallet = (0, import_viem15.createWalletClient)({
|
|
7515
8408
|
account: state.walletAddress,
|
|
7516
8409
|
chain: VIEM_CHAIN2[chainId],
|
|
7517
|
-
transport: (0,
|
|
8410
|
+
transport: (0, import_viem15.custom)(provider)
|
|
7518
8411
|
});
|
|
7519
8412
|
await ensureWalletOnChain(walletChainClient, wallet, chainId);
|
|
7520
8413
|
const hash = await wallet.writeContract({
|
|
@@ -7676,7 +8569,7 @@ var OwneySDK = class {
|
|
|
7676
8569
|
};
|
|
7677
8570
|
|
|
7678
8571
|
// src/agents/zyfai/zyfai.siwx.ts
|
|
7679
|
-
var
|
|
8572
|
+
var import_viem16 = require("viem");
|
|
7680
8573
|
var import_siwe2 = require("siwe");
|
|
7681
8574
|
var import_sdk2 = require("@zyfai/sdk");
|
|
7682
8575
|
|
|
@@ -7803,7 +8696,7 @@ function buildSIWXConfig(deps) {
|
|
|
7803
8696
|
issuedAt,
|
|
7804
8697
|
toString() {
|
|
7805
8698
|
return new import_siwe2.SiweMessage({
|
|
7806
|
-
address: (0,
|
|
8699
|
+
address: (0, import_viem16.getAddress)(accountAddress),
|
|
7807
8700
|
chainId: numericChainId(chainId),
|
|
7808
8701
|
domain,
|
|
7809
8702
|
uri,
|