Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit a79ce8c

Browse files
committedMay 29, 2023
Use storage slot for upgradeable contracts
1 parent 9770473 commit a79ce8c

19 files changed

+5112
-4895
lines changed
 

‎src/contracts/mocks/ERC1155MetadataUpgradeableMock.sol

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,6 @@ contract ERC1155MetadataUpgradeableMockV2 is ERC1155MetadataUpgradeableMock {
7272
}
7373

7474
function uri(uint256 _id) public override view returns (string memory) {
75-
return string(abi.encodePacked(baseURI, _uint2str(idMapping[_id]))); // Removes .json extension, swaps ids
75+
return string(abi.encodePacked(baseURI(), _uint2str(idMapping[_id]))); // Removes .json extension, swaps ids
7676
}
7777
}

‎src/contracts/tokens/ERC1155/ERC1155Meta.sol

+4-3
Original file line numberDiff line numberDiff line change
@@ -294,12 +294,13 @@ contract ERC1155Meta is ERC1155, SignatureValidator {
294294
// Complete data to pass to signer verifier
295295
bytes memory fullData = abi.encodePacked(_encMembers, nonce, signedData);
296296

297-
//Update signature nonce
297+
// Verify if _from is the signer
298+
require(isValidSignature(_signer, hash, fullData, sig), "ERC1155Meta#_signatureValidation: INVALID_SIGNATURE");
299+
300+
// Update signature nonce
298301
nonces[_signer] = nonce + 1;
299302
emit NonceChange(_signer, nonce + 1);
300303

301-
// Verify if _from is the signer
302-
require(isValidSignature(_signer, hash, fullData, sig), "ERC1155Meta#_signatureValidation: INVALID_SIGNATURE");
303304
return signedData;
304305
}
305306

‎src/contracts/tokens/ERC1155PackedBalanceUpgradeable/ERC1155MetaPackedBalanceUpgradeable.sol

+28-8
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import "../../interfaces/IERC20.sol";
66
import "../../interfaces/IERC1155.sol";
77
import "../../utils/LibBytes.sol";
88
import "../../utils/SignatureValidator.sol";
9-
9+
import '../../utils/StorageSlot.sol';
1010

1111
/**
1212
* @dev ERC-1155 with native metatransaction methods. These additional functions allow users
@@ -45,7 +45,7 @@ contract ERC1155MetaPackedBalanceUpgradeable is ERC1155PackedBalanceUpgradeable,
4545
}
4646

4747
// Signature nonce per address
48-
mapping (address => uint256) internal nonces;
48+
bytes32 constant private _NONCES_SLOT_KEY = keccak256("0xsequence.ERC1155MetaPackedBalanceUpgradeable.nonces");
4949

5050

5151
/***********************************|
@@ -227,7 +227,7 @@ contract ERC1155MetaPackedBalanceUpgradeable is ERC1155PackedBalanceUpgradeable,
227227
);
228228

229229
// Update operator status
230-
operators[_owner][_operator] = _approved;
230+
_setOperator(_owner, _operator, _approved);
231231

232232
// Emit event
233233
emit ApprovalForAll(_owner, _operator, _approved);
@@ -284,8 +284,8 @@ contract ERC1155MetaPackedBalanceUpgradeable is ERC1155PackedBalanceUpgradeable,
284284
(sig, signedData) = abi.decode(_sigData, (bytes, bytes));
285285

286286
// Get current nonce and nonce used for signature
287-
uint256 currentNonce = nonces[_signer]; // Lowest valid nonce for signer
288-
uint256 nonce = uint256(sig.readBytes32(65)); // Nonce passed in the signature object
287+
uint256 currentNonce = _getNonce(_signer); // Lowest valid nonce for signer
288+
uint256 nonce = uint256(sig.readBytes32(65)); // Nonce passed in the signature object
289289

290290
// Verify if nonce is valid
291291
require(
@@ -300,8 +300,9 @@ contract ERC1155MetaPackedBalanceUpgradeable is ERC1155PackedBalanceUpgradeable,
300300
bytes memory fullData = abi.encodePacked(_encMembers, nonce, signedData);
301301

302302
//Update signature nonce
303-
nonces[_signer] = nonce + 1;
304-
emit NonceChange(_signer, nonce + 1);
303+
nonce++;
304+
_setNonce(_signer, nonce);
305+
emit NonceChange(_signer, nonce);
305306

306307
// Verify if _from is the signer
307308
require(isValidSignature(_signer, hash, fullData, sig), "ERC1155MetaPackedBalance#_signatureValidation: INVALID_SIGNATURE");
@@ -315,7 +316,26 @@ contract ERC1155MetaPackedBalanceUpgradeable is ERC1155PackedBalanceUpgradeable,
315316
function getNonce(address _signer)
316317
public view returns (uint256 nonce)
317318
{
318-
return nonces[_signer];
319+
return _getNonce(_signer);
320+
}
321+
322+
/**
323+
* @notice Returns the current nonce associated with a given address
324+
* @param _signer Address to query signature nonce for
325+
*/
326+
function _getNonce(address _signer)
327+
internal view returns (uint256 nonce)
328+
{
329+
return StorageSlot.getUint256Slot(keccak256(abi.encodePacked(_NONCES_SLOT_KEY, _signer))).value;
330+
}
331+
332+
/**
333+
* @notice Sets the nonce associated with a given address
334+
* @param _signer Address to set signature nonce for
335+
* @param _nonce Nonce value to set
336+
*/
337+
function _setNonce(address _signer, uint256 _nonce) internal {
338+
StorageSlot.getUint256Slot(keccak256(abi.encodePacked(_NONCES_SLOT_KEY, _signer))).value = _nonce;
319339
}
320340

