@owney/sdk 0.6.9-beta.7 → 0.6.9-beta.9

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 CHANGED
@@ -334,27 +334,20 @@ var init_surfliquid_wallet_adapter = __esm({
334
334
  });
335
335
 
336
336
  // src/agents/surfliquid/surfliquid.morpho.ts
337
- async function fetchMorphoVaultStats(vaultAddress, chainId) {
337
+ async function queryMorpho(query, vaultAddress, chainId) {
338
338
  try {
339
339
  const res = await fetch(MORPHO_API_URL, {
340
340
  method: "POST",
341
341
  headers: { "Content-Type": "application/json" },
342
342
  body: JSON.stringify({
343
- query: VAULT_STATS_QUERY,
343
+ query,
344
344
  variables: { address: vaultAddress, chainId }
345
345
  })
346
346
  });
347
347
  if (!res.ok) return null;
348
348
  const json = await res.json();
349
349
  if (json.errors) return null;
350
- const vault = json.data?.vaultByAddress;
351
- const tvlUsd = vault?.state?.totalAssetsUsd;
352
- const liquidityUsd = vault?.liquidity?.usd;
353
- if (typeof tvlUsd !== "number" || typeof liquidityUsd !== "number") {
354
- return null;
355
- }
356
- const name = typeof vault?.name === "string" ? vault.name : null;
357
- return { name, tvlUsd, liquidityUsd };
350
+ return json.data ?? null;
358
351
  } catch (error) {
359
352
  console.warn("surfliquid: Morpho vault stats fetch failed", {
360
353
  vaultAddress,
@@ -364,6 +357,29 @@ async function fetchMorphoVaultStats(vaultAddress, chainId) {
364
357
  return null;
365
358
  }
366
359
  }
360
+ function toStats(name, tvlUsd, liquidityUsd) {
361
+ if (typeof tvlUsd !== "number" || typeof liquidityUsd !== "number") {
362
+ return null;
363
+ }
364
+ return {
365
+ name: typeof name === "string" ? name : null,
366
+ tvlUsd,
367
+ liquidityUsd
368
+ };
369
+ }
370
+ async function fetchMorphoVaultStats(vaultAddress, chainId) {
371
+ const v1 = await queryMorpho(VAULT_STATS_QUERY, vaultAddress, chainId);
372
+ const vault = v1?.vaultByAddress;
373
+ const v1Stats = toStats(
374
+ vault?.name,
375
+ vault?.state?.totalAssetsUsd,
376
+ vault?.liquidity?.usd
377
+ );
378
+ if (v1Stats) return v1Stats;
379
+ const v2 = await queryMorpho(VAULT_V2_STATS_QUERY, vaultAddress, chainId);
380
+ const vaultV2 = v2?.vaultV2ByAddress;
381
+ return toStats(vaultV2?.name, vaultV2?.totalAssetsUsd, vaultV2?.liquidityUsd);
382
+ }
367
383
  async function fetchMorphoStatsByVault(vaultAddresses, chainId) {
368
384
  const unique = [...new Set(vaultAddresses.map((a) => a.toLowerCase()))];
369
385
  const entries = await Promise.all(
@@ -377,7 +393,7 @@ async function fetchMorphoStatsByVault(vaultAddresses, chainId) {
377
393
  }
378
394
  return byVault;
379
395
  }
380
- var MORPHO_API_URL, VAULT_STATS_QUERY;
396
+ var MORPHO_API_URL, VAULT_STATS_QUERY, VAULT_V2_STATS_QUERY;
381
397
  var init_surfliquid_morpho = __esm({
382
398
  "src/agents/surfliquid/surfliquid.morpho.ts"() {
383
399
  "use strict";
@@ -390,6 +406,15 @@ var init_surfliquid_morpho = __esm({
390
406
  liquidity { usd }
391
407
  }
392
408
  }
409
+ `;
410
+ VAULT_V2_STATS_QUERY = `
411
+ query VaultV2Stats($address: String!, $chainId: Int!) {
412
+ vaultV2ByAddress(address: $address, chainId: $chainId) {
413
+ name
414
+ totalAssetsUsd
415
+ liquidityUsd
416
+ }
417
+ }
393
418
  `;
394
419
  }
395
420
  });
@@ -723,6 +748,12 @@ var isValidChainId = (chainId) => {
723
748
  }
724
749
  return chainId;
725
750
  };
751
+ function isSameAsset(tokenSymbol, asset) {
752
+ const token = tokenSymbol.toLowerCase();
753
+ const target = asset.toLowerCase();
754
+ if (token === target) return true;
755
+ return target === "weth" && token === "eth" || target === "eth" && token === "weth";
756
+ }
726
757
  function hexToDecimal(hex, decimals = 6) {
727
758
  const normalized = hex.startsWith("0x") || hex.startsWith("0X") ? hex : `0x${hex}`;
728
759
  const parsed = BigInt(normalized);
@@ -748,6 +779,10 @@ var DECIMALS_BY_SYMBOL = {
748
779
  wbtc: 8,
749
780
  cbbtc: 8
750
781
  };
782
+ function canonicalSymbol(symbol) {
783
+ const upper = symbol.toUpperCase();
784
+ return upper === "ETH" ? "WETH" : upper;
785
+ }
751
786
  function tokenDecimals(symbol, explicit) {
752
787
  if (typeof explicit === "number" && Number.isFinite(explicit))
753
788
  return explicit;
@@ -790,7 +825,7 @@ function mapBalances(raw, _chainId, smartWallet) {
790
825
  const detailByKey = /* @__PURE__ */ new Map();
791
826
  for (const p of rawPositions) {
792
827
  const cid = resolveChainId(p.chain ?? "");
793
- const symbol = (p.token_symbol ?? "").toUpperCase();
828
+ const symbol = canonicalSymbol(p.token_symbol ?? "");
794
829
  if (Number.isFinite(cid) && symbol) detailByKey.set(`${cid}:${symbol}`, p);
795
830
  }
796
831
  let totalBalance = 0;
@@ -810,13 +845,17 @@ function mapBalances(raw, _chainId, smartWallet) {
810
845
  asset: symbol,
811
846
  amount: String(amount)
812
847
  });
813
- const detail = detailByKey.get(`${positionChainId}:${symbol.toUpperCase()}`);
848
+ const detail = detailByKey.get(
849
+ `${positionChainId}:${canonicalSymbol(symbol)}`
850
+ );
814
851
  positions.push({
815
852
  chain: chainName,
816
853
  protocol: detail?.protocol_name ?? detail?.protocol_id ?? "",
817
854
  protocolId: detail?.protocol_id,
818
855
  pool: detail?.pool,
819
- asset: symbol,
856
+ // Report the token the way the rest of owney spells it ("WETH", as the
857
+ // pre-portfolioByChain mapper did), not Zyfai's internal "eth".
858
+ asset: canonicalSymbol(symbol),
820
859
  amount: String(amount),
821
860
  apy: detail?.pool_apy,
822
861
  tvl: detail?.pool_tvl,
@@ -1931,6 +1970,37 @@ var ZyfaiAgent = class {
1931
1970
  );
1932
1971
  }
1933
1972
  }
1973
+ /**
1974
+ * Records the deposit with Zyfai, retrying transient failures.
1975
+ *
1976
+ * This runs AFTER the transfer has already landed on-chain, so it must never
1977
+ * fail the deposit — the funds moved. But it is also the ONLY source of the
1978
+ * "Top up wallet" entry the history is built from: Zyfai auto-deploys the
1979
+ * balance it detects either way, so when this call is lost the user's deposit
1980
+ * never appears in Activity (an earlier withdrawal stays the newest row) and
1981
+ * nothing ever backfills it. Retry, then log loudly enough to be recoverable.
1982
+ */
1983
+ async logDepositWithRetry(chainId, txHash, amount, tokenAddress) {
1984
+ const ATTEMPTS = 3;
1985
+ const RETRY_DELAY_MS = 1e3;
1986
+ for (let attempt = 1; attempt <= ATTEMPTS; attempt++) {
1987
+ try {
1988
+ await (tokenAddress ? this.sdk.logDeposit(chainId, txHash, amount, tokenAddress) : this.sdk.logDeposit(chainId, txHash, amount));
1989
+ return;
1990
+ } catch (logError) {
1991
+ if (attempt === ATTEMPTS) {
1992
+ console.error(
1993
+ "[owney-sdk] Deposit landed on-chain but logDeposit failed \u2014 it will be missing from Zyfai history:",
1994
+ { txHash, chainId, amount, tokenAddress, error: logError }
1995
+ );
1996
+ return;
1997
+ }
1998
+ await new Promise(
1999
+ (resolve) => setTimeout(resolve, RETRY_DELAY_MS * attempt)
2000
+ );
2001
+ }
2002
+ }
2003
+ }
1934
2004
  async deposit(state, chainId, amount, asset, depositCallback) {
1935
2005
  try {
1936
2006
  await this.connectFull(state, chainId);
@@ -1946,14 +2016,12 @@ var ZyfaiAgent = class {
1946
2016
  amount
1947
2017
  );
1948
2018
  const tokenAddress = asset === "WETH" ? WETH_ADDRESS_BY_CHAIN[validChainId] : void 0;
1949
- try {
1950
- await (tokenAddress ? this.sdk.logDeposit(validChainId, txHash, amount, tokenAddress) : this.sdk.logDeposit(validChainId, txHash, amount));
1951
- } catch (logError) {
1952
- console.warn(
1953
- "[owney-sdk] Deposit landed on-chain but logDeposit failed (non-fatal):",
1954
- logError
1955
- );
1956
- }
2019
+ await this.logDepositWithRetry(
2020
+ validChainId,
2021
+ txHash,
2022
+ amount,
2023
+ tokenAddress
2024
+ );
1957
2025
  return { txHash, smartWallet: wallet.address, amount };
1958
2026
  }
1959
2027
  const raw = await this.sdk.depositFunds(
@@ -2197,11 +2265,10 @@ async function withFailureReporting(apiKey, agentType, fn) {
2197
2265
  // src/lib/helpers/withdraw-helper.ts
2198
2266
  var import_viem2 = require("viem");
2199
2267
  function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
2200
- const target = asset.toUpperCase();
2201
2268
  return agents.map((agent) => {
2202
2269
  const agentBalance = aggregated[agent.id];
2203
2270
  const tokenBalance = agentBalance?.tokens.find(
2204
- (t) => t.chainId === chainId && t.asset.toUpperCase() === target
2271
+ (t) => t.chainId === chainId && isSameAsset(t.asset, asset)
2205
2272
  );
2206
2273
  if (!tokenBalance) return { agent, balance: 0n };
2207
2274
  return { agent, balance: (0, import_viem2.parseUnits)(tokenBalance.amount, decimals) };
@@ -3235,9 +3302,8 @@ var OwneySDK = class {
3235
3302
  async hasExistingBalance(agent, state, chainId, asset) {
3236
3303
  try {
3237
3304
  const balance = await agent.getBalances(state, chainId);
3238
- const target = asset.toLowerCase();
3239
3305
  const token = balance.tokens.find(
3240
- (t) => t.chainId === chainId && t.asset.toLowerCase() === target
3306
+ (t) => t.chainId === chainId && isSameAsset(t.asset, asset)
3241
3307
  );
3242
3308
  return !!token && Number(token.amount) > 0;
3243
3309
  } catch {
package/dist/index.js CHANGED
@@ -81,6 +81,12 @@ var isValidChainId = (chainId) => {
81
81
  }
82
82
  return chainId;
83
83
  };
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
+ }
84
90
  function hexToDecimal(hex, decimals = 6) {
85
91
  const normalized = hex.startsWith("0x") || hex.startsWith("0X") ? hex : `0x${hex}`;
86
92
  const parsed = BigInt(normalized);
@@ -106,6 +112,10 @@ var DECIMALS_BY_SYMBOL = {
106
112
  wbtc: 8,
107
113
  cbbtc: 8
108
114
  };
115
+ function canonicalSymbol(symbol) {
116
+ const upper = symbol.toUpperCase();
117
+ return upper === "ETH" ? "WETH" : upper;
118
+ }
109
119
  function tokenDecimals(symbol, explicit) {
110
120
  if (typeof explicit === "number" && Number.isFinite(explicit))
111
121
  return explicit;
@@ -148,7 +158,7 @@ function mapBalances(raw, _chainId, smartWallet) {
148
158
  const detailByKey = /* @__PURE__ */ new Map();
149
159
  for (const p of rawPositions) {
150
160
  const cid = resolveChainId(p.chain ?? "");
151
- const symbol = (p.token_symbol ?? "").toUpperCase();
161
+ const symbol = canonicalSymbol(p.token_symbol ?? "");
152
162
  if (Number.isFinite(cid) && symbol) detailByKey.set(`${cid}:${symbol}`, p);
153
163
  }
154
164
  let totalBalance = 0;
@@ -168,13 +178,17 @@ function mapBalances(raw, _chainId, smartWallet) {
168
178
  asset: symbol,
169
179
  amount: String(amount)
170
180
  });
171
- const detail = detailByKey.get(`${positionChainId}:${symbol.toUpperCase()}`);
181
+ const detail = detailByKey.get(
182
+ `${positionChainId}:${canonicalSymbol(symbol)}`
183
+ );
172
184
  positions.push({
173
185
  chain: chainName,
174
186
  protocol: detail?.protocol_name ?? detail?.protocol_id ?? "",
175
187
  protocolId: detail?.protocol_id,
176
188
  pool: detail?.pool,
177
- asset: symbol,
189
+ // Report the token the way the rest of owney spells it ("WETH", as the
190
+ // pre-portfolioByChain mapper did), not Zyfai's internal "eth".
191
+ asset: canonicalSymbol(symbol),
178
192
  amount: String(amount),
179
193
  apy: detail?.pool_apy,
180
194
  tvl: detail?.pool_tvl,
@@ -1286,6 +1300,37 @@ var ZyfaiAgent = class {
1286
1300
  );
1287
1301
  }
1288
1302
  }
1303
+ /**
1304
+ * Records the deposit with Zyfai, retrying transient failures.
1305
+ *
1306
+ * This runs AFTER the transfer has already landed on-chain, so it must never
1307
+ * fail the deposit — the funds moved. But it is also the ONLY source of the
1308
+ * "Top up wallet" entry the history is built from: Zyfai auto-deploys the
1309
+ * balance it detects either way, so when this call is lost the user's deposit
1310
+ * never appears in Activity (an earlier withdrawal stays the newest row) and
1311
+ * nothing ever backfills it. Retry, then log loudly enough to be recoverable.
1312
+ */
1313
+ async logDepositWithRetry(chainId, txHash, amount, tokenAddress) {
1314
+ const ATTEMPTS = 3;
1315
+ const RETRY_DELAY_MS = 1e3;
1316
+ for (let attempt = 1; attempt <= ATTEMPTS; attempt++) {
1317
+ try {
1318
+ await (tokenAddress ? this.sdk.logDeposit(chainId, txHash, amount, tokenAddress) : this.sdk.logDeposit(chainId, txHash, amount));
1319
+ return;
1320
+ } catch (logError) {
1321
+ if (attempt === ATTEMPTS) {
1322
+ console.error(
1323
+ "[owney-sdk] Deposit landed on-chain but logDeposit failed \u2014 it will be missing from Zyfai history:",
1324
+ { txHash, chainId, amount, tokenAddress, error: logError }
1325
+ );
1326
+ return;
1327
+ }
1328
+ await new Promise(
1329
+ (resolve) => setTimeout(resolve, RETRY_DELAY_MS * attempt)
1330
+ );
1331
+ }
1332
+ }
1333
+ }
1289
1334
  async deposit(state, chainId, amount, asset, depositCallback) {
1290
1335
  try {
1291
1336
  await this.connectFull(state, chainId);
@@ -1301,14 +1346,12 @@ var ZyfaiAgent = class {
1301
1346
  amount
1302
1347
  );
1303
1348
  const tokenAddress = asset === "WETH" ? WETH_ADDRESS_BY_CHAIN[validChainId] : void 0;
1304
- try {
1305
- await (tokenAddress ? this.sdk.logDeposit(validChainId, txHash, amount, tokenAddress) : this.sdk.logDeposit(validChainId, txHash, amount));
1306
- } catch (logError) {
1307
- console.warn(
1308
- "[owney-sdk] Deposit landed on-chain but logDeposit failed (non-fatal):",
1309
- logError
1310
- );
1311
- }
1349
+ await this.logDepositWithRetry(
1350
+ validChainId,
1351
+ txHash,
1352
+ amount,
1353
+ tokenAddress
1354
+ );
1312
1355
  return { txHash, smartWallet: wallet.address, amount };
1313
1356
  }
1314
1357
  const raw = await this.sdk.depositFunds(
@@ -1547,11 +1590,10 @@ async function withFailureReporting(apiKey, agentType, fn) {
1547
1590
  // src/lib/helpers/withdraw-helper.ts
1548
1591
  import { parseUnits } from "viem";
1549
1592
  function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
1550
- const target = asset.toUpperCase();
1551
1593
  return agents.map((agent) => {
1552
1594
  const agentBalance = aggregated[agent.id];
1553
1595
  const tokenBalance = agentBalance?.tokens.find(
1554
- (t) => t.chainId === chainId && t.asset.toUpperCase() === target
1596
+ (t) => t.chainId === chainId && isSameAsset(t.asset, asset)
1555
1597
  );
1556
1598
  if (!tokenBalance) return { agent, balance: 0n };
1557
1599
  return { agent, balance: parseUnits(tokenBalance.amount, decimals) };
@@ -2278,7 +2320,7 @@ var OwneySDK = class {
2278
2320
  }
2279
2321
  if (agentId === "surfliquid") {
2280
2322
  if (!projectName) return null;
2281
- const { SurfLiquidAgent } = await import("./surfliquid.agent-JOJJ3C5Y.js");
2323
+ const { SurfLiquidAgent } = await import("./surfliquid.agent-VNGQUSXN.js");
2282
2324
  return new SurfLiquidAgent({
2283
2325
  projectName,
2284
2326
  appId: key2,
@@ -2581,9 +2623,8 @@ var OwneySDK = class {
2581
2623
  async hasExistingBalance(agent, state, chainId, asset) {
2582
2624
  try {
2583
2625
  const balance = await agent.getBalances(state, chainId);
2584
- const target = asset.toLowerCase();
2585
2626
  const token = balance.tokens.find(
2586
- (t) => t.chainId === chainId && t.asset.toLowerCase() === target
2627
+ (t) => t.chainId === chainId && isSameAsset(t.asset, asset)
2587
2628
  );
2588
2629
  return !!token && Number(token.amount) > 0;
2589
2630
  } catch {
@@ -174,27 +174,29 @@ var VAULT_STATS_QUERY = `
174
174
  }
175
175
  }
176
176
  `;
177
- async function fetchMorphoVaultStats(vaultAddress, chainId) {
177
+ var VAULT_V2_STATS_QUERY = `
178
+ query VaultV2Stats($address: String!, $chainId: Int!) {
179
+ vaultV2ByAddress(address: $address, chainId: $chainId) {
180
+ name
181
+ totalAssetsUsd
182
+ liquidityUsd
183
+ }
184
+ }
185
+ `;
186
+ async function queryMorpho(query, vaultAddress, chainId) {
178
187
  try {
179
188
  const res = await fetch(MORPHO_API_URL, {
180
189
  method: "POST",
181
190
  headers: { "Content-Type": "application/json" },
182
191
  body: JSON.stringify({
183
- query: VAULT_STATS_QUERY,
192
+ query,
184
193
  variables: { address: vaultAddress, chainId }
185
194
  })
186
195
  });
187
196
  if (!res.ok) return null;
188
197
  const json = await res.json();
189
198
  if (json.errors) return null;
190
- const vault = json.data?.vaultByAddress;
191
- const tvlUsd = vault?.state?.totalAssetsUsd;
192
- const liquidityUsd = vault?.liquidity?.usd;
193
- if (typeof tvlUsd !== "number" || typeof liquidityUsd !== "number") {
194
- return null;
195
- }
196
- const name = typeof vault?.name === "string" ? vault.name : null;
197
- return { name, tvlUsd, liquidityUsd };
199
+ return json.data ?? null;
198
200
  } catch (error) {
199
201
  console.warn("surfliquid: Morpho vault stats fetch failed", {
200
202
  vaultAddress,
@@ -204,6 +206,29 @@ async function fetchMorphoVaultStats(vaultAddress, chainId) {
204
206
  return null;
205
207
  }
206
208
  }
209
+ function toStats(name, tvlUsd, liquidityUsd) {
210
+ if (typeof tvlUsd !== "number" || typeof liquidityUsd !== "number") {
211
+ return null;
212
+ }
213
+ return {
214
+ name: typeof name === "string" ? name : null,
215
+ tvlUsd,
216
+ liquidityUsd
217
+ };
218
+ }
219
+ async function fetchMorphoVaultStats(vaultAddress, chainId) {
220
+ const v1 = await queryMorpho(VAULT_STATS_QUERY, vaultAddress, chainId);
221
+ const vault = v1?.vaultByAddress;
222
+ const v1Stats = toStats(
223
+ vault?.name,
224
+ vault?.state?.totalAssetsUsd,
225
+ vault?.liquidity?.usd
226
+ );
227
+ if (v1Stats) return v1Stats;
228
+ const v2 = await queryMorpho(VAULT_V2_STATS_QUERY, vaultAddress, chainId);
229
+ const vaultV2 = v2?.vaultV2ByAddress;
230
+ return toStats(vaultV2?.name, vaultV2?.totalAssetsUsd, vaultV2?.liquidityUsd);
231
+ }
207
232
  async function fetchMorphoStatsByVault(vaultAddresses, chainId) {
208
233
  const unique = [...new Set(vaultAddresses.map((a) => a.toLowerCase()))];
209
234
  const entries = await Promise.all(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owney/sdk",
3
- "version": "0.6.9-beta.7",
3
+ "version": "0.6.9-beta.9",
4
4
  "type": "module",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",