@owney/sdk 0.7.25-beta.3 → 0.7.25-beta.6
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 +72 -13
- package/dist/index.cjs +614 -187
- package/dist/index.d.cts +51 -8
- package/dist/index.d.ts +51 -8
- package/dist/index.js +555 -125
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -159,6 +159,34 @@ function rateLimitDelay(error, now = Date.now()) {
|
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
// src/lib/agent-reads.ts
|
|
162
|
+
function rateLimitDiagnostics(error) {
|
|
163
|
+
const seen = /* @__PURE__ */ new Set();
|
|
164
|
+
let details = {};
|
|
165
|
+
function visit(value, depth = 0) {
|
|
166
|
+
if (depth > 6 || !value || typeof value !== "object" || seen.has(value))
|
|
167
|
+
return;
|
|
168
|
+
seen.add(value);
|
|
169
|
+
const record = value;
|
|
170
|
+
for (const key2 of [
|
|
171
|
+
"rpcSource",
|
|
172
|
+
"chainId",
|
|
173
|
+
"rpcMethod",
|
|
174
|
+
"providerRequestId",
|
|
175
|
+
"statusCode"
|
|
176
|
+
]) {
|
|
177
|
+
const candidate = record[key2];
|
|
178
|
+
if (candidate !== void 0 && details[key2] === void 0)
|
|
179
|
+
details = { ...details, [key2]: candidate };
|
|
180
|
+
}
|
|
181
|
+
for (const key2 of ["details", "cause", "response", "fields", "error"])
|
|
182
|
+
visit(record[key2], depth + 1);
|
|
183
|
+
}
|
|
184
|
+
visit(error);
|
|
185
|
+
return {
|
|
186
|
+
rpcSource: details.rpcSource ?? "agent-api",
|
|
187
|
+
...details
|
|
188
|
+
};
|
|
189
|
+
}
|
|
162
190
|
var AgentReads = class {
|
|
163
191
|
inFlight = /* @__PURE__ */ new Map();
|
|
164
192
|
cooldowns = /* @__PURE__ */ new Map();
|
|
@@ -166,14 +194,15 @@ var AgentReads = class {
|
|
|
166
194
|
clearInFlight() {
|
|
167
195
|
this.inFlight.clear();
|
|
168
196
|
}
|
|
169
|
-
limited(agentId, until) {
|
|
197
|
+
limited(agentId, until, diagnostics) {
|
|
170
198
|
return new OwneyError(
|
|
171
199
|
"AGENT_RATE_LIMITED",
|
|
172
200
|
"Too many requests. Please wait before trying again.",
|
|
173
201
|
{
|
|
174
202
|
statusCode: 429,
|
|
175
203
|
retryAt: until,
|
|
176
|
-
retryAfterSeconds: Math.max(0, Math.ceil((until - Date.now()) / 1e3))
|
|
204
|
+
retryAfterSeconds: Math.max(0, Math.ceil((until - Date.now()) / 1e3)),
|
|
205
|
+
...diagnostics
|
|
177
206
|
},
|
|
178
207
|
agentId
|
|
179
208
|
);
|
|
@@ -181,7 +210,9 @@ var AgentReads = class {
|
|
|
181
210
|
run(agentId, key2, fetch2) {
|
|
182
211
|
const cooldown = this.cooldowns.get(agentId);
|
|
183
212
|
if (cooldown && cooldown.until > Date.now()) {
|
|
184
|
-
return Promise.reject(
|
|
213
|
+
return Promise.reject(
|
|
214
|
+
this.limited(agentId, cooldown.until, cooldown.diagnostics)
|
|
215
|
+
);
|
|
185
216
|
}
|
|
186
217
|
const requestKey = JSON.stringify([agentId, key2]);
|
|
187
218
|
const existing = this.inFlight.get(requestKey);
|
|
@@ -202,8 +233,9 @@ var AgentReads = class {
|
|
|
202
233
|
Math.min(3e4 * 2 ** (failures - 1), 3e5)
|
|
203
234
|
);
|
|
204
235
|
const until = Math.max(previous?.until ?? 0, Date.now() + delay);
|
|
205
|
-
|
|
206
|
-
|
|
236
|
+
const diagnostics = rateLimitDiagnostics(error);
|
|
237
|
+
this.cooldowns.set(agentId, { until, failures, diagnostics });
|
|
238
|
+
throw this.limited(agentId, until, diagnostics);
|
|
207
239
|
}
|
|
208
240
|
).finally(() => {
|
|
209
241
|
if (this.inFlight.get(requestKey) === promise)
|
|
@@ -216,7 +248,7 @@ var AgentReads = class {
|
|
|
216
248
|
|
|
217
249
|
// src/agents/zyfai/zyfai.agent.ts
|
|
218
250
|
var import_sdk = require("@zyfai/sdk");
|
|
219
|
-
var
|
|
251
|
+
var import_viem2 = require("viem");
|
|
220
252
|
var import_chains = require("viem/chains");
|
|
221
253
|
|
|
222
254
|
// src/types/config.ts
|
|
@@ -1097,15 +1129,128 @@ function protocolsPolicyNeedsUpdate(current, desiredProtocols, desiredAutoSelect
|
|
|
1097
1129
|
return !protocolListsEqual(current.protocols, desiredProtocols);
|
|
1098
1130
|
}
|
|
1099
1131
|
|
|
1132
|
+
// src/lib/paid-rpc.ts
|
|
1133
|
+
var import_viem = require("viem");
|
|
1134
|
+
var PAID_RPC_RETRY_COUNT = 3;
|
|
1135
|
+
var PAID_RPC_RETRY_DELAY_MS = 1e3;
|
|
1136
|
+
var DEFAULT_RPC_URLS = {
|
|
1137
|
+
1: "https://eth-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V",
|
|
1138
|
+
8453: "https://base-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V",
|
|
1139
|
+
42161: "https://arb-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V"
|
|
1140
|
+
};
|
|
1141
|
+
function resolveRpcUrl(rpcUrls, chainId) {
|
|
1142
|
+
const url = rpcUrls?.[chainId]?.trim();
|
|
1143
|
+
if (url) return url;
|
|
1144
|
+
return DEFAULT_RPC_URLS[chainId];
|
|
1145
|
+
}
|
|
1146
|
+
function resolveRpcUrls(rpcUrls) {
|
|
1147
|
+
return {
|
|
1148
|
+
1: resolveRpcUrl(rpcUrls, 1),
|
|
1149
|
+
8453: resolveRpcUrl(rpcUrls, 8453),
|
|
1150
|
+
42161: resolveRpcUrl(rpcUrls, 42161)
|
|
1151
|
+
};
|
|
1152
|
+
}
|
|
1153
|
+
function createPaidRpcClient(chain, rpcUrls) {
|
|
1154
|
+
const url = resolveRpcUrl(
|
|
1155
|
+
rpcUrls,
|
|
1156
|
+
chain.id
|
|
1157
|
+
);
|
|
1158
|
+
return (0, import_viem.createPublicClient)({
|
|
1159
|
+
chain,
|
|
1160
|
+
transport: (0, import_viem.http)(url, {
|
|
1161
|
+
retryCount: PAID_RPC_RETRY_COUNT,
|
|
1162
|
+
retryDelay: PAID_RPC_RETRY_DELAY_MS
|
|
1163
|
+
})
|
|
1164
|
+
});
|
|
1165
|
+
}
|
|
1166
|
+
function headerValue(error, name) {
|
|
1167
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1168
|
+
let value;
|
|
1169
|
+
function visit(candidate, depth = 0) {
|
|
1170
|
+
if (value || depth > 6 || !candidate || typeof candidate !== "object")
|
|
1171
|
+
return;
|
|
1172
|
+
if (seen.has(candidate)) return;
|
|
1173
|
+
seen.add(candidate);
|
|
1174
|
+
const record = candidate;
|
|
1175
|
+
const headers = record.headers;
|
|
1176
|
+
const found = typeof headers?.get === "function" ? headers.get(name) : headers?.[name] ?? headers?.[name.toLowerCase()];
|
|
1177
|
+
if (typeof found === "string" && found) {
|
|
1178
|
+
value = found;
|
|
1179
|
+
return;
|
|
1180
|
+
}
|
|
1181
|
+
for (const key2 of ["cause", "details", "response", "error"])
|
|
1182
|
+
visit(record[key2], depth + 1);
|
|
1183
|
+
}
|
|
1184
|
+
visit(error);
|
|
1185
|
+
return value;
|
|
1186
|
+
}
|
|
1187
|
+
function statusCode(error) {
|
|
1188
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1189
|
+
let status;
|
|
1190
|
+
function visit(candidate, depth = 0) {
|
|
1191
|
+
if (status || depth > 6 || !candidate || typeof candidate !== "object")
|
|
1192
|
+
return;
|
|
1193
|
+
if (seen.has(candidate)) return;
|
|
1194
|
+
seen.add(candidate);
|
|
1195
|
+
const record = candidate;
|
|
1196
|
+
for (const key2 of ["status", "statusCode"]) {
|
|
1197
|
+
const parsed = Number(record[key2]);
|
|
1198
|
+
if (Number.isInteger(parsed) && parsed >= 100 && parsed <= 599) {
|
|
1199
|
+
status = parsed;
|
|
1200
|
+
return;
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
for (const key2 of ["cause", "details", "response", "error"])
|
|
1204
|
+
visit(record[key2], depth + 1);
|
|
1205
|
+
}
|
|
1206
|
+
visit(error);
|
|
1207
|
+
return status;
|
|
1208
|
+
}
|
|
1209
|
+
function paidRpcError(error, chainId, rpcMethod, agentId) {
|
|
1210
|
+
const delay = rateLimitDelay(error);
|
|
1211
|
+
const providerRequestId = headerValue(error, "x-alchemy-request-id") ?? headerValue(error, "x-request-id");
|
|
1212
|
+
if (delay === void 0) {
|
|
1213
|
+
return new OwneyError(
|
|
1214
|
+
"AGENT_API_ERROR",
|
|
1215
|
+
"The blockchain RPC request failed.",
|
|
1216
|
+
{
|
|
1217
|
+
rpcSource: "paid-rpc",
|
|
1218
|
+
chainId,
|
|
1219
|
+
rpcMethod,
|
|
1220
|
+
...statusCode(error) ? { statusCode: statusCode(error) } : {},
|
|
1221
|
+
...providerRequestId ? { providerRequestId } : {}
|
|
1222
|
+
},
|
|
1223
|
+
agentId
|
|
1224
|
+
);
|
|
1225
|
+
}
|
|
1226
|
+
const retryAt = Date.now() + delay;
|
|
1227
|
+
return new OwneyError(
|
|
1228
|
+
"AGENT_RATE_LIMITED",
|
|
1229
|
+
"The blockchain RPC is rate limited. Please wait before trying again.",
|
|
1230
|
+
{
|
|
1231
|
+
rpcSource: "paid-rpc",
|
|
1232
|
+
chainId,
|
|
1233
|
+
rpcMethod,
|
|
1234
|
+
statusCode: 429,
|
|
1235
|
+
retryAt,
|
|
1236
|
+
retryAfterSeconds: Math.max(0, Math.ceil(delay / 1e3)),
|
|
1237
|
+
...providerRequestId ? { providerRequestId } : {}
|
|
1238
|
+
},
|
|
1239
|
+
agentId
|
|
1240
|
+
);
|
|
1241
|
+
}
|
|
1242
|
+
async function withPaidRpcDiagnostics(operation, chainId, rpcMethod, agentId) {
|
|
1243
|
+
try {
|
|
1244
|
+
return await operation();
|
|
1245
|
+
} catch (error) {
|
|
1246
|
+
throw paidRpcError(error, chainId, rpcMethod, agentId);
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1100
1250
|
// src/agents/zyfai/zyfai.agent.ts
|
|
1101
|
-
var ERC7579_IS_MODULE_INSTALLED_ABI = (0,
|
|
1251
|
+
var ERC7579_IS_MODULE_INSTALLED_ABI = (0, import_viem2.parseAbi)([
|
|
1102
1252
|
"function isModuleInstalled(uint256 moduleTypeId, address module, bytes additionalContext) view returns (bool)"
|
|
1103
1253
|
]);
|
|
1104
|
-
var DEFAULT_ZYFAI_RPC_URLS = {
|
|
1105
|
-
8453: "https://base-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V",
|
|
1106
|
-
42161: "https://arb-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V",
|
|
1107
|
-
1: "https://eth-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V"
|
|
1108
|
-
};
|
|
1109
1254
|
var WETH_ADDRESS_BY_CHAIN = {
|
|
1110
1255
|
8453: "0x4200000000000000000000000000000000000006",
|
|
1111
1256
|
42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
|
|
@@ -1171,7 +1316,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1171
1316
|
earningsSnapshot = null;
|
|
1172
1317
|
earningsGeneration = 0;
|
|
1173
1318
|
constructor(apiKey, rpcUrls, referralSource) {
|
|
1174
|
-
this.rpcUrls = rpcUrls
|
|
1319
|
+
this.rpcUrls = resolveRpcUrls(rpcUrls);
|
|
1175
1320
|
this.sdk = new import_sdk.ZyfaiSDK({
|
|
1176
1321
|
apiKey,
|
|
1177
1322
|
rpcUrls: this.rpcUrls,
|
|
@@ -1185,10 +1330,10 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1185
1330
|
getPublicClient(chainId) {
|
|
1186
1331
|
const cached = this.publicClients.get(chainId);
|
|
1187
1332
|
if (cached) return cached;
|
|
1188
|
-
const client = (
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1333
|
+
const client = createPaidRpcClient(
|
|
1334
|
+
VIEM_CHAIN[chainId],
|
|
1335
|
+
this.rpcUrls
|
|
1336
|
+
);
|
|
1192
1337
|
this.publicClients.set(chainId, client);
|
|
1193
1338
|
return client;
|
|
1194
1339
|
}
|
|
@@ -2156,7 +2301,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
2156
2301
|
};
|
|
2157
2302
|
|
|
2158
2303
|
// src/agents/yieldseeker/yieldseeker.agent.ts
|
|
2159
|
-
var
|
|
2304
|
+
var import_viem7 = require("viem");
|
|
2160
2305
|
var import_chains3 = require("viem/chains");
|
|
2161
2306
|
|
|
2162
2307
|
// src/lib/chain-guard.ts
|
|
@@ -2195,7 +2340,7 @@ async function ensureWalletOnChain(pub, wallet, expected) {
|
|
|
2195
2340
|
}
|
|
2196
2341
|
|
|
2197
2342
|
// src/lib/transfer-auth.ts
|
|
2198
|
-
var
|
|
2343
|
+
var import_viem3 = require("viem");
|
|
2199
2344
|
|
|
2200
2345
|
// src/lib/sponsor-client.ts
|
|
2201
2346
|
var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
@@ -2311,7 +2456,7 @@ async function postSponsorBatchTransfer(input) {
|
|
|
2311
2456
|
}
|
|
2312
2457
|
|
|
2313
2458
|
// src/lib/permit2.ts
|
|
2314
|
-
var
|
|
2459
|
+
var import_viem4 = require("viem");
|
|
2315
2460
|
var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
2316
2461
|
var MAX_UINT256 = 2n ** 256n - 1n;
|
|
2317
2462
|
function permit2ApprovalAmount(requiredAmount) {
|
|
@@ -2352,14 +2497,15 @@ var ERC20_ALLOWANCE_ABI = [
|
|
|
2352
2497
|
function randomPermit2Nonce() {
|
|
2353
2498
|
const bytes = new Uint8Array(32);
|
|
2354
2499
|
globalThis.crypto.getRandomValues(bytes);
|
|
2355
|
-
return BigInt((0,
|
|
2500
|
+
return BigInt((0, import_viem4.bytesToHex)(bytes));
|
|
2356
2501
|
}
|
|
2357
|
-
async function readPermit2Allowance(publicClient, token, owner) {
|
|
2502
|
+
async function readPermit2Allowance(publicClient, token, owner, blockNumber) {
|
|
2358
2503
|
return publicClient.readContract({
|
|
2359
2504
|
address: token,
|
|
2360
2505
|
abi: ERC20_ALLOWANCE_ABI,
|
|
2361
2506
|
functionName: "allowance",
|
|
2362
|
-
args: [owner, PERMIT2_ADDRESS]
|
|
2507
|
+
args: [owner, PERMIT2_ADDRESS],
|
|
2508
|
+
...blockNumber === void 0 ? {} : { blockNumber }
|
|
2363
2509
|
});
|
|
2364
2510
|
}
|
|
2365
2511
|
async function readErc20Balance(publicClient, token, owner) {
|
|
@@ -2394,7 +2540,7 @@ function makeVerificationAwareDepositCallback(implementation) {
|
|
|
2394
2540
|
|
|
2395
2541
|
// src/agents/yieldseeker/yieldseeker.auth.ts
|
|
2396
2542
|
var import_siwe = require("siwe");
|
|
2397
|
-
var
|
|
2543
|
+
var import_viem5 = require("viem");
|
|
2398
2544
|
var import_chains2 = require("viem/chains");
|
|
2399
2545
|
|
|
2400
2546
|
// src/agents/yieldseeker/yieldseeker.auth-cache.ts
|
|
@@ -2507,7 +2653,7 @@ function createYieldseekerSiweMessage(address, chainId, dependencies = {}) {
|
|
|
2507
2653
|
return new import_siwe.SiweMessage({
|
|
2508
2654
|
scheme: url.protocol.slice(0, -1),
|
|
2509
2655
|
domain: url.host,
|
|
2510
|
-
address: (0,
|
|
2656
|
+
address: (0, import_viem5.getAddress)(address),
|
|
2511
2657
|
uri: url.origin,
|
|
2512
2658
|
version: "1",
|
|
2513
2659
|
chainId,
|
|
@@ -2593,15 +2739,15 @@ var YieldseekerAuth = class {
|
|
|
2593
2739
|
clearYieldseekerSession(state.walletAddress, chainId);
|
|
2594
2740
|
}
|
|
2595
2741
|
async sign(state, chainId) {
|
|
2596
|
-
const account = (0,
|
|
2597
|
-
const publicClient = (0,
|
|
2742
|
+
const account = (0, import_viem5.getAddress)(state.walletAddress);
|
|
2743
|
+
const publicClient = (0, import_viem5.createPublicClient)({
|
|
2598
2744
|
chain: import_chains2.base,
|
|
2599
|
-
transport: (0,
|
|
2745
|
+
transport: (0, import_viem5.custom)(state.provider)
|
|
2600
2746
|
});
|
|
2601
|
-
const walletClient = (0,
|
|
2747
|
+
const walletClient = (0, import_viem5.createWalletClient)({
|
|
2602
2748
|
account,
|
|
2603
2749
|
chain: import_chains2.base,
|
|
2604
|
-
transport: (0,
|
|
2750
|
+
transport: (0, import_viem5.custom)(state.provider)
|
|
2605
2751
|
});
|
|
2606
2752
|
await ensureWalletOnChain(
|
|
2607
2753
|
publicClient,
|
|
@@ -2767,7 +2913,7 @@ var YieldseekerApiClient = class {
|
|
|
2767
2913
|
};
|
|
2768
2914
|
|
|
2769
2915
|
// src/agents/yieldseeker/yieldseeker.mapper.ts
|
|
2770
|
-
var
|
|
2916
|
+
var import_viem6 = require("viem");
|
|
2771
2917
|
|
|
2772
2918
|
// src/lib/helpers/snapshot-apy.ts
|
|
2773
2919
|
var DAY_MS = 864e5;
|
|
@@ -2834,10 +2980,10 @@ function raw(value, endpoint) {
|
|
|
2834
2980
|
return BigInt(value);
|
|
2835
2981
|
}
|
|
2836
2982
|
function decimal(value, decimals, endpoint) {
|
|
2837
|
-
return (0,
|
|
2983
|
+
return (0, import_viem6.formatUnits)(raw(value, endpoint), decimals);
|
|
2838
2984
|
}
|
|
2839
2985
|
function usd(rawAmount, decimals, price) {
|
|
2840
|
-
return Number((0,
|
|
2986
|
+
return Number((0, import_viem6.formatUnits)(rawAmount, decimals)) * price;
|
|
2841
2987
|
}
|
|
2842
2988
|
function percent(value) {
|
|
2843
2989
|
const result = Number(value);
|
|
@@ -2863,7 +3009,7 @@ function assetAddressValue(record, address) {
|
|
|
2863
3009
|
}
|
|
2864
3010
|
function position(value, asset, baseAssetDecimals) {
|
|
2865
3011
|
const option = value?.yieldOption;
|
|
2866
|
-
if (!option || typeof option.provider !== "string" || typeof option.name !== "string" || typeof option.address !== "string" || !(0,
|
|
3012
|
+
if (!option || typeof option.provider !== "string" || typeof option.name !== "string" || typeof option.address !== "string" || !(0, import_viem6.isAddress)(option.address)) {
|
|
2867
3013
|
return invalid("yield positions", "missing vault metadata");
|
|
2868
3014
|
}
|
|
2869
3015
|
return {
|
|
@@ -2944,7 +3090,7 @@ function mapYieldseekerEarnings(contexts) {
|
|
|
2944
3090
|
chain: "BASE",
|
|
2945
3091
|
chainId: 8453,
|
|
2946
3092
|
asset: context.asset,
|
|
2947
|
-
amount: (0,
|
|
3093
|
+
amount: (0, import_viem6.formatUnits)(amount, context.snapshot.baseAssetDecimals)
|
|
2948
3094
|
});
|
|
2949
3095
|
lifetimeEarnings += usd(
|
|
2950
3096
|
amount,
|
|
@@ -3211,6 +3357,9 @@ var YIELDSEEKER_USERNAME_PREFIX = "owney_";
|
|
|
3211
3357
|
var YIELDSEEKER_USERNAME_RANDOM_LENGTH = 14;
|
|
3212
3358
|
var YIELDSEEKER_USERNAME_CREATE_ATTEMPTS = 3;
|
|
3213
3359
|
var YIELDSEEKER_YIELD_OPTIONS_CACHE_MS = 6e4;
|
|
3360
|
+
var YIELDSEEKER_AGENT_LIST_CACHE_MS = 6e4;
|
|
3361
|
+
var YIELDSEEKER_PORTFOLIO_CACHE_MS = 3e4;
|
|
3362
|
+
var YIELDSEEKER_ACTIVITY_CACHE_MS = 6e4;
|
|
3214
3363
|
function generateYieldseekerUsername() {
|
|
3215
3364
|
const suffix = globalThis.crypto.randomUUID().replaceAll("-", "").slice(0, YIELDSEEKER_USERNAME_RANDOM_LENGTH).toLowerCase();
|
|
3216
3365
|
return `${YIELDSEEKER_USERNAME_PREFIX}${suffix}`;
|
|
@@ -3254,6 +3403,7 @@ function query(params) {
|
|
|
3254
3403
|
var YieldseekerAgent = class {
|
|
3255
3404
|
id = "yieldseeker";
|
|
3256
3405
|
balanceComposition = "tokens-plus-positions";
|
|
3406
|
+
withdrawalRequiresWalletApproval = true;
|
|
3257
3407
|
supportedChainIds = [8453];
|
|
3258
3408
|
supportedAssets = [
|
|
3259
3409
|
{
|
|
@@ -3267,11 +3417,17 @@ var YieldseekerAgent = class {
|
|
|
3267
3417
|
];
|
|
3268
3418
|
api;
|
|
3269
3419
|
auth;
|
|
3420
|
+
rpcUrls;
|
|
3421
|
+
receiptClient;
|
|
3270
3422
|
transactionExecutor;
|
|
3271
3423
|
unwindReceiptWaiter;
|
|
3272
3424
|
agentContexts = /* @__PURE__ */ new Map();
|
|
3273
3425
|
users = /* @__PURE__ */ new Map();
|
|
3274
3426
|
pendingAgents = /* @__PURE__ */ new Map();
|
|
3427
|
+
pendingWalletContexts = /* @__PURE__ */ new Map();
|
|
3428
|
+
readCache = /* @__PURE__ */ new Map();
|
|
3429
|
+
pendingReads = /* @__PURE__ */ new Map();
|
|
3430
|
+
readGeneration = 0;
|
|
3275
3431
|
yieldOptions = /* @__PURE__ */ new Map();
|
|
3276
3432
|
pendingYieldOptions = /* @__PURE__ */ new Map();
|
|
3277
3433
|
constructor(owneyApiKey, options = {}) {
|
|
@@ -3281,10 +3437,16 @@ var YieldseekerAgent = class {
|
|
|
3281
3437
|
options.fetchFn
|
|
3282
3438
|
);
|
|
3283
3439
|
this.auth = new YieldseekerAuth(options.auth);
|
|
3440
|
+
this.rpcUrls = options.rpcUrls;
|
|
3284
3441
|
this.transactionExecutor = options.transactionExecutor;
|
|
3285
3442
|
this.unwindReceiptWaiter = options.unwindReceiptWaiter;
|
|
3286
3443
|
}
|
|
3444
|
+
getReceiptClient() {
|
|
3445
|
+
this.receiptClient ??= createPaidRpcClient(import_chains3.base, this.rpcUrls);
|
|
3446
|
+
return this.receiptClient;
|
|
3447
|
+
}
|
|
3287
3448
|
async disconnect() {
|
|
3449
|
+
this.readGeneration += 1;
|
|
3288
3450
|
this.auth.clear();
|
|
3289
3451
|
for (const key2 of this.users.keys()) {
|
|
3290
3452
|
const [walletAddress, chainId] = key2.split(":");
|
|
@@ -3293,6 +3455,9 @@ var YieldseekerAgent = class {
|
|
|
3293
3455
|
this.users.clear();
|
|
3294
3456
|
this.agentContexts.clear();
|
|
3295
3457
|
this.pendingAgents.clear();
|
|
3458
|
+
this.pendingWalletContexts.clear();
|
|
3459
|
+
this.readCache.clear();
|
|
3460
|
+
this.pendingReads.clear();
|
|
3296
3461
|
}
|
|
3297
3462
|
async activateAgent(state, chainId, asset) {
|
|
3298
3463
|
this.assertChain(chainId);
|
|
@@ -3329,12 +3494,12 @@ var YieldseekerAgent = class {
|
|
|
3329
3494
|
await this.waitForReceipt(state, chainId, txHash);
|
|
3330
3495
|
} else {
|
|
3331
3496
|
txHash = await this.submitTransaction(state, chainId, {
|
|
3332
|
-
from: (0,
|
|
3497
|
+
from: (0, import_viem7.getAddress)(state.walletAddress),
|
|
3333
3498
|
to: YIELDSEEKER_ASSET_METADATA[asset].address,
|
|
3334
|
-
data: (0,
|
|
3335
|
-
abi:
|
|
3499
|
+
data: (0, import_viem7.encodeFunctionData)({
|
|
3500
|
+
abi: import_viem7.erc20Abi,
|
|
3336
3501
|
functionName: "transfer",
|
|
3337
|
-
args: [(0,
|
|
3502
|
+
args: [(0, import_viem7.getAddress)(context.wallet.walletAddress), BigInt(amount)]
|
|
3338
3503
|
}),
|
|
3339
3504
|
value: "0",
|
|
3340
3505
|
chainId
|
|
@@ -3434,15 +3599,15 @@ var YieldseekerAgent = class {
|
|
|
3434
3599
|
remaining: remaining.toString()
|
|
3435
3600
|
});
|
|
3436
3601
|
}
|
|
3437
|
-
const account = (0,
|
|
3602
|
+
const account = (0, import_viem7.getAddress)(state.walletAddress);
|
|
3438
3603
|
const txHash = await this.submitTransaction(state, chainId, {
|
|
3439
3604
|
from: account,
|
|
3440
|
-
to: (0,
|
|
3441
|
-
data: amount === void 0 ? (0,
|
|
3605
|
+
to: (0, import_viem7.getAddress)(context.wallet.walletAddress),
|
|
3606
|
+
data: amount === void 0 ? (0, import_viem7.encodeFunctionData)({
|
|
3442
3607
|
abi: YIELDSEEKER_AGENT_WALLET_ABI,
|
|
3443
3608
|
functionName: "withdrawAllAssetToUser",
|
|
3444
3609
|
args: [account, metadata.address]
|
|
3445
|
-
}) : (0,
|
|
3610
|
+
}) : (0, import_viem7.encodeFunctionData)({
|
|
3446
3611
|
abi: YIELDSEEKER_AGENT_WALLET_ABI,
|
|
3447
3612
|
functionName: "withdrawAssetToUser",
|
|
3448
3613
|
args: [account, metadata.address, requested]
|
|
@@ -3498,7 +3663,7 @@ var YieldseekerAgent = class {
|
|
|
3498
3663
|
);
|
|
3499
3664
|
const vaultAddresses = new Set(
|
|
3500
3665
|
catalog.flat().filter(
|
|
3501
|
-
(yieldOption) => yieldOption.chainId === chainId && (0,
|
|
3666
|
+
(yieldOption) => yieldOption.chainId === chainId && (0, import_viem7.isAddress)(yieldOption.address)
|
|
3502
3667
|
).map((yieldOption) => yieldOption.address.toLowerCase())
|
|
3503
3668
|
);
|
|
3504
3669
|
return mapYieldseekerHistory(contexts, {
|
|
@@ -3555,6 +3720,86 @@ var YieldseekerAgent = class {
|
|
|
3555
3720
|
contextKey(state, chainId, asset) {
|
|
3556
3721
|
return `${this.userKey(state, chainId)}:${asset}`;
|
|
3557
3722
|
}
|
|
3723
|
+
cachedRead(key2, ttlMs, read2) {
|
|
3724
|
+
const cached = this.readCache.get(key2);
|
|
3725
|
+
if (cached && cached.expiresAt > Date.now()) {
|
|
3726
|
+
return Promise.resolve(cached.value);
|
|
3727
|
+
}
|
|
3728
|
+
const pending = this.pendingReads.get(key2);
|
|
3729
|
+
if (pending) return pending;
|
|
3730
|
+
const generation = this.readGeneration;
|
|
3731
|
+
const request = Promise.resolve().then(read2).then((value) => {
|
|
3732
|
+
if (this.readGeneration === generation) {
|
|
3733
|
+
this.readCache.set(key2, {
|
|
3734
|
+
expiresAt: Date.now() + ttlMs,
|
|
3735
|
+
value
|
|
3736
|
+
});
|
|
3737
|
+
}
|
|
3738
|
+
return value;
|
|
3739
|
+
}).finally(() => {
|
|
3740
|
+
if (this.pendingReads.get(key2) === request) {
|
|
3741
|
+
this.pendingReads.delete(key2);
|
|
3742
|
+
}
|
|
3743
|
+
});
|
|
3744
|
+
this.pendingReads.set(key2, request);
|
|
3745
|
+
return request;
|
|
3746
|
+
}
|
|
3747
|
+
agentListKey(state, chainId) {
|
|
3748
|
+
return `agents:${this.userKey(state, chainId)}`;
|
|
3749
|
+
}
|
|
3750
|
+
async listAgents(state, chainId, user) {
|
|
3751
|
+
const response = await this.cachedRead(
|
|
3752
|
+
this.agentListKey(state, chainId),
|
|
3753
|
+
YIELDSEEKER_AGENT_LIST_CACHE_MS,
|
|
3754
|
+
async () => {
|
|
3755
|
+
const response2 = await this.walletRequest(
|
|
3756
|
+
state,
|
|
3757
|
+
chainId,
|
|
3758
|
+
`/users/${user.userId}/agents`
|
|
3759
|
+
);
|
|
3760
|
+
if (!Array.isArray(response2?.agents)) {
|
|
3761
|
+
throw this.invalidResponse("agent list");
|
|
3762
|
+
}
|
|
3763
|
+
return response2;
|
|
3764
|
+
}
|
|
3765
|
+
);
|
|
3766
|
+
return response.agents;
|
|
3767
|
+
}
|
|
3768
|
+
async contextForAgent(state, chainId, user, agent, asset) {
|
|
3769
|
+
const key2 = this.contextKey(state, chainId, asset);
|
|
3770
|
+
const cached = this.agentContexts.get(key2);
|
|
3771
|
+
if (cached?.agent.agentId === agent.agentId) return cached;
|
|
3772
|
+
const pending = this.pendingWalletContexts.get(key2);
|
|
3773
|
+
if (pending) return pending;
|
|
3774
|
+
const generation = this.readGeneration;
|
|
3775
|
+
const request = this.walletRequest(
|
|
3776
|
+
state,
|
|
3777
|
+
chainId,
|
|
3778
|
+
`/users/${user.userId}/agents/${agent.agentId}/wallet`
|
|
3779
|
+
).then((walletResponse) => {
|
|
3780
|
+
if (!walletResponse?.agentWallet || !(0, import_viem7.isAddress)(walletResponse.agentWallet.walletAddress)) {
|
|
3781
|
+
throw this.invalidResponse("agent wallet");
|
|
3782
|
+
}
|
|
3783
|
+
const context = {
|
|
3784
|
+
user,
|
|
3785
|
+
agent,
|
|
3786
|
+
wallet: walletResponse.agentWallet,
|
|
3787
|
+
asset
|
|
3788
|
+
};
|
|
3789
|
+
if (this.readGeneration === generation) {
|
|
3790
|
+
this.agentContexts.set(key2, context);
|
|
3791
|
+
}
|
|
3792
|
+
return context;
|
|
3793
|
+
});
|
|
3794
|
+
this.pendingWalletContexts.set(key2, request);
|
|
3795
|
+
try {
|
|
3796
|
+
return await request;
|
|
3797
|
+
} finally {
|
|
3798
|
+
if (this.pendingWalletContexts.get(key2) === request) {
|
|
3799
|
+
this.pendingWalletContexts.delete(key2);
|
|
3800
|
+
}
|
|
3801
|
+
}
|
|
3802
|
+
}
|
|
3558
3803
|
async resolveUser(state, chainId) {
|
|
3559
3804
|
const key2 = this.userKey(state, chainId);
|
|
3560
3805
|
const inMemory = this.users.get(key2);
|
|
@@ -3564,7 +3809,7 @@ var YieldseekerAgent = class {
|
|
|
3564
3809
|
this.users.set(key2, persisted);
|
|
3565
3810
|
return persisted;
|
|
3566
3811
|
}
|
|
3567
|
-
const walletAddress = (0,
|
|
3812
|
+
const walletAddress = (0, import_viem7.getAddress)(state.walletAddress);
|
|
3568
3813
|
let user = null;
|
|
3569
3814
|
try {
|
|
3570
3815
|
const login = await this.providerRequest(
|
|
@@ -3651,16 +3896,9 @@ var YieldseekerAgent = class {
|
|
|
3651
3896
|
}
|
|
3652
3897
|
async resolveAgent(state, chainId, asset, createIfMissing) {
|
|
3653
3898
|
const user = await this.resolveUser(state, chainId);
|
|
3654
|
-
const
|
|
3655
|
-
state,
|
|
3656
|
-
chainId,
|
|
3657
|
-
`/users/${user.userId}/agents`
|
|
3658
|
-
);
|
|
3659
|
-
if (!Array.isArray(response?.agents)) {
|
|
3660
|
-
throw this.invalidResponse("agent list");
|
|
3661
|
-
}
|
|
3899
|
+
const agents = await this.listAgents(state, chainId, user);
|
|
3662
3900
|
const metadata = YIELDSEEKER_ASSET_METADATA[asset];
|
|
3663
|
-
let agent =
|
|
3901
|
+
let agent = agents.find(
|
|
3664
3902
|
(candidate) => this.isOwneyAgent(candidate) && candidate.chainId === chainId && candidate.type === "vault" && candidate.assetAddress.toLowerCase() === metadata.address.toLowerCase()
|
|
3665
3903
|
);
|
|
3666
3904
|
if (!agent && createIfMissing) {
|
|
@@ -3681,83 +3919,91 @@ var YieldseekerAgent = class {
|
|
|
3681
3919
|
}
|
|
3682
3920
|
);
|
|
3683
3921
|
agent = created?.agent;
|
|
3922
|
+
if (agent) {
|
|
3923
|
+
this.readCache.set(this.agentListKey(state, chainId), {
|
|
3924
|
+
expiresAt: Date.now() + YIELDSEEKER_AGENT_LIST_CACHE_MS,
|
|
3925
|
+
value: {
|
|
3926
|
+
agents: [...agents, agent]
|
|
3927
|
+
}
|
|
3928
|
+
});
|
|
3929
|
+
}
|
|
3684
3930
|
}
|
|
3685
3931
|
if (!agent) return null;
|
|
3686
3932
|
this.assertAgent(agent);
|
|
3687
|
-
|
|
3688
|
-
state,
|
|
3689
|
-
chainId,
|
|
3690
|
-
`/users/${user.userId}/agents/${agent.agentId}/wallet`
|
|
3691
|
-
);
|
|
3692
|
-
if (!walletResponse?.agentWallet || !(0, import_viem6.isAddress)(walletResponse.agentWallet.walletAddress)) {
|
|
3693
|
-
throw this.invalidResponse("agent wallet");
|
|
3694
|
-
}
|
|
3695
|
-
return { user, agent, wallet: walletResponse.agentWallet, asset };
|
|
3933
|
+
return this.contextForAgent(state, chainId, user, agent, asset);
|
|
3696
3934
|
}
|
|
3697
3935
|
async loadPortfolio(state, chainId, options) {
|
|
3698
3936
|
const user = await this.resolveUser(state, chainId);
|
|
3699
|
-
const
|
|
3700
|
-
state,
|
|
3701
|
-
chainId,
|
|
3702
|
-
`/users/${user.userId}/agents`
|
|
3703
|
-
);
|
|
3704
|
-
if (!Array.isArray(response?.agents)) {
|
|
3705
|
-
throw this.invalidResponse("agent list");
|
|
3706
|
-
}
|
|
3937
|
+
const agents = await this.listAgents(state, chainId, user);
|
|
3707
3938
|
const contexts = [];
|
|
3708
|
-
for (const agent of
|
|
3939
|
+
for (const agent of agents) {
|
|
3709
3940
|
const asset = this.assetForAgent(agent);
|
|
3710
3941
|
if (!this.isOwneyAgent(agent) || !asset || agent.chainId !== chainId || agent.type !== "vault" || options.asset && options.asset !== asset) {
|
|
3711
3942
|
continue;
|
|
3712
3943
|
}
|
|
3713
3944
|
this.assertAgent(agent);
|
|
3714
|
-
|
|
3715
|
-
state,
|
|
3716
|
-
chainId,
|
|
3717
|
-
`/users/${user.userId}/agents/${agent.agentId}/wallet`
|
|
3718
|
-
);
|
|
3719
|
-
if (!walletResponse?.agentWallet || !(0, import_viem6.isAddress)(walletResponse.agentWallet.walletAddress)) {
|
|
3720
|
-
throw this.invalidResponse("agent wallet");
|
|
3721
|
-
}
|
|
3722
|
-
const context = {
|
|
3723
|
-
user,
|
|
3724
|
-
agent,
|
|
3725
|
-
wallet: walletResponse.agentWallet,
|
|
3726
|
-
asset
|
|
3727
|
-
};
|
|
3728
|
-
this.agentContexts.set(this.contextKey(state, chainId, asset), context);
|
|
3729
|
-
contexts.push(context);
|
|
3945
|
+
contexts.push(this.contextForAgent(state, chainId, user, agent, asset));
|
|
3730
3946
|
}
|
|
3947
|
+
const resolvedContexts = await Promise.all(contexts);
|
|
3731
3948
|
return Promise.all(
|
|
3732
|
-
|
|
3949
|
+
resolvedContexts.map(
|
|
3733
3950
|
(context) => this.loadPortfolioContext(state, chainId, context, options)
|
|
3734
3951
|
)
|
|
3735
3952
|
);
|
|
3736
3953
|
}
|
|
3737
3954
|
async loadPortfolioContext(state, chainId, context, options = {}) {
|
|
3955
|
+
const contextKey = this.contextKey(state, chainId, context.asset);
|
|
3738
3956
|
const [snapshot, positions, historic, actions] = await Promise.all([
|
|
3739
|
-
this.
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3957
|
+
this.cachedRead(
|
|
3958
|
+
`snapshot:${contextKey}`,
|
|
3959
|
+
YIELDSEEKER_PORTFOLIO_CACHE_MS,
|
|
3960
|
+
async () => {
|
|
3961
|
+
const response = await this.walletRequest(
|
|
3962
|
+
state,
|
|
3963
|
+
chainId,
|
|
3964
|
+
`${this.agentPath(context, "snapshot")}${query({
|
|
3965
|
+
shouldOnlyUseRecentValue: true,
|
|
3966
|
+
shouldAllowStaleOnError: true
|
|
3967
|
+
})}`
|
|
3968
|
+
);
|
|
3969
|
+
if (!response?.agentSnapshot) {
|
|
3970
|
+
throw this.invalidResponse("agent snapshot");
|
|
3971
|
+
}
|
|
3972
|
+
return response;
|
|
3973
|
+
}
|
|
3746
3974
|
),
|
|
3747
|
-
this.
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3975
|
+
this.cachedRead(
|
|
3976
|
+
`positions:${contextKey}`,
|
|
3977
|
+
YIELDSEEKER_PORTFOLIO_CACHE_MS,
|
|
3978
|
+
async () => {
|
|
3979
|
+
const response = await this.walletRequest(
|
|
3980
|
+
state,
|
|
3981
|
+
chainId,
|
|
3982
|
+
this.agentPath(context, "yield-positions")
|
|
3983
|
+
);
|
|
3984
|
+
if (!Array.isArray(response?.yieldPositions)) {
|
|
3985
|
+
throw this.invalidResponse("yield positions");
|
|
3986
|
+
}
|
|
3987
|
+
return response;
|
|
3988
|
+
}
|
|
3751
3989
|
),
|
|
3752
|
-
options.historic ? this.
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
this.
|
|
3990
|
+
options.historic ? this.cachedRead(
|
|
3991
|
+
`historic:${contextKey}`,
|
|
3992
|
+
YIELDSEEKER_ACTIVITY_CACHE_MS,
|
|
3993
|
+
() => this.walletRequest(
|
|
3994
|
+
state,
|
|
3995
|
+
chainId,
|
|
3996
|
+
this.agentPath(context, "wallet/historic-position")
|
|
3997
|
+
)
|
|
3756
3998
|
) : Promise.resolve(void 0),
|
|
3757
|
-
options.actions ? this.
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
this.
|
|
3999
|
+
options.actions ? this.cachedRead(
|
|
4000
|
+
`actions:${contextKey}`,
|
|
4001
|
+
YIELDSEEKER_ACTIVITY_CACHE_MS,
|
|
4002
|
+
() => this.walletRequest(
|
|
4003
|
+
state,
|
|
4004
|
+
chainId,
|
|
4005
|
+
this.agentPath(context, "actions")
|
|
4006
|
+
)
|
|
3761
4007
|
) : Promise.resolve(void 0)
|
|
3762
4008
|
]);
|
|
3763
4009
|
if (!snapshot?.agentSnapshot) {
|
|
@@ -3783,7 +4029,7 @@ var YieldseekerAgent = class {
|
|
|
3783
4029
|
this.agentPath(context, "deploy"),
|
|
3784
4030
|
{ method: "POST", body: {} }
|
|
3785
4031
|
);
|
|
3786
|
-
if (!deployed?.agentWallet || !(0,
|
|
4032
|
+
if (!deployed?.agentWallet || !(0, import_viem7.isAddress)(deployed.agentWallet.walletAddress) || deployed.agentWallet.walletAddress.toLowerCase() !== walletAddress) {
|
|
3787
4033
|
throw this.invalidResponse("agent deployment", {
|
|
3788
4034
|
reason: "Deploy did not return the expected Agent Wallet."
|
|
3789
4035
|
});
|
|
@@ -3791,6 +4037,13 @@ var YieldseekerAgent = class {
|
|
|
3791
4037
|
context.wallet = deployed.agentWallet;
|
|
3792
4038
|
}
|
|
3793
4039
|
async refreshSnapshotAfterMovement(state, chainId, context, movement) {
|
|
4040
|
+
const contextKey = this.contextKey(state, chainId, context.asset);
|
|
4041
|
+
const invalidatePortfolio = () => {
|
|
4042
|
+
for (const kind of ["snapshot", "positions", "historic", "actions"]) {
|
|
4043
|
+
this.readCache.delete(`${kind}:${contextKey}`);
|
|
4044
|
+
}
|
|
4045
|
+
};
|
|
4046
|
+
invalidatePortfolio();
|
|
3794
4047
|
try {
|
|
3795
4048
|
const response = await this.walletRequest(
|
|
3796
4049
|
state,
|
|
@@ -3807,6 +4060,8 @@ var YieldseekerAgent = class {
|
|
|
3807
4060
|
`[owney-sdk] Yieldseeker ${movement} snapshot refresh failed:`,
|
|
3808
4061
|
error
|
|
3809
4062
|
);
|
|
4063
|
+
} finally {
|
|
4064
|
+
invalidatePortfolio();
|
|
3810
4065
|
}
|
|
3811
4066
|
}
|
|
3812
4067
|
agentPath(context, suffix) {
|
|
@@ -3857,6 +4112,7 @@ var YieldseekerAgent = class {
|
|
|
3857
4112
|
code,
|
|
3858
4113
|
`Yieldseeker request failed: ${error.providerCode}.`,
|
|
3859
4114
|
{
|
|
4115
|
+
rpcSource: "agent-api",
|
|
3860
4116
|
statusCode: error.status,
|
|
3861
4117
|
providerCode: error.providerCode,
|
|
3862
4118
|
...error.responseFields ? { fields: error.responseFields } : {}
|
|
@@ -3869,32 +4125,37 @@ var YieldseekerAgent = class {
|
|
|
3869
4125
|
return this.transactionExecutor(state, chainId, transaction);
|
|
3870
4126
|
}
|
|
3871
4127
|
this.assertTransaction(transaction, state, chainId);
|
|
3872
|
-
const account = (0,
|
|
3873
|
-
const walletClient = (0,
|
|
4128
|
+
const account = (0, import_viem7.getAddress)(state.walletAddress);
|
|
4129
|
+
const walletClient = (0, import_viem7.createWalletClient)({
|
|
3874
4130
|
account,
|
|
3875
4131
|
chain: import_chains3.base,
|
|
3876
|
-
transport: (0,
|
|
4132
|
+
transport: (0, import_viem7.custom)(state.provider)
|
|
3877
4133
|
});
|
|
3878
|
-
const
|
|
4134
|
+
const walletChainClient = (0, import_viem7.createPublicClient)({
|
|
3879
4135
|
chain: import_chains3.base,
|
|
3880
|
-
transport: (0,
|
|
4136
|
+
transport: (0, import_viem7.custom)(state.provider)
|
|
3881
4137
|
});
|
|
3882
4138
|
await ensureWalletOnChain(
|
|
3883
|
-
|
|
4139
|
+
walletChainClient,
|
|
3884
4140
|
walletClient,
|
|
3885
4141
|
8453
|
|
3886
4142
|
);
|
|
3887
4143
|
const hash = await walletClient.sendTransaction({
|
|
3888
4144
|
account,
|
|
3889
4145
|
chain: import_chains3.base,
|
|
3890
|
-
to: (0,
|
|
4146
|
+
to: (0, import_viem7.getAddress)(transaction.to),
|
|
3891
4147
|
data: transaction.data,
|
|
3892
4148
|
value: BigInt(transaction.value)
|
|
3893
4149
|
});
|
|
3894
|
-
const receipt = await
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
4150
|
+
const receipt = await withPaidRpcDiagnostics(
|
|
4151
|
+
() => this.getReceiptClient().waitForTransactionReceipt({
|
|
4152
|
+
hash,
|
|
4153
|
+
confirmations: 1
|
|
4154
|
+
}),
|
|
4155
|
+
8453,
|
|
4156
|
+
"eth_getTransactionReceipt",
|
|
4157
|
+
this.id
|
|
4158
|
+
);
|
|
3898
4159
|
if (receipt.status !== "success") {
|
|
3899
4160
|
throw new OwneyError(
|
|
3900
4161
|
"AGENT_TRANSACTION_REVERTED",
|
|
@@ -3910,14 +4171,15 @@ var YieldseekerAgent = class {
|
|
|
3910
4171
|
await this.unwindReceiptWaiter(state, chainId, transactionHash);
|
|
3911
4172
|
return;
|
|
3912
4173
|
}
|
|
3913
|
-
const
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
4174
|
+
const receipt = await withPaidRpcDiagnostics(
|
|
4175
|
+
() => this.getReceiptClient().waitForTransactionReceipt({
|
|
4176
|
+
hash: transactionHash,
|
|
4177
|
+
confirmations: 1
|
|
4178
|
+
}),
|
|
4179
|
+
8453,
|
|
4180
|
+
"eth_getTransactionReceipt",
|
|
4181
|
+
this.id
|
|
4182
|
+
);
|
|
3921
4183
|
if (receipt.status !== "success") {
|
|
3922
4184
|
throw new OwneyError(
|
|
3923
4185
|
"AGENT_TRANSACTION_REVERTED",
|
|
@@ -3928,12 +4190,12 @@ var YieldseekerAgent = class {
|
|
|
3928
4190
|
}
|
|
3929
4191
|
}
|
|
3930
4192
|
assertTransaction(transaction, state, chainId) {
|
|
3931
|
-
if (!transaction || typeof transaction.from !== "string" || !(0,
|
|
4193
|
+
if (!transaction || typeof transaction.from !== "string" || !(0, import_viem7.isAddress)(transaction.from) || typeof transaction.to !== "string" || !(0, import_viem7.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_viem7.getAddress)(transaction.from) !== (0, import_viem7.getAddress)(state.walletAddress)) {
|
|
3932
4194
|
throw this.invalidResponse("transaction");
|
|
3933
4195
|
}
|
|
3934
4196
|
}
|
|
3935
4197
|
assertAgent(agent) {
|
|
3936
|
-
if (typeof agent.agentId !== "string" || typeof agent.assetAddress !== "string" || !(0,
|
|
4198
|
+
if (typeof agent.agentId !== "string" || typeof agent.assetAddress !== "string" || !(0, import_viem7.isAddress)(agent.assetAddress) || agent.chainId !== 8453) {
|
|
3937
4199
|
throw this.invalidResponse("agent");
|
|
3938
4200
|
}
|
|
3939
4201
|
}
|
|
@@ -4086,7 +4348,7 @@ async function withFailureReporting(apiKey, agentType, fn, baseUrl) {
|
|
|
4086
4348
|
}
|
|
4087
4349
|
|
|
4088
4350
|
// src/lib/helpers/withdraw-helper.ts
|
|
4089
|
-
var
|
|
4351
|
+
var import_viem8 = require("viem");
|
|
4090
4352
|
function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
|
|
4091
4353
|
const target = asset.toUpperCase();
|
|
4092
4354
|
return agents.map((agent) => {
|
|
@@ -4094,7 +4356,7 @@ function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decima
|
|
|
4094
4356
|
const tokenBalance = agentBalance?.tokens.find(
|
|
4095
4357
|
(t) => t.chainId === chainId && t.asset.toUpperCase() === target
|
|
4096
4358
|
);
|
|
4097
|
-
let balance = tokenBalance ? (0,
|
|
4359
|
+
let balance = tokenBalance ? (0, import_viem8.parseUnits)(tokenBalance.amount, decimals) : 0n;
|
|
4098
4360
|
if (agent.balanceComposition === "tokens-plus-positions") {
|
|
4099
4361
|
const chainNameById = {
|
|
4100
4362
|
1: "ETHEREUM",
|
|
@@ -4113,7 +4375,7 @@ function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decima
|
|
|
4113
4375
|
} catch {
|
|
4114
4376
|
}
|
|
4115
4377
|
}
|
|
4116
|
-
balance += (0,
|
|
4378
|
+
balance += (0, import_viem8.parseUnits)(position2.amount, decimals);
|
|
4117
4379
|
}
|
|
4118
4380
|
}
|
|
4119
4381
|
return { agent, balance };
|
|
@@ -4272,15 +4534,50 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
|
|
|
4272
4534
|
}
|
|
4273
4535
|
|
|
4274
4536
|
// src/client.ts
|
|
4275
|
-
var
|
|
4537
|
+
var import_viem12 = require("viem");
|
|
4276
4538
|
var import_chains4 = require("viem/chains");
|
|
4277
4539
|
|
|
4278
4540
|
// src/lib/sponsored-token-batch.ts
|
|
4279
|
-
var
|
|
4541
|
+
var import_viem10 = require("viem");
|
|
4280
4542
|
|
|
4281
4543
|
// src/lib/permit2-batch.ts
|
|
4282
|
-
var
|
|
4544
|
+
var import_viem9 = require("viem");
|
|
4283
4545
|
var BATCH_PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
4546
|
+
var BASE_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
|
|
4547
|
+
var MULTICALL3_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976CA11";
|
|
4548
|
+
var ERC2612_PERMIT_TYPES = {
|
|
4549
|
+
Permit: [
|
|
4550
|
+
{ name: "owner", type: "address" },
|
|
4551
|
+
{ name: "spender", type: "address" },
|
|
4552
|
+
{ name: "value", type: "uint256" },
|
|
4553
|
+
{ name: "nonce", type: "uint256" },
|
|
4554
|
+
{ name: "deadline", type: "uint256" }
|
|
4555
|
+
]
|
|
4556
|
+
};
|
|
4557
|
+
var ERC2612_READ_ABI = (0, import_viem9.parseAbi)([
|
|
4558
|
+
"function name() view returns (string)",
|
|
4559
|
+
"function version() view returns (string)",
|
|
4560
|
+
"function nonces(address owner) view returns (uint256)"
|
|
4561
|
+
]);
|
|
4562
|
+
function erc2612TypedData(input) {
|
|
4563
|
+
return {
|
|
4564
|
+
domain: {
|
|
4565
|
+
name: input.permit.tokenName,
|
|
4566
|
+
version: input.permit.tokenVersion,
|
|
4567
|
+
chainId: input.chainId,
|
|
4568
|
+
verifyingContract: input.token
|
|
4569
|
+
},
|
|
4570
|
+
types: ERC2612_PERMIT_TYPES,
|
|
4571
|
+
primaryType: "Permit",
|
|
4572
|
+
message: {
|
|
4573
|
+
owner: input.owner,
|
|
4574
|
+
spender: BATCH_PERMIT2_ADDRESS,
|
|
4575
|
+
value: BigInt(input.permit.value),
|
|
4576
|
+
nonce: BigInt(input.permit.nonce),
|
|
4577
|
+
deadline: BigInt(input.permit.deadline)
|
|
4578
|
+
}
|
|
4579
|
+
};
|
|
4580
|
+
}
|
|
4284
4581
|
var PERMIT_BATCH_TYPES = {
|
|
4285
4582
|
PermitBatchWitnessTransferFrom: [
|
|
4286
4583
|
{ name: "permitted", type: "TokenPermissions[]" },
|
|
@@ -4295,7 +4592,7 @@ var PERMIT_BATCH_TYPES = {
|
|
|
4295
4592
|
{ name: "amount", type: "uint256" }
|
|
4296
4593
|
]
|
|
4297
4594
|
};
|
|
4298
|
-
var PERMIT2_BATCH_ABI = (0,
|
|
4595
|
+
var PERMIT2_BATCH_ABI = (0, import_viem9.parseAbi)([
|
|
4299
4596
|
"struct TokenPermissions { address token; uint256 amount; }",
|
|
4300
4597
|
"struct PermitBatchTransferFrom { TokenPermissions[] permitted; uint256 nonce; uint256 deadline; }",
|
|
4301
4598
|
"struct SignatureTransferDetails { address to; uint256 requestedAmount; }",
|
|
@@ -4354,7 +4651,7 @@ function clear(key2) {
|
|
|
4354
4651
|
else window.localStorage.removeItem(key2);
|
|
4355
4652
|
}
|
|
4356
4653
|
function sponsorTokenBatch(i) {
|
|
4357
|
-
const key2 = `owney.token-batch.v1:${(0,
|
|
4654
|
+
const key2 = `owney.token-batch.v1:${(0, import_viem10.keccak256)((0, import_viem10.toBytes)(i.apiKey))}:${i.baseUrl ?? "default"}:${i.chainId}:${i.owner.toLowerCase()}:${i.token.toLowerCase()}`;
|
|
4358
4655
|
const plan = planOf(i.transfers);
|
|
4359
4656
|
const active = inflight.get(key2);
|
|
4360
4657
|
if (active) {
|
|
@@ -4385,7 +4682,7 @@ async function execute(i, key2, plan) {
|
|
|
4385
4682
|
baseUrl: i.baseUrl,
|
|
4386
4683
|
body
|
|
4387
4684
|
});
|
|
4388
|
-
if (!prepared.serializedTransaction || (0,
|
|
4685
|
+
if (!prepared.serializedTransaction || (0, import_viem10.keccak256)(prepared.serializedTransaction) !== prepared.txHash)
|
|
4389
4686
|
throw new Error(
|
|
4390
4687
|
"Sponsorship API did not return a valid prepared transaction."
|
|
4391
4688
|
);
|
|
@@ -4400,7 +4697,7 @@ async function execute(i, key2, plan) {
|
|
|
4400
4697
|
baseUrl: i.baseUrl,
|
|
4401
4698
|
body
|
|
4402
4699
|
});
|
|
4403
|
-
if (result.txHash !== (0,
|
|
4700
|
+
if (result.txHash !== (0, import_viem10.keccak256)(body.serializedTransaction))
|
|
4404
4701
|
throw new Error(
|
|
4405
4702
|
"Sponsorship receipt does not match the pending transaction."
|
|
4406
4703
|
);
|
|
@@ -4415,7 +4712,7 @@ async function execute(i, key2, plan) {
|
|
|
4415
4712
|
const saved = read(key2);
|
|
4416
4713
|
if (saved) {
|
|
4417
4714
|
const previous = JSON.parse(saved);
|
|
4418
|
-
if (previous.chainId !== i.chainId || !(0,
|
|
4715
|
+
if (previous.chainId !== i.chainId || !(0, import_viem10.isAddressEqual)(previous.from, i.owner) || !(0, import_viem10.isAddressEqual)(previous.token, i.token) || planOf(previous.transfers) !== plan)
|
|
4419
4716
|
throw new Error(
|
|
4420
4717
|
"Retry the previous token deposit and agent split first to reconcile its status."
|
|
4421
4718
|
);
|
|
@@ -4432,28 +4729,67 @@ async function execute(i, key2, plan) {
|
|
|
4432
4729
|
"DEPOSIT_INSUFFICIENT_BALANCE",
|
|
4433
4730
|
"Insufficient token balance for this deposit."
|
|
4434
4731
|
);
|
|
4435
|
-
if (allowance < total)
|
|
4732
|
+
if (allowance < total && (i.chainId !== 8453 || !(0, import_viem10.isAddressEqual)(i.token, BASE_USDC_ADDRESS)))
|
|
4436
4733
|
throw new OwneyError(
|
|
4437
4734
|
"PERMIT2_APPROVAL_REQUIRED",
|
|
4438
4735
|
"token deposits need a one-time Permit2 approval."
|
|
4439
4736
|
);
|
|
4440
|
-
const
|
|
4737
|
+
const now = (await i.pub.getBlock()).timestamp;
|
|
4738
|
+
let erc2612Permit;
|
|
4739
|
+
if (allowance < total) {
|
|
4740
|
+
const [tokenName, tokenVersion, permitNonce] = await Promise.all([
|
|
4741
|
+
i.pub.readContract({
|
|
4742
|
+
address: i.token,
|
|
4743
|
+
abi: ERC2612_READ_ABI,
|
|
4744
|
+
functionName: "name"
|
|
4745
|
+
}),
|
|
4746
|
+
i.pub.readContract({
|
|
4747
|
+
address: i.token,
|
|
4748
|
+
abi: ERC2612_READ_ABI,
|
|
4749
|
+
functionName: "version"
|
|
4750
|
+
}),
|
|
4751
|
+
i.pub.readContract({
|
|
4752
|
+
address: i.token,
|
|
4753
|
+
abi: ERC2612_READ_ABI,
|
|
4754
|
+
functionName: "nonces",
|
|
4755
|
+
args: [i.owner]
|
|
4756
|
+
})
|
|
4757
|
+
]);
|
|
4758
|
+
const unsignedPermit = {
|
|
4759
|
+
value: MAX_UINT256.toString(),
|
|
4760
|
+
nonce: permitNonce.toString(),
|
|
4761
|
+
deadline: (now + 900n).toString(),
|
|
4762
|
+
tokenName,
|
|
4763
|
+
tokenVersion
|
|
4764
|
+
};
|
|
4765
|
+
const signature2 = await i.wallet.signTypedData({
|
|
4766
|
+
account: i.owner,
|
|
4767
|
+
...erc2612TypedData({
|
|
4768
|
+
chainId: 8453,
|
|
4769
|
+
token: i.token,
|
|
4770
|
+
owner: i.owner,
|
|
4771
|
+
permit: unsignedPermit
|
|
4772
|
+
})
|
|
4773
|
+
});
|
|
4774
|
+
erc2612Permit = { ...unsignedPermit, signature: signature2 };
|
|
4775
|
+
}
|
|
4776
|
+
const spender = erc2612Permit ? MULTICALL3_ADDRESS : await getSponsorRelayerAddress({
|
|
4441
4777
|
apiKey: i.apiKey,
|
|
4442
4778
|
baseUrl: i.baseUrl,
|
|
4443
4779
|
chainId: i.chainId
|
|
4444
4780
|
});
|
|
4445
|
-
const now = (await i.pub.getBlock()).timestamp;
|
|
4446
4781
|
const unsigned = {
|
|
4447
4782
|
chainId: i.chainId,
|
|
4448
4783
|
token: i.token,
|
|
4449
4784
|
from: i.owner,
|
|
4450
4785
|
transfers: i.transfers,
|
|
4451
4786
|
nonce: randomPermit2Nonce().toString(),
|
|
4452
|
-
deadline: (now + 900n).toString()
|
|
4787
|
+
deadline: (now + 900n).toString(),
|
|
4788
|
+
...erc2612Permit ? { erc2612Permit } : {}
|
|
4453
4789
|
};
|
|
4454
4790
|
const signature = await i.wallet.signTypedData({
|
|
4455
4791
|
account: i.owner,
|
|
4456
|
-
...batchTypedData(unsigned,
|
|
4792
|
+
...batchTypedData(unsigned, spender)
|
|
4457
4793
|
});
|
|
4458
4794
|
i.onApproved?.();
|
|
4459
4795
|
return send({ ...unsigned, signature });
|
|
@@ -4473,8 +4809,8 @@ function makeSponsoredTokenCallback(deps) {
|
|
|
4473
4809
|
"CHAIN_UNSUPPORTED",
|
|
4474
4810
|
`No sponsored token configured for chain ${chainId}`
|
|
4475
4811
|
);
|
|
4476
|
-
const pub = deps.getPublicClient(chainId), wallet = deps.getWalletClient(chainId);
|
|
4477
|
-
await ensureWalletOnChain(
|
|
4812
|
+
const pub = deps.getPublicClient(chainId), walletChain = deps.getWalletChainClient?.(chainId) ?? pub, wallet = deps.getWalletClient(chainId);
|
|
4813
|
+
await ensureWalletOnChain(walletChain, wallet, chainId);
|
|
4478
4814
|
return sponsorTokenBatch({
|
|
4479
4815
|
apiKey: deps.apiKey,
|
|
4480
4816
|
baseUrl: deps.baseUrl,
|
|
@@ -4570,7 +4906,7 @@ async function runAgentDepositBatch(chainId, legs, transfer) {
|
|
|
4570
4906
|
}
|
|
4571
4907
|
|
|
4572
4908
|
// src/lib/sponsored-calls-deposit.ts
|
|
4573
|
-
var
|
|
4909
|
+
var import_viem11 = require("viem");
|
|
4574
4910
|
var DEFAULT_POLL_INTERVAL_MS = 1500;
|
|
4575
4911
|
var DEFAULT_MAX_POLLS = 30;
|
|
4576
4912
|
async function paymasterSupported(provider, owner, chainId) {
|
|
@@ -4578,7 +4914,7 @@ async function paymasterSupported(provider, owner, chainId) {
|
|
|
4578
4914
|
method: "wallet_getCapabilities",
|
|
4579
4915
|
params: [owner]
|
|
4580
4916
|
});
|
|
4581
|
-
const forChain = caps?.[(0,
|
|
4917
|
+
const forChain = caps?.[(0, import_viem11.toHex)(chainId)] ?? caps?.[String(chainId)];
|
|
4582
4918
|
return Boolean(forChain?.paymasterService?.supported);
|
|
4583
4919
|
}
|
|
4584
4920
|
function makeSponsoredCallsCallback(deps) {
|
|
@@ -4615,8 +4951,8 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
4615
4951
|
const calls = transfers.map((transfer) => ({
|
|
4616
4952
|
to: token,
|
|
4617
4953
|
value: "0x0",
|
|
4618
|
-
data: (0,
|
|
4619
|
-
abi:
|
|
4954
|
+
data: (0, import_viem11.encodeFunctionData)({
|
|
4955
|
+
abi: import_viem11.erc20Abi,
|
|
4620
4956
|
functionName: "transfer",
|
|
4621
4957
|
args: [transfer.to, BigInt(transfer.amount)]
|
|
4622
4958
|
})
|
|
@@ -4654,7 +4990,7 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
4654
4990
|
{
|
|
4655
4991
|
version: "2.0.0",
|
|
4656
4992
|
from: deps.ownerAddress,
|
|
4657
|
-
chainId: (0,
|
|
4993
|
+
chainId: (0, import_viem11.toHex)(chainId),
|
|
4658
4994
|
atomicRequired: transfers.length > 1,
|
|
4659
4995
|
calls,
|
|
4660
4996
|
capabilities: {
|
|
@@ -4714,6 +5050,8 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
4714
5050
|
}
|
|
4715
5051
|
|
|
4716
5052
|
// src/client.ts
|
|
5053
|
+
var PERMIT2_ALLOWANCE_VERIFY_ATTEMPTS = 6;
|
|
5054
|
+
var PERMIT2_ALLOWANCE_VERIFY_DELAY_MS = 250;
|
|
4717
5055
|
function encodeMultiAgentCursor(map) {
|
|
4718
5056
|
return Buffer.from(JSON.stringify(map), "utf8").toString("base64");
|
|
4719
5057
|
}
|
|
@@ -4774,6 +5112,7 @@ var OwneySDK = class {
|
|
|
4774
5112
|
// leave every user's agent profile alone.
|
|
4775
5113
|
orgAgentConfig;
|
|
4776
5114
|
orgAgentConfigPromise = null;
|
|
5115
|
+
rpcUrls;
|
|
4777
5116
|
zyfaiRpcUrls;
|
|
4778
5117
|
yieldseekerApiBaseUrl;
|
|
4779
5118
|
yieldseekerSiweOrigin;
|
|
@@ -4798,6 +5137,7 @@ var OwneySDK = class {
|
|
|
4798
5137
|
constructor(config) {
|
|
4799
5138
|
this.apiKey = config.apiKey;
|
|
4800
5139
|
if (config.debug) setOwneyDebug(true);
|
|
5140
|
+
this.rpcUrls = config.rpcUrls;
|
|
4801
5141
|
this.zyfaiRpcUrls = config.zyfaiRpcUrls;
|
|
4802
5142
|
this.yieldseekerApiBaseUrl = config.yieldseekerApiBaseUrl;
|
|
4803
5143
|
this.yieldseekerSiweOrigin = config.yieldseekerSiweOrigin;
|
|
@@ -4888,6 +5228,9 @@ var OwneySDK = class {
|
|
|
4888
5228
|
}
|
|
4889
5229
|
return this.state.provider;
|
|
4890
5230
|
}
|
|
5231
|
+
getPaidRpcClient(chainId) {
|
|
5232
|
+
return createPaidRpcClient(VIEM_CHAIN2[chainId], this.rpcUrls);
|
|
5233
|
+
}
|
|
4891
5234
|
/** Builds the default USDC batch callback for the connected wallet. */
|
|
4892
5235
|
getDefaultSponsoredCallback(onApproved) {
|
|
4893
5236
|
if (!onApproved && this.cachedSponsoredCallback)
|
|
@@ -4903,14 +5246,15 @@ var OwneySDK = class {
|
|
|
4903
5246
|
// Casts work around viem's chain-narrowed Client vs the generic
|
|
4904
5247
|
// PublicClient/WalletClient param types — structurally identical at
|
|
4905
5248
|
// runtime, but the two share a name TS treats as unrelated.
|
|
4906
|
-
getPublicClient: (cid) => (
|
|
5249
|
+
getPublicClient: (cid) => this.getPaidRpcClient(cid),
|
|
5250
|
+
getWalletChainClient: (cid) => (0, import_viem12.createPublicClient)({
|
|
4907
5251
|
chain: VIEM_CHAIN2[cid],
|
|
4908
|
-
transport: (0,
|
|
5252
|
+
transport: (0, import_viem12.custom)(provider)
|
|
4909
5253
|
}),
|
|
4910
|
-
getWalletClient: (cid) => (0,
|
|
5254
|
+
getWalletClient: (cid) => (0, import_viem12.createWalletClient)({
|
|
4911
5255
|
account: owner,
|
|
4912
5256
|
chain: VIEM_CHAIN2[cid],
|
|
4913
|
-
transport: (0,
|
|
5257
|
+
transport: (0, import_viem12.custom)(provider)
|
|
4914
5258
|
})
|
|
4915
5259
|
});
|
|
4916
5260
|
if (!onApproved) this.cachedSponsoredCallback = callback;
|
|
@@ -4953,14 +5297,15 @@ var OwneySDK = class {
|
|
|
4953
5297
|
// Casts work around viem's chain-narrowed Client vs the generic
|
|
4954
5298
|
// PublicClient/WalletClient param types — structurally identical at
|
|
4955
5299
|
// runtime, but the two share a name TS treats as unrelated.
|
|
4956
|
-
getPublicClient: (cid) => (
|
|
5300
|
+
getPublicClient: (cid) => this.getPaidRpcClient(cid),
|
|
5301
|
+
getWalletChainClient: (cid) => (0, import_viem12.createPublicClient)({
|
|
4957
5302
|
chain: VIEM_CHAIN2[cid],
|
|
4958
|
-
transport: (0,
|
|
5303
|
+
transport: (0, import_viem12.custom)(provider)
|
|
4959
5304
|
}),
|
|
4960
|
-
getWalletClient: (cid) => (0,
|
|
5305
|
+
getWalletClient: (cid) => (0, import_viem12.createWalletClient)({
|
|
4961
5306
|
account: owner,
|
|
4962
5307
|
chain: VIEM_CHAIN2[cid],
|
|
4963
|
-
transport: (0,
|
|
5308
|
+
transport: (0, import_viem12.custom)(provider)
|
|
4964
5309
|
})
|
|
4965
5310
|
});
|
|
4966
5311
|
if (!onApproved) this.cachedWethSponsoredCallback = callback;
|
|
@@ -5066,12 +5411,17 @@ var OwneySDK = class {
|
|
|
5066
5411
|
createAgent(agentId, key2) {
|
|
5067
5412
|
if (agentId === "zyfai") {
|
|
5068
5413
|
if (!key2) return null;
|
|
5069
|
-
return new ZyfaiAgent(
|
|
5414
|
+
return new ZyfaiAgent(
|
|
5415
|
+
key2,
|
|
5416
|
+
this.rpcUrls ?? this.zyfaiRpcUrls,
|
|
5417
|
+
this.referralSource
|
|
5418
|
+
);
|
|
5070
5419
|
}
|
|
5071
5420
|
if (agentId === "yieldseeker") {
|
|
5072
5421
|
return new YieldseekerAgent(this.apiKey, {
|
|
5073
5422
|
auth: { origin: this.yieldseekerSiweOrigin },
|
|
5074
|
-
baseUrl: this.yieldseekerApiBaseUrl ?? getYieldseekerProxyBaseUrl(this.routingApiBaseUrl)
|
|
5423
|
+
baseUrl: this.yieldseekerApiBaseUrl ?? getYieldseekerProxyBaseUrl(this.routingApiBaseUrl),
|
|
5424
|
+
rpcUrls: this.rpcUrls
|
|
5075
5425
|
});
|
|
5076
5426
|
}
|
|
5077
5427
|
return null;
|
|
@@ -5362,7 +5712,8 @@ var OwneySDK = class {
|
|
|
5362
5712
|
);
|
|
5363
5713
|
await this.approvePermit2(
|
|
5364
5714
|
asset,
|
|
5365
|
-
requiredAmount
|
|
5715
|
+
requiredAmount,
|
|
5716
|
+
cid
|
|
5366
5717
|
);
|
|
5367
5718
|
return batchTransfer(cid, transfers);
|
|
5368
5719
|
}
|
|
@@ -5406,10 +5757,12 @@ var OwneySDK = class {
|
|
|
5406
5757
|
* Invokes `agent.deposit` with the resolved sponsored callback, composing
|
|
5407
5758
|
* two independent auto-recovery mechanisms:
|
|
5408
5759
|
*
|
|
5409
|
-
* 1. Missing Permit2 allowance
|
|
5410
|
-
* callback and the attempt fails with
|
|
5411
|
-
*
|
|
5412
|
-
*
|
|
5760
|
+
* 1. Missing Permit2 allowance outside the atomic Base-USDC path: when the
|
|
5761
|
+
* app did not supply its own callback and the attempt fails with
|
|
5762
|
+
* `PERMIT2_APPROVAL_REQUIRED`, this is the wallet's first Permit2 deposit
|
|
5763
|
+
* for that token. Base USDC bundles a gasless ERC-2612 approval inside
|
|
5764
|
+
* its sponsored deposit and never reaches this branch. Other tokens send
|
|
5765
|
+
* the one-time user-paid Permit2 approval via `approvePermit2()` and
|
|
5413
5766
|
* retry the SAME sponsored attempt once. Bounded to one approval attempt
|
|
5414
5767
|
* per call so a wallet/agent that keeps reporting the allowance as
|
|
5415
5768
|
* missing can't loop forever. If `approvePermit2()` itself throws (e.g.
|
|
@@ -5452,7 +5805,8 @@ var OwneySDK = class {
|
|
|
5452
5805
|
);
|
|
5453
5806
|
await this.approvePermit2(
|
|
5454
5807
|
asset,
|
|
5455
|
-
BigInt(amount)
|
|
5808
|
+
BigInt(amount),
|
|
5809
|
+
chainId
|
|
5456
5810
|
);
|
|
5457
5811
|
continue;
|
|
5458
5812
|
}
|
|
@@ -5599,6 +5953,32 @@ var OwneySDK = class {
|
|
|
5599
5953
|
}
|
|
5600
5954
|
return eligible;
|
|
5601
5955
|
}
|
|
5956
|
+
/**
|
|
5957
|
+
* Run owner-approved withdrawals before relayer-only withdrawals. Wallet
|
|
5958
|
+
* approval is the only point at which the user can cancel the aggregate
|
|
5959
|
+
* operation, so no relayer leg should commit before it has completed.
|
|
5960
|
+
*/
|
|
5961
|
+
orderAgentsForWithdrawal(agents) {
|
|
5962
|
+
return agents.map((agent, index) => ({ agent, index })).sort((left, right) => {
|
|
5963
|
+
const approvalOrder = Number(Boolean(right.agent.withdrawalRequiresWalletApproval)) - Number(Boolean(left.agent.withdrawalRequiresWalletApproval));
|
|
5964
|
+
return approvalOrder || left.index - right.index;
|
|
5965
|
+
}).map(({ agent }) => agent);
|
|
5966
|
+
}
|
|
5967
|
+
isUserRejectedWithdrawal(error) {
|
|
5968
|
+
let current = error;
|
|
5969
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5970
|
+
while (current && typeof current === "object" && !seen.has(current)) {
|
|
5971
|
+
seen.add(current);
|
|
5972
|
+
const candidate = current;
|
|
5973
|
+
if (candidate.code === 4001 || candidate.code === "4001") return true;
|
|
5974
|
+
const message = [candidate.message, candidate.shortMessage].filter((value) => typeof value === "string").join(" ");
|
|
5975
|
+
if (/user (?:rejected|denied)|rejected by user/i.test(message)) {
|
|
5976
|
+
return true;
|
|
5977
|
+
}
|
|
5978
|
+
current = candidate.cause;
|
|
5979
|
+
}
|
|
5980
|
+
return false;
|
|
5981
|
+
}
|
|
5602
5982
|
// --- Fund operations ---
|
|
5603
5983
|
/**
|
|
5604
5984
|
* Withdraw funds from a specific agent, or all agents that support the active chain+asset if agentId is omitted.
|
|
@@ -5634,13 +6014,15 @@ var OwneySDK = class {
|
|
|
5634
6014
|
);
|
|
5635
6015
|
}
|
|
5636
6016
|
const eligibleAgents = this.getEligibleAgents(chainId, asset);
|
|
6017
|
+
const withdrawalAgents = this.orderAgentsForWithdrawal(eligibleAgents);
|
|
5637
6018
|
if (!amount) {
|
|
5638
6019
|
const results2 = {};
|
|
5639
6020
|
const agentErrors2 = {};
|
|
5640
|
-
for (const agent of
|
|
6021
|
+
for (const agent of withdrawalAgents) {
|
|
5641
6022
|
try {
|
|
5642
6023
|
results2[agent.id] = await agent.withdraw(state, chainId, token);
|
|
5643
6024
|
} catch (err) {
|
|
6025
|
+
if (this.isUserRejectedWithdrawal(err)) throw err;
|
|
5644
6026
|
console.error(`withdraw failed for agent "${agent.id}":`, err);
|
|
5645
6027
|
agentErrors2[agent.id] = err instanceof Error ? err.message : String(err);
|
|
5646
6028
|
const code = err instanceof OwneyError ? err.code : "SDK_AGENT_FAILURE";
|
|
@@ -5721,12 +6103,13 @@ var OwneySDK = class {
|
|
|
5721
6103
|
planned: 0n
|
|
5722
6104
|
}));
|
|
5723
6105
|
const plans = [...disabledPlans, ...enabledPlans];
|
|
6106
|
+
const orderedPlans = this.orderAgentsForWithdrawal(plans.map((p) => p.agent)).map((agent) => plans.find((plan) => plan.agent === agent));
|
|
5724
6107
|
const results = {};
|
|
5725
6108
|
const agentErrors = {
|
|
5726
6109
|
...aggregated.agentErrors ?? {}
|
|
5727
6110
|
};
|
|
5728
|
-
for (let i = 0; i <
|
|
5729
|
-
const p =
|
|
6111
|
+
for (let i = 0; i < orderedPlans.length; i++) {
|
|
6112
|
+
const p = orderedPlans[i];
|
|
5730
6113
|
if (p.planned === 0n) continue;
|
|
5731
6114
|
try {
|
|
5732
6115
|
results[p.agent.id] = await p.agent.withdraw(
|
|
@@ -5736,6 +6119,7 @@ var OwneySDK = class {
|
|
|
5736
6119
|
p.planned.toString()
|
|
5737
6120
|
);
|
|
5738
6121
|
} catch (err) {
|
|
6122
|
+
if (this.isUserRejectedWithdrawal(err)) throw err;
|
|
5739
6123
|
console.error(`withdraw failed for agent "${p.agent.id}":`, err);
|
|
5740
6124
|
agentErrors[p.agent.id] = err instanceof Error ? err.message : String(err);
|
|
5741
6125
|
const code = err instanceof OwneyError ? err.code : "SDK_AGENT_FAILURE";
|
|
@@ -5747,7 +6131,7 @@ var OwneySDK = class {
|
|
|
5747
6131
|
);
|
|
5748
6132
|
const failedAmount = p.planned;
|
|
5749
6133
|
p.planned = 0n;
|
|
5750
|
-
redistributeShare(
|
|
6134
|
+
redistributeShare(orderedPlans, i, failedAmount);
|
|
5751
6135
|
}
|
|
5752
6136
|
}
|
|
5753
6137
|
if (Object.keys(results).length === 0) {
|
|
@@ -6175,14 +6559,16 @@ var OwneySDK = class {
|
|
|
6175
6559
|
* User-paid approval of Permit2 on the selected token for the active chain.
|
|
6176
6560
|
* Grants the maximum ERC20 allowance so later deposits do not require another
|
|
6177
6561
|
* approval. Resolves after one confirmation so the subsequent deposit attempt
|
|
6178
|
-
* sees the new allowance.
|
|
6562
|
+
* sees the new allowance. Deposit retries pass their captured chain id so a
|
|
6563
|
+
* concurrent activation cannot redirect the approval to another network.
|
|
6179
6564
|
*
|
|
6180
6565
|
* @param requiredAmount Raw base-unit amount the pending deposit must cover.
|
|
6566
|
+
* @param expectedChainId Chain captured by the deposit that requested approval.
|
|
6181
6567
|
* @returns the approval transaction hash.
|
|
6182
6568
|
*/
|
|
6183
|
-
async approvePermit2(asset = "WETH", requiredAmount = 0n) {
|
|
6569
|
+
async approvePermit2(asset = "WETH", requiredAmount = 0n, expectedChainId) {
|
|
6184
6570
|
const state = this.requireState();
|
|
6185
|
-
const chainId = this.requireChainId();
|
|
6571
|
+
const chainId = expectedChainId ?? this.requireChainId();
|
|
6186
6572
|
this.getEligibleAgents(chainId, asset, { excludeDisabled: true });
|
|
6187
6573
|
const token = sponsoredTokensFor(asset)[chainId];
|
|
6188
6574
|
if (!token) {
|
|
@@ -6192,16 +6578,18 @@ var OwneySDK = class {
|
|
|
6192
6578
|
);
|
|
6193
6579
|
}
|
|
6194
6580
|
const provider = this.requireConnectedProvider();
|
|
6195
|
-
const
|
|
6581
|
+
const walletChainClient = (0, import_viem12.createPublicClient)({
|
|
6196
6582
|
chain: VIEM_CHAIN2[chainId],
|
|
6197
|
-
transport: (0,
|
|
6583
|
+
transport: (0, import_viem12.custom)(provider)
|
|
6198
6584
|
});
|
|
6585
|
+
const publicClient = this.getPaidRpcClient(chainId);
|
|
6199
6586
|
const approvalAmount = permit2ApprovalAmount(requiredAmount);
|
|
6200
|
-
const wallet = (0,
|
|
6587
|
+
const wallet = (0, import_viem12.createWalletClient)({
|
|
6201
6588
|
account: state.walletAddress,
|
|
6202
6589
|
chain: VIEM_CHAIN2[chainId],
|
|
6203
|
-
transport: (0,
|
|
6590
|
+
transport: (0, import_viem12.custom)(provider)
|
|
6204
6591
|
});
|
|
6592
|
+
await ensureWalletOnChain(walletChainClient, wallet, chainId);
|
|
6205
6593
|
const hash = await wallet.writeContract({
|
|
6206
6594
|
address: token,
|
|
6207
6595
|
abi: ERC20_ALLOWANCE_ABI,
|
|
@@ -6210,14 +6598,53 @@ var OwneySDK = class {
|
|
|
6210
6598
|
account: state.walletAddress,
|
|
6211
6599
|
chain: VIEM_CHAIN2[chainId]
|
|
6212
6600
|
});
|
|
6213
|
-
const receipt = await
|
|
6214
|
-
|
|
6215
|
-
|
|
6216
|
-
|
|
6601
|
+
const receipt = await withPaidRpcDiagnostics(
|
|
6602
|
+
() => publicClient.waitForTransactionReceipt({
|
|
6603
|
+
hash,
|
|
6604
|
+
confirmations: 1
|
|
6605
|
+
}),
|
|
6606
|
+
chainId,
|
|
6607
|
+
"eth_getTransactionReceipt"
|
|
6608
|
+
);
|
|
6217
6609
|
if (receipt.status !== "success") {
|
|
6218
6610
|
throw new Error(`Permit2 approval reverted (tx ${hash})`);
|
|
6219
6611
|
}
|
|
6220
|
-
|
|
6612
|
+
let observedAllowance = 0n;
|
|
6613
|
+
let verificationError;
|
|
6614
|
+
for (let attempt = 0; attempt < PERMIT2_ALLOWANCE_VERIFY_ATTEMPTS; attempt += 1) {
|
|
6615
|
+
try {
|
|
6616
|
+
observedAllowance = await readPermit2Allowance(
|
|
6617
|
+
publicClient,
|
|
6618
|
+
token,
|
|
6619
|
+
state.walletAddress,
|
|
6620
|
+
attempt === 0 ? receipt.blockNumber : void 0
|
|
6621
|
+
);
|
|
6622
|
+
verificationError = void 0;
|
|
6623
|
+
if (observedAllowance >= requiredAmount) return hash;
|
|
6624
|
+
} catch (error) {
|
|
6625
|
+
verificationError = error;
|
|
6626
|
+
}
|
|
6627
|
+
if (attempt + 1 < PERMIT2_ALLOWANCE_VERIFY_ATTEMPTS) {
|
|
6628
|
+
await new Promise(
|
|
6629
|
+
(resolve) => setTimeout(resolve, PERMIT2_ALLOWANCE_VERIFY_DELAY_MS)
|
|
6630
|
+
);
|
|
6631
|
+
}
|
|
6632
|
+
}
|
|
6633
|
+
throw new OwneyError(
|
|
6634
|
+
"PERMIT2_APPROVAL_REQUIRED",
|
|
6635
|
+
"Permit2 approval was confirmed, but the required token allowance was not observable.",
|
|
6636
|
+
{
|
|
6637
|
+
approvalConfirmed: true,
|
|
6638
|
+
approvalTxHash: hash,
|
|
6639
|
+
owner: state.walletAddress,
|
|
6640
|
+
token,
|
|
6641
|
+
spender: PERMIT2_ADDRESS,
|
|
6642
|
+
chainId,
|
|
6643
|
+
requiredAmount: requiredAmount.toString(),
|
|
6644
|
+
observedAllowance: observedAllowance.toString(),
|
|
6645
|
+
...verificationError instanceof Error ? { verificationError: verificationError.message } : {}
|
|
6646
|
+
}
|
|
6647
|
+
);
|
|
6221
6648
|
}
|
|
6222
6649
|
// --- Discovery (no wallet required) ---
|
|
6223
6650
|
/**
|
|
@@ -6322,7 +6749,7 @@ var OwneySDK = class {
|
|
|
6322
6749
|
};
|
|
6323
6750
|
|
|
6324
6751
|
// src/agents/zyfai/zyfai.siwx.ts
|
|
6325
|
-
var
|
|
6752
|
+
var import_viem13 = require("viem");
|
|
6326
6753
|
var import_siwe2 = require("siwe");
|
|
6327
6754
|
var import_sdk2 = require("@zyfai/sdk");
|
|
6328
6755
|
|
|
@@ -6449,7 +6876,7 @@ function buildSIWXConfig(deps) {
|
|
|
6449
6876
|
issuedAt,
|
|
6450
6877
|
toString() {
|
|
6451
6878
|
return new import_siwe2.SiweMessage({
|
|
6452
|
-
address: (0,
|
|
6879
|
+
address: (0, import_viem13.getAddress)(accountAddress),
|
|
6453
6880
|
chainId: numericChainId(chainId),
|
|
6454
6881
|
domain,
|
|
6455
6882
|
uri,
|