@gearbox-protocol/sdk 16.4.0-next.1 → 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 (115) 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 +80 -16
  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 +1 -0
  7. package/dist/cjs/model/errors/operation-errors.js +9 -0
  8. package/dist/cjs/model/index.js +1 -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-money.js → collateral-valuation.js} +7 -7
  12. package/dist/cjs/onchain/accounts/intents/index.js +86 -2
  13. package/dist/cjs/onchain/accounts/intents/leverage-band.js +2 -12
  14. package/dist/cjs/onchain/accounts/intents/maxBorrow.js +89 -0
  15. package/dist/cjs/onchain/accounts/intents/maxWithdrawCollateral.js +14 -14
  16. package/dist/cjs/onchain/accounts/intents/open-strategy.js +6 -45
  17. package/dist/cjs/onchain/accounts/intents/realize.js +44 -0
  18. package/dist/cjs/onchain/accounts/intents/testing/sdk-mock.js +1 -0
  19. package/dist/cjs/onchain/accounts/intents/utils/common.js +19 -0
  20. package/dist/cjs/onchain/accounts/intents/utils/credit-account-slice.js +21 -0
  21. package/dist/cjs/onchain/accounts/intents/utils/index.js +2 -0
  22. package/dist/cjs/onchain/accounts/intents/utils/price-impact.js +3 -3
  23. package/dist/cjs/onchain/accounts/intents/withdraw-limits.js +8 -8
  24. package/dist/cjs/onchain/core/createAddressProvider.js +2 -5
  25. package/dist/cjs/onchain/index.js +4 -0
  26. package/dist/cjs/onchain/market/adapters/contracts/MidasGatewayAdapterContract.js +11 -3
  27. package/dist/cjs/onchain/positions/calcHealthFactor.js +3 -3
  28. package/dist/cjs/onchain/preview/index.js +2 -0
  29. package/dist/cjs/onchain/preview/preview/index.js +2 -0
  30. package/dist/cjs/onchain/preview/preview/midasGreenlistsAccount.js +17 -0
  31. package/dist/cjs/onchain/preview/preview/previewOpenStrategyPosition.js +5 -2
  32. package/dist/cjs/onchain/validation/bundles/checkCreditOperation.js +2 -1
  33. package/dist/cjs/onchain/validation/bundles/checkMidasAccountGreenlist.js +44 -0
  34. package/dist/cjs/onchain/validation/bundles/checkRWAOpening.js +15 -5
  35. package/dist/cjs/onchain/validation/bundles/index.js +2 -0
  36. package/dist/cjs/onchain/validation/index.js +2 -0
  37. package/dist/cjs/sdk/execute/ExecuteApi.js +65 -5
  38. package/dist/cjs/sdk/prepare/PrepareApi.js +86 -12
  39. package/dist/esm/dev/index.js +3 -3
  40. package/dist/esm/dev/kycUtils.js +17 -33
  41. package/dist/esm/dev/midasUtils.js +80 -18
  42. package/dist/esm/dev/securitizeUtils.js +15 -11
  43. package/dist/esm/dev/withdrawalUtils.js +3 -6
  44. package/dist/esm/model/errors/index.js +2 -2
  45. package/dist/esm/model/errors/operation-errors.js +9 -1
  46. package/dist/esm/model/index.js +2 -2
  47. package/dist/esm/onchain/accounts/CreditAccountsServiceV310.js +0 -1
  48. package/dist/esm/onchain/accounts/intents/borrow.js +137 -0
  49. package/dist/esm/onchain/accounts/intents/{collateral-money.js → collateral-valuation.js} +7 -7
  50. package/dist/esm/onchain/accounts/intents/index.js +86 -2
  51. package/dist/esm/onchain/accounts/intents/leverage-band.js +2 -12
  52. package/dist/esm/onchain/accounts/intents/maxBorrow.js +87 -0
  53. package/dist/esm/onchain/accounts/intents/maxWithdrawCollateral.js +14 -14
  54. package/dist/esm/onchain/accounts/intents/open-strategy.js +6 -45
  55. package/dist/esm/onchain/accounts/intents/realize.js +44 -0
  56. package/dist/esm/onchain/accounts/intents/testing/sdk-mock.js +1 -0
  57. package/dist/esm/onchain/accounts/intents/utils/common.js +19 -1
  58. package/dist/esm/onchain/accounts/intents/utils/credit-account-slice.js +21 -1
  59. package/dist/esm/onchain/accounts/intents/utils/index.js +3 -3
  60. package/dist/esm/onchain/accounts/intents/utils/price-impact.js +3 -3
  61. package/dist/esm/onchain/accounts/intents/withdraw-limits.js +8 -8
  62. package/dist/esm/onchain/core/createAddressProvider.js +2 -5
  63. package/dist/esm/onchain/index.js +3 -1
  64. package/dist/esm/onchain/market/adapters/contracts/MidasGatewayAdapterContract.js +11 -3
  65. package/dist/esm/onchain/positions/calcHealthFactor.js +3 -3
  66. package/dist/esm/onchain/preview/index.js +2 -1
  67. package/dist/esm/onchain/preview/preview/index.js +2 -1
  68. package/dist/esm/onchain/preview/preview/midasGreenlistsAccount.js +16 -0
  69. package/dist/esm/onchain/preview/preview/previewOpenStrategyPosition.js +5 -2
  70. package/dist/esm/onchain/validation/bundles/checkCreditOperation.js +2 -1
  71. package/dist/esm/onchain/validation/bundles/checkMidasAccountGreenlist.js +43 -0
  72. package/dist/esm/onchain/validation/bundles/checkRWAOpening.js +15 -5
  73. package/dist/esm/onchain/validation/bundles/index.js +2 -1
  74. package/dist/esm/onchain/validation/index.js +2 -1
  75. package/dist/esm/sdk/execute/ExecuteApi.js +65 -5
  76. package/dist/esm/sdk/prepare/PrepareApi.js +86 -12
  77. package/dist/types/dev/index.d.ts +3 -3
  78. package/dist/types/dev/kycUtils.d.ts +1 -5
  79. package/dist/types/dev/midasUtils.d.ts +15 -4
  80. package/dist/types/model/errors/index.d.ts +2 -2
  81. package/dist/types/model/errors/operation-errors.d.ts +14 -1
  82. package/dist/types/model/index.d.ts +2 -2
  83. package/dist/types/model/previews.d.ts +17 -2
  84. package/dist/types/onchain/accounts/index.d.ts +4 -3
  85. package/dist/types/onchain/accounts/intents/borrow.d.ts +141 -0
  86. package/dist/types/onchain/accounts/intents/{collateral-money.d.ts → collateral-valuation.d.ts} +8 -8
  87. package/dist/types/onchain/accounts/intents/index.d.ts +81 -2
  88. package/dist/types/onchain/accounts/intents/maxBorrow.d.ts +54 -0
  89. package/dist/types/onchain/accounts/intents/maxWithdrawCollateral.d.ts +3 -3
  90. package/dist/types/onchain/accounts/intents/open-strategy.d.ts +3 -17
  91. package/dist/types/onchain/accounts/intents/testing/sdk-mock.d.ts +2 -0
  92. package/dist/types/onchain/accounts/intents/tests/open-strategy.fixtures.d.ts +2 -2
  93. package/dist/types/onchain/accounts/intents/types.d.ts +15 -1
  94. package/dist/types/onchain/accounts/intents/utils/common.d.ts +15 -1
  95. package/dist/types/onchain/accounts/intents/utils/credit-account-slice.d.ts +14 -1
  96. package/dist/types/onchain/accounts/intents/utils/index.d.ts +3 -3
  97. package/dist/types/onchain/accounts/intents/withdraw-limits.d.ts +1 -1
  98. package/dist/types/onchain/index.d.ts +7 -4
  99. package/dist/types/onchain/market/adapters/contracts/MidasGatewayAdapterContract.d.ts +8 -2
  100. package/dist/types/onchain/preview/index.d.ts +2 -1
  101. package/dist/types/onchain/preview/preview/index.d.ts +2 -1
  102. package/dist/types/onchain/preview/preview/midasGreenlistsAccount.d.ts +13 -0
  103. package/dist/types/onchain/validation/bundles/checkCreditOperation.d.ts +2 -2
  104. package/dist/types/onchain/validation/bundles/checkMidasAccountGreenlist.d.ts +22 -0
  105. package/dist/types/onchain/validation/bundles/checkRWAOpening.d.ts +6 -4
  106. package/dist/types/onchain/validation/bundles/index.d.ts +3 -2
  107. package/dist/types/onchain/validation/checks/checkDebtLimits.d.ts +2 -2
  108. package/dist/types/onchain/validation/index.d.ts +3 -2
  109. package/dist/types/sdk/execute/index.d.ts +2 -2
  110. package/dist/types/sdk/execute/types.d.ts +48 -6
  111. package/dist/types/sdk/index.d.ts +5 -4
  112. package/dist/types/sdk/prepare/PrepareApi.d.ts +15 -3
  113. package/dist/types/sdk/prepare/index.d.ts +4 -3
  114. package/dist/types/sdk/prepare/types.d.ts +176 -49
  115. package/package.json +1 -1
