@owney/sdk 0.2.17 → 0.3.0-beta.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 CHANGED
@@ -556,6 +556,19 @@ async function fetchAgentKeys(apiKey) {
556
556
  }
557
557
 
558
558
  // src/lib/helpers/withdraw-helper.ts
559
+ var import_viem = require("viem");
560
+ function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
561
+ const target = asset.toUpperCase();
562
+ return agents.map((agent) => {
563
+ const agentBalance = aggregated[agent.id];
564
+ const tokenBalance = agentBalance?.tokens.find(
565
+ (t) => t.chainId === chainId && t.asset.toUpperCase() === target
566
+ );
567
+ if (!tokenBalance)
568
+ return { agent, balance: 0n };
569
+ return { agent, balance: (0, import_viem.parseUnits)(tokenBalance.amount, decimals) };
570
+ });
571
+ }
559
572
  function planProportionalShares(balances, requested, totalAvailable) {
560
573
  const plans = balances.map(({ agent, balance }) => ({
561
574
  agent,
@@ -580,8 +593,24 @@ function planProportionalShares(balances, requested, totalAvailable) {
580
593
  }
581
594
  return plans;
582
595
  }
583
- function redistributeShare(plans, fromIndex, amount) {
584
- const candidates = plans.slice(fromIndex + 1).filter((c) => c.balance - c.planned > 0n);
596
+ function planDisabledDrain(disabled, requested) {
597
+ const sorted = [...disabled].filter((d) => d.balance > 0n).sort((a, b) => b.balance > a.balance ? 1 : b.balance < a.balance ? -1 : 0);
598
+ const plans = [];
599
+ let remaining = requested;
600
+ for (const { agent, balance } of sorted) {
601
+ if (remaining === 0n) {
602
+ plans.push({ agent, balance, planned: 0n });
603
+ continue;
604
+ }
605
+ const take = balance < remaining ? balance : remaining;
606
+ plans.push({ agent, balance, planned: take });
607
+ remaining -= take;
608
+ }
609
+ return { plans, remaining };
610
+ }
611
+ function redistributeShare(plans, fromIndex, amount, candidatePool) {
612
+ const pool = candidatePool ?? plans.slice(fromIndex + 1);
613
+ const candidates = pool.filter((c) => c.balance - c.planned > 0n);
585
614
  const totalHeadroom = candidates.reduce(
586
615
  (s, c) => s + (c.balance - c.planned),
587
616
  0n
@@ -613,10 +642,15 @@ function sumWithdrawnAmount(results) {
613
642
  }
614
643
 
615
644
  // src/client.ts
616
- var import_viem = require("viem");
617
645
  var OwneySDK = class {
618
646
  agents = /* @__PURE__ */ new Map();
619
647
  activeAgents = /* @__PURE__ */ new Set();
648
+ /**
649
+ * Agents whose routing flag is_enabled === false. They remain in
650
+ * `this.agents` and may still be added to `activeAgents` for read +
651
+ * withdraw, but they are excluded from new deposits / activations.
652
+ */
653
+ disabledAgents = /* @__PURE__ */ new Set();
620
654
  state = null;
621
655
  apiKey;
622
656
  zyfaiRpcUrls;
@@ -653,8 +687,12 @@ var OwneySDK = class {
653
687
  await agent.disconnect();
654
688
  }
655
689
  this.activeAgents.clear();
690
+ this.disabledAgents.clear();
656
691
  this.state = null;
657
692
  }
693
+ isAgentDisabled(agentId) {
694
+ return this.disabledAgents.has(agentId);
695
+ }
658
696
  /**
659
697
  * Check if the SDK has an active connection state.
660
698
  * @returns `true` if `connect()` has been called and `disconnect()` has not
@@ -706,11 +744,15 @@ var OwneySDK = class {
706
744
  if (!this.initializingAgentsPromise) {
707
745
  this.initializingAgentsPromise = (async () => {
708
746
  const agentKeys = await fetchAgentKeys(this.apiKey);
709
- for (const { key, agent_type } of agentKeys) {
747
+ this.disabledAgents.clear();
748
+ for (const { key, agent_type, is_enabled } of agentKeys) {
710
749
  const agent = this.createAgent(agent_type, key);
711
750
  if (!agent)
712
751
  continue;
713
752
  this.agents.set(agent_type, agent);
753
+ if (is_enabled === false) {
754
+ this.disabledAgents.add(agent_type);
755
+ }
714
756
  }
715
757
  if (this.agents.size === 0) {
716
758
  throw new OwneyError(
@@ -755,6 +797,16 @@ var OwneySDK = class {
755
797
  }
756
798
  const uniqueIds = [...new Set(agentId)];
757
799
  const agents = uniqueIds.map((id) => this.getAgent(id));
800
+ const disabledRequested = uniqueIds.filter(
801
+ (id) => this.isAgentDisabled(id)
802
+ );
803
+ if (disabledRequested.length > 0) {
804
+ throw new OwneyError(
805
+ "AGENT_DISABLED",
806
+ `Cannot activate disabled agent(s): ${disabledRequested.join(", ")}.`,
807
+ { agentIds: disabledRequested }
808
+ );
809
+ }
758
810
  const incompatibleAgents = agents.filter(
759
811
  (agent) => !agent.supportedChainIds.includes(chainId)
760
812
  ).map((agent) => ({
@@ -793,8 +845,11 @@ var OwneySDK = class {
793
845
  this.activeAgents.add(agent.id);
794
846
  }
795
847
  state.chainId = chainId;
848
+ const enabledCompatible = compatible.filter(
849
+ (agent) => !this.isAgentDisabled(agent.id)
850
+ );
796
851
  Promise.all(
797
- compatible.map(async (agent) => {
852
+ enabledCompatible.map(async (agent) => {
798
853
  await agent.activateAgent(state, chainId);
799
854
  })
800
855
  ).catch((error) => {
@@ -821,13 +876,22 @@ var OwneySDK = class {
821
876
  const state = this.requireState();
822
877
  const chainId = this.requireChainId();
823
878
  if (agentId) {
879
+ if (this.isAgentDisabled(agentId)) {
880
+ throw new OwneyError(
881
+ "AGENT_DISABLED",
882
+ `Cannot deposit into disabled agent "${agentId}". Existing balances remain visible and withdrawable.`,
883
+ { agentId }
884
+ );
885
+ }
824
886
  const agent = this.getAgent(agentId);
825
887
  this.validateAssetSupport(agent, chainId, asset);
826
888
  this.validateMinDepositAmount(agent, chainId, asset, amount);
827
889
  return agent.deposit(state, chainId, amount, depositCallback);
828
890
  }
829
891
  const totalAmount = BigInt(amount);
830
- const eligibleAgents = this.getEligibleAgents(chainId, asset);
892
+ const eligibleAgents = this.getEligibleAgents(chainId, asset, {
893
+ excludeDisabled: true
894
+ });
831
895
  const agentAmounts = this.splitDepositAmount(
832
896
  totalAmount,
833
897
  eligibleAgents,
@@ -911,8 +975,11 @@ var OwneySDK = class {
911
975
  );
912
976
  }
913
977
  }
914
- getEligibleAgents(chainId, asset) {
978
+ getEligibleAgents(chainId, asset, opts) {
915
979
  const eligible = [...this.agents.values()].filter((agent) => {
980
+ if (opts?.excludeDisabled && this.isAgentDisabled(agent.id)) {
981
+ return false;
982
+ }
916
983
  const chainAssets = agent.supportedAssets.find(
917
984
  (sa) => sa.chainId === chainId
918
985
  );
@@ -979,16 +1046,13 @@ var OwneySDK = class {
979
1046
  }
980
1047
  const requested = BigInt(amount);
981
1048
  const aggregated = await this.getBalances();
982
- const balances = eligibleAgents.map((agent) => {
983
- const agentBalance = aggregated.agentBalances[agent.id];
984
- const tokenBalance = agentBalance?.tokens.find(
985
- (t) => t.chainId === chainId && t.asset.toUpperCase() === asset.toUpperCase()
986
- );
987
- if (!tokenBalance)
988
- return { agent, balance: 0n };
989
- const balance = (0, import_viem.parseUnits)(tokenBalance.amount, assetInfo.decimals);
990
- return { agent, balance };
991
- });
1049
+ const balances = projectAgentBalancesForAsset(
1050
+ eligibleAgents,
1051
+ aggregated.agentBalances,
1052
+ chainId,
1053
+ asset,
1054
+ assetInfo.decimals
1055
+ );
992
1056
  const totalAvailable = balances.reduce((sum, x) => sum + x.balance, 0n);
993
1057
  if (totalAvailable < requested) {
994
1058
  throw new OwneyError(
@@ -1001,7 +1065,26 @@ var OwneySDK = class {
1001
1065
  }
1002
1066
  );
1003
1067
  }
1004
- const plans = planProportionalShares(balances, requested, totalAvailable);
1068
+ const disabledBalances = balances.filter(
1069
+ (b) => this.isAgentDisabled(b.agent.id)
1070
+ );
1071
+ const enabledBalances = balances.filter(
1072
+ (b) => !this.isAgentDisabled(b.agent.id)
1073
+ );
1074
+ const { plans: disabledPlans, remaining: afterDrain } = planDisabledDrain(
1075
+ disabledBalances,
1076
+ requested
1077
+ );
1078
+ const enabledTotal = enabledBalances.reduce(
1079
+ (s, b) => s + b.balance,
1080
+ 0n
1081
+ );
1082
+ const enabledPlans = afterDrain > 0n ? planProportionalShares(enabledBalances, afterDrain, enabledTotal) : enabledBalances.map(({ agent, balance }) => ({
1083
+ agent,
1084
+ balance,
1085
+ planned: 0n
1086
+ }));
1087
+ const plans = [...disabledPlans, ...enabledPlans];
1005
1088
  const results = {};
1006
1089
  const agentErrors = {};
1007
1090
  for (let i = 0; i < plans.length; i++) {
@@ -1018,7 +1101,9 @@ var OwneySDK = class {
1018
1101
  } catch (err) {
1019
1102
  console.error(`withdraw failed for agent "${p.agent.id}":`, err);
1020
1103
  agentErrors[p.agent.id] = err instanceof Error ? err.message : String(err);
1021
- redistributeShare(plans, i, p.planned);
1104
+ const failedAmount = p.planned;
1105
+ p.planned = 0n;
1106
+ redistributeShare(plans, i, failedAmount);
1022
1107
  }
1023
1108
  }
1024
1109
  if (Object.keys(results).length === 0) {
package/dist/index.d.cts CHANGED
@@ -208,6 +208,12 @@ interface OwneyAgentAllocation {
208
208
  declare class OwneySDK {
209
209
  private agents;
210
210
  private activeAgents;
211
+ /**
212
+ * Agents whose routing flag is_enabled === false. They remain in
213
+ * `this.agents` and may still be added to `activeAgents` for read +
214
+ * withdraw, but they are excluded from new deposits / activations.
215
+ */
216
+ private disabledAgents;
211
217
  private state;
212
218
  private apiKey;
213
219
  private zyfaiRpcUrls?;
@@ -224,6 +230,7 @@ declare class OwneySDK {
224
230
  * After calling this, `connect()` must be called again before using agent methods.
225
231
  */
226
232
  disconnect(): Promise<void>;
233
+ private isAgentDisabled;
227
234
  /**
228
235
  * Check if the SDK has an active connection state.
229
236
  * @returns `true` if `connect()` has been called and `disconnect()` has not
@@ -346,7 +353,7 @@ declare class OwneySDK {
346
353
  getAgentAllocation(): Promise<OwneyAgentAllocation>;
347
354
  }
348
355
 
349
- 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";
356
+ 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";
350
357
  declare class OwneyError extends Error {
351
358
  readonly code: OwneyErrorCode;
352
359
  readonly details?: Record<string, unknown>;
package/dist/index.d.ts CHANGED
@@ -208,6 +208,12 @@ interface OwneyAgentAllocation {
208
208
  declare class OwneySDK {
209
209
  private agents;
210
210
  private activeAgents;
211
+ /**
212
+ * Agents whose routing flag is_enabled === false. They remain in
213
+ * `this.agents` and may still be added to `activeAgents` for read +
214
+ * withdraw, but they are excluded from new deposits / activations.
215
+ */
216
+ private disabledAgents;
211
217
  private state;
212
218
  private apiKey;
213
219
  private zyfaiRpcUrls?;
@@ -224,6 +230,7 @@ declare class OwneySDK {
224
230
  * After calling this, `connect()` must be called again before using agent methods.
225
231
  */
226
232
  disconnect(): Promise<void>;
233
+ private isAgentDisabled;
227
234
  /**
228
235
  * Check if the SDK has an active connection state.
229
236
  * @returns `true` if `connect()` has been called and `disconnect()` has not
@@ -346,7 +353,7 @@ declare class OwneySDK {
346
353
  getAgentAllocation(): Promise<OwneyAgentAllocation>;
347
354
  }
348
355
 
349
- 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";
356
+ 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";
350
357
  declare class OwneyError extends Error {
351
358
  readonly code: OwneyErrorCode;
352
359
  readonly details?: Record<string, unknown>;
package/dist/index.js CHANGED
@@ -526,6 +526,19 @@ async function fetchAgentKeys(apiKey) {
526
526
  }
527
527
 
528
528
  // src/lib/helpers/withdraw-helper.ts
529
+ import { parseUnits } from "viem";
530
+ function projectAgentBalancesForAsset(agents, aggregated, chainId, asset, decimals) {
531
+ const target = asset.toUpperCase();
532
+ return agents.map((agent) => {
533
+ const agentBalance = aggregated[agent.id];
534
+ const tokenBalance = agentBalance?.tokens.find(
535
+ (t) => t.chainId === chainId && t.asset.toUpperCase() === target
536
+ );
537
+ if (!tokenBalance)
538
+ return { agent, balance: 0n };
539
+ return { agent, balance: parseUnits(tokenBalance.amount, decimals) };
540
+ });
541
+ }
529
542
  function planProportionalShares(balances, requested, totalAvailable) {
530
543
  const plans = balances.map(({ agent, balance }) => ({
531
544
  agent,
@@ -550,8 +563,24 @@ function planProportionalShares(balances, requested, totalAvailable) {
550
563
  }
551
564
  return plans;
552
565
  }
553
- function redistributeShare(plans, fromIndex, amount) {
554
- const candidates = plans.slice(fromIndex + 1).filter((c) => c.balance - c.planned > 0n);
566
+ function planDisabledDrain(disabled, requested) {
567
+ const sorted = [...disabled].filter((d) => d.balance > 0n).sort((a, b) => b.balance > a.balance ? 1 : b.balance < a.balance ? -1 : 0);
568
+ const plans = [];
569
+ let remaining = requested;
570
+ for (const { agent, balance } of sorted) {
571
+ if (remaining === 0n) {
572
+ plans.push({ agent, balance, planned: 0n });
573
+ continue;
574
+ }
575
+ const take = balance < remaining ? balance : remaining;
576
+ plans.push({ agent, balance, planned: take });
577
+ remaining -= take;
578
+ }
579
+ return { plans, remaining };
580
+ }
581
+ function redistributeShare(plans, fromIndex, amount, candidatePool) {
582
+ const pool = candidatePool ?? plans.slice(fromIndex + 1);
583
+ const candidates = pool.filter((c) => c.balance - c.planned > 0n);
555
584
  const totalHeadroom = candidates.reduce(
556
585
  (s, c) => s + (c.balance - c.planned),
557
586
  0n
@@ -583,10 +612,15 @@ function sumWithdrawnAmount(results) {
583
612
  }
584
613
 
585
614
  // src/client.ts
586
- import { parseUnits } from "viem";
587
615
  var OwneySDK = class {
588
616
  agents = /* @__PURE__ */ new Map();
589
617
  activeAgents = /* @__PURE__ */ new Set();
618
+ /**
619
+ * Agents whose routing flag is_enabled === false. They remain in
620
+ * `this.agents` and may still be added to `activeAgents` for read +
621
+ * withdraw, but they are excluded from new deposits / activations.
622
+ */
623
+ disabledAgents = /* @__PURE__ */ new Set();
590
624
  state = null;
591
625
  apiKey;
592
626
  zyfaiRpcUrls;
@@ -623,8 +657,12 @@ var OwneySDK = class {
623
657
  await agent.disconnect();
624
658
  }
625
659
  this.activeAgents.clear();
660
+ this.disabledAgents.clear();
626
661
  this.state = null;
627
662
  }
663
+ isAgentDisabled(agentId) {
664
+ return this.disabledAgents.has(agentId);
665
+ }
628
666
  /**
629
667
  * Check if the SDK has an active connection state.
630
668
  * @returns `true` if `connect()` has been called and `disconnect()` has not
@@ -676,11 +714,15 @@ var OwneySDK = class {
676
714
  if (!this.initializingAgentsPromise) {
677
715
  this.initializingAgentsPromise = (async () => {
678
716
  const agentKeys = await fetchAgentKeys(this.apiKey);
679
- for (const { key, agent_type } of agentKeys) {
717
+ this.disabledAgents.clear();
718
+ for (const { key, agent_type, is_enabled } of agentKeys) {
680
719
  const agent = this.createAgent(agent_type, key);
681
720
  if (!agent)
682
721
  continue;
683
722
  this.agents.set(agent_type, agent);
723
+ if (is_enabled === false) {
724
+ this.disabledAgents.add(agent_type);
725
+ }
684
726
  }
685
727
  if (this.agents.size === 0) {
686
728
  throw new OwneyError(
@@ -725,6 +767,16 @@ var OwneySDK = class {
725
767
  }
726
768
  const uniqueIds = [...new Set(agentId)];
727
769
  const agents = uniqueIds.map((id) => this.getAgent(id));
770
+ const disabledRequested = uniqueIds.filter(
771
+ (id) => this.isAgentDisabled(id)
772
+ );
773
+ if (disabledRequested.length > 0) {
774
+ throw new OwneyError(
775
+ "AGENT_DISABLED",
776
+ `Cannot activate disabled agent(s): ${disabledRequested.join(", ")}.`,
777
+ { agentIds: disabledRequested }
778
+ );
779
+ }
728
780
  const incompatibleAgents = agents.filter(
729
781
  (agent) => !agent.supportedChainIds.includes(chainId)
730
782
  ).map((agent) => ({
@@ -763,8 +815,11 @@ var OwneySDK = class {
763
815
  this.activeAgents.add(agent.id);
764
816
  }
765
817
  state.chainId = chainId;
818
+ const enabledCompatible = compatible.filter(
819
+ (agent) => !this.isAgentDisabled(agent.id)
820
+ );
766
821
  Promise.all(
767
- compatible.map(async (agent) => {
822
+ enabledCompatible.map(async (agent) => {
768
823
  await agent.activateAgent(state, chainId);
769
824
  })
770
825
  ).catch((error) => {
@@ -791,13 +846,22 @@ var OwneySDK = class {
791
846
  const state = this.requireState();
792
847
  const chainId = this.requireChainId();
793
848
  if (agentId) {
849
+ if (this.isAgentDisabled(agentId)) {
850
+ throw new OwneyError(
851
+ "AGENT_DISABLED",
852
+ `Cannot deposit into disabled agent "${agentId}". Existing balances remain visible and withdrawable.`,
853
+ { agentId }
854
+ );
855
+ }
794
856
  const agent = this.getAgent(agentId);
795
857
  this.validateAssetSupport(agent, chainId, asset);
796
858
  this.validateMinDepositAmount(agent, chainId, asset, amount);
797
859
  return agent.deposit(state, chainId, amount, depositCallback);
798
860
  }
799
861
  const totalAmount = BigInt(amount);
800
- const eligibleAgents = this.getEligibleAgents(chainId, asset);
862
+ const eligibleAgents = this.getEligibleAgents(chainId, asset, {
863
+ excludeDisabled: true
864
+ });
801
865
  const agentAmounts = this.splitDepositAmount(
802
866
  totalAmount,
803
867
  eligibleAgents,
@@ -881,8 +945,11 @@ var OwneySDK = class {
881
945
  );
882
946
  }
883
947
  }
884
- getEligibleAgents(chainId, asset) {
948
+ getEligibleAgents(chainId, asset, opts) {
885
949
  const eligible = [...this.agents.values()].filter((agent) => {
950
+ if (opts?.excludeDisabled && this.isAgentDisabled(agent.id)) {
951
+ return false;
952
+ }
886
953
  const chainAssets = agent.supportedAssets.find(
887
954
  (sa) => sa.chainId === chainId
888
955
  );
@@ -949,16 +1016,13 @@ var OwneySDK = class {
949
1016
  }
950
1017
  const requested = BigInt(amount);
951
1018
  const aggregated = await this.getBalances();
952
- const balances = eligibleAgents.map((agent) => {
953
- const agentBalance = aggregated.agentBalances[agent.id];
954
- const tokenBalance = agentBalance?.tokens.find(
955
- (t) => t.chainId === chainId && t.asset.toUpperCase() === asset.toUpperCase()
956
- );
957
- if (!tokenBalance)
958
- return { agent, balance: 0n };
959
- const balance = parseUnits(tokenBalance.amount, assetInfo.decimals);
960
- return { agent, balance };
961
- });
1019
+ const balances = projectAgentBalancesForAsset(
1020
+ eligibleAgents,
1021
+ aggregated.agentBalances,
1022
+ chainId,
1023
+ asset,
1024
+ assetInfo.decimals
1025
+ );
962
1026
  const totalAvailable = balances.reduce((sum, x) => sum + x.balance, 0n);
963
1027
  if (totalAvailable < requested) {
964
1028
  throw new OwneyError(
@@ -971,7 +1035,26 @@ var OwneySDK = class {
971
1035
  }
972
1036
  );
973
1037
  }
974
- const plans = planProportionalShares(balances, requested, totalAvailable);
1038
+ const disabledBalances = balances.filter(
1039
+ (b) => this.isAgentDisabled(b.agent.id)
1040
+ );
1041
+ const enabledBalances = balances.filter(
1042
+ (b) => !this.isAgentDisabled(b.agent.id)
1043
+ );
1044
+ const { plans: disabledPlans, remaining: afterDrain } = planDisabledDrain(
1045
+ disabledBalances,
1046
+ requested
1047
+ );
1048
+ const enabledTotal = enabledBalances.reduce(
1049
+ (s, b) => s + b.balance,
1050
+ 0n
1051
+ );
1052
+ const enabledPlans = afterDrain > 0n ? planProportionalShares(enabledBalances, afterDrain, enabledTotal) : enabledBalances.map(({ agent, balance }) => ({
1053
+ agent,
1054
+ balance,
1055
+ planned: 0n
1056
+ }));
1057
+ const plans = [...disabledPlans, ...enabledPlans];
975
1058
  const results = {};
976
1059
  const agentErrors = {};
977
1060
  for (let i = 0; i < plans.length; i++) {
@@ -988,7 +1071,9 @@ var OwneySDK = class {
988
1071
  } catch (err) {
989
1072
  console.error(`withdraw failed for agent "${p.agent.id}":`, err);
990
1073
  agentErrors[p.agent.id] = err instanceof Error ? err.message : String(err);
991
- redistributeShare(plans, i, p.planned);
1074
+ const failedAmount = p.planned;
1075
+ p.planned = 0n;
1076
+ redistributeShare(plans, i, failedAmount);
992
1077
  }
993
1078
  }
994
1079
  if (Object.keys(results).length === 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owney/sdk",
3
- "version": "0.2.17",
3
+ "version": "0.3.0-beta.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",
@@ -17,16 +17,19 @@
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
- "@zyfai/sdk": "^0.2.34",
25
+ "@zyfai/sdk": "^0.2.33",
24
26
  "viem": "^2.48.1"
25
27
  },
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"