curvance 5.1.9 → 5.2.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.
Files changed (109) hide show
  1. package/README.md +249 -65
  2. package/dist/abis/OptimizerReader.json +292 -1
  3. package/dist/chains/arbitrum.d.ts.map +1 -1
  4. package/dist/chains/arbitrum.js +14 -1
  5. package/dist/chains/arbitrum.js.map +1 -1
  6. package/dist/chains/index.d.ts +19 -0
  7. package/dist/chains/index.d.ts.map +1 -1
  8. package/dist/chains/index.js.map +1 -1
  9. package/dist/chains/monad.d.ts.map +1 -1
  10. package/dist/chains/monad.js +25 -2
  11. package/dist/chains/monad.js.map +1 -1
  12. package/dist/chains/services.d.ts +8 -0
  13. package/dist/chains/services.d.ts.map +1 -0
  14. package/dist/chains/services.js +9 -0
  15. package/dist/chains/services.js.map +1 -0
  16. package/dist/classes/Api.d.ts +7 -2
  17. package/dist/classes/Api.d.ts.map +1 -1
  18. package/dist/classes/Api.js +60 -24
  19. package/dist/classes/Api.js.map +1 -1
  20. package/dist/classes/BorrowableCToken.d.ts.map +1 -1
  21. package/dist/classes/BorrowableCToken.js +7 -2
  22. package/dist/classes/BorrowableCToken.js.map +1 -1
  23. package/dist/classes/CToken.d.ts +28 -15
  24. package/dist/classes/CToken.d.ts.map +1 -1
  25. package/dist/classes/CToken.js +217 -85
  26. package/dist/classes/CToken.js.map +1 -1
  27. package/dist/classes/DexAggregators/IDexAgg.d.ts +8 -0
  28. package/dist/classes/DexAggregators/IDexAgg.d.ts.map +1 -1
  29. package/dist/classes/DexAggregators/KyberSwap.d.ts +5 -2
  30. package/dist/classes/DexAggregators/KyberSwap.d.ts.map +1 -1
  31. package/dist/classes/DexAggregators/KyberSwap.js +41 -19
  32. package/dist/classes/DexAggregators/KyberSwap.js.map +1 -1
  33. package/dist/classes/DexAggregators/MultiDexAgg.d.ts +7 -4
  34. package/dist/classes/DexAggregators/MultiDexAgg.d.ts.map +1 -1
  35. package/dist/classes/DexAggregators/MultiDexAgg.js +62 -16
  36. package/dist/classes/DexAggregators/MultiDexAgg.js.map +1 -1
  37. package/dist/classes/DexAggregators/helpers.d.ts +1 -1
  38. package/dist/classes/DexAggregators/helpers.d.ts.map +1 -1
  39. package/dist/classes/DexAggregators/helpers.js +1 -1
  40. package/dist/classes/DexAggregators/helpers.js.map +1 -1
  41. package/dist/classes/DexAggregators/index.d.ts +0 -1
  42. package/dist/classes/DexAggregators/index.d.ts.map +1 -1
  43. package/dist/classes/DexAggregators/index.js +0 -1
  44. package/dist/classes/DexAggregators/index.js.map +1 -1
  45. package/dist/classes/LendingOptimizer.d.ts.map +1 -1
  46. package/dist/classes/LendingOptimizer.js +8 -2
  47. package/dist/classes/LendingOptimizer.js.map +1 -1
  48. package/dist/classes/Market.d.ts +5 -0
  49. package/dist/classes/Market.d.ts.map +1 -1
  50. package/dist/classes/Market.js +129 -30
  51. package/dist/classes/Market.js.map +1 -1
  52. package/dist/classes/NativeToken.d.ts +5 -2
  53. package/dist/classes/NativeToken.d.ts.map +1 -1
  54. package/dist/classes/NativeToken.js +5 -5
  55. package/dist/classes/NativeToken.js.map +1 -1
  56. package/dist/classes/OptimizerReader.d.ts +44 -4
  57. package/dist/classes/OptimizerReader.d.ts.map +1 -1
  58. package/dist/classes/OptimizerReader.js +133 -62
  59. package/dist/classes/OptimizerReader.js.map +1 -1
  60. package/dist/classes/PositionManager.d.ts +1 -0
  61. package/dist/classes/PositionManager.d.ts.map +1 -1
  62. package/dist/classes/PositionManager.js +25 -0
  63. package/dist/classes/PositionManager.js.map +1 -1
  64. package/dist/classes/ProtocolReader.d.ts +3 -0
  65. package/dist/classes/ProtocolReader.d.ts.map +1 -1
  66. package/dist/classes/ProtocolReader.js +34 -0
  67. package/dist/classes/ProtocolReader.js.map +1 -1
  68. package/dist/classes/Zapper.d.ts +4 -1
  69. package/dist/classes/Zapper.d.ts.map +1 -1
  70. package/dist/classes/Zapper.js +34 -9
  71. package/dist/classes/Zapper.js.map +1 -1
  72. package/dist/classes/index.d.ts +1 -0
  73. package/dist/classes/index.d.ts.map +1 -1
  74. package/dist/classes/index.js +1 -0
  75. package/dist/classes/index.js.map +1 -1
  76. package/dist/contracts/index.d.ts +248 -248
  77. package/dist/contracts/index.d.ts.map +1 -1
  78. package/dist/contracts/index.js +3 -2
  79. package/dist/contracts/index.js.map +1 -1
  80. package/dist/contracts/monad-mainnet.json +1 -1
  81. package/dist/feePolicy.d.ts +29 -26
  82. package/dist/feePolicy.d.ts.map +1 -1
  83. package/dist/feePolicy.js +43 -34
  84. package/dist/feePolicy.js.map +1 -1
  85. package/dist/format/index.d.ts +5 -0
  86. package/dist/format/index.d.ts.map +1 -1
  87. package/dist/format/index.js +28 -0
  88. package/dist/format/index.js.map +1 -1
  89. package/dist/helpers.d.ts +247 -248
  90. package/dist/helpers.d.ts.map +1 -1
  91. package/dist/helpers.js +5 -5
  92. package/dist/helpers.js.map +1 -1
  93. package/dist/immutability.d.ts +6 -0
  94. package/dist/immutability.d.ts.map +1 -0
  95. package/dist/immutability.js +25 -0
  96. package/dist/immutability.js.map +1 -0
  97. package/dist/integrations/merkl.d.ts +9 -2
  98. package/dist/integrations/merkl.d.ts.map +1 -1
  99. package/dist/integrations/merkl.js +219 -11
  100. package/dist/integrations/merkl.js.map +1 -1
  101. package/dist/integrations/snapshot.d.ts +3 -0
  102. package/dist/integrations/snapshot.d.ts.map +1 -1
  103. package/dist/integrations/snapshot.js +47 -3
  104. package/dist/integrations/snapshot.js.map +1 -1
  105. package/dist/setup.d.ts +13 -3
  106. package/dist/setup.d.ts.map +1 -1
  107. package/dist/setup.js +101 -7
  108. package/dist/setup.js.map +1 -1
  109. package/package.json +7 -4
