@owney/sdk 0.6.0-beta.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -15
- package/dist/index.cjs +151 -136
- package/dist/index.d.cts +12 -13
- package/dist/index.d.ts +12 -13
- package/dist/index.js +142 -127
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -407,17 +407,6 @@ const usdcBaseApy = await sdk.getAgentApy({
|
|
|
407
407
|
console.log(usdcBaseApy.agentApy.zyfai.averageApy); // APY scoped to USDC on Base
|
|
408
408
|
```
|
|
409
409
|
|
|
410
|
-
### `getAgentAllocation()`
|
|
411
|
-
|
|
412
|
-
Get the current fund allocation percentages across agents.
|
|
413
|
-
|
|
414
|
-
Returns: `OwneyAgentAllocation`
|
|
415
|
-
|
|
416
|
-
```typescript
|
|
417
|
-
const allocation = await sdk.getAgentAllocation();
|
|
418
|
-
console.log(allocation.agentAllocation); // { zyfai: 100 }
|
|
419
|
-
```
|
|
420
|
-
|
|
421
410
|
## Types
|
|
422
411
|
|
|
423
412
|
### Configuration
|
|
@@ -630,10 +619,6 @@ interface AgentApyDetails {
|
|
|
630
619
|
interface OwneyAgentApy {
|
|
631
620
|
agentApy: Record<AgentId, AgentApy>;
|
|
632
621
|
}
|
|
633
|
-
|
|
634
|
-
interface OwneyAgentAllocation {
|
|
635
|
-
agentAllocation: Record<AgentId, number>;
|
|
636
|
-
}
|
|
637
622
|
```
|
|
638
623
|
|
|
639
624
|
### Callback Types
|
package/dist/index.cjs
CHANGED
|
@@ -32,13 +32,15 @@ module.exports = __toCommonJS(src_exports);
|
|
|
32
32
|
|
|
33
33
|
// src/agents/zyfai/zyfai.agent.ts
|
|
34
34
|
var import_sdk = require("@zyfai/sdk");
|
|
35
|
+
var import_viem = require("viem");
|
|
36
|
+
var import_chains = require("viem/chains");
|
|
35
37
|
|
|
36
38
|
// src/types/config.ts
|
|
37
39
|
var P_SUPPORTED_CHAINS = {
|
|
38
40
|
chainIds: [8453, 42161],
|
|
39
41
|
chains: ["BASE", "ARBITRUM"]
|
|
40
42
|
};
|
|
41
|
-
var SUPPORTED_TOKENS = ["USDC", "USDT"
|
|
43
|
+
var SUPPORTED_TOKENS = ["USDC", "USDT"];
|
|
42
44
|
var SUPPORTED_CHAIN_IDS = P_SUPPORTED_CHAINS.chainIds;
|
|
43
45
|
var SUPPORTED_CHAINS = P_SUPPORTED_CHAINS.chains;
|
|
44
46
|
var SupportedAssets = [
|
|
@@ -59,18 +61,6 @@ var SupportedAssets = [
|
|
|
59
61
|
symbol: "USDT",
|
|
60
62
|
chainId: 42161,
|
|
61
63
|
decimals: 6
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
address: `0x4200000000000000000000000000000000000006`,
|
|
65
|
-
symbol: "WETH",
|
|
66
|
-
chainId: 8453,
|
|
67
|
-
decimals: 18
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
address: `0x82aF49447D8a07e3bd95BD0d56f35241523fBab1`,
|
|
71
|
-
symbol: "WETH",
|
|
72
|
-
chainId: 42161,
|
|
73
|
-
decimals: 18
|
|
74
64
|
}
|
|
75
65
|
];
|
|
76
66
|
|
|
@@ -280,6 +270,14 @@ function mapApyHistory(raw) {
|
|
|
280
270
|
apyByChainAndAsset: mapWeightedApyByChain(raw.weightedApyAfterFeeByChain)
|
|
281
271
|
};
|
|
282
272
|
}
|
|
273
|
+
function splitOpportunity(opportunity) {
|
|
274
|
+
const match = opportunity.match(/^(.*?)\s*\(([^)]*)\)\s*$/);
|
|
275
|
+
if (match) {
|
|
276
|
+
const pool = match[2].trim();
|
|
277
|
+
return { protocol: match[1].trim(), pool: pool || void 0 };
|
|
278
|
+
}
|
|
279
|
+
return { protocol: opportunity.trim() };
|
|
280
|
+
}
|
|
283
281
|
function mapEntries(rawEntries, chainId) {
|
|
284
282
|
const actionMap = {
|
|
285
283
|
"Top up wallet": "Top up",
|
|
@@ -299,21 +297,26 @@ function mapEntries(rawEntries, chainId) {
|
|
|
299
297
|
);
|
|
300
298
|
oldApy = Number(rawLog.oldApy);
|
|
301
299
|
newApy = Number(rawLog.newApy);
|
|
300
|
+
const from = splitOpportunity(rawLog.oldOpportunity);
|
|
301
|
+
const to = splitOpportunity(rawLog.newOpportunity);
|
|
302
302
|
rebalanceLog = [
|
|
303
303
|
{
|
|
304
|
-
fromProtocol:
|
|
305
|
-
toProtocol:
|
|
304
|
+
fromProtocol: from.protocol,
|
|
305
|
+
toProtocol: to.protocol,
|
|
306
|
+
fromPool: from.pool,
|
|
307
|
+
toPool: to.pool,
|
|
306
308
|
tokenSymbol: matched?.token_symbol ?? "",
|
|
307
309
|
amount: matched ? String(hexToDecimal(matched.amount || "0x")) : "",
|
|
308
310
|
status: "success"
|
|
309
311
|
}
|
|
310
312
|
];
|
|
311
313
|
}
|
|
314
|
+
const mappedAction = (entry.action ? actionMap[entry.action] : void 0) ?? entry.action;
|
|
312
315
|
const rawAmount = entry?.positions?.[0]?.amount;
|
|
313
|
-
const hasAmount = typeof rawAmount === "string" && rawAmount !== "" && rawAmount !== "0x" && rawAmount !== "0x0" && rawAmount !== "0";
|
|
316
|
+
const hasAmount = mappedAction !== "Withdraw" && typeof rawAmount === "string" && rawAmount !== "" && rawAmount !== "0x" && rawAmount !== "0x0" && rawAmount !== "0";
|
|
314
317
|
return {
|
|
315
318
|
agent: "zyfai",
|
|
316
|
-
action:
|
|
319
|
+
action: mappedAction,
|
|
317
320
|
date: entry.date || "",
|
|
318
321
|
newApy: newApy === null ? null : String(newApy),
|
|
319
322
|
oldApy: oldApy === null ? null : String(oldApy),
|
|
@@ -405,6 +408,33 @@ function computeAllocationApy(positions) {
|
|
|
405
408
|
return { totalApy, apyByChainAndAsset };
|
|
406
409
|
}
|
|
407
410
|
|
|
411
|
+
// src/agents/zyfai/zyfai.withdraw-amount.ts
|
|
412
|
+
var TRANSFER_TOPIC = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef";
|
|
413
|
+
function topicToAddress(topic) {
|
|
414
|
+
return `0x${(topic ?? "").slice(-40)}`.toLowerCase();
|
|
415
|
+
}
|
|
416
|
+
function extractWithdrawnAmount(logs, recipient, token, decimals) {
|
|
417
|
+
const wantRecipient = recipient.toLowerCase();
|
|
418
|
+
const wantToken = token.toLowerCase();
|
|
419
|
+
let total = 0n;
|
|
420
|
+
let matched = false;
|
|
421
|
+
for (const log of logs) {
|
|
422
|
+
if (log.address.toLowerCase() !== wantToken)
|
|
423
|
+
continue;
|
|
424
|
+
if ((log.topics[0] ?? "").toLowerCase() !== TRANSFER_TOPIC)
|
|
425
|
+
continue;
|
|
426
|
+
if (topicToAddress(log.topics[2]) !== wantRecipient)
|
|
427
|
+
continue;
|
|
428
|
+
if (!log.data || log.data === "0x")
|
|
429
|
+
continue;
|
|
430
|
+
total += BigInt(log.data);
|
|
431
|
+
matched = true;
|
|
432
|
+
}
|
|
433
|
+
if (!matched)
|
|
434
|
+
return void 0;
|
|
435
|
+
return String(hexToDecimal(`0x${total.toString(16)}`, decimals));
|
|
436
|
+
}
|
|
437
|
+
|
|
408
438
|
// src/agents/zyfai/zyfai.history-cursor.ts
|
|
409
439
|
var InvalidHistoryCursorError = class extends Error {
|
|
410
440
|
code = "invalid_cursor";
|
|
@@ -503,10 +533,7 @@ var DEFAULT_ZYFAI_RPC_URLS = {
|
|
|
503
533
|
8453: "https://base-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V",
|
|
504
534
|
42161: "https://arb-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V"
|
|
505
535
|
};
|
|
506
|
-
var
|
|
507
|
-
8453: "0x4200000000000000000000000000000000000006",
|
|
508
|
-
42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"
|
|
509
|
-
};
|
|
536
|
+
var VIEM_CHAIN = { 8453: import_chains.base, 42161: import_chains.arbitrum };
|
|
510
537
|
var ZyfaiAgent = class {
|
|
511
538
|
id = "zyfai";
|
|
512
539
|
supportedChainIds = [8453, 42161];
|
|
@@ -514,18 +541,12 @@ var ZyfaiAgent = class {
|
|
|
514
541
|
{
|
|
515
542
|
chainId: 8453,
|
|
516
543
|
chain: "BASE",
|
|
517
|
-
assets: [
|
|
518
|
-
{ symbol: "USDC", minDepositAmount: "1500000" },
|
|
519
|
-
{ symbol: "WETH", minDepositAmount: "500000000000000" }
|
|
520
|
-
]
|
|
544
|
+
assets: [{ symbol: "USDC", minDepositAmount: "1500000" }]
|
|
521
545
|
},
|
|
522
546
|
{
|
|
523
547
|
chainId: 42161,
|
|
524
548
|
chain: "ARBITRUM",
|
|
525
|
-
assets: [
|
|
526
|
-
{ symbol: "USDC", minDepositAmount: "1500000" },
|
|
527
|
-
{ symbol: "WETH", minDepositAmount: "500000000000000" }
|
|
528
|
-
]
|
|
549
|
+
assets: [{ symbol: "USDC", minDepositAmount: "1500000" }]
|
|
529
550
|
}
|
|
530
551
|
];
|
|
531
552
|
sdk;
|
|
@@ -533,13 +554,83 @@ var ZyfaiAgent = class {
|
|
|
533
554
|
connectedChainId = null;
|
|
534
555
|
smartWalletCache = /* @__PURE__ */ new Map();
|
|
535
556
|
connectAuthPromise = null;
|
|
557
|
+
rpcUrls;
|
|
558
|
+
publicClients = /* @__PURE__ */ new Map();
|
|
559
|
+
// txHash -> resolved withdrawn amount. Receipts are immutable, so a
|
|
560
|
+
// successful decode is cached forever; failures are NOT cached so a transient
|
|
561
|
+
// RPC error retries on the next fetch.
|
|
562
|
+
withdrawAmountCache = /* @__PURE__ */ new Map();
|
|
536
563
|
constructor(apiKey, rpcUrls) {
|
|
564
|
+
this.rpcUrls = rpcUrls ?? DEFAULT_ZYFAI_RPC_URLS;
|
|
537
565
|
this.sdk = new import_sdk.ZyfaiSDK({
|
|
538
566
|
apiKey,
|
|
539
|
-
rpcUrls: rpcUrls
|
|
567
|
+
rpcUrls: this.rpcUrls
|
|
540
568
|
});
|
|
541
569
|
this.installAuthCache();
|
|
542
570
|
}
|
|
571
|
+
getPublicClient(chainId) {
|
|
572
|
+
const cached = this.publicClients.get(chainId);
|
|
573
|
+
if (cached)
|
|
574
|
+
return cached;
|
|
575
|
+
const client = (0, import_viem.createPublicClient)({
|
|
576
|
+
chain: VIEM_CHAIN[chainId],
|
|
577
|
+
transport: (0, import_viem.http)(this.rpcUrls[chainId])
|
|
578
|
+
});
|
|
579
|
+
this.publicClients.set(chainId, client);
|
|
580
|
+
return client;
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* Fills in the true withdrawn amount for `Withdraw` entries by decoding the
|
|
584
|
+
* USDC `Transfer` that lands in the user's wallet on-chain. The Zyfai history
|
|
585
|
+
* payload only reports the *remaining* position for a partial withdraw (see
|
|
586
|
+
* the note in `mapEntries`), so without this the UI shows the leftover
|
|
587
|
+
* balance instead of the amount withdrawn.
|
|
588
|
+
*
|
|
589
|
+
* Mutates `entries` in place. Runs all lookups concurrently and is tolerant
|
|
590
|
+
* of RPC failures: an entry whose amount can't be resolved keeps
|
|
591
|
+
* `amount: undefined`, which consumers render as a hidden/retryable row
|
|
592
|
+
* rather than a wrong number.
|
|
593
|
+
*/
|
|
594
|
+
async resolveWithdrawnAmounts(entries, chainId, recipient) {
|
|
595
|
+
const asset = SupportedAssets.find(
|
|
596
|
+
(a) => a.chainId === chainId && a.symbol === "USDC"
|
|
597
|
+
);
|
|
598
|
+
if (!asset)
|
|
599
|
+
return;
|
|
600
|
+
const withdrawals = entries.filter(
|
|
601
|
+
(e) => e.action === "Withdraw" && e.transactions[0]?.txHashes[0]
|
|
602
|
+
);
|
|
603
|
+
if (withdrawals.length === 0)
|
|
604
|
+
return;
|
|
605
|
+
const client = this.getPublicClient(chainId);
|
|
606
|
+
await Promise.all(
|
|
607
|
+
withdrawals.map(async (entry) => {
|
|
608
|
+
const tx = entry.transactions[0];
|
|
609
|
+
const txHash = tx.txHashes[0];
|
|
610
|
+
const cached = this.withdrawAmountCache.get(txHash);
|
|
611
|
+
if (cached !== void 0) {
|
|
612
|
+
tx.amount = cached;
|
|
613
|
+
return;
|
|
614
|
+
}
|
|
615
|
+
try {
|
|
616
|
+
const receipt = await client.getTransactionReceipt({
|
|
617
|
+
hash: txHash
|
|
618
|
+
});
|
|
619
|
+
const amount = extractWithdrawnAmount(
|
|
620
|
+
receipt.logs,
|
|
621
|
+
recipient,
|
|
622
|
+
asset.address,
|
|
623
|
+
asset.decimals
|
|
624
|
+
);
|
|
625
|
+
if (amount !== void 0) {
|
|
626
|
+
this.withdrawAmountCache.set(txHash, amount);
|
|
627
|
+
tx.amount = amount;
|
|
628
|
+
}
|
|
629
|
+
} catch {
|
|
630
|
+
}
|
|
631
|
+
})
|
|
632
|
+
);
|
|
633
|
+
}
|
|
543
634
|
/**
|
|
544
635
|
* Patches `sdk.authenticateUser` so a fresh page can reuse the JWT from a
|
|
545
636
|
* prior session instead of triggering a new SIWE prompt. Runs inside
|
|
@@ -691,7 +782,7 @@ var ZyfaiAgent = class {
|
|
|
691
782
|
throw error;
|
|
692
783
|
}
|
|
693
784
|
}
|
|
694
|
-
async deposit(state, chainId, amount,
|
|
785
|
+
async deposit(state, chainId, amount, depositCallback) {
|
|
695
786
|
try {
|
|
696
787
|
await this.connectFull(state, chainId);
|
|
697
788
|
const validChainId = isValidChainId(chainId);
|
|
@@ -705,15 +796,13 @@ var ZyfaiAgent = class {
|
|
|
705
796
|
validChainId,
|
|
706
797
|
amount
|
|
707
798
|
);
|
|
708
|
-
|
|
709
|
-
await (tokenAddress ? this.sdk.logDeposit(validChainId, txHash, amount, tokenAddress) : this.sdk.logDeposit(validChainId, txHash, amount));
|
|
799
|
+
await this.sdk.logDeposit(validChainId, txHash, amount);
|
|
710
800
|
return { txHash, smartWallet: wallet.address, amount };
|
|
711
801
|
}
|
|
712
802
|
const raw = await this.sdk.depositFunds(
|
|
713
803
|
this.getAddress(),
|
|
714
804
|
validChainId,
|
|
715
|
-
amount
|
|
716
|
-
asset
|
|
805
|
+
amount
|
|
717
806
|
);
|
|
718
807
|
return mapDeposit(raw);
|
|
719
808
|
} catch (error) {
|
|
@@ -792,8 +881,10 @@ var ZyfaiAgent = class {
|
|
|
792
881
|
toDate,
|
|
793
882
|
rawOffset: firstOvershoot ? firstOvershoot.rawIdx : offset
|
|
794
883
|
}) : void 0;
|
|
884
|
+
const data = mapEntries(pageData, validChainId);
|
|
885
|
+
await this.resolveWithdrawnAmounts(data, validChainId, state.walletAddress);
|
|
795
886
|
return {
|
|
796
|
-
data
|
|
887
|
+
data,
|
|
797
888
|
hasMore,
|
|
798
889
|
nextCursor
|
|
799
890
|
};
|
|
@@ -884,7 +975,7 @@ async function withFailureReporting(apiKey, agentType, fn) {
|
|
|
884
975
|
}
|
|
885
976
|
|
|
886
977
|
// src/lib/helpers/withdraw-helper.ts
|
|
887
|
-
var
|
|
978
|
+
var import_viem2 = require("viem");
|
|
888
979
|
function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
|
|
889
980
|
const target = asset.toUpperCase();
|
|
890
981
|
return agents.map((agent) => {
|
|
@@ -894,7 +985,7 @@ function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decima
|
|
|
894
985
|
);
|
|
895
986
|
if (!tokenBalance)
|
|
896
987
|
return { agent, balance: 0n };
|
|
897
|
-
return { agent, balance: (0,
|
|
988
|
+
return { agent, balance: (0, import_viem2.parseUnits)(tokenBalance.amount, decimals) };
|
|
898
989
|
});
|
|
899
990
|
}
|
|
900
991
|
function planProportionalShares(balances, requested, totalAvailable) {
|
|
@@ -1010,11 +1101,11 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
|
|
|
1010
1101
|
}
|
|
1011
1102
|
|
|
1012
1103
|
// src/client.ts
|
|
1013
|
-
var
|
|
1014
|
-
var
|
|
1104
|
+
var import_viem4 = require("viem");
|
|
1105
|
+
var import_chains2 = require("viem/chains");
|
|
1015
1106
|
|
|
1016
1107
|
// src/lib/transfer-auth.ts
|
|
1017
|
-
var
|
|
1108
|
+
var import_viem3 = require("viem");
|
|
1018
1109
|
var ERC20_META_ABI = [
|
|
1019
1110
|
{ type: "function", name: "name", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] },
|
|
1020
1111
|
{ type: "function", name: "version", stateMutability: "view", inputs: [], outputs: [{ name: "", type: "string" }] }
|
|
@@ -1046,16 +1137,16 @@ async function readTokenMeta(publicClient, token) {
|
|
|
1046
1137
|
function randomAuthNonce() {
|
|
1047
1138
|
const bytes = new Uint8Array(32);
|
|
1048
1139
|
globalThis.crypto.getRandomValues(bytes);
|
|
1049
|
-
return (0,
|
|
1140
|
+
return (0, import_viem3.bytesToHex)(bytes);
|
|
1050
1141
|
}
|
|
1051
1142
|
|
|
1052
1143
|
// src/lib/sponsor-client.ts
|
|
1053
1144
|
var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
1054
1145
|
async function postSponsorTransferAuth(input) {
|
|
1055
|
-
const
|
|
1146
|
+
const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
1056
1147
|
let res;
|
|
1057
1148
|
try {
|
|
1058
|
-
res = await fetch(`${
|
|
1149
|
+
res = await fetch(`${base3}/api/v1/sponsor/erc20-transfer-auth`, {
|
|
1059
1150
|
method: "POST",
|
|
1060
1151
|
headers: { "content-type": "application/json", "x-owney-api-key": input.apiKey },
|
|
1061
1152
|
body: JSON.stringify(input.body)
|
|
@@ -1158,9 +1249,9 @@ var SPONSORED_USDC_BY_CHAIN = {
|
|
|
1158
1249
|
8453: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
|
|
1159
1250
|
42161: "0xaf88d065e77c8cc2239327c5edb3a432268e5831"
|
|
1160
1251
|
};
|
|
1161
|
-
var
|
|
1162
|
-
8453:
|
|
1163
|
-
42161:
|
|
1252
|
+
var VIEM_CHAIN2 = {
|
|
1253
|
+
8453: import_chains2.base,
|
|
1254
|
+
42161: import_chains2.arbitrum
|
|
1164
1255
|
};
|
|
1165
1256
|
var OwneySDK = class {
|
|
1166
1257
|
agents = /* @__PURE__ */ new Map();
|
|
@@ -1273,14 +1364,14 @@ var OwneySDK = class {
|
|
|
1273
1364
|
// Casts work around viem's chain-narrowed Client vs the generic
|
|
1274
1365
|
// PublicClient/WalletClient param types — structurally identical at
|
|
1275
1366
|
// runtime, but the two share a name TS treats as unrelated.
|
|
1276
|
-
getPublicClient: (cid) => (0,
|
|
1277
|
-
chain:
|
|
1278
|
-
transport: (0,
|
|
1367
|
+
getPublicClient: (cid) => (0, import_viem4.createPublicClient)({
|
|
1368
|
+
chain: VIEM_CHAIN2[cid],
|
|
1369
|
+
transport: (0, import_viem4.custom)(provider)
|
|
1279
1370
|
}),
|
|
1280
|
-
getWalletClient: (cid) => (0,
|
|
1371
|
+
getWalletClient: (cid) => (0, import_viem4.createWalletClient)({
|
|
1281
1372
|
account: owner,
|
|
1282
|
-
chain:
|
|
1283
|
-
transport: (0,
|
|
1373
|
+
chain: VIEM_CHAIN2[cid],
|
|
1374
|
+
transport: (0, import_viem4.custom)(provider)
|
|
1284
1375
|
})
|
|
1285
1376
|
});
|
|
1286
1377
|
return this.cachedSponsoredCallback;
|
|
@@ -1438,7 +1529,7 @@ var OwneySDK = class {
|
|
|
1438
1529
|
}
|
|
1439
1530
|
const state = this.requireState();
|
|
1440
1531
|
const chainId = this.requireChainId();
|
|
1441
|
-
const effectiveCallback = depositCallback ??
|
|
1532
|
+
const effectiveCallback = depositCallback ?? this.getDefaultSponsoredCallback();
|
|
1442
1533
|
if (agentId) {
|
|
1443
1534
|
if (this.isAgentDisabled(agentId)) {
|
|
1444
1535
|
throw new OwneyError(
|
|
@@ -1453,13 +1544,7 @@ var OwneySDK = class {
|
|
|
1453
1544
|
return withFailureReporting(
|
|
1454
1545
|
this.apiKey,
|
|
1455
1546
|
agent.id,
|
|
1456
|
-
() => agent.deposit(
|
|
1457
|
-
state,
|
|
1458
|
-
chainId,
|
|
1459
|
-
amount,
|
|
1460
|
-
asset,
|
|
1461
|
-
effectiveCallback
|
|
1462
|
-
)
|
|
1547
|
+
() => agent.deposit(state, chainId, amount, effectiveCallback)
|
|
1463
1548
|
);
|
|
1464
1549
|
}
|
|
1465
1550
|
const totalAmount = BigInt(amount);
|
|
@@ -1493,13 +1578,7 @@ var OwneySDK = class {
|
|
|
1493
1578
|
agentResults[agent.id] = await withFailureReporting(
|
|
1494
1579
|
this.apiKey,
|
|
1495
1580
|
agent.id,
|
|
1496
|
-
() => agent.deposit(
|
|
1497
|
-
state,
|
|
1498
|
-
chainId,
|
|
1499
|
-
agentAmount,
|
|
1500
|
-
asset,
|
|
1501
|
-
effectiveCallback
|
|
1502
|
-
)
|
|
1581
|
+
() => agent.deposit(state, chainId, agentAmount, effectiveCallback)
|
|
1503
1582
|
);
|
|
1504
1583
|
}
|
|
1505
1584
|
return { agentResults };
|
|
@@ -2029,70 +2108,6 @@ var OwneySDK = class {
|
|
|
2029
2108
|
agentApy: results
|
|
2030
2109
|
};
|
|
2031
2110
|
}
|
|
2032
|
-
/**
|
|
2033
|
-
* Get the current fund allocation percentages across agents.
|
|
2034
|
-
* @returns Object with agent names as keys and allocation percentages as values
|
|
2035
|
-
*/
|
|
2036
|
-
async getAgentAllocation() {
|
|
2037
|
-
const state = this.requireState();
|
|
2038
|
-
const chainId = this.requireChainId();
|
|
2039
|
-
const activeAgents = this.getActiveAgents();
|
|
2040
|
-
const balances = {};
|
|
2041
|
-
const positionsByAgent = {};
|
|
2042
|
-
let totalBalance = 0;
|
|
2043
|
-
const entries = [...activeAgents.entries()];
|
|
2044
|
-
const balanceResults = await Promise.allSettled(
|
|
2045
|
-
entries.map(async ([id, agent]) => {
|
|
2046
|
-
const b = await agent.getBalances(state, chainId);
|
|
2047
|
-
return [id, Number(b.totalBalance), b.positions ?? []];
|
|
2048
|
-
})
|
|
2049
|
-
);
|
|
2050
|
-
let successCount = 0;
|
|
2051
|
-
const agentErrors = {};
|
|
2052
|
-
for (let i = 0; i < balanceResults.length; i++) {
|
|
2053
|
-
const settledResult = balanceResults[i];
|
|
2054
|
-
const [agentId] = entries[i];
|
|
2055
|
-
if (settledResult.status === "fulfilled") {
|
|
2056
|
-
const [id, bal, agentPositions] = settledResult.value;
|
|
2057
|
-
balances[id] = bal;
|
|
2058
|
-
positionsByAgent[id] = agentPositions;
|
|
2059
|
-
totalBalance += bal;
|
|
2060
|
-
successCount += 1;
|
|
2061
|
-
} else {
|
|
2062
|
-
const reason = settledResult.reason;
|
|
2063
|
-
agentErrors[agentId] = reason instanceof Error ? reason.message : String(reason);
|
|
2064
|
-
console.error(`getAgentAllocation agent "${agentId}" failed:`, reason);
|
|
2065
|
-
}
|
|
2066
|
-
}
|
|
2067
|
-
if (successCount === 0) {
|
|
2068
|
-
throw new OwneyError(
|
|
2069
|
-
"ALLOCATION_ALL_FAILED",
|
|
2070
|
-
"Failed to fetch allocation: all agents failed.",
|
|
2071
|
-
{ agentErrors }
|
|
2072
|
-
);
|
|
2073
|
-
}
|
|
2074
|
-
const allocation = {};
|
|
2075
|
-
if (totalBalance === 0) {
|
|
2076
|
-
for (const id of activeAgents.keys()) {
|
|
2077
|
-
allocation[id] = 0;
|
|
2078
|
-
}
|
|
2079
|
-
} else {
|
|
2080
|
-
for (const id of activeAgents.keys()) {
|
|
2081
|
-
allocation[id] = balances[id] > 0 ? Math.max(1, Math.floor(balances[id] / totalBalance * 100)) : 0;
|
|
2082
|
-
}
|
|
2083
|
-
const remainder = 100 - Object.values(allocation).reduce((a, b) => a + b, 0);
|
|
2084
|
-
if (remainder > 0) {
|
|
2085
|
-
const largestId = [...activeAgents.keys()].reduce(
|
|
2086
|
-
(a, b) => balances[a] >= balances[b] ? a : b
|
|
2087
|
-
);
|
|
2088
|
-
allocation[largestId] += remainder;
|
|
2089
|
-
}
|
|
2090
|
-
}
|
|
2091
|
-
return {
|
|
2092
|
-
agentAllocation: allocation,
|
|
2093
|
-
agentPositions: positionsByAgent
|
|
2094
|
-
};
|
|
2095
|
-
}
|
|
2096
2111
|
/**
|
|
2097
2112
|
* Allocation-weighted APY from the current portfolio: each pool's APY
|
|
2098
2113
|
* weighted by the user's position value in it. More accurate per-user than
|
|
@@ -2152,7 +2167,7 @@ var OwneySDK = class {
|
|
|
2152
2167
|
};
|
|
2153
2168
|
|
|
2154
2169
|
// src/agents/zyfai/zyfai.siwx.ts
|
|
2155
|
-
var
|
|
2170
|
+
var import_viem5 = require("viem");
|
|
2156
2171
|
var import_siwe = require("siwe");
|
|
2157
2172
|
var import_sdk2 = require("@zyfai/sdk");
|
|
2158
2173
|
|
|
@@ -2234,7 +2249,7 @@ function buildSIWXConfig(deps) {
|
|
|
2234
2249
|
issuedAt,
|
|
2235
2250
|
toString() {
|
|
2236
2251
|
return new import_siwe.SiweMessage({
|
|
2237
|
-
address: (0,
|
|
2252
|
+
address: (0, import_viem5.getAddress)(accountAddress),
|
|
2238
2253
|
chainId: numericChainId(chainId),
|
|
2239
2254
|
domain,
|
|
2240
2255
|
uri,
|
|
@@ -2310,9 +2325,9 @@ function buildSIWXConfig(deps) {
|
|
|
2310
2325
|
}
|
|
2311
2326
|
function createOwneySIWX(config) {
|
|
2312
2327
|
const zyfai = new import_sdk2.ZyfaiSDK({ apiKey: config.apiKey });
|
|
2313
|
-
const
|
|
2328
|
+
const http2 = zyfai.httpClient;
|
|
2314
2329
|
return buildSIWXConfig({
|
|
2315
|
-
post: (url, data) =>
|
|
2330
|
+
post: (url, data) => http2.post(url, data),
|
|
2316
2331
|
referralSource: config.referralSource
|
|
2317
2332
|
});
|
|
2318
2333
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -14,7 +14,7 @@ interface ConnectionState {
|
|
|
14
14
|
walletAddress: `0x${string}`;
|
|
15
15
|
chainId: number | null;
|
|
16
16
|
}
|
|
17
|
-
declare const SUPPORTED_TOKENS: readonly ["USDC", "USDT"
|
|
17
|
+
declare const SUPPORTED_TOKENS: readonly ["USDC", "USDT"];
|
|
18
18
|
declare const SUPPORTED_CHAIN_IDS: readonly [8453, 42161];
|
|
19
19
|
declare const SUPPORTED_CHAINS: readonly ["BASE", "ARBITRUM"];
|
|
20
20
|
type OwneySupportedChainId = (typeof SUPPORTED_CHAIN_IDS)[number];
|
|
@@ -114,6 +114,15 @@ interface HistoryTransaction {
|
|
|
114
114
|
interface RebalanceLog {
|
|
115
115
|
fromProtocol: string;
|
|
116
116
|
toProtocol: string;
|
|
117
|
+
/**
|
|
118
|
+
* Pool/vault sub-label for the source position (e.g. "USDC Core"), when the
|
|
119
|
+
* agent exposes one. Lets consumers disambiguate moves within the same
|
|
120
|
+
* protocol ("Morpho · USDC Core → Morpho · Spark USDC"). Absent when the
|
|
121
|
+
* agent only reports a bare protocol name.
|
|
122
|
+
*/
|
|
123
|
+
fromPool?: string;
|
|
124
|
+
/** Pool/vault sub-label for the destination position. See {@link fromPool}. */
|
|
125
|
+
toPool?: string;
|
|
117
126
|
tokenSymbol: string;
|
|
118
127
|
amount: string;
|
|
119
128
|
status: "success" | "failed";
|
|
@@ -162,11 +171,6 @@ interface AgentApy {
|
|
|
162
171
|
interface OwneyAgentApy {
|
|
163
172
|
agentApy: Record<AgentId, AgentApy>;
|
|
164
173
|
}
|
|
165
|
-
interface OwneyAgentAllocation {
|
|
166
|
-
agentAllocation: Record<AgentId, number>;
|
|
167
|
-
/** Per-agent positions. Empty array for agents that don't expose positions. */
|
|
168
|
-
agentPositions: Record<AgentId, OwneyPosition[]>;
|
|
169
|
-
}
|
|
170
174
|
|
|
171
175
|
type DepositCallback = (smartWalletAddress: string, chainId: number, amount: string) => Promise<`0x${string}`> | `0x${string}`;
|
|
172
176
|
interface IAgent {
|
|
@@ -175,7 +179,7 @@ interface IAgent {
|
|
|
175
179
|
readonly supportedAssets: readonly AgentSupportedAssets[];
|
|
176
180
|
disconnect(): Promise<void>;
|
|
177
181
|
activateAgent(state: ConnectionState, chainId: number): Promise<void>;
|
|
178
|
-
deposit(state: ConnectionState, chainId: number, amount: string,
|
|
182
|
+
deposit(state: ConnectionState, chainId: number, amount: string, depositCallback?: DepositCallback): Promise<OwneyDepositResult>;
|
|
179
183
|
withdraw(state: ConnectionState, chainId: number, token: OwneySupportedTokens, amount?: string): Promise<AgentWithdrawResult>;
|
|
180
184
|
getBalances(state: ConnectionState, chainId: number): Promise<AgentBalance>;
|
|
181
185
|
getEarnings(state: ConnectionState, chainId: number): Promise<AgentEarnings>;
|
|
@@ -405,11 +409,6 @@ declare class OwneySDK {
|
|
|
405
409
|
* @returns {AgentApy} for a single agent, or {OwneyAgentApy} with per-agent APY
|
|
406
410
|
*/
|
|
407
411
|
getAgentApy({ agentId, days, tokenSymbol, chainId, }: AgentsApyOptions): Promise<OwneyAgentApy | AgentApy>;
|
|
408
|
-
/**
|
|
409
|
-
* Get the current fund allocation percentages across agents.
|
|
410
|
-
* @returns Object with agent names as keys and allocation percentages as values
|
|
411
|
-
*/
|
|
412
|
-
getAgentAllocation(): Promise<OwneyAgentAllocation>;
|
|
413
412
|
/**
|
|
414
413
|
* Allocation-weighted APY from the current portfolio: each pool's APY
|
|
415
414
|
* weighted by the user's position value in it. More accurate per-user than
|
|
@@ -465,4 +464,4 @@ type OwneySIWXConfig = {
|
|
|
465
464
|
*/
|
|
466
465
|
declare function createOwneySIWX(config: OwneySIWXConfig): SIWXConfig;
|
|
467
466
|
|
|
468
|
-
export { AccountAgentApy, AccountApyOptions, AgentApy, AgentApyDetails, AgentBalance, AgentChainIncompatibleError, AgentEarnings, AgentHistoryEntry, AgentHistoryPosition, AgentId, AgentNotFoundError, AgentSupportedAsset, AgentSupportedAssets, AgentUserProfile, AgentWithdrawResult, AgentsApyOptions, AllocationAgentApy, ApyByChainAndAsset, Asset, ConnectionState, DailyApyDays, DepositCallback, DepositOptions, HistoryAction, HistoryFilters, HistoryOptions, HistoryTransaction, IAgent, InvalidHistoryCursorError, NotConnectedError, OwneyAccountApy,
|
|
467
|
+
export { AccountAgentApy, AccountApyOptions, AgentApy, AgentApyDetails, AgentBalance, AgentChainIncompatibleError, AgentEarnings, AgentHistoryEntry, AgentHistoryPosition, AgentId, AgentNotFoundError, AgentSupportedAsset, AgentSupportedAssets, AgentUserProfile, AgentWithdrawResult, AgentsApyOptions, AllocationAgentApy, ApyByChainAndAsset, Asset, ConnectionState, DailyApyDays, DepositCallback, DepositOptions, HistoryAction, HistoryFilters, HistoryOptions, HistoryTransaction, IAgent, InvalidHistoryCursorError, NotConnectedError, OwneyAccountApy, OwneyAgentApy, OwneyAgentHistory, OwneyAllocationApy, OwneyBalances, OwneyDepositResult, OwneyEarnings, OwneyError, OwneyErrorCode, OwneyMultiDepositResult, OwneyPosition, OwneySDK, OwneySDKConfig, OwneySIWXConfig, OwneySupportedChainId, OwneySupportedChains, OwneySupportedTokens, OwneyToken, OwneyUserProfile, OwneyWithdrawResult, RebalanceLog, WithdrawOptions, createOwneySIWX };
|
package/dist/index.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ interface ConnectionState {
|
|
|
14
14
|
walletAddress: `0x${string}`;
|
|
15
15
|
chainId: number | null;
|
|
16
16
|
}
|
|
17
|
-
declare const SUPPORTED_TOKENS: readonly ["USDC", "USDT"
|
|
17
|
+
declare const SUPPORTED_TOKENS: readonly ["USDC", "USDT"];
|
|
18
18
|
declare const SUPPORTED_CHAIN_IDS: readonly [8453, 42161];
|
|
19
19
|
declare const SUPPORTED_CHAINS: readonly ["BASE", "ARBITRUM"];
|
|
20
20
|
type OwneySupportedChainId = (typeof SUPPORTED_CHAIN_IDS)[number];
|
|
@@ -114,6 +114,15 @@ interface HistoryTransaction {
|
|
|
114
114
|
interface RebalanceLog {
|
|
115
115
|
fromProtocol: string;
|
|
116
116
|
toProtocol: string;
|
|
117
|
+
/**
|
|
118
|
+
* Pool/vault sub-label for the source position (e.g. "USDC Core"), when the
|
|
119
|
+
* agent exposes one. Lets consumers disambiguate moves within the same
|
|
120
|
+
* protocol ("Morpho · USDC Core → Morpho · Spark USDC"). Absent when the
|
|
121
|
+
* agent only reports a bare protocol name.
|
|
122
|
+
*/
|
|
123
|
+
fromPool?: string;
|
|
124
|
+
/** Pool/vault sub-label for the destination position. See {@link fromPool}. */
|
|
125
|
+
toPool?: string;
|
|
117
126
|
tokenSymbol: string;
|
|
118
127
|
amount: string;
|
|
119
128
|
status: "success" | "failed";
|
|
@@ -162,11 +171,6 @@ interface AgentApy {
|
|
|
162
171
|
interface OwneyAgentApy {
|
|
163
172
|
agentApy: Record<AgentId, AgentApy>;
|
|
164
173
|
}
|
|
165
|
-
interface OwneyAgentAllocation {
|
|
166
|
-
agentAllocation: Record<AgentId, number>;
|
|
167
|
-
/** Per-agent positions. Empty array for agents that don't expose positions. */
|
|
168
|
-
agentPositions: Record<AgentId, OwneyPosition[]>;
|
|
169
|
-
}
|
|
170
174
|
|
|
171
175
|
type DepositCallback = (smartWalletAddress: string, chainId: number, amount: string) => Promise<`0x${string}`> | `0x${string}`;
|
|
172
176
|
interface IAgent {
|
|
@@ -175,7 +179,7 @@ interface IAgent {
|
|
|
175
179
|
readonly supportedAssets: readonly AgentSupportedAssets[];
|
|
176
180
|
disconnect(): Promise<void>;
|
|
177
181
|
activateAgent(state: ConnectionState, chainId: number): Promise<void>;
|
|
178
|
-
deposit(state: ConnectionState, chainId: number, amount: string,
|
|
182
|
+
deposit(state: ConnectionState, chainId: number, amount: string, depositCallback?: DepositCallback): Promise<OwneyDepositResult>;
|
|
179
183
|
withdraw(state: ConnectionState, chainId: number, token: OwneySupportedTokens, amount?: string): Promise<AgentWithdrawResult>;
|
|
180
184
|
getBalances(state: ConnectionState, chainId: number): Promise<AgentBalance>;
|
|
181
185
|
getEarnings(state: ConnectionState, chainId: number): Promise<AgentEarnings>;
|
|
@@ -405,11 +409,6 @@ declare class OwneySDK {
|
|
|
405
409
|
* @returns {AgentApy} for a single agent, or {OwneyAgentApy} with per-agent APY
|
|
406
410
|
*/
|
|
407
411
|
getAgentApy({ agentId, days, tokenSymbol, chainId, }: AgentsApyOptions): Promise<OwneyAgentApy | AgentApy>;
|
|
408
|
-
/**
|
|
409
|
-
* Get the current fund allocation percentages across agents.
|
|
410
|
-
* @returns Object with agent names as keys and allocation percentages as values
|
|
411
|
-
*/
|
|
412
|
-
getAgentAllocation(): Promise<OwneyAgentAllocation>;
|
|
413
412
|
/**
|
|
414
413
|
* Allocation-weighted APY from the current portfolio: each pool's APY
|
|
415
414
|
* weighted by the user's position value in it. More accurate per-user than
|
|
@@ -465,4 +464,4 @@ type OwneySIWXConfig = {
|
|
|
465
464
|
*/
|
|
466
465
|
declare function createOwneySIWX(config: OwneySIWXConfig): SIWXConfig;
|
|
467
466
|
|
|
468
|
-
export { AccountAgentApy, AccountApyOptions, AgentApy, AgentApyDetails, AgentBalance, AgentChainIncompatibleError, AgentEarnings, AgentHistoryEntry, AgentHistoryPosition, AgentId, AgentNotFoundError, AgentSupportedAsset, AgentSupportedAssets, AgentUserProfile, AgentWithdrawResult, AgentsApyOptions, AllocationAgentApy, ApyByChainAndAsset, Asset, ConnectionState, DailyApyDays, DepositCallback, DepositOptions, HistoryAction, HistoryFilters, HistoryOptions, HistoryTransaction, IAgent, InvalidHistoryCursorError, NotConnectedError, OwneyAccountApy,
|
|
467
|
+
export { AccountAgentApy, AccountApyOptions, AgentApy, AgentApyDetails, AgentBalance, AgentChainIncompatibleError, AgentEarnings, AgentHistoryEntry, AgentHistoryPosition, AgentId, AgentNotFoundError, AgentSupportedAsset, AgentSupportedAssets, AgentUserProfile, AgentWithdrawResult, AgentsApyOptions, AllocationAgentApy, ApyByChainAndAsset, Asset, ConnectionState, DailyApyDays, DepositCallback, DepositOptions, HistoryAction, HistoryFilters, HistoryOptions, HistoryTransaction, IAgent, InvalidHistoryCursorError, NotConnectedError, OwneyAccountApy, OwneyAgentApy, OwneyAgentHistory, OwneyAllocationApy, OwneyBalances, OwneyDepositResult, OwneyEarnings, OwneyError, OwneyErrorCode, OwneyMultiDepositResult, OwneyPosition, OwneySDK, OwneySDKConfig, OwneySIWXConfig, OwneySupportedChainId, OwneySupportedChains, OwneySupportedTokens, OwneyToken, OwneyUserProfile, OwneyWithdrawResult, RebalanceLog, WithdrawOptions, createOwneySIWX };
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
// src/agents/zyfai/zyfai.agent.ts
|
|
2
2
|
import { ZyfaiSDK } from "@zyfai/sdk";
|
|
3
|
+
import { createPublicClient, http } from "viem";
|
|
4
|
+
import { base, arbitrum } from "viem/chains";
|
|
3
5
|
|
|
4
6
|
// src/types/config.ts
|
|
5
7
|
var P_SUPPORTED_CHAINS = {
|
|
6
8
|
chainIds: [8453, 42161],
|
|
7
9
|
chains: ["BASE", "ARBITRUM"]
|
|
8
10
|
};
|
|
9
|
-
var SUPPORTED_TOKENS = ["USDC", "USDT"
|
|
11
|
+
var SUPPORTED_TOKENS = ["USDC", "USDT"];
|
|
10
12
|
var SUPPORTED_CHAIN_IDS = P_SUPPORTED_CHAINS.chainIds;
|
|
11
13
|
var SUPPORTED_CHAINS = P_SUPPORTED_CHAINS.chains;
|
|
12
14
|
var SupportedAssets = [
|
|
@@ -27,18 +29,6 @@ var SupportedAssets = [
|
|
|
27
29
|
symbol: "USDT",
|
|
28
30
|
chainId: 42161,
|
|
29
31
|
decimals: 6
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
address: `0x4200000000000000000000000000000000000006`,
|
|
33
|
-
symbol: "WETH",
|
|
34
|
-
chainId: 8453,
|
|
35
|
-
decimals: 18
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
address: `0x82aF49447D8a07e3bd95BD0d56f35241523fBab1`,
|
|
39
|
-
symbol: "WETH",
|
|
40
|
-
chainId: 42161,
|
|
41
|
-
decimals: 18
|
|
42
32
|
}
|
|
43
33
|
];
|
|
44
34
|
|
|
@@ -248,6 +238,14 @@ function mapApyHistory(raw) {
|
|
|
248
238
|
apyByChainAndAsset: mapWeightedApyByChain(raw.weightedApyAfterFeeByChain)
|
|
249
239
|
};
|
|
250
240
|
}
|
|
241
|
+
function splitOpportunity(opportunity) {
|
|
242
|
+
const match = opportunity.match(/^(.*?)\s*\(([^)]*)\)\s*$/);
|
|
243
|
+
if (match) {
|
|
244
|
+
const pool = match[2].trim();
|
|
245
|
+
return { protocol: match[1].trim(), pool: pool || void 0 };
|
|
246
|
+
}
|
|
247
|
+
return { protocol: opportunity.trim() };
|
|
248
|
+
}
|
|
251
249
|
function mapEntries(rawEntries, chainId) {
|
|
252
250
|
const actionMap = {
|
|
253
251
|
"Top up wallet": "Top up",
|
|
@@ -267,21 +265,26 @@ function mapEntries(rawEntries, chainId) {
|
|
|
267
265
|
);
|
|
268
266
|
oldApy = Number(rawLog.oldApy);
|
|
269
267
|
newApy = Number(rawLog.newApy);
|
|
268
|
+
const from = splitOpportunity(rawLog.oldOpportunity);
|
|
269
|
+
const to = splitOpportunity(rawLog.newOpportunity);
|
|
270
270
|
rebalanceLog = [
|
|
271
271
|
{
|
|
272
|
-
fromProtocol:
|
|
273
|
-
toProtocol:
|
|
272
|
+
fromProtocol: from.protocol,
|
|
273
|
+
toProtocol: to.protocol,
|
|
274
|
+
fromPool: from.pool,
|
|
275
|
+
toPool: to.pool,
|
|
274
276
|
tokenSymbol: matched?.token_symbol ?? "",
|
|
275
277
|
amount: matched ? String(hexToDecimal(matched.amount || "0x")) : "",
|
|
276
278
|
status: "success"
|
|
277
279
|
}
|
|
278
280
|
];
|
|
279
281
|
}
|
|
282
|
+
const mappedAction = (entry.action ? actionMap[entry.action] : void 0) ?? entry.action;
|
|
280
283
|
const rawAmount = entry?.positions?.[0]?.amount;
|
|
281
|
-
const hasAmount = typeof rawAmount === "string" && rawAmount !== "" && rawAmount !== "0x" && rawAmount !== "0x0" && rawAmount !== "0";
|
|
284
|
+
const hasAmount = mappedAction !== "Withdraw" && typeof rawAmount === "string" && rawAmount !== "" && rawAmount !== "0x" && rawAmount !== "0x0" && rawAmount !== "0";
|
|
282
285
|
return {
|
|
283
286
|
agent: "zyfai",
|
|
284
|
-
action:
|
|
287
|
+
action: mappedAction,
|
|
285
288
|
date: entry.date || "",
|
|
286
289
|
newApy: newApy === null ? null : String(newApy),
|
|
287
290
|
oldApy: oldApy === null ? null : String(oldApy),
|
|
@@ -373,6 +376,33 @@ function computeAllocationApy(positions) {
|
|
|
373
376
|
return { totalApy, apyByChainAndAsset };
|
|
374
377
|
}
|
|
375
378
|
|
|
379
|
+
// src/agents/zyfai/zyfai.withdraw-amount.ts
|
|
380
|
+
var TRANSFER_TOPIC = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef";
|
|
381
|
+
function topicToAddress(topic) {
|
|
382
|
+
return `0x${(topic ?? "").slice(-40)}`.toLowerCase();
|
|
383
|
+
}
|
|
384
|
+
function extractWithdrawnAmount(logs, recipient, token, decimals) {
|
|
385
|
+
const wantRecipient = recipient.toLowerCase();
|
|
386
|
+
const wantToken = token.toLowerCase();
|
|
387
|
+
let total = 0n;
|
|
388
|
+
let matched = false;
|
|
389
|
+
for (const log of logs) {
|
|
390
|
+
if (log.address.toLowerCase() !== wantToken)
|
|
391
|
+
continue;
|
|
392
|
+
if ((log.topics[0] ?? "").toLowerCase() !== TRANSFER_TOPIC)
|
|
393
|
+
continue;
|
|
394
|
+
if (topicToAddress(log.topics[2]) !== wantRecipient)
|
|
395
|
+
continue;
|
|
396
|
+
if (!log.data || log.data === "0x")
|
|
397
|
+
continue;
|
|
398
|
+
total += BigInt(log.data);
|
|
399
|
+
matched = true;
|
|
400
|
+
}
|
|
401
|
+
if (!matched)
|
|
402
|
+
return void 0;
|
|
403
|
+
return String(hexToDecimal(`0x${total.toString(16)}`, decimals));
|
|
404
|
+
}
|
|
405
|
+
|
|
376
406
|
// src/agents/zyfai/zyfai.history-cursor.ts
|
|
377
407
|
var InvalidHistoryCursorError = class extends Error {
|
|
378
408
|
code = "invalid_cursor";
|
|
@@ -471,10 +501,7 @@ var DEFAULT_ZYFAI_RPC_URLS = {
|
|
|
471
501
|
8453: "https://base-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V",
|
|
472
502
|
42161: "https://arb-mainnet.g.alchemy.com/v2/ZWyVU-9XfS3z8Rn-xkq7V"
|
|
473
503
|
};
|
|
474
|
-
var
|
|
475
|
-
8453: "0x4200000000000000000000000000000000000006",
|
|
476
|
-
42161: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"
|
|
477
|
-
};
|
|
504
|
+
var VIEM_CHAIN = { 8453: base, 42161: arbitrum };
|
|
478
505
|
var ZyfaiAgent = class {
|
|
479
506
|
id = "zyfai";
|
|
480
507
|
supportedChainIds = [8453, 42161];
|
|
@@ -482,18 +509,12 @@ var ZyfaiAgent = class {
|
|
|
482
509
|
{
|
|
483
510
|
chainId: 8453,
|
|
484
511
|
chain: "BASE",
|
|
485
|
-
assets: [
|
|
486
|
-
{ symbol: "USDC", minDepositAmount: "1500000" },
|
|
487
|
-
{ symbol: "WETH", minDepositAmount: "500000000000000" }
|
|
488
|
-
]
|
|
512
|
+
assets: [{ symbol: "USDC", minDepositAmount: "1500000" }]
|
|
489
513
|
},
|
|
490
514
|
{
|
|
491
515
|
chainId: 42161,
|
|
492
516
|
chain: "ARBITRUM",
|
|
493
|
-
assets: [
|
|
494
|
-
{ symbol: "USDC", minDepositAmount: "1500000" },
|
|
495
|
-
{ symbol: "WETH", minDepositAmount: "500000000000000" }
|
|
496
|
-
]
|
|
517
|
+
assets: [{ symbol: "USDC", minDepositAmount: "1500000" }]
|
|
497
518
|
}
|
|
498
519
|
];
|
|
499
520
|
sdk;
|
|
@@ -501,13 +522,83 @@ var ZyfaiAgent = class {
|
|
|
501
522
|
connectedChainId = null;
|
|
502
523
|
smartWalletCache = /* @__PURE__ */ new Map();
|
|
503
524
|
connectAuthPromise = null;
|
|
525
|
+
rpcUrls;
|
|
526
|
+
publicClients = /* @__PURE__ */ new Map();
|
|
527
|
+
// txHash -> resolved withdrawn amount. Receipts are immutable, so a
|
|
528
|
+
// successful decode is cached forever; failures are NOT cached so a transient
|
|
529
|
+
// RPC error retries on the next fetch.
|
|
530
|
+
withdrawAmountCache = /* @__PURE__ */ new Map();
|
|
504
531
|
constructor(apiKey, rpcUrls) {
|
|
532
|
+
this.rpcUrls = rpcUrls ?? DEFAULT_ZYFAI_RPC_URLS;
|
|
505
533
|
this.sdk = new ZyfaiSDK({
|
|
506
534
|
apiKey,
|
|
507
|
-
rpcUrls: rpcUrls
|
|
535
|
+
rpcUrls: this.rpcUrls
|
|
508
536
|
});
|
|
509
537
|
this.installAuthCache();
|
|
510
538
|
}
|
|
539
|
+
getPublicClient(chainId) {
|
|
540
|
+
const cached = this.publicClients.get(chainId);
|
|
541
|
+
if (cached)
|
|
542
|
+
return cached;
|
|
543
|
+
const client = createPublicClient({
|
|
544
|
+
chain: VIEM_CHAIN[chainId],
|
|
545
|
+
transport: http(this.rpcUrls[chainId])
|
|
546
|
+
});
|
|
547
|
+
this.publicClients.set(chainId, client);
|
|
548
|
+
return client;
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* Fills in the true withdrawn amount for `Withdraw` entries by decoding the
|
|
552
|
+
* USDC `Transfer` that lands in the user's wallet on-chain. The Zyfai history
|
|
553
|
+
* payload only reports the *remaining* position for a partial withdraw (see
|
|
554
|
+
* the note in `mapEntries`), so without this the UI shows the leftover
|
|
555
|
+
* balance instead of the amount withdrawn.
|
|
556
|
+
*
|
|
557
|
+
* Mutates `entries` in place. Runs all lookups concurrently and is tolerant
|
|
558
|
+
* of RPC failures: an entry whose amount can't be resolved keeps
|
|
559
|
+
* `amount: undefined`, which consumers render as a hidden/retryable row
|
|
560
|
+
* rather than a wrong number.
|
|
561
|
+
*/
|
|
562
|
+
async resolveWithdrawnAmounts(entries, chainId, recipient) {
|
|
563
|
+
const asset = SupportedAssets.find(
|
|
564
|
+
(a) => a.chainId === chainId && a.symbol === "USDC"
|
|
565
|
+
);
|
|
566
|
+
if (!asset)
|
|
567
|
+
return;
|
|
568
|
+
const withdrawals = entries.filter(
|
|
569
|
+
(e) => e.action === "Withdraw" && e.transactions[0]?.txHashes[0]
|
|
570
|
+
);
|
|
571
|
+
if (withdrawals.length === 0)
|
|
572
|
+
return;
|
|
573
|
+
const client = this.getPublicClient(chainId);
|
|
574
|
+
await Promise.all(
|
|
575
|
+
withdrawals.map(async (entry) => {
|
|
576
|
+
const tx = entry.transactions[0];
|
|
577
|
+
const txHash = tx.txHashes[0];
|
|
578
|
+
const cached = this.withdrawAmountCache.get(txHash);
|
|
579
|
+
if (cached !== void 0) {
|
|
580
|
+
tx.amount = cached;
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
583
|
+
try {
|
|
584
|
+
const receipt = await client.getTransactionReceipt({
|
|
585
|
+
hash: txHash
|
|
586
|
+
});
|
|
587
|
+
const amount = extractWithdrawnAmount(
|
|
588
|
+
receipt.logs,
|
|
589
|
+
recipient,
|
|
590
|
+
asset.address,
|
|
591
|
+
asset.decimals
|
|
592
|
+
);
|
|
593
|
+
if (amount !== void 0) {
|
|
594
|
+
this.withdrawAmountCache.set(txHash, amount);
|
|
595
|
+
tx.amount = amount;
|
|
596
|
+
}
|
|
597
|
+
} catch {
|
|
598
|
+
}
|
|
599
|
+
})
|
|
600
|
+
);
|
|
601
|
+
}
|
|
511
602
|
/**
|
|
512
603
|
* Patches `sdk.authenticateUser` so a fresh page can reuse the JWT from a
|
|
513
604
|
* prior session instead of triggering a new SIWE prompt. Runs inside
|
|
@@ -659,7 +750,7 @@ var ZyfaiAgent = class {
|
|
|
659
750
|
throw error;
|
|
660
751
|
}
|
|
661
752
|
}
|
|
662
|
-
async deposit(state, chainId, amount,
|
|
753
|
+
async deposit(state, chainId, amount, depositCallback) {
|
|
663
754
|
try {
|
|
664
755
|
await this.connectFull(state, chainId);
|
|
665
756
|
const validChainId = isValidChainId(chainId);
|
|
@@ -673,15 +764,13 @@ var ZyfaiAgent = class {
|
|
|
673
764
|
validChainId,
|
|
674
765
|
amount
|
|
675
766
|
);
|
|
676
|
-
|
|
677
|
-
await (tokenAddress ? this.sdk.logDeposit(validChainId, txHash, amount, tokenAddress) : this.sdk.logDeposit(validChainId, txHash, amount));
|
|
767
|
+
await this.sdk.logDeposit(validChainId, txHash, amount);
|
|
678
768
|
return { txHash, smartWallet: wallet.address, amount };
|
|
679
769
|
}
|
|
680
770
|
const raw = await this.sdk.depositFunds(
|
|
681
771
|
this.getAddress(),
|
|
682
772
|
validChainId,
|
|
683
|
-
amount
|
|
684
|
-
asset
|
|
773
|
+
amount
|
|
685
774
|
);
|
|
686
775
|
return mapDeposit(raw);
|
|
687
776
|
} catch (error) {
|
|
@@ -760,8 +849,10 @@ var ZyfaiAgent = class {
|
|
|
760
849
|
toDate,
|
|
761
850
|
rawOffset: firstOvershoot ? firstOvershoot.rawIdx : offset
|
|
762
851
|
}) : void 0;
|
|
852
|
+
const data = mapEntries(pageData, validChainId);
|
|
853
|
+
await this.resolveWithdrawnAmounts(data, validChainId, state.walletAddress);
|
|
763
854
|
return {
|
|
764
|
-
data
|
|
855
|
+
data,
|
|
765
856
|
hasMore,
|
|
766
857
|
nextCursor
|
|
767
858
|
};
|
|
@@ -979,11 +1070,11 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
|
|
|
979
1070
|
|
|
980
1071
|
// src/client.ts
|
|
981
1072
|
import {
|
|
982
|
-
createPublicClient,
|
|
1073
|
+
createPublicClient as createPublicClient2,
|
|
983
1074
|
createWalletClient,
|
|
984
1075
|
custom
|
|
985
1076
|
} from "viem";
|
|
986
|
-
import { base, arbitrum } from "viem/chains";
|
|
1077
|
+
import { base as base2, arbitrum as arbitrum2 } from "viem/chains";
|
|
987
1078
|
|
|
988
1079
|
// src/lib/transfer-auth.ts
|
|
989
1080
|
import { bytesToHex } from "viem";
|
|
@@ -1024,10 +1115,10 @@ function randomAuthNonce() {
|
|
|
1024
1115
|
// src/lib/sponsor-client.ts
|
|
1025
1116
|
var ROUTING_API_BASE_URL3 = "https://owney-routing-api-243946518160.europe-west4.run.app";
|
|
1026
1117
|
async function postSponsorTransferAuth(input) {
|
|
1027
|
-
const
|
|
1118
|
+
const base3 = input.baseUrl ?? ROUTING_API_BASE_URL3;
|
|
1028
1119
|
let res;
|
|
1029
1120
|
try {
|
|
1030
|
-
res = await fetch(`${
|
|
1121
|
+
res = await fetch(`${base3}/api/v1/sponsor/erc20-transfer-auth`, {
|
|
1031
1122
|
method: "POST",
|
|
1032
1123
|
headers: { "content-type": "application/json", "x-owney-api-key": input.apiKey },
|
|
1033
1124
|
body: JSON.stringify(input.body)
|
|
@@ -1130,9 +1221,9 @@ var SPONSORED_USDC_BY_CHAIN = {
|
|
|
1130
1221
|
8453: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
|
|
1131
1222
|
42161: "0xaf88d065e77c8cc2239327c5edb3a432268e5831"
|
|
1132
1223
|
};
|
|
1133
|
-
var
|
|
1134
|
-
8453:
|
|
1135
|
-
42161:
|
|
1224
|
+
var VIEM_CHAIN2 = {
|
|
1225
|
+
8453: base2,
|
|
1226
|
+
42161: arbitrum2
|
|
1136
1227
|
};
|
|
1137
1228
|
var OwneySDK = class {
|
|
1138
1229
|
agents = /* @__PURE__ */ new Map();
|
|
@@ -1245,13 +1336,13 @@ var OwneySDK = class {
|
|
|
1245
1336
|
// Casts work around viem's chain-narrowed Client vs the generic
|
|
1246
1337
|
// PublicClient/WalletClient param types — structurally identical at
|
|
1247
1338
|
// runtime, but the two share a name TS treats as unrelated.
|
|
1248
|
-
getPublicClient: (cid) =>
|
|
1249
|
-
chain:
|
|
1339
|
+
getPublicClient: (cid) => createPublicClient2({
|
|
1340
|
+
chain: VIEM_CHAIN2[cid],
|
|
1250
1341
|
transport: custom(provider)
|
|
1251
1342
|
}),
|
|
1252
1343
|
getWalletClient: (cid) => createWalletClient({
|
|
1253
1344
|
account: owner,
|
|
1254
|
-
chain:
|
|
1345
|
+
chain: VIEM_CHAIN2[cid],
|
|
1255
1346
|
transport: custom(provider)
|
|
1256
1347
|
})
|
|
1257
1348
|
});
|
|
@@ -1410,7 +1501,7 @@ var OwneySDK = class {
|
|
|
1410
1501
|
}
|
|
1411
1502
|
const state = this.requireState();
|
|
1412
1503
|
const chainId = this.requireChainId();
|
|
1413
|
-
const effectiveCallback = depositCallback ??
|
|
1504
|
+
const effectiveCallback = depositCallback ?? this.getDefaultSponsoredCallback();
|
|
1414
1505
|
if (agentId) {
|
|
1415
1506
|
if (this.isAgentDisabled(agentId)) {
|
|
1416
1507
|
throw new OwneyError(
|
|
@@ -1425,13 +1516,7 @@ var OwneySDK = class {
|
|
|
1425
1516
|
return withFailureReporting(
|
|
1426
1517
|
this.apiKey,
|
|
1427
1518
|
agent.id,
|
|
1428
|
-
() => agent.deposit(
|
|
1429
|
-
state,
|
|
1430
|
-
chainId,
|
|
1431
|
-
amount,
|
|
1432
|
-
asset,
|
|
1433
|
-
effectiveCallback
|
|
1434
|
-
)
|
|
1519
|
+
() => agent.deposit(state, chainId, amount, effectiveCallback)
|
|
1435
1520
|
);
|
|
1436
1521
|
}
|
|
1437
1522
|
const totalAmount = BigInt(amount);
|
|
@@ -1465,13 +1550,7 @@ var OwneySDK = class {
|
|
|
1465
1550
|
agentResults[agent.id] = await withFailureReporting(
|
|
1466
1551
|
this.apiKey,
|
|
1467
1552
|
agent.id,
|
|
1468
|
-
() => agent.deposit(
|
|
1469
|
-
state,
|
|
1470
|
-
chainId,
|
|
1471
|
-
agentAmount,
|
|
1472
|
-
asset,
|
|
1473
|
-
effectiveCallback
|
|
1474
|
-
)
|
|
1553
|
+
() => agent.deposit(state, chainId, agentAmount, effectiveCallback)
|
|
1475
1554
|
);
|
|
1476
1555
|
}
|
|
1477
1556
|
return { agentResults };
|
|
@@ -2001,70 +2080,6 @@ var OwneySDK = class {
|
|
|
2001
2080
|
agentApy: results
|
|
2002
2081
|
};
|
|
2003
2082
|
}
|
|
2004
|
-
/**
|
|
2005
|
-
* Get the current fund allocation percentages across agents.
|
|
2006
|
-
* @returns Object with agent names as keys and allocation percentages as values
|
|
2007
|
-
*/
|
|
2008
|
-
async getAgentAllocation() {
|
|
2009
|
-
const state = this.requireState();
|
|
2010
|
-
const chainId = this.requireChainId();
|
|
2011
|
-
const activeAgents = this.getActiveAgents();
|
|
2012
|
-
const balances = {};
|
|
2013
|
-
const positionsByAgent = {};
|
|
2014
|
-
let totalBalance = 0;
|
|
2015
|
-
const entries = [...activeAgents.entries()];
|
|
2016
|
-
const balanceResults = await Promise.allSettled(
|
|
2017
|
-
entries.map(async ([id, agent]) => {
|
|
2018
|
-
const b = await agent.getBalances(state, chainId);
|
|
2019
|
-
return [id, Number(b.totalBalance), b.positions ?? []];
|
|
2020
|
-
})
|
|
2021
|
-
);
|
|
2022
|
-
let successCount = 0;
|
|
2023
|
-
const agentErrors = {};
|
|
2024
|
-
for (let i = 0; i < balanceResults.length; i++) {
|
|
2025
|
-
const settledResult = balanceResults[i];
|
|
2026
|
-
const [agentId] = entries[i];
|
|
2027
|
-
if (settledResult.status === "fulfilled") {
|
|
2028
|
-
const [id, bal, agentPositions] = settledResult.value;
|
|
2029
|
-
balances[id] = bal;
|
|
2030
|
-
positionsByAgent[id] = agentPositions;
|
|
2031
|
-
totalBalance += bal;
|
|
2032
|
-
successCount += 1;
|
|
2033
|
-
} else {
|
|
2034
|
-
const reason = settledResult.reason;
|
|
2035
|
-
agentErrors[agentId] = reason instanceof Error ? reason.message : String(reason);
|
|
2036
|
-
console.error(`getAgentAllocation agent "${agentId}" failed:`, reason);
|
|
2037
|
-
}
|
|
2038
|
-
}
|
|
2039
|
-
if (successCount === 0) {
|
|
2040
|
-
throw new OwneyError(
|
|
2041
|
-
"ALLOCATION_ALL_FAILED",
|
|
2042
|
-
"Failed to fetch allocation: all agents failed.",
|
|
2043
|
-
{ agentErrors }
|
|
2044
|
-
);
|
|
2045
|
-
}
|
|
2046
|
-
const allocation = {};
|
|
2047
|
-
if (totalBalance === 0) {
|
|
2048
|
-
for (const id of activeAgents.keys()) {
|
|
2049
|
-
allocation[id] = 0;
|
|
2050
|
-
}
|
|
2051
|
-
} else {
|
|
2052
|
-
for (const id of activeAgents.keys()) {
|
|
2053
|
-
allocation[id] = balances[id] > 0 ? Math.max(1, Math.floor(balances[id] / totalBalance * 100)) : 0;
|
|
2054
|
-
}
|
|
2055
|
-
const remainder = 100 - Object.values(allocation).reduce((a, b) => a + b, 0);
|
|
2056
|
-
if (remainder > 0) {
|
|
2057
|
-
const largestId = [...activeAgents.keys()].reduce(
|
|
2058
|
-
(a, b) => balances[a] >= balances[b] ? a : b
|
|
2059
|
-
);
|
|
2060
|
-
allocation[largestId] += remainder;
|
|
2061
|
-
}
|
|
2062
|
-
}
|
|
2063
|
-
return {
|
|
2064
|
-
agentAllocation: allocation,
|
|
2065
|
-
agentPositions: positionsByAgent
|
|
2066
|
-
};
|
|
2067
|
-
}
|
|
2068
2083
|
/**
|
|
2069
2084
|
* Allocation-weighted APY from the current portfolio: each pool's APY
|
|
2070
2085
|
* weighted by the user's position value in it. More accurate per-user than
|
|
@@ -2282,9 +2297,9 @@ function buildSIWXConfig(deps) {
|
|
|
2282
2297
|
}
|
|
2283
2298
|
function createOwneySIWX(config) {
|
|
2284
2299
|
const zyfai = new ZyfaiSDK2({ apiKey: config.apiKey });
|
|
2285
|
-
const
|
|
2300
|
+
const http2 = zyfai.httpClient;
|
|
2286
2301
|
return buildSIWXConfig({
|
|
2287
|
-
post: (url, data) =>
|
|
2302
|
+
post: (url, data) => http2.post(url, data),
|
|
2288
2303
|
referralSource: config.referralSource
|
|
2289
2304
|
});
|
|
2290
2305
|
}
|