@owney/sdk 0.2.18 → 0.3.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/dist/index.cjs +104 -19
- package/dist/index.d.cts +8 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.js +104 -19
- package/package.json +6 -3
package/dist/index.cjs
CHANGED
|
@@ -578,6 +578,19 @@ async function fetchAgentKeys(apiKey) {
|
|
|
578
578
|
}
|
|
579
579
|
|
|
580
580
|
// src/lib/helpers/withdraw-helper.ts
|
|
581
|
+
var import_viem = require("viem");
|
|
582
|
+
function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
|
|
583
|
+
const target = asset.toUpperCase();
|
|
584
|
+
return agents.map((agent) => {
|
|
585
|
+
const agentBalance = aggregated[agent.id];
|
|
586
|
+
const tokenBalance = agentBalance?.tokens.find(
|
|
587
|
+
(t) => t.chainId === chainId && t.asset.toUpperCase() === target
|
|
588
|
+
);
|
|
589
|
+
if (!tokenBalance)
|
|
590
|
+
return { agent, balance: 0n };
|
|
591
|
+
return { agent, balance: (0, import_viem.parseUnits)(tokenBalance.amount, decimals) };
|
|
592
|
+
});
|
|
593
|
+
}
|
|
581
594
|
function planProportionalShares(balances, requested, totalAvailable) {
|
|
582
595
|
const plans = balances.map(({ agent, balance }) => ({
|
|
583
596
|
agent,
|
|
@@ -602,8 +615,24 @@ function planProportionalShares(balances, requested, totalAvailable) {
|
|
|
602
615
|
}
|
|
603
616
|
return plans;
|
|
604
617
|
}
|
|
605
|
-
function
|
|
606
|
-
const
|
|
618
|
+
function planDisabledDrain(disabled, requested) {
|
|
619
|
+
const sorted = [...disabled].filter((d) => d.balance > 0n).sort((a, b) => b.balance > a.balance ? 1 : b.balance < a.balance ? -1 : 0);
|
|
620
|
+
const plans = [];
|
|
621
|
+
let remaining = requested;
|
|
622
|
+
for (const { agent, balance } of sorted) {
|
|
623
|
+
if (remaining === 0n) {
|
|
624
|
+
plans.push({ agent, balance, planned: 0n });
|
|
625
|
+
continue;
|
|
626
|
+
}
|
|
627
|
+
const take = balance < remaining ? balance : remaining;
|
|
628
|
+
plans.push({ agent, balance, planned: take });
|
|
629
|
+
remaining -= take;
|
|
630
|
+
}
|
|
631
|
+
return { plans, remaining };
|
|
632
|
+
}
|
|
633
|
+
function redistributeShare(plans, fromIndex, amount, candidatePool) {
|
|
634
|
+
const pool = candidatePool ?? plans.slice(fromIndex + 1);
|
|
635
|
+
const candidates = pool.filter((c) => c.balance - c.planned > 0n);
|
|
607
636
|
const totalHeadroom = candidates.reduce(
|
|
608
637
|
(s, c) => s + (c.balance - c.planned),
|
|
609
638
|
0n
|
|
@@ -675,10 +704,15 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
|
|
|
675
704
|
}
|
|
676
705
|
|
|
677
706
|
// src/client.ts
|
|
678
|
-
var import_viem = require("viem");
|
|
679
707
|
var OwneySDK = class {
|
|
680
708
|
agents = /* @__PURE__ */ new Map();
|
|
681
709
|
activeAgents = /* @__PURE__ */ new Set();
|
|
710
|
+
/**
|
|
711
|
+
* Agents whose routing flag is_enabled === false. They remain in
|
|
712
|
+
* `this.agents` and may still be added to `activeAgents` for read +
|
|
713
|
+
* withdraw, but they are excluded from new deposits / activations.
|
|
714
|
+
*/
|
|
715
|
+
disabledAgents = /* @__PURE__ */ new Set();
|
|
682
716
|
state = null;
|
|
683
717
|
apiKey;
|
|
684
718
|
zyfaiRpcUrls;
|
|
@@ -715,8 +749,12 @@ var OwneySDK = class {
|
|
|
715
749
|
await agent.disconnect();
|
|
716
750
|
}
|
|
717
751
|
this.activeAgents.clear();
|
|
752
|
+
this.disabledAgents.clear();
|
|
718
753
|
this.state = null;
|
|
719
754
|
}
|
|
755
|
+
isAgentDisabled(agentId) {
|
|
756
|
+
return this.disabledAgents.has(agentId);
|
|
757
|
+
}
|
|
720
758
|
/**
|
|
721
759
|
* Check if the SDK has an active connection state.
|
|
722
760
|
* @returns `true` if `connect()` has been called and `disconnect()` has not
|
|
@@ -768,11 +806,15 @@ var OwneySDK = class {
|
|
|
768
806
|
if (!this.initializingAgentsPromise) {
|
|
769
807
|
this.initializingAgentsPromise = (async () => {
|
|
770
808
|
const agentKeys = await fetchAgentKeys(this.apiKey);
|
|
771
|
-
|
|
809
|
+
this.disabledAgents.clear();
|
|
810
|
+
for (const { key, agent_type, is_enabled } of agentKeys) {
|
|
772
811
|
const agent = this.createAgent(agent_type, key);
|
|
773
812
|
if (!agent)
|
|
774
813
|
continue;
|
|
775
814
|
this.agents.set(agent_type, agent);
|
|
815
|
+
if (is_enabled === false) {
|
|
816
|
+
this.disabledAgents.add(agent_type);
|
|
817
|
+
}
|
|
776
818
|
}
|
|
777
819
|
if (this.agents.size === 0) {
|
|
778
820
|
throw new OwneyError(
|
|
@@ -817,6 +859,16 @@ var OwneySDK = class {
|
|
|
817
859
|
}
|
|
818
860
|
const uniqueIds = [...new Set(agentId)];
|
|
819
861
|
const agents = uniqueIds.map((id) => this.getAgent(id));
|
|
862
|
+
const disabledRequested = uniqueIds.filter(
|
|
863
|
+
(id) => this.isAgentDisabled(id)
|
|
864
|
+
);
|
|
865
|
+
if (disabledRequested.length > 0) {
|
|
866
|
+
throw new OwneyError(
|
|
867
|
+
"AGENT_DISABLED",
|
|
868
|
+
`Cannot activate disabled agent(s): ${disabledRequested.join(", ")}.`,
|
|
869
|
+
{ agentIds: disabledRequested }
|
|
870
|
+
);
|
|
871
|
+
}
|
|
820
872
|
const incompatibleAgents = agents.filter(
|
|
821
873
|
(agent) => !agent.supportedChainIds.includes(chainId)
|
|
822
874
|
).map((agent) => ({
|
|
@@ -855,8 +907,11 @@ var OwneySDK = class {
|
|
|
855
907
|
this.activeAgents.add(agent.id);
|
|
856
908
|
}
|
|
857
909
|
state.chainId = chainId;
|
|
910
|
+
const enabledCompatible = compatible.filter(
|
|
911
|
+
(agent) => !this.isAgentDisabled(agent.id)
|
|
912
|
+
);
|
|
858
913
|
Promise.all(
|
|
859
|
-
|
|
914
|
+
enabledCompatible.map(async (agent) => {
|
|
860
915
|
await agent.activateAgent(state, chainId);
|
|
861
916
|
})
|
|
862
917
|
).catch((error) => {
|
|
@@ -883,13 +938,22 @@ var OwneySDK = class {
|
|
|
883
938
|
const state = this.requireState();
|
|
884
939
|
const chainId = this.requireChainId();
|
|
885
940
|
if (agentId) {
|
|
941
|
+
if (this.isAgentDisabled(agentId)) {
|
|
942
|
+
throw new OwneyError(
|
|
943
|
+
"AGENT_DISABLED",
|
|
944
|
+
`Cannot deposit into disabled agent "${agentId}". Existing balances remain visible and withdrawable.`,
|
|
945
|
+
{ agentId }
|
|
946
|
+
);
|
|
947
|
+
}
|
|
886
948
|
const agent = this.getAgent(agentId);
|
|
887
949
|
this.validateAssetSupport(agent, chainId, asset);
|
|
888
950
|
this.validateMinDepositAmount(agent, chainId, asset, amount);
|
|
889
951
|
return agent.deposit(state, chainId, amount, depositCallback);
|
|
890
952
|
}
|
|
891
953
|
const totalAmount = BigInt(amount);
|
|
892
|
-
const eligibleAgents = this.getEligibleAgents(chainId, asset
|
|
954
|
+
const eligibleAgents = this.getEligibleAgents(chainId, asset, {
|
|
955
|
+
excludeDisabled: true
|
|
956
|
+
});
|
|
893
957
|
const agentAmounts = this.splitDepositAmount(
|
|
894
958
|
totalAmount,
|
|
895
959
|
eligibleAgents,
|
|
@@ -973,8 +1037,11 @@ var OwneySDK = class {
|
|
|
973
1037
|
);
|
|
974
1038
|
}
|
|
975
1039
|
}
|
|
976
|
-
getEligibleAgents(chainId, asset) {
|
|
1040
|
+
getEligibleAgents(chainId, asset, opts) {
|
|
977
1041
|
const eligible = [...this.agents.values()].filter((agent) => {
|
|
1042
|
+
if (opts?.excludeDisabled && this.isAgentDisabled(agent.id)) {
|
|
1043
|
+
return false;
|
|
1044
|
+
}
|
|
978
1045
|
const chainAssets = agent.supportedAssets.find(
|
|
979
1046
|
(sa) => sa.chainId === chainId
|
|
980
1047
|
);
|
|
@@ -1041,16 +1108,13 @@ var OwneySDK = class {
|
|
|
1041
1108
|
}
|
|
1042
1109
|
const requested = BigInt(amount);
|
|
1043
1110
|
const aggregated = await this.getBalances();
|
|
1044
|
-
const balances =
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
const balance = (0, import_viem.parseUnits)(tokenBalance.amount, assetInfo.decimals);
|
|
1052
|
-
return { agent, balance };
|
|
1053
|
-
});
|
|
1111
|
+
const balances = projectAgentBalancesForAsset(
|
|
1112
|
+
eligibleAgents,
|
|
1113
|
+
aggregated.agentBalances,
|
|
1114
|
+
chainId,
|
|
1115
|
+
asset,
|
|
1116
|
+
assetInfo.decimals
|
|
1117
|
+
);
|
|
1054
1118
|
const totalAvailable = balances.reduce((sum, x) => sum + x.balance, 0n);
|
|
1055
1119
|
if (totalAvailable < requested) {
|
|
1056
1120
|
throw new OwneyError(
|
|
@@ -1063,7 +1127,26 @@ var OwneySDK = class {
|
|
|
1063
1127
|
}
|
|
1064
1128
|
);
|
|
1065
1129
|
}
|
|
1066
|
-
const
|
|
1130
|
+
const disabledBalances = balances.filter(
|
|
1131
|
+
(b) => this.isAgentDisabled(b.agent.id)
|
|
1132
|
+
);
|
|
1133
|
+
const enabledBalances = balances.filter(
|
|
1134
|
+
(b) => !this.isAgentDisabled(b.agent.id)
|
|
1135
|
+
);
|
|
1136
|
+
const { plans: disabledPlans, remaining: afterDrain } = planDisabledDrain(
|
|
1137
|
+
disabledBalances,
|
|
1138
|
+
requested
|
|
1139
|
+
);
|
|
1140
|
+
const enabledTotal = enabledBalances.reduce(
|
|
1141
|
+
(s, b) => s + b.balance,
|
|
1142
|
+
0n
|
|
1143
|
+
);
|
|
1144
|
+
const enabledPlans = afterDrain > 0n ? planProportionalShares(enabledBalances, afterDrain, enabledTotal) : enabledBalances.map(({ agent, balance }) => ({
|
|
1145
|
+
agent,
|
|
1146
|
+
balance,
|
|
1147
|
+
planned: 0n
|
|
1148
|
+
}));
|
|
1149
|
+
const plans = [...disabledPlans, ...enabledPlans];
|
|
1067
1150
|
const results = {};
|
|
1068
1151
|
const agentErrors = {};
|
|
1069
1152
|
for (let i = 0; i < plans.length; i++) {
|
|
@@ -1080,7 +1163,9 @@ var OwneySDK = class {
|
|
|
1080
1163
|
} catch (err) {
|
|
1081
1164
|
console.error(`withdraw failed for agent "${p.agent.id}":`, err);
|
|
1082
1165
|
agentErrors[p.agent.id] = err instanceof Error ? err.message : String(err);
|
|
1083
|
-
|
|
1166
|
+
const failedAmount = p.planned;
|
|
1167
|
+
p.planned = 0n;
|
|
1168
|
+
redistributeShare(plans, i, failedAmount);
|
|
1084
1169
|
}
|
|
1085
1170
|
}
|
|
1086
1171
|
if (Object.keys(results).length === 0) {
|
package/dist/index.d.cts
CHANGED
|
@@ -211,6 +211,12 @@ interface OwneyAgentAllocation {
|
|
|
211
211
|
declare class OwneySDK {
|
|
212
212
|
private agents;
|
|
213
213
|
private activeAgents;
|
|
214
|
+
/**
|
|
215
|
+
* Agents whose routing flag is_enabled === false. They remain in
|
|
216
|
+
* `this.agents` and may still be added to `activeAgents` for read +
|
|
217
|
+
* withdraw, but they are excluded from new deposits / activations.
|
|
218
|
+
*/
|
|
219
|
+
private disabledAgents;
|
|
214
220
|
private state;
|
|
215
221
|
private apiKey;
|
|
216
222
|
private zyfaiRpcUrls?;
|
|
@@ -227,6 +233,7 @@ declare class OwneySDK {
|
|
|
227
233
|
* After calling this, `connect()` must be called again before using agent methods.
|
|
228
234
|
*/
|
|
229
235
|
disconnect(): Promise<void>;
|
|
236
|
+
private isAgentDisabled;
|
|
230
237
|
/**
|
|
231
238
|
* Check if the SDK has an active connection state.
|
|
232
239
|
* @returns `true` if `connect()` has been called and `disconnect()` has not
|
|
@@ -349,7 +356,7 @@ declare class OwneySDK {
|
|
|
349
356
|
getAgentAllocation(): Promise<OwneyAgentAllocation>;
|
|
350
357
|
}
|
|
351
358
|
|
|
352
|
-
type OwneyErrorCode = "NOT_CONNECTED" | "NO_ACTIVE_CHAIN" | "WALLET_NO_ACCOUNTS" | "WALLET_ADDRESS_REQUIRED" | "AGENT_NOT_FOUND" | "AGENT_CHAIN_INCOMPATIBLE" | "AGENT_EMPTY_LIST" | "CHAIN_UNSUPPORTED" | "CHAIN_NO_COMPATIBLE_AGENTS" | "ASSET_UNSUPPORTED" | "ASSET_NO_COMPATIBLE_AGENTS" | "DEPOSIT_AMOUNT_BELOW_MINIMUM" | "DEPOSIT_CALLBACK_REQUIRED" | "DEPOSIT_CALLBACK_INVALID" | "DEPOSIT_NO_PERMITTED_TOKENS" | "WITHDRAW_NO_PERMITTED_TOKENS" | "WITHDRAW_INSUFFICIENT_BALANCE" | "WITHDRAW_ALL_FAILED" | "WITHDRAW_PARTIAL_FAILURE" | "WITHDRAW_FAILED" | "API_ROUTING_ERROR" | "API_ROUTING_FAILED" | "API_SAIL_ERROR" | "API_SAIL_TIMEOUT" | "API_NO_AGENTS" | "BALANCE_ALL_FAILED" | "ALLOCATION_ALL_FAILED" | "VALIDATION_INVALID_DAYS";
|
|
359
|
+
type OwneyErrorCode = "NOT_CONNECTED" | "NO_ACTIVE_CHAIN" | "WALLET_NO_ACCOUNTS" | "WALLET_ADDRESS_REQUIRED" | "AGENT_NOT_FOUND" | "AGENT_CHAIN_INCOMPATIBLE" | "AGENT_EMPTY_LIST" | "AGENT_DISABLED" | "CHAIN_UNSUPPORTED" | "CHAIN_NO_COMPATIBLE_AGENTS" | "ASSET_UNSUPPORTED" | "ASSET_NO_COMPATIBLE_AGENTS" | "DEPOSIT_AMOUNT_BELOW_MINIMUM" | "DEPOSIT_CALLBACK_REQUIRED" | "DEPOSIT_CALLBACK_INVALID" | "DEPOSIT_NO_PERMITTED_TOKENS" | "WITHDRAW_NO_PERMITTED_TOKENS" | "WITHDRAW_INSUFFICIENT_BALANCE" | "WITHDRAW_ALL_FAILED" | "WITHDRAW_PARTIAL_FAILURE" | "WITHDRAW_FAILED" | "API_ROUTING_ERROR" | "API_ROUTING_FAILED" | "API_SAIL_ERROR" | "API_SAIL_TIMEOUT" | "API_NO_AGENTS" | "BALANCE_ALL_FAILED" | "ALLOCATION_ALL_FAILED" | "VALIDATION_INVALID_DAYS";
|
|
353
360
|
declare class OwneyError extends Error {
|
|
354
361
|
readonly code: OwneyErrorCode;
|
|
355
362
|
readonly details?: Record<string, unknown>;
|
package/dist/index.d.ts
CHANGED
|
@@ -211,6 +211,12 @@ interface OwneyAgentAllocation {
|
|
|
211
211
|
declare class OwneySDK {
|
|
212
212
|
private agents;
|
|
213
213
|
private activeAgents;
|
|
214
|
+
/**
|
|
215
|
+
* Agents whose routing flag is_enabled === false. They remain in
|
|
216
|
+
* `this.agents` and may still be added to `activeAgents` for read +
|
|
217
|
+
* withdraw, but they are excluded from new deposits / activations.
|
|
218
|
+
*/
|
|
219
|
+
private disabledAgents;
|
|
214
220
|
private state;
|
|
215
221
|
private apiKey;
|
|
216
222
|
private zyfaiRpcUrls?;
|
|
@@ -227,6 +233,7 @@ declare class OwneySDK {
|
|
|
227
233
|
* After calling this, `connect()` must be called again before using agent methods.
|
|
228
234
|
*/
|
|
229
235
|
disconnect(): Promise<void>;
|
|
236
|
+
private isAgentDisabled;
|
|
230
237
|
/**
|
|
231
238
|
* Check if the SDK has an active connection state.
|
|
232
239
|
* @returns `true` if `connect()` has been called and `disconnect()` has not
|
|
@@ -349,7 +356,7 @@ declare class OwneySDK {
|
|
|
349
356
|
getAgentAllocation(): Promise<OwneyAgentAllocation>;
|
|
350
357
|
}
|
|
351
358
|
|
|
352
|
-
type OwneyErrorCode = "NOT_CONNECTED" | "NO_ACTIVE_CHAIN" | "WALLET_NO_ACCOUNTS" | "WALLET_ADDRESS_REQUIRED" | "AGENT_NOT_FOUND" | "AGENT_CHAIN_INCOMPATIBLE" | "AGENT_EMPTY_LIST" | "CHAIN_UNSUPPORTED" | "CHAIN_NO_COMPATIBLE_AGENTS" | "ASSET_UNSUPPORTED" | "ASSET_NO_COMPATIBLE_AGENTS" | "DEPOSIT_AMOUNT_BELOW_MINIMUM" | "DEPOSIT_CALLBACK_REQUIRED" | "DEPOSIT_CALLBACK_INVALID" | "DEPOSIT_NO_PERMITTED_TOKENS" | "WITHDRAW_NO_PERMITTED_TOKENS" | "WITHDRAW_INSUFFICIENT_BALANCE" | "WITHDRAW_ALL_FAILED" | "WITHDRAW_PARTIAL_FAILURE" | "WITHDRAW_FAILED" | "API_ROUTING_ERROR" | "API_ROUTING_FAILED" | "API_SAIL_ERROR" | "API_SAIL_TIMEOUT" | "API_NO_AGENTS" | "BALANCE_ALL_FAILED" | "ALLOCATION_ALL_FAILED" | "VALIDATION_INVALID_DAYS";
|
|
359
|
+
type OwneyErrorCode = "NOT_CONNECTED" | "NO_ACTIVE_CHAIN" | "WALLET_NO_ACCOUNTS" | "WALLET_ADDRESS_REQUIRED" | "AGENT_NOT_FOUND" | "AGENT_CHAIN_INCOMPATIBLE" | "AGENT_EMPTY_LIST" | "AGENT_DISABLED" | "CHAIN_UNSUPPORTED" | "CHAIN_NO_COMPATIBLE_AGENTS" | "ASSET_UNSUPPORTED" | "ASSET_NO_COMPATIBLE_AGENTS" | "DEPOSIT_AMOUNT_BELOW_MINIMUM" | "DEPOSIT_CALLBACK_REQUIRED" | "DEPOSIT_CALLBACK_INVALID" | "DEPOSIT_NO_PERMITTED_TOKENS" | "WITHDRAW_NO_PERMITTED_TOKENS" | "WITHDRAW_INSUFFICIENT_BALANCE" | "WITHDRAW_ALL_FAILED" | "WITHDRAW_PARTIAL_FAILURE" | "WITHDRAW_FAILED" | "API_ROUTING_ERROR" | "API_ROUTING_FAILED" | "API_SAIL_ERROR" | "API_SAIL_TIMEOUT" | "API_NO_AGENTS" | "BALANCE_ALL_FAILED" | "ALLOCATION_ALL_FAILED" | "VALIDATION_INVALID_DAYS";
|
|
353
360
|
declare class OwneyError extends Error {
|
|
354
361
|
readonly code: OwneyErrorCode;
|
|
355
362
|
readonly details?: Record<string, unknown>;
|
package/dist/index.js
CHANGED
|
@@ -548,6 +548,19 @@ async function fetchAgentKeys(apiKey) {
|
|
|
548
548
|
}
|
|
549
549
|
|
|
550
550
|
// src/lib/helpers/withdraw-helper.ts
|
|
551
|
+
import { parseUnits } from "viem";
|
|
552
|
+
function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
|
|
553
|
+
const target = asset.toUpperCase();
|
|
554
|
+
return agents.map((agent) => {
|
|
555
|
+
const agentBalance = aggregated[agent.id];
|
|
556
|
+
const tokenBalance = agentBalance?.tokens.find(
|
|
557
|
+
(t) => t.chainId === chainId && t.asset.toUpperCase() === target
|
|
558
|
+
);
|
|
559
|
+
if (!tokenBalance)
|
|
560
|
+
return { agent, balance: 0n };
|
|
561
|
+
return { agent, balance: parseUnits(tokenBalance.amount, decimals) };
|
|
562
|
+
});
|
|
563
|
+
}
|
|
551
564
|
function planProportionalShares(balances, requested, totalAvailable) {
|
|
552
565
|
const plans = balances.map(({ agent, balance }) => ({
|
|
553
566
|
agent,
|
|
@@ -572,8 +585,24 @@ function planProportionalShares(balances, requested, totalAvailable) {
|
|
|
572
585
|
}
|
|
573
586
|
return plans;
|
|
574
587
|
}
|
|
575
|
-
function
|
|
576
|
-
const
|
|
588
|
+
function planDisabledDrain(disabled, requested) {
|
|
589
|
+
const sorted = [...disabled].filter((d) => d.balance > 0n).sort((a, b) => b.balance > a.balance ? 1 : b.balance < a.balance ? -1 : 0);
|
|
590
|
+
const plans = [];
|
|
591
|
+
let remaining = requested;
|
|
592
|
+
for (const { agent, balance } of sorted) {
|
|
593
|
+
if (remaining === 0n) {
|
|
594
|
+
plans.push({ agent, balance, planned: 0n });
|
|
595
|
+
continue;
|
|
596
|
+
}
|
|
597
|
+
const take = balance < remaining ? balance : remaining;
|
|
598
|
+
plans.push({ agent, balance, planned: take });
|
|
599
|
+
remaining -= take;
|
|
600
|
+
}
|
|
601
|
+
return { plans, remaining };
|
|
602
|
+
}
|
|
603
|
+
function redistributeShare(plans, fromIndex, amount, candidatePool) {
|
|
604
|
+
const pool = candidatePool ?? plans.slice(fromIndex + 1);
|
|
605
|
+
const candidates = pool.filter((c) => c.balance - c.planned > 0n);
|
|
577
606
|
const totalHeadroom = candidates.reduce(
|
|
578
607
|
(s, c) => s + (c.balance - c.planned),
|
|
579
608
|
0n
|
|
@@ -645,10 +674,15 @@ function aggregateApyByChainAndAsset(agentApys, agentBalances) {
|
|
|
645
674
|
}
|
|
646
675
|
|
|
647
676
|
// src/client.ts
|
|
648
|
-
import { parseUnits } from "viem";
|
|
649
677
|
var OwneySDK = class {
|
|
650
678
|
agents = /* @__PURE__ */ new Map();
|
|
651
679
|
activeAgents = /* @__PURE__ */ new Set();
|
|
680
|
+
/**
|
|
681
|
+
* Agents whose routing flag is_enabled === false. They remain in
|
|
682
|
+
* `this.agents` and may still be added to `activeAgents` for read +
|
|
683
|
+
* withdraw, but they are excluded from new deposits / activations.
|
|
684
|
+
*/
|
|
685
|
+
disabledAgents = /* @__PURE__ */ new Set();
|
|
652
686
|
state = null;
|
|
653
687
|
apiKey;
|
|
654
688
|
zyfaiRpcUrls;
|
|
@@ -685,8 +719,12 @@ var OwneySDK = class {
|
|
|
685
719
|
await agent.disconnect();
|
|
686
720
|
}
|
|
687
721
|
this.activeAgents.clear();
|
|
722
|
+
this.disabledAgents.clear();
|
|
688
723
|
this.state = null;
|
|
689
724
|
}
|
|
725
|
+
isAgentDisabled(agentId) {
|
|
726
|
+
return this.disabledAgents.has(agentId);
|
|
727
|
+
}
|
|
690
728
|
/**
|
|
691
729
|
* Check if the SDK has an active connection state.
|
|
692
730
|
* @returns `true` if `connect()` has been called and `disconnect()` has not
|
|
@@ -738,11 +776,15 @@ var OwneySDK = class {
|
|
|
738
776
|
if (!this.initializingAgentsPromise) {
|
|
739
777
|
this.initializingAgentsPromise = (async () => {
|
|
740
778
|
const agentKeys = await fetchAgentKeys(this.apiKey);
|
|
741
|
-
|
|
779
|
+
this.disabledAgents.clear();
|
|
780
|
+
for (const { key, agent_type, is_enabled } of agentKeys) {
|
|
742
781
|
const agent = this.createAgent(agent_type, key);
|
|
743
782
|
if (!agent)
|
|
744
783
|
continue;
|
|
745
784
|
this.agents.set(agent_type, agent);
|
|
785
|
+
if (is_enabled === false) {
|
|
786
|
+
this.disabledAgents.add(agent_type);
|
|
787
|
+
}
|
|
746
788
|
}
|
|
747
789
|
if (this.agents.size === 0) {
|
|
748
790
|
throw new OwneyError(
|
|
@@ -787,6 +829,16 @@ var OwneySDK = class {
|
|
|
787
829
|
}
|
|
788
830
|
const uniqueIds = [...new Set(agentId)];
|
|
789
831
|
const agents = uniqueIds.map((id) => this.getAgent(id));
|
|
832
|
+
const disabledRequested = uniqueIds.filter(
|
|
833
|
+
(id) => this.isAgentDisabled(id)
|
|
834
|
+
);
|
|
835
|
+
if (disabledRequested.length > 0) {
|
|
836
|
+
throw new OwneyError(
|
|
837
|
+
"AGENT_DISABLED",
|
|
838
|
+
`Cannot activate disabled agent(s): ${disabledRequested.join(", ")}.`,
|
|
839
|
+
{ agentIds: disabledRequested }
|
|
840
|
+
);
|
|
841
|
+
}
|
|
790
842
|
const incompatibleAgents = agents.filter(
|
|
791
843
|
(agent) => !agent.supportedChainIds.includes(chainId)
|
|
792
844
|
).map((agent) => ({
|
|
@@ -825,8 +877,11 @@ var OwneySDK = class {
|
|
|
825
877
|
this.activeAgents.add(agent.id);
|
|
826
878
|
}
|
|
827
879
|
state.chainId = chainId;
|
|
880
|
+
const enabledCompatible = compatible.filter(
|
|
881
|
+
(agent) => !this.isAgentDisabled(agent.id)
|
|
882
|
+
);
|
|
828
883
|
Promise.all(
|
|
829
|
-
|
|
884
|
+
enabledCompatible.map(async (agent) => {
|
|
830
885
|
await agent.activateAgent(state, chainId);
|
|
831
886
|
})
|
|
832
887
|
).catch((error) => {
|
|
@@ -853,13 +908,22 @@ var OwneySDK = class {
|
|
|
853
908
|
const state = this.requireState();
|
|
854
909
|
const chainId = this.requireChainId();
|
|
855
910
|
if (agentId) {
|
|
911
|
+
if (this.isAgentDisabled(agentId)) {
|
|
912
|
+
throw new OwneyError(
|
|
913
|
+
"AGENT_DISABLED",
|
|
914
|
+
`Cannot deposit into disabled agent "${agentId}". Existing balances remain visible and withdrawable.`,
|
|
915
|
+
{ agentId }
|
|
916
|
+
);
|
|
917
|
+
}
|
|
856
918
|
const agent = this.getAgent(agentId);
|
|
857
919
|
this.validateAssetSupport(agent, chainId, asset);
|
|
858
920
|
this.validateMinDepositAmount(agent, chainId, asset, amount);
|
|
859
921
|
return agent.deposit(state, chainId, amount, depositCallback);
|
|
860
922
|
}
|
|
861
923
|
const totalAmount = BigInt(amount);
|
|
862
|
-
const eligibleAgents = this.getEligibleAgents(chainId, asset
|
|
924
|
+
const eligibleAgents = this.getEligibleAgents(chainId, asset, {
|
|
925
|
+
excludeDisabled: true
|
|
926
|
+
});
|
|
863
927
|
const agentAmounts = this.splitDepositAmount(
|
|
864
928
|
totalAmount,
|
|
865
929
|
eligibleAgents,
|
|
@@ -943,8 +1007,11 @@ var OwneySDK = class {
|
|
|
943
1007
|
);
|
|
944
1008
|
}
|
|
945
1009
|
}
|
|
946
|
-
getEligibleAgents(chainId, asset) {
|
|
1010
|
+
getEligibleAgents(chainId, asset, opts) {
|
|
947
1011
|
const eligible = [...this.agents.values()].filter((agent) => {
|
|
1012
|
+
if (opts?.excludeDisabled && this.isAgentDisabled(agent.id)) {
|
|
1013
|
+
return false;
|
|
1014
|
+
}
|
|
948
1015
|
const chainAssets = agent.supportedAssets.find(
|
|
949
1016
|
(sa) => sa.chainId === chainId
|
|
950
1017
|
);
|
|
@@ -1011,16 +1078,13 @@ var OwneySDK = class {
|
|
|
1011
1078
|
}
|
|
1012
1079
|
const requested = BigInt(amount);
|
|
1013
1080
|
const aggregated = await this.getBalances();
|
|
1014
|
-
const balances =
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
const balance = parseUnits(tokenBalance.amount, assetInfo.decimals);
|
|
1022
|
-
return { agent, balance };
|
|
1023
|
-
});
|
|
1081
|
+
const balances = projectAgentBalancesForAsset(
|
|
1082
|
+
eligibleAgents,
|
|
1083
|
+
aggregated.agentBalances,
|
|
1084
|
+
chainId,
|
|
1085
|
+
asset,
|
|
1086
|
+
assetInfo.decimals
|
|
1087
|
+
);
|
|
1024
1088
|
const totalAvailable = balances.reduce((sum, x) => sum + x.balance, 0n);
|
|
1025
1089
|
if (totalAvailable < requested) {
|
|
1026
1090
|
throw new OwneyError(
|
|
@@ -1033,7 +1097,26 @@ var OwneySDK = class {
|
|
|
1033
1097
|
}
|
|
1034
1098
|
);
|
|
1035
1099
|
}
|
|
1036
|
-
const
|
|
1100
|
+
const disabledBalances = balances.filter(
|
|
1101
|
+
(b) => this.isAgentDisabled(b.agent.id)
|
|
1102
|
+
);
|
|
1103
|
+
const enabledBalances = balances.filter(
|
|
1104
|
+
(b) => !this.isAgentDisabled(b.agent.id)
|
|
1105
|
+
);
|
|
1106
|
+
const { plans: disabledPlans, remaining: afterDrain } = planDisabledDrain(
|
|
1107
|
+
disabledBalances,
|
|
1108
|
+
requested
|
|
1109
|
+
);
|
|
1110
|
+
const enabledTotal = enabledBalances.reduce(
|
|
1111
|
+
(s, b) => s + b.balance,
|
|
1112
|
+
0n
|
|
1113
|
+
);
|
|
1114
|
+
const enabledPlans = afterDrain > 0n ? planProportionalShares(enabledBalances, afterDrain, enabledTotal) : enabledBalances.map(({ agent, balance }) => ({
|
|
1115
|
+
agent,
|
|
1116
|
+
balance,
|
|
1117
|
+
planned: 0n
|
|
1118
|
+
}));
|
|
1119
|
+
const plans = [...disabledPlans, ...enabledPlans];
|
|
1037
1120
|
const results = {};
|
|
1038
1121
|
const agentErrors = {};
|
|
1039
1122
|
for (let i = 0; i < plans.length; i++) {
|
|
@@ -1050,7 +1133,9 @@ var OwneySDK = class {
|
|
|
1050
1133
|
} catch (err) {
|
|
1051
1134
|
console.error(`withdraw failed for agent "${p.agent.id}":`, err);
|
|
1052
1135
|
agentErrors[p.agent.id] = err instanceof Error ? err.message : String(err);
|
|
1053
|
-
|
|
1136
|
+
const failedAmount = p.planned;
|
|
1137
|
+
p.planned = 0n;
|
|
1138
|
+
redistributeShare(plans, i, failedAmount);
|
|
1054
1139
|
}
|
|
1055
1140
|
}
|
|
1056
1141
|
if (Object.keys(results).length === 0) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owney/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -17,7 +17,9 @@
|
|
|
17
17
|
],
|
|
18
18
|
"scripts": {
|
|
19
19
|
"build": "tsup",
|
|
20
|
-
"dev": "tsup --watch"
|
|
20
|
+
"dev": "tsup --watch",
|
|
21
|
+
"test": "vitest run",
|
|
22
|
+
"test:watch": "vitest"
|
|
21
23
|
},
|
|
22
24
|
"dependencies": {
|
|
23
25
|
"@zyfai/sdk": "^0.2.34",
|
|
@@ -26,7 +28,8 @@
|
|
|
26
28
|
"devDependencies": {
|
|
27
29
|
"dotenv": "^17.3.1",
|
|
28
30
|
"tsup": "^7.0.0",
|
|
29
|
-
"typescript": "^5.0.0"
|
|
31
|
+
"typescript": "^5.0.0",
|
|
32
|
+
"vitest": "^4.1.5"
|
|
30
33
|
},
|
|
31
34
|
"publishConfig": {
|
|
32
35
|
"access": "public"
|