@@ -15,9 +15,6 @@ const PositionManager_1 = require("./PositionManager");
15
15
  const NativeToken_1 = require("./NativeToken");
16
16
  const ERC4626_1 = require("./ERC4626");
17
17
  const FormatConverter_1 = __importDefault(require("./FormatConverter"));
18
- const EXCLUDED_ZAP_SYMBOLS = new Set([
19
- 'eBTC', 'vUSD', 'ezETH', 'YZM', 'wsrUSD', 'sAUSD',
20
- ]);
21
18
  const EXECUTION_DEBT_BUFFER_TIME = 100n;
22
19
  function ceilDiv(numerator, denominator) {
23
20
  if (denominator <= 0n) {
@@ -182,27 +179,44 @@ class CToken extends Calldata_1.Calldata {
182
179
  this.contract = (0, helpers_1.contractSetup)(this.provider, address, BaseCToken_json_1.default);
183
180
  this.cache = cache;
184
181
  this.market = market;
185
- const chainSettings = this.currentChainConfig;
182
+ const chainSettings = this.currentChainAssets;
186
183
  const assetAddr = this.asset.address.toLowerCase();
187
184
  this.isNativeVault = chainSettings.native_vaults.some(vault => vault.contract.toLowerCase() == assetAddr);
188
185
  this.isVault = chainSettings.vaults.some(vault => vault.contract.toLowerCase() == assetAddr);
189
186
  this.isWrappedNative = chainSettings.wrapped_native.toLowerCase() == assetAddr;
190
- if (EXCLUDED_ZAP_SYMBOLS.has(this.asset.symbol)) {
187
+ this.refreshRouteCapabilities();
188
+ }
189
+ refreshRouteCapabilities() {
190
+ this.zapTypes = [];
191
+ this.leverageTypes = [];
192
+ if (this.isZapSymbolExcluded(this.asset.symbol)) {
191
193
  return;
192
194
  }
193
- if (this.isNativeVault)
195
+ const zappers = this.setup.contracts.zappers;
196
+ const nativeVaultZapper = zappers?.nativeVaultZapper;
197
+ const vaultZapper = zappers?.vaultZapper;
198
+ const simpleZapper = zappers?.simpleZapper;
199
+ const supportsNativeVaultZaps = typeof nativeVaultZapper === 'string'
200
+ && nativeVaultZapper.toLowerCase() !== helpers_1.EMPTY_ADDRESS.toLowerCase();
201
+ const supportsVaultZaps = typeof vaultZapper === 'string'
202
+ && vaultZapper.toLowerCase() !== helpers_1.EMPTY_ADDRESS.toLowerCase();
203
+ const supportsSimpleZaps = typeof simpleZapper === 'string'
204
+ && simpleZapper.toLowerCase() !== helpers_1.EMPTY_ADDRESS.toLowerCase()
205
+ && this.hasExecutableDexRoute;
206
+ if (supportsNativeVaultZaps && this.isNativeVault)
194
207
  this.zapTypes.push('native-vault');
195
208
  if ("nativeVaultPositionManager" in this.market.plugins && this.isNativeVault)
196
209
  this.leverageTypes.push('native-vault');
197
- if (this.isWrappedNative)
210
+ if (supportsSimpleZaps && this.isWrappedNative)
198
211
  this.zapTypes.push('native-simple');
199
- if (this.isVault)
212
+ if (supportsVaultZaps && this.isVault)
200
213
  this.zapTypes.push('vault');
201
214
  if ("vaultPositionManager" in this.market.plugins && this.isVault)
202
215
  this.leverageTypes.push('vault');
203
- if ("simplePositionManager" in this.market.plugins)
216
+ if (supportsSimpleZaps && "simplePositionManager" in this.market.plugins)
204
217
  this.leverageTypes.push('simple');
205
- this.zapTypes.push('simple');
218
+ if (supportsSimpleZaps)
219
+ this.zapTypes.push('simple');
206
220
  }
207
221
  getUserCacheFreshness() {
208
222
  if (this.userCacheFreshness == undefined) {
@@ -231,7 +245,28 @@ class CToken extends Calldata_1.Calldata {
231
245
  }
232
246
  get setup() { return this.market.setup; }
233
247
  get currentChain() { return this.setup.chain; }
234
- get currentChainConfig() { return (0, helpers_1.getChainConfig)(this.currentChain); }
248
+ get currentChainAssets() { return this.setup.assets; }
249
+ isZapSymbolExcluded(symbol) {
250
+ if (symbol == null) {
251
+ return false;
252
+ }
253
+ const excludedSymbols = this.setup.assets
254
+ ?.excluded_zap_symbols ?? [];
255
+ return excludedSymbols.some((excluded) => excluded.toLowerCase() === symbol.toLowerCase());
256
+ }
257
+ get boundDexAgg() { return this.market.dexAgg ?? null; }
258
+ get currentDexAgg() {
259
+ const dexAgg = this.boundDexAgg;
260
+ if (dexAgg == null) {
261
+ throw new Error(`DEX aggregator is not bound for token ${this.address} on ${this.currentChain}. ` +
262
+ `Use setupChain(...) result markets or attach a setup-bound dexAgg before route discovery/execution.`);
263
+ }
264
+ return dexAgg;
265
+ }
266
+ get hasExecutableDexRoute() {
267
+ const router = this.boundDexAgg?.router;
268
+ return typeof router === "string" && router.toLowerCase() !== helpers_1.EMPTY_ADDRESS.toLowerCase();
269
+ }
235
270
  requireSigner() { return (0, helpers_1.requireSigner)(this.signer); }
236
271
  getAccountOrThrow(account = null) {
237
272
  return (0, helpers_1.requireAccount)(account ?? this.account, this.signer);
@@ -239,6 +274,31 @@ class CToken extends Calldata_1.Calldata {
239
274
  getWriteContract() {
240
275
  return (0, helpers_1.contractSetup)(this.requireSigner(), this.address, BaseCToken_json_1.default);
241
276
  }
277
+ assertBorrowTokenBelongsToMarket(borrow, label = "Borrow") {
278
+ if (borrow == null) {
279
+ return;
280
+ }
281
+ const borrowMarket = borrow.market;
282
+ if (borrowMarket == undefined) {
283
+ return;
284
+ }
285
+ if (borrowMarket === this.market) {
286
+ return;
287
+ }
288
+ const borrowChain = borrowMarket.setup?.chain;
289
+ const collateralChain = this.market.setup?.chain;
290
+ const sameMarket = borrowMarket.address?.toLowerCase() === this.market.address.toLowerCase();
291
+ const sameChain = borrowChain != null && collateralChain != null && borrowChain === collateralChain;
292
+ const borrowReaderKey = borrowMarket.reader?.batchKey ?? null;
293
+ const collateralReaderKey = this.market.reader?.batchKey ?? null;
294
+ const sameReaderDeployment = borrowMarket.reader === this.market.reader ||
295
+ (borrowReaderKey != null && borrowReaderKey === collateralReaderKey);
296
+ if (!sameMarket || !sameChain || !sameReaderDeployment) {
297
+ throw new Error(`${label} token ${borrow.address} belongs to market ${borrowMarket.address} ` +
298
+ `on ${borrowChain ?? "unknown"}, not market ${this.market.address} on ${collateralChain ?? "unknown"} ` +
299
+ `with the same reader deployment.`);
300
+ }
301
+ }
242
302
  getZapType(zap) {
243
303
  return typeof zap === "object" ? zap.type : zap;
244
304
  }
@@ -264,7 +324,7 @@ class CToken extends Calldata_1.Calldata {
264
324
  if (zap.inputToken.toLowerCase() === helpers_1.NATIVE_ADDRESS.toLowerCase()) {
265
325
  return 18n;
266
326
  }
267
- const inputErc20 = new ERC20_1.ERC20(this.provider, zap.inputToken, undefined, undefined, this.signer);
327
+ const inputErc20 = new ERC20_1.ERC20(this.provider, zap.inputToken, undefined, this.setup.contracts.OracleManager, this.signer);
268
328
  return inputErc20.decimals ?? await inputErc20.contract.decimals();
269
329
  }
270
330
  }
@@ -272,8 +332,9 @@ class CToken extends Calldata_1.Calldata {
272
332
  return FormatConverter_1.default.decimalToBigInt(amount, await this.getZapInputDecimals(zap));
273
333
  }
274
334
  async assertVaultLeverageBorrowAssetSupported(borrow, type) {
335
+ this.assertBorrowTokenBelongsToMarket(borrow);
275
336
  const expectedAsset = type === "native-vault"
276
- ? this.currentChainConfig.wrapped_native
337
+ ? this.currentChainAssets.wrapped_native
277
338
  : await this.getVaultAsset(false);
278
339
  const actualAsset = borrow.asset.address;
279
340
  if (actualAsset.toLowerCase() === expectedAsset.toLowerCase()) {
@@ -382,11 +443,15 @@ class CToken extends Calldata_1.Calldata {
382
443
  const shares = this.totalSupply === 0n || this.totalAssets === 0n
383
444
  ? assets
384
445
  : (assets * this.totalSupply) / this.totalAssets;
385
- return bufferBps > 0n ? shares * (10000n - bufferBps) / 10000n : shares;
386
- }
387
- getMarketLeverageState() {
388
- const currentCollateralInUsd = this.market.userCollateral;
389
- const currentDebt = this.market.userDebt;
446
+ return bufferBps > 0n ? shares * (helpers_1.BPS - bufferBps) / helpers_1.BPS : shares;
447
+ }
448
+ getMarketLeverageState(leverageState) {
449
+ const currentCollateralInUsd = leverageState?.collateralUsd != null
450
+ ? (0, helpers_1.toDecimal)(leverageState.collateralUsd, 18n)
451
+ : this.market.userCollateral;
452
+ const currentDebt = leverageState?.debtUsd != null
453
+ ? (0, helpers_1.toDecimal)(leverageState.debtUsd, 18n)
454
+ : this.market.userDebt;
390
455
  const equity = currentCollateralInUsd.sub(currentDebt);
391
456
  if (currentCollateralInUsd.lte(0) || equity.lte(0)) {
392
457
  return {
@@ -523,7 +588,7 @@ class CToken extends Calldata_1.Calldata {
523
588
  // into Curvance shares. Buffer the inner preview so exchange-rate drift
524
589
  // between quote time and inclusion cannot trip the outer expectedShares
525
590
  // check on otherwise-valid deposits/leverage/zaps.
526
- const vaultShares = vaultSharesRaw * (10000n - exports.LEVERAGE.SHARES_BUFFER_BPS) / 10000n;
591
+ const vaultShares = vaultSharesRaw * (helpers_1.BPS - exports.LEVERAGE.SHARES_BUFFER_BPS) / helpers_1.BPS;
527
592
  return this.convertToShares(vaultShares);
528
593
  }
529
594
  getAsset(asErc20) {
@@ -586,7 +651,7 @@ class CToken extends Calldata_1.Calldata {
586
651
  if (zap_contract == null) {
587
652
  return null;
588
653
  }
589
- return new Zapper_1.Zapper(zap_contract, signer, type, this.setup);
654
+ return new Zapper_1.Zapper(zap_contract, signer, type, this.setup, this.currentDexAgg);
590
655
  }
591
656
  async isZapAssetApproved(instructions, amount) {
592
657
  if (instructions == 'none') {
@@ -653,7 +718,7 @@ class CToken extends Calldata_1.Calldata {
653
718
  }
654
719
  async getAllowance(check_contract, underlying = true) {
655
720
  const signer = this.requireSigner();
656
- const erc20 = new ERC20_1.ERC20(this.provider, underlying ? this.asset.address : this.address, undefined, undefined, this.signer);
721
+ const erc20 = new ERC20_1.ERC20(this.provider, underlying ? this.asset.address : this.address, undefined, this.setup.contracts.OracleManager, this.signer);
657
722
  const allowance = await erc20.allowance(signer.address, check_contract);
658
723
  return allowance;
659
724
  }
@@ -663,12 +728,12 @@ class CToken extends Calldata_1.Calldata {
663
728
  * @returns tx
664
729
  */
665
730
  async approveUnderlying(amount = null, target = null) {
666
- const erc20 = new ERC20_1.ERC20(this.provider, this.asset.address, undefined, undefined, this.signer);
731
+ const erc20 = new ERC20_1.ERC20(this.provider, this.asset.address, undefined, this.setup.contracts.OracleManager, this.signer);
667
732
  const tx = await erc20.approve(target ? target : this.address, amount);
668
733
  return tx;
669
734
  }
670
735
  async approve(amount = null, spender) {
671
- const erc20 = new ERC20_1.ERC20(this.provider, this.address, undefined, undefined, this.signer);
736
+ const erc20 = new ERC20_1.ERC20(this.provider, this.address, undefined, this.setup.contracts.OracleManager, this.signer);
672
737
  const tx = await erc20.approve(spender, amount);
673
738
  return tx;
674
739
  }
@@ -739,7 +804,8 @@ class CToken extends Calldata_1.Calldata {
739
804
  }
740
805
  async transfer(receiver, amount) {
741
806
  const shares = this.convertTokenInputToShares(amount);
742
- return this.getWriteContract().transfer(receiver, shares);
807
+ const calldata = this.getCallData("transfer", [receiver, shares]);
808
+ return this.oracleRoute(calldata);
743
809
  }
744
810
  async redeemCollateral(amount, receiver = null, owner = null) {
745
811
  const signer = this.requireSigner();
@@ -773,21 +839,47 @@ class CToken extends Calldata_1.Calldata {
773
839
  if (max_shares <= 0n) {
774
840
  throw new Error("No cToken shares available to post as collateral.");
775
841
  }
842
+ this.assertCollateralCapacity(max_shares);
776
843
  const calldata = this.getCallData("postCollateral", [max_shares]);
777
844
  const tx = await this.oracleRoute(calldata);
778
845
  // Reload collateral state after execution
779
846
  await this.fetchUserCollateral();
780
847
  return tx;
781
848
  }
849
+ assertCollateralCapacity(shares) {
850
+ const collateralCapError = "There is not enough collateral left in this tokens collateral cap for this deposit.";
851
+ const remainingCollateral = this.getRemainingCollateral(false);
852
+ if (remainingCollateral <= 0n)
853
+ throw new Error(collateralCapError);
854
+ if (shares != undefined && shares > remainingCollateral) {
855
+ throw new Error(collateralCapError);
856
+ }
857
+ }
858
+ getZapperExpectedShares(zapper, calldata) {
859
+ if (zapper == null)
860
+ return undefined;
861
+ let expectedShares;
862
+ try {
863
+ const decoded = zapper.contract.interface.decodeFunctionData("swapAndDeposit", calldata);
864
+ expectedShares = BigInt(decoded[3]);
865
+ }
866
+ catch {
867
+ return undefined;
868
+ }
869
+ if (expectedShares <= 0n) {
870
+ throw new Error("Zap expected shares must be greater than zero.");
871
+ }
872
+ return expectedShares;
873
+ }
782
874
  async getZapBalance(zap) {
783
875
  const signer = this.requireSigner();
784
876
  let asset;
785
877
  if (typeof zap === 'object') {
786
878
  if (zap.type === 'native-vault' || zap.type === 'native-simple' || zap.inputToken.toLowerCase() === helpers_1.NATIVE_ADDRESS.toLowerCase()) {
787
- asset = new NativeToken_1.NativeToken(this.currentChain, this.provider, this.setup.contracts.OracleManager, this.signer, this.account);
879
+ asset = new NativeToken_1.NativeToken(this.currentChain, this.provider, this.setup.contracts.OracleManager, this.signer, this.account, this.currentChainAssets);
788
880
  }
789
881
  else {
790
- asset = new ERC20_1.ERC20(this.provider, zap.inputToken, undefined, undefined, this.signer);
882
+ asset = new ERC20_1.ERC20(this.provider, zap.inputToken, undefined, this.setup.contracts.OracleManager, this.signer);
791
883
  }
792
884
  }
793
885
  else {
@@ -799,10 +891,10 @@ class CToken extends Calldata_1.Calldata {
799
891
  asset = await this.getVaultAsset(true);
800
892
  break;
801
893
  case 'native-vault':
802
- asset = new NativeToken_1.NativeToken(this.currentChain, this.provider, this.setup.contracts.OracleManager, this.signer, this.account);
894
+ asset = new NativeToken_1.NativeToken(this.currentChain, this.provider, this.setup.contracts.OracleManager, this.signer, this.account, this.currentChainAssets);
803
895
  break;
804
896
  case 'native-simple':
805
- asset = new NativeToken_1.NativeToken(this.currentChain, this.provider, this.setup.contracts.OracleManager, this.signer, this.account);
897
+ asset = new NativeToken_1.NativeToken(this.currentChain, this.provider, this.setup.contracts.OracleManager, this.signer, this.account, this.currentChainAssets);
806
898
  break;
807
899
  default: throw new Error("Unsupported zap type for balance fetch");
808
900
  }
@@ -881,7 +973,7 @@ class CToken extends Calldata_1.Calldata {
881
973
  }
882
974
  async convertToShares(assets, bufferBps = exports.LEVERAGE.SHARES_BUFFER_BPS) {
883
975
  const shares = await this.contract.convertToShares(assets);
884
- return bufferBps > 0n ? shares * (10000n - bufferBps) / 10000n : shares;
976
+ return bufferBps > 0n ? shares * (helpers_1.BPS - bufferBps) / helpers_1.BPS : shares;
885
977
  }
886
978
  async maxRedemption(in_shares = false, bufferTime = 0n, breakdown = false) {
887
979
  const data = await this.market.reader.maxRedemptionOf(this.getAccountOrThrow(), this, bufferTime);
@@ -910,14 +1002,14 @@ class CToken extends Calldata_1.Calldata {
910
1002
  let tokens_exclude = [this.asset.address.toLocaleLowerCase()];
911
1003
  if (this.zapTypes.includes('native-vault')) {
912
1004
  tokens.push({
913
- interface: new NativeToken_1.NativeToken(this.currentChain, this.provider, this.setup.contracts.OracleManager, this.signer, this.account),
1005
+ interface: new NativeToken_1.NativeToken(this.currentChain, this.provider, this.setup.contracts.OracleManager, this.signer, this.account, this.currentChainAssets),
914
1006
  type: 'native-vault'
915
1007
  });
916
1008
  tokens_exclude.push(helpers_1.EMPTY_ADDRESS.toLowerCase(), helpers_1.NATIVE_ADDRESS.toLowerCase());
917
1009
  }
918
1010
  if (this.zapTypes.includes('native-simple')) {
919
1011
  tokens.push({
920
- interface: new NativeToken_1.NativeToken(this.currentChain, this.provider, this.setup.contracts.OracleManager, this.signer, this.account),
1012
+ interface: new NativeToken_1.NativeToken(this.currentChain, this.provider, this.setup.contracts.OracleManager, this.signer, this.account, this.currentChainAssets),
921
1013
  type: 'native-simple'
922
1014
  });
923
1015
  if (!this.zapTypes.includes('native-vault')) {
@@ -932,20 +1024,20 @@ class CToken extends Calldata_1.Calldata {
932
1024
  });
933
1025
  tokens_exclude.push(vault_asset.address.toLocaleLowerCase());
934
1026
  }
935
- if (this.zapTypes.includes('simple') && this.currentChainConfig.dexAgg.router !== helpers_1.EMPTY_ADDRESS) {
936
- let dexAggSearch = await this.currentChainConfig.dexAgg.getAvailableTokens(this.provider, search, this.account);
1027
+ if (this.zapTypes.includes('simple') && this.hasExecutableDexRoute) {
1028
+ let dexAggSearch = await this.currentDexAgg.getAvailableTokens(this.provider, search, this.account);
937
1029
  tokens = tokens.concat(dexAggSearch.filter(token => !tokens_exclude.includes(token.interface.address.toLocaleLowerCase())));
938
1030
  // Add native MON as a zap option for any token with a simple zapper
939
1031
  // (not just wrapped native). The simple zapper handles wrapping + swapping.
940
1032
  if (!tokens_exclude.includes(helpers_1.NATIVE_ADDRESS.toLowerCase()) && !this.isWrappedNative) {
941
1033
  tokens.push({
942
- interface: new NativeToken_1.NativeToken(this.currentChain, this.provider, this.setup.contracts.OracleManager, this.signer, this.account),
1034
+ interface: new NativeToken_1.NativeToken(this.currentChain, this.provider, this.setup.contracts.OracleManager, this.signer, this.account, this.currentChainAssets),
943
1035
  type: 'simple'
944
1036
  });
945
1037
  tokens_exclude.push(helpers_1.NATIVE_ADDRESS.toLowerCase());
946
1038
  }
947
1039
  }
948
- tokens = tokens.filter(token => token.type === 'none' || !EXCLUDED_ZAP_SYMBOLS.has(token.interface.symbol ?? ''));
1040
+ tokens = tokens.filter(token => token.type === 'none' || !this.isZapSymbolExcluded(token.interface.symbol));
949
1041
  if (search) {
950
1042
  const lowerSearch = search.toLowerCase();
951
1043
  tokens = tokens.filter(token => (token.interface.name ?? '').toLowerCase().includes(lowerSearch) ||
@@ -961,23 +1053,22 @@ class CToken extends Calldata_1.Calldata {
961
1053
  * Single-RPC snapshot of fresh position state for leverage operations.
962
1054
  * Calls ProtocolReader.getLeverageSnapshot which internally uses
963
1055
  * hypotheticalLiquidityOf for aggregate position + fresh oracle prices
964
- * + projected debt balance. Updates the local cache so downstream
965
- * preview computations (previewLeverageUp/Down) read fresh values.
1056
+ * + projected debt balance. Updates only token price/share caches; leverage
1057
+ * previews consume the returned aggregate values explicitly so failed or
1058
+ * simulated plans cannot leave market user totals ahead of token user rows.
966
1059
  *
967
1060
  * Returns the snapshot for direct use where needed (e.g. debtTokenBalance
968
1061
  * for full deleverage swap sizing).
969
1062
  */
970
1063
  async _getLeverageSnapshot(borrow) {
1064
+ this.assertBorrowTokenBelongsToMarket(borrow);
971
1065
  const snapshot = await this.market.reader.getLeverageSnapshot(this.getAccountOrThrow(), this.address, borrow.address, 120n);
972
1066
  if (snapshot.oracleError) {
973
1067
  throw new Error(`Oracle error fetching leverage snapshot for ${this.symbol}/${borrow.symbol}`);
974
1068
  }
975
- // Update cache so preview functions read fresh values
976
1069
  this.cache.assetPrice = snapshot.collateralAssetPrice;
977
1070
  this.cache.sharePrice = snapshot.sharePrice;
978
1071
  borrow.cache.assetPrice = snapshot.debtAssetPrice;
979
- this.market.cache.user.collateral = snapshot.collateralUsd;
980
- this.market.cache.user.debt = snapshot.debtUsd;
981
1072
  return snapshot;
982
1073
  }
983
1074
  /**
@@ -1008,11 +1099,13 @@ class CToken extends Calldata_1.Calldata {
1008
1099
  return slippage + exports.LEVERAGE.LEVERAGE_UP_BUFFER_BPS;
1009
1100
  }
1010
1101
  assertSimpleLeverageSwapAssetsDiffer(borrow) {
1102
+ this.assertBorrowTokenBelongsToMarket(borrow);
1011
1103
  if (borrow.asset.address.toLowerCase() === this.asset.address.toLowerCase()) {
1012
1104
  throw new Error("Simple leverage requires distinct collateral and borrow assets.");
1013
1105
  }
1014
1106
  }
1015
1107
  async assertLeverageBorrowCapacity(borrow, borrowAssets) {
1108
+ this.assertBorrowTokenBelongsToMarket(borrow);
1016
1109
  if (borrowAssets === 0n) {
1017
1110
  return;
1018
1111
  }
@@ -1029,6 +1122,7 @@ class CToken extends Calldata_1.Calldata {
1029
1122
  }
1030
1123
  }
1031
1124
  assertSelectedBorrowDebtCanDeleverage(borrow, selectedDebtAssets, requiredDebtReductionUsd) {
1125
+ this.assertBorrowTokenBelongsToMarket(borrow);
1032
1126
  if (requiredDebtReductionUsd.lte(0)) {
1033
1127
  return;
1034
1128
  }
@@ -1050,15 +1144,16 @@ class CToken extends Calldata_1.Calldata {
1050
1144
  return (0, decimal_js_1.default)(1);
1051
1145
  return collateralAfterDeposit.div(equityAfterDeposit);
1052
1146
  }
1053
- resolveLeverageUpPreview({ operation, targetLeverage, borrow, depositAssets = 0n, positionManagerType, }) {
1054
- const leverageState = this.getMarketLeverageState();
1055
- const currentLeverage = leverageState.currentLeverage ?? (0, decimal_js_1.default)(1);
1056
- const currentCollateralInUsd = leverageState.currentCollateralInUsd;
1147
+ resolveLeverageUpPreview({ operation, targetLeverage, borrow, depositAssets = 0n, positionManagerType, leverageState, }) {
1148
+ this.assertBorrowTokenBelongsToMarket(borrow);
1149
+ const currentState = this.getMarketLeverageState(leverageState);
1150
+ const currentLeverage = currentState.currentLeverage ?? (0, decimal_js_1.default)(1);
1151
+ const currentCollateralInUsd = currentState.currentCollateralInUsd;
1057
1152
  const depositInAssets = FormatConverter_1.default.bigIntToDecimal(depositAssets, this.asset.decimals);
1058
1153
  const depositInUsd = depositAssets > 0n
1059
1154
  ? this.convertTokensToUsd(depositAssets, true)
1060
1155
  : (0, decimal_js_1.default)(0);
1061
- const currentDebt = leverageState.currentDebt;
1156
+ const currentDebt = currentState.currentDebt;
1062
1157
  const effectiveCurrentLeverage = depositAssets > 0n
1063
1158
  ? this.computePostDepositNaturalLeverage(currentCollateralInUsd, currentDebt, depositInUsd)
1064
1159
  : currentLeverage;
@@ -1099,7 +1194,7 @@ class CToken extends Calldata_1.Calldata {
1099
1194
  targetLeverage: resolvedTargetLeverage,
1100
1195
  })
1101
1196
  : 0n;
1102
- const feeAssets = borrowAmount.mul((0, decimal_js_1.default)(Number(feeBps))).div((0, decimal_js_1.default)(10000));
1197
+ const feeAssets = borrowAmount.mul((0, decimal_js_1.default)(Number(feeBps))).div(helpers_1.BPS_DECIMAL);
1103
1198
  const feeUsd = feeAssets.mul(borrowPrice);
1104
1199
  const collateralIncreaseFromBorrow = decimal_js_1.default.max(debtIncrease.sub(feeUsd), (0, decimal_js_1.default)(0));
1105
1200
  const collateralIncrease = depositInUsd.add(collateralIncreaseFromBorrow);
@@ -1124,36 +1219,39 @@ class CToken extends Calldata_1.Calldata {
1124
1219
  feeUsd,
1125
1220
  };
1126
1221
  }
1127
- previewDepositAndLeverage(newLeverage, borrow, depositAmount, positionManagerType) {
1222
+ previewDepositAndLeverage(newLeverage, borrow, depositAmount, positionManagerType, leverageState) {
1128
1223
  return this.resolveLeverageUpPreview({
1129
1224
  operation: 'deposit-and-leverage',
1130
1225
  targetLeverage: newLeverage,
1131
1226
  borrow,
1132
1227
  depositAssets: depositAmount,
1133
1228
  positionManagerType,
1229
+ leverageState,
1134
1230
  });
1135
1231
  }
1136
- previewLeverageUp(newLeverage, borrow, depositAmount, positionManagerType) {
1232
+ previewLeverageUp(newLeverage, borrow, depositAmount, positionManagerType, leverageState) {
1137
1233
  if ((depositAmount ?? 0n) > 0n) {
1138
- return this.previewDepositAndLeverage(newLeverage, borrow, depositAmount, positionManagerType);
1234
+ return this.previewDepositAndLeverage(newLeverage, borrow, depositAmount, positionManagerType, leverageState);
1139
1235
  }
1140
1236
  return this.resolveLeverageUpPreview({
1141
1237
  operation: 'leverage-up',
1142
1238
  targetLeverage: newLeverage,
1143
1239
  borrow,
1144
1240
  positionManagerType,
1241
+ leverageState,
1145
1242
  });
1146
1243
  }
1147
- previewLeverageDown(newLeverage, currentLeverage, borrow) {
1244
+ previewLeverageDown(newLeverage, currentLeverage, borrow, leverageState) {
1245
+ this.assertBorrowTokenBelongsToMarket(borrow);
1148
1246
  if (newLeverage.gte(currentLeverage)) {
1149
1247
  throw new Error("New leverage must be less than current leverage");
1150
1248
  }
1151
1249
  if (newLeverage.lt((0, decimal_js_1.default)(1))) {
1152
1250
  throw new Error("New leverage must be at least 1");
1153
1251
  }
1154
- const leverageState = this.getMarketLeverageState();
1155
- const collateralInUsd = leverageState.currentCollateralInUsd;
1156
- const currentDebt = leverageState.currentDebt;
1252
+ const currentState = this.getMarketLeverageState(leverageState);
1253
+ const collateralInUsd = currentState.currentCollateralInUsd;
1254
+ const currentDebt = currentState.currentDebt;
1157
1255
  const equity = collateralInUsd.sub(currentDebt);
1158
1256
  if (equity.lte(0)) {
1159
1257
  throw new Error("Position has no positive equity to deleverage.");
@@ -1178,7 +1276,7 @@ class CToken extends Calldata_1.Calldata {
1178
1276
  currentLeverage,
1179
1277
  targetLeverage: newLeverage,
1180
1278
  }) : 0n;
1181
- const feeUsd = collateralAssetReductionUsd.mul((0, decimal_js_1.default)(Number(feeBps))).div((0, decimal_js_1.default)(10000));
1279
+ const feeUsd = collateralAssetReductionUsd.mul((0, decimal_js_1.default)(Number(feeBps))).div(helpers_1.BPS_DECIMAL);
1182
1280
  const feeAssets = this.getPrice(true).gt(0)
1183
1281
  ? feeUsd.div(this.getPrice(true))
1184
1282
  : (0, decimal_js_1.default)(0);
@@ -1197,6 +1295,7 @@ class CToken extends Calldata_1.Calldata {
1197
1295
  }
1198
1296
  async leverageUp(borrow, newLeverage, type, slippage_ = (0, decimal_js_1.default)(0.05), simulate = false) {
1199
1297
  try {
1298
+ this.assertBorrowTokenBelongsToMarket(borrow);
1200
1299
  this.requireSigner();
1201
1300
  const manager = this.getPositionManager(type);
1202
1301
  if (type === 'vault' || type === 'native-vault') {
@@ -1206,8 +1305,8 @@ class CToken extends Calldata_1.Calldata {
1206
1305
  this.assertSimpleLeverageSwapAssetsDiffer(borrow);
1207
1306
  }
1208
1307
  let calldata;
1209
- await this._getLeverageSnapshot(borrow);
1210
- const preview = this.previewLeverageUp(newLeverage, borrow, undefined, type);
1308
+ const snapshot = await this._getLeverageSnapshot(borrow);
1309
+ const preview = this.previewLeverageUp(newLeverage, borrow, undefined, type, snapshot);
1211
1310
  const slippage = this._leverageUpSlippage(FormatConverter_1.default.percentageToBps(slippage_), preview.targetLeverage);
1212
1311
  const { borrowAmount, borrowAssets, feeBps, targetLeverage } = preview;
1213
1312
  if (borrowAssets === 0n) {
@@ -1223,7 +1322,7 @@ class CToken extends Calldata_1.Calldata {
1223
1322
  switch (type) {
1224
1323
  case 'simple': {
1225
1324
  const feeReceiver = feeBps > 0n ? this.setup.feePolicy.feeReceiver : undefined;
1226
- const { action, quote } = await this.currentChainConfig.dexAgg.quoteAction(manager.address, borrow.asset.address, this.asset.address, borrowAssets, slippage, feeBps, feeReceiver);
1325
+ const { action, quote } = await this.currentDexAgg.quoteAction(manager.address, borrow.asset.address, this.asset.address, borrowAssets, slippage, feeBps, feeReceiver);
1227
1326
  // Fee-aware slippage expansion now lives inside KyberSwap.quoteAction
1228
1327
  // so any caller inherits correct behavior. See KyberSwap.ts for the
1229
1328
  // rationale. The fee still reduces swap output, which checkSlippage
@@ -1278,13 +1377,13 @@ class CToken extends Calldata_1.Calldata {
1278
1377
  }
1279
1378
  async leverageDown(borrowToken, currentLeverage, newLeverage, type, slippage_ = (0, decimal_js_1.default)(0.05), simulate = false) {
1280
1379
  try {
1380
+ this.assertBorrowTokenBelongsToMarket(borrowToken);
1281
1381
  if (newLeverage.gte(currentLeverage)) {
1282
1382
  if (simulate)
1283
1383
  return { success: false, error: "New leverage must be less than current leverage" };
1284
1384
  throw new Error("New leverage must be less than current leverage");
1285
1385
  }
1286
1386
  this.requireSigner();
1287
- const config = this.currentChainConfig;
1288
1387
  const slippage = (0, helpers_1.toBps)(slippage_);
1289
1388
  const manager = this.getPositionManager(type);
1290
1389
  if (type === 'simple') {
@@ -1292,7 +1391,7 @@ class CToken extends Calldata_1.Calldata {
1292
1391
  }
1293
1392
  let calldata;
1294
1393
  const snapshot = await this._getLeverageSnapshot(borrowToken);
1295
- const preview = this.previewLeverageDown(newLeverage, currentLeverage);
1394
+ const preview = this.previewLeverageDown(newLeverage, currentLeverage, undefined, snapshot);
1296
1395
  const { collateralAssetReduction } = preview;
1297
1396
  const isFullDeleverage = newLeverage.equals(1);
1298
1397
  const maxTokenCollateral = this.virtualConvertToAssets(this.readFreshUserCache("userCollateral", "executing leverage down"));
@@ -1337,7 +1436,7 @@ class CToken extends Calldata_1.Calldata {
1337
1436
  // Additive approximation is accurate to sub-bp at typical
1338
1437
  // fee+overhead magnitudes (< 100 bps combined).
1339
1438
  const overheadBps = exports.LEVERAGE.DELEVERAGE_OVERHEAD_BPS + feeBps;
1340
- swapCollateral = ceilDiv(debtInCollateral * (10000n + overheadBps), 10000n);
1439
+ swapCollateral = ceilDiv(debtInCollateral * (helpers_1.BPS + overheadBps), helpers_1.BPS);
1341
1440
  if (swapCollateral > maxTokenCollateral) {
1342
1441
  const error = "Selected collateral token does not have enough posted collateral to fully deleverage.";
1343
1442
  if (simulate) {
@@ -1354,7 +1453,7 @@ class CToken extends Calldata_1.Calldata {
1354
1453
  // from input before swapping, so without compensation
1355
1454
  // the swap underdelivers and actual leverage is slightly
1356
1455
  // higher than target.
1357
- swapCollateral = ceilDiv(swapCollateral * 10000n, 10000n - feeBps);
1456
+ swapCollateral = ceilDiv(swapCollateral * helpers_1.BPS, helpers_1.BPS - feeBps);
1358
1457
  }
1359
1458
  }
1360
1459
  if (!isFullDeleverage && swapCollateral > maxTokenCollateral) {
@@ -1364,7 +1463,7 @@ class CToken extends Calldata_1.Calldata {
1364
1463
  }
1365
1464
  throw new Error(error);
1366
1465
  }
1367
- const { action, quote } = await config.dexAgg.quoteAction(manager.address, this.asset.address, borrowToken.asset.address, swapCollateral, slippage, feeBps, feeReceiver);
1466
+ const { action, quote } = await this.currentDexAgg.quoteAction(manager.address, this.asset.address, borrowToken.asset.address, swapCollateral, slippage, feeBps, feeReceiver);
1368
1467
  // Fee-aware slippage expansion for `_swapSafe` is handled by
1369
1468
  // KyberSwap.quoteAction. See KyberSwap.ts for rationale.
1370
1469
  // In the current PositionManager, `repayAssets` is only a
@@ -1421,6 +1520,7 @@ class CToken extends Calldata_1.Calldata {
1421
1520
  }
1422
1521
  async depositAndLeverage(depositAmount, borrow, multiplier, type, slippage_ = (0, decimal_js_1.default)(0.05), simulate = false) {
1423
1522
  try {
1523
+ this.assertBorrowTokenBelongsToMarket(borrow);
1424
1524
  if (multiplier.lte((0, decimal_js_1.default)(1))) {
1425
1525
  if (simulate)
1426
1526
  return { success: false, error: "Multiplier must be greater than 1" };
@@ -1436,9 +1536,14 @@ class CToken extends Calldata_1.Calldata {
1436
1536
  }
1437
1537
  let calldata;
1438
1538
  const depositAssets = FormatConverter_1.default.decimalToBigInt(depositAmount, this.asset.decimals);
1539
+ if (depositAssets <= 0n) {
1540
+ if (simulate)
1541
+ return { success: false, error: "Deposit amount must be greater than zero." };
1542
+ throw new Error("Deposit amount must be greater than zero.");
1543
+ }
1439
1544
  await this._checkTokenApproval(this.getPositionManagerDepositApprovalTarget(manager), depositAssets);
1440
- await this._getLeverageSnapshot(borrow);
1441
- const preview = this.previewDepositAndLeverage(multiplier, borrow, depositAssets, type);
1545
+ const snapshot = await this._getLeverageSnapshot(borrow);
1546
+ const preview = this.previewDepositAndLeverage(multiplier, borrow, depositAssets, type, snapshot);
1442
1547
  if (preview.borrowAssets === 0n) {
1443
1548
  if (simulate) {
1444
1549
  return {
@@ -1454,7 +1559,7 @@ class CToken extends Calldata_1.Calldata {
1454
1559
  switch (type) {
1455
1560
  case 'simple': {
1456
1561
  const feeReceiver = feeBps > 0n ? this.setup.feePolicy.feeReceiver : undefined;
1457
- const { action, quote } = await this.currentChainConfig.dexAgg.quoteAction(manager.address, borrow.asset.address, this.asset.address, borrowAssets, slippage, feeBps, feeReceiver);
1562
+ const { action, quote } = await this.currentDexAgg.quoteAction(manager.address, borrow.asset.address, this.asset.address, borrowAssets, slippage, feeBps, feeReceiver);
1458
1563
  // Fee-aware slippage expansion for `_swapSafe` is handled by
1459
1564
  // KyberSwap.quoteAction. See KyberSwap.ts for rationale.
1460
1565
  // Fee amplification: same pattern as leverageUp. See
@@ -1510,6 +1615,9 @@ class CToken extends Calldata_1.Calldata {
1510
1615
  receiver ??= signer.address;
1511
1616
  const depositAssets = FormatConverter_1.default.decimalToBigInt(amount, this.asset.decimals);
1512
1617
  const zapAssets = await this.getZapAssetAmount(amount, zap);
1618
+ if (zapAssets <= 0n) {
1619
+ throw new Error("Deposit amount must be greater than zero.");
1620
+ }
1513
1621
  const default_calldata = this.getCallData("deposit", [depositAssets, receiver]);
1514
1622
  const { calldata, calldata_overrides } = await this.zap(zapAssets, zap, false, default_calldata, receiver);
1515
1623
  return this.simulateOracleRoute(calldata, calldata_overrides);
@@ -1525,11 +1633,20 @@ class CToken extends Calldata_1.Calldata {
1525
1633
  receiver ??= signer.address;
1526
1634
  const depositAssets = FormatConverter_1.default.decimalToBigInt(amount, this.asset.decimals);
1527
1635
  const zapAssets = await this.getZapAssetAmount(amount, zap);
1636
+ if (zapAssets <= 0n) {
1637
+ throw new Error("Deposit amount must be greater than zero.");
1638
+ }
1639
+ const depositShares = this.isZapInstruction(zap) ? undefined : this.virtualConvertToShares(depositAssets);
1640
+ this.assertCollateralCapacity(depositShares);
1528
1641
  const collateralMethod = receiver.toLowerCase() === signer.address.toLowerCase()
1529
1642
  ? "depositAsCollateral"
1530
1643
  : "depositAsCollateralFor";
1531
1644
  const default_calldata = this.getCallData(collateralMethod, [depositAssets, receiver]);
1532
- const { calldata, calldata_overrides } = await this.zap(zapAssets, zap, true, default_calldata, receiver);
1645
+ const { calldata, calldata_overrides, expectedShares } = await this.zap(zapAssets, zap, true, default_calldata, receiver);
1646
+ if (expectedShares !== undefined && expectedShares <= 0n) {
1647
+ throw new Error("Zap expected shares must be greater than zero.");
1648
+ }
1649
+ this.assertCollateralCapacity(expectedShares ?? depositShares);
1533
1650
  return this.simulateOracleRoute(calldata, calldata_overrides);
1534
1651
  }
1535
1652
  catch (error) {
@@ -1580,7 +1697,12 @@ class CToken extends Calldata_1.Calldata {
1580
1697
  default:
1581
1698
  throw new Error("This zap type is not supported: " + type_of_zap);
1582
1699
  }
1583
- return { calldata, calldata_overrides, zapper };
1700
+ return {
1701
+ calldata,
1702
+ calldata_overrides,
1703
+ zapper,
1704
+ expectedShares: this.getZapperExpectedShares(zapper, calldata),
1705
+ };
1584
1706
  }
1585
1707
  async deposit(amount, zap = 'none', receiver = null) {
1586
1708
  amount = await this.ensureUnderlyingAmount(amount, zap);
@@ -1588,6 +1710,9 @@ class CToken extends Calldata_1.Calldata {
1588
1710
  receiver ??= signer.address;
1589
1711
  const depositAssets = FormatConverter_1.default.decimalToBigInt(amount, this.asset.decimals);
1590
1712
  const zapAssets = await this.getZapAssetAmount(amount, zap);
1713
+ if (zapAssets <= 0n) {
1714
+ throw new Error("Deposit amount must be greater than zero.");
1715
+ }
1591
1716
  await this._checkDepositApprovals(zap, depositAssets, zapAssets);
1592
1717
  const default_calldata = this.getCallData("deposit", [depositAssets, receiver]);
1593
1718
  const { calldata, calldata_overrides } = await this.zap(zapAssets, zap, false, default_calldata, receiver);
@@ -1599,43 +1724,49 @@ class CToken extends Calldata_1.Calldata {
1599
1724
  receiver ??= signer.address;
1600
1725
  const depositAssets = FormatConverter_1.default.decimalToBigInt(amount, this.asset.decimals);
1601
1726
  const zapAssets = await this.getZapAssetAmount(amount, zap);
1602
- if (!this.isZapInstruction(zap)) {
1603
- const collateralCapError = "There is not enough collateral left in this tokens collateral cap for this deposit.";
1604
- const remainingCollateral = this.getRemainingCollateral(false);
1605
- if (remainingCollateral <= 0n)
1606
- throw new Error(collateralCapError);
1607
- if (remainingCollateral > 0n) {
1608
- const shares = this.virtualConvertToShares(depositAssets);
1609
- if (shares > remainingCollateral) {
1610
- throw new Error(collateralCapError);
1611
- }
1612
- }
1727
+ if (zapAssets <= 0n) {
1728
+ throw new Error("Deposit amount must be greater than zero.");
1613
1729
  }
1730
+ const depositShares = this.isZapInstruction(zap) ? undefined : this.virtualConvertToShares(depositAssets);
1731
+ this.assertCollateralCapacity(depositShares);
1614
1732
  await this._checkDepositApprovals(zap, depositAssets, zapAssets, true, receiver);
1615
1733
  const collateralMethod = receiver.toLowerCase() === signer.address.toLowerCase()
1616
1734
  ? "depositAsCollateral"
1617
1735
  : "depositAsCollateralFor";
1618
1736
  const default_calldata = this.getCallData(collateralMethod, [depositAssets, receiver]);
1619
- const { calldata, calldata_overrides } = await this.zap(zapAssets, zap, true, default_calldata, receiver);
1737
+ const { calldata, calldata_overrides, expectedShares } = await this.zap(zapAssets, zap, true, default_calldata, receiver);
1738
+ if (expectedShares !== undefined && expectedShares <= 0n) {
1739
+ throw new Error("Zap expected shares must be greater than zero.");
1740
+ }
1741
+ this.assertCollateralCapacity(expectedShares ?? depositShares);
1620
1742
  return this.oracleRoute(calldata, calldata_overrides, receiver);
1621
1743
  }
1622
1744
  async redeem(amount) {
1623
1745
  const signer = this.requireSigner();
1624
1746
  const receiver = signer.address;
1625
1747
  const owner = signer.address;
1748
+ const converted_shares = this.convertTokenInputToShares(amount);
1749
+ if (converted_shares <= 0n) {
1750
+ throw new Error("Redeem amount must be greater than zero.");
1751
+ }
1626
1752
  const buffer = this.getExecutionDebtBufferTime();
1627
1753
  const balance_avail = await this.balanceOf(signer.address);
1628
1754
  const max_shares = await this.maxRedemption(true, buffer);
1629
- const converted_shares = this.convertTokenInputToShares(amount);
1630
1755
  const maxExecutableShares = max_shares < balance_avail ? max_shares : balance_avail;
1631
1756
  let shares = maxExecutableShares < converted_shares ? maxExecutableShares : converted_shares;
1632
1757
  if (maxExecutableShares === balance_avail && balance_avail - shares <= 10n) {
1633
1758
  shares = balance_avail;
1634
1759
  }
1760
+ if (shares <= 0n) {
1761
+ throw new Error("No redeemable cToken shares available.");
1762
+ }
1635
1763
  const calldata = this.getCallData("redeem", [shares, receiver, owner]);
1636
1764
  return this.oracleRoute(calldata);
1637
1765
  }
1638
1766
  async redeemShares(amount) {
1767
+ if (amount <= 0n) {
1768
+ throw new Error("Redeem amount must be greater than zero.");
1769
+ }
1639
1770
  const signer = this.requireSigner();
1640
1771
  const receiver = signer.address;
1641
1772
  const owner = signer.address;
@@ -1759,7 +1890,7 @@ class CToken extends Calldata_1.Calldata {
1759
1890
  return null;
1760
1891
  }
1761
1892
  return {
1762
- token: new ERC20_1.ERC20(this.provider, instructions.inputToken, undefined, undefined, this.signer),
1893
+ token: new ERC20_1.ERC20(this.provider, instructions.inputToken, undefined, this.setup.contracts.OracleManager, this.signer),
1763
1894
  spender,
1764
1895
  spenderLabel: `${zapType} Zapper`,
1765
1896
  };
@@ -1823,10 +1954,11 @@ class CToken extends Calldata_1.Calldata {
1823
1954
  if (typeof tx.wait === "function") {
1824
1955
  await tx.wait();
1825
1956
  }
1826
- const refreshAccount = reloadAccount ?? signer.address;
1827
- await this.market.reloadUserData(refreshAccount, {
1828
- allowSignerMismatch: refreshAccount.toLowerCase() !== signer.address.toLowerCase(),
1829
- });
1957
+ const signerAddress = signer.address;
1958
+ const refreshAccount = reloadAccount?.toLowerCase() === signerAddress.toLowerCase()
1959
+ ? reloadAccount
1960
+ : signerAddress;
1961
+ await this.market.reloadUserData(refreshAccount);
1830
1962
  return tx;
1831
1963
  }
1832
1964
  async simulateOracleRoute(calldata, override = {}) {