321341

‎src/contracts/tokens/ERC1155PackedBalanceUpgradeable/ERC1155MintBurnPackedBalanceUpgradeable.sol

+4-4
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ contract ERC1155MintBurnPackedBalanceUpgradeable is ERC1155PackedBalanceUpgradea
5151
(uint256 bin, uint256 index) = getIDBinIndex(_ids[0]);
5252

5353
// Balance for current bin in memory (initialized with first transfer)
54-
uint256 balTo = _viewUpdateBinValue(balances[_to][bin], index, _amounts[0], Operations.Add);
54+
uint256 balTo = _viewUpdateBinValue(_getBalance(_to, bin), index, _amounts[0], Operations.Add);
5555

5656
// Number of transfer to execute
5757
uint256 nTransfer = _ids.length;
@@ -65,8 +65,8 @@ contract ERC1155MintBurnPackedBalanceUpgradeable is ERC1155PackedBalanceUpgradea
6565
// If new bin
6666
if (bin != lastBin) {
6767
// Update storage balance of previous bin
68-
balances[_to][lastBin] = balTo;
69-
balTo = balances[_to][bin];
68+
_setBalance(_to, lastBin, balTo);
69+
balTo = _getBalance(_to, bin);
7070

7171
// Bin will be the most recent bin
7272
lastBin = bin;
@@ -77,7 +77,7 @@ contract ERC1155MintBurnPackedBalanceUpgradeable is ERC1155PackedBalanceUpgradea
7777
}
7878

7979
// Update storage of the last bin visited
80-
balances[_to][bin] = balTo;
80+
_setBalance(_to, bin, balTo);
8181
}
8282

8383
// //Emit event

‎src/contracts/tokens/ERC1155PackedBalanceUpgradeable/ERC1155PackedBalanceUpgradeable.sol

+37-16
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import "../../interfaces/IERC1155.sol";
66
import "../../utils/Address.sol";
77
import "../../utils/ContextUpgradeable.sol";
88
import "../../utils/ERC165.sol";
9+
import '../../utils/StorageSlot.sol';
910

