@gearbox-protocol/sdk 16.3.2 → 16.4.0-next.10

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 (139) hide show
  1. package/dist/cjs/dev/index.js +3 -2
  2. package/dist/cjs/dev/kycUtils.js +18 -35
  3. package/dist/cjs/dev/midasUtils.js +40 -11
  4. package/dist/cjs/dev/securitizeUtils.js +14 -10
  5. package/dist/cjs/dev/withdrawalUtils.js +3 -6
  6. package/dist/cjs/model/errors/index.js +2 -0
  7. package/dist/cjs/model/errors/operation-errors.js +18 -0
  8. package/dist/cjs/model/index.js +2 -0
  9. package/dist/cjs/onchain/accounts/CreditAccountsServiceV310.js +0 -1
  10. package/dist/cjs/onchain/accounts/intents/borrow.js +139 -0
  11. package/dist/cjs/onchain/accounts/intents/collateral-valuation.js +41 -0
  12. package/dist/cjs/onchain/accounts/intents/guards.js +15 -3
  13. package/dist/cjs/onchain/accounts/intents/index.js +107 -20
  14. package/dist/cjs/onchain/accounts/intents/leverage-band.js +2 -12
  15. package/dist/cjs/onchain/accounts/intents/maxBorrow.js +89 -0
  16. package/dist/cjs/onchain/accounts/intents/maxWithdrawCollateral.js +15 -41
  17. package/dist/cjs/onchain/accounts/intents/open-strategy.js +6 -45
  18. package/dist/cjs/onchain/accounts/intents/realize.js +54 -2
  19. package/dist/cjs/onchain/accounts/intents/tail.js +1 -1
  20. package/dist/cjs/onchain/accounts/intents/testing/sdk-mock.js +1 -0
  21. package/dist/cjs/onchain/accounts/intents/utils/common.js +19 -0
  22. package/dist/cjs/onchain/accounts/intents/utils/credit-account-slice.js +21 -0
  23. package/dist/cjs/onchain/accounts/intents/utils/index.js +2 -0
  24. package/dist/cjs/onchain/accounts/intents/utils/price-impact.js +3 -3
  25. package/dist/cjs/onchain/accounts/intents/withdraw-limits.js +97 -0
  26. package/dist/cjs/onchain/core/createAddressProvider.js +2 -5
  27. package/dist/cjs/onchain/index.js +6 -0
  28. package/dist/cjs/onchain/market/adapters/abi/conctructorAbi.js +1 -1
  29. package/dist/cjs/onchain/market/adapters/contracts/MidasGatewayAdapterContract.js +11 -3
  30. package/dist/cjs/onchain/positions/calcHealthFactor.js +3 -3
  31. package/dist/cjs/onchain/preview/index.js +2 -0
  32. package/dist/cjs/onchain/preview/preview/index.js +2 -0
  33. package/dist/cjs/onchain/preview/preview/midasGreenlistsAccount.js +17 -0
  34. package/dist/cjs/onchain/preview/preview/previewOpenStrategyPosition.js +13 -16
  35. package/dist/cjs/onchain/preview/preview/previewOperation.js +19 -11
  36. package/dist/cjs/onchain/preview/preview/replayMulticall.js +4 -3
  37. package/dist/cjs/onchain/validation/bundles/checkCollateralFunding.js +3 -3
  38. package/dist/cjs/onchain/validation/bundles/checkCreditOperation.js +4 -3
  39. package/dist/cjs/onchain/validation/bundles/checkMidasAccountGreenlist.js +44 -0
  40. package/dist/cjs/onchain/validation/bundles/checkRWAOpening.js +16 -7
  41. package/dist/cjs/onchain/validation/bundles/index.js +2 -0
  42. package/dist/cjs/onchain/validation/checkOperation.js +0 -1
  43. package/dist/cjs/onchain/validation/checks/checkReservePriceLimited.js +30 -0
  44. package/dist/cjs/onchain/validation/checks/index.js +2 -0
  45. package/dist/cjs/onchain/validation/index.js +4 -0
  46. package/dist/cjs/sdk/execute/ExecuteApi.js +65 -5
  47. package/dist/cjs/sdk/prepare/PrepareApi.js +89 -14
  48. package/dist/esm/dev/index.js +3 -3
  49. package/dist/esm/dev/kycUtils.js +17 -33
  50. package/dist/esm/dev/midasUtils.js +39 -12
  51. package/dist/esm/dev/securitizeUtils.js +15 -11
  52. package/dist/esm/dev/withdrawalUtils.js +3 -6
  53. package/dist/esm/model/errors/index.js +2 -2
  54. package/dist/esm/model/errors/operation-errors.js +17 -1
  55. package/dist/esm/model/index.js +2 -2
  56. package/dist/esm/onchain/accounts/CreditAccountsServiceV310.js +0 -1
  57. package/dist/esm/onchain/accounts/intents/borrow.js +137 -0
  58. package/dist/esm/onchain/accounts/intents/collateral-valuation.js +40 -0
  59. package/dist/esm/onchain/accounts/intents/guards.js +15 -3
  60. package/dist/esm/onchain/accounts/intents/index.js +107 -20
  61. package/dist/esm/onchain/accounts/intents/leverage-band.js +2 -12
  62. package/dist/esm/onchain/accounts/intents/maxBorrow.js +87 -0
  63. package/dist/esm/onchain/accounts/intents/maxWithdrawCollateral.js +15 -41
  64. package/dist/esm/onchain/accounts/intents/open-strategy.js +6 -45
  65. package/dist/esm/onchain/accounts/intents/realize.js +54 -2
  66. package/dist/esm/onchain/accounts/intents/tail.js +1 -1
  67. package/dist/esm/onchain/accounts/intents/testing/sdk-mock.js +1 -0
  68. package/dist/esm/onchain/accounts/intents/utils/common.js +19 -1
  69. package/dist/esm/onchain/accounts/intents/utils/credit-account-slice.js +21 -1
  70. package/dist/esm/onchain/accounts/intents/utils/index.js +3 -3
  71. package/dist/esm/onchain/accounts/intents/utils/price-impact.js +3 -3
  72. package/dist/esm/onchain/accounts/intents/withdraw-limits.js +95 -0
  73. package/dist/esm/onchain/core/createAddressProvider.js +2 -5
  74. package/dist/esm/onchain/index.js +4 -1
  75. package/dist/esm/onchain/market/adapters/abi/conctructorAbi.js +1 -1
  76. package/dist/esm/onchain/market/adapters/contracts/MidasGatewayAdapterContract.js +11 -3
  77. package/dist/esm/onchain/positions/calcHealthFactor.js +3 -3
  78. package/dist/esm/onchain/preview/index.js +2 -1
  79. package/dist/esm/onchain/preview/preview/index.js +2 -1
  80. package/dist/esm/onchain/preview/preview/midasGreenlistsAccount.js +16 -0
  81. package/dist/esm/onchain/preview/preview/previewOpenStrategyPosition.js +14 -17
  82. package/dist/esm/onchain/preview/preview/previewOperation.js +19 -11
  83. package/dist/esm/onchain/preview/preview/replayMulticall.js +4 -3
  84. package/dist/esm/onchain/validation/bundles/checkCollateralFunding.js +3 -3
  85. package/dist/esm/onchain/validation/bundles/checkCreditOperation.js +4 -3
  86. package/dist/esm/onchain/validation/bundles/checkMidasAccountGreenlist.js +43 -0
  87. package/dist/esm/onchain/validation/bundles/checkRWAOpening.js +16 -7
  88. package/dist/esm/onchain/validation/bundles/index.js +2 -1
  89. package/dist/esm/onchain/validation/checkOperation.js +0 -1
  90. package/dist/esm/onchain/validation/checks/checkReservePriceLimited.js +29 -0
  91. package/dist/esm/onchain/validation/checks/index.js +2 -1
  92. package/dist/esm/onchain/validation/index.js +3 -1
  93. package/dist/esm/sdk/execute/ExecuteApi.js +65 -5
  94. package/dist/esm/sdk/prepare/PrepareApi.js +89 -14
  95. package/dist/types/dev/index.d.ts +3 -3
  96. package/dist/types/dev/kycUtils.d.ts +1 -5
  97. package/dist/types/dev/midasUtils.d.ts +11 -1
  98. package/dist/types/model/errors/index.d.ts +2 -2
  99. package/dist/types/model/errors/operation-errors.d.ts +54 -1
  100. package/dist/types/model/index.d.ts +3 -3
  101. package/dist/types/model/previews.d.ts +25 -19
  102. package/dist/types/onchain/accounts/index.d.ts +4 -3
  103. package/dist/types/onchain/accounts/intents/borrow.d.ts +141 -0
  104. package/dist/types/onchain/accounts/intents/collateral-valuation.d.ts +42 -0
  105. package/dist/types/onchain/accounts/intents/guards.d.ts +18 -2
  106. package/dist/types/onchain/accounts/intents/index.d.ts +102 -14
  107. package/dist/types/onchain/accounts/intents/maxBorrow.d.ts +54 -0
  108. package/dist/types/onchain/accounts/intents/maxWithdrawCollateral.d.ts +3 -8
  109. package/dist/types/onchain/accounts/intents/open-strategy.d.ts +3 -17
  110. package/dist/types/onchain/accounts/intents/testing/sdk-mock.d.ts +2 -0
  111. package/dist/types/onchain/accounts/intents/tests/open-strategy.fixtures.d.ts +2 -2
  112. package/dist/types/onchain/accounts/intents/types.d.ts +41 -5
  113. package/dist/types/onchain/accounts/intents/utils/common.d.ts +15 -1
  114. package/dist/types/onchain/accounts/intents/utils/credit-account-slice.d.ts +14 -1
  115. package/dist/types/onchain/accounts/intents/utils/index.d.ts +3 -3
  116. package/dist/types/onchain/accounts/intents/withdraw-limits.d.ts +80 -0
  117. package/dist/types/onchain/index.d.ts +8 -4
  118. package/dist/types/onchain/market/adapters/contracts/MidasGatewayAdapterContract.d.ts +8 -2
  119. package/dist/types/onchain/preview/index.d.ts +2 -1
  120. package/dist/types/onchain/preview/preview/index.d.ts +2 -1
  121. package/dist/types/onchain/preview/preview/midasGreenlistsAccount.d.ts +13 -0
  122. package/dist/types/onchain/preview/preview/previewOpenStrategyPosition.d.ts +5 -3
  123. package/dist/types/onchain/preview/preview/replayMulticall.d.ts +8 -7
  124. package/dist/types/onchain/validation/bundles/checkCreditOperation.d.ts +2 -2
  125. package/dist/types/onchain/validation/bundles/checkMidasAccountGreenlist.d.ts +22 -0
  126. package/dist/types/onchain/validation/bundles/checkRWAOpening.d.ts +6 -4
  127. package/dist/types/onchain/validation/bundles/index.d.ts +3 -2
  128. package/dist/types/onchain/validation/checks/checkDebtLimits.d.ts +2 -2
  129. package/dist/types/onchain/validation/checks/checkReservePriceLimited.d.ts +31 -0
  130. package/dist/types/onchain/validation/checks/index.d.ts +2 -1
  131. package/dist/types/onchain/validation/index.d.ts +4 -2
  132. package/dist/types/onchain/validation/raise.d.ts +2 -2
  133. package/dist/types/sdk/execute/index.d.ts +2 -2
  134. package/dist/types/sdk/execute/types.d.ts +48 -6
  135. package/dist/types/sdk/index.d.ts +5 -4
  136. package/dist/types/sdk/prepare/PrepareApi.d.ts +16 -4
  137. package/dist/types/sdk/prepare/index.d.ts +4 -3
  138. package/dist/types/sdk/prepare/types.d.ts +199 -65
  139. package/package.json +1 -1
