@gearbox-protocol/sdk 14.12.0-next.63 → 14.12.0-next.65

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 (30) hide show
  1. package/dist/cjs/dev/index.js +1 -1
  2. package/dist/cjs/dev/securitizeUtils.js +108 -87
  3. package/dist/cjs/sdk/accounts/liquidations/helpers.js +33 -16
  4. package/dist/esm/dev/AccountOpener.js +1 -1
  5. package/dist/esm/dev/index.js +2 -2
  6. package/dist/esm/dev/securitizeUtils.js +108 -87
  7. package/dist/esm/dev/withdrawalUtils.js +1 -1
  8. package/dist/esm/preview/simulate/simulatePoolOperation.js +1 -1
  9. package/dist/esm/preview/trace/extractTransfers.js +1 -1
  10. package/dist/esm/sdk/accounts/CreditAccountsServiceV310.js +2 -2
  11. package/dist/esm/sdk/accounts/liquidations/LiquidationsService.js +1 -1
  12. package/dist/esm/sdk/accounts/liquidations/helpers.js +33 -16
  13. package/dist/esm/sdk/accounts/withdrawal-compressor/RedemptionLoggerV310Contract.js +1 -1
  14. package/dist/esm/sdk/accounts/withdrawal-compressor/WithdrawalCompressorV310Contract.js +1 -1
  15. package/dist/esm/sdk/accounts/withdrawal-compressor/WithdrawalCompressorV311Contract.js +1 -1
  16. package/dist/esm/sdk/accounts/withdrawal-compressor/WithdrawalCompressorV313Contract.js +1 -1
  17. package/dist/esm/sdk/base/TokensMeta.js +2 -2
  18. package/dist/esm/sdk/chain/detectNetwork.js +1 -1
  19. package/dist/esm/sdk/core/createAddressProvider.js +1 -1
  20. package/dist/esm/sdk/market/credit/CreditFacadeV310BaseContract.js +1 -1
  21. package/dist/esm/sdk/market/pool/PoolV310Contract.js +1 -1
  22. package/dist/esm/sdk/market/zapper/IETHZapperContract.js +1 -1
  23. package/dist/esm/sdk/market/zapper/ZapperContract.js +1 -1
  24. package/dist/esm/sdk/pools/PoolService.js +1 -1
  25. package/dist/esm/sdk/utils/viem/simulateWithPriceUpdates.js +1 -1
  26. package/dist/types/dev/index.d.ts +2 -2
  27. package/dist/types/dev/securitizeUtils.d.ts +16 -8
  28. package/dist/types/sdk/accounts/liquidations/helpers.d.ts +3 -3
  29. package/dist/types/sdk/accounts/liquidations/types.d.ts +7 -10
  30. package/package.json +1 -1
@@ -46,7 +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.disableDSTokenLockPeriods = require_dev_securitizeUtils.disableDSTokenLockPeriods;
49
+ exports.enableDSTokenBackDating = require_dev_securitizeUtils.enableDSTokenBackDating;
50
50
  exports.evmMineDetailed = require_dev_createAnvilClient.evmMineDetailed;
51
51
  exports.extendAnvilClient = require_dev_createAnvilClient.extendAnvilClient;
52
52
  exports.faucetAbi = require_dev_abi.faucetAbi;
@@ -15,14 +15,15 @@ const iDSComplianceConfigurationServiceAbi = (0, viem.parseAbi)([
15
15
  "function getUSLockPeriod() external view returns (uint256)",
16
16
  "function getNonUSLockPeriod() external view returns (uint256)",
17
17
  "function setUSLockPeriod(uint256) external",
18
- "function setNonUSLockPeriod(uint256) external"
18
+ "function setNonUSLockPeriod(uint256) external",
19
+ "function getDisallowBackDating() external view returns (bool)",
20
+ "function setDisallowBackDating(bool) external"
19
21
  ]);
20
22
  /**
21
- * Returns issuance time that is old enough for the issued tokens to be past
22
- * both US and non-US compliance lock periods, or `undefined` when the token
23
- * has no compliance configuration service (e.g. MockDSToken)
23
+ * Returns the longest of US and non-US compliance lock periods, or `undefined`
24
+ * when the token has no compliance configuration service (e.g. MockDSToken)
24
25
  */
