Skip to content

Commit 6afb479

Browse files
committed
add upgradeability pattern to project
1 parent cd11d4c commit 6afb479

50 files changed

Lines changed: 4092 additions & 2517 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

PLAN.md

Lines changed: 761 additions & 0 deletions
Large diffs are not rendered by default.

contracts/ConfidentialToken.sol

Lines changed: 7 additions & 895 deletions
Large diffs are not rendered by default.

contracts/ConfidentialWrapper.sol

Lines changed: 4 additions & 168 deletions
Original file line numberDiff line numberDiff line change
@@ -19,188 +19,24 @@
1919
* along with confidential-token. If not, see <https://www.gnu.org/licenses/>.
2020
*/
2121

22-
// cspell:words IERC20
23-
2422
pragma solidity ^0.8.27;
2523

26-
import { ERC20, IERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
27-
import { ERC20Wrapper } from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Wrapper.sol";
2824
import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
29-
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
30-
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
3125

32-
import { BITE, ConfidentialToken } from "./ConfidentialToken.sol";
33-
import { IConfidentialWrapper } from "./interfaces/IConfidentialWrapper.sol";
26+
import { ConfidentialWrapperCore } from "./core/ConfidentialWrapperCore.sol";
3427

3528

3629
/// @title ConfidentialWrapper
3730
/// @author Dmytro Stebaiev
3831
/// @notice Confidential wrapper that adds confidentiality to an ERC20 token
39-
contract ConfidentialWrapper is ConfidentialToken, ERC20Wrapper, IConfidentialWrapper {
40-
using SafeERC20 for IERC20;
41-
42-
uint8 private constant _WITHDRAW_TO_ACTION = 2;
43-
44-
45-
/// @notice Amount of tokens requested to be wrapped
46-
/// @dev Almost always equals to zero
47-
/// @dev Has non-zero value only before the callback call is made
48-
mapping (address holder => uint256 value) public requestedMints;
49-
50-
error OutdatedMint(address to, uint256 value);
51-
error ZeroValue();
52-
32+
contract ConfidentialWrapper is ConfidentialWrapperCore {
5333
constructor(
5434
IERC20Metadata underlyingToken,
5535
string memory version_,
5636
address initialAuthority
5737
)
58-
ConfidentialToken(
59-
string.concat("Confidential ", underlyingToken.name()),
60-
string.concat("cnf", underlyingToken.symbol()),
61-
version_,
62-
initialAuthority
63-
)
64-
ERC20Wrapper(underlyingToken)
65-
{}
66-
67-
// External functions
68-
69-
/// @inheritdoc IConfidentialWrapper
70-
function releaseTo(address account, uint256 value) external override {
71-
requestedMints[_msgSender()] -= value;
72-
underlying().safeTransfer(account, value);
73-
}
74-
75-
// Public functions
76-
77-
///@inheritdoc ConfidentialToken
78-
function transferFrom(
79-
address from,
80-
address to,
81-
uint256 value
82-
) public virtual override(ConfidentialToken, ERC20) returns (bool result) {
83-
return ConfidentialToken.transferFrom(from, to, value);
84-
}
85-
86-
/// @inheritdoc ERC20Wrapper
87-
/// @dev Pending mint accounting is keyed by the recipient `account`, so only
88-
/// `account` can later call `releaseTo` for this deposit.
89-
function depositFor(address account, uint256 value) public override returns (bool success) {
90-
requestedMints[account] += value;
91-
return super.depositFor(account, value);
92-
}
93-
94-
/// @inheritdoc ERC20Wrapper
95-
/// @dev This operation is asynchronous and finalizes in the callback. On
96-
/// success, underlying tokens are sent to `account`.
97-
function withdrawTo(address account, uint256 value) public override returns (bool success) {
98-
_burnTo(_msgSender(), account, value);
99-
return true;
100-
}
101-
102-
/// @inheritdoc ERC20Wrapper
103-
function decimals() public view override(ERC20, ERC20Wrapper) returns (uint8 decimalsValue) {
104-
return ERC20Wrapper.decimals();
105-
}
106-
107-
/// @inheritdoc ConfidentialToken
108-
function totalSupply() public view override(ConfidentialToken, ERC20) returns (uint256 supply) {
109-
return ConfidentialToken.totalSupply();
110-
}
111-
112-
/// @inheritdoc ConfidentialToken
113-
function balanceOf(address account) public pure override(ConfidentialToken, ERC20) returns (uint256 balance) {
114-
return ConfidentialToken.balanceOf(account);
115-
}
116-
117-
// Internal functions
118-
119-
/// @notice Dispatches decrypted CTX actions for wrapper-specific flows.
120-
/// @dev Handles `_WITHDRAW_TO_ACTION` locally and delegates all other actions to
121-
/// the base ConfidentialToken logic.
122-
/// @param action Action discriminator encoded in callback plaintext.
123-
/// @param decryptedArguments Decrypted callback arguments from BITE.
124-
/// @param plaintextArguments Plaintext callback arguments used for routing.
125-
function _handleAction(
126-
uint8 action,
127-
bytes[] calldata decryptedArguments,
128-
bytes[] calldata plaintextArguments
129-
) internal override {
130-
if (action == _WITHDRAW_TO_ACTION) {
131-
_handleWithdrawToRequest(decryptedArguments, plaintextArguments);
132-
return;
133-
}
134-
super._handleAction(action, decryptedArguments, plaintextArguments);
135-
}
136-
137-
/// @notice Schedules an async burn that releases underlying to `to` on callback.
138-
/// @dev Encodes `to` as extra plaintext callback data for
139-
/// `_handleWithdrawToRequest`.
140-
/// @param from Address whose confidential balance is debited.
141-
/// @param to Recipient of the released underlying token.
142-
/// @param value Amount to burn and unwrap.
143-
function _burnTo(address from, address to, uint256 value) internal {
144-
if (to == address(0) || to == address(this)) {
145-
revert ERC20InvalidReceiver(to);
146-
}
147-
require(value != 0, ZeroValue());
148-
bytes memory encryptedValue = BITE.encryptTE(encryptTEAddress, abi.encodePacked(value));
149-
bytes[] memory extraArgs = new bytes[](1);
150-
extraArgs[0] = abi.encodePacked(to);
151-
_encryptedUpdateExtended({
152-
from: from,
153-
to: address(0),
154-
spender: address(0),
155-
gasPayer: _msgSender(),
156-
encryptedValue: encryptedValue,
157-
action: _WITHDRAW_TO_ACTION,
158-
extraPlaintextArguments: extraArgs
159-
});
160-
}
161-
162-
function _onUpdate(address from, address to, uint256 value) internal override {
163-
ConfidentialToken._onUpdate(from, to, value);
164-
if (from == address(0)) {
165-
_onMint(to, value);
166-
}
167-
}
168-
169-
function _update(address from, address to, uint256 value) internal override(ConfidentialToken, ERC20) {
170-
ConfidentialToken._update(from, to, value);
171-
}
172-
173-
// Private functions
174-
175-
function _onMint(address to, uint256 value) private {
176-
bool previouslyRequested;
177-
(previouslyRequested, requestedMints[to]) = Math.trySub(
178-
requestedMints[to],
179-
value
180-
);
181-
require(previouslyRequested, OutdatedMint(to, value));
182-
}
183-
184-
/// @notice Finalizes a queued wrapper burn/withdraw callback.
185-
/// @dev Validates recipient plaintext argument, finalizes encrypted transfer
186-
/// accounting via `_handleTransferRequest`, then releases underlying.
187-
/// @param decryptedArguments Decrypted callback arguments from BITE.
188-
/// @param plaintextArguments Plaintext callback arguments containing recipient.
189-
function _handleWithdrawToRequest(
190-
bytes[] calldata decryptedArguments,
191-
bytes[] calldata plaintextArguments
192-
)
193-
private
38+
initializer
19439
{
195-
require(plaintextArguments.length > 2, WrongPlaintextFormat());
196-
require(plaintextArguments[2].length == 20, WrongPlaintextFormat());
197-
198-
(bool finalized, uint256 value) = _handleTransferRequest(decryptedArguments, plaintextArguments);
199-
if (!finalized) {
200-
return;
201-
}
202-
203-
address recipient = address(bytes20(plaintextArguments[2]));
204-
underlying().safeTransfer(recipient, value);
40+
__ConfidentialWrapper_init(underlyingToken, version_, initialAuthority);
20541
}
20642
}

contracts/MintableConfidentialToken.sol

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,13 @@
2121

2222
pragma solidity ^0.8.27;
2323

24-
import { ConfidentialToken } from "./ConfidentialToken.sol";
25-
import { IMintableERC20 } from "./interfaces/IMintableERC20.sol";
24+
import { MintableConfidentialTokenCore } from "./core/MintableConfidentialTokenCore.sol";
2625

2726

2827
/// @title MintableConfidentialToken
2928
/// @author Dmytro Stebaiev
3029
/// @notice ConfidentialToken with minting functionality
31-
contract MintableConfidentialToken is ConfidentialToken, IMintableERC20 {
30+
contract MintableConfidentialToken is MintableConfidentialTokenCore {
3231
/// @notice Constructor of the MintableConfidentialToken contract
3332
/// @param name Name of the token
3433
/// @param symbol Symbol of the token
@@ -40,16 +39,8 @@ contract MintableConfidentialToken is ConfidentialToken, IMintableERC20 {
4039
string memory version_,
4140
address initialAuthority
4241
)
43-
ConfidentialToken(name, symbol, version_, initialAuthority)
44-
{}
45-
46-
/// @inheritdoc IMintableERC20
47-
function mint(address to, uint256 amount) external override restricted {
48-
_mint(to, amount);
49-
}
50-
51-
/// @inheritdoc IMintableERC20
52-
function burn(uint256 amount) external override {
53-
_burn(_msgSender(), amount);
42+
initializer
43+
{
44+
__MintableConfidentialToken_init(name, symbol, version_, initialAuthority);
5445
}
5546
}

0 commit comments

Comments
 (0)