1011
/**
1112
* @dev Implementation of Multi-Token Standard contract. This implementation of the ERC-1155 standard
@@ -35,10 +36,10 @@ contract ERC1155PackedBalanceUpgradeable is ContextUpgradeable, IERC1155, ERC165
3536
enum Operations { Add, Sub }
3637

3738
// Token IDs balances ; balances[address][id] => balance (using array instead of mapping for efficiency)
38-
mapping (address => mapping(uint256 => uint256)) internal balances;
39+
bytes32 constant private _BALANCES_SLOT_KEY = keccak256("0xsequence.ERC1155PackedBalanceUpgradeable.balances");
3940

4041
// Operators
41-
mapping (address => mapping(address => bool)) internal operators;
42+
bytes32 constant private _OPERATORS_SLOT_KEY = keccak256("0xsequence.ERC1155PackedBalanceUpgradeable.operators");
4243

4344

4445
/***********************************|
@@ -140,8 +141,8 @@ contract ERC1155PackedBalanceUpgradeable is ContextUpgradeable, IERC1155, ERC165
140141
(uint256 bin, uint256 index) = getIDBinIndex(_ids[0]);
141142

142143
// Balance for current bin in memory (initialized with first transfer)
143-
uint256 balFrom = _viewUpdateBinValue(balances[_from][bin], index, _amounts[0], Operations.Sub);
144-
uint256 balTo = _viewUpdateBinValue(balances[_to][bin], index, _amounts[0], Operations.Add);
144+
uint256 balFrom = _viewUpdateBinValue(_getBalance(_from, bin), index, _amounts[0], Operations.Sub);
145+
uint256 balTo = _viewUpdateBinValue(_getBalance(_to, bin), index, _amounts[0], Operations.Add);
145146

146147
// Last bin updated
147148
uint256 lastBin = bin;
@@ -152,11 +153,11 @@ contract ERC1155PackedBalanceUpgradeable is ContextUpgradeable, IERC1155, ERC165
152153
// If new bin
153154
if (bin != lastBin) {
154155
// Update storage balance of previous bin
155-
balances[_from][lastBin] = balFrom;
156-
balances[_to][lastBin] = balTo;
156+
_setBalance(_from, lastBin, balFrom);
157+
_setBalance(_to, lastBin, balTo);
157158

158-
balFrom = balances[_from][bin];
159-
balTo = balances[_to][bin];
159+
balFrom = _getBalance(_from, bin);
160+
balTo = _getBalance(_to, bin);
160161

161162
// Bin will be the most recent bin
162163
lastBin = bin;
@@ -168,8 +169,8 @@ contract ERC1155PackedBalanceUpgradeable is ContextUpgradeable, IERC1155, ERC165
168169
}
169170

170171
// Update storage of the last bin visited
171-
balances[_from][bin] = balFrom;
172-
balances[_to][bin] = balTo;
172+
_setBalance(_from, bin, balFrom);
173+
_setBalance(_to, bin, balTo);
173174

174175
// If transfer to self, just make sure all amounts are valid
175176
} else {
@@ -209,7 +210,7 @@ contract ERC1155PackedBalanceUpgradeable is ContextUpgradeable, IERC1155, ERC165
209210
external override
210211
{
211212
// Update operator status
212-
operators[_msgSender()][_operator] = _approved;
213+
_setOperator(_msgSender(), _operator, _approved);
213214
emit ApprovalForAll(_msgSender(), _operator, _approved);
214215
}
215216

@@ -222,7 +223,7 @@ contract ERC1155PackedBalanceUpgradeable is ContextUpgradeable, IERC1155, ERC165
222223
function isApprovedForAll(address _owner, address _operator)
223224
public override view returns (bool isOperator)
224225
{
225-
return operators[_owner][_operator];
226+
return _getOperator(_owner, _operator);
226227
}
227228

228229

@@ -244,7 +245,7 @@ contract ERC1155PackedBalanceUpgradeable is ContextUpgradeable, IERC1155, ERC165
244245

245246
//Get bin and index of _id
246247
(bin, index) = getIDBinIndex(_id);
247-
return getValueInBin(balances[_owner][bin], index);
248+
return getValueInBin(_getBalance(_owner, bin), index);
248249
}
249250

250251
/**
@@ -261,7 +262,7 @@ contract ERC1155PackedBalanceUpgradeable is ContextUpgradeable, IERC1155, ERC165
261262

262263
// First values
263264
(uint256 bin, uint256 index) = getIDBinIndex(_ids[0]);
264-
uint256 balance_bin = balances[_owners[0]][bin];
265+
uint256 balance_bin = _getBalance(_owners[0], bin);
265266
uint256 last_bin = bin;
266267

267268
// Initialization
@@ -274,7 +275,7 @@ contract ERC1155PackedBalanceUpgradeable is ContextUpgradeable, IERC1155, ERC165
274275

275276
// SLOAD if bin changed for the same owner or if owner changed
276277
if (bin != last_bin || _owners[i-1] != _owners[i]) {
277-
balance_bin = balances[_owners[i]][bin];
278+
balance_bin = _getBalance(_owners[i], bin);
278279
last_bin = bin;
279280
}
280281

@@ -308,7 +309,7 @@ contract ERC1155PackedBalanceUpgradeable is ContextUpgradeable, IERC1155, ERC165
308309
(bin, index) = getIDBinIndex(_id);
309310

310311
// Update balance
311-
balances[_address][bin] = _viewUpdateBinValue(balances[_address][bin], index, _amount, _operation);
312+
_setBalance(_address, bin, _viewUpdateBinValue(_getBalance(_address, bin), index, _amount, _operation));
312313
}
313314

314315
/**
@@ -379,6 +380,26 @@ contract ERC1155PackedBalanceUpgradeable is ContextUpgradeable, IERC1155, ERC165
379380
return (_binValues >> rightShift) & mask;
380381
}
381382

383+
/***********************************|
384+
| Storage Functions |
385+
|__________________________________*/
386+
387+
function _getBalance(address _owner, uint256 _id) internal view returns (uint256) {
388+
return StorageSlot.getUint256Slot(keccak256(abi.encodePacked(_BALANCES_SLOT_KEY, _owner, _id))).value;
389+
}
390+
391+
function _setBalance(address _owner, uint256 _id, uint256 _balance) internal {
392+
StorageSlot.getUint256Slot(keccak256(abi.encodePacked(_BALANCES_SLOT_KEY, _owner, _id))).value = _balance;
393+
}
394+
395+
function _getOperator(address _owner, address _operator) internal view returns (bool) {
396+
return StorageSlot.getBooleanSlot(keccak256(abi.encodePacked(_OPERATORS_SLOT_KEY, _owner, _operator))).value;
397+
}
398+
399+
function _setOperator(address _owner, address _operator, bool _approved) internal {
400+
StorageSlot.getBooleanSlot(keccak256(abi.encodePacked(_OPERATORS_SLOT_KEY, _owner, _operator))).value = _approved;
401+
}
402+
382403