@@ -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,5 +1,7 @@
1
- import { writeAndWait } from "./kycUtils.js";
2
- import { parseAbi, parseEther } from "viem";
1
+ import { AddressSet } from "../onchain/utils/AddressSet.js";
2
+ import { MidasGatewayAdapterContract } from "../onchain/market/adapters/contracts/MidasGatewayAdapterContract.js";
3
+ import "../onchain/index.js";
4
+ import { parseAbi, parseEther, toFunctionSelector } from "viem";
3
5
  //#region src/dev/midasUtils.ts
4
6
  /**
5
7
  * Midas vaults inherit their own `Pausable`, whose global pause is guarded by
@@ -9,14 +11,24 @@ const iMidasPausableVaultAbi = parseAbi([
9
11
  "function paused() external view returns (bool)",
10
12
  "function pause() external",
11
13
  "function unpause() external",
14
+ "function fnPaused(bytes4 fn) external view returns (bool)",
15
+ "function pauseFn(bytes4 fn) external",
16
+ "function unpauseFn(bytes4 fn) external",
12
17
  "function pauseAdminRole() external view returns (bytes32)",
13
18
  "function accessControl() external view returns (address)"
14
19
  ]);
15
20
  const iMidasAccessControlAbi = parseAbi(["function hasRole(bytes32 role, address account) external view returns (bool)", "function grantRole(bytes32 role, address account) external"]);
16
21
  /**
17
- * Unpauses a globally paused Midas issuance vault on an anvil fork, so that
18
- * `depositInstant` stops reverting with `Pausable: paused`, and returns a
19
- * callback that restores the original pause state.
22
+ * Selector for `DepositVault.depositInstant(address,uint256,uint256,bytes32)`,
23
+ * the 4-arg mint Gearbox adapters encode. Distinct from the custom-recipient
24
+ * overload.
25
+ */
26
+ const DEPOSIT_INSTANT_SELECTOR = toFunctionSelector("depositInstant(address,uint256,uint256,bytes32)");
27
+ /**
28
+ * Unpauses a Midas issuance vault on an anvil fork so that `depositInstant`
29
+ * stops reverting with `Pausable: paused` (global) or `Pausable: fn paused`
30
+ * (per-selector), and returns a callback that restores the original pause
31
+ * state of each layer that was cleared.
20
32
  *
21
33
  * Impersonates `admin` and grants it `pauseAdminRole()` when missing, same as
22
34
  * `greenlistMidasGateway` does with the greenlist roles. The grant is not
@@ -24,11 +36,20 @@ const iMidasAccessControlAbi = parseAbi(["function hasRole(bytes32 role, address
24
36
  */
