Skip to content

Commit ddec201

Browse files
committed
Rorganized ERC20 functionality
1 parent 4f2b6d2 commit ddec201

File tree

12 files changed

+262
-139
lines changed

12 files changed

+262
-139
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity >=0.8.30;
3+
4+
/* Compose
5+
* https://compose.diamonds
6+
*/
7+
8+
contract ERC20ApproveFacet {
9+
/**
10+
* @notice Thrown when the spender address is invalid (e.g., zero address).
11+
* @param _spender Invalid spender address.
12+
*/
13+
error ERC20InvalidSpender(address _spender);
14+
15+
/**
16+
* @notice Emitted when an approval is made for a spender by an owner.
17+
* @param _owner The address granting the allowance.
18+
* @param _spender The address receiving the allowance.
19+
* @param _value The amount approved.
20+
*/
21+
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
22+
23+
/**
24+
* @dev Storage position determined by the keccak256 hash of the diamond storage identifier.
25+
*/
26+
bytes32 constant STORAGE_POSITION = keccak256("erc20");
27+
28+
/**
29+
* @dev ERC-8042 compliant storage struct for ERC20 token data.
30+
* @custom:storage-location erc8042:erc20
31+
*/
32+
struct ERC20Storage {
33+
mapping(address owner => uint256 balance) balanceOf;
34+
uint256 totalSupply;
35+
mapping(address owner => mapping(address spender => uint256 allowance)) allowance;
36+
}
37+
38+
/**
39+
* @notice Returns the ERC20 storage struct from the predefined diamond storage slot.
40+
* @dev Uses inline assembly to set the storage slot reference.
41+
* @return s The ERC20 storage struct reference.
42+
*/
43+
function getStorage() internal pure returns (ERC20Storage storage s) {
44+
bytes32 position = STORAGE_POSITION;
45+
assembly {
46+
s.slot := position
47+
}
48+
}
49+
50+
/**
51+
* @notice Approves a spender to transfer up to a certain amount of tokens on behalf of the caller.
52+
* @dev Emits an {Approval} event.
53+
* @param _spender The address approved to spend tokens.
54+
* @param _value The number of tokens to approve.
55+
* @return True if the approval was successful.
56+
*/
57+
function approve(address _spender, uint256 _value) external returns (bool) {
58+
ERC20Storage storage s = getStorage();
59+
if (_spender == address(0)) {
60+
revert ERC20InvalidSpender(address(0));
61+
}
62+
s.allowance[msg.sender][_spender] = _value;
63+
emit Approval(msg.sender, _spender, _value);
64+
return true;
65+
}
66+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity >=0.8.30;
3+
4+
/* Compose
5+
* https://compose.diamonds
6+
*/
7+
8+
/**
9+
* @notice Thrown when the spender address is invalid (e.g., zero address).
10+
* @param _spender Invalid spender address.
11+
*/
12+
error ERC20InvalidSpender(address _spender);
13+
14+
/**
15+
* @notice Emitted when an approval is made for a spender by an owner.
16+
* @param _owner The address granting the allowance.
17+
* @param _spender The address receiving the allowance.
18+
* @param _value The amount approved.
19+
*/
20+
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
21+
22+
/**
23+
* @dev Storage position determined by the keccak256 hash of the diamond storage identifier.
24+
*/
25+
bytes32 constant STORAGE_POSITION = keccak256("erc20");
26+
27+
/**
28+
* @dev ERC-8042 compliant storage struct for ERC20 token data.
29+
* @custom:storage-location erc8042:erc20
30+
*/
31+
struct ERC20Storage {
32+
mapping(address owner => uint256 balance) balanceOf;
33+
uint256 totalSupply;
34+
mapping(address owner => mapping(address spender => uint256 allowance)) allowance;
35+
}
36+
37+
/**
38+
* @notice Returns the ERC20 storage struct from the predefined diamond storage slot.
39+
* @dev Uses inline assembly to set the storage slot reference.
40+
* @return s The ERC20 storage struct reference.
41+
*/
42+
function getStorage() pure returns (ERC20Storage storage s) {
43+
bytes32 position = STORAGE_POSITION;
44+
assembly {
45+
s.slot := position
46+
}
47+
}
48+
49+
/**
50+
* @notice Approves a spender to transfer tokens on behalf of the caller.
51+
* @dev Sets the allowance for the spender.
52+
* @param _spender The address to approve for spending.
53+
* @param _value The amount of tokens to approve.
54+
*/
55+
function approve(address _spender, uint256 _value) {
56+
if (_spender == address(0)) {
57+
revert ERC20InvalidSpender(address(0));
58+
}
59+
ERC20Storage storage s = getStorage();
60+
s.allowance[msg.sender][_spender] = _value;
61+
emit Approval(msg.sender, _spender, _value);
62+
}

src/token/ERC20/ERC20Bridgeable/ERC20BridgeableFacet.sol

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,13 @@ contract ERC20BridgeableFacet {
8080
* @notice Storage slot for ERC-20 token using ERC8042 for storage location standardization
8181
* @dev Storage position determined by the keccak256 hash of the diamond storage identifier.
8282
*/
83-
bytes32 constant ERC20_TRANSFER_STORAGE_POSITION = keccak256("erc20.transfer");
83+
bytes32 constant ERC20_STORAGE_POSITION = keccak256("erc20");
8484

8585
/**
8686
* @dev ERC-8042 compliant storage struct for ERC20 token data.
87-
* @custom:storage-location erc8042:erc20.transfer
87+
* @custom:storage-location erc8042:erc20
8888
*/
89-
struct ERC20TransferStorage {
89+
struct ERC20Storage {
9090
mapping(address owner => uint256 balance) balanceOf;
9191
uint256 totalSupply;
9292
}
@@ -96,8 +96,8 @@ contract ERC20BridgeableFacet {
9696
* @return s The ERC20 storage struct reference.
9797
*/
9898

99-
function getERC20TransferStorage() internal pure returns (ERC20TransferStorage storage s) {
100-
bytes32 position = ERC20_TRANSFER_STORAGE_POSITION;
99+
function getERC20Storage() internal pure returns (ERC20Storage storage s) {
100+
bytes32 position = ERC20_STORAGE_POSITION;
101101
assembly {
102102
s.slot := position
103103
}
@@ -137,7 +137,7 @@ contract ERC20BridgeableFacet {
137137
* @param _value The amount to mint.
138138
*/
139139
function crosschainMint(address _account, uint256 _value) external {
140-
ERC20TransferStorage storage erc20Transfer = getERC20TransferStorage();
140+
ERC20Storage storage erc20Storage = getERC20Storage();
141141

142142
AccessControlStorage storage acs = getAccessControlStorage();
143143

@@ -153,8 +153,8 @@ contract ERC20BridgeableFacet {
153153
}
154154

155155
unchecked {
156-
erc20Transfer.totalSupply += _value;
157-
erc20Transfer.balanceOf[_account] += _value;
156+
erc20Storage.totalSupply += _value;
157+
erc20Storage.balanceOf[_account] += _value;
158158
}
159159
emit Transfer(address(0), _account, _value);
160160
emit CrosschainMint(_account, _value, msg.sender);
@@ -166,7 +166,7 @@ contract ERC20BridgeableFacet {
166166
* @param _value The amount to burn.
167167
*/
168168
function crosschainBurn(address _from, uint256 _value) external {
169-
ERC20TransferStorage storage erc20Transfer = getERC20TransferStorage();
169+
ERC20Storage storage erc20Storage = getERC20Storage();
170170

171171
AccessControlStorage storage acs = getAccessControlStorage();
172172

@@ -180,15 +180,15 @@ contract ERC20BridgeableFacet {
180180
revert ERC20InvalidReceiver(address(0));
181181
}
182182

183-
uint256 accountBalance = erc20Transfer.balanceOf[_from];
183+
uint256 accountBalance = erc20Storage.balanceOf[_from];
184184

185185
if (accountBalance < _value) {
186186
revert ERC20InsufficientBalance(_from, accountBalance, _value);
187187
}
188188

189189
unchecked {
190-
erc20Transfer.totalSupply -= _value;
191-
erc20Transfer.balanceOf[_from] -= _value;
190+
erc20Storage.totalSupply -= _value;
191+
erc20Storage.balanceOf[_from] -= _value;
192192
}
193193

194194
emit Transfer(_from, address(0), _value);

src/token/ERC20/ERC20Bridgeable/ERC20BridgeableMod.sol

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,13 @@ event Transfer(address indexed _from, address indexed _to, uint256 _value);
8080
* @notice Storage slot for ERC-20 token using ERC8042 for storage location standardization
8181
* @dev Storage position determined by the keccak256 hash of the diamond storage identifier.
8282
*/
83-
bytes32 constant ERC20_TRANSFER_STORAGE_POSITION = keccak256("erc20.transfer");
83+
bytes32 constant ERC20_STORAGE_POSITION = keccak256("erc20");
8484

8585
/**
8686
* @dev ERC-8042 compliant storage struct for ERC20 token data.
87-
* @custom:storage-location erc8042:erc20.transfer
87+
* @custom:storage-location erc8042:erc20
8888
*/
89-
struct ERC20TransferStorage {
89+
struct ERC20Storage {
9090
mapping(address owner => uint256 balance) balanceOf;
9191
uint256 totalSupply;
9292
}
@@ -96,8 +96,8 @@ struct ERC20TransferStorage {
9696
* @return s The ERC20 storage struct reference.
9797
*/
9898

99-
function getERC20TransferStorage() pure returns (ERC20TransferStorage storage s) {
100-
bytes32 position = ERC20_TRANSFER_STORAGE_POSITION;
99+
function getERC20Storage() pure returns (ERC20Storage storage s) {
100+
bytes32 position = ERC20_STORAGE_POSITION;
101101
assembly {
102102
s.slot := position
103103
}
@@ -137,7 +137,7 @@ function getAccessControlStorage() pure returns (AccessControlStorage storage s)
137137
* @param _value The amount to mint.
138138
*/
139139
function crosschainMint(address _account, uint256 _value) {
140-
ERC20TransferStorage storage erc20Transfer = getERC20TransferStorage();
140+
ERC20Storage storage erc20Storage = getERC20Storage();
141141

142142
AccessControlStorage storage acs = getAccessControlStorage();
143143

@@ -153,8 +153,8 @@ function crosschainMint(address _account, uint256 _value) {
153153
}
154154

155155
unchecked {
156-
erc20Transfer.totalSupply += _value;
157-
erc20Transfer.balanceOf[_account] += _value;
156+
erc20Storage.totalSupply += _value;
157+
erc20Storage.balanceOf[_account] += _value;
158158
}
159159

160160
emit Transfer(address(0), _account, _value);
@@ -167,7 +167,7 @@ function crosschainMint(address _account, uint256 _value) {
167167
* @param _value The amount to burn.
168168
*/
169169
function crosschainBurn(address _from, uint256 _value) {
170-
ERC20TransferStorage storage erc20Transfer = getERC20TransferStorage();
170+
ERC20Storage storage erc20Storage = getERC20Storage();
171171

172172
AccessControlStorage storage acs = getAccessControlStorage();
173173

@@ -182,15 +182,15 @@ function crosschainBurn(address _from, uint256 _value) {
182182
revert ERC20InvalidReceiver(address(0));
183183
}
184184

185-
uint256 accountBalance = erc20Transfer.balanceOf[_from];
185+
uint256 accountBalance = erc20Storage.balanceOf[_from];
186186

187187
if (accountBalance < _value) {
188188
revert ERC20InsufficientBalance(_from, accountBalance, _value);
189189
}
190190

191191
unchecked {
192-
erc20Transfer.totalSupply -= _value;
193-
erc20Transfer.balanceOf[_from] -= _value;
192+
erc20Storage.totalSupply -= _value;
193+
erc20Storage.balanceOf[_from] -= _value;
194194
}
195195
emit Transfer(_from, address(0), _value);
196196
emit CrosschainBurn(_from, _value, msg.sender);
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity >=0.8.30;
3+
4+
/* Compose
5+
* https://compose.diamonds
6+
*/
7+
8+
contract ERC20DataFacet {
9+
/**
10+
* @dev Storage position determined by the keccak256 hash of the diamond storage identifier.
11+
*/
12+
bytes32 constant STORAGE_POSITION = keccak256("erc20");
13+
14+
/**
15+
* @dev ERC-8042 compliant storage struct for ERC20 token data.
16+
* @custom:storage-location erc8042:erc20.transfer
17+
*/
18+
struct ERC20Storage {
19+
mapping(address owner => uint256 balance) balanceOf;
20+
uint256 totalSupply;
21+
mapping(address owner => mapping(address spender => uint256 allowance)) allowance;
22+
}
23+
24+
/**
25+
* @notice Returns the ERC20 storage struct from the predefined diamond storage slot.
26+
* @dev Uses inline assembly to set the storage slot reference.
27+
* @return s The ERC20 storage struct reference.
28+
*/
29+
function getStorage() internal pure returns (ERC20Storage storage s) {
30+
bytes32 position = STORAGE_POSITION;
31+
assembly {
32+
s.slot := position
33+
}
34+
}
35+
36+
/**
37+
* @notice Returns the total supply of tokens.
38+
* @return The total token supply.
39+
*/
40+
function totalSupply() external view returns (uint256) {
41+
return getStorage().totalSupply;
42+
}
43+
44+
/**
45+
* @notice Returns the balance of a specific account.
46+
* @param _account The address of the account.
47+
* @return The account balance.
48+
*/
49+
function balanceOf(address _account) external view returns (uint256) {
50+
return getStorage().balanceOf[_account];
51+
}
52+
53+
/**
54+
* @notice Returns the remaining number of tokens that a spender is allowed to spend on behalf of an owner.
55+
* @param _owner The address of the token owner.
56+
* @param _spender The address of the spender.
57+
* @return The remaining allowance.
58+
*/
59+
function allowance(address _owner, address _spender) external view returns (uint256) {
60+
return getStorage().allowance[_owner][_spender];
61+
}
62+
}

src/token/ERC20/ERC20Permit/ERC20PermitFacet.sol

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,19 +50,19 @@ contract ERC20PermitFacet {
5050
}
5151
}
5252

53-
bytes32 constant ERC20_TRANSFER_STORAGE_POSITION = keccak256("erc20.transfer");
53+
bytes32 constant ERC20_STORAGE_POSITION = keccak256("erc20");
5454

5555
/**
56-
* @custom:storage-location erc8042:erc20.transfer
56+
* @custom:storage-location erc8042:erc20
5757
*/
58-
struct ERC20TransferStorage {
58+
struct ERC20Storage {
5959
mapping(address owner => uint256 balance) balanceOf;
6060
uint256 totalSupply;
6161
mapping(address owner => mapping(address spender => uint256 allowance)) allowance;
6262
}
6363

64-
function getERC20TransferStorage() internal pure returns (ERC20TransferStorage storage s) {
65-
bytes32 position = ERC20_TRANSFER_STORAGE_POSITION;
64+
function getERC20Storage() internal pure returns (ERC20Storage storage s) {
65+
bytes32 position = ERC20_STORAGE_POSITION;
6666
assembly {
6767
s.slot := position
6868
}
@@ -139,7 +139,7 @@ contract ERC20PermitFacet {
139139
}
140140

141141
NoncesStorage storage s = getStorage();
142-
ERC20TransferStorage storage erc20Transfer = getERC20TransferStorage();
142+
ERC20Storage storage erc20Storage = getERC20Storage();
143143
uint256 currentNonce = s.nonces[_owner];
144144
bytes32 structHash = keccak256(
145145
abi.encode(
@@ -173,7 +173,7 @@ contract ERC20PermitFacet {
173173
revert ERC2612InvalidSignature(_owner, _spender, _value, _deadline, _v, _r, _s);
174174
}
175175

176-
erc20Transfer.allowance[_owner][_spender] = _value;
176+
erc20Storage.allowance[_owner][_spender] = _value;
177177
s.nonces[_owner] = currentNonce + 1;
178178
emit Approval(_owner, _spender, _value);
179179
}

0 commit comments

Comments
 (0)