@owney/sdk 0.7.10-beta.0 → 0.7.11
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 +238 -891
- package/dist/index.d.cts +11 -30
- package/dist/index.d.ts +11 -30
- package/dist/index.js +214 -210
- package/package.json +2 -4
- package/dist/chunk-PWIKIQOX.js +0 -140
- package/dist/surfliquid.agent-VNGQUSXN.js +0 -473
package/dist/index.js
CHANGED
|
@@ -1,17 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
AgentChainIncompatibleError,
|
|
3
|
-
AgentNotFoundError,
|
|
4
|
-
ERC20_ALLOWANCE_ABI,
|
|
5
|
-
MAX_UINT256,
|
|
6
|
-
NotConnectedError,
|
|
7
|
-
OwneyError,
|
|
8
|
-
PERMIT2_ADDRESS,
|
|
9
|
-
buildPermitTransferFromTypedData,
|
|
10
|
-
randomPermit2Nonce,
|
|
11
|
-
readErc20Balance,
|
|
12
|
-
readPermit2Allowance
|
|
13
|
-
} from "./chunk-PWIKIQOX.js";
|
|
14
|
-
|
|
15
1
|
// src/agents/zyfai/zyfai.agent.ts
|
|
16
2
|
import { SMART_SESSIONS_VALIDATOR, ZyfaiSDK } from "@zyfai/sdk";
|
|
17
3
|
import { createPublicClient, http, parseAbi } from "viem";
|
|
@@ -70,6 +56,55 @@ var SupportedAssets = [
|
|
|
70
56
|
}
|
|
71
57
|
];
|
|
72
58
|
|
|
59
|
+
// src/errors.ts
|
|
60
|
+
var OwneyError = class extends Error {
|
|
61
|
+
code;
|
|
62
|
+
details;
|
|
63
|
+
agentId;
|
|
64
|
+
constructor(code, message, details, agentId) {
|
|
65
|
+
const prefix = agentId ? `[${code}][agent:${agentId}]` : `[${code}]`;
|
|
66
|
+
super(`${prefix} ${message}`);
|
|
67
|
+
this.name = "OwneyError";
|
|
68
|
+
this.code = code;
|
|
69
|
+
this.details = details;
|
|
70
|
+
this.agentId = agentId;
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
var AgentNotFoundError = class extends OwneyError {
|
|
74
|
+
constructor(agentId, available) {
|
|
75
|
+
super(
|
|
76
|
+
"AGENT_NOT_FOUND",
|
|
77
|
+
`Unknown agent "${agentId}". Available agents: ${available.join(", ")}`,
|
|
78
|
+
{ agentId, available },
|
|
79
|
+
agentId
|
|
80
|
+
);
|
|
81
|
+
this.name = "AgentNotFoundError";
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
var NotConnectedError = class extends OwneyError {
|
|
85
|
+
constructor() {
|
|
86
|
+
super("NOT_CONNECTED", "Not connected. Call sdk.connect(provider) first.");
|
|
87
|
+
this.name = "NotConnectedError";
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
var AgentChainIncompatibleError = class extends OwneyError {
|
|
91
|
+
incompatibleAgents;
|
|
92
|
+
connectedChainId;
|
|
93
|
+
constructor(incompatibleAgents, connectedChainId) {
|
|
94
|
+
const details = incompatibleAgents.map(
|
|
95
|
+
({ agentId, supportedChainIds }) => `"${agentId}" supports chains [${supportedChainIds.join(", ")}]`
|
|
96
|
+
).join("; ");
|
|
97
|
+
super(
|
|
98
|
+
"AGENT_CHAIN_INCOMPATIBLE",
|
|
99
|
+
`Chain ${connectedChainId} is not supported by the following agents: ${details}`,
|
|
100
|
+
{ incompatibleAgents, connectedChainId }
|
|
101
|
+
);
|
|
102
|
+
this.name = "AgentChainIncompatibleError";
|
|
103
|
+
this.incompatibleAgents = incompatibleAgents;
|
|
104
|
+
this.connectedChainId = connectedChainId;
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
73
108
|
// src/lib/utils.ts
|
|
74
109
|
var isValidChainId = (chainId) => {
|
|
75
110
|
if (!SUPPORTED_CHAIN_IDS.includes(chainId)) {
|
|
@@ -81,12 +116,6 @@ var isValidChainId = (chainId) => {
|
|
|
81
116
|
}
|
|
82
117
|
return chainId;
|
|
83
118
|
};
|
|
84
|
-
function isSameAsset(tokenSymbol, asset) {
|
|
85
|
-
const token = tokenSymbol.toLowerCase();
|
|
86
|
-
const target = asset.toLowerCase();
|
|
87
|
-
if (token === target) return true;
|
|
88
|
-
return target === "weth" && token === "eth" || target === "eth" && token === "weth";
|
|
89
|
-
}
|
|
90
119
|
function hexToDecimal(hex, decimals = 6) {
|
|
91
120
|
const normalized = hex.startsWith("0x") || hex.startsWith("0X") ? hex : `0x${hex}`;
|
|
92
121
|
const parsed = BigInt(normalized);
|
|
@@ -120,10 +149,6 @@ var DECIMALS_BY_SYMBOL = {
|
|
|
120
149
|
wbtc: 8,
|
|
121
150
|
cbbtc: 8
|
|
122
151
|
};
|
|
123
|
-
function canonicalSymbol(symbol) {
|
|
124
|
-
const upper = symbol.toUpperCase();
|
|
125
|
-
return upper === "ETH" ? "WETH" : upper;
|
|
126
|
-
}
|
|
127
152
|
function tokenDecimals(symbol, explicit) {
|
|
128
153
|
if (typeof explicit === "number" && Number.isFinite(explicit))
|
|
129
154
|
return explicit;
|
|
@@ -188,89 +213,55 @@ function mapPendingAllocations(raw) {
|
|
|
188
213
|
function mapBalances(raw, _chainId, smartWallet) {
|
|
189
214
|
const portfolio = raw.portfolio;
|
|
190
215
|
const portfolioByChain = portfolio.portfolioByChain ?? {};
|
|
191
|
-
const rawPositions = portfolio.positions ?? [];
|
|
192
|
-
const detailByKey = /* @__PURE__ */ new Map();
|
|
193
|
-
for (const p of rawPositions) {
|
|
194
|
-
const cid = resolveChainId(p.chain ?? "");
|
|
195
|
-
const symbol = canonicalSymbol(p.token_symbol ?? "");
|
|
196
|
-
if (Number.isFinite(cid) && symbol) detailByKey.set(`${cid}:${symbol}`, p);
|
|
197
|
-
}
|
|
198
216
|
let totalBalance = 0;
|
|
199
217
|
const tokens = [];
|
|
200
|
-
const positions = [];
|
|
201
218
|
for (const [chainIdKey, tokensBySymbol] of Object.entries(portfolioByChain)) {
|
|
202
219
|
const positionChainId = Number(chainIdKey);
|
|
203
|
-
const chainName2 = CHAIN_ID_TO_NAME[positionChainId] ?? "BASE";
|
|
204
220
|
for (const [
|
|
205
221
|
symbol,
|
|
206
222
|
{ balance, balanceWithFee, decimals }
|
|
207
223
|
] of Object.entries(tokensBySymbol ?? {})) {
|
|
208
|
-
const amount = hexToDecimal(
|
|
209
|
-
balanceWithFee ?? balance ?? "0",
|
|
210
|
-
tokenDecimals(symbol, decimals)
|
|
211
|
-
);
|
|
224
|
+
const amount = hexToDecimal(balanceWithFee ?? balance ?? "0", decimals);
|
|
212
225
|
totalBalance += amount;
|
|
213
226
|
tokens.push({
|
|
214
|
-
chain:
|
|
227
|
+
chain: CHAIN_ID_TO_NAME[positionChainId] ?? "BASE",
|
|
215
228
|
chainId: positionChainId,
|
|
216
229
|
asset: symbol,
|
|
217
230
|
amount: String(amount)
|
|
218
231
|
});
|
|
219
|
-
const detail = detailByKey.get(
|
|
220
|
-
`${positionChainId}:${canonicalSymbol(symbol)}`
|
|
221
|
-
);
|
|
222
|
-
positions.push({
|
|
223
|
-
chain: chainName2,
|
|
224
|
-
protocol: detail?.protocol_name ?? detail?.protocol_id ?? "",
|
|
225
|
-
protocolId: detail?.protocol_id,
|
|
226
|
-
pool: detail?.pool,
|
|
227
|
-
// Report the token the way the rest of owney spells it ("WETH", as the
|
|
228
|
-
// pre-portfolioByChain mapper did), not Zyfai's internal "eth".
|
|
229
|
-
asset: canonicalSymbol(symbol),
|
|
230
|
-
amount: String(amount),
|
|
231
|
-
apy: detail?.pool_apy,
|
|
232
|
-
tvl: detail?.pool_tvl,
|
|
233
|
-
// PositionSlot has no `liquidity` field yet; Zyfai will add it. Narrow
|
|
234
|
-
// structural read keeps it undefined today and auto-populates later.
|
|
235
|
-
liquidity: detail?.liquidity
|
|
236
|
-
});
|
|
237
232
|
}
|
|
238
233
|
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
liquidity: p.liquidity
|
|
271
|
-
}))
|
|
272
|
-
);
|
|
273
|
-
}
|
|
234
|
+
const positions = (portfolio.positions ?? []).map((p) => ({
|
|
235
|
+
chain: p.chain ?? "",
|
|
236
|
+
protocol: p.protocol_name ?? p.protocol_id ?? "",
|
|
237
|
+
protocolId: p.protocol_id,
|
|
238
|
+
pool: p.pool,
|
|
239
|
+
asset: p.token_symbol ?? "",
|
|
240
|
+
// Fee-adjusted underlying amounts are decimal base-unit strings. The
|
|
241
|
+
// legacy `amount` fallback is hex. Runtime
|
|
242
|
+
// getBalances payloads often carry one (e.g. 18 for WETH) — prefer that
|
|
243
|
+
// when present, otherwise fall back to the per-symbol lookup.
|
|
244
|
+
amount: String(
|
|
245
|
+
p.underlyingAmountWithFee ?? p.underlyingAmount ? normalizeDecimalPlace(
|
|
246
|
+
p.underlyingAmountWithFee ?? p.underlyingAmount ?? "0",
|
|
247
|
+
tokenDecimals(
|
|
248
|
+
p.token_symbol,
|
|
249
|
+
p.decimals
|
|
250
|
+
)
|
|
251
|
+
) : hexToDecimal(
|
|
252
|
+
p.amount || "0",
|
|
253
|
+
tokenDecimals(
|
|
254
|
+
p.token_symbol,
|
|
255
|
+
p.decimals
|
|
256
|
+
)
|
|
257
|
+
)
|
|
258
|
+
),
|
|
259
|
+
apy: p.pool_apy,
|
|
260
|
+
tvl: p.pool_tvl,
|
|
261
|
+
// PositionSlot has no `liquidity` field yet; Zyfai will add it. Narrow
|
|
262
|
+
// structural read keeps it undefined today and auto-populates later.
|
|
263
|
+
liquidity: p.liquidity
|
|
264
|
+
}));
|
|
274
265
|
const pendingAllocations = mapPendingAllocations(
|
|
275
266
|
portfolio.staleBalances
|
|
276
267
|
);
|
|
@@ -861,7 +852,7 @@ var VIEM_CHAIN = { 8453: base, 42161: arbitrum, 1: mainnet };
|
|
|
861
852
|
var SPLITTING_ASSETS = ["USDC", "WETH"];
|
|
862
853
|
var POOL_POLICY_CHAIN_IDS = [8453, 42161, 1];
|
|
863
854
|
var EARNINGS_REFRESH_COOLDOWN_MS = 60 * 60 * 1e3;
|
|
864
|
-
var ZyfaiAgent = class {
|
|
855
|
+
var ZyfaiAgent = class _ZyfaiAgent {
|
|
865
856
|
id = "zyfai";
|
|
866
857
|
supportedChainIds = [8453, 42161, 1];
|
|
867
858
|
supportedAssets = [
|
|
@@ -1353,37 +1344,6 @@ var ZyfaiAgent = class {
|
|
|
1353
1344
|
);
|
|
1354
1345
|
}
|
|
1355
1346
|
}
|
|
1356
|
-
/**
|
|
1357
|
-
* Records the deposit with Zyfai, retrying transient failures.
|
|
1358
|
-
*
|
|
1359
|
-
* This runs AFTER the transfer has already landed on-chain, so it must never
|
|
1360
|
-
* fail the deposit — the funds moved. But it is also the ONLY source of the
|
|
1361
|
-
* "Top up wallet" entry the history is built from: Zyfai auto-deploys the
|
|
1362
|
-
* balance it detects either way, so when this call is lost the user's deposit
|
|
1363
|
-
* never appears in Activity (an earlier withdrawal stays the newest row) and
|
|
1364
|
-
* nothing ever backfills it. Retry, then log loudly enough to be recoverable.
|
|
1365
|
-
*/
|
|
1366
|
-
async logDepositWithRetry(chainId, txHash, amount, tokenAddress) {
|
|
1367
|
-
const ATTEMPTS = 3;
|
|
1368
|
-
const RETRY_DELAY_MS = 1e3;
|
|
1369
|
-
for (let attempt = 1; attempt <= ATTEMPTS; attempt++) {
|
|
1370
|
-
try {
|
|
1371
|
-
await (tokenAddress ? this.sdk.logDeposit(chainId, txHash, amount, tokenAddress) : this.sdk.logDeposit(chainId, txHash, amount));
|
|
1372
|
-
return;
|
|
1373
|
-
} catch (logError) {
|
|
1374
|
-
if (attempt === ATTEMPTS) {
|
|
1375
|
-
console.error(
|
|
1376
|
-
"[owney-sdk] Deposit landed on-chain but logDeposit failed \u2014 it will be missing from Zyfai history:",
|
|
1377
|
-
{ txHash, chainId, amount, tokenAddress, error: logError }
|
|
1378
|
-
);
|
|
1379
|
-
return;
|
|
1380
|
-
}
|
|
1381
|
-
await new Promise(
|
|
1382
|
-
(resolve) => setTimeout(resolve, RETRY_DELAY_MS * attempt)
|
|
1383
|
-
);
|
|
1384
|
-
}
|
|
1385
|
-
}
|
|
1386
|
-
}
|
|
1387
1347
|
/**
|
|
1388
1348
|
* True when `smartWallet` is the backend-managed pool wallet Zyfai assigned
|
|
1389
1349
|
* to this EOA — the "new wallet" kind that is predeployed on the chains it
|
|
@@ -1687,12 +1647,14 @@ var ZyfaiAgent = class {
|
|
|
1687
1647
|
);
|
|
1688
1648
|
const txHash = await depositCallback(smartWallet, validChainId, amount);
|
|
1689
1649
|
const tokenAddress = asset === "WETH" ? WETH_ADDRESS_BY_CHAIN[validChainId] : void 0;
|
|
1690
|
-
|
|
1691
|
-
validChainId,
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1650
|
+
try {
|
|
1651
|
+
await (tokenAddress ? this.sdk.logDeposit(validChainId, txHash, amount, tokenAddress) : this.sdk.logDeposit(validChainId, txHash, amount));
|
|
1652
|
+
} catch (logError) {
|
|
1653
|
+
console.warn(
|
|
1654
|
+
"[owney-sdk] Deposit landed on-chain but logDeposit failed (non-fatal):",
|
|
1655
|
+
logError
|
|
1656
|
+
);
|
|
1657
|
+
}
|
|
1696
1658
|
return { txHash, smartWallet, amount };
|
|
1697
1659
|
}
|
|
1698
1660
|
await this.ensureWalletDeployed(this.getAddress(), validChainId);
|
|
@@ -1760,9 +1722,30 @@ var ZyfaiAgent = class {
|
|
|
1760
1722
|
const raw = await this.sdk.getDailyApyHistory(smartWallet, days);
|
|
1761
1723
|
return mapApyHistory(raw, chainId, tokenSymbol);
|
|
1762
1724
|
}
|
|
1725
|
+
/**
|
|
1726
|
+
* Owney speaks asset symbols ("USDC" / "WETH"); Zyfai's history endpoint
|
|
1727
|
+
* takes lowercase `assetType` and denominates WETH as "eth" (the same
|
|
1728
|
+
* spelling `resolveWithdrawnAmounts` normalizes on the way in). Anything
|
|
1729
|
+
* unrecognised returns undefined so the request stays unfiltered rather
|
|
1730
|
+
* than silently narrowing to nothing.
|
|
1731
|
+
*/
|
|
1732
|
+
static toZyfaiAssetType(tokenSymbol) {
|
|
1733
|
+
switch (tokenSymbol?.toUpperCase()) {
|
|
1734
|
+
case "USDC":
|
|
1735
|
+
return "usdc";
|
|
1736
|
+
case "WETH":
|
|
1737
|
+
case "ETH":
|
|
1738
|
+
return "eth";
|
|
1739
|
+
case "EURC":
|
|
1740
|
+
return "eurc";
|
|
1741
|
+
default:
|
|
1742
|
+
return void 0;
|
|
1743
|
+
}
|
|
1744
|
+
}
|
|
1763
1745
|
async getHistory(state, chainId, options) {
|
|
1764
1746
|
const { smartWallet, chainId: validChainId } = await this.resolveSmartWallet(state, chainId);
|
|
1765
1747
|
const limit = options?.limit ?? 10;
|
|
1748
|
+
const assetType = _ZyfaiAgent.toZyfaiAssetType(options?.tokenSymbol);
|
|
1766
1749
|
const cursor = options?.cursor ? decodeHistoryCursor(options.cursor) : null;
|
|
1767
1750
|
const toDate = cursor?.toDate ?? options?.toDate ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
1768
1751
|
let offset = cursor?.rawOffset ?? 0;
|
|
@@ -1776,7 +1759,12 @@ var ZyfaiAgent = class {
|
|
|
1776
1759
|
limit: backendPageSize,
|
|
1777
1760
|
offset,
|
|
1778
1761
|
fromDate: options?.fromDate,
|
|
1779
|
-
toDate
|
|
1762
|
+
toDate,
|
|
1763
|
+
// Filtering server-side means the pages coming back are already the
|
|
1764
|
+
// asset the caller asked for, so the loop below fills `limit` from
|
|
1765
|
+
// relevant entries instead of spending its budget on the other
|
|
1766
|
+
// asset's rows and handing back a page that filters to nothing.
|
|
1767
|
+
assetType
|
|
1780
1768
|
});
|
|
1781
1769
|
raw.data.forEach((entry, idx) => {
|
|
1782
1770
|
if (entry.chainId === validChainId) {
|
|
@@ -1947,10 +1935,11 @@ async function withFailureReporting(apiKey, agentType, fn) {
|
|
|
1947
1935
|
// src/lib/helpers/withdraw-helper.ts
|
|
1948
1936
|
import { parseUnits } from "viem";
|
|
1949
1937
|
function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
|
|
1938
|
+
const target = asset.toUpperCase();
|
|
1950
1939
|
return agents.map((agent) => {
|
|
1951
1940
|
const agentBalance = aggregated[agent.id];
|
|
1952
1941
|
const tokenBalance = agentBalance?.tokens.find(
|
|
1953
|
-
(t) => t.chainId === chainId &&
|
|
1942
|
+
(t) => t.chainId === chainId && t.asset.toUpperCase() === target
|
|
1954
1943
|
);
|
|
1955
1944
|
if (!tokenBalance) return { agent, balance: 0n };
|
|
1956
1945
|
return { agent, balance: parseUnits(tokenBalance.amount, decimals) };
|
|
@@ -2220,6 +2209,84 @@ async function getSponsorRelayerAddress(input) {
|
|
|
2220
2209
|
return parsed.data.relayer;
|
|
2221
2210
|
}
|
|
2222
2211
|
|
|
2212
|
+
// src/lib/permit2.ts
|
|
2213
|
+
import { bytesToHex as bytesToHex2 } from "viem";
|
|
2214
|
+
var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
2215
|
+
var MAX_UINT256 = 2n ** 256n - 1n;
|
|
2216
|
+
var ERC20_ALLOWANCE_ABI = [
|
|
2217
|
+
{
|
|
2218
|
+
type: "function",
|
|
2219
|
+
name: "allowance",
|
|
2220
|
+
stateMutability: "view",
|
|
2221
|
+
inputs: [
|
|
2222
|
+
{ name: "owner", type: "address" },
|
|
2223
|
+
{ name: "spender", type: "address" }
|
|
2224
|
+
],
|
|
2225
|
+
outputs: [{ name: "", type: "uint256" }]
|
|
2226
|
+
},
|
|
2227
|
+
{
|
|
2228
|
+
type: "function",
|
|
2229
|
+
name: "approve",
|
|
2230
|
+
stateMutability: "nonpayable",
|
|
2231
|
+
inputs: [
|
|
2232
|
+
{ name: "spender", type: "address" },
|
|
2233
|
+
{ name: "amount", type: "uint256" }
|
|
2234
|
+
],
|
|
2235
|
+
outputs: [{ name: "", type: "bool" }]
|
|
2236
|
+
},
|
|
2237
|
+
{
|
|
2238
|
+
type: "function",
|
|
2239
|
+
name: "balanceOf",
|
|
2240
|
+
stateMutability: "view",
|
|
2241
|
+
inputs: [{ name: "account", type: "address" }],
|
|
2242
|
+
outputs: [{ name: "", type: "uint256" }]
|
|
2243
|
+
}
|
|
2244
|
+
];
|
|
2245
|
+
function buildPermitTransferFromTypedData(input) {
|
|
2246
|
+
return {
|
|
2247
|
+
domain: {
|
|
2248
|
+
name: "Permit2",
|
|
2249
|
+
chainId: input.chainId,
|
|
2250
|
+
verifyingContract: PERMIT2_ADDRESS
|
|
2251
|
+
},
|
|
2252
|
+
types: {
|
|
2253
|
+
PermitTransferFrom: [
|
|
2254
|
+
{ name: "permitted", type: "TokenPermissions" },
|
|
2255
|
+
{ name: "spender", type: "address" },
|
|
2256
|
+
{ name: "nonce", type: "uint256" },
|
|
2257
|
+
{ name: "deadline", type: "uint256" }
|
|
2258
|
+
],
|
|
2259
|
+
TokenPermissions: [
|
|
2260
|
+
{ name: "token", type: "address" },
|
|
2261
|
+
{ name: "amount", type: "uint256" }
|
|
2262
|
+
]
|
|
2263
|
+
},
|
|
2264
|
+
primaryType: "PermitTransferFrom",
|
|
2265
|
+
message: input.message
|
|
2266
|
+
};
|
|
2267
|
+
}
|
|
2268
|
+
function randomPermit2Nonce() {
|
|
2269
|
+
const bytes = new Uint8Array(32);
|
|
2270
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
2271
|
+
return BigInt(bytesToHex2(bytes));
|
|
2272
|
+
}
|
|
2273
|
+
async function readPermit2Allowance(publicClient, token, owner) {
|
|
2274
|
+
return publicClient.readContract({
|
|
2275
|
+
address: token,
|
|
2276
|
+
abi: ERC20_ALLOWANCE_ABI,
|
|
2277
|
+
functionName: "allowance",
|
|
2278
|
+
args: [owner, PERMIT2_ADDRESS]
|
|
2279
|
+
});
|
|
2280
|
+
}
|
|
2281
|
+
async function readErc20Balance(publicClient, token, owner) {
|
|
2282
|
+
return publicClient.readContract({
|
|
2283
|
+
address: token,
|
|
2284
|
+
abi: ERC20_ALLOWANCE_ABI,
|
|
2285
|
+
functionName: "balanceOf",
|
|
2286
|
+
args: [owner]
|
|
2287
|
+
});
|
|
2288
|
+
}
|
|
2289
|
+
|
|
2223
2290
|
// src/lib/chain-guard.ts
|
|
2224
2291
|
var CHAIN_NAMES = {
|
|
2225
2292
|
1: "Ethereum",
|
|
@@ -2538,7 +2605,6 @@ var VIEM_CHAIN2 = {
|
|
|
2538
2605
|
42161: arbitrum2,
|
|
2539
2606
|
1: mainnet2
|
|
2540
2607
|
};
|
|
2541
|
-
var AGENT_ELIGIBILITY_ORDER = ["surfliquid", "zyfai", "sail"];
|
|
2542
2608
|
var SPONSORED_WETH_BY_CHAIN = {
|
|
2543
2609
|
8453: "0x4200000000000000000000000000000000000006",
|
|
2544
2610
|
42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
|
|
@@ -2567,7 +2633,6 @@ var OwneySDK = class {
|
|
|
2567
2633
|
zyfaiRpcUrls;
|
|
2568
2634
|
routingApiBaseUrl;
|
|
2569
2635
|
referralSource;
|
|
2570
|
-
surfliquidApiBaseUrl;
|
|
2571
2636
|
cachedSponsoredCallback = null;
|
|
2572
2637
|
cachedWethSponsoredCallback = null;
|
|
2573
2638
|
paymasterServiceUrl;
|
|
@@ -2580,7 +2645,6 @@ var OwneySDK = class {
|
|
|
2580
2645
|
this.routingApiBaseUrl = config.routingApiBaseUrl;
|
|
2581
2646
|
this.paymasterServiceUrl = config.paymasterServiceUrl;
|
|
2582
2647
|
this.referralSource = config.referralSource;
|
|
2583
|
-
this.surfliquidApiBaseUrl = config.surfliquidApiBaseUrl;
|
|
2584
2648
|
}
|
|
2585
2649
|
/**
|
|
2586
2650
|
* Establish connection state for all subsequent SDK calls.
|
|
@@ -2810,8 +2874,8 @@ var OwneySDK = class {
|
|
|
2810
2874
|
this.initializingAgentsPromise = (async () => {
|
|
2811
2875
|
const agentKeys = await fetchAgentKeys(this.apiKey);
|
|
2812
2876
|
this.disabledAgents.clear();
|
|
2813
|
-
for (const { key: key2, agent_type,
|
|
2814
|
-
const agent =
|
|
2877
|
+
for (const { key: key2, agent_type, is_enabled } of agentKeys) {
|
|
2878
|
+
const agent = this.createAgent(agent_type, key2);
|
|
2815
2879
|
if (!agent) continue;
|
|
2816
2880
|
this.agents.set(agent_type, agent);
|
|
2817
2881
|
if (is_enabled === false) {
|
|
@@ -2832,22 +2896,10 @@ var OwneySDK = class {
|
|
|
2832
2896
|
this.initializingAgentsPromise = null;
|
|
2833
2897
|
}
|
|
2834
2898
|
}
|
|
2835
|
-
|
|
2899
|
+
createAgent(agentId, key2) {
|
|
2836
2900
|
if (agentId === "zyfai") {
|
|
2837
2901
|
return new ZyfaiAgent(key2, this.zyfaiRpcUrls, this.referralSource);
|
|
2838
2902
|
}
|
|
2839
|
-
if (agentId === "surfliquid") {
|
|
2840
|
-
if (!projectName) return null;
|
|
2841
|
-
const { SurfLiquidAgent } = await import("./surfliquid.agent-VNGQUSXN.js");
|
|
2842
|
-
return new SurfLiquidAgent({
|
|
2843
|
-
projectName,
|
|
2844
|
-
appId: key2,
|
|
2845
|
-
// Same-origin proxy override — SurfLiquid auth is an httpOnly cookie,
|
|
2846
|
-
// which WebKit (iOS) discards when it is third-party. See
|
|
2847
|
-
// OwneySDKConfig.surfliquidApiBaseUrl.
|
|
2848
|
-
apiBaseUrl: this.surfliquidApiBaseUrl
|
|
2849
|
-
});
|
|
2850
|
-
}
|
|
2851
2903
|
return null;
|
|
2852
2904
|
}
|
|
2853
2905
|
// --- Account lifecycle ---
|
|
@@ -3002,30 +3054,18 @@ var OwneySDK = class {
|
|
|
3002
3054
|
);
|
|
3003
3055
|
}
|
|
3004
3056
|
const agentResults = {};
|
|
3005
|
-
const agentErrors = {};
|
|
3006
3057
|
for (const { agent, amount: agentAmount } of agentAmounts) {
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
depositCallback
|
|
3016
|
-
);
|
|
3017
|
-
} catch (error) {
|
|
3018
|
-
agentErrors[agent.id] = error instanceof Error ? error.message : String(error);
|
|
3019
|
-
}
|
|
3020
|
-
}
|
|
3021
|
-
if (Object.keys(agentResults).length === 0) {
|
|
3022
|
-
throw new OwneyError(
|
|
3023
|
-
"DEPOSIT_ALL_FAILED",
|
|
3024
|
-
`All ${agentAmounts.length} agent deposit(s) failed.`,
|
|
3025
|
-
{ agentErrors }
|
|
3058
|
+
agentResults[agent.id] = await this.depositWithFallback(
|
|
3059
|
+
agent,
|
|
3060
|
+
state,
|
|
3061
|
+
chainId,
|
|
3062
|
+
agentAmount,
|
|
3063
|
+
asset,
|
|
3064
|
+
effectiveCallback,
|
|
3065
|
+
depositCallback
|
|
3026
3066
|
);
|
|
3027
3067
|
}
|
|
3028
|
-
return
|
|
3068
|
+
return { agentResults };
|
|
3029
3069
|
}
|
|
3030
3070
|
/**
|
|
3031
3071
|
* Invokes `agent.deposit` with the resolved sponsored callback, composing
|
|
@@ -3141,8 +3181,9 @@ var OwneySDK = class {
|
|
|
3141
3181
|
async hasExistingBalance(agent, state, chainId, asset) {
|
|
3142
3182
|
try {
|
|
3143
3183
|
const balance = await agent.getBalances(state, chainId);
|
|
3184
|
+
const target = asset.toLowerCase();
|
|
3144
3185
|
const token = balance.tokens.find(
|
|
3145
|
-
(t) => t.chainId === chainId &&
|
|
3186
|
+
(t) => t.chainId === chainId && t.asset.toLowerCase() === target
|
|
3146
3187
|
);
|
|
3147
3188
|
return !!token && Number(token.amount) > 0;
|
|
3148
3189
|
} catch {
|
|
@@ -3181,34 +3222,6 @@ var OwneySDK = class {
|
|
|
3181
3222
|
}
|
|
3182
3223
|
return eligible;
|
|
3183
3224
|
}
|
|
3184
|
-
/**
|
|
3185
|
-
* Agent ids the routing API provisioned for this org that support the given
|
|
3186
|
-
* chain + asset, ordered by preference ({@link AGENT_ELIGIBILITY_ORDER},
|
|
3187
|
-
* surfliquid first). Returns `[]` when the org has no compatible agent — never
|
|
3188
|
-
* throws on an empty org. Loads agent keys on first call (apiKey only, no
|
|
3189
|
-
* wallet), so the UI can resolve which agent to use before the user connects.
|
|
3190
|
-
*
|
|
3191
|
-
* This is the source of truth for agent availability: an agent appears here
|
|
3192
|
-
* iff the routing API returned its key. No per-app feature flags.
|
|
3193
|
-
*/
|
|
3194
|
-
async getEligibleAgentIds(chainId, asset) {
|
|
3195
|
-
try {
|
|
3196
|
-
await this.ensureAgentsInitialized();
|
|
3197
|
-
} catch (error) {
|
|
3198
|
-
if (error instanceof OwneyError && error.code === "API_NO_AGENTS") {
|
|
3199
|
-
return [];
|
|
3200
|
-
}
|
|
3201
|
-
throw error;
|
|
3202
|
-
}
|
|
3203
|
-
return [...this.agents.values()].filter((agent) => {
|
|
3204
|
-
const chainAssets = agent.supportedAssets.find(
|
|
3205
|
-
(sa) => sa.chainId === chainId
|
|
3206
|
-
);
|
|
3207
|
-
return chainAssets?.assets.some((a) => a.symbol === asset) ?? false;
|
|
3208
|
-
}).map((agent) => agent.id).sort(
|
|
3209
|
-
(a, b) => AGENT_ELIGIBILITY_ORDER.indexOf(a) - AGENT_ELIGIBILITY_ORDER.indexOf(b)
|
|
3210
|
-
);
|
|
3211
|
-
}
|
|
3212
3225
|
// --- Fund operations ---
|
|
3213
3226
|
/**
|
|
3214
3227
|
* Withdraw funds from a specific agent, or all agents that support the active chain+asset if agentId is omitted.
|
|
@@ -3244,17 +3257,9 @@ var OwneySDK = class {
|
|
|
3244
3257
|
}
|
|
3245
3258
|
const eligibleAgents = this.getEligibleAgents(chainId, asset);
|
|
3246
3259
|
if (!amount) {
|
|
3247
|
-
const aggregated2 = await this.getBalances();
|
|
3248
|
-
const funded = projectAgentBalancesForAsset(
|
|
3249
|
-
eligibleAgents,
|
|
3250
|
-
aggregated2.agentBalances,
|
|
3251
|
-
chainId,
|
|
3252
|
-
asset,
|
|
3253
|
-
assetInfo.decimals
|
|
3254
|
-
).filter((b) => b.balance > 0n);
|
|
3255
3260
|
const results2 = {};
|
|
3256
3261
|
const agentErrors2 = {};
|
|
3257
|
-
for (const
|
|
3262
|
+
for (const agent of eligibleAgents) {
|
|
3258
3263
|
try {
|
|
3259
3264
|
results2[agent.id] = await agent.withdraw(state, chainId, token);
|
|
3260
3265
|
} catch (err) {
|
|
@@ -3271,10 +3276,9 @@ var OwneySDK = class {
|
|
|
3271
3276
|
{ asset, agentErrors: agentErrors2 }
|
|
3272
3277
|
);
|
|
3273
3278
|
}
|
|
3274
|
-
const totalWithdrawn = funded.filter(({ agent }) => results2[agent.id] !== void 0).reduce((sum, { balance }) => sum + balance, 0n);
|
|
3275
3279
|
return {
|
|
3276
3280
|
agentResult: results2,
|
|
3277
|
-
totalWithdrawn:
|
|
3281
|
+
totalWithdrawn: sumWithdrawnAmount(results2).toString()
|
|
3278
3282
|
};
|
|
3279
3283
|
}
|
|
3280
3284
|
const requested = BigInt(amount);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owney/sdk",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.11",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -23,9 +23,7 @@
|
|
|
23
23
|
"test:watch": "vitest"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@
|
|
27
|
-
"@zyfai/sdk": "0.2.48",
|
|
28
|
-
"ethers": "^6.17.0",
|
|
26
|
+
"@zyfai/sdk": "0.2.50",
|
|
29
27
|
"siwe": "^3.0.0",
|
|
30
28
|
"viem": "^2.48.1"
|
|
31
29
|
},
|