-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathConfidentialWrapper.sol
More file actions
142 lines (117 loc) · 4.92 KB
/
ConfidentialWrapper.sol
File metadata and controls
142 lines (117 loc) · 4.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// SPDX-License-Identifier: AGPL-3.0-only
/**
* ConfidentialWrapper.sol - confidential-token
* Copyright (C) 2026-Present SKALE Labs
* @author Dmytro Stebaiev
*
* confidential-token is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* confidential-token is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with confidential-token. If not, see <https://www.gnu.org/licenses/>.
*/
// cspell:words IERC20
pragma solidity ^0.8.24;
import { ERC20, IERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { ERC20Wrapper } from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Wrapper.sol";
import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
import { ConfidentialToken } from "./ConfidentialToken.sol";
import { IConfidentialWrapper } from "./interfaces/IConfidentialWrapper.sol";
/// @title ConfidentialWrapper
/// @author Dmytro Stebaiev
/// @notice Confidential wrapper that adds confidentiality to an ERC20 token
contract ConfidentialWrapper is ConfidentialToken, ERC20Wrapper, IConfidentialWrapper {
using SafeERC20 for IERC20;
/// @notice Amount of tokens requested to be wrapped
/// @dev Almost always equals to zero
/// @dev Has non-zero value only before the callback call is made
mapping (address holder => uint256 value) public requestedMints;
error OutdatedMint(address to, uint256 value);
constructor(
IERC20Metadata underlyingToken,
string memory version_,
address initialAuthority
)
ConfidentialToken(
string.concat("Confidential ", underlyingToken.name()),
string.concat("cnf", underlyingToken.symbol()),
version_,
initialAuthority
)
ERC20Wrapper(underlyingToken)
{}
// External functions
/// @inheritdoc IConfidentialWrapper
function releaseTo(address account, uint256 value) external override {
requestedMints[msg.sender] -= value;
underlying().safeTransfer(account, value);
}
// Public functions
///@inheritdoc ConfidentialToken
function transferFrom(
address from,
address to,
uint256 value
) public virtual override(ConfidentialToken, ERC20) returns (bool result) {
return ConfidentialToken.transferFrom(from, to, value);
}
/// @inheritdoc ERC20Wrapper
function depositFor(address account, uint256 value) public override returns (bool success) {
requestedMints[msg.sender] += value;
return super.depositFor(account, value);
}
/// @inheritdoc ERC20Wrapper
function withdrawTo(address account, uint256 value) public override returns (bool success) {
if (account == address(this)) {
revert ERC20InvalidReceiver(account);
}
_burn(_msgSender(), value);
return true;
}
/// @inheritdoc ERC20Wrapper
function decimals() public view override(ERC20, ERC20Wrapper) returns (uint8 decimalsValue) {
return ERC20Wrapper.decimals();
}
/// @inheritdoc ConfidentialToken
function totalSupply() public view override(ConfidentialToken, ERC20) returns (uint256 supply) {
return ConfidentialToken.totalSupply();
}
/// @inheritdoc ConfidentialToken
function balanceOf(address account) public pure override(ConfidentialToken, ERC20) returns (uint256 balance) {
return ConfidentialToken.balanceOf(account);
}
// Internal functions
function _onUpdate(address from, address to, uint256 value) internal override {
ConfidentialToken._onUpdate(from, to, value);
if (from == address(0)) {
_onMint(to, value);
}
if (to == address(0)) {
_onBurn(from, value);
}
}
function _update(address from, address to, uint256 value) internal override(ConfidentialToken, ERC20) {
ConfidentialToken._update(from, to, value);
}
// Private functions
function _onMint(address to, uint256 value) private {
bool previouslyRequested;
(previouslyRequested, requestedMints[to]) = Math.trySub(
requestedMints[to],
value
);
require(previouslyRequested, OutdatedMint(to, value));
}
function _onBurn(address from, uint256 value) private {
underlying().safeTransfer(from, value);
}
}