@owney/sdk 0.7.21-beta.3 → 0.7.21-beta.5
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 +446 -361
- package/dist/index.d.cts +12 -22
- package/dist/index.d.ts +12 -22
- package/dist/index.js +432 -343
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -32,6 +32,26 @@ __export(index_exports, {
|
|
|
32
32
|
});
|
|
33
33
|
module.exports = __toCommonJS(index_exports);
|
|
34
34
|
|
|
35
|
+
// src/lib/deposit-batch-callback.ts
|
|
36
|
+
var batchCallbacks = /* @__PURE__ */ new WeakMap();
|
|
37
|
+
var getDepositBatchTransfer = (callback) => callback ? batchCallbacks.get(callback) : void 0;
|
|
38
|
+
function toBatchTransfer(to, amount, verification) {
|
|
39
|
+
return {
|
|
40
|
+
to,
|
|
41
|
+
amount,
|
|
42
|
+
...verification ? {
|
|
43
|
+
yieldseeker: {
|
|
44
|
+
signature: verification.signature,
|
|
45
|
+
userId: verification.userId,
|
|
46
|
+
agentId: verification.yieldseekerAgentId
|
|
47
|
+
}
|
|
48
|
+
} : {}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function registerDepositBatch(callback, transfer) {
|
|
52
|
+
batchCallbacks.set(callback, transfer);
|
|
53
|
+
}
|
|
54
|
+
|
|
35
55
|
// src/errors.ts
|
|
36
56
|
var OwneyError = class extends Error {
|
|
37
57
|
code;
|
|
@@ -2098,39 +2118,6 @@ async function ensureWalletOnChain(pub, wallet, expected) {
|
|
|
2098
2118
|
|
|
2099
2119
|
// src/lib/transfer-auth.ts
|
|
2100
2120
|
var import_viem2 = require("viem");
|
|
2101
|
-
var ERC20_META_ABI = [
|
|
2102
|
-
{ type: "function", name: "name", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] },
|
|
2103
|
-
{ type: "function", name: "version", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] }
|
|
2104
|
-
];
|
|
2105
|
-
function buildTransferWithAuthorizationTypedData(input) {
|
|
2106
|
-
return {
|
|
2107
|
-
domain: { name: input.tokenName, version: input.tokenVersion, chainId: input.chainId, verifyingContract: input.token },
|
|
2108
|
-
types: {
|
|
2109
|
-
TransferWithAuthorization: [
|
|
2110
|
-
{ name: "from", type: "address" },
|
|
2111
|
-
{ name: "to", type: "address" },
|
|
2112
|
-
{ name: "value", type: "uint256" },
|
|
2113
|
-
{ name: "validAfter", type: "uint256" },
|
|
2114
|
-
{ name: "validBefore", type: "uint256" },
|
|
2115
|
-
{ name: "nonce", type: "bytes32" }
|
|
2116
|
-
]
|
|
2117
|
-
},
|
|
2118
|
-
primaryType: "TransferWithAuthorization",
|
|
2119
|
-
message: input.message
|
|
2120
|
-
};
|
|
2121
|
-
}
|
|
2122
|
-
async function readTokenMeta(publicClient, token) {
|
|
2123
|
-
const [tokenName, tokenVersion] = await Promise.all([
|
|
2124
|
-
publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "name" }),
|
|
2125
|
-
publicClient.readContract({ address: token, abi: ERC20_META_ABI, functionName: "version" }).catch(() => "2")
|
|
2126
|
-
]);
|
|
2127
|
-
return { tokenName, tokenVersion };
|
|
2128
|
-
}
|
|
2129
|
-
function randomAuthNonce() {
|
|
2130
|
-
const bytes = new Uint8Array(32);
|
|
2131
|
-
globalThis.crypto.getRandomValues(bytes);
|
|
2132
|
-
return (0, import_viem2.bytesToHex)(bytes);
|
|
2133
|
-
}
|
|
2134
2121
|
|
|
2135
2122
|
// src/lib/sponsor-client.ts
|
|
2136
2123
|
var ROUTING_API_BASE_URL = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
@@ -2173,65 +2160,21 @@ async function postPaymasterIntent(input) {
|
|
|
2173
2160
|
}
|
|
2174
2161
|
return parsed.data;
|
|
2175
2162
|
}
|
|
2176
|
-
async function
|
|
2163
|
+
async function getSponsorRelayerAddress(input) {
|
|
2177
2164
|
const base5 = input.baseUrl ?? ROUTING_API_BASE_URL;
|
|
2178
2165
|
let res;
|
|
2179
2166
|
try {
|
|
2180
|
-
res = await fetch(
|
|
2181
|
-
|
|
2182
|
-
headers: {
|
|
2183
|
-
"content-type": "application/json",
|
|
2184
|
-
"x-owney-api-key": input.apiKey,
|
|
2185
|
-
...input.yieldseekerSignature ? { Authorization: `Signature ${input.yieldseekerSignature}` } : {}
|
|
2186
|
-
},
|
|
2187
|
-
body: JSON.stringify(input.body)
|
|
2188
|
-
});
|
|
2189
|
-
} catch (networkError) {
|
|
2190
|
-
throw new OwneyError(
|
|
2191
|
-
"SPONSOR_REQUEST_FAILED",
|
|
2192
|
-
`Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
|
|
2193
|
-
{ cause: String(networkError) }
|
|
2194
|
-
);
|
|
2195
|
-
}
|
|
2196
|
-
const text = await res.text();
|
|
2197
|
-
let parsed = null;
|
|
2198
|
-
try {
|
|
2199
|
-
parsed = JSON.parse(text);
|
|
2200
|
-
} catch {
|
|
2201
|
-
}
|
|
2202
|
-
if (!res.ok || !parsed?.success || !parsed.data) {
|
|
2203
|
-
throw new OwneyError(
|
|
2204
|
-
"SPONSOR_REQUEST_FAILED",
|
|
2205
|
-
`Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
|
|
2167
|
+
res = await fetch(
|
|
2168
|
+
`${base5}/api/v1/sponsor/relayer-address?chainId=${input.chainId}`,
|
|
2206
2169
|
{
|
|
2207
|
-
|
|
2208
|
-
responseBody: text.slice(0, 500),
|
|
2209
|
-
// 503 SPONSOR_UNAVAILABLE = relayer out of gas; the tx was rejected
|
|
2210
|
-
// before broadcast, so it is safe to fall back to a user-paid deposit.
|
|
2211
|
-
safeToFallback: res.status === 503
|
|
2170
|
+
headers: { "x-owney-api-key": input.apiKey }
|
|
2212
2171
|
}
|
|
2213
2172
|
);
|
|
2214
|
-
}
|
|
2215
|
-
return parsed.data;
|
|
2216
|
-
}
|
|
2217
|
-
async function postSponsorPermit2Transfer(input) {
|
|
2218
|
-
const base5 = input.baseUrl ?? ROUTING_API_BASE_URL;
|
|
2219
|
-
let res;
|
|
2220
|
-
try {
|
|
2221
|
-
res = await fetch(`${base5}/api/v1/sponsor/permit2-transfer`, {
|
|
2222
|
-
method: "POST",
|
|
2223
|
-
headers: {
|
|
2224
|
-
"content-type": "application/json",
|
|
2225
|
-
"x-owney-api-key": input.apiKey,
|
|
2226
|
-
...input.yieldseekerSignature ? { Authorization: `Signature ${input.yieldseekerSignature}` } : {}
|
|
2227
|
-
},
|
|
2228
|
-
body: JSON.stringify(input.body)
|
|
2229
|
-
});
|
|
2230
2173
|
} catch (networkError) {
|
|
2231
2174
|
throw new OwneyError(
|
|
2232
2175
|
"SPONSOR_REQUEST_FAILED",
|
|
2233
2176
|
`Sponsor API network error: ${networkError instanceof Error ? networkError.message : String(networkError)}`,
|
|
2234
|
-
{ cause: String(networkError), safeToFallback:
|
|
2177
|
+
{ cause: String(networkError), safeToFallback: true }
|
|
2235
2178
|
);
|
|
2236
2179
|
}
|
|
2237
2180
|
const text = await res.text();
|
|
@@ -2240,54 +2183,53 @@ async function postSponsorPermit2Transfer(input) {
|
|
|
2240
2183
|
parsed = JSON.parse(text);
|
|
2241
2184
|
} catch {
|
|
2242
2185
|
}
|
|
2243
|
-
if (!res.ok || !parsed?.success || !parsed.data) {
|
|
2186
|
+
if (!res.ok || !parsed?.success || !parsed.data?.relayer) {
|
|
2244
2187
|
throw new OwneyError(
|
|
2245
2188
|
"SPONSOR_REQUEST_FAILED",
|
|
2246
2189
|
`Sponsor API error ${res.status}: ${parsed?.message ?? text.slice(0, 500)}`,
|
|
2247
2190
|
{
|
|
2248
2191
|
statusCode: res.status,
|
|
2249
2192
|
responseBody: text.slice(0, 500),
|
|
2250
|
-
safeToFallback:
|
|
2193
|
+
safeToFallback: true
|
|
2251
2194
|
}
|
|
2252
2195
|
);
|
|
2253
2196
|
}
|
|
2254
|
-
return parsed.data;
|
|
2197
|
+
return parsed.data.relayer;
|
|
2255
2198
|
}
|
|
2256
|
-
async function
|
|
2257
|
-
const base5 = input.baseUrl ?? ROUTING_API_BASE_URL;
|
|
2199
|
+
async function postSponsorBatchTransfer(input) {
|
|
2258
2200
|
let res;
|
|
2259
2201
|
try {
|
|
2260
2202
|
res = await fetch(
|
|
2261
|
-
`${
|
|
2203
|
+
`${input.baseUrl ?? ROUTING_API_BASE_URL}/api/v1/sponsor/permit2-batch`,
|
|
2262
2204
|
{
|
|
2263
|
-
|
|
2205
|
+
method: "POST",
|
|
2206
|
+
headers: {
|
|
2207
|
+
"content-type": "application/json",
|
|
2208
|
+
"x-owney-api-key": input.apiKey
|
|
2209
|
+
},
|
|
2210
|
+
body: JSON.stringify(input.body)
|
|
2264
2211
|
}
|
|
2265
2212
|
);
|
|
2266
|
-
} catch
|
|
2213
|
+
} catch {
|
|
2267
2214
|
throw new OwneyError(
|
|
2268
2215
|
"SPONSOR_REQUEST_FAILED",
|
|
2269
|
-
|
|
2270
|
-
{
|
|
2216
|
+
"Deposit status is unknown. Retry the same amount to check it.",
|
|
2217
|
+
{ safeToFallback: false }
|
|
2271
2218
|
);
|
|
2272
2219
|
}
|
|
2273
|
-
const
|
|
2274
|
-
|
|
2275
|
-
try {
|
|
2276
|
-
parsed = JSON.parse(text);
|
|
2277
|
-
} catch {
|
|
2278
|
-
}
|
|
2279
|
-
if (!res.ok || !parsed?.success || !parsed.data?.relayer) {
|
|
2220
|
+
const parsed = await res.json().catch(() => null);
|
|
2221
|
+
if (!res.ok || !parsed?.success || !/^0x[0-9a-fA-F]{64}$/.test(parsed.data?.txHash ?? "")) {
|
|
2280
2222
|
throw new OwneyError(
|
|
2281
2223
|
"SPONSOR_REQUEST_FAILED",
|
|
2282
|
-
|
|
2224
|
+
"Deposit could not be confirmed. Retry the same amount to check its status.",
|
|
2283
2225
|
{
|
|
2284
2226
|
statusCode: res.status,
|
|
2285
|
-
|
|
2286
|
-
|
|
2227
|
+
safeToFallback: false,
|
|
2228
|
+
notSubmitted: parsed?.notSubmitted === true || parsed?.error?.notSubmitted === true || parsed?.error?.details?.notSubmitted === true
|
|
2287
2229
|
}
|
|
2288
2230
|
);
|
|
2289
2231
|
}
|
|
2290
|
-
return parsed.data
|
|
2232
|
+
return parsed.data;
|
|
2291
2233
|
}
|
|
2292
2234
|
|
|
2293
2235
|
// src/lib/permit2.ts
|
|
@@ -2323,29 +2265,6 @@ var ERC20_ALLOWANCE_ABI = [
|
|
|
2323
2265
|
outputs: [{ name: "", type: "uint256" }]
|
|
2324
2266
|
}
|
|
2325
2267
|
];
|
|
2326
|
-
function buildPermitTransferFromTypedData(input) {
|
|
2327
|
-
return {
|
|
2328
|
-
domain: {
|
|
2329
|
-
name: "Permit2",
|
|
2330
|
-
chainId: input.chainId,
|
|
2331
|
-
verifyingContract: PERMIT2_ADDRESS
|
|
2332
|
-
},
|
|
2333
|
-
types: {
|
|
2334
|
-
PermitTransferFrom: [
|
|
2335
|
-
{ name: "permitted", type: "TokenPermissions" },
|
|
2336
|
-
{ name: "spender", type: "address" },
|
|
2337
|
-
{ name: "nonce", type: "uint256" },
|
|
2338
|
-
{ name: "deadline", type: "uint256" }
|
|
2339
|
-
],
|
|
2340
|
-
TokenPermissions: [
|
|
2341
|
-
{ name: "token", type: "address" },
|
|
2342
|
-
{ name: "amount", type: "uint256" }
|
|
2343
|
-
]
|
|
2344
|
-
},
|
|
2345
|
-
primaryType: "PermitTransferFrom",
|
|
2346
|
-
message: input.message
|
|
2347
|
-
};
|
|
2348
|
-
}
|
|
2349
2268
|
function randomPermit2Nonce() {
|
|
2350
2269
|
const bytes = new Uint8Array(32);
|
|
2351
2270
|
globalThis.crypto.getRandomValues(bytes);
|
|
@@ -2388,88 +2307,6 @@ function makeVerificationAwareDepositCallback(implementation) {
|
|
|
2388
2307
|
});
|
|
2389
2308
|
return callback;
|
|
2390
2309
|
}
|
|
2391
|
-
function makeSponsoredDepositCallback(deps) {
|
|
2392
|
-
const post = deps.httpPost ?? postSponsorTransferAuth;
|
|
2393
|
-
return makeVerificationAwareDepositCallback(
|
|
2394
|
-
async (smartWallet, chainId, amount, verification) => {
|
|
2395
|
-
const cid = chainId;
|
|
2396
|
-
const token = deps.tokenAddressByChain[cid];
|
|
2397
|
-
if (!token) {
|
|
2398
|
-
throw new OwneyError(
|
|
2399
|
-
"CHAIN_UNSUPPORTED",
|
|
2400
|
-
`No sponsored token configured for chain ${chainId}`
|
|
2401
|
-
);
|
|
2402
|
-
}
|
|
2403
|
-
const pub = deps.getPublicClient(cid);
|
|
2404
|
-
const wallet = deps.getWalletClient(cid);
|
|
2405
|
-
await ensureWalletOnChain(pub, wallet, cid);
|
|
2406
|
-
try {
|
|
2407
|
-
const balance = await readErc20Balance(pub, token, deps.ownerAddress);
|
|
2408
|
-
if (balance < BigInt(amount)) {
|
|
2409
|
-
throw new OwneyError(
|
|
2410
|
-
"DEPOSIT_INSUFFICIENT_BALANCE",
|
|
2411
|
-
"Insufficient balance for this deposit.",
|
|
2412
|
-
{ token, chainId: cid, balance: balance.toString(), amount }
|
|
2413
|
-
);
|
|
2414
|
-
}
|
|
2415
|
-
} catch (err) {
|
|
2416
|
-
if (err instanceof OwneyError) throw err;
|
|
2417
|
-
console.warn(
|
|
2418
|
-
"[owney-sdk] Deposit balance pre-check failed (non-fatal):",
|
|
2419
|
-
err instanceof Error ? err.message : String(err)
|
|
2420
|
-
);
|
|
2421
|
-
}
|
|
2422
|
-
const { tokenName, tokenVersion } = await readTokenMeta(pub, token);
|
|
2423
|
-
const validAfter = 0n;
|
|
2424
|
-
const validBefore = BigInt(
|
|
2425
|
-
Math.floor(Date.now() / 1e3) + AUTH_WINDOW_SECONDS
|
|
2426
|
-
);
|
|
2427
|
-
const nonce = randomAuthNonce();
|
|
2428
|
-
const typedData = buildTransferWithAuthorizationTypedData({
|
|
2429
|
-
token,
|
|
2430
|
-
chainId: cid,
|
|
2431
|
-
tokenName,
|
|
2432
|
-
tokenVersion,
|
|
2433
|
-
message: {
|
|
2434
|
-
from: deps.ownerAddress,
|
|
2435
|
-
to: smartWallet,
|
|
2436
|
-
value: BigInt(amount),
|
|
2437
|
-
validAfter,
|
|
2438
|
-
validBefore,
|
|
2439
|
-
nonce
|
|
2440
|
-
}
|
|
2441
|
-
});
|
|
2442
|
-
const authSignature = await wallet.signTypedData({
|
|
2443
|
-
account: deps.ownerAddress,
|
|
2444
|
-
...typedData
|
|
2445
|
-
});
|
|
2446
|
-
deps.onApproved?.();
|
|
2447
|
-
const result = await post({
|
|
2448
|
-
baseUrl: deps.baseUrl,
|
|
2449
|
-
apiKey: deps.apiKey,
|
|
2450
|
-
...verification?.agentId === "yieldseeker" ? { yieldseekerSignature: verification.signature } : {},
|
|
2451
|
-
body: {
|
|
2452
|
-
chainId: cid,
|
|
2453
|
-
token,
|
|
2454
|
-
from: deps.ownerAddress,
|
|
2455
|
-
to: smartWallet,
|
|
2456
|
-
value: amount,
|
|
2457
|
-
validAfter: validAfter.toString(),
|
|
2458
|
-
validBefore: validBefore.toString(),
|
|
2459
|
-
nonce,
|
|
2460
|
-
authSignature,
|
|
2461
|
-
tokenName,
|
|
2462
|
-
tokenVersion,
|
|
2463
|
-
...verification?.agentId === "yieldseeker" ? {
|
|
2464
|
-
yieldseekerUserId: verification.userId,
|
|
2465
|
-
yieldseekerAgentId: verification.yieldseekerAgentId
|
|
2466
|
-
} : {}
|
|
2467
|
-
}
|
|
2468
|
-
});
|
|
2469
|
-
return result.txHash;
|
|
2470
|
-
}
|
|
2471
|
-
);
|
|
2472
|
-
}
|
|
2473
2310
|
|
|
2474
2311
|
// src/agents/yieldseeker/yieldseeker.auth.ts
|
|
2475
2312
|
var import_siwe = require("siwe");
|
|
@@ -4325,105 +4162,305 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
|
|
|
4325
4162
|
}
|
|
4326
4163
|
|
|
4327
4164
|
// src/client.ts
|
|
4328
|
-
var
|
|
4165
|
+
var import_viem11 = require("viem");
|
|
4329
4166
|
var import_chains4 = require("viem/chains");
|
|
4330
4167
|
|
|
4331
|
-
// src/lib/sponsored-
|
|
4332
|
-
var
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4168
|
+
// src/lib/sponsored-token-batch.ts
|
|
4169
|
+
var import_viem9 = require("viem");
|
|
4170
|
+
|
|
4171
|
+
// src/lib/permit2-batch.ts
|
|
4172
|
+
var import_viem8 = require("viem");
|
|
4173
|
+
var BATCH_PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
4174
|
+
var PERMIT_BATCH_TYPES = {
|
|
4175
|
+
PermitBatchWitnessTransferFrom: [
|
|
4176
|
+
{ name: "permitted", type: "TokenPermissions[]" },
|
|
4177
|
+
{ name: "spender", type: "address" },
|
|
4178
|
+
{ name: "nonce", type: "uint256" },
|
|
4179
|
+
{ name: "deadline", type: "uint256" },
|
|
4180
|
+
{ name: "witness", type: "Deposit" }
|
|
4181
|
+
],
|
|
4182
|
+
Deposit: [{ name: "recipients", type: "address[]" }],
|
|
4183
|
+
TokenPermissions: [
|
|
4184
|
+
{ name: "token", type: "address" },
|
|
4185
|
+
{ name: "amount", type: "uint256" }
|
|
4186
|
+
]
|
|
4187
|
+
};
|
|
4188
|
+
var PERMIT2_BATCH_ABI = (0, import_viem8.parseAbi)([
|
|
4189
|
+
"struct TokenPermissions { address token; uint256 amount; }",
|
|
4190
|
+
"struct PermitBatchTransferFrom { TokenPermissions[] permitted; uint256 nonce; uint256 deadline; }",
|
|
4191
|
+
"struct SignatureTransferDetails { address to; uint256 requestedAmount; }",
|
|
4192
|
+
"function permitWitnessTransferFrom(PermitBatchTransferFrom permit,SignatureTransferDetails[] transferDetails,address owner,bytes32 witness,string witnessTypeString,bytes signature)",
|
|
4193
|
+
"function nonceBitmap(address owner,uint256 wordPos) view returns (uint256)"
|
|
4194
|
+
]);
|
|
4195
|
+
function batchPermit(b) {
|
|
4196
|
+
return {
|
|
4197
|
+
permitted: b.transfers.map((t) => ({
|
|
4198
|
+
token: b.token,
|
|
4199
|
+
amount: BigInt(t.amount)
|
|
4200
|
+
})),
|
|
4201
|
+
nonce: BigInt(b.nonce),
|
|
4202
|
+
deadline: BigInt(b.deadline)
|
|
4203
|
+
};
|
|
4204
|
+
}
|
|
4205
|
+
function batchTypedData(b, spender) {
|
|
4206
|
+
return {
|
|
4207
|
+
domain: {
|
|
4208
|
+
name: "Permit2",
|
|
4209
|
+
chainId: b.chainId,
|
|
4210
|
+
verifyingContract: BATCH_PERMIT2_ADDRESS
|
|
4211
|
+
},
|
|
4212
|
+
types: PERMIT_BATCH_TYPES,
|
|
4213
|
+
primaryType: "PermitBatchWitnessTransferFrom",
|
|
4214
|
+
message: {
|
|
4215
|
+
...batchPermit(b),
|
|
4216
|
+
spender,
|
|
4217
|
+
witness: { recipients: b.transfers.map((t) => t.to) }
|
|
4218
|
+
}
|
|
4219
|
+
};
|
|
4220
|
+
}
|
|
4221
|
+
|
|
4222
|
+
// src/lib/sponsored-token-batch.ts
|
|
4223
|
+
var memory = /* @__PURE__ */ new Map();
|
|
4224
|
+
var inflight = /* @__PURE__ */ new Map();
|
|
4225
|
+
var planOf = (transfers) => JSON.stringify(
|
|
4226
|
+
transfers.map((t) => ({
|
|
4227
|
+
to: t.to.toLowerCase(),
|
|
4228
|
+
amount: BigInt(t.amount).toString()
|
|
4229
|
+
}))
|
|
4230
|
+
);
|
|
4231
|
+
function read(key2) {
|
|
4232
|
+
return typeof window === "undefined" ? memory.get(key2) : window.localStorage.getItem(key2);
|
|
4233
|
+
}
|
|
4234
|
+
function save(key2, body) {
|
|
4235
|
+
const value = JSON.stringify({
|
|
4236
|
+
...body,
|
|
4237
|
+
transfers: body.transfers.map(({ to, amount }) => ({ to, amount }))
|
|
4238
|
+
});
|
|
4239
|
+
if (typeof window === "undefined") memory.set(key2, value);
|
|
4240
|
+
else window.localStorage.setItem(key2, value);
|
|
4241
|
+
}
|
|
4242
|
+
function clear(key2) {
|
|
4243
|
+
if (typeof window === "undefined") memory.delete(key2);
|
|
4244
|
+
else window.localStorage.removeItem(key2);
|
|
4245
|
+
}
|
|
4246
|
+
function sponsorTokenBatch(i) {
|
|
4247
|
+
const key2 = `owney.token-batch.v1:${(0, import_viem9.keccak256)((0, import_viem9.toBytes)(i.apiKey))}:${i.baseUrl ?? "default"}:${i.chainId}:${i.owner.toLowerCase()}:${i.token.toLowerCase()}`;
|
|
4248
|
+
const plan = planOf(i.transfers);
|
|
4249
|
+
const active = inflight.get(key2);
|
|
4250
|
+
if (active) {
|
|
4251
|
+
if (active.plan !== plan)
|
|
4252
|
+
return Promise.reject(
|
|
4253
|
+
new Error(
|
|
4254
|
+
"A token deposit is already in progress. Wait for its result before depositing again."
|
|
4255
|
+
)
|
|
4370
4256
|
);
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4257
|
+
return active.promise;
|
|
4258
|
+
}
|
|
4259
|
+
const promise = execute(i, key2, plan).finally(() => inflight.delete(key2));
|
|
4260
|
+
inflight.set(key2, { plan, promise });
|
|
4261
|
+
return promise;
|
|
4262
|
+
}
|
|
4263
|
+
async function execute(i, key2, plan) {
|
|
4264
|
+
if (!i.transfers.length || i.transfers.length > 16 || i.transfers.some(
|
|
4265
|
+
(t) => BigInt(t.amount) <= 0n || BigInt(t.amount) >= 1n << 256n
|
|
4266
|
+
) || new Set(i.transfers.map((t) => t.to.toLowerCase())).size !== i.transfers.length)
|
|
4267
|
+
throw new Error("Invalid token deposit shares.");
|
|
4268
|
+
const send = async (initial) => {
|
|
4269
|
+
let body = initial;
|
|
4270
|
+
save(key2, body);
|
|
4271
|
+
try {
|
|
4272
|
+
if (!body.serializedTransaction) {
|
|
4273
|
+
const prepared = await postSponsorBatchTransfer({
|
|
4274
|
+
apiKey: i.apiKey,
|
|
4275
|
+
baseUrl: i.baseUrl,
|
|
4276
|
+
body
|
|
4277
|
+
});
|
|
4278
|
+
if (!prepared.serializedTransaction || (0, import_viem9.keccak256)(prepared.serializedTransaction) !== prepared.txHash)
|
|
4279
|
+
throw new Error(
|
|
4280
|
+
"Sponsorship API did not return a valid prepared transaction."
|
|
4281
|
+
);
|
|
4282
|
+
body = {
|
|
4283
|
+
...body,
|
|
4284
|
+
serializedTransaction: prepared.serializedTransaction
|
|
4285
|
+
};
|
|
4286
|
+
save(key2, body);
|
|
4377
4287
|
}
|
|
4378
|
-
const
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
});
|
|
4383
|
-
const nonce = randomPermit2Nonce();
|
|
4384
|
-
const deadline = BigInt(
|
|
4385
|
-
Math.floor(Date.now() / 1e3) + PERMIT_WINDOW_SECONDS
|
|
4386
|
-
);
|
|
4387
|
-
const typedData = buildPermitTransferFromTypedData({
|
|
4388
|
-
chainId: cid,
|
|
4389
|
-
message: {
|
|
4390
|
-
permitted: { token, amount: amountWei },
|
|
4391
|
-
spender: relayer,
|
|
4392
|
-
nonce,
|
|
4393
|
-
deadline
|
|
4394
|
-
}
|
|
4395
|
-
});
|
|
4396
|
-
const signature = await wallet.signTypedData({
|
|
4397
|
-
account: deps.ownerAddress,
|
|
4398
|
-
...typedData
|
|
4399
|
-
});
|
|
4400
|
-
deps.onApproved?.();
|
|
4401
|
-
const result = await post({
|
|
4402
|
-
baseUrl: deps.baseUrl,
|
|
4403
|
-
apiKey: deps.apiKey,
|
|
4404
|
-
...verification?.agentId === "yieldseeker" ? { yieldseekerSignature: verification.signature } : {},
|
|
4405
|
-
body: {
|
|
4406
|
-
chainId: cid,
|
|
4407
|
-
token,
|
|
4408
|
-
from: deps.ownerAddress,
|
|
4409
|
-
to: smartWallet,
|
|
4410
|
-
amount,
|
|
4411
|
-
nonce: nonce.toString(),
|
|
4412
|
-
deadline: deadline.toString(),
|
|
4413
|
-
signature,
|
|
4414
|
-
...verification?.agentId === "yieldseeker" ? {
|
|
4415
|
-
yieldseekerUserId: verification.userId,
|
|
4416
|
-
yieldseekerAgentId: verification.yieldseekerAgentId
|
|
4417
|
-
} : {}
|
|
4418
|
-
}
|
|
4288
|
+
const result = await postSponsorBatchTransfer({
|
|
4289
|
+
apiKey: i.apiKey,
|
|
4290
|
+
baseUrl: i.baseUrl,
|
|
4291
|
+
body
|
|
4419
4292
|
});
|
|
4293
|
+
if (result.txHash !== (0, import_viem9.keccak256)(body.serializedTransaction))
|
|
4294
|
+
throw new Error(
|
|
4295
|
+
"Sponsorship receipt does not match the pending transaction."
|
|
4296
|
+
);
|
|
4297
|
+
clear(key2);
|
|
4420
4298
|
return result.txHash;
|
|
4299
|
+
} catch (error) {
|
|
4300
|
+
if (!body.serializedTransaction || error instanceof OwneyError && error.details?.notSubmitted === true)
|
|
4301
|
+
clear(key2);
|
|
4302
|
+
throw error;
|
|
4421
4303
|
}
|
|
4304
|
+
};
|
|
4305
|
+
const saved = read(key2);
|
|
4306
|
+
if (saved) {
|
|
4307
|
+
const previous = JSON.parse(saved);
|
|
4308
|
+
if (previous.chainId !== i.chainId || !(0, import_viem9.isAddressEqual)(previous.from, i.owner) || !(0, import_viem9.isAddressEqual)(previous.token, i.token) || planOf(previous.transfers) !== plan)
|
|
4309
|
+
throw new Error(
|
|
4310
|
+
"Retry the previous token deposit and agent split first to reconcile its status."
|
|
4311
|
+
);
|
|
4312
|
+
i.onApproved?.();
|
|
4313
|
+
return send({ ...previous, transfers: i.transfers });
|
|
4314
|
+
}
|
|
4315
|
+
const total = i.transfers.reduce((sum, t) => sum + BigInt(t.amount), 0n);
|
|
4316
|
+
const [balance, allowance] = await Promise.all([
|
|
4317
|
+
readErc20Balance(i.pub, i.token, i.owner),
|
|
4318
|
+
readPermit2Allowance(i.pub, i.token, i.owner)
|
|
4319
|
+
]);
|
|
4320
|
+
if (balance < total)
|
|
4321
|
+
throw new OwneyError(
|
|
4322
|
+
"DEPOSIT_INSUFFICIENT_BALANCE",
|
|
4323
|
+
"Insufficient token balance for this deposit."
|
|
4324
|
+
);
|
|
4325
|
+
if (allowance < total)
|
|
4326
|
+
throw new OwneyError(
|
|
4327
|
+
"PERMIT2_APPROVAL_REQUIRED",
|
|
4328
|
+
"token deposits need a one-time Permit2 approval."
|
|
4329
|
+
);
|
|
4330
|
+
const relayer = await getSponsorRelayerAddress({
|
|
4331
|
+
apiKey: i.apiKey,
|
|
4332
|
+
baseUrl: i.baseUrl,
|
|
4333
|
+
chainId: i.chainId
|
|
4334
|
+
});
|
|
4335
|
+
const now = (await i.pub.getBlock()).timestamp;
|
|
4336
|
+
const unsigned = {
|
|
4337
|
+
chainId: i.chainId,
|
|
4338
|
+
token: i.token,
|
|
4339
|
+
from: i.owner,
|
|
4340
|
+
transfers: i.transfers,
|
|
4341
|
+
nonce: randomPermit2Nonce().toString(),
|
|
4342
|
+
deadline: (now + 900n).toString()
|
|
4343
|
+
};
|
|
4344
|
+
const signature = await i.wallet.signTypedData({
|
|
4345
|
+
account: i.owner,
|
|
4346
|
+
...batchTypedData(unsigned, relayer)
|
|
4347
|
+
});
|
|
4348
|
+
i.onApproved?.();
|
|
4349
|
+
return send({ ...unsigned, signature });
|
|
4350
|
+
}
|
|
4351
|
+
|
|
4352
|
+
// src/lib/sponsored-token-deposit.ts
|
|
4353
|
+
function makeSponsoredTokenCallback(deps) {
|
|
4354
|
+
const batch = async (chainId, transfers) => {
|
|
4355
|
+
if (chainId !== 8453 && chainId !== 42161 && chainId !== 1)
|
|
4356
|
+
throw new OwneyError(
|
|
4357
|
+
"CHAIN_UNSUPPORTED",
|
|
4358
|
+
`No sponsored token configured for chain ${chainId}`
|
|
4359
|
+
);
|
|
4360
|
+
const token = deps.tokenAddressByChain[chainId];
|
|
4361
|
+
if (!token)
|
|
4362
|
+
throw new OwneyError(
|
|
4363
|
+
"CHAIN_UNSUPPORTED",
|
|
4364
|
+
`No sponsored token configured for chain ${chainId}`
|
|
4365
|
+
);
|
|
4366
|
+
const pub = deps.getPublicClient(chainId), wallet = deps.getWalletClient(chainId);
|
|
4367
|
+
await ensureWalletOnChain(pub, wallet, chainId);
|
|
4368
|
+
return sponsorTokenBatch({
|
|
4369
|
+
apiKey: deps.apiKey,
|
|
4370
|
+
baseUrl: deps.baseUrl,
|
|
4371
|
+
owner: deps.ownerAddress,
|
|
4372
|
+
token,
|
|
4373
|
+
chainId,
|
|
4374
|
+
transfers,
|
|
4375
|
+
pub,
|
|
4376
|
+
wallet,
|
|
4377
|
+
onApproved: deps.onApproved
|
|
4378
|
+
});
|
|
4379
|
+
};
|
|
4380
|
+
const callback = makeVerificationAwareDepositCallback(
|
|
4381
|
+
(to, chainId, amount, verification) => batch(chainId, [toBatchTransfer(to, amount, verification)])
|
|
4422
4382
|
);
|
|
4383
|
+
registerDepositBatch(callback, batch);
|
|
4384
|
+
return callback;
|
|
4385
|
+
}
|
|
4386
|
+
|
|
4387
|
+
// src/lib/agent-deposit-batch.ts
|
|
4388
|
+
function deferred() {
|
|
4389
|
+
let resolve, reject;
|
|
4390
|
+
const promise = new Promise((yes, no) => {
|
|
4391
|
+
resolve = yes;
|
|
4392
|
+
reject = no;
|
|
4393
|
+
});
|
|
4394
|
+
void promise.catch(() => {
|
|
4395
|
+
});
|
|
4396
|
+
return { promise, resolve, reject };
|
|
4397
|
+
}
|
|
4398
|
+
async function runAgentDepositBatch(chainId, legs, transfer) {
|
|
4399
|
+
const funding = deferred();
|
|
4400
|
+
const tasks = [];
|
|
4401
|
+
const transfers = [];
|
|
4402
|
+
try {
|
|
4403
|
+
for (const leg of legs) {
|
|
4404
|
+
const ready = deferred();
|
|
4405
|
+
let entered = false;
|
|
4406
|
+
const callback = makeVerificationAwareDepositCallback(
|
|
4407
|
+
(to, cid, amount, verification) => {
|
|
4408
|
+
if (entered || cid !== chainId || BigInt(amount) !== BigInt(leg.amount)) {
|
|
4409
|
+
const error = new Error(
|
|
4410
|
+
"Agent changed its prepared deposit share."
|
|
4411
|
+
);
|
|
4412
|
+
ready.reject(error);
|
|
4413
|
+
throw error;
|
|
4414
|
+
}
|
|
4415
|
+
entered = true;
|
|
4416
|
+
ready.resolve(toBatchTransfer(to, amount, verification));
|
|
4417
|
+
return funding.promise;
|
|
4418
|
+
}
|
|
4419
|
+
);
|
|
4420
|
+
const task = Promise.resolve().then(() => leg.run(callback));
|
|
4421
|
+
tasks.push(task);
|
|
4422
|
+
void task.then(
|
|
4423
|
+
() => {
|
|
4424
|
+
if (!entered)
|
|
4425
|
+
ready.reject(
|
|
4426
|
+
new Error("Agent did not prepare a deposit transfer.")
|
|
4427
|
+
);
|
|
4428
|
+
},
|
|
4429
|
+
(error) => ready.reject(error)
|
|
4430
|
+
);
|
|
4431
|
+
transfers.push(await ready.promise);
|
|
4432
|
+
}
|
|
4433
|
+
const txHash = await transfer(chainId, transfers);
|
|
4434
|
+
funding.resolve(txHash);
|
|
4435
|
+
const settled = await Promise.allSettled(tasks);
|
|
4436
|
+
const agentResults = {};
|
|
4437
|
+
const failures = [];
|
|
4438
|
+
for (const [index, result] of settled.entries()) {
|
|
4439
|
+
if (result.status === "fulfilled")
|
|
4440
|
+
agentResults[legs[index].id] = result.value;
|
|
4441
|
+
else failures.push(legs[index].id);
|
|
4442
|
+
}
|
|
4443
|
+
if (failures.length)
|
|
4444
|
+
throw new OwneyError(
|
|
4445
|
+
"DEPOSIT_PARTIAL_FAILURE",
|
|
4446
|
+
"The deposit was sent to all agents, but some agent updates could not be confirmed. Check activity before depositing again.",
|
|
4447
|
+
{
|
|
4448
|
+
txHash,
|
|
4449
|
+
fundsSubmitted: true,
|
|
4450
|
+
agentResults,
|
|
4451
|
+
failedAgentIds: failures
|
|
4452
|
+
}
|
|
4453
|
+
);
|
|
4454
|
+
return { agentResults };
|
|
4455
|
+
} catch (error) {
|
|
4456
|
+
funding.reject(error);
|
|
4457
|
+
await Promise.allSettled(tasks);
|
|
4458
|
+
throw error;
|
|
4459
|
+
}
|
|
4423
4460
|
}
|
|
4424
4461
|
|
|
4425
4462
|
// src/lib/sponsored-calls-deposit.ts
|
|
4426
|
-
var
|
|
4463
|
+
var import_viem10 = require("viem");
|
|
4427
4464
|
var DEFAULT_POLL_INTERVAL_MS = 1500;
|
|
4428
4465
|
var DEFAULT_MAX_POLLS = 30;
|
|
4429
4466
|
async function paymasterSupported(provider, owner, chainId) {
|
|
@@ -4431,7 +4468,7 @@ async function paymasterSupported(provider, owner, chainId) {
|
|
|
4431
4468
|
method: "wallet_getCapabilities",
|
|
4432
4469
|
params: [owner]
|
|
4433
4470
|
});
|
|
4434
|
-
const forChain = caps?.[(0,
|
|
4471
|
+
const forChain = caps?.[(0, import_viem10.toHex)(chainId)] ?? caps?.[String(chainId)];
|
|
4435
4472
|
return Boolean(forChain?.paymasterService?.supported);
|
|
4436
4473
|
}
|
|
4437
4474
|
function makeSponsoredCallsCallback(deps) {
|
|
@@ -4449,7 +4486,7 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
4449
4486
|
}
|
|
4450
4487
|
return new URL(configured, origin).toString();
|
|
4451
4488
|
};
|
|
4452
|
-
|
|
4489
|
+
const batch = async (chainId, transfers) => {
|
|
4453
4490
|
const cid = chainId;
|
|
4454
4491
|
const token = deps.tokenAddressByChain[cid];
|
|
4455
4492
|
if (!token) {
|
|
@@ -4465,19 +4502,24 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
4465
4502
|
{ chainId }
|
|
4466
4503
|
);
|
|
4467
4504
|
}
|
|
4468
|
-
const
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4505
|
+
const calls = transfers.map((transfer) => ({
|
|
4506
|
+
to: token,
|
|
4507
|
+
value: "0x0",
|
|
4508
|
+
data: (0, import_viem10.encodeFunctionData)({
|
|
4509
|
+
abi: import_viem10.erc20Abi,
|
|
4510
|
+
functionName: "transfer",
|
|
4511
|
+
args: [transfer.to, BigInt(transfer.amount)]
|
|
4512
|
+
})
|
|
4513
|
+
}));
|
|
4473
4514
|
let paymasterUrl = absolutePaymasterUrl();
|
|
4474
|
-
|
|
4475
|
-
|
|
4515
|
+
for (const transfer of transfers) {
|
|
4516
|
+
const verification = transfer.yieldseeker;
|
|
4517
|
+
if (!verification) continue;
|
|
4518
|
+
if (chainId !== 8453)
|
|
4476
4519
|
throw new OwneyError(
|
|
4477
4520
|
"CHAIN_UNSUPPORTED",
|
|
4478
|
-
`Yieldseeker
|
|
4521
|
+
`Yieldseeker sponsorship is not available on chain ${chainId}.`
|
|
4479
4522
|
);
|
|
4480
|
-
}
|
|
4481
4523
|
const { intent } = await postPaymasterIntent({
|
|
4482
4524
|
baseUrl: deps.routingApiBaseUrl,
|
|
4483
4525
|
apiKey: deps.apiKey,
|
|
@@ -4486,14 +4528,14 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
4486
4528
|
chainId,
|
|
4487
4529
|
token,
|
|
4488
4530
|
from: deps.ownerAddress,
|
|
4489
|
-
to:
|
|
4490
|
-
amount,
|
|
4531
|
+
to: transfer.to,
|
|
4532
|
+
amount: transfer.amount,
|
|
4491
4533
|
yieldseekerUserId: verification.userId,
|
|
4492
|
-
yieldseekerAgentId: verification.
|
|
4534
|
+
yieldseekerAgentId: verification.agentId
|
|
4493
4535
|
}
|
|
4494
4536
|
});
|
|
4495
4537
|
const url = new URL(paymasterUrl);
|
|
4496
|
-
url.searchParams.
|
|
4538
|
+
url.searchParams.append("owneyIntent", intent);
|
|
4497
4539
|
paymasterUrl = url.toString();
|
|
4498
4540
|
}
|
|
4499
4541
|
const sendResult = await deps.provider.request({
|
|
@@ -4502,9 +4544,9 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
4502
4544
|
{
|
|
4503
4545
|
version: "2.0.0",
|
|
4504
4546
|
from: deps.ownerAddress,
|
|
4505
|
-
chainId: (0,
|
|
4506
|
-
atomicRequired:
|
|
4507
|
-
calls
|
|
4547
|
+
chainId: (0, import_viem10.toHex)(chainId),
|
|
4548
|
+
atomicRequired: transfers.length > 1,
|
|
4549
|
+
calls,
|
|
4508
4550
|
capabilities: {
|
|
4509
4551
|
paymasterService: { url: paymasterUrl }
|
|
4510
4552
|
}
|
|
@@ -4526,7 +4568,24 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
4526
4568
|
params: [callsId]
|
|
4527
4569
|
});
|
|
4528
4570
|
const txHash = status?.receipts?.[0]?.transactionHash;
|
|
4529
|
-
if (
|
|
4571
|
+
if (status?.receipts?.some((receipt) => receipt.status === "0x0") || typeof status?.status === "number" && status.status >= 400) {
|
|
4572
|
+
throw new OwneyError(
|
|
4573
|
+
"SPONSOR_REQUEST_FAILED",
|
|
4574
|
+
"The sponsored deposit did not complete successfully.",
|
|
4575
|
+
{ chainId, callsId, safeToFallback: false }
|
|
4576
|
+
);
|
|
4577
|
+
}
|
|
4578
|
+
if (txHash && (transfers.length === 1 || status?.status === 200 || status?.status === "CONFIRMED")) {
|
|
4579
|
+
if (status?.receipts?.some(
|
|
4580
|
+
(receipt) => receipt.transactionHash !== txHash
|
|
4581
|
+
))
|
|
4582
|
+
throw new OwneyError(
|
|
4583
|
+
"SPONSORED_CALLS_NO_RECEIPT",
|
|
4584
|
+
"The wallet returned multiple transactions for an atomic deposit. Check activity before trying again.",
|
|
4585
|
+
{ chainId, callsId }
|
|
4586
|
+
);
|
|
4587
|
+
return txHash;
|
|
4588
|
+
}
|
|
4530
4589
|
if (pollIntervalMs > 0) {
|
|
4531
4590
|
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
4532
4591
|
}
|
|
@@ -4536,7 +4595,12 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
4536
4595
|
`No receipt for calls ${callsId} after ${maxPolls} polls; the deposit may still settle.`,
|
|
4537
4596
|
{ chainId, callsId }
|
|
4538
4597
|
);
|
|
4539
|
-
}
|
|
4598
|
+
};
|
|
4599
|
+
const callback = makeVerificationAwareDepositCallback(
|
|
4600
|
+
(to, chainId, amount, verification) => batch(chainId, [toBatchTransfer(to, amount, verification)])
|
|
4601
|
+
);
|
|
4602
|
+
registerDepositBatch(callback, batch);
|
|
4603
|
+
return callback;
|
|
4540
4604
|
}
|
|
4541
4605
|
|
|
4542
4606
|
// src/client.ts
|
|
@@ -4575,6 +4639,11 @@ var SPONSORED_WETH_BY_CHAIN = {
|
|
|
4575
4639
|
42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
|
|
4576
4640
|
1: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
|
|
4577
4641
|
};
|
|
4642
|
+
var SPONSORED_TOKENS_BY_ASSET = { USDC: SPONSORED_USDC_BY_CHAIN, WETH: SPONSORED_WETH_BY_CHAIN };
|
|
4643
|
+
function sponsoredTokensFor(asset) {
|
|
4644
|
+
if (!Object.prototype.hasOwnProperty.call(SPONSORED_TOKENS_BY_ASSET, asset)) throw new OwneyError("ASSET_UNSUPPORTED", `No sponsored token configured for ${asset}`);
|
|
4645
|
+
return SPONSORED_TOKENS_BY_ASSET[asset];
|
|
4646
|
+
}
|
|
4578
4647
|
function shouldFallbackToUserPaid(error, asset, appCallback) {
|
|
4579
4648
|
return (asset === "WETH" || asset === "USDC") && appCallback === void 0 && error instanceof OwneyError && error.code === "SPONSOR_REQUEST_FAILED" && error.details?.safeToFallback === true;
|
|
4580
4649
|
}
|
|
@@ -4709,18 +4778,13 @@ var OwneySDK = class {
|
|
|
4709
4778
|
}
|
|
4710
4779
|
return this.state.provider;
|
|
4711
4780
|
}
|
|
4712
|
-
/**
|
|
4713
|
-
* Lazily builds (and caches) the default EIP-3009 sponsored deposit callback
|
|
4714
|
-
* used when the caller omits `depositCallback`. Wraps the connected EIP-1193
|
|
4715
|
-
* provider with viem `custom(provider)` to read token meta and sign the
|
|
4716
|
-
* `TransferWithAuthorization`, then POSTs to the sponsor API.
|
|
4717
|
-
*/
|
|
4781
|
+
/** Builds the default USDC batch callback for the connected wallet. */
|
|
4718
4782
|
getDefaultSponsoredCallback(onApproved) {
|
|
4719
4783
|
if (!onApproved && this.cachedSponsoredCallback)
|
|
4720
4784
|
return this.cachedSponsoredCallback;
|
|
4721
4785
|
const provider = this.requireConnectedProvider();
|
|
4722
4786
|
const owner = this.state.walletAddress;
|
|
4723
|
-
const callback =
|
|
4787
|
+
const callback = makeSponsoredTokenCallback({
|
|
4724
4788
|
apiKey: this.apiKey,
|
|
4725
4789
|
baseUrl: this.routingApiBaseUrl,
|
|
4726
4790
|
ownerAddress: owner,
|
|
@@ -4729,25 +4793,20 @@ var OwneySDK = class {
|
|
|
4729
4793
|
// Casts work around viem's chain-narrowed Client vs the generic
|
|
4730
4794
|
// PublicClient/WalletClient param types — structurally identical at
|
|
4731
4795
|
// runtime, but the two share a name TS treats as unrelated.
|
|
4732
|
-
getPublicClient: (cid) => (0,
|
|
4796
|
+
getPublicClient: (cid) => (0, import_viem11.createPublicClient)({
|
|
4733
4797
|
chain: VIEM_CHAIN2[cid],
|
|
4734
|
-
transport: (0,
|
|
4798
|
+
transport: (0, import_viem11.custom)(provider)
|
|
4735
4799
|
}),
|
|
4736
|
-
getWalletClient: (cid) => (0,
|
|
4800
|
+
getWalletClient: (cid) => (0, import_viem11.createWalletClient)({
|
|
4737
4801
|
account: owner,
|
|
4738
4802
|
chain: VIEM_CHAIN2[cid],
|
|
4739
|
-
transport: (0,
|
|
4803
|
+
transport: (0, import_viem11.custom)(provider)
|
|
4740
4804
|
})
|
|
4741
4805
|
});
|
|
4742
4806
|
if (!onApproved) this.cachedSponsoredCallback = callback;
|
|
4743
4807
|
return callback;
|
|
4744
4808
|
}
|
|
4745
|
-
/**
|
|
4746
|
-
* Lazily builds (and caches) the default Permit2 sponsored WETH deposit
|
|
4747
|
-
* callback used when the caller omits `depositCallback` for a WETH
|
|
4748
|
-
* deposit. Mirrors `getDefaultSponsoredCallback()` but signs a Permit2
|
|
4749
|
-
* `PermitTransferFrom` instead of an EIP-3009 authorization.
|
|
4750
|
-
*/
|
|
4809
|
+
/** Builds the wallet-native sponsored calls callback for compatible paymasters. */
|
|
4751
4810
|
getDefaultSponsoredCallsCallback(asset, onApproved) {
|
|
4752
4811
|
const cached = this.cachedSponsoredCallsCallbacks.get(asset);
|
|
4753
4812
|
if (!onApproved && cached) return cached;
|
|
@@ -4759,7 +4818,7 @@ var OwneySDK = class {
|
|
|
4759
4818
|
ownerAddress: this.state.walletAddress,
|
|
4760
4819
|
paymasterServiceUrl: this.paymasterServiceUrl,
|
|
4761
4820
|
onApproved,
|
|
4762
|
-
tokenAddressByChain: asset
|
|
4821
|
+
tokenAddressByChain: sponsoredTokensFor(asset)
|
|
4763
4822
|
});
|
|
4764
4823
|
if (!onApproved) this.cachedSponsoredCallsCallbacks.set(asset, callback);
|
|
4765
4824
|
return callback;
|
|
@@ -4768,14 +4827,14 @@ var OwneySDK = class {
|
|
|
4768
4827
|
* Lazily builds (and caches) the default Permit2 sponsored WETH deposit
|
|
4769
4828
|
* callback used when the caller omits `depositCallback` for a WETH deposit.
|
|
4770
4829
|
* Mirrors `getDefaultSponsoredCallback()` but signs a Permit2
|
|
4771
|
-
*
|
|
4830
|
+
* single-use batch authorization instead of an EIP-3009 authorization.
|
|
4772
4831
|
*/
|
|
4773
4832
|
getDefaultWethSponsoredCallback(onApproved) {
|
|
4774
4833
|
if (!onApproved && this.cachedWethSponsoredCallback)
|
|
4775
4834
|
return this.cachedWethSponsoredCallback;
|
|
4776
4835
|
const provider = this.requireConnectedProvider();
|
|
4777
4836
|
const owner = this.state.walletAddress;
|
|
4778
|
-
const callback =
|
|
4837
|
+
const callback = makeSponsoredTokenCallback({
|
|
4779
4838
|
apiKey: this.apiKey,
|
|
4780
4839
|
baseUrl: this.routingApiBaseUrl,
|
|
4781
4840
|
ownerAddress: owner,
|
|
@@ -4784,14 +4843,14 @@ var OwneySDK = class {
|
|
|
4784
4843
|
// Casts work around viem's chain-narrowed Client vs the generic
|
|
4785
4844
|
// PublicClient/WalletClient param types — structurally identical at
|
|
4786
4845
|
// runtime, but the two share a name TS treats as unrelated.
|
|
4787
|
-
getPublicClient: (cid) => (0,
|
|
4846
|
+
getPublicClient: (cid) => (0, import_viem11.createPublicClient)({
|
|
4788
4847
|
chain: VIEM_CHAIN2[cid],
|
|
4789
|
-
transport: (0,
|
|
4848
|
+
transport: (0, import_viem11.custom)(provider)
|
|
4790
4849
|
}),
|
|
4791
|
-
getWalletClient: (cid) => (0,
|
|
4850
|
+
getWalletClient: (cid) => (0, import_viem11.createWalletClient)({
|
|
4792
4851
|
account: owner,
|
|
4793
4852
|
chain: VIEM_CHAIN2[cid],
|
|
4794
|
-
transport: (0,
|
|
4853
|
+
transport: (0, import_viem11.custom)(provider)
|
|
4795
4854
|
})
|
|
4796
4855
|
});
|
|
4797
4856
|
if (!onApproved) this.cachedWethSponsoredCallback = callback;
|
|
@@ -5027,10 +5086,9 @@ var OwneySDK = class {
|
|
|
5027
5086
|
* Serializing costs no real wall-clock: the user can only approve one prompt
|
|
5028
5087
|
* at a time anyway.
|
|
5029
5088
|
*
|
|
5030
|
-
*
|
|
5031
|
-
*
|
|
5032
|
-
*
|
|
5033
|
-
* retry; if none activated, the original provider error is preserved.
|
|
5089
|
+
* Stop at the first failure so a canceled sign-in does not open another
|
|
5090
|
+
* agent's wallet prompt. Report any earlier successes for diagnostics; the
|
|
5091
|
+
* app discards the session when the complete sign-in does not succeed.
|
|
5034
5092
|
*/
|
|
5035
5093
|
async activateAgentsInTurn(agents, state, chainId, asset) {
|
|
5036
5094
|
let firstError = null;
|
|
@@ -5058,6 +5116,7 @@ var OwneySDK = class {
|
|
|
5058
5116
|
} else {
|
|
5059
5117
|
console.error(`activateAgent(${agent.id}) failed:`, error);
|
|
5060
5118
|
}
|
|
5119
|
+
break;
|
|
5061
5120
|
}
|
|
5062
5121
|
}
|
|
5063
5122
|
if (firstError === null) return;
|
|
@@ -5081,7 +5140,8 @@ var OwneySDK = class {
|
|
|
5081
5140
|
* @param options.asset - Asset symbol to deposit (e.g. "USDC")
|
|
5082
5141
|
* @param options.depositCallback - Callback that performs the token transfer and returns a tx hash.
|
|
5083
5142
|
* When agentId is omitted, this callback is invoked once per eligible agent with that agent's
|
|
5084
|
-
* split amount and smart wallet address
|
|
5143
|
+
* split amount and smart wallet address. Default sponsored deposits batch
|
|
5144
|
+
* all shares into one signature; custom callbacks still run once per agent.
|
|
5085
5145
|
* @param options.agentId - Optional explicit target. Otherwise split equally,
|
|
5086
5146
|
* or fund remaining agents when a recovery deposit cannot meet every minimum.
|
|
5087
5147
|
* @returns {OwneyDepositResult} for a single agent, or {OwneyMultiDepositResult} with per-agent results
|
|
@@ -5166,6 +5226,32 @@ var OwneySDK = class {
|
|
|
5166
5226
|
}
|
|
5167
5227
|
);
|
|
5168
5228
|
}
|
|
5229
|
+
const batchTransfer = getDepositBatchTransfer(effectiveCallback);
|
|
5230
|
+
if (!depositCallback && batchTransfer) {
|
|
5231
|
+
return runAgentDepositBatch(
|
|
5232
|
+
chainId,
|
|
5233
|
+
agentAmounts.map(({ agent, amount: amount2 }) => ({
|
|
5234
|
+
id: agent.id,
|
|
5235
|
+
amount: amount2,
|
|
5236
|
+
run: (callback) => withFailureReporting(
|
|
5237
|
+
this.apiKey,
|
|
5238
|
+
agent.id,
|
|
5239
|
+
() => agent.deposit(state, chainId, amount2, asset, callback),
|
|
5240
|
+
this.routingApiBaseUrl
|
|
5241
|
+
)
|
|
5242
|
+
})),
|
|
5243
|
+
async (cid, transfers) => {
|
|
5244
|
+
try {
|
|
5245
|
+
return await batchTransfer(cid, transfers);
|
|
5246
|
+
} catch (error) {
|
|
5247
|
+
if (!(error instanceof OwneyError) || error.code !== "PERMIT2_APPROVAL_REQUIRED")
|
|
5248
|
+
throw error;
|
|
5249
|
+
await this.approvePermit2(asset);
|
|
5250
|
+
return batchTransfer(cid, transfers);
|
|
5251
|
+
}
|
|
5252
|
+
}
|
|
5253
|
+
);
|
|
5254
|
+
}
|
|
5169
5255
|
const agentResults = {};
|
|
5170
5256
|
for (const [
|
|
5171
5257
|
index,
|
|
@@ -5205,7 +5291,7 @@ var OwneySDK = class {
|
|
|
5205
5291
|
*
|
|
5206
5292
|
* 1. Missing Permit2 allowance: when the app did not supply its own
|
|
5207
5293
|
* callback and the attempt fails with `PERMIT2_APPROVAL_REQUIRED` on a
|
|
5208
|
-
*
|
|
5294
|
+
* token deposit, this is the wallet's first Permit2 deposit for that token. We send
|
|
5209
5295
|
* the one-time (user-paid) Permit2 approval via `approvePermit2()` and
|
|
5210
5296
|
* retry the SAME sponsored attempt once. Bounded to one approval attempt
|
|
5211
5297
|
* per call so a wallet/agent that keeps reporting the allowance as
|
|
@@ -5242,12 +5328,12 @@ var OwneySDK = class {
|
|
|
5242
5328
|
try {
|
|
5243
5329
|
return await attempt(effectiveCallback);
|
|
5244
5330
|
} catch (error) {
|
|
5245
|
-
if (!approvalAttempted && appCallback === void 0 && asset === "WETH" && error instanceof OwneyError && error.code === "PERMIT2_APPROVAL_REQUIRED") {
|
|
5331
|
+
if (!approvalAttempted && appCallback === void 0 && (asset === "WETH" || asset === "USDC") && error instanceof OwneyError && error.code === "PERMIT2_APPROVAL_REQUIRED") {
|
|
5246
5332
|
approvalAttempted = true;
|
|
5247
5333
|
console.warn(
|
|
5248
|
-
"[owney-sdk] First
|
|
5334
|
+
"[owney-sdk] First token deposit: sending one-time Permit2 approval..."
|
|
5249
5335
|
);
|
|
5250
|
-
await this.approvePermit2();
|
|
5336
|
+
await this.approvePermit2(asset);
|
|
5251
5337
|
continue;
|
|
5252
5338
|
}
|
|
5253
5339
|
if (!shouldFallbackToUserPaid(error, asset, appCallback)) throw error;
|
|
@@ -5900,30 +5986,29 @@ var OwneySDK = class {
|
|
|
5900
5986
|
return pending;
|
|
5901
5987
|
}
|
|
5902
5988
|
/**
|
|
5903
|
-
* One-time, user-paid approval of Permit2 on the
|
|
5904
|
-
* the active chain. Required once per wallet
|
|
5989
|
+
* One-time, user-paid approval of Permit2 on the selected token for
|
|
5990
|
+
* the active chain. Required once per wallet, token and chain before sponsored
|
|
5905
5991
|
* deposits; afterwards deposit() is signature-only. Resolves only after the
|
|
5906
5992
|
* approval transaction is mined (1 confirmation), so a subsequent deposit()
|
|
5907
5993
|
* will see the new allowance; throws if the transaction reverted.
|
|
5908
5994
|
* @returns the approval transaction hash.
|
|
5909
5995
|
*/
|
|
5910
5996
|
async approvePermit2(asset = "WETH") {
|
|
5911
|
-
void asset;
|
|
5912
5997
|
const state = this.requireState();
|
|
5913
5998
|
const chainId = this.requireChainId();
|
|
5914
|
-
this.
|
|
5915
|
-
const token =
|
|
5999
|
+
this.getEligibleAgents(chainId, asset, { excludeDisabled: true });
|
|
6000
|
+
const token = sponsoredTokensFor(asset)[chainId];
|
|
5916
6001
|
if (!token) {
|
|
5917
6002
|
throw new OwneyError(
|
|
5918
6003
|
"CHAIN_UNSUPPORTED",
|
|
5919
|
-
`No sponsored
|
|
6004
|
+
`No sponsored token on chain ${chainId}`
|
|
5920
6005
|
);
|
|
5921
6006
|
}
|
|
5922
6007
|
const provider = this.requireConnectedProvider();
|
|
5923
|
-
const wallet = (0,
|
|
6008
|
+
const wallet = (0, import_viem11.createWalletClient)({
|
|
5924
6009
|
account: state.walletAddress,
|
|
5925
6010
|
chain: VIEM_CHAIN2[chainId],
|
|
5926
|
-
transport: (0,
|
|
6011
|
+
transport: (0, import_viem11.custom)(provider)
|
|
5927
6012
|
});
|
|
5928
6013
|
const hash = await wallet.writeContract({
|
|
5929
6014
|
address: token,
|
|
@@ -5933,9 +6018,9 @@ var OwneySDK = class {
|
|
|
5933
6018
|
account: state.walletAddress,
|
|
5934
6019
|
chain: VIEM_CHAIN2[chainId]
|
|
5935
6020
|
});
|
|
5936
|
-
const publicClient = (0,
|
|
6021
|
+
const publicClient = (0, import_viem11.createPublicClient)({
|
|
5937
6022
|
chain: VIEM_CHAIN2[chainId],
|
|
5938
|
-
transport: (0,
|
|
6023
|
+
transport: (0, import_viem11.custom)(provider)
|
|
5939
6024
|
});
|
|
5940
6025
|
const receipt = await publicClient.waitForTransactionReceipt({
|
|
5941
6026
|
hash,
|
|
@@ -6049,7 +6134,7 @@ var OwneySDK = class {
|
|
|
6049
6134
|
};
|
|
6050
6135
|
|
|
6051
6136
|
// src/agents/zyfai/zyfai.siwx.ts
|
|
6052
|
-
var
|
|
6137
|
+
var import_viem12 = require("viem");
|
|
6053
6138
|
var import_siwe2 = require("siwe");
|
|
6054
6139
|
var import_sdk2 = require("@zyfai/sdk");
|
|
6055
6140
|
|
|
@@ -6176,7 +6261,7 @@ function buildSIWXConfig(deps) {
|
|
|
6176
6261
|
issuedAt,
|
|
6177
6262
|
toString() {
|
|
6178
6263
|
return new import_siwe2.SiweMessage({
|
|
6179
|
-
address: (0,
|
|
6264
|
+
address: (0, import_viem12.getAddress)(accountAddress),
|
|
6180
6265
|
chainId: numericChainId(chainId),
|
|
6181
6266
|
domain,
|
|
6182
6267
|
uri,
|