@gearbox-protocol/sdk 14.12.0-next.64 → 14.12.0-next.66

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.
@@ -2,6 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_dev_abi = require("./abi.js");
3
3
  const require_dev_claimFromFaucet = require("./claimFromFaucet.js");
4
4
  const require_dev_createAnvilClient = require("./createAnvilClient.js");
5
+ const require_dev_kycUtils = require("./kycUtils.js");
5
6
  const require_dev_midasUtils = require("./midasUtils.js");
6
7
  const require_dev_mint_factory = require("./mint/factory.js");
7
8
  require("./mint/index.js");
@@ -15,7 +16,6 @@ const require_dev_detectChain = require("./detectChain.js");
15
16
  const require_dev_isOutOfSyncError = require("./isOutOfSyncError.js");
16
17
  const require_dev_isRateLimitError = require("./isRateLimitError.js");
17
18
  const require_dev_isTransientError = require("./isTransientError.js");
18
- const require_dev_kycUtils = require("./kycUtils.js");
19
19
  const require_dev_logSplitterTransport = require("./logSplitterTransport.js");
20
20
  const require_dev_ltUtils = require("./ltUtils.js");
21
21
  const require_dev_migrateFaucet = require("./migrateFaucet.js");
@@ -46,6 +46,7 @@ exports.createAnvilClient = require_dev_createAnvilClient.createAnvilClient;
46
46
  exports.createMinter = require_dev_mint_factory.createMinter;
47
47
  exports.deployUsingPublicCreate2 = require_dev_create2.deployUsingPublicCreate2;
48
48
  exports.detectChain = require_dev_detectChain.detectChain;
49
+ exports.enableDSTokenBackDating = require_dev_securitizeUtils.enableDSTokenBackDating;
49
50
  exports.evmMineDetailed = require_dev_createAnvilClient.evmMineDetailed;
50
51
  exports.extendAnvilClient = require_dev_createAnvilClient.extendAnvilClient;
51
52
  exports.faucetAbi = require_dev_abi.faucetAbi;
@@ -84,5 +85,6 @@ exports.revolverTransportConfigSchema = require_dev_RevolverTransport.revolverTr
84
85
  exports.rpcProvidersSchema = require_dev_providers.rpcProvidersSchema;
85
86
  exports.setLTZero = require_dev_ltUtils.setLTZero;
86
87
  exports.setLTs = require_dev_ltUtils.setLTs;
88
+ exports.unpauseMidasIssuanceVault = require_dev_midasUtils.unpauseMidasIssuanceVault;
87
89
  exports.verifyTestnet = require_dev_verifyTestnet.verifyTestnet;
88
90
  exports.writeAndWait = require_dev_kycUtils.writeAndWait;
@@ -3,9 +3,9 @@ const require_sdk_utils_AddressSet = require("../sdk/utils/AddressSet.js");
3
3
  const require_sdk_constants_math = require("../sdk/constants/math.js");
4
4
  const require_sdk_OnchainSDK = require("../sdk/OnchainSDK.js");
5
5
  require("../sdk/index.js");
6
- const require_dev_withdrawalAbi = require("./withdrawalAbi.js");
7
6
  const require_abi_rwa_iDSRegistryService = require("../abi/rwa/iDSRegistryService.js");
8
7
  const require_abi_rwa_iDSToken = require("../abi/rwa/iDSToken.js");
8
+ const require_dev_withdrawalAbi = require("./withdrawalAbi.js");
9
9
  let viem = require("viem");
10
10
  let viem_accounts = require("viem/accounts");
11
11
  //#region src/dev/kycUtils.ts
@@ -1,5 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_dev_withdrawalAbi = require("./withdrawalAbi.js");
3
+ const require_dev_kycUtils = require("./kycUtils.js");
3
4
  let viem = require("viem");
4
5
  //#region src/dev/midasUtils.ts
5
6
  const ADAPTER_MIDAS_GATEWAY = "ADAPTER::MIDAS_GATEWAY";
@@ -16,6 +17,18 @@ const MIDAS_MODE_PERMISSIONLESS = 0;
16
17
  */
17
18
  const iMidasMTokenAbi = (0, viem.parseAbi)(["function mToken() external view returns (address)"]);
18
19
  const iMidasGatewayAdapterExtAbi = (0, viem.parseAbi)(["function receiveGreenlist() external returns (bool)"]);