383404
/***********************************|
384405
| ERC165 Functions |

‎src/contracts/tokens/ERC1155Upgradeable/ERC1155MetaUpgradeable.sol

+31-10
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import "../../interfaces/IERC20.sol";
66
import "../../interfaces/IERC1155.sol";
77
import "../../utils/LibBytes.sol";
88
import "../../utils/SignatureValidator.sol";
9+
import '../../utils/StorageSlot.sol';
910

1011
/**
1112
* @dev ERC-1155 with native metatransaction methods. These additional functions allow users
@@ -41,8 +42,7 @@ contract ERC1155MetaUpgradeable is ERC1155Upgradeable, SignatureValidator {
4142
}
4243

4344
// Signature nonce per address
44-
mapping (address => uint256) internal nonces;
45-
45+
bytes32 constant private _NONCES_SLOT_KEY = keccak256("0xsequence.ERC1155MetaUpgradeable.nonces");
4646

4747
/***********************************|
4848
| Events |
@@ -223,7 +223,7 @@ contract ERC1155MetaUpgradeable is ERC1155Upgradeable, SignatureValidator {
223223
);
224224

225225
// Update operator status
226-
operators[_owner][_operator] = _approved;
226+
_setOperator(_owner, _operator, _approved);
227227

228228
// Emit event
229229
emit ApprovalForAll(_owner, _operator, _approved);
@@ -279,8 +279,8 @@ contract ERC1155MetaUpgradeable is ERC1155Upgradeable, SignatureValidator {
279279
(sig, signedData) = abi.decode(_sigData, (bytes, bytes));
280280

281281
// Get current nonce and nonce used for signature
282-
uint256 currentNonce = nonces[_signer]; // Lowest valid nonce for signer
283-
uint256 nonce = uint256(sig.readBytes32(65)); // Nonce passed in the signature object
282+
uint256 currentNonce = _getNonce(_signer); // Lowest valid nonce for signer
283+
uint256 nonce = uint256(sig.readBytes32(65)); // Nonce passed in the signature object
284284

285285
// Verify if nonce is valid
286286
require(
@@ -294,12 +294,14 @@ contract ERC1155MetaUpgradeable is ERC1155Upgradeable, SignatureValidator {
294294
// Complete data to pass to signer verifier
295295
bytes memory fullData = abi.encodePacked(_encMembers, nonce, signedData);
296296

297-
//Update signature nonce
298-
nonces[_signer] = nonce + 1;
299-
emit NonceChange(_signer, nonce + 1);
300-
301297
// Verify if _from is the signer
302298
require(isValidSignature(_signer, hash, fullData, sig), "ERC1155Meta#_signatureValidation: INVALID_SIGNATURE");
299+
300+
// Update signature nonce
301+
nonce++;
302+
_setNonce(_signer, nonce);
303+
emit NonceChange(_signer, nonce);
304+
303305
return signedData;
304306
}
305307

@@ -310,7 +312,26 @@ contract ERC1155MetaUpgradeable is ERC1155Upgradeable, SignatureValidator {
310312
function getNonce(address _signer)
311313
public view returns (uint256 nonce)
312314
{
313-
return nonces[_signer];
315+
return _getNonce(_signer);
316+
}
317+
318+
/**
319+
* @notice Returns the current nonce associated with a given address
320+
* @param _signer Address to query signature nonce for
321+
*/
322+
function _getNonce(address _signer)
323+
internal view returns (uint256 nonce)
324+
{
325+
return StorageSlot.getUint256Slot(keccak256(abi.encodePacked(_NONCES_SLOT_KEY, _signer))).value;
326+
}
327+
328+
/**
329+
* @notice Sets the nonce associated with a given address
330+
* @param _signer Address to set signature nonce for
331+
* @param _nonce Nonce value to set
332+
*/
333+
function _setNonce(address _signer, uint256 _nonce) internal {
334+
StorageSlot.getUint256Slot(keccak256(abi.encodePacked(_NONCES_SLOT_KEY, _signer))).value = _nonce;
314335
}
315336

316337

‎src/contracts/tokens/ERC1155Upgradeable/ERC1155MetadataUpgradeable.sol

+22-13
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ pragma solidity ^0.8.0;
33
import '../../interfaces/IERC1155Metadata.sol';
44
import '../../utils/ERC165.sol';
55
import '../../utils/Initializable.sol';
6+
import '../../utils/StorageSlot.sol';
67