@@ -43,7 +43,6 @@ async function checkOperation(input, options = {}) {
43
43
  sender
44
44
  }, options);
45
45
  case "OpenCreditAccount":
46
- case "RWAOpenCreditAccount":
47
46
  case "AdjustCreditAccount": return require_onchain_validation_bundles_checkCreditOperation.checkCreditOperation({
48
47
  sdk,
49
48
  preview,
@@ -0,0 +1,30 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_model_errors_operation_errors = require("../../../model/errors/operation-errors.js");
3
+ require("../../../model/index.js");
4
+ //#region src/onchain/validation/checks/checkReservePriceLimited.ts
5
+ /**
6
+ * Whether a failed collateral check is the reserve price feed's doing.
7
+ *
8
+ * A call that hands funds over is weighed at safe prices — `min` of a token's
9
+ * two feeds, and nothing at all where governance registered no reserve feed —
10
+ * so an account that covers its debt at the main feed can still be refused.
11
+ * The two are worth telling apart: a position that is genuinely too small is
12
+ * fixed by adding collateral or requesting less, while this one is a valuation
13
+ * the account does not control, and requesting less only helps as far as
14
+ * `withdrawable` says it does.
15
+ *
16
+ * Runs after `checkCollateralised` and answers only when that one refused, so
17
+ * the caller keeps its own threshold rather than restating it here.
18
+ */
19
+ function checkReservePriceLimited(args) {
20
+ const { healthFactor, atMainPrices, healthFactorThreshold, withdrawable } = args;
21
+ if (healthFactor >= healthFactorThreshold || atMainPrices < healthFactorThreshold) return [];
22
+ return [require_model_errors_operation_errors.reservePriceLimited({
23
+ healthFactor,
24
+ atMainPrices,
25
+ healthFactorThreshold,
26
+ withdrawable
27
+ })];
28
+ }
29
+ //#endregion
30
+ exports.checkReservePriceLimited = checkReservePriceLimited;
@@ -14,6 +14,7 @@ const require_onchain_validation_checks_checkPoolPaused = require("./checkPoolPa
14
14
  const require_onchain_validation_checks_checkPoolSunset = require("./checkPoolSunset.js");
15
15
  const require_onchain_validation_checks_checkQuotaCount = require("./checkQuotaCount.js");
16
16
  const require_onchain_validation_checks_checkQuotaLimit = require("./checkQuotaLimit.js");
17
+ const require_onchain_validation_checks_checkReservePriceLimited = require("./checkReservePriceLimited.js");
17
18
  exports.checkBorrowLimit = require_onchain_validation_checks_checkBorrowLimit.checkBorrowLimit;
18
19
  exports.checkCollateralised = require_onchain_validation_checks_checkCollateralised.checkCollateralised;
19
20
  exports.checkCreditAccountFrozen = require_onchain_validation_checks_checkCreditAccountFrozen.checkCreditAccountFrozen;
@@ -29,3 +30,4 @@ exports.checkPoolPaused = require_onchain_validation_checks_checkPoolPaused.chec
29
30
  exports.checkPoolSunset = require_onchain_validation_checks_checkPoolSunset.checkPoolSunset;
30
31
  exports.checkQuotaCount = require_onchain_validation_checks_checkQuotaCount.checkQuotaCount;
31
32
  exports.checkQuotaLimit = require_onchain_validation_checks_checkQuotaLimit.checkQuotaLimit;
33
+ exports.checkReservePriceLimited = require_onchain_validation_checks_checkReservePriceLimited.checkReservePriceLimited;
@@ -18,6 +18,7 @@ const require_onchain_validation_checks_checkPoolPaused = require("./checks/chec
18
18
  const require_onchain_validation_checks_checkPoolSunset = require("./checks/checkPoolSunset.js");
19
19
  const require_onchain_validation_checks_checkQuotaCount = require("./checks/checkQuotaCount.js");
20
20
  const require_onchain_validation_checks_checkQuotaLimit = require("./checks/checkQuotaLimit.js");
21
+ const require_onchain_validation_checks_checkReservePriceLimited = require("./checks/checkReservePriceLimited.js");
21
22
  require("./checks/index.js");
22
23
  const require_onchain_validation_bundles_checkAccountQuotas = require("./bundles/checkAccountQuotas.js");
23
24
  const require_onchain_validation_bundles_checkWalletAllowance = require("./bundles/checkWalletAllowance.js");
@@ -28,6 +29,7 @@ const require_onchain_validation_bundles_checkIncreaseDebt = require("./bundles/
28
29
  const require_onchain_validation_bundles_checkIncreaseQuota = require("./bundles/checkIncreaseQuota.js");
29
30
  const require_onchain_validation_bundles_checkMarket = require("./bundles/checkMarket.js");
30
31
  const require_onchain_validation_bundles_checkObtained = require("./bundles/checkObtained.js");
32
+ const require_onchain_validation_bundles_checkMidasAccountGreenlist = require("./bundles/checkMidasAccountGreenlist.js");
31
33
  const require_onchain_validation_bundles_checkRWAOpenRequirements = require("./bundles/checkRWAOpenRequirements.js");
32
34
  const require_onchain_validation_bundles_checkRWAOpening = require("./bundles/checkRWAOpening.js");
33
35
  const require_onchain_validation_bundles_checkCreditOperation = require("./bundles/checkCreditOperation.js");
@@ -66,6 +68,7 @@ exports.checkLiquidationFunding = require_onchain_validation_bundles_checkLiquid
66
68
  exports.checkLiquidatorEligible = require_onchain_validation_checks_checkLiquidatorEligible.checkLiquidatorEligible;
67
69
  exports.checkMarket = require_onchain_validation_bundles_checkMarket.checkMarket;
68
70
  exports.checkMarketExpired = require_onchain_validation_checks_checkMarketExpired.checkMarketExpired;
71
+ exports.checkMidasAccountGreenlist = require_onchain_validation_bundles_checkMidasAccountGreenlist.checkMidasAccountGreenlist;
69
72
  exports.checkObtained = require_onchain_validation_bundles_checkObtained.checkObtained;
70
73
  exports.checkOperation = require_onchain_validation_checkOperation.checkOperation;
71
74
  exports.checkPoolFunding = require_onchain_validation_bundles_checkPoolFunding.checkPoolFunding;
@@ -77,6 +80,7 @@ exports.checkQuotaCount = require_onchain_validation_checks_checkQuotaCount.chec
77
80
  exports.checkQuotaLimit = require_onchain_validation_checks_checkQuotaLimit.checkQuotaLimit;
78
81
  exports.checkRWAOpenRequirements = require_onchain_validation_bundles_checkRWAOpenRequirements.checkRWAOpenRequirements;
79
82
  exports.checkRWAOpening = require_onchain_validation_bundles_checkRWAOpening.checkRWAOpening;
83
+ exports.checkReservePriceLimited = require_onchain_validation_checks_checkReservePriceLimited.checkReservePriceLimited;
80
84
  exports.checkSimulation = require_onchain_validation_checkSimulation.checkSimulation;
81
85
  exports.checkWallet = require_onchain_validation_bundles_checkWallet.checkWallet;
82
86
  exports.checkWalletAllowance = require_onchain_validation_bundles_checkWalletAllowance.checkWalletAllowance;
@@ -17,6 +17,8 @@ var ExecuteApi = class {
17
17
  switch (request.kind) {
18
18
  case "pool": return poolTx(sdk, request);
19
19
  case "open": return openTx(sdk, request);
20
+ case "openEmpty": return openEmptyTx(sdk, request);
21
+ case "borrow": return borrowTx(sdk, request);
20
22
  case "account": return accountTx(sdk, request);
21
23
  }
22
24
  }
@@ -63,17 +65,75 @@ async function openTx(sdk, request) {
63
65
  reopenCreditAccount: state.creditAccount,
64
66
  permits: {},
65
67
  referralCode: 0n,
66
- rwaOptions: await openRwaOptions(sdk, request)
68
+ rwaOptions: await openRwaOptions(sdk, request, request.targetToken)
69
+ });
70
+ }
71
+ /**
72
+ * The opening with nothing in it: no debt to draw, no collateral to take, no
73
+ * path to run and no quota to buy, so `openCA` is left with the price updates
74
+ * the market demands and the facade's own `openCreditAccount`.
75
+ *
76
+ * Nothing is read off the preparation because there is nothing on it. The
77
+ * account holds no token, so an RWA market has none to gate on either.
78
+ **/
79
+ function openEmptyTx(sdk, request) {
80
+ return sdk.accounts.openCA({
81
+ creditManager: request.creditManager,
82
+ to: request.wallet,
83
+ collateral: [],
84
+ ethAmount: 0n,
85
+ debt: 0n,
86
+ calls: [],
87
+ averageQuota: [],
88
+ minQuota: [],
89
+ permits: {},
90
+ referralCode: 0n
91
+ });
92
+ }
93
+ /**
94
+ * A loan is an opening whose debt leaves again, so it is the same `openCA`
95
+ * with `withdrawToken` set: the facade draws the debt, takes the collateral,
96
+ * runs whatever path buys the payout, and sweeps that payout to the wallet.
97
+ *
98
+ * Both quota branches are the one the state carries. An opening has two
99
+ * because the balances it lands on are a router quote; here the account is
100
+ * left holding the collateral the caller named, and a named amount has no
101
+ * floor to differ from.
102
+ **/
103
+ async function borrowTx(sdk, request) {
104
+ const { creditManager, wallet, ethAmount, sim } = request;
105
+ const { state } = sim.data;
106
+ const collateral = {
107
+ token: state.collateral.token.address,
108
+ balance: state.collateral.value
109
+ };
110
+ return sdk.accounts.openCA({
111
+ creditManager,
112
+ to: wallet,
113
+ collateral: [collateral],
114
+ ethAmount,
115
+ debt: state.totalDebt.value,
116
+ calls: state.calls,
117
+ withdrawToken: state.borrowed.token.address,
118
+ averageQuota: state.quotaIncrease,
119
+ minQuota: state.quotaIncrease,
120
+ reopenCreditAccount: state.creditAccount,
121
+ permits: {},
122
+ referralCode: 0n,
123
+ rwaOptions: await openRwaOptions(sdk, request, collateral.token)
67
124
  });
68
125
  }
69
126
  /**
70
127
  * The documented `openCA` contract: ask the market for its open requirements
71
128
  * and hand them back as operation args, with the caller's cached signatures
72
- * attached. `undefined` on non-RWA markets and when no target token is named.
129
+ * attached. `undefined` on non-RWA markets and when no token is named.
130
+ *
131
+ * `token` is the one the account ends up holding, which is what an RWA market
132
+ * gates on: the opening's target, and the borrow's collateral.
73
133
  **/
74
- async function openRwaOptions(sdk, request) {
75
- if (!request.targetToken) return;
76
- const requirements = await sdk.accounts.getOpenAccountRequirements(request.wallet, request.creditManager, { tokenOutAddress: request.targetToken });
134
+ async function openRwaOptions(sdk, request, token) {
135
+ if (!token) return;
136
+ const requirements = await sdk.accounts.getOpenAccountRequirements(request.wallet, request.creditManager, { tokenOutAddress: token });
77
137
  if (requirements?.protocol !== "securitize") return;
78
138
  return {
79
139
  protocol: "securitize",
@@ -196,26 +196,33 @@ var PrepareApi = class extends require_onchain_base_MultichainConstruct.Multicha
196
196
  }
197
197
  }
198
198
  /**
199
+ * {@inheritDoc IOpportunitiesPrepare.openEmptyCreditAccount}
200
+ **/
201
+ async openEmptyCreditAccount(strategy) {
202
+ try {
203
+ const sdk = await this.#chain(strategy.chainId);
204
+ const at = stateBlock(sdk);
205
+ const result = await service(sdk).openEmptyAccountIntent({
206
+ sdk,
207
+ creditManager: strategy.creditManager
208
+ });
209
+ return result.ok ? require_model_result.sdkOk(at) : methodError(result);
210
+ } catch (e) {
211
+ return require_model_result.sdkErr(require_model_errors_prepare_errors.unexpectedFailure(e));
212
+ }
213
+ }
214
+ /**
199
215
  * {@inheritDoc IOpportunitiesPrepare.openNewStrategy}
200
216
  **/
201
217
  async openNewStrategy(strategy, params) {
202
218
  try {
203
219
  const sdk = await this.#chain(strategy.chainId);
204
220
  const at = stateBlock(sdk);
205
- if (params.empty) return opened(await service(sdk).openStrategyIntent({
206
- sdk,
207
- creditManager: strategy.creditManager,
208
- empty: true
209
- }), at);
210
221
  const targetToken = params.targetToken ?? sdk.marketRegister.findCreditManager(strategy.creditManager).strategyTargetCollateral;
211
222
  if (!targetToken) return require_model_result.sdkErr(require_model_errors_prepare_errors.noStrategyTargetCollateral(strategy.creditManager));
212
- let creditAccount;
213
- if (params.creditAccount) {
214
- const reused = await slice(sdk, params.creditAccount);
215
- if (!reused || !(0, viem.isAddressEqual)(reused.creditManager, strategy.creditManager)) return require_model_result.sdkErr(require_model_errors_prepare_errors.creditAccountNotFound(params.creditAccount));
216
- if (reused.totalDebt > 0n || reused.tokens.some((t) => t.quota > 0n)) return require_model_result.sdkErr(require_model_errors_prepare_errors.creditAccountNotEmpty(params.creditAccount));
217
- creditAccount = reused;
218
- }
223
+ const reused = await reusable(sdk, strategy, params.creditAccount);
224
+ if (reused && "error" in reused) return reused;
225
+ const creditAccount = reused?.account;
219
226
  return opened(await service(sdk).openStrategyIntent({
220
227
  sdk,
221
228
  creditManager: strategy.creditManager,
@@ -232,6 +239,30 @@ var PrepareApi = class extends require_onchain_base_MultichainConstruct.Multicha
232
239
  }
233
240
  }
234
241
  /**
242
+ * {@inheritDoc IOpportunitiesPrepare.borrow}
243
+ **/
244
+ async borrow(strategy, params) {
245
+ try {
246
+ const sdk = await this.#chain(strategy.chainId);
247
+ const at = stateBlock(sdk);
248
+ const reused = await reusable(sdk, strategy, params.creditAccount);
249
+ if (reused && "error" in reused) return reused;
250
+ return borrowed(await service(sdk).borrowIntent({
251
+ sdk,
252
+ creditManager: strategy.creditManager,
253
+ collateralToken: params.collateralToken,
254
+ collateralAmount: params.collateralAmount,
255
+ borrowToken: params.borrowToken,
256
+ borrowAmount: params.borrowAmount,
257
+ slippage: params.slippage,
258
+ quotaReserve: params.quotaReserve,
259
+ creditAccount: reused?.account
260
+ }), at);
261
+ } catch (e) {
262
+ return require_model_result.sdkErr(require_model_errors_prepare_errors.unexpectedFailure(e));
263
+ }
264
+ }
265
+ /**
235
266
  * {@inheritDoc IOpportunitiesPrepare.depositStrategy}
236
267
  **/
237
268
  async depositStrategy(position, params) {
@@ -259,12 +290,13 @@ var PrepareApi = class extends require_onchain_base_MultichainConstruct.Multicha
259
290
  /**
260
291
  * {@inheritDoc IOpportunitiesPrepare.maxWithdraw}
261
292
  **/
262
- async maxWithdraw(position) {
293
+ async maxWithdraw(position, sourceToken) {
263
294
  const sdk = await this.#chain(position.chainId);
264
295
  const creditAccount = await this.#account(sdk, position);
265
296
  return service(sdk).maxWithdraw({
266
297
  creditAccount,
267
- sdk
298
+ sdk,
299
+ sourceToken
268
300
  });
269
301
  }
270
302
  /**
@@ -353,6 +385,21 @@ var PrepareApi = class extends require_onchain_base_MultichainConstruct.Multicha
353
385
  });
354
386
  }
355
387
  /**
388
+ * {@inheritDoc IOpportunitiesPrepare.maxBorrow}
389
+ **/
390
+ maxBorrow(strategy, params) {
391
+ const sdk = this.sdk.chain(strategy.chainId);
392
+ return service(sdk).maxBorrow({
393
+ sdk,
394
+ creditManager: strategy.creditManager,
395
+ collateralToken: params.collateralToken,
396
+ collateralAmount: params.collateralAmount,
397
+ borrowToken: params.borrowToken,
398
+ targetHF: params.targetHF,
399
+ quotaReserve: params.quotaReserve
400
+ });
401
+ }
402
+ /**
356
403
  * The account a bare `max*` read weighs. These reads answer a number, not
357
404
  * an envelope, so an account the markets do not hold is thrown rather than
358
405
  * described, see {@link IOpportunitiesPrepare.maxWithdraw}.
@@ -438,6 +485,25 @@ async function slice(sdk, creditAccount) {
438
485
  return data && require_onchain_accounts_intents_utils_credit_account_slice.toCreditAccountSlice(data);
439
486
  }
440
487
  /**
488
+ * The pre-opened account a request asks to be run on, held to what "pre-opened"
489
+ * means: this manager's, owing nothing and holding no quota.
490
+ *
491
+ * Shared by the two flows that put something on a fresh account — an opening
492
+ * and a borrow — so both hold a reused one to the same terms. Whatever
493
+ * balances sit on it are left to the flow: an opening routes them, a borrow
494
+ * leaves them where they are.
495
+ *
496
+ * @returns Nothing when the request named no account, the refusal to answer
497
+ * with when it named one that does not qualify, and the slice otherwise
498
+ **/
499
+ async function reusable(sdk, strategy, creditAccount) {
500
+ if (!creditAccount) return;
501
+ const account = await slice(sdk, creditAccount);
502
+ if (!account || !(0, viem.isAddressEqual)(account.creditManager, strategy.creditManager)) return require_model_result.sdkErr(require_model_errors_prepare_errors.creditAccountNotFound(creditAccount));
503
+ if (account.totalDebt > 0n || account.tokens.some((t) => t.quota > 0n)) return require_model_result.sdkErr(require_model_errors_prepare_errors.creditAccountNotEmpty(creditAccount));
504
+ return { account };
505
+ }
506
+ /**
441
507
  * The operation a claim resumes, or `undefined` when there is none to resume:
442
508
  * a withdrawal requested without an intent, or one read through a compressor
443
509
  * too old to report it. Every intent the engine records can be finished,
@@ -537,6 +603,15 @@ function opened(result, at) {
537
603
  }
538
604
  /**
539
605
  * {@inheritDoc planned}
606
+ **/
607
+ function borrowed(result, at) {
608
+ return result.ok ? require_model_result.sdkOk({
609
+ state: result.state,
610
+ ...at
611
+ }) : methodError(result);
612
+ }
613
+ /**
614
+ * {@inheritDoc planned}
540
615
  *
541
616
  * Both routes are payload, error and all: `errors` says why a missing one is
542
617
  * missing, and it stays on the error when neither route answered, since that is
@@ -13,10 +13,10 @@ import { detectChain } from "./detectChain.js";
13
13
  import { isOutOfSyncError } from "./isOutOfSyncError.js";
14
14
  import { isRateLimitError } from "./isRateLimitError.js";
15
15
  import { isTransientError } from "./isTransientError.js";
16
- import { greenlistMidasGateway, registerMidasInvestor, registerRWAInvestor, registerSecuritizeInvestor, writeAndWait } from "./kycUtils.js";
16
+ import { collectMidasGateways, collectMidasMTokens, unpauseMidasIssuanceVault } from "./midasUtils.js";
17
+ import { greenlistMidasGateway, registerMidasInvestor, registerRWAInvestor, registerSecuritizeInvestor } from "./kycUtils.js";
17
18
  import { isRangeError, logSplitterTransport } from "./logSplitterTransport.js";
18
19
  import { setLTZero, setLTs } from "./ltUtils.js";
19
- import { unpauseMidasIssuanceVault } from "./midasUtils.js";
20
20
  import { migrateFaucet } from "./migrateFaucet.js";
21
21
  import { SUPPORTED_RPC_PROVIDERS, getAlchemyUrl, getAnkrUrl, getDrpcUrl, getErpcKey, getRpcProviderUrl, getThirdWebUrl, rpcProvidersSchema } from "./providers.js";
22
22
  import { replaceStorage } from "./replaceStorage.js";
@@ -25,4 +25,4 @@ import { claimDSToken, claimDSTokens, enableDSTokenBackDating } from "./securiti
25
25
  import "./types.js";
26
26
  import { ONCHAIN_EXECUTION_ID_ADDRESS, verifyTestnet } from "./verifyTestnet.js";
27
27
  import { makePendingWithdrawalsClaimable } from "./withdrawalUtils.js";
28
- export { AccountOpener, Create2Deployer, DEFAULT_CREATE2_SALT, EthCallSpy, NoAvailableTransportsError, ONCHAIN_EXECUTION_ID_ADDRESS, OpenTxRevertedError, PUBLIC_CREATE2_FACTORY, RevolverTransport, SUPPORTED_RPC_PROVIDERS, SelectionStrategy, anvilNodeInfo, calcLiquidatableLTs, claimDSToken, claimDSTokens, claimFromFaucet, createAnvilClient, createMinter, deployUsingPublicCreate2, detectChain, enableDSTokenBackDating, evmMineDetailed, extendAnvilClient, getAlchemyUrl, getAnkrUrl, getDrpcUrl, getErpcKey, getPublicCreate2Address, getRpcProviderUrl, getThirdWebUrl, greenlistMidasGateway, httpTransportOptionsSchema, iDegenNftv2Abi, iFaucetAbi, iOnchainExecutionIdAbi, iOwnableAbi, iaclTraitAbi, isAnvil, isDeployedUsingPublicCreate2, isOutOfSyncError, isRangeError, isRateLimitError, isTransientError, logSplitterTransport, makePendingWithdrawalsClaimable, migrateFaucet, providerConfigSchema, registerMidasInvestor, registerRWAInvestor, registerSecuritizeInvestor, replaceStorage, resilientTransport, resilientTransportOptionsSchema, revolverTransportConfigBaseSchema, revolverTransportConfigSchema, rpcProvidersSchema, setLTZero, setLTs, unpauseMidasIssuanceVault, verifyTestnet, writeAndWait };
28
+ export { AccountOpener, Create2Deployer, DEFAULT_CREATE2_SALT, EthCallSpy, NoAvailableTransportsError, ONCHAIN_EXECUTION_ID_ADDRESS, OpenTxRevertedError, PUBLIC_CREATE2_FACTORY, RevolverTransport, SUPPORTED_RPC_PROVIDERS, SelectionStrategy, anvilNodeInfo, calcLiquidatableLTs, claimDSToken, claimDSTokens, claimFromFaucet, collectMidasGateways, collectMidasMTokens, createAnvilClient, createMinter, deployUsingPublicCreate2, detectChain, enableDSTokenBackDating, evmMineDetailed, extendAnvilClient, getAlchemyUrl, getAnkrUrl, getDrpcUrl, getErpcKey, getPublicCreate2Address, getRpcProviderUrl, getThirdWebUrl, greenlistMidasGateway, httpTransportOptionsSchema, iDegenNftv2Abi, iFaucetAbi, iOnchainExecutionIdAbi, iOwnableAbi, iaclTraitAbi, isAnvil, isDeployedUsingPublicCreate2, isOutOfSyncError, isRangeError, isRateLimitError, isTransientError, logSplitterTransport, makePendingWithdrawalsClaimable, migrateFaucet, providerConfigSchema, registerMidasInvestor, registerRWAInvestor, registerSecuritizeInvestor, replaceStorage, resilientTransport, resilientTransportOptionsSchema, revolverTransportConfigBaseSchema, revolverTransportConfigSchema, rpcProvidersSchema, setLTZero, setLTs, unpauseMidasIssuanceVault, verifyTestnet };
@@ -4,23 +4,12 @@ import { OnchainSDK } from "../onchain/OnchainSDK.js";
4
4
  import "../onchain/index.js";
5
5
  import { iDSRegistryServiceAbi } from "../abi/rwa/iDSRegistryService.js";
6
6
  import { iDSTokenAbi } from "../abi/rwa/iDSToken.js";
7
+ import { collectMidasGateways } from "./midasUtils.js";
7
8
  import { midasGatewayAbi } from "./withdrawalAbi.js";
8
9
  import { isAddressEqual, parseAbi, parseEther, zeroAddress } from "viem";
9
10
  import { privateKeyToAccount } from "viem/accounts";
10
11
  //#region src/dev/kycUtils.ts
11
12
  /**
12
- * Writes to a contract, mines a block and waits for the receipt
13
- */
14
- async function writeAndWait(anvil, params) {
15
- const hash = await anvil.writeContract(params);
16
- await anvil.mine({ blocks: 1 });
17
- await anvil.waitForTransactionReceipt({
18
- hash,
19
- pollingInterval: 100
20
- });
21
- return hash;
22
- }
23
- /**
24
13
  * Resolves the account that performs the DS registry writes: either the admin
25
14
  * private key, or the admin address impersonated on the fork
26
15
  */
@@ -98,36 +87,39 @@ async function registerSecuritizeInvestor(props) {
98
87
  const { account, release } = await useSecuritizeAdmin(props);
99
88
  try {
100
89
  if (!investorExists) {
101
- await writeAndWait(anvil, {
90
+ await anvil.writeContractSync({
102
91
  account,
103
92
  chain: anvil.chain,
104
93
  address: registryService,
105
94
  abi: iDSRegistryServiceAbi,
106
95
  functionName: "registerInvestor",
107
- args: [investorId, investorId]
96
+ args: [investorId, investorId],
97
+ throwOnReceiptRevert: true
108
98
  });
109
99
  logger?.debug(`Registered investor "${investorId}"`);
110
100
  }
111
- await writeAndWait(anvil, {
101
+ await anvil.writeContractSync({
112
102
  account,
113
103
  chain: anvil.chain,
114
104
  address: registryService,
115
105
  abi: iDSRegistryServiceAbi,
116
106
  functionName: "addWallet",
117
- args: [investor, investorId]
107
+ args: [investor, investorId],
108
+ throwOnReceiptRevert: true
118
109
  });
119
110
  logger?.debug(`Added wallet ${investor} for investor "${investorId}"`);
120
111
  try {
121
- await writeAndWait(anvil, {
112
+ await anvil.writeContractSync({
122
113
  account,
123
114
  chain: anvil.chain,
124
115
  address: registryService,
125
116
  abi: iDSRegistryServiceAbi,
126
117
  functionName: "setCountry",
127
- args: [investorId, "US"]
118
+ args: [investorId, "US"],
119
+ throwOnReceiptRevert: true
128
120
  });
129
121
  logger?.debug(`Set country for investor "${investorId}" to "US"`);
130
- await writeAndWait(anvil, {
122
+ await anvil.writeContractSync({
131
123
  account,
132
124
  chain: anvil.chain,
133
125
  address: registryService,
@@ -139,7 +131,8 @@ async function registerSecuritizeInvestor(props) {
139
131
  BigInt(APPROVED),
140
132
  MAX_UINT256,
141
133
  "fake proof"
142
- ]
134
+ ],
135
+ throwOnReceiptRevert: true
143
136
  });
144
137
  logger?.debug(`Set attributes for investor "${investorId}"`);
145
138
  } catch (e) {
@@ -241,13 +234,14 @@ async function greenlistMidasGateway(props) {
241
234
  logger?.debug(`midas: ${account} already has role ${role}`);
242
235
  continue;
243
236
  }
244
- await writeAndWait(anvil, {
237
+ await anvil.writeContractSync({
245
238
  account: admin,
246
239
  chain: anvil.chain,
247
240
  address: accessControl,
248
241
  abi: iMidasAccessControlAbi,
249
242
  functionName: "grantRole",
250
- args: [role, account]
243
+ args: [role, account],
244
+ throwOnReceiptRevert: true
251
245
  });
252
246
  logger?.debug(`midas: granted role ${role} to ${account}`);
253
247
  }
@@ -294,16 +288,6 @@ async function findMidasGateway(props) {
294
288
  return candidates[index];
295
289
  }
296
290
  /**
297
- * Collects the target contracts of all Midas gateway adapters of the loaded
298
- * credit managers, same as the foundry tests do with
299
- * `ICreditConfiguratorV3.allowedAdapters`
300
- */
301
- function collectMidasGateways(sdk) {
302
- const gateways = new AddressSet();
303
- for (const cm of sdk.marketRegister.creditManagers) for (const adapter of cm.creditManager.adapters.values()) if (adapter.contractType === "ADAPTER::MIDAS_GATEWAY") gateways.add(adapter.targetContract);
304
- return gateways.asArray();
305
- }
306
- /**
307
291
  * Registers a wallet as an investor (fake KYC) in every Securitize DSToken and
308
292
  * every Midas gateway of the markets loaded by `sdk`.
309
293
  *
@@ -361,4 +345,4 @@ async function registerRWAInvestor(props) {
361
345
  };
362
346
  }
363
347
  //#endregion
364
- export { greenlistMidasGateway, registerMidasInvestor, registerRWAInvestor, registerSecuritizeInvestor, writeAndWait };
348
+ export { greenlistMidasGateway, registerMidasInvestor, registerRWAInvestor, registerSecuritizeInvestor };
@@ -1,4 +1,6 @@
1
- import { writeAndWait } from "./kycUtils.js";
1
+ import { AddressSet } from "../onchain/utils/AddressSet.js";
2
+ import { MidasGatewayAdapterContract } from "../onchain/market/adapters/contracts/MidasGatewayAdapterContract.js";
3
+ import "../onchain/index.js";
2
4
  import { parseAbi, parseEther, toFunctionSelector } from "viem";
3
5
  //#region src/dev/midasUtils.ts
4
6
  /**
@@ -77,30 +79,33 @@ async function unpauseMidasIssuanceVault(props) {
77
79
  value: parseEther("100")
78
80
  });
79
81
  if (!isPauseAdmin) {
80
- await writeAndWait(anvil, {
82
+ await anvil.writeContractSync({
81
83
  account: admin,
82
84
  chain: anvil.chain,
83
85
  address: accessControl,
84
86
  abi: iMidasAccessControlAbi,
85
87
  functionName: "grantRole",
86
- args: [pauseAdminRole, admin]
88
+ args: [pauseAdminRole, admin],
89
+ throwOnReceiptRevert: true
87
90
  });
88
91
  logger?.debug(`midas: granted pause admin role to ${admin}`);
89
92
  }
90
- if (paused) await writeAndWait(anvil, {
93
+ if (paused) await anvil.writeContractSync({
91
94
  account: admin,
92
95
  chain: anvil.chain,
93
96
  address: vault,
94
97
  abi: iMidasPausableVaultAbi,
95
- functionName: "unpause"
98
+ functionName: "unpause",
99
+ throwOnReceiptRevert: true
96
100
  });
97
- if (depositInstantPaused) await writeAndWait(anvil, {
101
+ if (depositInstantPaused) await anvil.writeContractSync({
98
102
  account: admin,
99
103
  chain: anvil.chain,
100
104
  address: vault,
101
105
  abi: iMidasPausableVaultAbi,
102
106
  functionName: "unpauseFn",
103
- args: [DEPOSIT_INSTANT_SELECTOR]
107
+ args: [DEPOSIT_INSTANT_SELECTOR],
108
+ throwOnReceiptRevert: true
104
109
  });
105
110
  } finally {
106
111
  await anvil.stopImpersonatingAccount({ address: admin });
@@ -116,20 +121,22 @@ async function unpauseMidasIssuanceVault(props) {
116
121
  address: admin,
117
122
  value: parseEther("100")
118
123
  });
119
- if (paused) await writeAndWait(anvil, {
124
+ if (paused) await anvil.writeContractSync({
120
125
  account: admin,
121
126
  chain: anvil.chain,
122
127
  address: vault,
123
128
  abi: iMidasPausableVaultAbi,
124
- functionName: "pause"
129
+ functionName: "pause",
130
+ throwOnReceiptRevert: true
125
131
  });
126
- if (depositInstantPaused) await writeAndWait(anvil, {
132
+ if (depositInstantPaused) await anvil.writeContractSync({
127
133
  account: admin,
128
134
  chain: anvil.chain,
129
135
  address: vault,
130
136
  abi: iMidasPausableVaultAbi,
131
137
  functionName: "pauseFn",
132
- args: [DEPOSIT_INSTANT_SELECTOR]
138
+ args: [DEPOSIT_INSTANT_SELECTOR],
139
+ throwOnReceiptRevert: true
133
140
  });
134
141
  } catch (e) {
135
142
  logger?.warn(`midas: failed to pause issuance vault ${vault} back: ${e}`);
@@ -138,5 +145,25 @@ async function unpauseMidasIssuanceVault(props) {
138
145
  }
139
146
  };
140
147
  }
148
+ function* midasGatewayAdapters(sdk) {
149
+ for (const cm of sdk.marketRegister.creditManagers) for (const adapter of cm.creditManager.adapters.values()) if (adapter instanceof MidasGatewayAdapterContract) yield adapter;
150
+ }
151
+ /**
152
+ * Target contracts of all Midas gateway adapters of the loaded credit managers,
153
+ * same as the foundry tests do with `ICreditConfiguratorV3.allowedAdapters`
154
+ */
155
+ function collectMidasGateways(sdk) {
156
+ const gateways = new AddressSet();
157
+ for (const adapter of midasGatewayAdapters(sdk)) gateways.add(adapter.targetContract);
158
+ return gateways.asArray();
159
+ }
160
+ /**
161
+ * mTokens of all Midas gateway adapters of the loaded credit managers
162
+ */
163
+ function collectMidasMTokens(sdk) {
164
+ const mTokens = new AddressSet();
165
+ for (const adapter of midasGatewayAdapters(sdk)) mTokens.add(adapter.mToken);
166
+ return mTokens.asArray();
167
+ }
141
168
  //#endregion
142
- export { unpauseMidasIssuanceVault };
169
+ export { collectMidasGateways, collectMidasMTokens, unpauseMidasIssuanceVault };
@@ -2,7 +2,7 @@ import { AddressSet } from "../onchain/utils/AddressSet.js";
2
2
  import { OnchainSDK } from "../onchain/OnchainSDK.js";
3
3
  import "../onchain/index.js";
4
4
  import { iDSTokenAbi } from "../abi/rwa/iDSToken.js";
5
- import { registerSecuritizeInvestor, writeAndWait } from "./kycUtils.js";
5
+ import { registerSecuritizeInvestor } from "./kycUtils.js";
6
6
  import { erc20Abi, isAddressEqual, parseAbi, zeroAddress } from "viem";
7
7
  import { privateKeyToAccount } from "viem/accounts";
8
8
  //#region src/dev/securitizeUtils.ts
@@ -64,7 +64,7 @@ async function issueDSTokens(props) {
64
64
  const { timestamp } = await anvil.getBlock();
65
65
  const issuanceTime = timestamp - lockPeriod - 1n;
66
66
  try {
67
- const hash = await writeAndWait(anvil, {
67
+ const receipt = await anvil.writeContractSync({
68
68
  account,
69
69
  chain: anvil.chain,
70
70
  address: token,
@@ -77,14 +77,15 @@ async function issueDSTokens(props) {
77
77
  0n,
78
78
  "",
79
79
  0n
80
- ]
80
+ ],
81
+ throwOnReceiptRevert: true
81
82
  });
82
83
  logger?.debug({
83
84
  issuanceTime,
84
85
  investor,
85
86
  amount
86
87
  }, "issueTokensCustom successful");
87
- return hash;
88
+ return receipt.transactionHash;
88
89
  } catch (e) {
89
90
  logger?.debug(`issueTokensCustom failed: ${e}`);
90
91
  }
@@ -93,14 +94,15 @@ async function issueDSTokens(props) {
93
94
  investor,
94
95
  amount
95
96
  }, "Falling back to issueTokens");
96
- return writeAndWait(anvil, {
97
+ return (await anvil.writeContractSync({
97
98
  account,
98
99
  chain: anvil.chain,
99
100
  address: token,
100
101
  abi: iDSTokenAbi,
101
102
  functionName: "issueTokens",
102
- args: [investor, amount]
103
- });
103
+ args: [investor, amount],
104
+ throwOnReceiptRevert: true
105
+ })).transactionHash;
104
106
  }
105
107
  /**
106
108
  * Resolves unique compliance configuration services of `tokens`: several
@@ -160,13 +162,14 @@ async function enableDSTokenBackDating(props) {
160
162
  continue;
161
163
  }
162
164
  logger?.info(`Allowing back-dating on ${service}`);
163
- await writeAndWait(anvil, {
165
+ await anvil.writeContractSync({
164
166
  account,
165
167
  chain: anvil.chain,
166
168
  address: service,
167
169
  abi: iDSComplianceConfigurationServiceAbi,
168
170
  functionName: "setDisallowBackDating",
169
- args: [false]
171
+ args: [false],
172
+ throwOnReceiptRevert: true
170
173
  });
171
174
  toRestore.push(service);
172
175
  }
@@ -176,13 +179,14 @@ async function enableDSTokenBackDating(props) {
176
179
  for (const service of services) {
177
180
  logger?.info(`Disallowing back-dating on ${service}`);
178
181
  try {
179
- await writeAndWait(anvil, {
182
+ await anvil.writeContractSync({
180
183
  account,
181
184
  chain: anvil.chain,
182
185
  address: service,
183
186
  abi: iDSComplianceConfigurationServiceAbi,
184
187
  functionName: "setDisallowBackDating",
185
- args: [true]
188
+ args: [true],
189
+ throwOnReceiptRevert: true
186
190
  });
187
191
  } catch (e) {
188
192
  logger?.warn(`Failed to restore disallowBackDating on ${service}: ${e}`);