20
+ /**
21
+ * Midas vaults inherit their own `Pausable`, whose global pause is guarded by
22
+ * `pauseAdminRole()` in the vault's access control instead of `Ownable`
23
+ */
24
+ const iMidasPausableVaultAbi = (0, viem.parseAbi)([
25
+ "function paused() external view returns (bool)",
26
+ "function pause() external",
27
+ "function unpause() external",
28
+ "function pauseAdminRole() external view returns (bytes32)",
29
+ "function accessControl() external view returns (address)"
30
+ ]);
31
+ const iMidasAccessControlAbi = (0, viem.parseAbi)(["function hasRole(bytes32 role, address account) external view returns (bool)", "function grantRole(bytes32 role, address account) external"]);
19
32
  const receiveGreenlistCallData = (0, viem.encodeFunctionData)({
20
33
  abi: iMidasGatewayAdapterExtAbi,
21
34
  functionName: "receiveGreenlist"
@@ -86,6 +99,96 @@ async function prependMidasReceiveGreenlist(props) {
86
99
  }
87
100
  return prepended.length > 0 ? [...prepended, ...calls] : calls;
88
101
  }
102
+ /**
103
+ * Unpauses a globally paused Midas issuance vault on an anvil fork, so that
104
+ * `depositInstant` stops reverting with `Pausable: paused`, and returns a
105
+ * callback that restores the original pause state.
106
+ *
107
+ * Impersonates `admin` and grants it `pauseAdminRole()` when missing, same as
108
+ * `greenlistMidasGateway` does with the greenlist roles. The grant is not
109
+ * reverted by the callback, only the pause state is.
110
+ */
111
+ async function unpauseMidasIssuanceVault(props) {
112
+ const { anvil, vault, admin, logger } = props;
113
+ if (!await anvil.readContract({
114
+ address: vault,
115
+ abi: iMidasPausableVaultAbi,
116
+ functionName: "paused"
117
+ })) {
118
+ logger?.debug(`midas: issuance vault ${vault} is not paused`);
119
+ return async () => {};
120
+ }
121
+ const [accessControl, pauseAdminRole] = await anvil.multicall({
122
+ allowFailure: false,
123
+ contracts: [{
124
+ address: vault,
125
+ abi: iMidasPausableVaultAbi,
126
+ functionName: "accessControl"
127
+ }, {
128
+ address: vault,
129
+ abi: iMidasPausableVaultAbi,
130
+ functionName: "pauseAdminRole"
131
+ }]
132
+ });
133
+ const isPauseAdmin = await anvil.readContract({
134
+ address: accessControl,
135
+ abi: iMidasAccessControlAbi,
136
+ functionName: "hasRole",
137
+ args: [pauseAdminRole, admin]
138
+ });
139
+ logger?.debug(`midas: unpausing issuance vault ${vault} as ${admin}, access control ${accessControl}, pause admin role ${pauseAdminRole}`);
140
+ await anvil.impersonateAccount({ address: admin });
141
+ try {
142
+ await anvil.setBalance({
143
+ address: admin,
144
+ value: (0, viem.parseEther)("100")
145
+ });
146
+ if (!isPauseAdmin) {
147
+ await require_dev_kycUtils.writeAndWait(anvil, {
148
+ account: admin,
149
+ chain: anvil.chain,
150
+ address: accessControl,
151
+ abi: iMidasAccessControlAbi,
152
+ functionName: "grantRole",
153
+ args: [pauseAdminRole, admin]
154
+ });
155
+ logger?.debug(`midas: granted pause admin role to ${admin}`);
156
+ }
157
+ await require_dev_kycUtils.writeAndWait(anvil, {
158
+ account: admin,
159
+ chain: anvil.chain,
160
+ address: vault,
161
+ abi: iMidasPausableVaultAbi,
162
+ functionName: "unpause"
163
+ });
164
+ } finally {
165
+ await anvil.stopImpersonatingAccount({ address: admin });
166
+ }
167
+ let toRestore = true;
168
+ return async () => {
169
+ if (!toRestore) return;
170
+ toRestore = false;
171
+ logger?.debug(`midas: pausing issuance vault ${vault} back`);
172
+ await anvil.impersonateAccount({ address: admin });
173
+ try {
174
+ await anvil.setBalance({
175
+ address: admin,
176
+ value: (0, viem.parseEther)("100")
177
+ });
178
+ await require_dev_kycUtils.writeAndWait(anvil, {
179
+ account: admin,
180
+ chain: anvil.chain,
181
+ address: vault,
182
+ abi: iMidasPausableVaultAbi,
183
+ functionName: "pause"
184
+ });
185
+ } catch (e) {
186
+ logger?.warn(`midas: failed to pause issuance vault ${vault} back: ${e}`);
187
+ } finally {
188
+ await anvil.stopImpersonatingAccount({ address: admin });
189
+ }
190
+ };
191
+ }
89
192
  async function readMTokens(client, adapters) {
90
193
  return await client.multicall({
91
194
  allowFailure: false,
@@ -98,3 +201,4 @@ async function readMTokens(client, adapters) {
98
201
  }
99
202
  //#endregion
100
203
  exports.prependMidasReceiveGreenlist = prependMidasReceiveGreenlist;
204
+ exports.unpauseMidasIssuanceVault = unpauseMidasIssuanceVault;
@@ -1,4 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_sdk_utils_AddressSet = require("../sdk/utils/AddressSet.js");
2
3
  const require_sdk_OnchainSDK = require("../sdk/OnchainSDK.js");
3
4
  require("../sdk/index.js");
4
5
  const require_abi_rwa_iDSToken = require("../abi/rwa/iDSToken.js");
@@ -14,7 +15,9 @@ const iDSComplianceConfigurationServiceAbi = (0, viem.parseAbi)([
14
15
  "function getUSLockPeriod() external view returns (uint256)",
15
16
  "function getNonUSLockPeriod() external view returns (uint256)",
16
17
  "function setUSLockPeriod(uint256) external",
17
- "function setNonUSLockPeriod(uint256) external"
18
+ "function setNonUSLockPeriod(uint256) external",
19
+ "function getDisallowBackDating() external view returns (bool)",
20
+ "function setDisallowBackDating(bool) external"
18
21
  ]);
19
22
  /**
20
23
  * Returns the longest of US and non-US compliance lock periods, or `undefined`
@@ -62,7 +65,7 @@ async function issueDSTokens(props) {
62
65
  const { timestamp } = await anvil.getBlock();
63
66
  const issuanceTime = timestamp - lockPeriod - 1n;
64
67
  try {
65
- await require_dev_kycUtils.writeAndWait(anvil, {
68
+ const hash = await require_dev_kycUtils.writeAndWait(anvil, {
66
69
  account,
67
70
  chain: anvil.chain,
68
71
  address: token,
@@ -82,6 +85,7 @@ async function issueDSTokens(props) {
82
85
  investor,
83
86
  amount
84
87
  }, "issueTokensCustom successful");
88
+ return hash;
85
89
  } catch (e) {
86
90
  logger?.debug(`issueTokensCustom failed: ${e}`);
87
91
  }
@@ -99,6 +103,94 @@ async function issueDSTokens(props) {
99
103
  args: [investor, amount]
100
104
  });
101
105
  }
106
+ /**
107
+ * Resolves unique compliance configuration services of `tokens`: several
108
+ * DSTokens can share one service, and it's the service that holds the flags.
109
+ * Tokens without one (e.g. MockDSToken) are skipped
110
+ */
111
+ async function getComplianceConfigurationServices({ anvil, tokens, logger }) {
112
+ const services = new require_sdk_utils_AddressSet.AddressSet();
113
+ for (const token of new require_sdk_utils_AddressSet.AddressSet(tokens)) try {
114
+ const service = await anvil.readContract({
115
+ address: token,
116
+ abi: require_abi_rwa_iDSToken.iDSTokenAbi,
117
+ functionName: "getDSService",
118
+ args: [COMPLIANCE_CONFIGURATION_SERVICE]
119
+ });
120
+ if ((0, viem.isAddressEqual)(service, viem.zeroAddress)) {
121
+ logger?.debug(`${token} has no compliance configuration service`);
122
+ continue;
123
+ }
124
+ services.add(service);
125
+ } catch (e) {
126
+ logger?.debug(`Failed to get compliance configuration service of ${token}: ${e}`);
127
+ }
128
+ return [...services];
129
+ }
130
+ /**
131
+ * Sets `disallowBackDating` to false on compliance configuration services of
132
+ * `tokens`, so that the issuance time passed to `issueTokensCustom` is
133
+ * honoured: DS protocol silently replaces it with `block.timestamp` otherwise,
134
+ * and freshly minted tokens stay under lock-up.
135
+ *
136
+ * Must be signed by a DS admin with sufficient trust (same key as
137
+ * `issueTokens` / registerInvestor); Ownable `owner()` alone is not enough.
138
+ *
139
+ * The flag is only read while tokens are issued, so restoring it does not
140
+ * re-lock tokens minted in the meantime.
141
+ */
142
+ async function enableDSTokenBackDating(props) {
143
+ const { anvil, adminPrivateKey, logger } = props;
144
+ const account = (0, viem_accounts.privateKeyToAccount)(adminPrivateKey);
145
+ const services = await getComplianceConfigurationServices(props);
146
+ let toRestore = [];
147
+ for (const service of services) {
148
+ let disallowBackDating;
149
+ try {
150
+ disallowBackDating = await anvil.readContract({
151
+ address: service,
152
+ abi: iDSComplianceConfigurationServiceAbi,
153
+ functionName: "getDisallowBackDating"
154
+ });
155
+ } catch (e) {
156
+ logger?.debug(`Failed to read disallowBackDating of ${service}: ${e}`);
157
+ continue;
158
+ }
159
+ if (!disallowBackDating) {
160
+ logger?.debug(`Back-dating is already allowed by ${service}`);
161
+ continue;
162
+ }
163
+ logger?.info(`Allowing back-dating on ${service}`);
164
+ await require_dev_kycUtils.writeAndWait(anvil, {
165
+ account,
166
+ chain: anvil.chain,
167
+ address: service,
168
+ abi: iDSComplianceConfigurationServiceAbi,
169
+ functionName: "setDisallowBackDating",
170
+ args: [false]
171
+ });
172
+ toRestore.push(service);
173
+ }
174
+ return async () => {
175
+ const services = toRestore;
176
+ toRestore = [];
177
+ for (const service of services) {
178
+ logger?.info(`Disallowing back-dating on ${service}`);
179
+ try {
180
+ await require_dev_kycUtils.writeAndWait(anvil, {
181
+ account,
182
+ chain: anvil.chain,
183
+ address: service,
184
+ abi: iDSComplianceConfigurationServiceAbi,
185
+ functionName: "setDisallowBackDating",
186
+ args: [true]
187
+ });
188
+ } catch (e) {
189
+ logger?.warn(`Failed to restore disallowBackDating on ${service}: ${e}`);
190
+ }
191
+ }
192
+ };
193
+ }
102
194
  async function claimDSToken(props) {
103
195
  const { anvil, investor, adminPrivateKey, token, marketConfigurators, rwaFactories, usdAmount: usdAmountProp = "100000" } = props;
104
196
  const account = (0, viem_accounts.privateKeyToAccount)(adminPrivateKey);
@@ -164,3 +256,4 @@ async function claimDSTokens(props) {
164
256
  //#endregion
165
257
  exports.claimDSToken = claimDSToken;
166
258
  exports.claimDSTokens = claimDSTokens;
259
+ exports.enableDSTokenBackDating = enableDSTokenBackDating;
@@ -1,7 +1,8 @@
1
1
  import { faucetAbi, iDegenNftv2Abi, iOnchainExecutionIdAbi, iOwnableAbi, iaclTraitAbi } from "./abi.js";
2
2
  import { claimFromFaucet } from "./claimFromFaucet.js";
3
3
  import { anvilNodeInfo, createAnvilClient, evmMineDetailed, extendAnvilClient, isAnvil } from "./createAnvilClient.js";
4
- import { prependMidasReceiveGreenlist } from "./midasUtils.js";
4
+ import { greenlistMidasGateway, registerMidasInvestor, registerRWAInvestor, registerSecuritizeInvestor, writeAndWait } from "./kycUtils.js";
5
+ import { prependMidasReceiveGreenlist, unpauseMidasIssuanceVault } from "./midasUtils.js";
5
6
  import { createMinter } from "./mint/factory.js";
6
7
  import "./mint/index.js";
7
8
  import { AccountOpener, OpenTxRevertedError } from "./AccountOpener.js";
@@ -14,15 +15,14 @@ import { detectChain } from "./detectChain.js";
14
15
  import { isOutOfSyncError } from "./isOutOfSyncError.js";
15
16
  import { isRateLimitError } from "./isRateLimitError.js";
16
17
  import { isTransientError } from "./isTransientError.js";
17
- import { greenlistMidasGateway, registerMidasInvestor, registerRWAInvestor, registerSecuritizeInvestor, writeAndWait } from "./kycUtils.js";
18
18
  import { isRangeError, logSplitterTransport } from "./logSplitterTransport.js";
19
19
  import { setLTZero, setLTs } from "./ltUtils.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";
23
23
  import { resilientTransport, resilientTransportOptionsSchema } from "./resilientTransport.js";
24
- import { claimDSToken, claimDSTokens } from "./securitizeUtils.js";
24
+ import { claimDSToken, claimDSTokens, enableDSTokenBackDating } from "./securitizeUtils.js";
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, evmMineDetailed, extendAnvilClient, faucetAbi, getAlchemyUrl, getAnkrUrl, getDrpcUrl, getErpcKey, getPublicCreate2Address, getRpcProviderUrl, getThirdWebUrl, greenlistMidasGateway, httpTransportOptionsSchema, iDegenNftv2Abi, iOnchainExecutionIdAbi, iOwnableAbi, iaclTraitAbi, isAnvil, isDeployedUsingPublicCreate2, isOutOfSyncError, isRangeError, isRateLimitError, isTransientError, logSplitterTransport, makePendingWithdrawalsClaimable, migrateFaucet, prependMidasReceiveGreenlist, providerConfigSchema, registerMidasInvestor, registerRWAInvestor, registerSecuritizeInvestor, replaceStorage, resilientTransport, resilientTransportOptionsSchema, revolverTransportConfigBaseSchema, revolverTransportConfigSchema, rpcProvidersSchema, setLTZero, setLTs, 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, createAnvilClient, createMinter, deployUsingPublicCreate2, detectChain, enableDSTokenBackDating, evmMineDetailed, extendAnvilClient, faucetAbi, getAlchemyUrl, getAnkrUrl, getDrpcUrl, getErpcKey, getPublicCreate2Address, getRpcProviderUrl, getThirdWebUrl, greenlistMidasGateway, httpTransportOptionsSchema, iDegenNftv2Abi, iOnchainExecutionIdAbi, iOwnableAbi, iaclTraitAbi, isAnvil, isDeployedUsingPublicCreate2, isOutOfSyncError, isRangeError, isRateLimitError, isTransientError, logSplitterTransport, makePendingWithdrawalsClaimable, migrateFaucet, prependMidasReceiveGreenlist, providerConfigSchema, registerMidasInvestor, registerRWAInvestor, registerSecuritizeInvestor, replaceStorage, resilientTransport, resilientTransportOptionsSchema, revolverTransportConfigBaseSchema, revolverTransportConfigSchema, rpcProvidersSchema, setLTZero, setLTs, unpauseMidasIssuanceVault, verifyTestnet, writeAndWait };
@@ -2,9 +2,9 @@ import { AddressSet } from "../sdk/utils/AddressSet.js";
2
2
  import { MAX_UINT256 } from "../sdk/constants/math.js";
3
3
  import { OnchainSDK } from "../sdk/OnchainSDK.js";
4
4
  import "../sdk/index.js";
5
- import { midasGatewayAbi } from "./withdrawalAbi.js";
6
5
  import { iDSRegistryServiceAbi } from "../abi/rwa/iDSRegistryService.js";
7
6
  import { iDSTokenAbi } from "../abi/rwa/iDSToken.js";
7
+ import { midasGatewayAbi } from "./withdrawalAbi.js";
8
8
  import { isAddressEqual, parseAbi, parseEther, zeroAddress } from "viem";
9
9
  import { privateKeyToAccount } from "viem/accounts";
10
10
  //#region src/dev/kycUtils.ts
@@ -1,5 +1,6 @@
1
1
  import { midasGatewayAbi } from "./withdrawalAbi.js";
2
- import { encodeFunctionData, isAddressEqual, parseAbi } from "viem";
2
+ import { writeAndWait } from "./kycUtils.js";
3
+ import { encodeFunctionData, isAddressEqual, parseAbi, parseEther } from "viem";
3
4
  //#region src/dev/midasUtils.ts
4
5
  const ADAPTER_MIDAS_GATEWAY = "ADAPTER::MIDAS_GATEWAY";
5
6
  const ADAPTER_MIDAS_ISSUANCE_VAULT = "ADAPTER::MIDAS_ISSUANCE_VAULT";
@@ -15,6 +16,18 @@ const MIDAS_MODE_PERMISSIONLESS = 0;
15
16
  */
16
17
  const iMidasMTokenAbi = parseAbi(["function mToken() external view returns (address)"]);
17
18
  const iMidasGatewayAdapterExtAbi = parseAbi(["function receiveGreenlist() external returns (bool)"]);
19
+ /**
20
+ * Midas vaults inherit their own `Pausable`, whose global pause is guarded by
21
+ * `pauseAdminRole()` in the vault's access control instead of `Ownable`
22
+ */
23
+ const iMidasPausableVaultAbi = parseAbi([
24
+ "function paused() external view returns (bool)",
25
+ "function pause() external",
26
+ "function unpause() external",
27
+ "function pauseAdminRole() external view returns (bytes32)",
28
+ "function accessControl() external view returns (address)"
29
+ ]);
30
+ const iMidasAccessControlAbi = parseAbi(["function hasRole(bytes32 role, address account) external view returns (bool)", "function grantRole(bytes32 role, address account) external"]);
18
31
  const receiveGreenlistCallData = encodeFunctionData({
19
32
  abi: iMidasGatewayAdapterExtAbi,
20
33
  functionName: "receiveGreenlist"
@@ -85,6 +98,96 @@ async function prependMidasReceiveGreenlist(props) {
85
98
  }
86
99
  return prepended.length > 0 ? [...prepended, ...calls] : calls;
87
100
  }
101
+ /**
102
+ * Unpauses a globally paused Midas issuance vault on an anvil fork, so that
103
+ * `depositInstant` stops reverting with `Pausable: paused`, and returns a
104
+ * callback that restores the original pause state.
105
+ *
106
+ * Impersonates `admin` and grants it `pauseAdminRole()` when missing, same as
107
+ * `greenlistMidasGateway` does with the greenlist roles. The grant is not
108
+ * reverted by the callback, only the pause state is.
109
+ */
110
+ async function unpauseMidasIssuanceVault(props) {
111
+ const { anvil, vault, admin, logger } = props;
112
+ if (!await anvil.readContract({
113
+ address: vault,
114
+ abi: iMidasPausableVaultAbi,
115
+ functionName: "paused"
116
+ })) {
117
+ logger?.debug(`midas: issuance vault ${vault} is not paused`);
118
+ return async () => {};
119
+ }
120
+ const [accessControl, pauseAdminRole] = await anvil.multicall({
121
+ allowFailure: false,
122
+ contracts: [{
123
+ address: vault,
124
+ abi: iMidasPausableVaultAbi,
125
+ functionName: "accessControl"
126
+ }, {
127
+ address: vault,
128
+ abi: iMidasPausableVaultAbi,
129
+ functionName: "pauseAdminRole"
130
+ }]
131
+ });
132
+ const isPauseAdmin = await anvil.readContract({
133
+ address: accessControl,
134
+ abi: iMidasAccessControlAbi,
135
+ functionName: "hasRole",
136
+ args: [pauseAdminRole, admin]
137
+ });
138
+ logger?.debug(`midas: unpausing issuance vault ${vault} as ${admin}, access control ${accessControl}, pause admin role ${pauseAdminRole}`);
139
+ await anvil.impersonateAccount({ address: admin });
140
+ try {
141
+ await anvil.setBalance({
142
+ address: admin,
143
+ value: parseEther("100")
144
+ });
145
+ if (!isPauseAdmin) {
146
+ await writeAndWait(anvil, {
147
+ account: admin,
148
+ chain: anvil.chain,
149
+ address: accessControl,
150
+ abi: iMidasAccessControlAbi,
151
+ functionName: "grantRole",
152
+ args: [pauseAdminRole, admin]
153
+ });
154
+ logger?.debug(`midas: granted pause admin role to ${admin}`);
155
+ }
156
+ await writeAndWait(anvil, {
157
+ account: admin,
158
+ chain: anvil.chain,
159
+ address: vault,
160
+ abi: iMidasPausableVaultAbi,
161
+ functionName: "unpause"
162
+ });
163
+ } finally {
164
+ await anvil.stopImpersonatingAccount({ address: admin });
165
+ }
166
+ let toRestore = true;
167
+ return async () => {
168
+ if (!toRestore) return;
169
+ toRestore = false;
170
+ logger?.debug(`midas: pausing issuance vault ${vault} back`);
171
+ await anvil.impersonateAccount({ address: admin });
172
+ try {
173
+ await anvil.setBalance({
174
+ address: admin,
175
+ value: parseEther("100")
176
+ });
177
+ await writeAndWait(anvil, {
178
+ account: admin,
179
+ chain: anvil.chain,
180
+ address: vault,
181
+ abi: iMidasPausableVaultAbi,
182
+ functionName: "pause"
183
+ });
184
+ } catch (e) {
185
+ logger?.warn(`midas: failed to pause issuance vault ${vault} back: ${e}`);
186
+ } finally {
187
+ await anvil.stopImpersonatingAccount({ address: admin });
188
+ }
189
+ };
190
+ }
88
191
  async function readMTokens(client, adapters) {
89
192
  return await client.multicall({
90
193
  allowFailure: false,
@@ -96,4 +199,4 @@ async function readMTokens(client, adapters) {
96
199
  });
97
200
  }
98
201
  //#endregion
99
- export { prependMidasReceiveGreenlist };
202
+ export { prependMidasReceiveGreenlist, unpauseMidasIssuanceVault };
@@ -1,3 +1,4 @@
1
+ import { AddressSet } from "../sdk/utils/AddressSet.js";
1
2
  import { OnchainSDK } from "../sdk/OnchainSDK.js";
2
3
  import "../sdk/index.js";
3
4
  import { iDSTokenAbi } from "../abi/rwa/iDSToken.js";
@@ -13,7 +14,9 @@ const iDSComplianceConfigurationServiceAbi = parseAbi([
13
14
  "function getUSLockPeriod() external view returns (uint256)",
14
15
  "function getNonUSLockPeriod() external view returns (uint256)",
15
16
  "function setUSLockPeriod(uint256) external",
16
- "function setNonUSLockPeriod(uint256) external"
17
+ "function setNonUSLockPeriod(uint256) external",
18
+ "function getDisallowBackDating() external view returns (bool)",
19
+ "function setDisallowBackDating(bool) external"
17
20
  ]);
18
21
  /**
19
22
  * Returns the longest of US and non-US compliance lock periods, or `undefined`
@@ -61,7 +64,7 @@ async function issueDSTokens(props) {
61
64
  const { timestamp } = await anvil.getBlock();
62
65
  const issuanceTime = timestamp - lockPeriod - 1n;
63
66
  try {
64
- await writeAndWait(anvil, {
67
+ const hash = await writeAndWait(anvil, {
65
68
  account,
66
69
  chain: anvil.chain,
67
70
  address: token,
@@ -81,6 +84,7 @@ async function issueDSTokens(props) {
81
84
  investor,
82
85
  amount
83
86
  }, "issueTokensCustom successful");
87
+ return hash;
84
88
  } catch (e) {
85
89
  logger?.debug(`issueTokensCustom failed: ${e}`);
86
90
  }
@@ -98,6 +102,94 @@ async function issueDSTokens(props) {
98
102
  args: [investor, amount]
99
103
  });
100
104
  }
105
+ /**
106
+ * Resolves unique compliance configuration services of `tokens`: several
107
+ * DSTokens can share one service, and it's the service that holds the flags.
108
+ * Tokens without one (e.g. MockDSToken) are skipped
109
+ */
110
+ async function getComplianceConfigurationServices({ anvil, tokens, logger }) {
111
+ const services = new AddressSet();
112
+ for (const token of new AddressSet(tokens)) try {
113
+ const service = await anvil.readContract({
114
+ address: token,
115
+ abi: iDSTokenAbi,
116
+ functionName: "getDSService",
117
+ args: [COMPLIANCE_CONFIGURATION_SERVICE]
118
+ });
119
+ if (isAddressEqual(service, zeroAddress)) {
120
+ logger?.debug(`${token} has no compliance configuration service`);
121
+ continue;
122
+ }
123
+ services.add(service);
124
+ } catch (e) {
125
+ logger?.debug(`Failed to get compliance configuration service of ${token}: ${e}`);
126
+ }
127
+ return [...services];
128
+ }
129
+ /**
130
+ * Sets `disallowBackDating` to false on compliance configuration services of
131
+ * `tokens`, so that the issuance time passed to `issueTokensCustom` is
132
+ * honoured: DS protocol silently replaces it with `block.timestamp` otherwise,
133
+ * and freshly minted tokens stay under lock-up.
134
+ *
135
+ * Must be signed by a DS admin with sufficient trust (same key as
136
+ * `issueTokens` / registerInvestor); Ownable `owner()` alone is not enough.
137
+ *
138
+ * The flag is only read while tokens are issued, so restoring it does not
139
+ * re-lock tokens minted in the meantime.
140
+ */
141
+ async function enableDSTokenBackDating(props) {
142
+ const { anvil, adminPrivateKey, logger } = props;
143
+ const account = privateKeyToAccount(adminPrivateKey);
144
+ const services = await getComplianceConfigurationServices(props);
145
+ let toRestore = [];
146
+ for (const service of services) {
147
+ let disallowBackDating;
148
+ try {
149
+ disallowBackDating = await anvil.readContract({
150
+ address: service,
151
+ abi: iDSComplianceConfigurationServiceAbi,
152
+ functionName: "getDisallowBackDating"
153
+ });
154
+ } catch (e) {
155
+ logger?.debug(`Failed to read disallowBackDating of ${service}: ${e}`);
156
+ continue;
157
+ }
158
+ if (!disallowBackDating) {
159
+ logger?.debug(`Back-dating is already allowed by ${service}`);
160
+ continue;
161
+ }
162
+ logger?.info(`Allowing back-dating on ${service}`);
163
+ await writeAndWait(anvil, {
164
+ account,
165
+ chain: anvil.chain,
166
+ address: service,
167
+ abi: iDSComplianceConfigurationServiceAbi,
168
+ functionName: "setDisallowBackDating",
169
+ args: [false]
170
+ });
171
+ toRestore.push(service);
172
+ }
173
+ return async () => {
174
+ const services = toRestore;
175
+ toRestore = [];
176
+ for (const service of services) {
177
+ logger?.info(`Disallowing back-dating on ${service}`);
178
+ try {
179
+ await writeAndWait(anvil, {
180
+ account,
181
+ chain: anvil.chain,
182
+ address: service,
183
+ abi: iDSComplianceConfigurationServiceAbi,
184
+ functionName: "setDisallowBackDating",
185
+ args: [true]
186
+ });
187
+ } catch (e) {
188
+ logger?.warn(`Failed to restore disallowBackDating on ${service}: ${e}`);
189
+ }
190
+ }
191
+ };
192
+ }
101
193
  async function claimDSToken(props) {
102
194
  const { anvil, investor, adminPrivateKey, token, marketConfigurators, rwaFactories, usdAmount: usdAmountProp = "100000" } = props;
103
195
  const account = privateKeyToAccount(adminPrivateKey);
@@ -161,4 +253,4 @@ async function claimDSTokens(props) {
161
253
  });
162
254
  }
163
255
  //#endregion
164
- export { claimDSToken, claimDSTokens };
256
+ export { claimDSToken, claimDSTokens, enableDSTokenBackDating };
@@ -14,7 +14,7 @@ import { isTransientError } from "./isTransientError.js";
14
14
  import { GreenlistMidasGatewayProps, RWAKycFailure, RegisterMidasInvestorProps, RegisterRWAInvestorProps, RegisterRWAInvestorResult, RegisterSecuritizeInvestorProps, greenlistMidasGateway, registerMidasInvestor, registerRWAInvestor, registerSecuritizeInvestor, writeAndWait } from "./kycUtils.js";
15
15
  import { LogSplitterTransportOptions, isRangeError, logSplitterTransport } from "./logSplitterTransport.js";
16
16
  import { setLTZero, setLTs } from "./ltUtils.js";
17
- import { PrependMidasReceiveGreenlistProps, prependMidasReceiveGreenlist } from "./midasUtils.js";
17
+ import { PrependMidasReceiveGreenlistProps, RestoreMidasIssuanceVaultPause, UnpauseMidasIssuanceVaultProps, prependMidasReceiveGreenlist, unpauseMidasIssuanceVault } from "./midasUtils.js";
18
18
  import { migrateFaucet } from "./migrateFaucet.js";
19
19
  import { IMinter } from "./mint/types.js";
20
20
  import { createMinter } from "./mint/factory.js";
@@ -22,8 +22,8 @@ import "./mint/index.js";
22
22
  import { RpcProvider, SUPPORTED_RPC_PROVIDERS, getAlchemyUrl, getAnkrUrl, getDrpcUrl, getErpcKey, getRpcProviderUrl, getThirdWebUrl, rpcProvidersSchema } from "./providers.js";
23
23
  import { ReplaceStorageParams, replaceStorage } from "./replaceStorage.js";
24
24
  import { ResilientTransportOptions, resilientTransport, resilientTransportOptionsSchema } from "./resilientTransport.js";
25
- import { DisableDSTokenLockPeriodsProps, claimDSToken, claimDSTokens } from "./securitizeUtils.js";
25
+ import { EnableDSTokenBackDatingProps, RestoreDSTokenBackDating, claimDSToken, claimDSTokens, enableDSTokenBackDating } from "./securitizeUtils.js";
26
26
  import { httpTransportOptionsSchema } from "./transports.js";
27
27
  import { ONCHAIN_EXECUTION_ID_ADDRESS, VerifyTestnetParams, verifyTestnet } from "./verifyTestnet.js";
28
28
  import { MakePendingWithdrawalsClaimableOptions, makePendingWithdrawalsClaimable } from "./withdrawalUtils.js";
29
- export { AccountOpener, AccountOpenerOptions, AnvilActions, AnvilClient, AnvilClientConfig, AnvilDealParameters, AnvilNodeInfo, AnvilRPCSchema, CheckMulticallFn, Create2Deployer, Create2Parameters, DEFAULT_CREATE2_SALT, DetectedCall, DisableDSTokenLockPeriodsProps, EnsureExistsUsingPublicCreate2ReturnType, EthCallMethod, EthCallRequest, EthCallSpy, GetCreate2AddressParameters, GreenlistMidasGatewayProps, IMinter, type LogSplitterTransportOptions, MakePendingWithdrawalsClaimableOptions, NoAvailableTransportsError, ONCHAIN_EXECUTION_ID_ADDRESS, OpenAccountHumanizedPreview, OpenAccountResult, OpenAccountsResult, OpenTxRevertedError, PUBLIC_CREATE2_FACTORY, PoolDepositResult, PrependMidasReceiveGreenlistProps, ProviderConfig, ProviderStatus, RWAKycFailure, RegisterMidasInvestorProps, RegisterRWAInvestorProps, RegisterRWAInvestorResult, RegisterSecuritizeInvestorProps, ReplaceStorageParams, ResilientTransportOptions, RevolverTransport, RevolverTransportConfig, RevolverTransportValue, RpcErrorResult, RpcProvider, RpcResponse, RpcSuccessResult, SUPPORTED_RPC_PROVIDERS, SelectionStrategy, TargetAccount, VerifyTestnetParams, anvilNodeInfo, calcLiquidatableLTs, claimDSToken, claimDSTokens, claimFromFaucet, createAnvilClient, createMinter, deployUsingPublicCreate2, detectChain, evmMineDetailed, extendAnvilClient, faucetAbi, getAlchemyUrl, getAnkrUrl, getDrpcUrl, getErpcKey, getPublicCreate2Address, getRpcProviderUrl, getThirdWebUrl, greenlistMidasGateway, httpTransportOptionsSchema, iDegenNftv2Abi, iOnchainExecutionIdAbi, iOwnableAbi, iaclTraitAbi, isAnvil, isDeployedUsingPublicCreate2, isOutOfSyncError, isRangeError, isRateLimitError, isTransientError, logSplitterTransport, makePendingWithdrawalsClaimable, migrateFaucet, prependMidasReceiveGreenlist, providerConfigSchema, registerMidasInvestor, registerRWAInvestor, registerSecuritizeInvestor, replaceStorage, resilientTransport, resilientTransportOptionsSchema, revolverTransportConfigBaseSchema, revolverTransportConfigSchema, rpcProvidersSchema, setLTZero, setLTs, verifyTestnet, writeAndWait };
29
+ export { AccountOpener, AccountOpenerOptions, AnvilActions, AnvilClient, AnvilClientConfig, AnvilDealParameters, AnvilNodeInfo, AnvilRPCSchema, CheckMulticallFn, Create2Deployer, Create2Parameters, DEFAULT_CREATE2_SALT, DetectedCall, EnableDSTokenBackDatingProps, EnsureExistsUsingPublicCreate2ReturnType, EthCallMethod, EthCallRequest, EthCallSpy, GetCreate2AddressParameters, GreenlistMidasGatewayProps, IMinter, type LogSplitterTransportOptions, MakePendingWithdrawalsClaimableOptions, NoAvailableTransportsError, ONCHAIN_EXECUTION_ID_ADDRESS, OpenAccountHumanizedPreview, OpenAccountResult, OpenAccountsResult, OpenTxRevertedError, PUBLIC_CREATE2_FACTORY, PoolDepositResult, PrependMidasReceiveGreenlistProps, ProviderConfig, ProviderStatus, RWAKycFailure, RegisterMidasInvestorProps, RegisterRWAInvestorProps, RegisterRWAInvestorResult, RegisterSecuritizeInvestorProps, ReplaceStorageParams, ResilientTransportOptions, RestoreDSTokenBackDating, RestoreMidasIssuanceVaultPause, RevolverTransport, RevolverTransportConfig, RevolverTransportValue, RpcErrorResult, RpcProvider, RpcResponse, RpcSuccessResult, SUPPORTED_RPC_PROVIDERS, SelectionStrategy, TargetAccount, UnpauseMidasIssuanceVaultProps, VerifyTestnetParams, anvilNodeInfo, calcLiquidatableLTs, claimDSToken, claimDSTokens, claimFromFaucet, createAnvilClient, createMinter, deployUsingPublicCreate2, detectChain, enableDSTokenBackDating, evmMineDetailed, extendAnvilClient, faucetAbi, getAlchemyUrl, getAnkrUrl, getDrpcUrl, getErpcKey, getPublicCreate2Address, getRpcProviderUrl, getThirdWebUrl, greenlistMidasGateway, httpTransportOptionsSchema, iDegenNftv2Abi, iOnchainExecutionIdAbi, iOwnableAbi, iaclTraitAbi, isAnvil, isDeployedUsingPublicCreate2, isOutOfSyncError, isRangeError, isRateLimitError, isTransientError, logSplitterTransport, makePendingWithdrawalsClaimable, migrateFaucet, prependMidasReceiveGreenlist, providerConfigSchema, registerMidasInvestor, registerRWAInvestor, registerSecuritizeInvestor, replaceStorage, resilientTransport, resilientTransportOptionsSchema, revolverTransportConfigBaseSchema, revolverTransportConfigSchema, rpcProvidersSchema, setLTZero, setLTs, unpauseMidasIssuanceVault, verifyTestnet, writeAndWait };
@@ -2,7 +2,8 @@ import { ILogger } from "../sdk/types/logger.js";
2
2
  import { CreditSuite } from "../sdk/market/credit/CreditSuite.js";
3
3
  import { MultiCall } from "../sdk/types/transactions.js";
4
4
  import "../sdk/index.js";
5
- import { PublicClient } from "viem";
5
+ import { AnvilClient } from "./createAnvilClient.js";
6
+ import { Address, PublicClient } from "viem";
6
7
  //#region src/dev/midasUtils.d.ts
7
8
  interface PrependMidasReceiveGreenlistProps {
8
9
  /**
@@ -35,5 +36,33 @@ interface PrependMidasReceiveGreenlistProps {
35
36
  * the gateway is permissionless, or the call is already there.
36
37
  */
37
38
  declare function prependMidasReceiveGreenlist(props: PrependMidasReceiveGreenlistProps): Promise<MultiCall[]>;
39
+ interface UnpauseMidasIssuanceVaultProps {
40
+ anvil: AnvilClient;
41
+ /**
42
+ * Midas issuance vault (deposit vault) to unpause
43
+ */
44
+ vault: Address;
45
+ /**
46
+ * Midas access control admin, impersonated on the fork
47
+ * (MIDAS_ACL_ADMIN in periphery-v3/router-v3 foundry tests)
48
+ */
49
+ admin: Address;
50
+ logger?: ILogger;
51
+ }
52
+ /**
53
+ * Pauses the vault back when it was unpaused by `unpauseMidasIssuanceVault`,
54
+ * and does nothing otherwise. Safe to call more than once.
55
+ */
56
+ type RestoreMidasIssuanceVaultPause = () => Promise<void>;
57
+ /**
58
+ * Unpauses a globally paused Midas issuance vault on an anvil fork, so that
59
+ * `depositInstant` stops reverting with `Pausable: paused`, and returns a
60
+ * callback that restores the original pause state.
61
+ *
62
+ * Impersonates `admin` and grants it `pauseAdminRole()` when missing, same as
63
+ * `greenlistMidasGateway` does with the greenlist roles. The grant is not
64
+ * reverted by the callback, only the pause state is.
65
+ */
66
+ declare function unpauseMidasIssuanceVault(props: UnpauseMidasIssuanceVaultProps): Promise<RestoreMidasIssuanceVaultPause>;
38
67
  //#endregion
39
- export { PrependMidasReceiveGreenlistProps, prependMidasReceiveGreenlist };
68
+ export { PrependMidasReceiveGreenlistProps, RestoreMidasIssuanceVaultPause, UnpauseMidasIssuanceVaultProps, prependMidasReceiveGreenlist, unpauseMidasIssuanceVault };
@@ -22,7 +22,7 @@ interface ClaimDSTokenProps {
22
22
  type ClaimDSTokensProps = Omit<ClaimDSTokenProps, "token"> & {
23
23
  tokens: Address[];
24
24
  };
25
- interface DisableDSTokenLockPeriodsProps {
25
+ interface EnableDSTokenBackDatingProps {
26
26
  anvil: AnvilClient;
27
27
  /**
28
28
  * Securitize DS admin with sufficient trust to call compliance setters
@@ -30,11 +30,29 @@ interface DisableDSTokenLockPeriodsProps {
30
30
  */
31
31
  adminPrivateKey: Hex;
32
32
  /**
33
- * DSToken addresses whose compliance lock periods should be zeroed
33
+ * DSToken addresses whose compliance configuration should allow back-dating
34
34
  */
35
35
  tokens: Address[];
36
36
  logger?: ILogger;
37
37
  }
38
+ /**
39
+ * Restores `disallowBackDating` to its previous value on every compliance
40
+ * configuration service that was changed. Safe to call more than once.
41
+ */
42
+ type RestoreDSTokenBackDating = () => Promise<void>;
43
+ /**
44
+ * Sets `disallowBackDating` to false on compliance configuration services of
45
+ * `tokens`, so that the issuance time passed to `issueTokensCustom` is
46
+ * honoured: DS protocol silently replaces it with `block.timestamp` otherwise,
47
+ * and freshly minted tokens stay under lock-up.
48
+ *
49
+ * Must be signed by a DS admin with sufficient trust (same key as
50
+ * `issueTokens` / registerInvestor); Ownable `owner()` alone is not enough.
51
+ *
52
+ * The flag is only read while tokens are issued, so restoring it does not
53
+ * re-lock tokens minted in the meantime.
54
+ */
55
+ declare function enableDSTokenBackDating(props: EnableDSTokenBackDatingProps): Promise<RestoreDSTokenBackDating>;
38
56
  declare function claimDSToken(props: ClaimDSTokenProps): Promise<void>;
39
57
  /**
40
58
  * Helper function to claim DSToken from the faucet.
@@ -46,4 +64,4 @@ declare function claimDSToken(props: ClaimDSTokenProps): Promise<void>;
46
64
  */
47
65
  declare function claimDSTokens(props: ClaimDSTokensProps): Promise<void>;
48
66
  //#endregion
49
- export { DisableDSTokenLockPeriodsProps, claimDSToken, claimDSTokens };
67
+ export { EnableDSTokenBackDatingProps, RestoreDSTokenBackDating, claimDSToken, claimDSTokens, enableDSTokenBackDating };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gearbox-protocol/sdk",
3
- "version": "14.12.0-next.64",
3
+ "version": "14.12.0-next.66",
4
4
  "description": "Gearbox SDK",
5
5
  "license": "MIT",
6
6
  "repository": {