25
37
  async function unpauseMidasIssuanceVault(props) {
26
38
  const { anvil, vault, admin, logger } = props;
27
- if (!await anvil.readContract({
28
- address: vault,
29
- abi: iMidasPausableVaultAbi,
30
- functionName: "paused"
31
- })) {
39
+ const [paused, depositInstantPaused] = await anvil.multicall({
40
+ allowFailure: false,
41
+ contracts: [{
42
+ address: vault,
43
+ abi: iMidasPausableVaultAbi,
44
+ functionName: "paused"
45
+ }, {
46
+ address: vault,
47
+ abi: iMidasPausableVaultAbi,
48
+ functionName: "fnPaused",
49
+ args: [DEPOSIT_INSTANT_SELECTOR]
50
+ }]
51
+ });
52
+ if (!paused && !depositInstantPaused) {
32
53
  logger?.debug(`midas: issuance vault ${vault} is not paused`);
33
54
  return async () => {};
34
55
  }
@@ -50,7 +71,7 @@ async function unpauseMidasIssuanceVault(props) {
50
71
  functionName: "hasRole",
51
72
  args: [pauseAdminRole, admin]
52
73
  });
53
- logger?.debug(`midas: unpausing issuance vault ${vault} as ${admin}, access control ${accessControl}, pause admin role ${pauseAdminRole}`);
74
+ logger?.debug(`midas: unpausing issuance vault ${vault} as ${admin}, access control ${accessControl}, pause admin role ${pauseAdminRole}` + (paused ? ", global" : "") + (depositInstantPaused ? ", depositInstant" : ""));
54
75
  await anvil.impersonateAccount({ address: admin });
55
76
  try {
56
77
  await anvil.setBalance({
@@ -58,22 +79,33 @@ async function unpauseMidasIssuanceVault(props) {
58
79
  value: parseEther("100")
59
80
  });
60
81
  if (!isPauseAdmin) {
61
- await writeAndWait(anvil, {
82
+ await anvil.writeContractSync({
62
83
  account: admin,
63
84
  chain: anvil.chain,
64
85
  address: accessControl,
65
86
  abi: iMidasAccessControlAbi,
66
87
  functionName: "grantRole",
67
- args: [pauseAdminRole, admin]
88
+ args: [pauseAdminRole, admin],
89
+ throwOnReceiptRevert: true
68
90
  });
69
91
  logger?.debug(`midas: granted pause admin role to ${admin}`);
70
92
  }
71
- await writeAndWait(anvil, {
93
+ if (paused) await anvil.writeContractSync({
94
+ account: admin,
95
+ chain: anvil.chain,
96
+ address: vault,
97
+ abi: iMidasPausableVaultAbi,
98
+ functionName: "unpause",
99
+ throwOnReceiptRevert: true
100
+ });
101
+ if (depositInstantPaused) await anvil.writeContractSync({
72
102
  account: admin,
73
103
  chain: anvil.chain,
74
104
  address: vault,
75
105
  abi: iMidasPausableVaultAbi,
76
- functionName: "unpause"
106
+ functionName: "unpauseFn",
107
+ args: [DEPOSIT_INSTANT_SELECTOR],
108
+ throwOnReceiptRevert: true
77
109
  });
78
110
  } finally {
79
111
  await anvil.stopImpersonatingAccount({ address: admin });
@@ -89,12 +121,22 @@ async function unpauseMidasIssuanceVault(props) {
89
121
  address: admin,
90
122
  value: parseEther("100")
91
123
  });
92
- await writeAndWait(anvil, {
124
+ if (paused) await anvil.writeContractSync({
125
+ account: admin,
126
+ chain: anvil.chain,
127
+ address: vault,
128
+ abi: iMidasPausableVaultAbi,
129
+ functionName: "pause",
130
+ throwOnReceiptRevert: true
131
+ });
132
+ if (depositInstantPaused) await anvil.writeContractSync({
93
133
  account: admin,
94
134
  chain: anvil.chain,
95
135
  address: vault,
96
136
  abi: iMidasPausableVaultAbi,
97
- functionName: "pause"
137
+ functionName: "pauseFn",
138
+ args: [DEPOSIT_INSTANT_SELECTOR],
139
+ throwOnReceiptRevert: true
98
140
  });
99
141
  } catch (e) {
100
142
  logger?.warn(`midas: failed to pause issuance vault ${vault} back: ${e}`);
@@ -103,5 +145,25 @@ async function unpauseMidasIssuanceVault(props) {
103
145
  }
104
146
  };
105
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
+ }
106
168
  //#endregion
107
- 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}`);
@@ -204,18 +204,15 @@ async function fulfillMidasRedeemer(anvil, redeemer, logger) {
204
204
  address: MIDAS_VAULT_ADMIN,
205
205
  value: parseEther("100")
206
206
  });
207
- const hash = await anvil.writeContract({
207
+ await anvil.writeContractSync({
208
208
  chain: anvil.chain,
209
209
  address: midasRedemptionVault,
210
210
  account: MIDAS_VAULT_ADMIN,
211
211
  abi: iMidasRedemptionVaultExtAbi,
212
212
  functionName: "safeApproveRequest",
213
- args: [requestId, mTokenRate]
213
+ args: [requestId, mTokenRate],
214
+ throwOnReceiptRevert: true
214
215
  });
215
- if ((await anvil.waitForTransactionReceipt({
216
- hash,
217
- pollingInterval: 100
218
- })).status !== "success") throw new Error(`midas: safeApproveRequest tx ${hash} reverted`);
219
216
  await anvil.stopImpersonatingAccount({ address: MIDAS_VAULT_ADMIN });
220
217
  }
221
218
  /**
@@ -1,7 +1,7 @@
1
1
  import "./base.js";
2
2
  import { creditAccountFrozen, liquidatorNotEligible, notEmergencyLiquidator } from "./liquidation-errors.js";
3
- import { creditManagerPaused, debtOutOfRange, forbiddenToken, insufficientAllowance, insufficientBalance, insufficientCollateral, insufficientPoolLiquidity, leverageOutOfRange, marketExpired, poolPaused, poolSunset, quotaCountExceeded, quotaLimitReached, reservePriceLimited, rwaOpenRequirementsNotMet } from "./operation-errors.js";
3
+ import { accountNotMidasGreenlisted, creditManagerPaused, debtOutOfRange, forbiddenToken, insufficientAllowance, insufficientBalance, insufficientCollateral, insufficientPoolLiquidity, leverageOutOfRange, marketExpired, poolPaused, poolSunset, quotaCountExceeded, quotaLimitReached, reservePriceLimited, rwaOpenRequirementsNotMet } from "./operation-errors.js";
4
4
  import { unpriceableTokenError } from "./oracle-errors.js";
5
5
  import { creditAccountNotEmpty, creditAccountNotFound, multipleDelayedWithdrawals, noDelayedRoute, noRecordedIntent, noStrategyTargetCollateral, unexpectedFailure, unsupportedCollateralToken, unsupportedTokenPair, withdrawalInProgress } from "./prepare-errors.js";
6
6
  import { malformedTransaction } from "./preview-errors.js";
7
- export { creditAccountFrozen, creditAccountNotEmpty, creditAccountNotFound, creditManagerPaused, debtOutOfRange, forbiddenToken, insufficientAllowance, insufficientBalance, insufficientCollateral, insufficientPoolLiquidity, leverageOutOfRange, liquidatorNotEligible, malformedTransaction, marketExpired, multipleDelayedWithdrawals, noDelayedRoute, noRecordedIntent, noStrategyTargetCollateral, notEmergencyLiquidator, poolPaused, poolSunset, quotaCountExceeded, quotaLimitReached, reservePriceLimited, rwaOpenRequirementsNotMet, unexpectedFailure, unpriceableTokenError, unsupportedCollateralToken, unsupportedTokenPair, withdrawalInProgress };
7
+ export { accountNotMidasGreenlisted, creditAccountFrozen, creditAccountNotEmpty, creditAccountNotFound, creditManagerPaused, debtOutOfRange, forbiddenToken, insufficientAllowance, insufficientBalance, insufficientCollateral, insufficientPoolLiquidity, leverageOutOfRange, liquidatorNotEligible, malformedTransaction, marketExpired, multipleDelayedWithdrawals, noDelayedRoute, noRecordedIntent, noStrategyTargetCollateral, notEmergencyLiquidator, poolPaused, poolSunset, quotaCountExceeded, quotaLimitReached, reservePriceLimited, rwaOpenRequirementsNotMet, unexpectedFailure, unpriceableTokenError, unsupportedCollateralToken, unsupportedTokenPair, withdrawalInProgress };
@@ -125,5 +125,13 @@ function rwaOpenRequirementsNotMet(args) {
125
125
  ...args
126
126
  };
127
127
  }
128
+ /** {@inheritDoc AccountNotMidasGreenlistedError} */
129
+ function accountNotMidasGreenlisted(args) {
130
+ return {
131
+ code: "accountNotMidasGreenlisted",
132
+ message: `The credit account is not Midas-greenlisted for ${args.token.symbol}.`,
133
+ ...args
134
+ };
135
+ }
128
136
  //#endregion
129
- export { creditManagerPaused, debtOutOfRange, forbiddenToken, insufficientAllowance, insufficientBalance, insufficientCollateral, insufficientPoolLiquidity, leverageOutOfRange, marketExpired, poolPaused, poolSunset, quotaCountExceeded, quotaLimitReached, reservePriceLimited, rwaOpenRequirementsNotMet };
137
+ export { accountNotMidasGreenlisted, creditManagerPaused, debtOutOfRange, forbiddenToken, insufficientAllowance, insufficientBalance, insufficientCollateral, insufficientPoolLiquidity, leverageOutOfRange, marketExpired, poolPaused, poolSunset, quotaCountExceeded, quotaLimitReached, reservePriceLimited, rwaOpenRequirementsNotMet };
@@ -15,7 +15,7 @@ import { ANALYTICS_POSITIONS_DEFAULT_LIMIT, ANALYTICS_POSITIONS_MAX_LIMIT, analy
15
15
  import "./curators.js";
16
16
  import "./delayed-intents.js";
17
17
  import { creditAccountFrozen, liquidatorNotEligible, notEmergencyLiquidator } from "./errors/liquidation-errors.js";
18
- import { creditManagerPaused, debtOutOfRange, forbiddenToken, insufficientAllowance, insufficientBalance, insufficientCollateral, insufficientPoolLiquidity, leverageOutOfRange, marketExpired, poolPaused, poolSunset, quotaCountExceeded, quotaLimitReached, reservePriceLimited, rwaOpenRequirementsNotMet } from "./errors/operation-errors.js";
18
+ import { accountNotMidasGreenlisted, creditManagerPaused, debtOutOfRange, forbiddenToken, insufficientAllowance, insufficientBalance, insufficientCollateral, insufficientPoolLiquidity, leverageOutOfRange, marketExpired, poolPaused, poolSunset, quotaCountExceeded, quotaLimitReached, reservePriceLimited, rwaOpenRequirementsNotMet } from "./errors/operation-errors.js";
19
19
  import { unpriceableTokenError } from "./errors/oracle-errors.js";
20
20
  import { creditAccountNotEmpty, creditAccountNotFound, multipleDelayedWithdrawals, noDelayedRoute, noRecordedIntent, noStrategyTargetCollateral, unexpectedFailure, unsupportedCollateralToken, unsupportedTokenPair, withdrawalInProgress } from "./errors/prepare-errors.js";
21
21
  import { malformedTransaction } from "./errors/preview-errors.js";
@@ -32,4 +32,4 @@ import { chainFailedSchema, chainMetadataSchema, chainSucceededSchema, dataSourc
32
32
  import { safeValue, sdkErr, sdkOk } from "./result.js";
33
33
  import "./withdrawals.js";
34
34
  import { positionClaimableWithdrawalSchema, positionPendingWithdrawalSchema, positionWithdrawalsSchema, withdrawalOutputAmountSchema } from "./withdrawals.schema.js";
35
- export { ANALYTICS_POSITIONS_DEFAULT_LIMIT, ANALYTICS_POSITIONS_MAX_LIMIT, CHART_METRIC_UNITS, CHART_RANGES, CHART_UNAVAILABLE_CODES, FILTER_ALL, KYC_REGISTRATION_LINKS, POOL_OPPORTUNITY_CHART_METRICS, POOL_POSITION_CHART_METRICS, PROTOCOL_CHART_METRICS, RWA_FACTORY_SECURITIZE, RWA_FACTORY_TYPES, RWA_PROTOCOLS, SECURITIZE_REGISTER_VAULT_TYPES, STRATEGY_OPPORTUNITY_CHART_METRICS, STRATEGY_POSITION_CHART_METRICS, STRATEGY_POSITION_COLLATERAL_ERROR, amountSchema, analyticsChartQueryOptionsSchema, analyticsChartQueryParamsSchema, analyticsChartQuerySchema, analyticsPositionListOptionsSchema, analyticsPositionListQueryParamsSchema, analyticsPositionListQuerySchema, analyticsPositionPageSchema, analyticsPositionSchema, analyticsPositionSortFieldSchema, analyticsSortDirectionSchema, apyBreakdownSchema, asEstimated, assetTypeSchema, backendPreferred, booleanParamSchema, borrowRateBreakdownSchema, bpsSchema, chainFailedSchema, chainIdSchema, chainMetadataSchema, chainSucceededSchema, chartBundleSchemaFor, chartDenominationSchema, chartMetricSchema, chartQueryCodec, chartQueryParamsSchema, chartQuerySchema, chartRangeSchema, chartSeriesSchema, chartValueSchema, chartWindowSchema, compareTagOf, creditAccountFrozen, creditAccountNotEmpty, creditAccountNotFound, creditManagerPaused, curatorNameSchema, curatorSchema, dataSourceSchema, debtOutOfRange, delayedReceivedAssetSchema, encodeFlag, filterAllSchema, filterable, forbiddenToken, instantReceivedAssetSchema, insufficientAllowance, insufficientBalance, insufficientCollateral, insufficientPoolLiquidity, isFilterSet, kycRequirementSchema, leverageOutOfRange, leverageSchema, liquidatableAccountFilterSchema, liquidatableAccountSchema, liquidationApprovalSchema, liquidationDetailsSchema, liquidationPositionId, liquidationPositionSchema, liquidatorNotEligible, malformedTransaction, marketExpired, matchesLiquidatableAccountFilter, matchesOpportunityFilter, matchesPositionFilter, multipleDelayedWithdrawals, noDelayedRoute, noRecordedIntent, noStrategyTargetCollateral, notEmergencyLiquidator, noticeKindSchema, noticeSchema, offchainOnly, onchainOnly, opportunityBaseSchema, opportunityDetailSchema, opportunityFilterQueryParamsSchema, opportunityFilterQuerySchema, opportunityFilterSchema, opportunityId, opportunityKeySchema, opportunityKindSchema, opportunitySchema, opportunityTotalsSchema, pnlBreakdownSchema, pointRewardsSchema, pointsProgramPnLSchema, pointsProgramSchema, pointsRewardsPnLSchema, poolOpportunityChartMetricSchema, poolOpportunityDetailSchema, poolOpportunityId, poolOpportunityKeySchema, poolOpportunitySchema, poolPaused, poolPositionChartMetricSchema, poolPositionId, poolPositionKeySchema, poolPositionSchema, poolSunset, positionClaimableWithdrawalSchema, positionCollateralSchema, positionFilterQueryParamsSchema, positionFilterQuerySchema, positionFilterSchema, positionId, positionKeySchema, positionKindSchema, positionPendingWithdrawalSchema, positionSchema, positionTransactionKindSchema, positionTransactionSchema, positionWithdrawalsSchema, positionsTotalsSchema, priceFeedDataSchema, priceFeedSummarySchema, protocolChartMetricSchema, quotaAssetSchema, quotaCountExceeded, quotaLimitReached, rateCurvePointSchema, rateCurveSchema, receivedAssetSchema, reservePriceLimited, responseMetadataSchema, responseSchema, rewardsPnLSchema, rewardsSchema, rwaOpenRequirementsNotMet, rwaProtocolSchema, safeValue, sdkErr, sdkOk, strategyOpportunityChartMetricSchema, strategyOpportunityDetailSchema, strategyOpportunityId, strategyOpportunityKeySchema, strategyOpportunitySchema, strategyPositionChartMetricSchema, strategyPositionId, strategyPositionKeySchema, strategyPositionSchema, timestampSchema, tokenAmountSchema, tokenQuotaRateSchema, tokenRewardsPnLSchema, tokenRewardsSchema, tokenSchema, tolerance, txCallSchema, underlyingTokenSchema, unexpectedFailure, unpriceableTokenError, unsupportedCollateralToken, unsupportedTokenPair, withdrawalInProgress, withdrawalOutputAmountSchema };
35
+ export { ANALYTICS_POSITIONS_DEFAULT_LIMIT, ANALYTICS_POSITIONS_MAX_LIMIT, CHART_METRIC_UNITS, CHART_RANGES, CHART_UNAVAILABLE_CODES, FILTER_ALL, KYC_REGISTRATION_LINKS, POOL_OPPORTUNITY_CHART_METRICS, POOL_POSITION_CHART_METRICS, PROTOCOL_CHART_METRICS, RWA_FACTORY_SECURITIZE, RWA_FACTORY_TYPES, RWA_PROTOCOLS, SECURITIZE_REGISTER_VAULT_TYPES, STRATEGY_OPPORTUNITY_CHART_METRICS, STRATEGY_POSITION_CHART_METRICS, STRATEGY_POSITION_COLLATERAL_ERROR, accountNotMidasGreenlisted, amountSchema, analyticsChartQueryOptionsSchema, analyticsChartQueryParamsSchema, analyticsChartQuerySchema, analyticsPositionListOptionsSchema, analyticsPositionListQueryParamsSchema, analyticsPositionListQuerySchema, analyticsPositionPageSchema, analyticsPositionSchema, analyticsPositionSortFieldSchema, analyticsSortDirectionSchema, apyBreakdownSchema, asEstimated, assetTypeSchema, backendPreferred, booleanParamSchema, borrowRateBreakdownSchema, bpsSchema, chainFailedSchema, chainIdSchema, chainMetadataSchema, chainSucceededSchema, chartBundleSchemaFor, chartDenominationSchema, chartMetricSchema, chartQueryCodec, chartQueryParamsSchema, chartQuerySchema, chartRangeSchema, chartSeriesSchema, chartValueSchema, chartWindowSchema, compareTagOf, creditAccountFrozen, creditAccountNotEmpty, creditAccountNotFound, creditManagerPaused, curatorNameSchema, curatorSchema, dataSourceSchema, debtOutOfRange, delayedReceivedAssetSchema, encodeFlag, filterAllSchema, filterable, forbiddenToken, instantReceivedAssetSchema, insufficientAllowance, insufficientBalance, insufficientCollateral, insufficientPoolLiquidity, isFilterSet, kycRequirementSchema, leverageOutOfRange, leverageSchema, liquidatableAccountFilterSchema, liquidatableAccountSchema, liquidationApprovalSchema, liquidationDetailsSchema, liquidationPositionId, liquidationPositionSchema, liquidatorNotEligible, malformedTransaction, marketExpired, matchesLiquidatableAccountFilter, matchesOpportunityFilter, matchesPositionFilter, multipleDelayedWithdrawals, noDelayedRoute, noRecordedIntent, noStrategyTargetCollateral, notEmergencyLiquidator, noticeKindSchema, noticeSchema, offchainOnly, onchainOnly, opportunityBaseSchema, opportunityDetailSchema, opportunityFilterQueryParamsSchema, opportunityFilterQuerySchema, opportunityFilterSchema, opportunityId, opportunityKeySchema, opportunityKindSchema, opportunitySchema, opportunityTotalsSchema, pnlBreakdownSchema, pointRewardsSchema, pointsProgramPnLSchema, pointsProgramSchema, pointsRewardsPnLSchema, poolOpportunityChartMetricSchema, poolOpportunityDetailSchema, poolOpportunityId, poolOpportunityKeySchema, poolOpportunitySchema, poolPaused, poolPositionChartMetricSchema, poolPositionId, poolPositionKeySchema, poolPositionSchema, poolSunset, positionClaimableWithdrawalSchema, positionCollateralSchema, positionFilterQueryParamsSchema, positionFilterQuerySchema, positionFilterSchema, positionId, positionKeySchema, positionKindSchema, positionPendingWithdrawalSchema, positionSchema, positionTransactionKindSchema, positionTransactionSchema, positionWithdrawalsSchema, positionsTotalsSchema, priceFeedDataSchema, priceFeedSummarySchema, protocolChartMetricSchema, quotaAssetSchema, quotaCountExceeded, quotaLimitReached, rateCurvePointSchema, rateCurveSchema, receivedAssetSchema, reservePriceLimited, responseMetadataSchema, responseSchema, rewardsPnLSchema, rewardsSchema, rwaOpenRequirementsNotMet, rwaProtocolSchema, safeValue, sdkErr, sdkOk, strategyOpportunityChartMetricSchema, strategyOpportunityDetailSchema, strategyOpportunityId, strategyOpportunityKeySchema, strategyOpportunitySchema, strategyPositionChartMetricSchema, strategyPositionId, strategyPositionKeySchema, strategyPositionSchema, timestampSchema, tokenAmountSchema, tokenQuotaRateSchema, tokenRewardsPnLSchema, tokenRewardsSchema, tokenSchema, tolerance, txCallSchema, underlyingTokenSchema, unexpectedFailure, unpriceableTokenError, unsupportedCollateralToken, unsupportedTokenPair, withdrawalInProgress, withdrawalOutputAmountSchema };
@@ -212,7 +212,6 @@ var CreditAccountsServiceV310 = class extends SDKConstruct {
212
212
  }),
213
213
  ...callsAfter ?? []
214
214
  ];
215
- calls = await this.#prependMidasReceiveGreenlist(cm.address, calls);
216
215
  calls = await this.prependPriceUpdates(cm.address, calls);
217
216
  const tx = reopenCreditAccount ? cmSuite.multicallTx(reopenCreditAccount, calls, rwaOptions) : cmSuite.openCreditAccountTx(to, calls, referralCode, rwaOptions);
218
217
  tx.value = ethAmount.toString(10);
@@ -0,0 +1,137 @@
1
+ import { insufficientBalance } from "../../../model/errors/operation-errors.js";
2
+ import { unsupportedCollateralToken } from "../../../model/errors/prepare-errors.js";
3
+ import "../../../model/index.js";
4
+ import { toToken } from "../../validation/helpers/token.js";
5
+ import { IntentPreviewError } from "../../validation/raise.js";
6
+ import "../../validation/index.js";
7
+ import { eq, toTargetDecimals } from "./utils/common.js";
8
+ import { assertCanBorrow, assertCollateralised, assertGrowthAllowed, assertMarketOperable, assertQuotaAvailable } from "./guards.js";
9
+ import { assertDebtLimits } from "./math.js";
10
+ import { unopenedAccountSlice } from "./utils/credit-account-slice.js";
11
+ import { collectPriceImpact } from "./utils/price-impact.js";
12
+ import { getQuotasForUpdate } from "./utils/quotas-for-update.js";
13
+ import { createRouterPaths } from "./utils/router-path.js";
14
+ import "./utils/index.js";
15
+ //#region src/onchain/accounts/intents/borrow.ts
16
+ /**
17
+ * Builds the state a borrow would leave behind.
18
+ *
19
+ * The debt is named rather than derived: a borrow asks for an amount, where an
20
+ * opening asks for a leverage and lets the collateral decide. Everything the
21
+ * loan pays out leaves the account, so the collateral alone backs it — which
22
+ * is what makes the health factor here a straight function of the two amounts.
23
+ *
24
+ * Produces no operation list, as opening never does: the caller hands the
25
+ * numbers and the calls to `sdk.accounts.openCA`, with `withdrawToken` set to
26
+ * the payout.
27
+ */
28
+ async function buildBorrowState(props) {
29
+ const { sdk, creditManager, collateralAmount, borrowAmount, slippage = 0, quotaReserve, creditAccount: existing } = props;
30
+ const suite = sdk.marketRegister.findCreditManager(creditManager);
31
+ const market = sdk.marketRegister.findByCreditManager(creditManager);
32
+ assertMarketOperable(suite);
33
+ const underlying = market.pool.underlying.toLowerCase();
34
+ const collateralToken = props.collateralToken.toLowerCase();
35
+ const borrowToken = props.borrowToken.toLowerCase();
36
+ const convert = (from, to, amount) => market.priceOracle.safeConvert(from, to, amount).value;
37
+ if (eq(collateralToken, borrowToken)) throw new IntentPreviewError(unsupportedCollateralToken(toToken(sdk, collateralToken)), "borrow: the payout token cannot also be the collateral");
38
+ const rwaAsset = sdk.tokensMeta.rwaUnderlyings.get(underlying)?.asset?.toLowerCase();
39
+ const unwrapsPayout = !!rwaAsset && eq(borrowToken, rwaAsset);
40
+ if (rwaAsset && eq(borrowToken, underlying)) throw new IntentPreviewError(unsupportedCollateralToken(toToken(sdk, borrowToken)), `borrow: ${underlying} cannot leave the account, ask for the payout in ${rwaAsset}`);
41
+ if (collateralAmount <= 0n) throw new IntentPreviewError(insufficientBalance(), "borrow: no collateral supplied");
42
+ if (borrowAmount <= 0n) throw new IntentPreviewError(insufficientBalance(), "borrow: nothing to borrow");
43
+ const margin = convert(collateralToken, underlying, collateralAmount);
44
+ if (margin <= 0n) throw new IntentPreviewError(insufficientBalance(), "borrow: collateral is worth nothing in underlying");
45
+ const debt = eq(borrowToken, underlying) ? borrowAmount : unwrapsPayout ? toTargetDecimals(borrowAmount, borrowToken, underlying, sdk) : convert(borrowToken, underlying, borrowAmount);
46
+ assertDebtLimits(sdk, debt, suite.creditFacade, underlying);
47
+ assertCanBorrow(sdk, suite, debt);
48
+ const account = existing ?? unopenedAccountSlice({
49
+ creditManager,
50
+ creditFacade: suite.creditFacade.address,
51
+ underlying
52
+ });
53
+ const leg = eq(borrowToken, underlying) || unwrapsPayout ? void 0 : await createRouterPaths({
54
+ sdk,
55
+ creditAccount: account,
56
+ slippage
57
+ }).swap({
58
+ tokenIn: underlying,
59
+ tokenOut: borrowToken,
60
+ amount: debt,
61
+ keep: eq(collateralToken, underlying) ? collateralAmount : 0n
62
+ });
63
+ const unwrap = unwrapsPayout ? await sdk.accounts.assembleRWAUnwrapCalls(debt, creditManager) : void 0;
64
+ if (unwrapsPayout && !unwrap) throw new Error(`borrow: no unwrap calls found for ${borrowToken}`);
65
+ const assets = [{
66
+ token: collateralToken,
67
+ balance: collateralAmount
68
+ }];
69
+ const quotaIncrease = borrowCollateralQuota({
70
+ sdk,
71
+ creditManager,
72
+ assets,
73
+ quotaReserve
74
+ });
75
+ assertGrowthAllowed({
76
+ sdk,
77
+ suite,
78
+ market,
79
+ before: [],
80
+ after: assets
81
+ });
82
+ assertQuotaAvailable(sdk, market, quotaIncrease);
83
+ const snapshot = {
84
+ creditManager,
85
+ assets,
86
+ quotas: quotaIncrease,
87
+ totalDebt: debt,
88
+ totalValue: margin
89
+ };
90
+ const projection = sdk.positions.projection(snapshot, { availableLiquidityChange: -debt });
91
+ assertCollateralised(projection.safeHealthFactor, true);
92
+ const priced = (token, balance) => market.priceOracle.toTokenAmount(token, balance);
93
+ const payout = unwrapsPayout ? toTargetDecimals(debt, underlying, borrowToken, sdk) : leg ? leg.amount : debt;
94
+ return {
95
+ ...projection,
96
+ currentPrice: sdk.positions.currentPrice(snapshot),
97
+ executionCost: void 0,
98
+ priceImpact: await collectPriceImpact(leg?.probe ? [leg.probe] : [], {
99
+ totalValue: margin,
100
+ netValue: margin - debt,
101
+ toUnderlying: (from, amount) => convert(from, underlying, amount)
102
+ }),
103
+ collateral: priced(collateralToken, collateralAmount),
104
+ borrowed: priced(borrowToken, payout),
105
+ minBorrowed: priced(borrowToken, leg ? leg.minAmount : payout),
106
+ slippage,
107
+ quotaIncrease,
108
+ calls: leg ? [...leg.calls] : unwrap ?? [],
109
+ creditAccount: existing?.creditAccount
110
+ };
111
+ }
112
+ /**
113
+ * Quota a borrow buys for its collateral on an account that holds none yet.
114
+ *
115
+ * Shared with `maxBorrow`, because a quota short of the collateral's weighted
116
+ * value is what caps the loan: the two have to read the same number or the
117
+ * ceiling one offers is one the other refuses.
118
+ *
119
+ * @param props - {@link BorrowCollateralQuotaProps}
120
+ **/
121
+ function borrowCollateralQuota({ sdk, creditManager, assets, quotaReserve }) {
122
+ const suite = sdk.marketRegister.findCreditManager(creditManager);
123
+ const market = sdk.marketRegister.findByCreditManager(creditManager);
124
+ return getQuotasForUpdate({
125
+ assetsBefore: [],
126
+ assetsAfter: assets,
127
+ initialQuotas: [],
128
+ quotaReserve,
129
+ underlyingToken: market.pool.underlying,
130
+ liquidationThresholds: suite.creditManager.liquidationThresholds,
131
+ quotas: market.pool.pqk.quotas,
132
+ maxDebt: suite.creditFacade.maxDebt,
133
+ convert: (from, to, amount) => market.priceOracle.safeConvert(from, to, amount).value
134
+ }).quotaIncrease;
135
+ }
136
+ //#endregion
137
+ export { borrowCollateralQuota, buildBorrowState };
@@ -2,9 +2,9 @@ import { BigIntMath } from "../../utils/bigint-math.js";
2
2
  import { PERCENTAGE_FACTOR } from "../../constants/math.js";
3
3
  import "../../utils/index.js";
4
4
  import { eq } from "./utils/common.js";
5
- //#region src/onchain/accounts/intents/collateral-money.ts
6
- /** {@inheritDoc CollateralMoney} */
7
- function collateralMoney(creditAccount, sdk) {
5
+ //#region src/onchain/accounts/intents/collateral-valuation.ts
6
+ /** {@inheritDoc CollateralValuation} */
7
+ function collateralValuation(creditAccount, sdk) {
8
8
  const { market, creditManager } = sdk.marketRegister.findCreditManager(creditAccount.creditManager);
9
9
  const { priceOracle } = market;
10
10
  const { pqk } = market.pool;
@@ -20,21 +20,21 @@ function collateralMoney(creditAccount, sdk) {
20
20
  const lt = (token) => BigInt(creditManager.liquidationThresholds.get(token) ?? 0);
21
21
  const checkedUsd = (holding) => eq(holding.token, underlying) ? mainUsd(holding.token, holding.balance) ?? 0n : priceOracle.safeConvertMinUSD(holding.token, holding.balance).value;
22
22
  /** A quota is underlying-denominated, and a closed market backs nothing. */
23
- const quotaMoney = (holding) => pqk.hasActiveQuota(holding.token) ? (mainUsd(underlying, holding.quota) ?? 0n) * PERCENTAGE_FACTOR : 0n;
23
+ const quotaValue = (holding) => pqk.hasActiveQuota(holding.token) ? (mainUsd(underlying, holding.quota) ?? 0n) * PERCENTAGE_FACTOR : 0n;
24
24
  const weigh = (holding) => {
25
25
  const weighted = checkedUsd(holding) * lt(holding.token);
26
26
  if (holding.quota === 0n) return weighted;
27
- return BigIntMath.min(quotaMoney(holding), weighted);
27
+ return BigIntMath.min(quotaValue(holding), weighted);
28
28
  };
29
29
  return {
30
30
  underlying,
31
31
  counts: (holding) => holding.balance > 10n && (!masked || (holding.mask & creditAccount.enabledTokensMask) !== 0n),
32
32
  weigh,
33
- quotaMoney,
33
+ quotaValue,
34
34
  mainUsd,
35
35
  checkedUsd,
36
36
  lt
37
37
  };
38
38
  }
39
39
  //#endregion
40
- export { collateralMoney };
40
+ export { collateralValuation };