diff --git a/.editorconfig b/.editorconfig index b45ed774d..e885a65c4 100644 --- a/.editorconfig +++ b/.editorconfig @@ -6,7 +6,12 @@ root = true [*] charset = utf-8 end_of_line = lf -indent_size = 2 indent_style = space insert_final_newline = true trim_trailing_whitespace = true + +[*.sol] +indent_size = 4 + +[*.js] +indent_size = 2 diff --git a/contracts/GSN/bouncers/GSNBouncerERC20Fee.sol b/contracts/GSN/bouncers/GSNBouncerERC20Fee.sol index adfb67682..133689040 100644 --- a/contracts/GSN/bouncers/GSNBouncerERC20Fee.sol +++ b/contracts/GSN/bouncers/GSNBouncerERC20Fee.sol @@ -20,7 +20,7 @@ contract GSNBouncerERC20Fee is Initializable, GSNBouncerBase { // storage layout. This value is calculated as: keccak256('gsn.bouncer.signature.token'), minus 1. bytes32 constant private TOKEN_STORAGE_SLOT = 0xd918b70a5a5c95a8c0cac8acbdd59e1b4acd0645f53c0461d64b41f8825c8828; - function initialize(string memory name, string memory symbol, uint8 decimals) initializer public { + function initialize(string memory name, string memory symbol, uint8 decimals) public initializer { // TODO: Should we inject this token, instead of creating it, in order to make it upgradeable? // However, that would mean removing it from unstable and making in an official contract _setToken(new __unstable__ERC20PrimaryAdmin(name, symbol, decimals)); diff --git a/contracts/access/roles/CapperRole.sol b/contracts/access/roles/CapperRole.sol index 0236595a9..403bbae52 100644 --- a/contracts/access/roles/CapperRole.sol +++ b/contracts/access/roles/CapperRole.sol @@ -1,10 +1,11 @@ pragma solidity ^0.5.2; import "@openzeppelin/upgrades/contracts/Initializable.sol"; + +import "../../GSN/Context.sol"; import "../Roles.sol"; - -contract CapperRole is Initializable { +contract CapperRole is Initializable, Context { using Roles for Roles.Role; event CapperAdded(address indexed account); @@ -19,7 +20,7 @@ contract CapperRole is Initializable { } modifier onlyCapper() { - require(isCapper(msg.sender)); + require(isCapper(_msgSender()), "CapperRole: caller does not have the Capper role"); _; } @@ -32,7 +33,7 @@ contract CapperRole is Initializable { } function renounceCapper() public { - _removeCapper(msg.sender); + _removeCapper(_msgSender()); } function _addCapper(address account) internal { diff --git a/contracts/access/roles/MinterRole.sol b/contracts/access/roles/MinterRole.sol index 9feaa7db9..11c8f4af6 100644 --- a/contracts/access/roles/MinterRole.sol +++ b/contracts/access/roles/MinterRole.sol @@ -1,10 +1,11 @@ pragma solidity ^0.5.2; import "@openzeppelin/upgrades/contracts/Initializable.sol"; + +import "../../GSN/Context.sol"; import "../Roles.sol"; - -contract MinterRole is Initializable { +contract MinterRole is Initializable, Context { using Roles for Roles.Role; event MinterAdded(address indexed account); @@ -19,7 +20,7 @@ contract MinterRole is Initializable { } modifier onlyMinter() { - require(isMinter(msg.sender)); + require(isMinter(_msgSender()), "MinterRole: caller does not have the Minter role"); _; } @@ -32,7 +33,7 @@ contract MinterRole is Initializable { } function renounceMinter() public { - _removeMinter(msg.sender); + _removeMinter(_msgSender()); } function _addMinter(address account) internal { diff --git a/contracts/access/roles/PauserRole.sol b/contracts/access/roles/PauserRole.sol index d40835ebf..edc40aa6e 100644 --- a/contracts/access/roles/PauserRole.sol +++ b/contracts/access/roles/PauserRole.sol @@ -1,10 +1,11 @@ pragma solidity ^0.5.2; import "@openzeppelin/upgrades/contracts/Initializable.sol"; + +import "../../GSN/Context.sol"; import "../Roles.sol"; - -contract PauserRole is Initializable { +contract PauserRole is Initializable, Context { using Roles for Roles.Role; event PauserAdded(address indexed account); @@ -19,7 +20,7 @@ contract PauserRole is Initializable { } modifier onlyPauser() { - require(isPauser(msg.sender)); + require(isPauser(_msgSender()), "PauserRole: caller does not have the Pauser role"); _; } @@ -32,7 +33,7 @@ contract PauserRole is Initializable { } function renouncePauser() public { - _removePauser(msg.sender); + _removePauser(_msgSender()); } function _addPauser(address account) internal { diff --git a/contracts/access/roles/SignerRole.sol b/contracts/access/roles/SignerRole.sol index cc60b3540..9a8538459 100644 --- a/contracts/access/roles/SignerRole.sol +++ b/contracts/access/roles/SignerRole.sol @@ -1,10 +1,11 @@ pragma solidity ^0.5.2; import "@openzeppelin/upgrades/contracts/Initializable.sol"; + +import "../../GSN/Context.sol"; import "../Roles.sol"; - -contract SignerRole is Initializable { +contract SignerRole is Initializable, Context { using Roles for Roles.Role; event SignerAdded(address indexed account); @@ -19,7 +20,7 @@ contract SignerRole is Initializable { } modifier onlySigner() { - require(isSigner(msg.sender)); + require(isSigner(_msgSender()), "SignerRole: caller does not have the Signer role"); _; } @@ -32,7 +33,7 @@ contract SignerRole is Initializable { } function renounceSigner() public { - _removeSigner(msg.sender); + _removeSigner(_msgSender()); } function _addSigner(address account) internal { diff --git a/contracts/access/roles/WhitelistAdminRole.sol b/contracts/access/roles/WhitelistAdminRole.sol index 04b899e82..4450da350 100644 --- a/contracts/access/roles/WhitelistAdminRole.sol +++ b/contracts/access/roles/WhitelistAdminRole.sol @@ -2,13 +2,14 @@ pragma solidity ^0.5.2; import "@openzeppelin/upgrades/contracts/Initializable.sol"; +import "../../GSN/Context.sol"; import "../Roles.sol"; /** * @title WhitelistAdminRole * @dev WhitelistAdmins are responsible for assigning and removing Whitelisted accounts. */ -contract WhitelistAdminRole is Initializable { +contract WhitelistAdminRole is Initializable, Context { using Roles for Roles.Role; event WhitelistAdminAdded(address indexed account); @@ -23,7 +24,7 @@ contract WhitelistAdminRole is Initializable { } modifier onlyWhitelistAdmin() { - require(isWhitelistAdmin(msg.sender)); + require(isWhitelistAdmin(_msgSender()), "WhitelistAdminRole: caller does not have the WhitelistAdmin role"); _; } @@ -36,7 +37,7 @@ contract WhitelistAdminRole is Initializable { } function renounceWhitelistAdmin() public { - _removeWhitelistAdmin(msg.sender); + _removeWhitelistAdmin(_msgSender()); } function _addWhitelistAdmin(address account) internal { diff --git a/contracts/access/roles/WhitelistedRole.sol b/contracts/access/roles/WhitelistedRole.sol index 8ccf2cf59..2cd2f2fa6 100644 --- a/contracts/access/roles/WhitelistedRole.sol +++ b/contracts/access/roles/WhitelistedRole.sol @@ -2,6 +2,7 @@ pragma solidity ^0.5.2; import "@openzeppelin/upgrades/contracts/Initializable.sol"; +import "../../GSN/Context.sol"; import "../Roles.sol"; import "./WhitelistAdminRole.sol"; @@ -11,7 +12,7 @@ import "./WhitelistAdminRole.sol"; * crowdsale). This role is special in that the only accounts that can add it are WhitelistAdmins (who can also remove * it), and not Whitelisteds themselves. */ -contract WhitelistedRole is Initializable, WhitelistAdminRole { +contract WhitelistedRole is Initializable, Context, WhitelistAdminRole { using Roles for Roles.Role; event WhitelistedAdded(address indexed account); @@ -20,7 +21,7 @@ contract WhitelistedRole is Initializable, WhitelistAdminRole { Roles.Role private _whitelisteds; modifier onlyWhitelisted() { - require(isWhitelisted(msg.sender)); + require(isWhitelisted(_msgSender()), "WhitelistedRole: caller does not have the Whitelisted role"); _; } @@ -41,7 +42,7 @@ contract WhitelistedRole is Initializable, WhitelistAdminRole { } function renounceWhitelisted() public { - _removeWhitelisted(msg.sender); + _removeWhitelisted(_msgSender()); } function _addWhitelisted(address account) internal { diff --git a/contracts/crowdsale/Crowdsale.sol b/contracts/crowdsale/Crowdsale.sol index b4daab607..58483528b 100644 --- a/contracts/crowdsale/Crowdsale.sol +++ b/contracts/crowdsale/Crowdsale.sol @@ -1,6 +1,8 @@ pragma solidity ^0.5.2; import "@openzeppelin/upgrades/contracts/Initializable.sol"; + +import "../GSN/Context.sol"; import "../token/ERC20/IERC20.sol"; import "../math/SafeMath.sol"; import "../token/ERC20/SafeERC20.sol"; @@ -18,7 +20,7 @@ import "../utils/ReentrancyGuard.sol"; * the methods to add functionality. Consider using 'super' where appropriate to concatenate * behavior. */ -contract Crowdsale is Initializable, ReentrancyGuard { +contract Crowdsale is Initializable, Context, ReentrancyGuard { using SafeMath for uint256; using SafeERC20 for IERC20; @@ -71,7 +73,7 @@ contract Crowdsale is Initializable, ReentrancyGuard { * buyTokens directly when purchasing tokens from a contract. */ function () external payable { - buyTokens(msg.sender); + buyTokens(_msgSender()); } /** @@ -119,7 +121,7 @@ contract Crowdsale is Initializable, ReentrancyGuard { _weiRaised = _weiRaised.add(weiAmount); _processPurchase(beneficiary, tokens); - emit TokensPurchased(msg.sender, beneficiary, weiAmount, tokens); + emit TokensPurchased(_msgSender(), beneficiary, weiAmount, tokens); _updatePurchasingState(beneficiary, weiAmount); diff --git a/contracts/crowdsale/distribution/RefundableCrowdsale.sol b/contracts/crowdsale/distribution/RefundableCrowdsale.sol index 1de66ff81..e539abce9 100644 --- a/contracts/crowdsale/distribution/RefundableCrowdsale.sol +++ b/contracts/crowdsale/distribution/RefundableCrowdsale.sol @@ -1,6 +1,8 @@ pragma solidity ^0.5.2; import "@openzeppelin/upgrades/contracts/Initializable.sol"; + +import "../../GSN/Context.sol"; import "../../math/SafeMath.sol"; import "./FinalizableCrowdsale.sol"; import "../../payment/escrow/RefundEscrow.sol"; @@ -15,7 +17,7 @@ import "../../payment/escrow/RefundEscrow.sol"; * the goal is unlikely to be met, they sell their tokens (possibly at a discount). The attacker will be refunded when * the crowdsale is finalized, and the users that purchased from them will be left with worthless tokens. */ -contract RefundableCrowdsale is Initializable, FinalizableCrowdsale { +contract RefundableCrowdsale is Initializable, Context, FinalizableCrowdsale { using SafeMath for uint256; // minimum amount of funds to be raised in weis @@ -85,7 +87,7 @@ contract RefundableCrowdsale is Initializable, FinalizableCrowdsale { * @dev Overrides Crowdsale fund forwarding, sending funds to escrow. */ function _forwardFunds() internal { - _escrow.deposit.value(msg.value)(msg.sender); + _escrow.deposit.value(msg.value)(_msgSender()); } uint256[50] private ______gap; diff --git a/contracts/drafts/SignatureBouncer.sol b/contracts/drafts/SignatureBouncer.sol index 73b5fd6ee..0bade9f62 100644 --- a/contracts/drafts/SignatureBouncer.sol +++ b/contracts/drafts/SignatureBouncer.sol @@ -1,6 +1,8 @@ pragma solidity ^0.5.2; import "@openzeppelin/upgrades/contracts/Initializable.sol"; + +import "../GSN/Context.sol"; import "../access/roles/SignerRole.sol"; import "../cryptography/ECDSA.sol"; @@ -35,7 +37,7 @@ import "../cryptography/ECDSA.sol"; * the data in the signature much more complex. * See https://ethereum.stackexchange.com/a/50616 for more details. */ -contract SignatureBouncer is Initializable, SignerRole { +contract SignatureBouncer is Initializable, Context, SignerRole { using ECDSA for bytes32; // Function selectors are 4 bytes long, as documented in @@ -52,7 +54,7 @@ contract SignatureBouncer is Initializable, SignerRole { * @dev requires that a valid signature of a signer was provided */ modifier onlyValidSignature(bytes memory signature) { - require(_isValidSignature(msg.sender, signature)); + require(_isValidSignature(_msgSender(), signature), "SignatureBouncer: invalid signature for caller"); _; } @@ -60,7 +62,8 @@ contract SignatureBouncer is Initializable, SignerRole { * @dev requires that a valid signature with a specified method of a signer was provided */ modifier onlyValidSignatureAndMethod(bytes memory signature) { - require(_isValidSignatureAndMethod(msg.sender, signature)); + // solhint-disable-next-line max-line-length + require(_isValidSignatureAndMethod(_msgSender(), signature), "SignatureBouncer: invalid signature for caller and method"); _; } @@ -68,7 +71,8 @@ contract SignatureBouncer is Initializable, SignerRole { * @dev requires that a valid signature with a specified method and params of a signer was provided */ modifier onlyValidSignatureAndData(bytes memory signature) { - require(_isValidSignatureAndData(msg.sender, signature)); + // solhint-disable-next-line max-line-length + require(_isValidSignatureAndData(_msgSender(), signature), "SignatureBouncer: invalid signature for caller and data"); _; } @@ -85,9 +89,10 @@ contract SignatureBouncer is Initializable, SignerRole { * @return bool */ function _isValidSignatureAndMethod(address account, bytes memory signature) internal view returns (bool) { + bytes memory msgData = _msgData(); bytes memory data = new bytes(_METHOD_ID_SIZE); - for (uint i = 0; i < data.length; i++) { - data[i] = msg.data[i]; + for (uint256 i = 0; i < data.length; i++) { + data[i] = msgData[i]; } return _isValidDataHash(keccak256(abi.encodePacked(address(this), account, data)), signature); } @@ -98,11 +103,12 @@ contract SignatureBouncer is Initializable, SignerRole { * @return bool */ function _isValidSignatureAndData(address account, bytes memory signature) internal view returns (bool) { - require(msg.data.length > _SIGNATURE_SIZE); + bytes memory msgData = _msgData(); + require(msgData.length > _SIGNATURE_SIZE, "SignatureBouncer: data is too short"); - bytes memory data = new bytes(msg.data.length - _SIGNATURE_SIZE); - for (uint i = 0; i < data.length; i++) { - data[i] = msg.data[i]; + bytes memory data = new bytes(msgData.length - _SIGNATURE_SIZE); + for (uint256 i = 0; i < data.length; i++) { + data[i] = msgData[i]; } return _isValidDataHash(keccak256(abi.encodePacked(address(this), account, data)), signature); diff --git a/contracts/examples/SimpleToken.sol b/contracts/examples/SimpleToken.sol index 93583494c..cc0ae00ff 100644 --- a/contracts/examples/SimpleToken.sol +++ b/contracts/examples/SimpleToken.sol @@ -1,6 +1,8 @@ pragma solidity ^0.5.2; import "@openzeppelin/upgrades/contracts/Initializable.sol"; + +import "../GSN/Context.sol"; import "../token/ERC20/ERC20.sol"; import "../token/ERC20/ERC20Detailed.sol"; @@ -10,16 +12,14 @@ import "../token/ERC20/ERC20Detailed.sol"; * Note they can later distribute these tokens as they wish using `transfer` and other * `ERC20` functions. */ -contract SimpleToken is Initializable, ERC20, ERC20Detailed { - uint8 public constant DECIMALS = 18; - uint256 public constant INITIAL_SUPPLY = 10000 * (10 ** uint256(DECIMALS)); +contract SimpleToken is Initializable, Context, ERC20, ERC20Detailed { /** - * @dev Constructor that gives msg.sender all of existing tokens. + * @dev Constructor that gives _msgSender() all of existing tokens. */ function initialize(address sender) public initializer { - ERC20Detailed.initialize("SimpleToken", "SIM", DECIMALS); - _mint(sender, INITIAL_SUPPLY); + ERC20Detailed.initialize("SimpleToken", "SIM", 18); + _mint(sender, 10000 * (10 ** uint256(decimals()))); } uint256[50] private ______gap; diff --git a/contracts/lifecycle/Pausable.sol b/contracts/lifecycle/Pausable.sol index f4b5db465..14fb67130 100644 --- a/contracts/lifecycle/Pausable.sol +++ b/contracts/lifecycle/Pausable.sol @@ -1,13 +1,15 @@ pragma solidity ^0.5.2; import "@openzeppelin/upgrades/contracts/Initializable.sol"; + +import "../GSN/Context.sol"; import "../access/roles/PauserRole.sol"; /** * @title Pausable * @dev Base contract which allows children to implement an emergency stop mechanism. */ -contract Pausable is Initializable, PauserRole { +contract Pausable is Initializable, Context, PauserRole { event Paused(address account); event Unpaused(address account); @@ -47,7 +49,7 @@ contract Pausable is Initializable, PauserRole { */ function pause() public onlyPauser whenNotPaused { _paused = true; - emit Paused(msg.sender); + emit Paused(_msgSender()); } /** @@ -55,7 +57,7 @@ contract Pausable is Initializable, PauserRole { */ function unpause() public onlyPauser whenPaused { _paused = false; - emit Unpaused(msg.sender); + emit Unpaused(_msgSender()); } uint256[50] private ______gap; diff --git a/contracts/mocks/CapperRoleMock.sol b/contracts/mocks/CapperRoleMock.sol index 60f393872..9d97011df 100644 --- a/contracts/mocks/CapperRoleMock.sol +++ b/contracts/mocks/CapperRoleMock.sol @@ -4,7 +4,7 @@ import "../access/roles/CapperRole.sol"; contract CapperRoleMock is CapperRole { constructor() public { - CapperRole.initialize(msg.sender); + CapperRole.initialize(_msgSender()); } function removeCapper(address account) public { diff --git a/contracts/mocks/ConditionalEscrowMock.sol b/contracts/mocks/ConditionalEscrowMock.sol index bc168c90d..baf5de890 100644 --- a/contracts/mocks/ConditionalEscrowMock.sol +++ b/contracts/mocks/ConditionalEscrowMock.sol @@ -7,7 +7,7 @@ contract ConditionalEscrowMock is ConditionalEscrow { mapping(address => bool) private _allowed; constructor() public { - ConditionalEscrow.initialize(msg.sender); + ConditionalEscrow.initialize(_msgSender()); } function setAllowed(address payee, bool allowed) public { diff --git a/contracts/mocks/ERC20CappedMock.sol b/contracts/mocks/ERC20CappedMock.sol index 6be7f8834..2e764779b 100644 --- a/contracts/mocks/ERC20CappedMock.sol +++ b/contracts/mocks/ERC20CappedMock.sol @@ -7,7 +7,7 @@ import "./MinterRoleMock.sol"; contract ERC20CappedMock is ERC20Capped, MinterRoleMock { constructor(uint256 cap) public { - ERC20Capped.initialize(cap, msg.sender); + ERC20Capped.initialize(cap, _msgSender()); } } diff --git a/contracts/mocks/ERC20MintableMock.sol b/contracts/mocks/ERC20MintableMock.sol index c28264fbe..fa9cf710a 100644 --- a/contracts/mocks/ERC20MintableMock.sol +++ b/contracts/mocks/ERC20MintableMock.sol @@ -5,6 +5,6 @@ import "./MinterRoleMock.sol"; contract ERC20MintableMock is ERC20Mintable, MinterRoleMock { constructor() public { - ERC20Mintable.initialize(msg.sender); + ERC20Mintable.initialize(_msgSender()); } } diff --git a/contracts/mocks/ERC20PausableMock.sol b/contracts/mocks/ERC20PausableMock.sol index 1641618e3..022fdab4d 100644 --- a/contracts/mocks/ERC20PausableMock.sol +++ b/contracts/mocks/ERC20PausableMock.sol @@ -6,7 +6,7 @@ import "./PauserRoleMock.sol"; // mock class using ERC20Pausable contract ERC20PausableMock is ERC20Pausable, PauserRoleMock { constructor (address initialAccount, uint initialBalance) public { - ERC20Pausable.initialize(msg.sender); + ERC20Pausable.initialize(_msgSender()); _mint(initialAccount, initialBalance); } } diff --git a/contracts/mocks/ERC721FullMock.sol b/contracts/mocks/ERC721FullMock.sol index ddc223f0d..c008145c3 100644 --- a/contracts/mocks/ERC721FullMock.sol +++ b/contracts/mocks/ERC721FullMock.sol @@ -15,8 +15,8 @@ contract ERC721FullMock is ERC721Full, ERC721Mintable, ERC721MetadataMintable, E ERC721.initialize(); ERC721Metadata.initialize(name, symbol); ERC721Enumerable.initialize(); - ERC721Mintable.initialize(msg.sender); - ERC721MetadataMintable.initialize(msg.sender); + ERC721Mintable.initialize(_msgSender()); + ERC721MetadataMintable.initialize(_msgSender()); } function exists(uint256 tokenId) public view returns (bool) { diff --git a/contracts/mocks/ERC721GSNRecipientMock.sol b/contracts/mocks/ERC721GSNRecipientMock.sol new file mode 100644 index 000000000..d0a80934f --- /dev/null +++ b/contracts/mocks/ERC721GSNRecipientMock.sol @@ -0,0 +1,21 @@ +pragma solidity ^0.5.2; + +import "../token/ERC721/ERC721.sol"; +import "../GSN/GSNRecipient.sol"; +import "../GSN/bouncers/GSNBouncerSignature.sol"; + +/** + * @title ERC721GSNRecipientMock + * A simple ERC721 mock that has GSN support enabled + */ +contract ERC721GSNRecipientMock is ERC721, GSNRecipient, GSNBouncerSignature { + constructor(address trustedSigner) public { + ERC721.initialize(); + GSNRecipient.initialize(); + GSNBouncerSignature.initialize(trustedSigner); + } + + function mint(uint256 tokenId) public { + _mint(_msgSender(), tokenId); + } +} diff --git a/contracts/mocks/ERC721MintableBurnableImpl.sol b/contracts/mocks/ERC721MintableBurnableImpl.sol index 1e36ca9fe..13453e7e2 100644 --- a/contracts/mocks/ERC721MintableBurnableImpl.sol +++ b/contracts/mocks/ERC721MintableBurnableImpl.sol @@ -13,7 +13,7 @@ contract ERC721MintableBurnableImpl is ERC721Full, ERC721Mintable, ERC721Metadat ERC721.initialize(); ERC721Metadata.initialize("Test", "TEST"); ERC721Enumerable.initialize(); - ERC721Mintable.initialize(msg.sender); - ERC721MetadataMintable.initialize(msg.sender); + ERC721Mintable.initialize(_msgSender()); + ERC721MetadataMintable.initialize(_msgSender()); } } diff --git a/contracts/mocks/ERC721PausableMock.sol b/contracts/mocks/ERC721PausableMock.sol index dcdd9a115..215f3f7f8 100644 --- a/contracts/mocks/ERC721PausableMock.sol +++ b/contracts/mocks/ERC721PausableMock.sol @@ -10,7 +10,7 @@ import "./PauserRoleMock.sol"; contract ERC721PausableMock is ERC721Pausable, PauserRoleMock { constructor() public { ERC721.initialize(); - ERC721Pausable.initialize(msg.sender); + ERC721Pausable.initialize(_msgSender()); } function mint(address to, uint256 tokenId) public { diff --git a/contracts/mocks/EscrowMock.sol b/contracts/mocks/EscrowMock.sol index 20f33f985..59d76fff0 100644 --- a/contracts/mocks/EscrowMock.sol +++ b/contracts/mocks/EscrowMock.sol @@ -4,6 +4,6 @@ import "../payment/escrow/Escrow.sol"; contract EscrowMock is Escrow { constructor() public { - Escrow.initialize(msg.sender); + Escrow.initialize(_msgSender()); } } diff --git a/contracts/mocks/GSNBouncerERC20FeeMock.sol b/contracts/mocks/GSNBouncerERC20FeeMock.sol index c8ad04c50..932d51e92 100644 --- a/contracts/mocks/GSNBouncerERC20FeeMock.sol +++ b/contracts/mocks/GSNBouncerERC20FeeMock.sol @@ -6,8 +6,8 @@ import "../GSN/bouncers/GSNBouncerERC20Fee.sol"; contract GSNBouncerERC20FeeMock is GSNRecipient, GSNBouncerERC20Fee { constructor(string memory name, string memory symbol, uint8 decimals) public { - GSNBouncerERC20Fee.initialize(name, symbol, decimals); GSNRecipient.initialize(); + GSNBouncerERC20Fee.initialize(name, symbol, decimals); } function mint(address account, uint256 amount) public { diff --git a/contracts/mocks/GSNBouncerSignatureMock.sol b/contracts/mocks/GSNBouncerSignatureMock.sol index d92951b23..67bd5e50e 100644 --- a/contracts/mocks/GSNBouncerSignatureMock.sol +++ b/contracts/mocks/GSNBouncerSignatureMock.sol @@ -6,8 +6,8 @@ import "../GSN/bouncers/GSNBouncerSignature.sol"; contract GSNBouncerSignatureMock is GSNRecipient, GSNBouncerSignature { constructor(address trustedSigner) public { - GSNBouncerSignature.initialize(trustedSigner); GSNRecipient.initialize(); + GSNBouncerSignature.initialize(trustedSigner); } event MockFunctionCalled(); diff --git a/contracts/mocks/IndividuallyCappedCrowdsaleImpl.sol b/contracts/mocks/IndividuallyCappedCrowdsaleImpl.sol index f3e7d5563..a68024cf1 100644 --- a/contracts/mocks/IndividuallyCappedCrowdsaleImpl.sol +++ b/contracts/mocks/IndividuallyCappedCrowdsaleImpl.sol @@ -7,6 +7,6 @@ import "./CapperRoleMock.sol"; contract IndividuallyCappedCrowdsaleImpl is IndividuallyCappedCrowdsale, CapperRoleMock { constructor (uint256 rate, address payable wallet, IERC20 token) public { Crowdsale.initialize(rate, wallet, token); - IndividuallyCappedCrowdsale.initialize(msg.sender); + IndividuallyCappedCrowdsale.initialize(_msgSender()); } } diff --git a/contracts/mocks/MinterRoleMock.sol b/contracts/mocks/MinterRoleMock.sol index 7588a6649..ed5054691 100644 --- a/contracts/mocks/MinterRoleMock.sol +++ b/contracts/mocks/MinterRoleMock.sol @@ -4,7 +4,7 @@ import "../access/roles/MinterRole.sol"; contract MinterRoleMock is MinterRole { constructor() public { - MinterRole.initialize(msg.sender); + MinterRole.initialize(_msgSender()); } function removeMinter(address account) public { diff --git a/contracts/mocks/OwnableMock.sol b/contracts/mocks/OwnableMock.sol index 8d10a941c..7f7641293 100644 --- a/contracts/mocks/OwnableMock.sol +++ b/contracts/mocks/OwnableMock.sol @@ -4,6 +4,6 @@ import "../ownership/Ownable.sol"; contract OwnableMock is Ownable { constructor() public { - Ownable.initialize(msg.sender); + Ownable.initialize(_msgSender()); } } diff --git a/contracts/mocks/PausableCrowdsaleImpl.sol b/contracts/mocks/PausableCrowdsaleImpl.sol index c69b80c1b..55ef68b7b 100644 --- a/contracts/mocks/PausableCrowdsaleImpl.sol +++ b/contracts/mocks/PausableCrowdsaleImpl.sol @@ -6,6 +6,6 @@ import "../crowdsale/validation/PausableCrowdsale.sol"; contract PausableCrowdsaleImpl is PausableCrowdsale { constructor (uint256 _rate, address payable _wallet, ERC20 _token) public { Crowdsale.initialize(_rate, _wallet, _token); - PausableCrowdsale.initialize(msg.sender); + PausableCrowdsale.initialize(_msgSender()); } } diff --git a/contracts/mocks/PausableMock.sol b/contracts/mocks/PausableMock.sol index 31b0858d1..8f3817446 100644 --- a/contracts/mocks/PausableMock.sol +++ b/contracts/mocks/PausableMock.sol @@ -9,7 +9,7 @@ contract PausableMock is Pausable, PauserRoleMock { uint256 public count; constructor () public { - Pausable.initialize(msg.sender); + Pausable.initialize(_msgSender()); drasticMeasureTaken = false; count = 0; diff --git a/contracts/mocks/PauserRoleMock.sol b/contracts/mocks/PauserRoleMock.sol index ace7bd701..56397abf4 100644 --- a/contracts/mocks/PauserRoleMock.sol +++ b/contracts/mocks/PauserRoleMock.sol @@ -4,7 +4,7 @@ import "../access/roles/PauserRole.sol"; contract PauserRoleMock is PauserRole { constructor () public { - PauserRole.initialize(msg.sender); + PauserRole.initialize(_msgSender()); } function removePauser(address account) public { diff --git a/contracts/mocks/ReentrancyAttack.sol b/contracts/mocks/ReentrancyAttack.sol index 7f7fd35d4..e1a197489 100644 --- a/contracts/mocks/ReentrancyAttack.sol +++ b/contracts/mocks/ReentrancyAttack.sol @@ -1,9 +1,10 @@ pragma solidity ^0.5.2; -contract ReentrancyAttack { +import "../GSN/Context.sol"; +contract ReentrancyAttack is Context { function callSender(bytes4 data) public { // solhint-disable-next-line avoid-low-level-calls - (bool success,) = msg.sender.call(abi.encodeWithSelector(data)); - require(success); + (bool success,) = _msgSender().call(abi.encodeWithSelector(data)); + require(success, "ReentrancyAttack: failed call"); } } diff --git a/contracts/mocks/RefundEscrowMock.sol b/contracts/mocks/RefundEscrowMock.sol index 213c18af2..bfd546f9b 100644 --- a/contracts/mocks/RefundEscrowMock.sol +++ b/contracts/mocks/RefundEscrowMock.sol @@ -4,6 +4,6 @@ import "../payment/escrow/RefundEscrow.sol"; contract RefundEscrowMock is RefundEscrow { constructor(address payable beneficiary) public { - RefundEscrow.initialize(beneficiary, msg.sender); + RefundEscrow.initialize(beneficiary, _msgSender()); } } diff --git a/contracts/mocks/SafeERC20Helper.sol b/contracts/mocks/SafeERC20Helper.sol index b69d98b52..8a8f1b9db 100644 --- a/contracts/mocks/SafeERC20Helper.sol +++ b/contracts/mocks/SafeERC20Helper.sol @@ -1,9 +1,10 @@ pragma solidity ^0.5.2; +import "../GSN/Context.sol"; import "../token/ERC20/IERC20.sol"; import "../token/ERC20/SafeERC20.sol"; -contract ERC20ReturnFalseMock { +contract ERC20ReturnFalseMock is Context { uint256 private _allowance; // IERC20's functions are not pure, but these mock implementations are: to prevent Solidity from issuing warnings, @@ -31,7 +32,7 @@ contract ERC20ReturnFalseMock { } } -contract ERC20ReturnTrueMock { +contract ERC20ReturnTrueMock is Context { mapping (address => uint256) private _allowances; // IERC20's functions are not pure, but these mock implementations are: to prevent Solidity from issuing warnings, @@ -54,7 +55,7 @@ contract ERC20ReturnTrueMock { } function setAllowance(uint256 allowance_) public { - _allowances[msg.sender] = allowance_; + _allowances[_msgSender()] = allowance_; } function allowance(address owner, address) public view returns (uint256) { @@ -62,7 +63,7 @@ contract ERC20ReturnTrueMock { } } -contract ERC20NoReturnMock { +contract ERC20NoReturnMock is Context { mapping (address => uint256) private _allowances; // IERC20's functions are not pure, but these mock implementations are: to prevent Solidity from issuing warnings, @@ -82,7 +83,7 @@ contract ERC20NoReturnMock { } function setAllowance(uint256 allowance_) public { - _allowances[msg.sender] = allowance_; + _allowances[_msgSender()] = allowance_; } function allowance(address owner, address) public view returns (uint256) { @@ -90,7 +91,7 @@ contract ERC20NoReturnMock { } } -contract SafeERC20Wrapper { +contract SafeERC20Wrapper is Context { using SafeERC20 for IERC20; IERC20 private _token; diff --git a/contracts/mocks/SampleCrowdsaleMock.sol b/contracts/mocks/SampleCrowdsaleMock.sol index 7f5143785..883bdc88e 100644 --- a/contracts/mocks/SampleCrowdsaleMock.sol +++ b/contracts/mocks/SampleCrowdsaleMock.sol @@ -5,7 +5,7 @@ import "../examples/SampleCrowdsale.sol"; contract SampleCrowdsaleTokenMock is SampleCrowdsaleToken { constructor() public { - SampleCrowdsaleToken.initialize(msg.sender); + SampleCrowdsaleToken.initialize(_msgSender()); } } diff --git a/contracts/mocks/SecondaryMock.sol b/contracts/mocks/SecondaryMock.sol index f6e2ba5b8..2d76b3ed6 100644 --- a/contracts/mocks/SecondaryMock.sol +++ b/contracts/mocks/SecondaryMock.sol @@ -4,7 +4,7 @@ import "../ownership/Secondary.sol"; contract SecondaryMock is Secondary { constructor() public { - Secondary.initialize(msg.sender); + Secondary.initialize(_msgSender()); } function onlyPrimaryMock() public view onlyPrimary { diff --git a/contracts/mocks/SignatureBouncerMock.sol b/contracts/mocks/SignatureBouncerMock.sol index 9d96e3f26..a924ed3cc 100644 --- a/contracts/mocks/SignatureBouncerMock.sol +++ b/contracts/mocks/SignatureBouncerMock.sol @@ -5,7 +5,7 @@ import "./SignerRoleMock.sol"; contract SignatureBouncerMock is SignatureBouncer, SignerRoleMock { constructor() public { - SignatureBouncer.initialize(msg.sender); + SignatureBouncer.initialize(_msgSender()); } function checkValidSignature(address account, bytes memory signature) diff --git a/contracts/mocks/SignerRoleMock.sol b/contracts/mocks/SignerRoleMock.sol index 2160a8fd8..81d0e0f17 100644 --- a/contracts/mocks/SignerRoleMock.sol +++ b/contracts/mocks/SignerRoleMock.sol @@ -4,7 +4,7 @@ import "../access/roles/SignerRole.sol"; contract SignerRoleMock is SignerRole { constructor() public { - SignerRole.initialize(msg.sender); + SignerRole.initialize(_msgSender()); } function removeSigner(address account) public { diff --git a/contracts/mocks/SimpleTokenMock.sol b/contracts/mocks/SimpleTokenMock.sol index 11add07cd..d6b24662e 100644 --- a/contracts/mocks/SimpleTokenMock.sol +++ b/contracts/mocks/SimpleTokenMock.sol @@ -4,6 +4,6 @@ import "../examples/SimpleToken.sol"; contract SimpleTokenMock is SimpleToken { constructor() public { - SimpleToken.initialize(msg.sender); + SimpleToken.initialize(_msgSender()); } } diff --git a/contracts/mocks/TokenVestingMock.sol b/contracts/mocks/TokenVestingMock.sol index cab7fbed8..2f66d75fb 100644 --- a/contracts/mocks/TokenVestingMock.sol +++ b/contracts/mocks/TokenVestingMock.sol @@ -16,7 +16,7 @@ contract TokenVestingMock is TokenVesting { cliffDuration, duration, revocable, - msg.sender + _msgSender() ); } } diff --git a/contracts/mocks/WhitelistAdminRoleMock.sol b/contracts/mocks/WhitelistAdminRoleMock.sol index b2b8f5ebc..77c94772e 100644 --- a/contracts/mocks/WhitelistAdminRoleMock.sol +++ b/contracts/mocks/WhitelistAdminRoleMock.sol @@ -4,7 +4,7 @@ import "../access/roles/WhitelistAdminRole.sol"; contract WhitelistAdminRoleMock is WhitelistAdminRole { constructor () public { - WhitelistAdminRole.initialize(msg.sender); + WhitelistAdminRole.initialize(_msgSender()); } function removeWhitelistAdmin(address account) public { diff --git a/contracts/mocks/WhitelistCrowdsaleImpl.sol b/contracts/mocks/WhitelistCrowdsaleImpl.sol index 52061a432..54962ada6 100644 --- a/contracts/mocks/WhitelistCrowdsaleImpl.sol +++ b/contracts/mocks/WhitelistCrowdsaleImpl.sol @@ -4,10 +4,9 @@ import "../token/ERC20/IERC20.sol"; import "../crowdsale/validation/WhitelistCrowdsale.sol"; import "../crowdsale/Crowdsale.sol"; - contract WhitelistCrowdsaleImpl is Crowdsale, WhitelistCrowdsale { constructor (uint256 _rate, address payable _wallet, IERC20 _token) public { Crowdsale.initialize(_rate, _wallet, _token); - WhitelistCrowdsale.initialize(msg.sender); + WhitelistCrowdsale.initialize(_msgSender()); } } diff --git a/contracts/mocks/WhitelistedRoleMock.sol b/contracts/mocks/WhitelistedRoleMock.sol index cb53679fc..9c270b739 100644 --- a/contracts/mocks/WhitelistedRoleMock.sol +++ b/contracts/mocks/WhitelistedRoleMock.sol @@ -4,7 +4,7 @@ import "../access/roles/WhitelistedRole.sol"; contract WhitelistedRoleMock is WhitelistedRole { constructor() public { - WhitelistedRole.initialize(msg.sender); + WhitelistedRole.initialize(_msgSender()); } function onlyWhitelistedMock() public view onlyWhitelisted { diff --git a/contracts/ownership/Ownable.sol b/contracts/ownership/Ownable.sol index 9c35a9c27..726476446 100644 --- a/contracts/ownership/Ownable.sol +++ b/contracts/ownership/Ownable.sol @@ -2,12 +2,14 @@ pragma solidity ^0.5.2; import "@openzeppelin/upgrades/contracts/Initializable.sol"; +import "../GSN/Context.sol"; + /** * @title Ownable * @dev The Ownable contract has an owner address, and provides basic authorization control * functions, this simplifies the implementation of "user permissions". */ -contract Ownable is Initializable { +contract Ownable is Initializable, Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); @@ -40,7 +42,7 @@ contract Ownable is Initializable { * @return true if `msg.sender` is the owner of the contract. */ function isOwner() public view returns (bool) { - return msg.sender == _owner; + return _msgSender() == _owner; } /** diff --git a/contracts/ownership/Secondary.sol b/contracts/ownership/Secondary.sol index 60109d821..fa271bf73 100644 --- a/contracts/ownership/Secondary.sol +++ b/contracts/ownership/Secondary.sol @@ -2,11 +2,13 @@ pragma solidity ^0.5.2; import "@openzeppelin/upgrades/contracts/Initializable.sol"; +import "../GSN/Context.sol"; + /** * @title Secondary * @dev A Secondary contract can only be used by its primary account (the one that created it) */ -contract Secondary is Initializable { +contract Secondary is Initializable, Context { address private _primary; event PrimaryTransferred( @@ -25,7 +27,7 @@ contract Secondary is Initializable { * @dev Reverts if called from any account other than the primary. */ modifier onlyPrimary() { - require(msg.sender == _primary); + require(_msgSender() == _primary, "Secondary: caller is not the primary account"); _; } diff --git a/contracts/payment/PaymentSplitter.sol b/contracts/payment/PaymentSplitter.sol index dc4fddd17..9d437e792 100644 --- a/contracts/payment/PaymentSplitter.sol +++ b/contracts/payment/PaymentSplitter.sol @@ -2,6 +2,7 @@ pragma solidity ^0.5.2; import "@openzeppelin/upgrades/contracts/Initializable.sol"; +import "../GSN/Context.sol"; import "../math/SafeMath.sol"; /** @@ -9,7 +10,7 @@ import "../math/SafeMath.sol"; * @dev This contract can be used when payments need to be received by a group * of people and split proportionately to some number of shares they own. */ -contract PaymentSplitter is Initializable { +contract PaymentSplitter is Initializable, Context { using SafeMath for uint256; event PayeeAdded(address account, uint256 shares); @@ -39,7 +40,7 @@ contract PaymentSplitter is Initializable { * @dev payable fallback */ function () external payable { - emit PaymentReceived(msg.sender, msg.value); + emit PaymentReceived(_msgSender(), msg.value); } /** diff --git a/contracts/token/ERC20/ERC20.sol b/contracts/token/ERC20/ERC20.sol index d1ff35cbe..bcdba1969 100644 --- a/contracts/token/ERC20/ERC20.sol +++ b/contracts/token/ERC20/ERC20.sol @@ -1,6 +1,8 @@ pragma solidity ^0.5.2; import "@openzeppelin/upgrades/contracts/Initializable.sol"; + +import "../../GSN/Context.sol"; import "./IERC20.sol"; import "../../math/SafeMath.sol"; @@ -16,12 +18,12 @@ import "../../math/SafeMath.sol"; * all accounts just by listening to said events. Note that this isn't required by the specification, and other * compliant implementations may not do it. */ -contract ERC20 is Initializable, IERC20 { +contract ERC20 is Initializable, Context, IERC20 { using SafeMath for uint256; mapping (address => uint256) private _balances; - mapping (address => mapping (address => uint256)) private _allowed; + mapping (address => mapping (address => uint256)) private _allowances; uint256 private _totalSupply; @@ -48,7 +50,7 @@ contract ERC20 is Initializable, IERC20 { * @return A uint256 specifying the amount of tokens still available for the spender. */ function allowance(address owner, address spender) public view returns (uint256) { - return _allowed[owner][spender]; + return _allowances[owner][spender]; } /** @@ -57,7 +59,7 @@ contract ERC20 is Initializable, IERC20 { * @param value The amount to be transferred. */ function transfer(address to, uint256 value) public returns (bool) { - _transfer(msg.sender, to, value); + _transfer(_msgSender(), to, value); return true; } @@ -71,7 +73,7 @@ contract ERC20 is Initializable, IERC20 { * @param value The amount of tokens to be spent. */ function approve(address spender, uint256 value) public returns (bool) { - _approve(msg.sender, spender, value); + _approve(_msgSender(), spender, value); return true; } @@ -85,13 +87,13 @@ contract ERC20 is Initializable, IERC20 { */ function transferFrom(address from, address to, uint256 value) public returns (bool) { _transfer(from, to, value); - _approve(from, msg.sender, _allowed[from][msg.sender].sub(value)); + _approve(from, _msgSender(), _allowances[from][_msgSender()].sub(value)); return true; } /** * @dev Increase the amount of tokens that an owner allowed to a spender. - * approve should be called when _allowed[msg.sender][spender] == 0. To increment + * approve should be called when _allowances[msg.sender][spender] == 0. To increment * allowed value is better to use this function to avoid 2 calls (and wait until * the first transaction is mined) * From MonolithDAO Token.sol @@ -100,13 +102,13 @@ contract ERC20 is Initializable, IERC20 { * @param addedValue The amount of tokens to increase the allowance by. */ function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { - _approve(msg.sender, spender, _allowed[msg.sender][spender].add(addedValue)); + _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); return true; } /** * @dev Decrease the amount of tokens that an owner allowed to a spender. - * approve should be called when _allowed[msg.sender][spender] == 0. To decrement + * approve should be called when _allowances[msg.sender][spender] == 0. To decrement * allowed value is better to use this function to avoid 2 calls (and wait until * the first transaction is mined) * From MonolithDAO Token.sol @@ -115,7 +117,7 @@ contract ERC20 is Initializable, IERC20 { * @param subtractedValue The amount of tokens to decrease the allowance by. */ function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { - _approve(msg.sender, spender, _allowed[msg.sender][spender].sub(subtractedValue)); + _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue)); return true; } @@ -172,7 +174,7 @@ contract ERC20 is Initializable, IERC20 { require(spender != address(0)); require(owner != address(0)); - _allowed[owner][spender] = value; + _allowances[owner][spender] = value; emit Approval(owner, spender, value); } @@ -182,11 +184,11 @@ contract ERC20 is Initializable, IERC20 { * internal burn function. * Emits an Approval event (reflecting the reduced allowance). * @param account The account whose tokens will be burnt. - * @param value The amount that will be burnt. + * @param amount The amount that will be burnt. */ - function _burnFrom(address account, uint256 value) internal { - _burn(account, value); - _approve(account, msg.sender, _allowed[account][msg.sender].sub(value)); + function _burnFrom(address account, uint256 amount) internal { + _burn(account, amount); + _approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount)); } uint256[50] private ______gap; diff --git a/contracts/token/ERC20/ERC20Burnable.sol b/contracts/token/ERC20/ERC20Burnable.sol index af45b1a94..797d28fc0 100644 --- a/contracts/token/ERC20/ERC20Burnable.sol +++ b/contracts/token/ERC20/ERC20Burnable.sol @@ -1,19 +1,21 @@ pragma solidity ^0.5.2; import "@openzeppelin/upgrades/contracts/Initializable.sol"; + +import "../../GSN/Context.sol"; import "./ERC20.sol"; /** * @title Burnable Token * @dev Token that can be irreversibly burned (destroyed). */ -contract ERC20Burnable is Initializable, ERC20 { +contract ERC20Burnable is Initializable, Context, ERC20 { /** * @dev Burns a specific amount of tokens. - * @param value The amount of token to be burned. + * @param amount The amount of token to be burned. */ - function burn(uint256 value) public { - _burn(msg.sender, value); + function burn(uint256 amount) public { + _burn(_msgSender(), amount); } /** diff --git a/contracts/token/ERC721/ERC721.sol b/contracts/token/ERC721/ERC721.sol index d82900e7a..bcf1e86b5 100644 --- a/contracts/token/ERC721/ERC721.sol +++ b/contracts/token/ERC721/ERC721.sol @@ -1,6 +1,8 @@ pragma solidity ^0.5.2; import "@openzeppelin/upgrades/contracts/Initializable.sol"; + +import "../../GSN/Context.sol"; import "./IERC721.sol"; import "./IERC721Receiver.sol"; import "../../math/SafeMath.sol"; @@ -12,7 +14,7 @@ import "../../introspection/ERC165.sol"; * @title ERC721 Non-Fungible Token Standard basic implementation * @dev see https://eips.ethereum.org/EIPS/eip-721 */ -contract ERC721 is Initializable, ERC165, IERC721 { +contract ERC721 is Initializable, Context, ERC165, IERC721 { using SafeMath for uint256; using Address for address; using Counters for Counters.Counter; @@ -89,8 +91,11 @@ contract ERC721 is Initializable, ERC165, IERC721 { */ function approve(address to, uint256 tokenId) public { address owner = ownerOf(tokenId); - require(to != owner); - require(msg.sender == owner || isApprovedForAll(owner, msg.sender)); + require(to != owner, "ERC721: approval to current owner"); + + require(_msgSender() == owner || isApprovedForAll(owner, _msgSender()), + "ERC721: approve caller is not owner nor approved for all" + ); _tokenApprovals[tokenId] = to; emit Approval(owner, to, tokenId); @@ -114,9 +119,10 @@ contract ERC721 is Initializable, ERC165, IERC721 { * @param approved representing the status of the approval to be set */ function setApprovalForAll(address to, bool approved) public { - require(to != msg.sender); - _operatorApprovals[msg.sender][to] = approved; - emit ApprovalForAll(msg.sender, to, approved); + require(to != _msgSender(), "ERC721: approve to caller"); + + _operatorApprovals[_msgSender()][to] = approved; + emit ApprovalForAll(_msgSender(), to, approved); } /** @@ -138,7 +144,8 @@ contract ERC721 is Initializable, ERC165, IERC721 { * @param tokenId uint256 ID of the token to be transferred */ function transferFrom(address from, address to, uint256 tokenId) public { - require(_isApprovedOrOwner(msg.sender, tokenId)); + //solhint-disable-next-line max-line-length + require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); _transferFrom(from, to, tokenId); } @@ -164,7 +171,7 @@ contract ERC721 is Initializable, ERC165, IERC721 { * which is called upon a safe transfer, and return the magic value * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise, * the transfer is reverted. - * Requires the msg.sender to be the owner, approved, or operator + * Requires the _msgSender() to be the owner, approved, or operator * @param from current owner of the token * @param to address to receive the ownership of the given token ID * @param tokenId uint256 ID of the token to be transferred @@ -277,7 +284,7 @@ contract ERC721 is Initializable, ERC165, IERC721 { return true; } - bytes4 retval = IERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, _data); + bytes4 retval = IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data); return (retval == _ERC721_RECEIVED); } diff --git a/contracts/token/ERC721/ERC721Burnable.sol b/contracts/token/ERC721/ERC721Burnable.sol index 84c8a8e49..77aece497 100644 --- a/contracts/token/ERC721/ERC721Burnable.sol +++ b/contracts/token/ERC721/ERC721Burnable.sol @@ -1,19 +1,22 @@ pragma solidity ^0.5.2; import "@openzeppelin/upgrades/contracts/Initializable.sol"; + +import "../../GSN/Context.sol"; import "./ERC721.sol"; /** * @title ERC721 Burnable Token * @dev ERC721 Token that can be irreversibly burned (destroyed). */ -contract ERC721Burnable is Initializable, ERC721 { +contract ERC721Burnable is Initializable, Context, ERC721 { /** * @dev Burns a specific ERC721 token. * @param tokenId uint256 id of the ERC721 token to be burned. */ function burn(uint256 tokenId) public { - require(_isApprovedOrOwner(msg.sender, tokenId)); + //solhint-disable-next-line max-line-length + require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721Burnable: caller is not owner nor approved"); _burn(tokenId); } diff --git a/contracts/token/ERC721/ERC721Enumerable.sol b/contracts/token/ERC721/ERC721Enumerable.sol index 298175cbb..cf9455b49 100644 --- a/contracts/token/ERC721/ERC721Enumerable.sol +++ b/contracts/token/ERC721/ERC721Enumerable.sol @@ -1,6 +1,8 @@ pragma solidity ^0.5.2; import "@openzeppelin/upgrades/contracts/Initializable.sol"; + +import "../../GSN/Context.sol"; import "./IERC721Enumerable.sol"; import "./ERC721.sol"; import "../../introspection/ERC165.sol"; @@ -9,7 +11,7 @@ import "../../introspection/ERC165.sol"; * @title ERC-721 Non-Fungible Token with optional enumeration extension logic * @dev See https://eips.ethereum.org/EIPS/eip-721 */ -contract ERC721Enumerable is Initializable, ERC165, ERC721, IERC721Enumerable { +contract ERC721Enumerable is Initializable, Context, ERC165, ERC721, IERC721Enumerable { // Mapping from owner to list of owned token IDs mapping(address => uint256[]) private _ownedTokens; diff --git a/contracts/token/ERC721/ERC721Metadata.sol b/contracts/token/ERC721/ERC721Metadata.sol index 9219d3a7b..f0d915f72 100644 --- a/contracts/token/ERC721/ERC721Metadata.sol +++ b/contracts/token/ERC721/ERC721Metadata.sol @@ -1,11 +1,13 @@ pragma solidity ^0.5.2; import "@openzeppelin/upgrades/contracts/Initializable.sol"; + +import "../../GSN/Context.sol"; import "./ERC721.sol"; import "./IERC721Metadata.sol"; import "../../introspection/ERC165.sol"; -contract ERC721Metadata is Initializable, ERC165, ERC721, IERC721Metadata { +contract ERC721Metadata is Initializable, Context, ERC165, ERC721, IERC721Metadata { // Token name string private _name; diff --git a/package-lock.json b/package-lock.json index 29ffd6fe8..dc20c1b65 100644 --- a/package-lock.json +++ b/package-lock.json @@ -482,13 +482,15 @@ "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", "dev": true }, - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "eth-lib": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.7.tgz", + "integrity": "sha1-L5Pxex4jrsN1nNSj/iDBKGo/wco=", "dev": true, "requires": { - "ms": "2.0.0" + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "xhr-request-promise": "^0.1.2" } }, "ethers": { @@ -520,12 +522,6 @@ "hash.js": "^1.0.0", "inherits": "^2.0.1" } - }, - "setimmediate": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.4.tgz", - "integrity": "sha1-IOgd5iLUoCWIzgyNqJc8vPHTE48=", - "dev": true } } }, @@ -535,15 +531,6 @@ "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==", "dev": true }, - "follow-redirects": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", - "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", - "dev": true, - "requires": { - "debug": "=3.1.0" - } - }, "fs-extra": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", @@ -575,6 +562,12 @@ "integrity": "sha512-b9usnbDGnD928gJB3LrCmxoibr3VE4U2SMo5PBuBnokWyDADTqDPXg4YpwKF1trpH+UbGp7QLicO3+aWEy0+mw==", "dev": true }, + "js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc=", + "dev": true + }, "jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", @@ -644,12 +637,6 @@ "integrity": "sha512-jdFC1VdUGT/2Scgbimf7FSx9iJLXoqfglSF+gJeuNWVpiE37OIbc1jywR/GJyFdz3mnkz2/id0L0J/cr0izR5A==", "dev": true }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", - "dev": true - }, "swarm-js": { "version": "0.1.39", "resolved": "https://registry.npmjs.org/swarm-js/-/swarm-js-0.1.39.tgz", @@ -670,6 +657,21 @@ "xhr-request-promise": "^0.1.2" }, "dependencies": { + "eth-lib": { + "version": "0.1.27", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.1.27.tgz", + "integrity": "sha512-B8czsfkJYzn2UIEMwjc7Mbj+Cy72V+/OXH/tb44LV8jhrjizQJJ325xMOMyk3+ETa6r6oi0jsUY14+om8mQMWA==", + "dev": true, + "requires": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "keccakjs": "^0.2.1", + "nano-json-stream-parser": "^0.1.2", + "servify": "^0.1.12", + "ws": "^3.0.0", + "xhr-request-promise": "^0.1.2" + } + }, "fs-extra": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", @@ -702,6 +704,12 @@ "url-parse-lax": "^1.0.0", "url-to-options": "^1.0.1" } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true } } }, @@ -888,17 +896,6 @@ "web3-utils": "1.2.1" }, "dependencies": { - "eth-lib": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.7.tgz", - "integrity": "sha1-L5Pxex4jrsN1nNSj/iDBKGo/wco=", - "dev": true, - "requires": { - "bn.js": "^4.11.6", - "elliptic": "^6.4.0", - "xhr-request-promise": "^0.1.2" - } - }, "uuid": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", @@ -1030,19 +1027,6 @@ "randomhex": "0.1.5", "underscore": "1.9.1", "utf8": "3.0.0" - }, - "dependencies": { - "eth-lib": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.7.tgz", - "integrity": "sha1-L5Pxex4jrsN1nNSj/iDBKGo/wco=", - "dev": true, - "requires": { - "bn.js": "^4.11.6", - "elliptic": "^6.4.0", - "xhr-request-promise": "^0.1.2" - } - } } }, "websocket": { @@ -1056,17 +1040,6 @@ "nan": "^2.14.0", "typedarray-to-buffer": "^3.1.5", "yaeti": "^0.0.6" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - } } } } @@ -3897,12 +3870,12 @@ } }, "color-convert": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", - "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, "requires": { - "color-name": "^1.1.1" + "color-name": "1.1.3" } }, "color-name": { @@ -4076,28 +4049,6 @@ "vary": "^1" } }, - "coveralls": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-3.0.6.tgz", - "integrity": "sha512-Pgh4v3gCI4T/9VijVrm8Ym5v0OgjvGLKj3zTUwkvsCiwqae/p6VLzpsFNjQS2i6ewV7ef+DjFJ5TSKxYt/mCrA==", - "dev": true, - "requires": { - "growl": "~> 1.10.0", - "js-yaml": "^3.13.1", - "lcov-parse": "^0.0.10", - "log-driver": "^1.2.7", - "minimist": "^1.2.0", - "request": "^2.86.0" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } - } - }, "create-ecdh": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", @@ -6328,6 +6279,26 @@ } } }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "dev": true, + "requires": { + "debug": "=3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, "for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -9708,12 +9679,6 @@ "invert-kv": "^1.0.0" } }, - "lcov-parse": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-0.0.10.tgz", - "integrity": "sha1-GwuP+ayceIklBYK3C3ExXZ2m2aM=", - "dev": true - }, "lead": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz", @@ -10129,12 +10094,6 @@ "integrity": "sha1-PNRXSgC2e643OpS3SHcmQFB7eqw=", "dev": true }, - "log-driver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz", - "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==", - "dev": true - }, "lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", diff --git a/package.json b/package.json index f5364c23b..64c02218a 100644 --- a/package.json +++ b/package.json @@ -44,9 +44,8 @@ "@openzeppelin/gsn-helpers": "^0.1.5", "@openzeppelin/gsn-provider": "^0.1.5", "@openzeppelin/upgrades": "2.5.0", - "chai": "^4.1.2", + "chai": "^4.2.0", "chai-bn": "^0.1.1", - "coveralls": "^3.0.1", "eslint": "^4.19.1", "eslint-config-standard": "^10.2.1", "eslint-plugin-import": "^2.13.0", diff --git a/test/GSN/ERC721GSNRecipientMock.test.js b/test/GSN/ERC721GSNRecipientMock.test.js new file mode 100644 index 000000000..867753341 --- /dev/null +++ b/test/GSN/ERC721GSNRecipientMock.test.js @@ -0,0 +1,46 @@ +const { constants, expectEvent } = require('openzeppelin-test-helpers'); +const { ZERO_ADDRESS } = constants; +const gsn = require('@openzeppelin/gsn-helpers'); +const { fixSignature } = require('../helpers/sign'); +const { utils: { toBN } } = require('web3'); + +const ERC721GSNRecipientMock = artifacts.require('ERC721GSNRecipientMock'); + +contract('ERC721GSNRecipient (integration)', function ([_, signer, sender]) { + const tokenId = '42'; + + beforeEach(async function () { + this.token = await ERC721GSNRecipientMock.new(signer); + }); + + async function testMintToken (token, from, tokenId, options = {}) { + const { tx } = await token.mint(tokenId, { from, ...options }); + await expectEvent.inTransaction(tx, ERC721GSNRecipientMock, 'Transfer', { from: ZERO_ADDRESS, to: from, tokenId }); + } + + context('when called directly', function () { + it('sender can mint tokens', async function () { + await testMintToken(this.token, sender, tokenId); + }); + }); + + context('when relay-called', function () { + beforeEach(async function () { + await gsn.fundRecipient(web3, { recipient: this.token.address }); + }); + + it('sender can mint tokens', async function () { + const approveFunction = async (data) => + fixSignature( + await web3.eth.sign( + web3.utils.soliditySha3( + // eslint-disable-next-line max-len + data.relayerAddress, data.from, data.encodedFunctionCall, toBN(data.txFee), toBN(data.gasPrice), toBN(data.gas), toBN(data.nonce), data.relayHubAddress, this.token.address + ), signer + ) + ); + + await testMintToken(this.token, sender, tokenId, { useGSN: true, approveFunction }); + }); + }); +});