@openzeppelin/confidential-contracts 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/contracts/Checkpoints.json +2 -2
- package/build/contracts/CheckpointsConfidential.json +2 -2
- package/build/contracts/{ConfidentialFungibleToken.json → ERC7984.json} +87 -58
- package/build/contracts/{ConfidentialFungibleTokenERC20Wrapper.json → ERC7984ERC20Wrapper.json} +143 -59
- package/build/contracts/ERC7984Freezable.json +700 -0
- package/build/contracts/ERC7984ObserverAccess.json +710 -0
- package/build/contracts/ERC7984Omnibus.json +1028 -0
- package/build/contracts/ERC7984Restricted.json +711 -0
- package/build/contracts/ERC7984Rwa.json +1385 -0
- package/build/contracts/{ConfidentialFungibleTokenUtils.json → ERC7984Utils.json} +4 -4
- package/build/contracts/{ConfidentialFungibleTokenVotes.json → ERC7984Votes.json} +142 -113
- package/build/contracts/FHESafeMath.json +2 -2
- package/build/contracts/{IConfidentialFungibleToken.json → IERC7984.json} +26 -7
- package/build/contracts/{IConfidentialFungibleTokenReceiver.json → IERC7984Receiver.json} +2 -2
- package/build/contracts/IERC7984Rwa.json +797 -0
- package/build/contracts/VestingWalletConfidentialFactory.json +2 -2
- package/finance/ERC7821WithExecutor.sol +3 -4
- package/finance/VestingWalletCliffConfidential.sol +3 -4
- package/finance/VestingWalletConfidential.sol +8 -12
- package/finance/VestingWalletConfidentialFactory.sol +7 -12
- package/interfaces/{IConfidentialFungibleToken.sol → IERC7984.sol} +6 -5
- package/interfaces/{IConfidentialFungibleTokenReceiver.sol → IERC7984Receiver.sol} +3 -3
- package/interfaces/IERC7984Rwa.sol +63 -0
- package/package.json +4 -4
- package/token/{ConfidentialFungibleToken.sol → ERC7984/ERC7984.sol} +81 -82
- package/token/{extensions/ConfidentialFungibleTokenERC20Wrapper.sol → ERC7984/extensions/ERC7984ERC20Wrapper.sol} +40 -35
- package/token/ERC7984/extensions/ERC7984Freezable.sol +75 -0
- package/token/ERC7984/extensions/ERC7984ObserverAccess.sol +63 -0
- package/token/ERC7984/extensions/ERC7984Omnibus.sol +209 -0
- package/token/ERC7984/extensions/ERC7984Restricted.sol +110 -0
- package/token/ERC7984/extensions/ERC7984Rwa.sol +248 -0
- package/token/{extensions/ConfidentialFungibleTokenVotes.sol → ERC7984/extensions/ERC7984Votes.sol} +8 -14
- package/token/{utils/ConfidentialFungibleTokenUtils.sol → ERC7984/utils/ERC7984Utils.sol} +14 -13
- package/utils/FHESafeMath.sol +45 -7
- package/utils/structs/temporary-Checkpoints.sol +2 -2
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
{
|
|
56
56
|
"indexed": true,
|
|
57
57
|
"internalType": "address",
|
|
58
|
-
"name": "
|
|
58
|
+
"name": "token",
|
|
59
59
|
"type": "address"
|
|
60
60
|
},
|
|
61
61
|
{
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
"inputs": [
|
|
79
79
|
{
|
|
80
80
|
"internalType": "address",
|
|
81
|
-
"name": "
|
|
81
|
+
"name": "token",
|
|
82
82
|
"type": "address"
|
|
83
83
|
},
|
|
84
84
|
{
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Confidential Contracts (last updated v0.
|
|
2
|
+
// OpenZeppelin Confidential Contracts (last updated v0.3.0) (finance/ERC7821WithExecutor.sol)
|
|
3
3
|
pragma solidity ^0.8.20;
|
|
4
4
|
|
|
5
5
|
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
|
|
@@ -15,8 +15,7 @@ abstract contract ERC7821WithExecutor is Initializable, ERC7821 {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ERC7821WithExecutor")) - 1)) & ~bytes32(uint256(0xff))
|
|
18
|
-
|
|
19
|
-
bytes32 private constant ERC7821WithExecutorStorageLocation =
|
|
18
|
+
bytes32 private constant ERC7821_WITH_EXECUTOR_STORAGE_LOCATION =
|
|
20
19
|
0x246106ffca67a7d3806ba14f6748826b9c39c9fa594b14f83fe454e8e9d0dc00;
|
|
21
20
|
|
|
22
21
|
/// @dev Trusted address that is able to execute arbitrary calls from the vesting wallet via `ERC7821.execute`.
|
|
@@ -40,7 +39,7 @@ abstract contract ERC7821WithExecutor is Initializable, ERC7821 {
|
|
|
40
39
|
|
|
41
40
|
function _getERC7821WithExecutorStorage() private pure returns (ERC7821WithExecutorStorage storage $) {
|
|
42
41
|
assembly ("memory-safe") {
|
|
43
|
-
$.slot :=
|
|
42
|
+
$.slot := ERC7821_WITH_EXECUTOR_STORAGE_LOCATION
|
|
44
43
|
}
|
|
45
44
|
}
|
|
46
45
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Confidential Contracts (last updated v0.
|
|
2
|
+
// OpenZeppelin Confidential Contracts (last updated v0.3.0) (finance/VestingWalletCliffConfidential.sol)
|
|
3
3
|
pragma solidity ^0.8.27;
|
|
4
4
|
|
|
5
5
|
import {euint128} from "@fhevm/solidity/lib/FHE.sol";
|
|
@@ -16,8 +16,7 @@ abstract contract VestingWalletCliffConfidential is VestingWalletConfidential {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.VestingWalletCliffConfidential")) - 1)) & ~bytes32(uint256(0xff))
|
|
19
|
-
|
|
20
|
-
bytes32 private constant VestingWalletCliffStorageLocation =
|
|
19
|
+
bytes32 private constant VESTING_WALLET_CLIFF_STORAGE_LOCATION =
|
|
21
20
|
0x3c715f77db997bdb68403fafb54820cd57dedce553ed6315028656b0d601c700;
|
|
22
21
|
|
|
23
22
|
/// @dev The specified cliff duration is larger than the vesting duration.
|
|
@@ -67,7 +66,7 @@ abstract contract VestingWalletCliffConfidential is VestingWalletConfidential {
|
|
|
67
66
|
|
|
68
67
|
function _getVestingWalletCliffStorage() private pure returns (VestingWalletCliffStorage storage $) {
|
|
69
68
|
assembly ("memory-safe") {
|
|
70
|
-
$.slot :=
|
|
69
|
+
$.slot := VESTING_WALLET_CLIFF_STORAGE_LOCATION
|
|
71
70
|
}
|
|
72
71
|
}
|
|
73
72
|
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Confidential Contracts (last updated v0.
|
|
2
|
+
// OpenZeppelin Confidential Contracts (last updated v0.3.0) (finance/VestingWalletConfidential.sol)
|
|
3
3
|
pragma solidity ^0.8.24;
|
|
4
4
|
|
|
5
5
|
import {FHE, ebool, euint64, euint128} from "@fhevm/solidity/lib/FHE.sol";
|
|
6
6
|
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
|
|
7
7
|
import {ReentrancyGuardTransient} from "@openzeppelin/contracts/utils/ReentrancyGuardTransient.sol";
|
|
8
|
-
import {
|
|
8
|
+
import {IERC7984} from "./../interfaces/IERC7984.sol";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* @dev A vesting wallet is an ownable contract that can receive
|
|
11
|
+
* @dev A vesting wallet is an ownable contract that can receive ERC7984 tokens, and release these
|
|
12
12
|
* assets to the wallet owner, also referred to as "beneficiary", according to a vesting schedule.
|
|
13
13
|
*
|
|
14
14
|
* Any assets transferred to this contract will follow the vesting schedule as if they were locked from the beginning.
|
|
@@ -34,8 +34,7 @@ abstract contract VestingWalletConfidential is OwnableUpgradeable, ReentrancyGua
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.VestingWalletConfidential")) - 1)) & ~bytes32(uint256(0xff))
|
|
37
|
-
|
|
38
|
-
bytes32 private constant VestingWalletStorageLocation =
|
|
37
|
+
bytes32 private constant VESTING_WALLET_STORAGE_LOCATION =
|
|
39
38
|
0x78ce9ee9eb65fa0cf5bf10e861c3a95cb7c3c713c96ab1e5323a21e846796800;
|
|
40
39
|
|
|
41
40
|
/// @dev Emitted when releasable vested tokens are released.
|
|
@@ -63,7 +62,7 @@ abstract contract VestingWalletConfidential is OwnableUpgradeable, ReentrancyGua
|
|
|
63
62
|
|
|
64
63
|
/**
|
|
65
64
|
* @dev Getter for the amount of releasable `token` tokens. `token` should be the address of an
|
|
66
|
-
* {
|
|
65
|
+
* {IERC7984} contract.
|
|
67
66
|
*/
|
|
68
67
|
function releasable(address token) public virtual returns (euint64) {
|
|
69
68
|
euint128 vestedAmount_ = vestedAmount(token, uint48(block.timestamp));
|
|
@@ -80,7 +79,7 @@ abstract contract VestingWalletConfidential is OwnableUpgradeable, ReentrancyGua
|
|
|
80
79
|
function release(address token) public virtual nonReentrant {
|
|
81
80
|
euint64 amount = releasable(token);
|
|
82
81
|
FHE.allowTransient(amount, token);
|
|
83
|
-
euint64 amountSent =
|
|
82
|
+
euint64 amountSent = IERC7984(token).confidentialTransfer(owner(), amount);
|
|
84
83
|
|
|
85
84
|
// This could overflow if the total supply is resent `type(uint128).max/type(uint64).max` times. This is an accepted risk.
|
|
86
85
|
euint128 newReleasedAmount = FHE.add(released(token), amountSent);
|
|
@@ -96,10 +95,7 @@ abstract contract VestingWalletConfidential is OwnableUpgradeable, ReentrancyGua
|
|
|
96
95
|
*/
|
|
97
96
|
function vestedAmount(address token, uint48 timestamp) public virtual returns (euint128) {
|
|
98
97
|
return
|
|
99
|
-
_vestingSchedule(
|
|
100
|
-
FHE.add(released(token), IConfidentialFungibleToken(token).confidentialBalanceOf(address(this))),
|
|
101
|
-
timestamp
|
|
102
|
-
);
|
|
98
|
+
_vestingSchedule(FHE.add(released(token), IERC7984(token).confidentialBalanceOf(address(this))), timestamp);
|
|
103
99
|
}
|
|
104
100
|
|
|
105
101
|
/**
|
|
@@ -139,7 +135,7 @@ abstract contract VestingWalletConfidential is OwnableUpgradeable, ReentrancyGua
|
|
|
139
135
|
|
|
140
136
|
function _getVestingWalletStorage() private pure returns (VestingWalletStorage storage $) {
|
|
141
137
|
assembly ("memory-safe") {
|
|
142
|
-
$.slot :=
|
|
138
|
+
$.slot := VESTING_WALLET_STORAGE_LOCATION
|
|
143
139
|
}
|
|
144
140
|
}
|
|
145
141
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Confidential Contracts (last updated v0.
|
|
2
|
+
// OpenZeppelin Confidential Contracts (last updated v0.3.0) (finance/VestingWalletConfidentialFactory.sol)
|
|
3
3
|
pragma solidity ^0.8.27;
|
|
4
4
|
|
|
5
5
|
import {FHE, euint64, externalEuint64} from "@fhevm/solidity/lib/FHE.sol";
|
|
6
6
|
import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol";
|
|
7
|
-
import {
|
|
7
|
+
import {IERC7984} from "./../interfaces/IERC7984.sol";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* @dev A factory which enables batch funding of vesting wallets.
|
|
@@ -23,7 +23,7 @@ abstract contract VestingWalletConfidentialFactory {
|
|
|
23
23
|
/// @dev Emitted for each vesting wallet funded within a batch.
|
|
24
24
|
event VestingWalletConfidentialFunded(
|
|
25
25
|
address indexed vestingWalletConfidential,
|
|
26
|
-
address indexed
|
|
26
|
+
address indexed token,
|
|
27
27
|
euint64 transferredAmount,
|
|
28
28
|
bytes initArgs
|
|
29
29
|
);
|
|
@@ -43,7 +43,7 @@ abstract contract VestingWalletConfidentialFactory {
|
|
|
43
43
|
* Emits a {VestingWalletConfidentialFunded} event for each funded vesting plan.
|
|
44
44
|
*/
|
|
45
45
|
function batchFundVestingWalletConfidential(
|
|
46
|
-
address
|
|
46
|
+
address token,
|
|
47
47
|
VestingPlan[] calldata vestingPlans,
|
|
48
48
|
bytes calldata inputProof
|
|
49
49
|
) public virtual {
|
|
@@ -55,19 +55,14 @@ abstract contract VestingWalletConfidentialFactory {
|
|
|
55
55
|
address vestingWalletAddress = predictVestingWalletConfidential(vestingPlan.initArgs);
|
|
56
56
|
|
|
57
57
|
euint64 encryptedAmount = FHE.fromExternal(vestingPlan.encryptedAmount, inputProof);
|
|
58
|
-
FHE.allowTransient(encryptedAmount,
|
|
59
|
-
euint64 transferredAmount =
|
|
58
|
+
FHE.allowTransient(encryptedAmount, token);
|
|
59
|
+
euint64 transferredAmount = IERC7984(token).confidentialTransferFrom(
|
|
60
60
|
msg.sender,
|
|
61
61
|
vestingWalletAddress,
|
|
62
62
|
encryptedAmount
|
|
63
63
|
);
|
|
64
64
|
|
|
65
|
-
emit VestingWalletConfidentialFunded(
|
|
66
|
-
vestingWalletAddress,
|
|
67
|
-
confidentialFungibleToken,
|
|
68
|
-
transferredAmount,
|
|
69
|
-
vestingPlan.initArgs
|
|
70
|
-
);
|
|
65
|
+
emit VestingWalletConfidentialFunded(vestingWalletAddress, token, transferredAmount, vestingPlan.initArgs);
|
|
71
66
|
}
|
|
72
67
|
}
|
|
73
68
|
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Confidential Contracts (last updated v0.
|
|
2
|
+
// OpenZeppelin Confidential Contracts (last updated v0.3.0) (interfaces/IERC7984.sol)
|
|
3
3
|
pragma solidity ^0.8.24;
|
|
4
4
|
|
|
5
5
|
import {euint64, externalEuint64} from "@fhevm/solidity/lib/FHE.sol";
|
|
6
|
+
import {IERC165} from "@openzeppelin/contracts/interfaces/IERC165.sol";
|
|
6
7
|
|
|
7
8
|
/// @dev Draft interface for a confidential fungible token standard utilizing the Zama FHE library.
|
|
8
|
-
interface
|
|
9
|
+
interface IERC7984 is IERC165 {
|
|
9
10
|
/**
|
|
10
11
|
* @dev Emitted when the expiration timestamp for an operator `operator` is updated for a given `holder`.
|
|
11
12
|
* The operator may move any amount of tokens on behalf of the holder until the timestamp `until`.
|
|
@@ -32,8 +33,8 @@ interface IConfidentialFungibleToken {
|
|
|
32
33
|
/// @dev Returns the number of decimals of the token. Recommended to be 6.
|
|
33
34
|
function decimals() external view returns (uint8);
|
|
34
35
|
|
|
35
|
-
/// @dev Returns the
|
|
36
|
-
function
|
|
36
|
+
/// @dev Returns the contract URI. See https://eips.ethereum.org/EIPS/eip-7572[ERC-7572] for details.
|
|
37
|
+
function contractURI() external view returns (string memory);
|
|
37
38
|
|
|
38
39
|
/// @dev Returns the confidential total supply of the token.
|
|
39
40
|
function confidentialTotalSupply() external view returns (euint64);
|
|
@@ -91,7 +92,7 @@ interface IConfidentialFungibleToken {
|
|
|
91
92
|
* @dev Similar to {confidentialTransfer-address-externalEuint64-bytes} but with a callback to `to` after
|
|
92
93
|
* the transfer.
|
|
93
94
|
*
|
|
94
|
-
* The callback is made to the {
|
|
95
|
+
* The callback is made to the {IERC7984Receiver-onConfidentialTransferReceived} function on the
|
|
95
96
|
* to address with the actual transferred amount (may differ from the given `encryptedAmount`) and the given
|
|
96
97
|
* data `data`.
|
|
97
98
|
*/
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Confidential Contracts (last updated v0.
|
|
2
|
+
// OpenZeppelin Confidential Contracts (last updated v0.3.0) (interfaces/IERC7984Receiver.sol)
|
|
3
3
|
pragma solidity ^0.8.24;
|
|
4
4
|
|
|
5
5
|
import {ebool, euint64} from "@fhevm/solidity/lib/FHE.sol";
|
|
6
6
|
|
|
7
|
-
/// @dev Interface for contracts that can receive
|
|
8
|
-
interface
|
|
7
|
+
/// @dev Interface for contracts that can receive ERC7984 transfers with a callback.
|
|
8
|
+
interface IERC7984Receiver {
|
|
9
9
|
/**
|
|
10
10
|
* @dev Called upon receiving a confidential token transfer. Returns an encrypted boolean indicating success
|
|
11
11
|
* of the callback. If false is returned, the transfer must be reversed.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// OpenZeppelin Confidential Contracts (last updated v0.3.0) (interfaces/IERC7984Rwa.sol)
|
|
3
|
+
pragma solidity ^0.8.24;
|
|
4
|
+
|
|
5
|
+
import {externalEuint64, euint64} from "@fhevm/solidity/lib/FHE.sol";
|
|
6
|
+
import {IERC7984} from "./IERC7984.sol";
|
|
7
|
+
|
|
8
|
+
/// @dev Interface for confidential RWA contracts.
|
|
9
|
+
interface IERC7984Rwa is IERC7984 {
|
|
10
|
+
/// @dev Returns true if the contract is paused, false otherwise.
|
|
11
|
+
function paused() external view returns (bool);
|
|
12
|
+
/// @dev Returns whether an account is allowed to interact with the token.
|
|
13
|
+
function isUserAllowed(address account) external view returns (bool);
|
|
14
|
+
/// @dev Returns the confidential frozen balance of an account.
|
|
15
|
+
function confidentialFrozen(address account) external view returns (euint64);
|
|
16
|
+
/// @dev Returns the confidential available (unfrozen) balance of an account. Up to {IERC7984-confidentialBalanceOf}.
|
|
17
|
+
function confidentialAvailable(address account) external returns (euint64);
|
|
18
|
+
/// @dev Pauses contract.
|
|
19
|
+
function pause() external;
|
|
20
|
+
/// @dev Unpauses contract.
|
|
21
|
+
function unpause() external;
|
|
22
|
+
/// @dev Blocks a user account.
|
|
23
|
+
function blockUser(address account) external;
|
|
24
|
+
/// @dev Unblocks a user account.
|
|
25
|
+
function unblockUser(address account) external;
|
|
26
|
+
/// @dev Sets confidential amount of token for an account as frozen with proof.
|
|
27
|
+
function setConfidentialFrozen(
|
|
28
|
+
address account,
|
|
29
|
+
externalEuint64 encryptedAmount,
|
|
30
|
+
bytes calldata inputProof
|
|
31
|
+
) external;
|
|
32
|
+
/// @dev Sets confidential amount of token for an account as frozen.
|
|
33
|
+
function setConfidentialFrozen(address account, euint64 encryptedAmount) external;
|
|
34
|
+
/// @dev Mints confidential amount of tokens to account with proof.
|
|
35
|
+
function confidentialMint(
|
|
36
|
+
address to,
|
|
37
|
+
externalEuint64 encryptedAmount,
|
|
38
|
+
bytes calldata inputProof
|
|
39
|
+
) external returns (euint64);
|
|
40
|
+
/// @dev Mints confidential amount of tokens to account.
|
|
41
|
+
function confidentialMint(address to, euint64 encryptedAmount) external returns (euint64);
|
|
42
|
+
/// @dev Burns confidential amount of tokens from account with proof.
|
|
43
|
+
function confidentialBurn(
|
|
44
|
+
address account,
|
|
45
|
+
externalEuint64 encryptedAmount,
|
|
46
|
+
bytes calldata inputProof
|
|
47
|
+
) external returns (euint64);
|
|
48
|
+
/// @dev Burns confidential amount of tokens from account.
|
|
49
|
+
function confidentialBurn(address account, euint64 encryptedAmount) external returns (euint64);
|
|
50
|
+
/// @dev Forces transfer of confidential amount of tokens from account to account with proof by skipping compliance checks.
|
|
51
|
+
function forceConfidentialTransferFrom(
|
|
52
|
+
address from,
|
|
53
|
+
address to,
|
|
54
|
+
externalEuint64 encryptedAmount,
|
|
55
|
+
bytes calldata inputProof
|
|
56
|
+
) external returns (euint64);
|
|
57
|
+
/// @dev Forces transfer of confidential amount of tokens from account to account by skipping compliance checks.
|
|
58
|
+
function forceConfidentialTransferFrom(
|
|
59
|
+
address from,
|
|
60
|
+
address to,
|
|
61
|
+
euint64 encryptedAmount
|
|
62
|
+
) external returns (euint64);
|
|
63
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openzeppelin/confidential-contracts",
|
|
3
3
|
"description": "Smart Contract library for use with confidential coprocessors",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.3.0",
|
|
5
5
|
"files": [
|
|
6
6
|
"**/*.sol",
|
|
7
7
|
"/build/contracts/*.json",
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
},
|
|
33
33
|
"homepage": "https://openzeppelin.com/contracts/",
|
|
34
34
|
"peerDependencies": {
|
|
35
|
-
"@fhevm/solidity": "0.
|
|
36
|
-
"@openzeppelin/contracts": "^5.
|
|
37
|
-
"@openzeppelin/contracts-upgradeable": "^5.
|
|
35
|
+
"@fhevm/solidity": "0.9.1",
|
|
36
|
+
"@openzeppelin/contracts": "^5.4.0",
|
|
37
|
+
"@openzeppelin/contracts-upgradeable": "^5.4.0"
|
|
38
38
|
}
|
|
39
39
|
}
|