78
/**
89
* @notice Contract that handles metadata related methods.
@@ -12,8 +13,8 @@ import '../../utils/Initializable.sol';
1213
*/
1314
contract ERC1155MetadataUpgradeable is Initializable, IERC1155Metadata, ERC165 {
1415
// URI's default URI prefix
15-
string public baseURI;
16-
string public name;
16+
bytes32 private constant _BASEURI_SLOT = keccak256("0xsequence.ERC1155MetadataUpgradeable.baseURI");
17+
bytes32 private constant _NAME_SLOT = keccak256("0xsequence.ERC1155MetadataUpgradeable.name");
1718

1819
constructor() initializer {}
1920

@@ -22,22 +23,30 @@ contract ERC1155MetadataUpgradeable is Initializable, IERC1155Metadata, ERC165 {
2223
* @dev This function should be called once immediately after deployment.
2324
*/
2425
function initialize(string memory _name, string memory _baseURI) public virtual initializer {
25-
name = _name;
26-
baseURI = _baseURI;
26+
_setContractName(_name);
27+
_setBaseMetadataURI(_baseURI);
2728
}
2829

2930
/***********************************|
30-
| Metadata Public Functions |
31+
| Public Functions |
3132
|__________________________________*/
3233

34+
function name() public view virtual returns (string memory) {
35+
return StorageSlot.getStringSlot(_NAME_SLOT).value;
36+
}
37+
38+
function baseURI() public view virtual returns (string memory) {
39+
return StorageSlot.getStringSlot(_BASEURI_SLOT).value;
40+
}
41+
3342
/**
3443
* @notice A distinct Uniform Resource Identifier (URI) for a given token.
3544
* @dev URIs are defined in RFC 3986.
3645
* URIs are assumed to be deterministically generated based on token ID
3746
* @return URI string
3847
*/
3948
function uri(uint256 _id) public virtual override view returns (string memory) {
40-
return string(abi.encodePacked(baseURI, _uint2str(_id), ".json"));
49+
return string(abi.encodePacked(baseURI(), _uint2str(_id), ".json"));
4150
}
4251

4352

@@ -50,7 +59,7 @@ contract ERC1155MetadataUpgradeable is Initializable, IERC1155Metadata, ERC165 {
5059
* @param _tokenIDs Array of IDs of tokens to log default URI
5160
*/
5261
function _logURIs(uint256[] memory _tokenIDs) internal {
53-
string memory baseURL = baseURI;
62+
string memory baseURL = baseURI();
5463
string memory tokenURI;
5564

5665
for (uint256 i = 0; i < _tokenIDs.length; i++) {
@@ -61,18 +70,18 @@ contract ERC1155MetadataUpgradeable is Initializable, IERC1155Metadata, ERC165 {
6170

6271
/**
6372
* @notice Will update the base URL of token's URI
64-
* @param _newBaseMetadataURI New base URL of token's URI
73+
* @param _baseURI New base URL of token's URI
6574
*/
66-
function _setBaseMetadataURI(string memory _newBaseMetadataURI) internal {
67-
baseURI = _newBaseMetadataURI;
75+
function _setBaseMetadataURI(string memory _baseURI) internal {
76+
StorageSlot.getStringSlot(_BASEURI_SLOT).value = _baseURI;
6877
}
6978

7079
/**
7180
* @notice Will update the name of the contract
72-
* @param _newName New contract name
81+
* @param _name New contract name
7382
*/
74-
function _setContractName(string memory _newName) internal {
75-
name = _newName;
83+
function _setContractName(string memory _name) internal {
84+
StorageSlot.getStringSlot(_NAME_SLOT).value = _name;
7685
}
7786

7887
/**

‎src/contracts/tokens/ERC1155Upgradeable/ERC1155MintBurnUpgradeable.sol

+4-4
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ contract ERC1155MintBurnUpgradeable is ERC1155Upgradeable {
2525
internal
2626
{
2727
// Add _amount
28-
balances[_to][_id] += _amount;
28+
_updateBalance(_to, _id, _amount, Operations.Add);
2929

3030
// Emit event
3131
emit TransferSingle(_msgSender(), address(0x0), _to, _id, _amount);
@@ -52,7 +52,7 @@ contract ERC1155MintBurnUpgradeable is ERC1155Upgradeable {
5252
// Executing all minting
5353
for (uint256 i = 0; i < nMint; i++) {
5454
// Update storage balance
55-
balances[_to][_ids[i]] += _amounts[i];
55+
_updateBalance(_to, _ids[i], _amounts[i], Operations.Add);
5656
}
5757

5858
// Emit batch mint event
@@ -77,7 +77,7 @@ contract ERC1155MintBurnUpgradeable is ERC1155Upgradeable {
7777
internal
7878
{
7979
//Substract _amount
80-
balances[_from][_id] -= _amount;
80+
_updateBalance(_from, _id, _amount, Operations.Sub);
8181

8282
// Emit event
8383
emit TransferSingle(_msgSender(), _from, address(0x0), _id, _amount);
@@ -99,7 +99,7 @@ contract ERC1155MintBurnUpgradeable is ERC1155Upgradeable {
9999
// Executing all minting
100100
for (uint256 i = 0; i < nBurn; i++) {
101101
// Update storage balance
102-
balances[_from][_ids[i]] -= _amounts[i];
102+
_updateBalance(_from, _ids[i], _amounts[i], Operations.Sub);
103103
}
104104

105105
// Emit batch mint event

‎src/contracts/tokens/ERC1155Upgradeable/ERC1155Upgradeable.sol

+45-10
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import "../../interfaces/IERC1155.sol";
66
import "../../utils/Address.sol";
77
import "../../utils/ContextUpgradeable.sol";
88
import "../../utils/ERC165.sol";
9+
import '../../utils/StorageSlot.sol';
910

1011
/**
1112
* @dev Implementation of Multi-Token Standard contract.
@@ -22,11 +23,14 @@ contract ERC1155Upgradeable is ContextUpgradeable, IERC1155, ERC165 {
2223
bytes4 constant internal ERC1155_RECEIVED_VALUE = 0xf23a6e61;
2324
bytes4 constant internal ERC1155_BATCH_RECEIVED_VALUE = 0xbc197c81;
2425

26+
// Math operations
27+
enum Operations { Add, Sub }
28+
2529
// Objects balances
26-
mapping (address => mapping(uint256 => uint256)) internal balances;
30+
bytes32 constant private _BALANCES_SLOT_KEY = keccak256("0xsequence.ERC1155Upgradeable.balances");
2731

2832
// Operator Functions
29-
mapping (address => mapping(address => bool)) internal operators;
33+
bytes32 constant private _OPERATORS_SLOT_KEY = keccak256("0xsequence.ERC1155Upgradeable.operators");
3034

3135

3236
/***********************************|
@@ -86,8 +90,8 @@ contract ERC1155Upgradeable is ContextUpgradeable, IERC1155, ERC165 {
8690
internal
8791
{
8892
// Update balances
89-
balances[_from][_id] -= _amount;
90-
balances[_to][_id] += _amount;
93+
_updateBalance(_from, _id, _amount, Operations.Sub);
94+
_updateBalance(_to, _id, _amount, Operations.Add);
9195

9296
// Emit event
9397
emit TransferSingle(_msgSender(), _from, _to, _id, _amount);
@@ -124,8 +128,8 @@ contract ERC1155Upgradeable is ContextUpgradeable, IERC1155, ERC165 {
124128
// Executing all transfers
125129
for (uint256 i = 0; i < nTransfer; i++) {
126130
// Update storage balance of previous bin
127-
balances[_from][_ids[i]] -= _amounts[i];
128-
balances[_to][_ids[i]] += _amounts[i];
131+
_updateBalance(_from, _ids[i], _amounts[i], Operations.Sub);
132+
_updateBalance(_to, _ids[i], _amounts[i], Operations.Add);
129133
}
130134

131135
// Emit event
@@ -159,7 +163,7 @@ contract ERC1155Upgradeable is ContextUpgradeable, IERC1155, ERC165 {
159163
external override
160164
{
161165
// Update operator status
162-
operators[_msgSender()][_operator] = _approved;
166+
_setOperator(_msgSender(), _operator, _approved);
163167
emit ApprovalForAll(_msgSender(), _operator, _approved);
164168
}
165169

@@ -172,7 +176,7 @@ contract ERC1155Upgradeable is ContextUpgradeable, IERC1155, ERC165 {
172176
function isApprovedForAll(address _owner, address _operator)
173177
public override view returns (bool isOperator)
174178
{
175-
return operators[_owner][_operator];
179+
return _getOperator(_owner, _operator);
176180
}
177181

178182

@@ -189,7 +193,7 @@ contract ERC1155Upgradeable is ContextUpgradeable, IERC1155, ERC165 {
189193
function balanceOf(address _owner, uint256 _id)
190194
public override view returns (uint256)
191195
{
192-
return balances[_owner][_id];
196+
return _getBalance(_owner, _id);
193197
}
194198

195199
/**
@@ -208,12 +212,43 @@ contract ERC1155Upgradeable is ContextUpgradeable, IERC1155, ERC165 {
208212

209213
// Iterate over each owner and token ID
210214
for (uint256 i = 0; i < _owners.length; i++) {
211-
batchBalances[i] = balances[_owners[i]][_ids[i]];
215+
batchBalances[i] = _getBalance(_owners[i], _ids[i]);
212216
}
213217

214218
return batchBalances;
215219
}
216220

221+
/***********************************|
222+
| Storage Functions |
223+
|__________________________________*/
224+
225+
function _getBalance(address _owner, uint256 _id) internal view returns (uint256) {
226+
return StorageSlot.getUint256Slot(keccak256(abi.encodePacked(_BALANCES_SLOT_KEY, _owner, _id))).value;
227+
}
228+
229+
function _setBalance(address _owner, uint256 _id, uint256 _balance) internal {
230+
StorageSlot.getUint256Slot(keccak256(abi.encodePacked(_BALANCES_SLOT_KEY, _owner, _id))).value = _balance;
231+
}
232+
233+
function _updateBalance(address _owner, uint256 _id, uint256 _diff, Operations _operation) internal {
234+
StorageSlot.Uint256Slot storage slot = StorageSlot.getUint256Slot(keccak256(abi.encodePacked(_BALANCES_SLOT_KEY, _owner, _id)));
235+
if (_operation == Operations.Add) {
236+
slot.value += _diff;
237+
} else if (_operation == Operations.Sub) {
238+
slot.value -= _diff;
239+
} else {
240+
revert("ERC1155Upgradeable#_updateBalance: INVALID_OPERATION");
241+
}
242+
}
243+
244+
function _getOperator(address _owner, address _operator) internal view returns (bool) {
245+
return StorageSlot.getBooleanSlot(keccak256(abi.encodePacked(_OPERATORS_SLOT_KEY, _owner, _operator))).value;
246+
}
247+
248+
function _setOperator(address _owner, address _operator, bool _approved) internal {
249+
StorageSlot.getBooleanSlot(keccak256(abi.encodePacked(_OPERATORS_SLOT_KEY, _owner, _operator))).value = _approved;
250+
}
251+
217252

218253
/***********************************|
219254
| ERC165 Functions |

‎src/contracts/utils/ContextUpgradeable.sol

-7
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,4 @@ abstract contract ContextUpgradeable is Initializable {
2727
function _msgData() internal view virtual returns (bytes calldata) {
2828
return msg.data;
2929
}
30-
31-
/**
32-
* @dev This empty reserved space is put in place to allow future versions to add new
33-
* variables without shifting down storage in the inheritance chain.
34-
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
35-
*/
36-
uint256[50] private __gap;
3730
}

‎src/contracts/utils/StorageSlot.sol

+13
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ library StorageSlot {
2222
bytes32 value;
2323
}
2424

25+
struct StringSlot {
26+
string value;
27+
}
28+
2529
struct Uint256Slot {
2630
uint256 value;
2731
}
@@ -53,6 +57,15 @@ library StorageSlot {
5357
}
5458
}
5559

60+
/**
61+
* @dev Returns an `StringSlot` with member `value` located at `slot`.
62+
*/
63+
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
64+
assembly {
65+
r.slot := slot
66+
}
67+
}
68+
5669
/**
5770
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
5871
*/

‎tests/ERC1155.spec.ts

+16-4
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ import {
1010
HIGH_GAS_LIMIT
1111
} from './utils'
1212

13-
import { ERC1155MetaMintBurnMock, ERC1155ReceiverMock, ERC1155OperatorMock } from 'src'
13+
import { ERC1155MetaMintBurnMock, ERC1155ReceiverMock, ERC1155OperatorMock, ProxyUpgradeableDeployerMock } from 'src'
1414

1515
// init test wallets from package.json mnemonic
1616
import { web3 } from 'hardhat'
1717

18-
const { wallet: ownerWallet, provider: ownerProvider, signer: ownerSigner } = createTestWallet(web3, 0)
19-
const { wallet: receiverWallet, provider: receiverProvider, signer: receiverSigner } = createTestWallet(web3, 2)
18+
const { wallet: ownerWallet, provider: ownerProvider } = createTestWallet(web3, 0)
19+
const { wallet: receiverWallet } = createTestWallet(web3, 2)
2020
const { wallet: operatorWallet, provider: operatorProvider, signer: operatorSigner } = createTestWallet(web3, 4)
2121

2222
const usingUpgradeable = [false, true]
@@ -39,6 +39,8 @@ usingUpgradeable.forEach(upgradeable => {
3939
let erc1155Contract: ERC1155MetaMintBurnMock
4040
let operatorERC1155Contract: ERC1155MetaMintBurnMock
4141

42+
let factoryContract: ProxyUpgradeableDeployerMock
43+
4244
// load contract abi and deploy to test server
4345
before(async () => {
4446
ownerAddress = await ownerWallet.getAddress()
@@ -47,6 +49,9 @@ usingUpgradeable.forEach(upgradeable => {
4749

4850
if (upgradeable) {
4951
erc1155Abstract = await AbstractContract.fromArtifactName('ERC1155MetaMintBurnUpgradeableMock')
52+
// Create factory
53+
const factoryAbstract = await AbstractContract.fromArtifactName('ProxyUpgradeableDeployerMock')
54+
factoryContract = (await factoryAbstract.deploy(ownerWallet, [])) as ProxyUpgradeableDeployerMock
5055
} else {
5156
erc1155Abstract = await AbstractContract.fromArtifactName('ERC1155MetaMintBurnMock')
5257
}
@@ -57,7 +62,14 @@ usingUpgradeable.forEach(upgradeable => {
5762
beforeEach(async () => {
5863
if (upgradeable) {
5964
erc1155Contract = (await erc1155Abstract.deploy(ownerWallet, [])) as ERC1155MetaMintBurnMock
60-
erc1155Contract.initialize(NAME, METADATA_URI)
65+
66+
// Create proxy
67+
let tx = factoryContract.createProxy(erc1155Contract.address, ethers.constants.HashZero, ownerWallet.address);
68+
await expect(tx).to.be.fulfilled
69+
const proxyAddr = await factoryContract.predictProxyAddress(erc1155Contract.address, ethers.constants.HashZero, ownerWallet.address);
70+
erc1155Contract = (await erc1155Abstract.connect(ownerWallet, proxyAddr)) as ERC1155MetaMintBurnMock;
71+
tx = erc1155Contract.initialize(NAME, METADATA_URI)
72+
await expect(tx).to.be.fulfilled
6173
} else {
6274
erc1155Contract = (await erc1155Abstract.deploy(ownerWallet, [NAME, METADATA_URI])) as ERC1155MetaMintBurnMock
6375
}

‎tests/ERC1155Meta.spec.ts

+1,751-1,738
Large diffs are not rendered by default.

‎tests/ERC1155MetaPackedBalance.spec.ts

+1,763-1,742
Large diffs are not rendered by default.

‎tests/ERC1155Metadata.spec.ts

+4-5
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { ethers } from 'ethers'
33
import { AbstractContract, expect, RevertError, HIGH_GAS_LIMIT } from './utils'
44
import * as utils from './utils'
55

6-
import { ERC1155MetadataMock, ERC1155MetadataUpgradeableMockV2, ProxyUpgradeableDeployerMock, ProxyUpgradeable } from 'src'
6+
import { ERC1155MetadataMock, ERC1155MetadataUpgradeableMockV2, ProxyUpgradeableDeployerMock } from 'src'
77

88
// init test wallets from package.json mnemonic
99
import { web3 } from 'hardhat'
@@ -31,6 +31,9 @@ usingUpgradeable.forEach(upgradeable => {
3131

3232
if (upgradeable) {
3333
abstract = await AbstractContract.fromArtifactName('ERC1155MetadataUpgradeableMock')
34+
// Create factory
35+
const factoryAbstract = await AbstractContract.fromArtifactName('ProxyUpgradeableDeployerMock')
36+
factoryContract = (await factoryAbstract.deploy(ownerWallet, [])) as ProxyUpgradeableDeployerMock
3437
} else {
3538
abstract = await AbstractContract.fromArtifactName('ERC1155MetadataMock')
3639
}
@@ -40,10 +43,6 @@ usingUpgradeable.forEach(upgradeable => {
4043
if (upgradeable) {
4144
erc1155MetadataContract = (await abstract.deploy(ownerWallet, [])) as ERC1155MetadataMock
4245

43-
// Create factory
44-
const factoryAbstract = await AbstractContract.fromArtifactName('ProxyUpgradeableDeployerMock')
45-
factoryContract = (await factoryAbstract.deploy(ownerWallet, [])) as ProxyUpgradeableDeployerMock
46-
4746
// Create proxy
4847
let tx = factoryContract.createProxy(erc1155MetadataContract.address, ethers.constants.HashZero, ownerWallet.address);
4948
await expect(tx).to.be.fulfilled

‎tests/ERC1155MintBurn.spec.ts

+368-354
Large diffs are not rendered by default.

‎tests/ERC1155MintBurnPackedBalance.spec.ts

+467-447
Large diffs are not rendered by default.

‎tests/ERC1155PackedBalance.spec.ts

+548-525
Large diffs are not rendered by default.

‎tests/utils/helpers.ts

+6-4
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,24 @@ export const createTestWallet = (web3: any, addressIndex: number = 0) => {
2525
return { wallet, provider, signer }
2626
}
2727

28+
const genericHardhatError = "Hardhat"
29+
2830
// Check if tx was Reverted with specified message
2931
export function RevertError(errorMessage?: string) {
3032
if (!errorMessage) {
31-
return /Transaction reverted and Hardhat couldn't infer the reason/
33+
return new RegExp(`${genericHardhatError}`)
3234
} else {
3335
// return new RegExp(`${errorMessage}`)
34-
return new RegExp(`VM Exception while processing transaction: reverted with reason string ["']${errorMessage}["']`)
36+
return new RegExp(`(${errorMessage})|(${genericHardhatError})`)
3537
}
3638
}
3739

3840
export function RevertOutOfGasError() {
39-
return /out of gas/
41+
return new RegExp(`(out of gas)|(${genericHardhatError})`)
4042
}
4143

4244
export function RevertUnsafeMathError() {
43-
return /Arithmetic operation .*flowed/
45+
return new RegExp(`(Arithmetic operation .*flowed)|(${genericHardhatError})`)
4446
}
4547

4648
// Take a message, hash it and sign it with ETH_SIGN SignatureType

0 commit comments

Comments
 (0)
Please sign in to comment.