25
- async function getUnlockedIssuanceTime({ anvil, token, logger }) {
26
+ async function getLockPeriod({ anvil, token, logger }) {
26
27
  try {
27
28
  const complianceConfiguration = await anvil.readContract({
28
29
  address: token,
@@ -43,10 +44,8 @@ async function getUnlockedIssuanceTime({ anvil, token, logger }) {
43
44
  }],
44
45
  allowFailure: false
45
46
  });
46
- const lockPeriod = usLockPeriod > nonUSLockPeriod ? usLockPeriod : nonUSLockPeriod;
47
- const { timestamp } = await anvil.getBlock();
48
47
  logger?.debug(`Lock periods: US ${usLockPeriod}, non-US ${nonUSLockPeriod} (compliance configuration service ${complianceConfiguration})`);
49
- return timestamp > lockPeriod ? timestamp - lockPeriod : 0n;
48
+ return usLockPeriod > nonUSLockPeriod ? usLockPeriod : nonUSLockPeriod;
50
49
  } catch (e) {
51
50
  logger?.debug(`Failed to get compliance lock periods: ${e}`);
52
51
  return;
@@ -61,27 +60,40 @@ async function getUnlockedIssuanceTime({ anvil, token, logger }) {
61
60
  */
62
61
  async function issueDSTokens(props) {
63
62
  const { anvil, account, token, investor, amount, logger } = props;
64
- const issuanceTime = await getUnlockedIssuanceTime(props);
65
- if (issuanceTime !== void 0) try {
66
- return await require_dev_kycUtils.writeAndWait(anvil, {
67
- account,
68
- chain: anvil.chain,
69
- address: token,
70
- abi: require_abi_rwa_iDSToken.iDSTokenAbi,
71
- functionName: "issueTokensCustom",
72
- args: [
73
- investor,
74
- amount,
63
+ const lockPeriod = await getLockPeriod(props);
64
+ if (lockPeriod !== void 0) {
65
+ const { timestamp } = await anvil.getBlock();
66
+ const issuanceTime = timestamp - lockPeriod - 1n;
67
+ try {
68
+ const hash = await require_dev_kycUtils.writeAndWait(anvil, {
69
+ account,
70
+ chain: anvil.chain,
71
+ address: token,
72
+ abi: require_abi_rwa_iDSToken.iDSTokenAbi,
73
+ functionName: "issueTokensCustom",
74
+ args: [
75
+ investor,
76
+ amount,
77
+ issuanceTime,
78
+ 0n,
79
+ "",
80
+ 0n
81
+ ]
82
+ });
83
+ logger?.debug({
75
84
  issuanceTime,
76
- 0n,
77
- "",
78
- 0n
79
- ]
80
- });
81
- } catch (e) {
82
- logger?.debug(`issueTokensCustom failed: ${e}`);
85
+ investor,
86
+ amount
87
+ }, "issueTokensCustom successful");
88
+ return hash;
89
+ } catch (e) {
90
+ logger?.debug(`issueTokensCustom failed: ${e}`);
91
+ }
83
92
  }
84
- logger?.debug("Falling back to issueTokens");
93
+ logger?.debug({
94
+ investor,
95
+ amount
96
+ }, "Falling back to issueTokens");
85
97
  return require_dev_kycUtils.writeAndWait(anvil, {
86
98
  account,
87
99
  chain: anvil.chain,
@@ -92,83 +104,92 @@ async function issueDSTokens(props) {
92
104
  });
93
105
  }
94
106
  /**
95
- * Zeros US and non-US compliance lock periods on each DSToken's compliance
96
- * configuration service so collateral can be transferred during testnet
97
- * liquidations (e.g. STAC). No-ops for tokens without a compliance service
98
- * (MockDSToken) or when both periods are already 0.
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.
99
135
  *
100
136
  * Must be signed by a DS admin with sufficient trust (same key as
101
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.
102
141
  */
103
- async function disableDSTokenLockPeriods(props) {
142
+ async function enableDSTokenBackDating(props) {
104
143
  const { anvil, adminPrivateKey, logger } = props;
105
144
  const account = (0, viem_accounts.privateKeyToAccount)(adminPrivateKey);
106
- const tokens = [...new require_sdk_utils_AddressSet.AddressSet(props.tokens)];
107
- for (const token of tokens) {
108
- const symbol = await anvil.readContract({
109
- address: token,
110
- abi: viem.erc20Abi,
111
- functionName: "symbol",
112
- args: []
113
- }).catch(() => token);
114
- const tokenLogger = logger?.child?.({ symbol }) ?? logger;
115
- let complianceConfiguration;
116
- try {
117
- complianceConfiguration = await anvil.readContract({
118
- address: token,
119
- abi: require_abi_rwa_iDSToken.iDSTokenAbi,
120
- functionName: "getDSService",
121
- args: [COMPLIANCE_CONFIGURATION_SERVICE]
122
- });
123
- } catch (e) {
124
- tokenLogger?.debug(`Skipping lock-period disable for ${symbol}: no compliance service (${e})`);
125
- continue;
126
- }
127
- if ((0, viem.isAddressEqual)(complianceConfiguration, viem.zeroAddress)) {
128
- tokenLogger?.debug(`Skipping lock-period disable for ${symbol}: compliance configuration service is zero`);
129
- continue;
130
- }
131
- let usLockPeriod;
132
- let nonUSLockPeriod;
145
+ const services = await getComplianceConfigurationServices(props);
146
+ let toRestore = [];
147
+ for (const service of services) {
148
+ let disallowBackDating;
133
149
  try {
134
- [usLockPeriod, nonUSLockPeriod] = await anvil.multicall({
135
- contracts: [{
136
- address: complianceConfiguration,
137
- abi: iDSComplianceConfigurationServiceAbi,
138
- functionName: "getUSLockPeriod"
139
- }, {
140
- address: complianceConfiguration,
141
- abi: iDSComplianceConfigurationServiceAbi,
142
- functionName: "getNonUSLockPeriod"
143
- }],
144
- allowFailure: false
150
+ disallowBackDating = await anvil.readContract({
151
+ address: service,
152
+ abi: iDSComplianceConfigurationServiceAbi,
153
+ functionName: "getDisallowBackDating"
145
154
  });
146
155
  } catch (e) {
147
- tokenLogger?.debug(`Skipping lock-period disable for ${symbol}: failed to read lock periods (${e})`);
156
+ logger?.debug(`Failed to read disallowBackDating of ${service}: ${e}`);
148
157
  continue;
149
158
  }
150
- if (usLockPeriod === 0n && nonUSLockPeriod === 0n) {
151
- tokenLogger?.debug(`Lock periods already 0 for ${symbol} (${complianceConfiguration})`);
159
+ if (!disallowBackDating) {
160
+ logger?.debug(`Back-dating is already allowed by ${service}`);
152
161
  continue;
153
162
  }
154
- tokenLogger?.info(`Zeroing lock periods for ${symbol}: US ${usLockPeriod} → 0, non-US ${nonUSLockPeriod} → 0 (${complianceConfiguration})`);
155
- if (usLockPeriod !== 0n) await require_dev_kycUtils.writeAndWait(anvil, {
163
+ logger?.info(`Allowing back-dating on ${service}`);
164
+ await require_dev_kycUtils.writeAndWait(anvil, {
156
165
  account,
157
166
  chain: anvil.chain,
158
- address: complianceConfiguration,
167
+ address: service,
159
168
  abi: iDSComplianceConfigurationServiceAbi,
160
- functionName: "setUSLockPeriod",
161
- args: [0n]
162
- });
163
- if (nonUSLockPeriod !== 0n) await require_dev_kycUtils.writeAndWait(anvil, {
164
- account,
165
- chain: anvil.chain,
166
- address: complianceConfiguration,
167
- abi: iDSComplianceConfigurationServiceAbi,
168
- functionName: "setNonUSLockPeriod",
169
- args: [0n]
169
+ functionName: "setDisallowBackDating",
170
+ args: [false]
170
171
  });
172
+ toRestore.push(service);
171
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
+ };
172
193
  }
173
194
  async function claimDSToken(props) {
174
195
  const { anvil, investor, adminPrivateKey, token, marketConfigurators, rwaFactories, usdAmount: usdAmountProp = "100000" } = props;
@@ -235,4 +256,4 @@ async function claimDSTokens(props) {
235
256
  //#endregion
236
257
  exports.claimDSToken = claimDSToken;
237
258
  exports.claimDSTokens = claimDSTokens;
238
- exports.disableDSTokenLockPeriods = disableDSTokenLockPeriods;
259
+ exports.enableDSTokenBackDating = enableDSTokenBackDating;
@@ -63,9 +63,36 @@ function pickMainAsset(ca, convert) {
63
63
  return bestToken;
64
64
  }
65
65
  /**
66
- * Flattens delayed withdrawals of a liquidator into per-output rows:
67
- * claimable outputs have no `claimableAt` (claimable now), pending outputs
68
- * carry the estimated claim timestamp.
66
+ * Converts the single output of a liquidator's delayed withdrawal into an asset.
67
+ *
68
+ * @param outputs - `outputs` or `expectedOutputs` of a withdrawal
69
+ * @param sourceToken - Source token of the withdrawal, for error reporting
70
+ **/
71
+ function toWithdrawalOutputAsset(outputs, sourceToken) {
72
+ const [output] = outputs;
73
+ if (outputs.length !== 1 || !output) throw new Error(`expected exactly one output for withdrawal of ${sourceToken}, got ${outputs.length}`);
74
+ return {
75
+ balance: output.amount,
76
+ token: output.token
77
+ };
78
+ }
79
+ /**
80
+ * Converts the claim calls of a liquidator's delayed withdrawal into a
81
+ * transaction.
82
+ *
83
+ * @param claimCalls - `claimCalls` of a claimable withdrawal
84
+ * @param sourceToken - Source token of the withdrawal, for error reporting
85
+ * @returns The claim transaction, or `undefined` when there is no claim call
86
+ **/
87
+ function toWithdrawalClaimTx(claimCalls, sourceToken) {
88
+ if (claimCalls.length > 1) throw new Error(`expected at most one claim call for withdrawal of ${sourceToken}, got ${claimCalls.length}`);
89
+ const [call] = claimCalls;
90
+ return call ? liquidationCallToRawTx(call) : void 0;
91
+ }
92
+ /**
93
+ * Flattens delayed withdrawals of a liquidator into rows: claimable
94
+ * withdrawals have no `claimableAt` (claimable now) and carry a `claimTx`,
95
+ * pending ones carry the estimated claim timestamp.
69
96
  *
70
97
  * @param current - Claimable and pending withdrawals from the withdrawal compressor
71
98
  * @param network - Network the withdrawals live on
@@ -76,25 +103,15 @@ function toLiquidatorWithdrawals(current, network, chainId) {
76
103
  network,
77
104
  chainId,
78
105
  sourceToken: w.token,
79
- outputs: w.outputs.map((o) => {
80
- return {
81
- balance: o.amount,
82
- token: o.token
83
- };
84
- }),
85
- claimCalls: w.claimCalls,
106
+ output: toWithdrawalOutputAsset(w.outputs, w.token),
107
+ claimTx: toWithdrawalClaimTx(w.claimCalls, w.token),
86
108
  redeemer: w.redeemer
87
109
  });
88
110
  for (const w of current.pending) rows.push({
89
111
  network,
90
112
  chainId,
91
113
  sourceToken: w.token,
92
- outputs: w.expectedOutputs.map((o) => {
93
- return {
94
- balance: o.amount,
95
- token: o.token
96
- };
97
- }),
114
+ output: toWithdrawalOutputAsset(w.expectedOutputs, w.token),
98
115
  claimableAt: w.claimableAt,
99
116
  redeemer: w.redeemer
100
117
  });
@@ -1,9 +1,9 @@
1
- import { ierc20Abi } from "../abi/iERC20.js";
2
1
  import { iCreditFacadeV310Abi } from "../abi/310/generated.js";
3
2
  import { AddressMap } from "../sdk/utils/AddressMap.js";
4
3
  import { AddressSet } from "../sdk/utils/AddressSet.js";
5
4
  import { AssetsMap } from "../sdk/utils/AssetsMap.js";
6
5
  import { childLogger } from "../sdk/utils/childLogger.js";
6
+ import { ierc20Abi } from "../abi/iERC20.js";
7
7
  import "../sdk/constants/addresses.js";
8
8
  import { MAX_UINT256, PERCENTAGE_FACTOR } from "../sdk/constants/math.js";
9
9
  import { SDKConstruct } from "../sdk/base/SDKConstruct.js";
@@ -21,8 +21,8 @@ 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, disableDSTokenLockPeriods } 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, disableDSTokenLockPeriods, 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, verifyTestnet, writeAndWait };
@@ -14,14 +14,15 @@ const iDSComplianceConfigurationServiceAbi = parseAbi([
14
14
  "function getUSLockPeriod() external view returns (uint256)",
15
15
  "function getNonUSLockPeriod() external view returns (uint256)",
16
16
  "function setUSLockPeriod(uint256) external",
17
- "function setNonUSLockPeriod(uint256) external"
17
+ "function setNonUSLockPeriod(uint256) external",
18
+ "function getDisallowBackDating() external view returns (bool)",
19
+ "function setDisallowBackDating(bool) external"
18
20
  ]);
19
21
  /**
20
- * Returns issuance time that is old enough for the issued tokens to be past
21
- * both US and non-US compliance lock periods, or `undefined` when the token
22
- * has no compliance configuration service (e.g. MockDSToken)
22
+ * Returns the longest of US and non-US compliance lock periods, or `undefined`
23
+ * when the token has no compliance configuration service (e.g. MockDSToken)
23
24
  */
24
- async function getUnlockedIssuanceTime({ anvil, token, logger }) {
25
+ async function getLockPeriod({ anvil, token, logger }) {
25
26
  try {
26
27
  const complianceConfiguration = await anvil.readContract({
27
28
  address: token,
@@ -42,10 +43,8 @@ async function getUnlockedIssuanceTime({ anvil, token, logger }) {
42
43
  }],
43
44
  allowFailure: false
44
45
  });
45
- const lockPeriod = usLockPeriod > nonUSLockPeriod ? usLockPeriod : nonUSLockPeriod;
46
- const { timestamp } = await anvil.getBlock();
47
46
  logger?.debug(`Lock periods: US ${usLockPeriod}, non-US ${nonUSLockPeriod} (compliance configuration service ${complianceConfiguration})`);
48
- return timestamp > lockPeriod ? timestamp - lockPeriod : 0n;
47
+ return usLockPeriod > nonUSLockPeriod ? usLockPeriod : nonUSLockPeriod;
49
48
  } catch (e) {
50
49
  logger?.debug(`Failed to get compliance lock periods: ${e}`);
51
50
  return;
@@ -60,27 +59,40 @@ async function getUnlockedIssuanceTime({ anvil, token, logger }) {
60
59
  */
61
60
  async function issueDSTokens(props) {
62
61
  const { anvil, account, token, investor, amount, logger } = props;
63
- const issuanceTime = await getUnlockedIssuanceTime(props);
64
- if (issuanceTime !== void 0) try {
65
- return await writeAndWait(anvil, {
66
- account,
67
- chain: anvil.chain,
68
- address: token,
69
- abi: iDSTokenAbi,
70
- functionName: "issueTokensCustom",
71
- args: [
72
- investor,
73
- amount,
62
+ const lockPeriod = await getLockPeriod(props);
63
+ if (lockPeriod !== void 0) {
64
+ const { timestamp } = await anvil.getBlock();
65
+ const issuanceTime = timestamp - lockPeriod - 1n;
66
+ try {
67
+ const hash = await writeAndWait(anvil, {
68
+ account,
69
+ chain: anvil.chain,
70
+ address: token,
71
+ abi: iDSTokenAbi,
72
+ functionName: "issueTokensCustom",
73
+ args: [
74
+ investor,
75
+ amount,
76
+ issuanceTime,
77
+ 0n,
78
+ "",
79
+ 0n
80
+ ]
81
+ });
82
+ logger?.debug({
74
83
  issuanceTime,
75
- 0n,
76
- "",
77
- 0n
78
- ]
79
- });
80
- } catch (e) {
81
- logger?.debug(`issueTokensCustom failed: ${e}`);
84
+ investor,
85
+ amount
86
+ }, "issueTokensCustom successful");
87
+ return hash;
88
+ } catch (e) {
89
+ logger?.debug(`issueTokensCustom failed: ${e}`);
90
+ }
82
91
  }
83
- logger?.debug("Falling back to issueTokens");
92
+ logger?.debug({
93
+ investor,
94
+ amount
95
+ }, "Falling back to issueTokens");
84
96
  return writeAndWait(anvil, {
85
97
  account,
86
98
  chain: anvil.chain,
@@ -91,83 +103,92 @@ async function issueDSTokens(props) {
91
103
  });
92
104
  }
93
105
  /**
94
- * Zeros US and non-US compliance lock periods on each DSToken's compliance
95
- * configuration service so collateral can be transferred during testnet
96
- * liquidations (e.g. STAC). No-ops for tokens without a compliance service
97
- * (MockDSToken) or when both periods are already 0.
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.
98
134
  *
99
135
  * Must be signed by a DS admin with sufficient trust (same key as
100
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.
101
140
  */
102
- async function disableDSTokenLockPeriods(props) {
141
+ async function enableDSTokenBackDating(props) {
103
142
  const { anvil, adminPrivateKey, logger } = props;
104
143
  const account = privateKeyToAccount(adminPrivateKey);
105
- const tokens = [...new AddressSet(props.tokens)];
106
- for (const token of tokens) {
107
- const symbol = await anvil.readContract({
108
- address: token,
109
- abi: erc20Abi,
110
- functionName: "symbol",
111
- args: []
112
- }).catch(() => token);
113
- const tokenLogger = logger?.child?.({ symbol }) ?? logger;
114
- let complianceConfiguration;
115
- try {
116
- complianceConfiguration = await anvil.readContract({
117
- address: token,
118
- abi: iDSTokenAbi,
119
- functionName: "getDSService",
120
- args: [COMPLIANCE_CONFIGURATION_SERVICE]
121
- });
122
- } catch (e) {
123
- tokenLogger?.debug(`Skipping lock-period disable for ${symbol}: no compliance service (${e})`);
124
- continue;
125
- }
126
- if (isAddressEqual(complianceConfiguration, zeroAddress)) {
127
- tokenLogger?.debug(`Skipping lock-period disable for ${symbol}: compliance configuration service is zero`);
128
- continue;
129
- }
130
- let usLockPeriod;
131
- let nonUSLockPeriod;
144
+ const services = await getComplianceConfigurationServices(props);
145
+ let toRestore = [];
146
+ for (const service of services) {
147
+ let disallowBackDating;
132
148
  try {
133
- [usLockPeriod, nonUSLockPeriod] = await anvil.multicall({
134
- contracts: [{
135
- address: complianceConfiguration,
136
- abi: iDSComplianceConfigurationServiceAbi,
137
- functionName: "getUSLockPeriod"
138
- }, {
139
- address: complianceConfiguration,
140
- abi: iDSComplianceConfigurationServiceAbi,
141
- functionName: "getNonUSLockPeriod"
142
- }],
143
- allowFailure: false
149
+ disallowBackDating = await anvil.readContract({
150
+ address: service,
151
+ abi: iDSComplianceConfigurationServiceAbi,
152
+ functionName: "getDisallowBackDating"
144
153
  });
145
154
  } catch (e) {
146
- tokenLogger?.debug(`Skipping lock-period disable for ${symbol}: failed to read lock periods (${e})`);
155
+ logger?.debug(`Failed to read disallowBackDating of ${service}: ${e}`);
147
156
  continue;
148
157
  }
149
- if (usLockPeriod === 0n && nonUSLockPeriod === 0n) {
150
- tokenLogger?.debug(`Lock periods already 0 for ${symbol} (${complianceConfiguration})`);
158
+ if (!disallowBackDating) {
159
+ logger?.debug(`Back-dating is already allowed by ${service}`);
151
160
  continue;
152
161
  }
153
- tokenLogger?.info(`Zeroing lock periods for ${symbol}: US ${usLockPeriod} → 0, non-US ${nonUSLockPeriod} → 0 (${complianceConfiguration})`);
154
- if (usLockPeriod !== 0n) await writeAndWait(anvil, {
162
+ logger?.info(`Allowing back-dating on ${service}`);
163
+ await writeAndWait(anvil, {
155
164
  account,
156
165
  chain: anvil.chain,
157
- address: complianceConfiguration,
166
+ address: service,
158
167
  abi: iDSComplianceConfigurationServiceAbi,
159
- functionName: "setUSLockPeriod",
160
- args: [0n]
161
- });
162
- if (nonUSLockPeriod !== 0n) await writeAndWait(anvil, {
163
- account,
164
- chain: anvil.chain,
165
- address: complianceConfiguration,
166
- abi: iDSComplianceConfigurationServiceAbi,
167
- functionName: "setNonUSLockPeriod",
168
- args: [0n]
168
+ functionName: "setDisallowBackDating",
169
+ args: [false]
169
170
  });
171
+ toRestore.push(service);
170
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
+ };
171
192
  }
172
193
  async function claimDSToken(props) {
173
194
  const { anvil, investor, adminPrivateKey, token, marketConfigurators, rwaFactories, usdAmount: usdAmountProp = "100000" } = props;
@@ -232,4 +253,4 @@ async function claimDSTokens(props) {
232
253
  });
233
254
  }
234
255
  //#endregion
235
- export { claimDSToken, claimDSTokens, disableDSTokenLockPeriods };
256
+ export { claimDSToken, claimDSTokens, enableDSTokenBackDating };
@@ -1,6 +1,6 @@
1
- import { iWithdrawalCompressorV313Abi } from "../abi/IWithdrawalCompressorV313.js";
2
1
  import { getNetworkType } from "../sdk/chain/chains.js";
3
2
  import { getWithdrawalCompressorAddress } from "../sdk/accounts/withdrawal-compressor/addresses.js";
3
+ import { iWithdrawalCompressorV313Abi } from "../abi/IWithdrawalCompressorV313.js";
4
4
  import "../sdk/index.js";
5
5
  import { iMidasDataFeedAbi, iMidasRedemptionVaultAbi, midasGatewayAbi, midasRedeemerAbi, midasRedemptionVaultPhantomTokenAbi, securitizeRedeemerAbi, securitizeRedemptionGatewayAbi, securitizeRedemptionPhantomTokenAbi } from "./withdrawalAbi.js";
6
6
  import { erc20Abi, hexToString, parseAbi, parseEther } from "viem";
@@ -1,5 +1,5 @@
1
- import { iZapperAbi } from "../../abi/iZapper.js";
2
1
  import { iPoolV310Abi } from "../../abi/310/generated.js";
2
+ import { iZapperAbi } from "../../abi/iZapper.js";
3
3
  import { asPreviewSimulationError } from "./errors.js";
4
4
  //#region src/preview/simulate/simulatePoolOperation.ts
5
5
  function previewRead(operation) {
@@ -1,6 +1,6 @@
1
- import { ierc20Abi } from "../../abi/iERC20.js";
2
1
  import { iCreditFacadeV310Abi } from "../../abi/310/generated.js";
3
2
  import { AddressMap } from "../../sdk/utils/AddressMap.js";
3
+ import { ierc20Abi } from "../../abi/iERC20.js";
4
4
  import "../../sdk/index.js";
5
5
  import { UnexpectedFacadeEventOrderError } from "./errors.js";
6
6
  import { getAddress, isAddressEqual, parseEventLogs } from "viem";
@@ -1,9 +1,9 @@
1
- import { iBaseRewardPoolAbi } from "../../abi/iBaseRewardPool.js";
2
- import { ierc4626AdapterAbi } from "../../abi/ierc4626Adapter.js";
3
1
  import { iBotListV310Abi, iCreditFacadeMulticallV310Abi } from "../../abi/310/generated.js";
4
2
  import { creditAccountCompressorAbi } from "../../abi/compressors/creditAccountCompressor.js";
5
3
  import { peripheryCompressorAbi } from "../../abi/compressors/peripheryCompressor.js";
6
4
  import { rewardsCompressorAbi } from "../../abi/compressors/rewardsCompressor.js";
5
+ import { iBaseRewardPoolAbi } from "../../abi/iBaseRewardPool.js";
6
+ import { ierc4626AdapterAbi } from "../../abi/ierc4626Adapter.js";
7
7
  import { iRWAFactoryAbi } from "../../abi/rwa/iRWAFactory.js";
8
8
  import { AddressMap } from "../utils/AddressMap.js";
9
9
  import { AddressSet } from "../utils/AddressSet.js";
@@ -1,4 +1,3 @@
1
- import { iLiquidationCompressorV313Abi } from "../../../abi/ILiquidationCompressorV313.js";
2
1
  import { AddressSet } from "../../utils/AddressSet.js";
3
2
  import { bytes32ToString } from "../../utils/bytes32ToString.js";
4
3
  import { ADDRESS_0X0 } from "../../constants/addresses.js";
@@ -15,6 +14,7 @@ import { RWA_LIQUIDATOR_SECURITIZE } from "../../market/rwa/securitize/constants
15
14
  import { SecuritizeLiquidatorContract } from "../../market/rwa/securitize/SecuritizeLiquidatorContract.js";
16
15
  import "../../market/rwa/securitize/index.js";
17
16
  import { LIQUIDATION_COMPRESSOR_V313_ADDRESS } from "./constants.js";
17
+ import { iLiquidationCompressorV313Abi } from "../../../abi/ILiquidationCompressorV313.js";
18
18
  import { calcEstimatedProfit, calcRepaymentAmount, liquidationCallToRawTx, pickMainAsset, toLiquidationApproval, toLiquidatorWithdrawals, toReceivedAssets } from "./helpers.js";
19
19
  //#region src/sdk/accounts/liquidations/LiquidationsService.ts
20
20
  /**
@@ -62,9 +62,36 @@ function pickMainAsset(ca, convert) {
62
62
  return bestToken;
63
63
  }
64
64
  /**
65
- * Flattens delayed withdrawals of a liquidator into per-output rows:
66
- * claimable outputs have no `claimableAt` (claimable now), pending outputs
67
- * carry the estimated claim timestamp.
65
+ * Converts the single output of a liquidator's delayed withdrawal into an asset.
66
+ *
67
+ * @param outputs - `outputs` or `expectedOutputs` of a withdrawal
68
+ * @param sourceToken - Source token of the withdrawal, for error reporting
69
+ **/
70
+ function toWithdrawalOutputAsset(outputs, sourceToken) {
71
+ const [output] = outputs;
72
+ if (outputs.length !== 1 || !output) throw new Error(`expected exactly one output for withdrawal of ${sourceToken}, got ${outputs.length}`);
73
+ return {
74
+ balance: output.amount,
75
+ token: output.token
76
+ };
77
+ }
78
+ /**
79
+ * Converts the claim calls of a liquidator's delayed withdrawal into a
80
+ * transaction.
81
+ *
82
+ * @param claimCalls - `claimCalls` of a claimable withdrawal
83
+ * @param sourceToken - Source token of the withdrawal, for error reporting
84
+ * @returns The claim transaction, or `undefined` when there is no claim call
85
+ **/
86
+ function toWithdrawalClaimTx(claimCalls, sourceToken) {
87
+ if (claimCalls.length > 1) throw new Error(`expected at most one claim call for withdrawal of ${sourceToken}, got ${claimCalls.length}`);
88
+ const [call] = claimCalls;
89
+ return call ? liquidationCallToRawTx(call) : void 0;
90
+ }
91
+ /**
92
+ * Flattens delayed withdrawals of a liquidator into rows: claimable
93
+ * withdrawals have no `claimableAt` (claimable now) and carry a `claimTx`,
94
+ * pending ones carry the estimated claim timestamp.
68
95
  *
69
96
  * @param current - Claimable and pending withdrawals from the withdrawal compressor
70
97
  * @param network - Network the withdrawals live on
@@ -75,25 +102,15 @@ function toLiquidatorWithdrawals(current, network, chainId) {
75
102
  network,
76
103
  chainId,
77
104
  sourceToken: w.token,
78
- outputs: w.outputs.map((o) => {
79
- return {
80
- balance: o.amount,
81
- token: o.token
82
- };
83
- }),
84
- claimCalls: w.claimCalls,
105
+ output: toWithdrawalOutputAsset(w.outputs, w.token),
106
+ claimTx: toWithdrawalClaimTx(w.claimCalls, w.token),
85
107
  redeemer: w.redeemer
86
108
  });
87
109
  for (const w of current.pending) rows.push({
88
110
  network,
89
111
  chainId,
90
112
  sourceToken: w.token,
91
- outputs: w.expectedOutputs.map((o) => {
92
- return {
93
- balance: o.amount,
94
- token: o.token
95
- };
96
- }),
113
+ output: toWithdrawalOutputAsset(w.expectedOutputs, w.token),
97
114
  claimableAt: w.claimableAt,
98
115
  redeemer: w.redeemer
99
116
  });
@@ -1,7 +1,7 @@
1
- import { iRedemptionLoggerV310Abi } from "../../../abi/iRedemptionLoggerV310.js";
2
1
  import { BaseContract } from "../../base/BaseContract.js";
3
2
  import "../../base/index.js";
4
3
  import { decodeDelayedIntent } from "./intent-codec.js";
4
+ import { iRedemptionLoggerV310Abi } from "../../../abi/iRedemptionLoggerV310.js";
5
5
  import { InvalidDelayedIntentError } from "./errors.js";
6
6
  //#region src/sdk/accounts/withdrawal-compressor/RedemptionLoggerV310Contract.ts
7
7
  const abi = iRedemptionLoggerV310Abi;
@@ -1,5 +1,5 @@
1
- import { iWithdrawalCompressorV310Abi } from "../../../abi/IWithdrawalCompressorV310.js";
2
1
  import { AbstractWithdrawalCompressorContract } from "./AbstractWithdrawalCompressorContract.js";
2
+ import { iWithdrawalCompressorV310Abi } from "../../../abi/IWithdrawalCompressorV310.js";
3
3
  //#region src/sdk/accounts/withdrawal-compressor/WithdrawalCompressorV310Contract.ts
4
4
  const abi = iWithdrawalCompressorV310Abi;
5
5
  /**
@@ -1,5 +1,5 @@
1
- import { iWithdrawalCompressorV311Abi } from "../../../abi/IWithdrawalCompressorV311.js";
2
1
  import { AbstractWithdrawalCompressorContract } from "./AbstractWithdrawalCompressorContract.js";
2
+ import { iWithdrawalCompressorV311Abi } from "../../../abi/IWithdrawalCompressorV311.js";
3
3
  //#region src/sdk/accounts/withdrawal-compressor/WithdrawalCompressorV311Contract.ts
4
4
  const abi = iWithdrawalCompressorV311Abi;
5
5
  /**
@@ -1,6 +1,6 @@
1
- import { iWithdrawalCompressorV313Abi } from "../../../abi/IWithdrawalCompressorV313.js";
2
1
  import { encodeDelayedIntent } from "./intent-codec.js";
3
2
  import { AbstractWithdrawalCompressorContract, iCreditAccountAbi, toClaimableWithdrawal, toPendingWithdrawal, toRequestableWithdrawal } from "./AbstractWithdrawalCompressorContract.js";
3
+ import { iWithdrawalCompressorV313Abi } from "../../../abi/IWithdrawalCompressorV313.js";
4
4
  import { toWithdrawalStatus } from "./types.js";
5
5
  //#region src/sdk/accounts/withdrawal-compressor/WithdrawalCompressorV313Contract.ts
6
6
  const abi = iWithdrawalCompressorV313Abi;
@@ -1,10 +1,10 @@
1
- import { iStateSerializerAbi } from "../../abi/iStateSerializer.js";
2
- import { iVersionAbi } from "../../abi/iVersion.js";
3
1
  import { AddressMap } from "../utils/AddressMap.js";
4
2
  import { AddressSet } from "../utils/AddressSet.js";
5
3
  import { bytes32ToString } from "../utils/bytes32ToString.js";
6
4
  import { formatBN } from "../utils/formatter.js";
7
5
  import "../utils/index.js";
6
+ import { iStateSerializerAbi } from "../../abi/iStateSerializer.js";
7
+ import { iVersionAbi } from "../../abi/iVersion.js";
8
8
  //#region src/sdk/base/TokensMeta.ts
9
9
  /**
10
10
  * Registry of token metadata (symbol, decimals, phantom type) keyed by address.
@@ -1,5 +1,5 @@
1
- import { ierc20Abi } from "../../abi/iERC20.js";
2
1
  import { chains } from "./chains.js";
2
+ import { ierc20Abi } from "../../abi/iERC20.js";
3
3
  //#region src/sdk/chain/detectNetwork.ts
4
4
  /**
5
5
  * Detects the network type from the given client.
@@ -1,8 +1,8 @@
1
- import { iVersionAbi } from "../../abi/iVersion.js";
2
1
  import { AP_MARKET_COMPRESSOR, AP_PRICE_FEED_COMPRESSOR } from "../constants/address-provider.js";
3
2
  import { isV310 } from "../constants/versions.js";
4
3
  import "../constants/index.js";
5
4
  import { hexEq } from "../utils/hex.js";
5
+ import { iVersionAbi } from "../../abi/iVersion.js";
6
6
  import { AddressProviderV310Contract } from "./AddressProviderV310Contract.js";
7
7
  //#region src/sdk/core/createAddressProvider.ts
8
8
  const OVERRIDE_ADDRESSES = { Mainnet: {
@@ -1,7 +1,7 @@
1
- import { iPausableAbi } from "../../../abi/iPausable.js";
2
1
  import { iCreditFacadeMulticallV310Abi, iCreditFacadeV310Abi } from "../../../abi/310/generated.js";
3
2
  import { BaseContract } from "../../base/BaseContract.js";
4
3
  import "../../base/index.js";
4
+ import { iPausableAbi } from "../../../abi/iPausable.js";
5
5
  //#region src/sdk/market/credit/CreditFacadeV310BaseContract.ts
6
6
  const abi = [
7
7
  ...iCreditFacadeV310Abi,
@@ -1,10 +1,10 @@
1
- import { iPausableAbi } from "../../../abi/iPausable.js";
2
1
  import { iPoolV310Abi } from "../../../abi/310/generated.js";
3
2
  import { AddressMap } from "../../utils/AddressMap.js";
4
3
  import { formatBN, formatBNvalue, percentFmt } from "../../utils/formatter.js";
5
4
  import "../../utils/index.js";
6
5
  import { BaseContract } from "../../base/BaseContract.js";
7
6
  import "../../base/index.js";
7
+ import { iPausableAbi } from "../../../abi/iPausable.js";
8
8
  //#region src/sdk/market/pool/PoolV310Contract.ts
9
9
  const abi = [...iPoolV310Abi, ...iPausableAbi];
10
10
  var PoolV310Contract = class extends BaseContract {
@@ -1,5 +1,5 @@
1
- import { iethZapperAbi } from "../../../abi/iETHZapper.js";
2
1
  import { ZapperContract } from "./ZapperContract.js";
2
+ import { iethZapperAbi } from "../../../abi/iETHZapper.js";
3
3
  //#region src/sdk/market/zapper/IETHZapperContract.ts
4
4
  const abi = iethZapperAbi;
5
5
  var IETHZapperContract = class extends ZapperContract {
@@ -1,6 +1,6 @@
1
- import { iZapperAbi } from "../../../abi/iZapper.js";
2
1
  import { BaseContract } from "../../base/BaseContract.js";
3
2
  import "../../base/index.js";
3
+ import { iZapperAbi } from "../../../abi/iZapper.js";
4
4
  import { UnsupportedZapperFunctionError } from "./errors.js";
5
5
  //#region src/sdk/market/zapper/ZapperContract.ts
6
6
  /**
@@ -1,5 +1,5 @@
1
- import { ierc20Abi } from "../../abi/iERC20.js";
2
1
  import { AddressSet } from "../utils/AddressSet.js";
2
+ import { ierc20Abi } from "../../abi/iERC20.js";
3
3
  import "../constants/addresses.js";
4
4
  import "../constants/index.js";
5
5
  import { hexEq } from "../utils/hex.js";
@@ -1,6 +1,6 @@
1
1
  import { errorAbis } from "../../../abi/errors.js";
2
- import { iUpdatablePriceFeedAbi } from "../../../abi/iUpdatablePriceFeed.js";
3
2
  import { generateCastTraceCall } from "./cast.js";
3
+ import { iUpdatablePriceFeedAbi } from "../../../abi/iUpdatablePriceFeed.js";
4
4
  import { simulateMulticall } from "./simulateMulticall.js";
5
5
  import { BaseError, CallExecutionError, ContractFunctionRevertedError, decodeFunctionData, decodeFunctionResult, encodeFunctionData, parseAbi } from "viem";
6
6
  import { getAction, parseAccount } from "viem/utils";
@@ -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, disableDSTokenLockPeriods } 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, disableDSTokenLockPeriods, 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, RevolverTransport, RevolverTransportConfig, RevolverTransportValue, RpcErrorResult, RpcProvider, RpcResponse, RpcSuccessResult, SUPPORTED_RPC_PROVIDERS, SelectionStrategy, TargetAccount, 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, verifyTestnet, writeAndWait };
@@ -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,21 +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
38
  /**
39
- * Zeros US and non-US compliance lock periods on each DSToken's compliance
40
- * configuration service so collateral can be transferred during testnet
41
- * liquidations (e.g. STAC). No-ops for tokens without a compliance service
42
- * (MockDSToken) or when both periods are already 0.
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.
43
48
  *
44
49
  * Must be signed by a DS admin with sufficient trust (same key as
45
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.
46
54
  */
47
- declare function disableDSTokenLockPeriods(props: DisableDSTokenLockPeriodsProps): Promise<void>;
55
+ declare function enableDSTokenBackDating(props: EnableDSTokenBackDatingProps): Promise<RestoreDSTokenBackDating>;
48
56
  declare function claimDSToken(props: ClaimDSTokenProps): Promise<void>;
49
57
  /**
50
58
  * Helper function to claim DSToken from the faucet.
@@ -56,4 +64,4 @@ declare function claimDSToken(props: ClaimDSTokenProps): Promise<void>;
56
64
  */
57
65
  declare function claimDSTokens(props: ClaimDSTokensProps): Promise<void>;
58
66
  //#endregion
59
- export { DisableDSTokenLockPeriodsProps, claimDSToken, claimDSTokens, disableDSTokenLockPeriods };
67
+ export { EnableDSTokenBackDatingProps, RestoreDSTokenBackDating, claimDSToken, claimDSTokens, enableDSTokenBackDating };
@@ -68,9 +68,9 @@ declare function calcEstimatedProfit(totalValue: bigint, liquidationDiscount: nu
68
68
  **/
69
69
  declare function pickMainAsset(ca: CreditAccountData, convert: (token: Address, balance: bigint) => bigint): Address | undefined;
70
70
  /**
71
- * Flattens delayed withdrawals of a liquidator into per-output rows:
72
- * claimable outputs have no `claimableAt` (claimable now), pending outputs
73
- * carry the estimated claim timestamp.
71
+ * Flattens delayed withdrawals of a liquidator into rows: claimable
72
+ * withdrawals have no `claimableAt` (claimable now) and carry a `claimTx`,
73
+ * pending ones carry the estimated claim timestamp.
74
74
  *
75
75
  * @param current - Claimable and pending withdrawals from the withdrawal compressor
76
76
  * @param network - Network the withdrawals live on
@@ -1,7 +1,7 @@
1
1
  import { NetworkType } from "../../chain/chains.js";
2
2
  import "../../chain/index.js";
3
3
  import { Asset } from "../../base/types.js";
4
- import { MultiCall, RawTx } from "../../types/transactions.js";
4
+ import { RawTx } from "../../types/transactions.js";
5
5
  import "../../types/index.js";
6
6
  import "../../base/index.js";
7
7
  import { Address } from "viem";
@@ -233,23 +233,20 @@ interface LiquidatorWithdrawal {
233
233
  **/
234
234
  sourceToken: Address;
235
235
  /**
236
- * Receivable asset (e.g. USDC).
236
+ * Receivable asset (e.g. USDC) and its amount: exact for claimable
237
+ * withdrawals, estimated for pending ones.
237
238
  **/
238
- /**
239
- * Amount of `token` receivable: exact for claimable withdrawals, estimated
240
- * for pending ones.
241
- **/
242
- outputs: Array<Asset>;
239
+ output: Asset;
243
240
  /**
244
241
  * Estimated unix timestamp (in seconds) when a pending withdrawal becomes
245
242
  * claimable. `undefined` means the withdrawal is claimable now.
246
243
  **/
247
244
  claimableAt?: bigint;
248
245
  /**
249
- * Estimated unix timestamp (in seconds) when a pending withdrawal becomes
250
- * claimable. `undefined` means the withdrawal is claimable now.
246
+ * Transaction that claims the withdrawal. `undefined` for pending
247
+ * withdrawals and when the compressor reports no claim call.
251
248
  **/
252
- claimCalls?: Array<MultiCall>;
249
+ claimTx?: RawTx;
253
250
  /**
254
251
  * Redeemer contract the withdrawal is claimed from, owned by the liquidator.
255
252
  * `undefined` on compressor versions below 313, which do not report it.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gearbox-protocol/sdk",
3
- "version": "14.12.0-next.63",
3
+ "version": "14.12.0-next.65",
4
4
  "description": "Gearbox SDK",
5
5
  "license": "MIT",
6
6
  "repository": {