Commit 88ee64b9 by github-actions

Transpile bce31dee

parent 1e6ee726
...@@ -30,5 +30,6 @@ jobs: ...@@ -30,5 +30,6 @@ jobs:
env: env:
FORCE_COLOR: 1 FORCE_COLOR: 1
ENABLE_GAS_REPORT: true ENABLE_GAS_REPORT: true
- run: npm run test:inheritance
- name: Print gas report - name: Print gas report
run: cat gas-report.txt run: cat gas-report.txt
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
* `ERC20Votes`: add a new extension of the `ERC20` token with support for voting snapshots and delegation. ([#2632](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2632)) * `ERC20Votes`: add a new extension of the `ERC20` token with support for voting snapshots and delegation. ([#2632](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2632))
* `ERC20VotesComp`: Variant of `ERC20Votes` that is compatible with Compound's `Comp` token interface but restricts supply to `uint96`. ([#2706](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2706)) * `ERC20VotesComp`: Variant of `ERC20Votes` that is compatible with Compound's `Comp` token interface but restricts supply to `uint96`. ([#2706](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2706))
* `ERC20Wrapper`: add a new extension of the `ERC20` token which wraps an underlying token. Deposit and withdraw guarantee that the total supply is backed by a corresponding amount of underlying token. ([#2633](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2633))
* Enumerables: Improve gas cost of removal in `EnumerableSet` and `EnumerableMap`. * Enumerables: Improve gas cost of removal in `EnumerableSet` and `EnumerableMap`.
* Enumerables: Improve gas cost of lookup in `EnumerableSet` and `EnumerableMap`. * Enumerables: Improve gas cost of lookup in `EnumerableSet` and `EnumerableMap`.
* `Counter`: add a reset method. ([#2678](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2678)) * `Counter`: add a reset method. ([#2678](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2678))
......
...@@ -31,9 +31,7 @@ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { ...@@ -31,9 +31,7 @@ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
} }
function __Ownable_init_unchained() internal initializer { function __Ownable_init_unchained() internal initializer {
address msgSender = _msgSender(); _setOwner(_msgSender());
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
} }
/** /**
...@@ -59,8 +57,7 @@ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { ...@@ -59,8 +57,7 @@ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
* thereby removing any functionality that is only available to the owner. * thereby removing any functionality that is only available to the owner.
*/ */
function renounceOwnership() public virtual onlyOwner { function renounceOwnership() public virtual onlyOwner {
emit OwnershipTransferred(_owner, address(0)); _setOwner(address(0));
_owner = address(0);
} }
/** /**
...@@ -69,8 +66,13 @@ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { ...@@ -69,8 +66,13 @@ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
*/ */
function transferOwnership(address newOwner) public virtual onlyOwner { function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address"); require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner); _setOwner(newOwner);
}
function _setOwner(address newOwner) private {
address oldOwner = _owner;
_owner = newOwner; _owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
} }
uint256[49] private __gap; uint256[49] private __gap;
} }
...@@ -6,7 +6,7 @@ import "../token/ERC1155/IERC1155ReceiverUpgradeable.sol"; ...@@ -6,7 +6,7 @@ import "../token/ERC1155/IERC1155ReceiverUpgradeable.sol";
import "../utils/introspection/ERC165Upgradeable.sol"; import "../utils/introspection/ERC165Upgradeable.sol";
import "../proxy/utils/Initializable.sol"; import "../proxy/utils/Initializable.sol";
contract ERC1155ReceiverMockUpgradeable is Initializable, IERC1155ReceiverUpgradeable, ERC165Upgradeable { contract ERC1155ReceiverMockUpgradeable is Initializable, ERC165Upgradeable, IERC1155ReceiverUpgradeable {
bytes4 private _recRetval; bytes4 private _recRetval;
bool private _recReverts; bool private _recReverts;
bytes4 private _batRetval; bytes4 private _batRetval;
......
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../token/ERC20/extensions/ERC20WrapperUpgradeable.sol";
import "../proxy/utils/Initializable.sol";
contract ERC20WrapperMockUpgradeable is Initializable, ERC20WrapperUpgradeable {
function __ERC20WrapperMock_init(
IERC20Upgradeable _underlyingToken,
string memory name,
string memory symbol
) internal initializer {
__Context_init_unchained();
__ERC20_init_unchained(name, symbol);
__ERC20Wrapper_init_unchained(_underlyingToken);
__ERC20WrapperMock_init_unchained(_underlyingToken, name, symbol);
}
function __ERC20WrapperMock_init_unchained(
IERC20Upgradeable _underlyingToken,
string memory name,
string memory symbol
) internal initializer {}
function recover(address account) public returns (uint256) {
return _recover(account);
}
uint256[50] private __gap;
}
...@@ -65,50 +65,44 @@ contract ERC1271WalletMockUpgradeableWithInit is ERC1271WalletMockUpgradeable { ...@@ -65,50 +65,44 @@ contract ERC1271WalletMockUpgradeableWithInit is ERC1271WalletMockUpgradeable {
__ERC1271WalletMock_init(originalOwner); __ERC1271WalletMock_init(originalOwner);
} }
} }
import "../token/ERC20/utils/TokenTimelockUpgradeable.sol"; import "./MulticallTokenMockUpgradeable.sol";
contract TokenTimelockUpgradeableWithInit is TokenTimelockUpgradeable {
constructor(
IERC20Upgradeable token_,
address beneficiary_,
uint256 releaseTime_
) public payable {
__TokenTimelock_init(token_, beneficiary_, releaseTime_);
}
}
import "./SafeERC20HelperUpgradeable.sol";
contract ERC20ReturnFalseMockUpgradeableWithInit is ERC20ReturnFalseMockUpgradeable { contract MulticallTokenMockUpgradeableWithInit is MulticallTokenMockUpgradeable {
constructor() public payable { constructor(uint256 initialBalance) public payable {
__ERC20ReturnFalseMock_init(); __MulticallTokenMock_init(initialBalance);
} }
} }
import "./SafeERC20HelperUpgradeable.sol"; import "./ERC20MockUpgradeable.sol";
contract ERC20ReturnTrueMockUpgradeableWithInit is ERC20ReturnTrueMockUpgradeable { contract ERC20MockUpgradeableWithInit is ERC20MockUpgradeable {
constructor() public payable { constructor(
__ERC20ReturnTrueMock_init(); string memory name,
string memory symbol,
address initialAccount,
uint256 initialBalance
) public payable {
__ERC20Mock_init(name, symbol, initialAccount, initialBalance);
} }
} }
import "./SafeERC20HelperUpgradeable.sol"; import "../token/ERC20/presets/ERC20PresetMinterPauserUpgradeable.sol";
contract ERC20NoReturnMockUpgradeableWithInit is ERC20NoReturnMockUpgradeable { contract ERC20PresetMinterPauserUpgradeableWithInit is ERC20PresetMinterPauserUpgradeable {
constructor() public payable { constructor(string memory name, string memory symbol) public payable {
__ERC20NoReturnMock_init(); __ERC20PresetMinterPauser_init(name, symbol);
} }
} }
import "./SafeERC20HelperUpgradeable.sol"; import "../token/ERC1155/presets/ERC1155PresetMinterPauserUpgradeable.sol";
contract SafeERC20WrapperUpgradeableWithInit is SafeERC20WrapperUpgradeable { contract ERC1155PresetMinterPauserUpgradeableWithInit is ERC1155PresetMinterPauserUpgradeable {
constructor(IERC20Upgradeable token) public payable { constructor(string memory uri) public payable {
__SafeERC20Wrapper_init(token); __ERC1155PresetMinterPauser_init(uri);
} }
} }
import "../token/ERC20/presets/ERC20PresetMinterPauserUpgradeable.sol"; import "../token/ERC1155/ERC1155Upgradeable.sol";
contract ERC20PresetMinterPauserUpgradeableWithInit is ERC20PresetMinterPauserUpgradeable { contract ERC1155UpgradeableWithInit is ERC1155Upgradeable {
constructor(string memory name, string memory symbol) public payable { constructor(string memory uri_) public payable {
__ERC20PresetMinterPauser_init(name, symbol); __ERC1155_init(uri_);
} }
} }
import "./PausableMockUpgradeable.sol"; import "./PausableMockUpgradeable.sol";
...@@ -179,25 +173,11 @@ contract ERC1155ReceiverMockUpgradeableWithInit is ERC1155ReceiverMockUpgradeabl ...@@ -179,25 +173,11 @@ contract ERC1155ReceiverMockUpgradeableWithInit is ERC1155ReceiverMockUpgradeabl
__ERC1155ReceiverMock_init(recRetval, recReverts, batRetval, batReverts); __ERC1155ReceiverMock_init(recRetval, recReverts, batRetval, batReverts);
} }
} }
import "../token/ERC1155/ERC1155Upgradeable.sol"; import "./ERC1155SupplyMockUpgradeable.sol";
contract ERC1155UpgradeableWithInit is ERC1155Upgradeable {
constructor(string memory uri_) public payable {
__ERC1155_init(uri_);
}
}
import "../token/ERC1155/presets/ERC1155PresetMinterPauserUpgradeable.sol";
contract ERC1155PresetMinterPauserUpgradeableWithInit is ERC1155PresetMinterPauserUpgradeable {
constructor(string memory uri) public payable {
__ERC1155PresetMinterPauser_init(uri);
}
}
import "./ERC1155PausableMockUpgradeable.sol";
contract ERC1155PausableMockUpgradeableWithInit is ERC1155PausableMockUpgradeable { contract ERC1155SupplyMockUpgradeableWithInit is ERC1155SupplyMockUpgradeable {
constructor(string memory uri) public payable { constructor(string memory uri) public payable {
__ERC1155PausableMock_init(uri); __ERC1155SupplyMock_init(uri);
} }
} }
import "./ERC1155MockUpgradeable.sol"; import "./ERC1155MockUpgradeable.sol";
...@@ -207,11 +187,11 @@ contract ERC1155MockUpgradeableWithInit is ERC1155MockUpgradeable { ...@@ -207,11 +187,11 @@ contract ERC1155MockUpgradeableWithInit is ERC1155MockUpgradeable {
__ERC1155Mock_init(uri); __ERC1155Mock_init(uri);
} }
} }
import "./ERC1155SupplyMockUpgradeable.sol"; import "./ERC1155PausableMockUpgradeable.sol";
contract ERC1155SupplyMockUpgradeableWithInit is ERC1155SupplyMockUpgradeable { contract ERC1155PausableMockUpgradeableWithInit is ERC1155PausableMockUpgradeable {
constructor(string memory uri) public payable { constructor(string memory uri) public payable {
__ERC1155SupplyMock_init(uri); __ERC1155PausableMock_init(uri);
} }
} }
import "./ERC1155BurnableMockUpgradeable.sol"; import "./ERC1155BurnableMockUpgradeable.sol";
...@@ -270,133 +250,150 @@ contract ERC721PausableMockUpgradeableWithInit is ERC721PausableMockUpgradeable ...@@ -270,133 +250,150 @@ contract ERC721PausableMockUpgradeableWithInit is ERC721PausableMockUpgradeable
__ERC721PausableMock_init(name, symbol); __ERC721PausableMock_init(name, symbol);
} }
} }
import "./EIP712ExternalUpgradeable.sol"; import "./ERC20PausableMockUpgradeable.sol";
contract EIP712ExternalUpgradeableWithInit is EIP712ExternalUpgradeable {
constructor(string memory name, string memory version) public payable {
__EIP712External_init(name, version);
}
}
import "../metatx/MinimalForwarderUpgradeable.sol";
contract MinimalForwarderUpgradeableWithInit is MinimalForwarderUpgradeable {
constructor() public payable {
__MinimalForwarder_init();
}
}
import "./ERC20PermitMockUpgradeable.sol";
contract ERC20PermitMockUpgradeableWithInit is ERC20PermitMockUpgradeable { contract ERC20PausableMockUpgradeableWithInit is ERC20PausableMockUpgradeable {
constructor( constructor(
string memory name, string memory name,
string memory symbol, string memory symbol,
address initialAccount, address initialAccount,
uint256 initialBalance uint256 initialBalance
) public payable { ) public payable {
__ERC20PermitMock_init(name, symbol, initialAccount, initialBalance); __ERC20PausableMock_init(name, symbol, initialAccount, initialBalance);
} }
} }
import "./ERC20MockUpgradeable.sol"; import "./SafeERC20HelperUpgradeable.sol";
contract ERC20MockUpgradeableWithInit is ERC20MockUpgradeable { contract ERC20ReturnFalseMockUpgradeableWithInit is ERC20ReturnFalseMockUpgradeable {
constructor( constructor() public payable {
string memory name, __ERC20ReturnFalseMock_init();
string memory symbol,
address initialAccount,
uint256 initialBalance
) public payable {
__ERC20Mock_init(name, symbol, initialAccount, initialBalance);
} }
} }
import "./MulticallTokenMockUpgradeable.sol"; import "./SafeERC20HelperUpgradeable.sol";
contract MulticallTokenMockUpgradeableWithInit is MulticallTokenMockUpgradeable { contract ERC20ReturnTrueMockUpgradeableWithInit is ERC20ReturnTrueMockUpgradeable {
constructor(uint256 initialBalance) public payable { constructor() public payable {
__MulticallTokenMock_init(initialBalance); __ERC20ReturnTrueMock_init();
} }
} }
import "./MulticallTestUpgradeable.sol"; import "./SafeERC20HelperUpgradeable.sol";
contract MulticallTestUpgradeableWithInit is MulticallTestUpgradeable { contract ERC20NoReturnMockUpgradeableWithInit is ERC20NoReturnMockUpgradeable {
constructor() public payable { constructor() public payable {
__MulticallTest_init(); __ERC20NoReturnMock_init();
} }
} }
import "./ERC3156FlashBorrowerMockUpgradeable.sol"; import "./SafeERC20HelperUpgradeable.sol";
contract ERC3156FlashBorrowerMockUpgradeableWithInit is ERC3156FlashBorrowerMockUpgradeable { contract SafeERC20WrapperUpgradeableWithInit is SafeERC20WrapperUpgradeable {
constructor(bool enableReturn, bool enableApprove) public payable { constructor(IERC20Upgradeable token) public payable {
__ERC3156FlashBorrowerMock_init(enableReturn, enableApprove); __SafeERC20Wrapper_init(token);
} }
} }
import "./ERC20FlashMintMockUpgradeable.sol"; import "../token/ERC20/utils/TokenTimelockUpgradeable.sol";
contract ERC20FlashMintMockUpgradeableWithInit is ERC20FlashMintMockUpgradeable { contract TokenTimelockUpgradeableWithInit is TokenTimelockUpgradeable {
constructor( constructor(
string memory name, IERC20Upgradeable token_,
string memory symbol, address beneficiary_,
address initialAccount, uint256 releaseTime_
uint256 initialBalance
) public payable { ) public payable {
__ERC20FlashMintMock_init(name, symbol, initialAccount, initialBalance); __TokenTimelock_init(token_, beneficiary_, releaseTime_);
} }
} }
import "./ERC20DecimalsMockUpgradeable.sol"; import "../token/ERC777/ERC777Upgradeable.sol";
contract ERC20DecimalsMockUpgradeableWithInit is ERC20DecimalsMockUpgradeable { contract ERC777UpgradeableWithInit is ERC777Upgradeable {
constructor( constructor(
string memory name_, string memory name_,
string memory symbol_, string memory symbol_,
uint8 decimals_ address[] memory defaultOperators_
) public payable { ) public payable {
__ERC20DecimalsMock_init(name_, symbol_, decimals_); __ERC777_init(name_, symbol_, defaultOperators_);
} }
} }
import "./ERC20CappedMockUpgradeable.sol"; import "../token/ERC777/presets/ERC777PresetFixedSupplyUpgradeable.sol";
contract ERC20CappedMockUpgradeableWithInit is ERC20CappedMockUpgradeable { contract ERC777PresetFixedSupplyUpgradeableWithInit is ERC777PresetFixedSupplyUpgradeable {
constructor( constructor(
string memory name, string memory name,
string memory symbol, string memory symbol,
uint256 cap address[] memory defaultOperators,
uint256 initialSupply,
address owner
) public payable { ) public payable {
__ERC20CappedMock_init(name, symbol, cap); __ERC777PresetFixedSupply_init(name, symbol, defaultOperators, initialSupply, owner);
} }
} }
import "../token/ERC20/presets/ERC20PresetFixedSupplyUpgradeable.sol"; import "./ERC777SenderRecipientMockUpgradeable.sol";
contract ERC20PresetFixedSupplyUpgradeableWithInit is ERC20PresetFixedSupplyUpgradeable { contract ERC777SenderRecipientMockUpgradeableWithInit is ERC777SenderRecipientMockUpgradeable {
constructor() public payable {
__ERC777SenderRecipientMock_init();
}
}
import "../utils/introspection/ERC1820ImplementerUpgradeable.sol";
contract ERC1820ImplementerUpgradeableWithInit is ERC1820ImplementerUpgradeable {
constructor() public payable {
__ERC1820Implementer_init();
}
}
import "./ERC1820ImplementerMockUpgradeable.sol";
contract ERC1820ImplementerMockUpgradeableWithInit is ERC1820ImplementerMockUpgradeable {
constructor() public payable {
__ERC1820ImplementerMock_init();
}
}
import "./Create2ImplUpgradeable.sol";
contract Create2ImplUpgradeableWithInit is Create2ImplUpgradeable {
constructor() public payable {
__Create2Impl_init();
}
}
import "./ERC777MockUpgradeable.sol";
contract ERC777MockUpgradeableWithInit is ERC777MockUpgradeable {
constructor( constructor(
address initialHolder,
uint256 initialBalance,
string memory name, string memory name,
string memory symbol, string memory symbol,
uint256 initialSupply, address[] memory defaultOperators
address owner
) public payable { ) public payable {
__ERC20PresetFixedSupply_init(name, symbol, initialSupply, owner); __ERC777Mock_init(initialHolder, initialBalance, name, symbol, defaultOperators);
} }
} }
import "./ERC20BurnableMockUpgradeable.sol"; import "./ERC3156FlashBorrowerMockUpgradeable.sol";
contract ERC20BurnableMockUpgradeableWithInit is ERC20BurnableMockUpgradeable { contract ERC3156FlashBorrowerMockUpgradeableWithInit is ERC3156FlashBorrowerMockUpgradeable {
constructor(bool enableReturn, bool enableApprove) public payable {
__ERC3156FlashBorrowerMock_init(enableReturn, enableApprove);
}
}
import "./ERC20FlashMintMockUpgradeable.sol";
contract ERC20FlashMintMockUpgradeableWithInit is ERC20FlashMintMockUpgradeable {
constructor( constructor(
string memory name, string memory name,
string memory symbol, string memory symbol,
address initialAccount, address initialAccount,
uint256 initialBalance uint256 initialBalance
) public payable { ) public payable {
__ERC20BurnableMock_init(name, symbol, initialAccount, initialBalance); __ERC20FlashMintMock_init(name, symbol, initialAccount, initialBalance);
} }
} }
import "./ERC20PausableMockUpgradeable.sol"; import "./ERC20WrapperMockUpgradeable.sol";
contract ERC20PausableMockUpgradeableWithInit is ERC20PausableMockUpgradeable { contract ERC20WrapperMockUpgradeableWithInit is ERC20WrapperMockUpgradeable {
constructor( constructor(
IERC20Upgradeable _underlyingToken,
string memory name, string memory name,
string memory symbol, string memory symbol
address initialAccount,
uint256 initialBalance
) public payable { ) public payable {
__ERC20PausableMock_init(name, symbol, initialAccount, initialBalance); __ERC20WrapperMock_init(_underlyingToken, name, symbol);
} }
} }
import "./ReentrancyAttackUpgradeable.sol"; import "./ReentrancyAttackUpgradeable.sol";
...@@ -413,69 +410,28 @@ contract ReentrancyMockUpgradeableWithInit is ReentrancyMockUpgradeable { ...@@ -413,69 +410,28 @@ contract ReentrancyMockUpgradeableWithInit is ReentrancyMockUpgradeable {
__ReentrancyMock_init(); __ReentrancyMock_init();
} }
} }
import "./ERC777SenderRecipientMockUpgradeable.sol"; import "../token/ERC20/presets/ERC20PresetFixedSupplyUpgradeable.sol";
contract ERC777SenderRecipientMockUpgradeableWithInit is ERC777SenderRecipientMockUpgradeable {
constructor() public payable {
__ERC777SenderRecipientMock_init();
}
}
import "../utils/introspection/ERC1820ImplementerUpgradeable.sol";
contract ERC1820ImplementerUpgradeableWithInit is ERC1820ImplementerUpgradeable {
constructor() public payable {
__ERC1820Implementer_init();
}
}
import "./ERC1820ImplementerMockUpgradeable.sol";
contract ERC1820ImplementerMockUpgradeableWithInit is ERC1820ImplementerMockUpgradeable {
constructor() public payable {
__ERC1820ImplementerMock_init();
}
}
import "./Create2ImplUpgradeable.sol";
contract Create2ImplUpgradeableWithInit is Create2ImplUpgradeable {
constructor() public payable {
__Create2Impl_init();
}
}
import "../token/ERC777/ERC777Upgradeable.sol";
contract ERC777UpgradeableWithInit is ERC777Upgradeable {
constructor(
string memory name_,
string memory symbol_,
address[] memory defaultOperators_
) public payable {
__ERC777_init(name_, symbol_, defaultOperators_);
}
}
import "../token/ERC777/presets/ERC777PresetFixedSupplyUpgradeable.sol";
contract ERC777PresetFixedSupplyUpgradeableWithInit is ERC777PresetFixedSupplyUpgradeable { contract ERC20PresetFixedSupplyUpgradeableWithInit is ERC20PresetFixedSupplyUpgradeable {
constructor( constructor(
string memory name, string memory name,
string memory symbol, string memory symbol,
address[] memory defaultOperators,
uint256 initialSupply, uint256 initialSupply,
address owner address owner
) public payable { ) public payable {
__ERC777PresetFixedSupply_init(name, symbol, defaultOperators, initialSupply, owner); __ERC20PresetFixedSupply_init(name, symbol, initialSupply, owner);
} }
} }
import "./ERC777MockUpgradeable.sol"; import "./ERC20BurnableMockUpgradeable.sol";
contract ERC777MockUpgradeableWithInit is ERC777MockUpgradeable { contract ERC20BurnableMockUpgradeableWithInit is ERC20BurnableMockUpgradeable {
constructor( constructor(
address initialHolder,
uint256 initialBalance,
string memory name, string memory name,
string memory symbol, string memory symbol,
address[] memory defaultOperators address initialAccount,
uint256 initialBalance
) public payable { ) public payable {
__ERC777Mock_init(initialHolder, initialBalance, name, symbol, defaultOperators); __ERC20BurnableMock_init(name, symbol, initialAccount, initialBalance);
} }
} }
import "./ContextMockUpgradeable.sol"; import "./ContextMockUpgradeable.sol";
...@@ -513,6 +469,61 @@ contract SafeMathMockUpgradeableWithInit is SafeMathMockUpgradeable { ...@@ -513,6 +469,61 @@ contract SafeMathMockUpgradeableWithInit is SafeMathMockUpgradeable {
__SafeMathMock_init(); __SafeMathMock_init();
} }
} }
import "./EIP712ExternalUpgradeable.sol";
contract EIP712ExternalUpgradeableWithInit is EIP712ExternalUpgradeable {
constructor(string memory name, string memory version) public payable {
__EIP712External_init(name, version);
}
}
import "../metatx/MinimalForwarderUpgradeable.sol";
contract MinimalForwarderUpgradeableWithInit is MinimalForwarderUpgradeable {
constructor() public payable {
__MinimalForwarder_init();
}
}
import "./ERC20PermitMockUpgradeable.sol";
contract ERC20PermitMockUpgradeableWithInit is ERC20PermitMockUpgradeable {
constructor(
string memory name,
string memory symbol,
address initialAccount,
uint256 initialBalance
) public payable {
__ERC20PermitMock_init(name, symbol, initialAccount, initialBalance);
}
}
import "./ERC20DecimalsMockUpgradeable.sol";
contract ERC20DecimalsMockUpgradeableWithInit is ERC20DecimalsMockUpgradeable {
constructor(
string memory name_,
string memory symbol_,
uint8 decimals_
) public payable {
__ERC20DecimalsMock_init(name_, symbol_, decimals_);
}
}
import "./ERC20CappedMockUpgradeable.sol";
contract ERC20CappedMockUpgradeableWithInit is ERC20CappedMockUpgradeable {
constructor(
string memory name,
string memory symbol,
uint256 cap
) public payable {
__ERC20CappedMock_init(name, symbol, cap);
}
}
import "./MulticallTestUpgradeable.sol";
contract MulticallTestUpgradeableWithInit is MulticallTestUpgradeable {
constructor() public payable {
__MulticallTest_init();
}
}
import "../utils/escrow/EscrowUpgradeable.sol"; import "../utils/escrow/EscrowUpgradeable.sol";
contract EscrowUpgradeableWithInit is EscrowUpgradeable { contract EscrowUpgradeableWithInit is EscrowUpgradeable {
......
...@@ -72,8 +72,7 @@ abstract contract ERC1967UpgradeUpgradeable is Initializable { ...@@ -72,8 +72,7 @@ abstract contract ERC1967UpgradeUpgradeable is Initializable {
bytes memory data, bytes memory data,
bool forceCall bool forceCall
) internal { ) internal {
_setImplementation(newImplementation); _upgradeTo(newImplementation);
emit Upgraded(newImplementation);
if (data.length > 0 || forceCall) { if (data.length > 0 || forceCall) {
_functionDelegateCall(newImplementation, data); _functionDelegateCall(newImplementation, data);
} }
...@@ -110,26 +109,7 @@ abstract contract ERC1967UpgradeUpgradeable is Initializable { ...@@ -110,26 +109,7 @@ abstract contract ERC1967UpgradeUpgradeable is Initializable {
// Check rollback was effective // Check rollback was effective
require(oldImplementation == _getImplementation(), "ERC1967Upgrade: upgrade breaks further upgrades"); require(oldImplementation == _getImplementation(), "ERC1967Upgrade: upgrade breaks further upgrades");
// Finally reset to the new implementation and log the upgrade // Finally reset to the new implementation and log the upgrade
_setImplementation(newImplementation); _upgradeTo(newImplementation);
emit Upgraded(newImplementation);
}
}
/**
* @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
* not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
*
* Emits a {BeaconUpgraded} event.
*/
function _upgradeBeaconToAndCall(
address newBeacon,
bytes memory data,
bool forceCall
) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0 || forceCall) {
_functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), data);
} }
} }
...@@ -201,6 +181,24 @@ abstract contract ERC1967UpgradeUpgradeable is Initializable { ...@@ -201,6 +181,24 @@ abstract contract ERC1967UpgradeUpgradeable is Initializable {
} }
/** /**
* @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
* not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
*
* Emits a {BeaconUpgraded} event.
*/
function _upgradeBeaconToAndCall(
address newBeacon,
bytes memory data,
bool forceCall
) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0 || forceCall) {
_functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), data);
}
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call. * but performing a delegate call.
* *
......
...@@ -209,9 +209,9 @@ contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeabl ...@@ -209,9 +209,9 @@ contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeabl
} }
/** /**
* @dev Moves tokens `amount` from `sender` to `recipient`. * @dev Moves `amount` of tokens from `sender` to `recipient`.
* *
* This is internal function is equivalent to {transfer}, and can be used to * This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc. * e.g. implement automatic token fees, slashing mechanisms, etc.
* *
* Emits a {Transfer} event. * Emits a {Transfer} event.
...@@ -240,6 +240,8 @@ contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeabl ...@@ -240,6 +240,8 @@ contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeabl
_balances[recipient] += amount; _balances[recipient] += amount;
emit Transfer(sender, recipient, amount); emit Transfer(sender, recipient, amount);
_afterTokenTransfer(sender, recipient, amount);
} }
/** @dev Creates `amount` tokens and assigns them to `account`, increasing /** @dev Creates `amount` tokens and assigns them to `account`, increasing
...@@ -259,6 +261,8 @@ contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeabl ...@@ -259,6 +261,8 @@ contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeabl
_totalSupply += amount; _totalSupply += amount;
_balances[account] += amount; _balances[account] += amount;
emit Transfer(address(0), account, amount); emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
} }
/** /**
...@@ -285,6 +289,8 @@ contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeabl ...@@ -285,6 +289,8 @@ contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeabl
_totalSupply -= amount; _totalSupply -= amount;
emit Transfer(account, address(0), amount); emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
} }
/** /**
...@@ -319,7 +325,7 @@ contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeabl ...@@ -319,7 +325,7 @@ contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeabl
* Calling conditions: * Calling conditions:
* *
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be to transferred to `to`. * will be transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`. * - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero. * - `from` and `to` are never both zero.
...@@ -331,5 +337,25 @@ contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeabl ...@@ -331,5 +337,25 @@ contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeabl
address to, address to,
uint256 amount uint256 amount
) internal virtual {} ) internal virtual {}
/**
* @dev Hook that is called after any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* has been transferred to `to`.
* - when `from` is zero, `amount` tokens have been minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens have been burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
uint256[45] private __gap; uint256[45] private __gap;
} }
...@@ -23,6 +23,7 @@ Additionally there are multiple custom extensions, including: ...@@ -23,6 +23,7 @@ Additionally there are multiple custom extensions, including:
* {ERC20FlashMint}: token level support for flash loans through the minting and burning of ephemeral tokens (standardized as ERC3156). * {ERC20FlashMint}: token level support for flash loans through the minting and burning of ephemeral tokens (standardized as ERC3156).
* {ERC20Votes}: support for voting and vote delegation. * {ERC20Votes}: support for voting and vote delegation.
* {ERC20VotesComp}: support for voting and vote delegation (compatible with Compound's tokenn, with uint96 restrictions). * {ERC20VotesComp}: support for voting and vote delegation (compatible with Compound's tokenn, with uint96 restrictions).
* {ERC20Wrapper}: wrapper to create an ERC20 backed by another ERC20, with deposit and withdraw methods. Useful in conjunction with {ERC20Votes}.
Finally, there are some utilities to interact with ERC20 contracts in various ways. Finally, there are some utilities to interact with ERC20 contracts in various ways.
...@@ -58,6 +59,8 @@ NOTE: This core set of contracts is designed to be unopinionated, allowing devel ...@@ -58,6 +59,8 @@ NOTE: This core set of contracts is designed to be unopinionated, allowing devel
{{ERC20VotesComp}} {{ERC20VotesComp}}
{{ERC20Wrapper}}
== Draft EIPs == Draft EIPs
The following EIPs are still in Draft status. Due to their nature as drafts, the details of these contracts may change and we cannot guarantee their xref:ROOT:releases-stability.adoc[stability]. Minor releases of OpenZeppelin Contracts may contain breaking changes for the contracts in this directory, which will be duly announced in the https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/CHANGELOG.md[changelog]. The EIPs included here are used by projects in production and this may make them less likely to change significantly. The following EIPs are still in Draft status. Due to their nature as drafts, the details of these contracts may change and we cannot guarantee their xref:ROOT:releases-stability.adoc[stability]. Minor releases of OpenZeppelin Contracts may contain breaking changes for the contracts in this directory, which will be duly announced in the https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/CHANGELOG.md[changelog]. The EIPs included here are used by projects in production and this may make them less likely to change significantly.
......
...@@ -193,11 +193,13 @@ abstract contract ERC20VotesUpgradeable is Initializable, ERC20PermitUpgradeable ...@@ -193,11 +193,13 @@ abstract contract ERC20VotesUpgradeable is Initializable, ERC20PermitUpgradeable
* *
* Emits a {DelegateVotesChanged} event. * Emits a {DelegateVotesChanged} event.
*/ */
function _beforeTokenTransfer( function _afterTokenTransfer(
address from, address from,
address to, address to,
uint256 amount uint256 amount
) internal virtual override { ) internal virtual override {
super._afterTokenTransfer(from, to, amount);
_moveVotingPower(delegates(from), delegates(to), amount); _moveVotingPower(delegates(from), delegates(to), amount);
} }
......
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../ERC20Upgradeable.sol";
import "../utils/SafeERC20Upgradeable.sol";
import "../../../proxy/utils/Initializable.sol";
/**
* @dev Extension of the ERC20 token contract to support token wrapping.
*
* Users can deposit and withdraw "underlying tokens" and receive a matching number of "wrapped tokens". This is useful
* in conjunction with other modules. For example, combining this wrapping mechanism with {ERC20Votes} will allow the
* wrapping of an existing "basic" ERC20 into a governance token.
*
* _Available since v4.2._
*/
abstract contract ERC20WrapperUpgradeable is Initializable, ERC20Upgradeable {
IERC20Upgradeable public underlying;
function __ERC20Wrapper_init(IERC20Upgradeable underlyingToken) internal initializer {
__Context_init_unchained();
__ERC20Wrapper_init_unchained(underlyingToken);
}
function __ERC20Wrapper_init_unchained(IERC20Upgradeable underlyingToken) internal initializer {
underlying = underlyingToken;
}
/**
* @dev Allow a user to deposit underlying tokens and mint the corresponding number of wrapped tokens.
*/
function depositFor(address account, uint256 amount) public virtual returns (bool) {
SafeERC20Upgradeable.safeTransferFrom(underlying, _msgSender(), address(this), amount);
_mint(account, amount);
return true;
}
/**
* @dev Allow a user to burn a number of wrapped tokens and withdraw the corresponding number of underlying tokens.
*/
function withdrawTo(address account, uint256 amount) public virtual returns (bool) {
_burn(_msgSender(), amount);
SafeERC20Upgradeable.safeTransfer(underlying, account, amount);
return true;
}
/**
* @dev Mint wrapped token to cover any underlyingTokens that would have been transfered by mistake. Internal
* function that can be exposed with access control if desired.
*/
function _recover(address account) internal virtual returns (uint256) {
uint256 value = underlying.balanceOf(address(this)) - totalSupply();
_mint(account, value);
return value;
}
uint256[50] private __gap;
}
...@@ -60,7 +60,7 @@ library AddressUpgradeable { ...@@ -60,7 +60,7 @@ library AddressUpgradeable {
/** /**
* @dev Performs a Solidity function call using a low level `call`. A * @dev Performs a Solidity function call using a low level `call`. A
* plain`call` is an unsafe replacement for a function call: use this * plain `call` is an unsafe replacement for a function call: use this
* function instead. * function instead.
* *
* If `target` reverts with a revert reason, it is bubbled up by this * If `target` reverts with a revert reason, it is bubbled up by this
......
...@@ -25,7 +25,6 @@ abstract contract ContextUpgradeable is Initializable { ...@@ -25,7 +25,6 @@ abstract contract ContextUpgradeable is Initializable {
} }
function _msgData() internal view virtual returns (bytes calldata) { function _msgData() internal view virtual returns (bytes calldata) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data; return msg.data;
} }
uint256[50] private __gap; uint256[50] private __gap;
......
...@@ -6,7 +6,7 @@ pragma solidity ^0.8.0; ...@@ -6,7 +6,7 @@ pragma solidity ^0.8.0;
* @dev String operations. * @dev String operations.
*/ */
library StringsUpgradeable { library StringsUpgradeable {
bytes16 private constant _ALPHABET = "0123456789abcdef"; bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
/** /**
* @dev Converts a `uint256` to its ASCII `string` decimal representation. * @dev Converts a `uint256` to its ASCII `string` decimal representation.
...@@ -57,7 +57,7 @@ library StringsUpgradeable { ...@@ -57,7 +57,7 @@ library StringsUpgradeable {
buffer[0] = "0"; buffer[0] = "0";
buffer[1] = "x"; buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) { for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _ALPHABET[value & 0xf]; buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4; value >>= 4;
} }
require(value == 0, "Strings: hex length insufficient"); require(value == 0, "Strings: hex length insufficient");
......
...@@ -28,15 +28,13 @@ library ECDSAUpgradeable { ...@@ -28,15 +28,13 @@ library ECDSAUpgradeable {
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*/ */
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
// Divide the signature in r, s and v variables
bytes32 r;
bytes32 s;
uint8 v;
// Check the signature length // Check the signature length
// - case 65: r,s,v signature (standard) // - case 65: r,s,v signature (standard)
// - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._ // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._
if (signature.length == 65) { if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them // ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly. // currently is to use assembly.
assembly { assembly {
...@@ -44,25 +42,45 @@ library ECDSAUpgradeable { ...@@ -44,25 +42,45 @@ library ECDSAUpgradeable {
s := mload(add(signature, 0x40)) s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60))) v := byte(0, mload(add(signature, 0x60)))
} }
return recover(hash, v, r, s);
} else if (signature.length == 64) { } else if (signature.length == 64) {
bytes32 r;
bytes32 vs;
// ecrecover takes the signature parameters, and the only way to get them // ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly. // currently is to use assembly.
assembly { assembly {
let vs := mload(add(signature, 0x40))
r := mload(add(signature, 0x20)) r := mload(add(signature, 0x20))
s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) vs := mload(add(signature, 0x40))
v := add(shr(255, vs), 27)
} }
return recover(hash, r, vs);
} else { } else {
revert("ECDSA: invalid signature length"); revert("ECDSA: invalid signature length");
} }
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*
* _Available since v4.2._
*/
function recover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address) {
bytes32 s;
uint8 v;
assembly {
s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
v := add(shr(255, vs), 27)
}
return recover(hash, v, r, s); return recover(hash, v, r, s);
} }
/** /**
* @dev Overload of {ECDSA-recover} that receives the `v`, * @dev Overload of {ECDSA-recover} that receives the `v`, `r` and `s` signature fields separately.
* `r` and `s` signature fields separately.
*/ */
function recover( function recover(
bytes32 hash, bytes32 hash,
......
...@@ -64,10 +64,10 @@ abstract contract EIP712Upgradeable is Initializable { ...@@ -64,10 +64,10 @@ abstract contract EIP712Upgradeable is Initializable {
function _buildDomainSeparator( function _buildDomainSeparator(
bytes32 typeHash, bytes32 typeHash,
bytes32 name, bytes32 nameHash,
bytes32 version bytes32 versionHash
) private view returns (bytes32) { ) private view returns (bytes32) {
return keccak256(abi.encode(typeHash, name, version, block.chainid, address(this))); return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));
} }
/** /**
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
"release": "scripts/release/release.sh", "release": "scripts/release/release.sh",
"version": "scripts/release/version.sh", "version": "scripts/release/version.sh",
"test": "hardhat test", "test": "hardhat test",
"test:inheritance": "node scripts/inheritanceOrdering artifacts/build-info/*",
"gas-report": "env ENABLE_GAS_REPORT=true npm run test" "gas-report": "env ENABLE_GAS_REPORT=true npm run test"
}, },
"repository": { "repository": {
...@@ -65,6 +66,7 @@ ...@@ -65,6 +66,7 @@
"eth-sig-util": "^3.0.0", "eth-sig-util": "^3.0.0",
"ethereumjs-util": "^7.0.7", "ethereumjs-util": "^7.0.7",
"ethereumjs-wallet": "^1.0.1", "ethereumjs-wallet": "^1.0.1",
"graphlib": "^2.1.8",
"hardhat": "^2.0.6", "hardhat": "^2.0.6",
"hardhat-gas-reporter": "^1.0.4", "hardhat-gas-reporter": "^1.0.4",
"keccak256": "^1.0.2", "keccak256": "^1.0.2",
...@@ -72,11 +74,11 @@ ...@@ -72,11 +74,11 @@
"lodash.zip": "^4.2.0", "lodash.zip": "^4.2.0",
"merkletreejs": "^0.2.13", "merkletreejs": "^0.2.13",
"micromatch": "^4.0.2", "micromatch": "^4.0.2",
"mocha": "^8.0.1",
"prettier": "^2.3.0", "prettier": "^2.3.0",
"prettier-plugin-solidity": "^1.0.0-beta.13", "prettier-plugin-solidity": "^1.0.0-beta.13",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"solhint": "^3.3.6", "solhint": "^3.3.6",
"solidity-ast": "^0.4.25",
"solidity-coverage": "^0.7.11", "solidity-coverage": "^0.7.11",
"solidity-docgen": "^0.5.3", "solidity-docgen": "^0.5.3",
"web3": "^1.3.0", "web3": "^1.3.0",
......
const path = require('path');
const graphlib = require('graphlib');
const { findAll } = require('solidity-ast/utils');
const { _: artifacts } = require('yargs').argv;
for (const artifact of artifacts) {
const { output: solcOutput } = require(path.resolve(__dirname, '..', artifact));
const graph = new graphlib.Graph({ directed: true });
const names = {};
const linearized = [];
for (const source in solcOutput.contracts) {
for (const contractDef of findAll('ContractDefinition', solcOutput.sources[source].ast)) {
names[contractDef.id] = contractDef.name;
linearized.push(contractDef.linearizedBaseContracts);
contractDef.linearizedBaseContracts.forEach((c1, i, contracts) => contracts.slice(i + 1).forEach(c2 => {
graph.setEdge(c1, c2);
}));
}
}
graphlib.alg.findCycles(graph).forEach(([ c1, c2 ]) => {
console.log(`Conflict between ${names[c1]} and ${names[c2]} detected in the following dependency chains:`);
linearized
.filter(chain => chain.includes(parseInt(c1)) && chain.includes(parseInt(c2)))
.forEach(chain => {
const comp = chain.indexOf(c1) < chain.indexOf(c2) ? '>' : '<';
console.log(`- ${names[c1]} ${comp} ${names[c2]}: ${chain.reverse().map(id => names[id]).join(', ')}`);
});
process.exitCode = 1;
});
}
if (!process.exitCode) {
console.log('Contract ordering is consistent.');
}
...@@ -306,6 +306,9 @@ contract('ERC20Votes', function (accounts) { ...@@ -306,6 +306,9 @@ contract('ERC20Votes', function (accounts) {
expectEvent(receipt, 'Transfer', { from: holder, to: recipient, value: '1' }); expectEvent(receipt, 'Transfer', { from: holder, to: recipient, value: '1' });
expectEvent(receipt, 'DelegateVotesChanged', { delegate: holder, previousBalance: supply, newBalance: supply.subn(1) }); expectEvent(receipt, 'DelegateVotesChanged', { delegate: holder, previousBalance: supply, newBalance: supply.subn(1) });
const { logIndex: transferLogIndex } = receipt.logs.find(({ event }) => event == 'Transfer');
expect(receipt.logs.filter(({ event }) => event == 'DelegateVotesChanged').every(({ logIndex }) => transferLogIndex < logIndex)).to.be.equal(true);
this.holderVotes = supply.subn(1); this.holderVotes = supply.subn(1);
this.recipientVotes = '0'; this.recipientVotes = '0';
}); });
...@@ -317,6 +320,9 @@ contract('ERC20Votes', function (accounts) { ...@@ -317,6 +320,9 @@ contract('ERC20Votes', function (accounts) {
expectEvent(receipt, 'Transfer', { from: holder, to: recipient, value: '1' }); expectEvent(receipt, 'Transfer', { from: holder, to: recipient, value: '1' });
expectEvent(receipt, 'DelegateVotesChanged', { delegate: recipient, previousBalance: '0', newBalance: '1' }); expectEvent(receipt, 'DelegateVotesChanged', { delegate: recipient, previousBalance: '0', newBalance: '1' });
const { logIndex: transferLogIndex } = receipt.logs.find(({ event }) => event == 'Transfer');
expect(receipt.logs.filter(({ event }) => event == 'DelegateVotesChanged').every(({ logIndex }) => transferLogIndex < logIndex)).to.be.equal(true);
this.holderVotes = '0'; this.holderVotes = '0';
this.recipientVotes = '1'; this.recipientVotes = '1';
}); });
...@@ -330,6 +336,9 @@ contract('ERC20Votes', function (accounts) { ...@@ -330,6 +336,9 @@ contract('ERC20Votes', function (accounts) {
expectEvent(receipt, 'DelegateVotesChanged', { delegate: holder, previousBalance: supply, newBalance: supply.subn(1) }); expectEvent(receipt, 'DelegateVotesChanged', { delegate: holder, previousBalance: supply, newBalance: supply.subn(1) });
expectEvent(receipt, 'DelegateVotesChanged', { delegate: recipient, previousBalance: '0', newBalance: '1' }); expectEvent(receipt, 'DelegateVotesChanged', { delegate: recipient, previousBalance: '0', newBalance: '1' });
const { logIndex: transferLogIndex } = receipt.logs.find(({ event }) => event == 'Transfer');
expect(receipt.logs.filter(({ event }) => event == 'DelegateVotesChanged').every(({ logIndex }) => transferLogIndex < logIndex)).to.be.equal(true);
this.holderVotes = supply.subn(1); this.holderVotes = supply.subn(1);
this.recipientVotes = '1'; this.recipientVotes = '1';
}); });
......
const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers');
const { expect } = require('chai');
const { ZERO_ADDRESS, MAX_UINT256 } = constants;
const { shouldBehaveLikeERC20 } = require('../ERC20.behavior');
const ERC20Mock = artifacts.require('ERC20Mock');
const ERC20WrapperMock = artifacts.require('ERC20WrapperMock');
contract('ERC20', function (accounts) {
const [ initialHolder, recipient, anotherAccount ] = accounts;
const name = 'My Token';
const symbol = 'MTKN';
const initialSupply = new BN(100);
beforeEach(async function () {
this.underlying = await ERC20Mock.new(name, symbol, initialHolder, initialSupply);
this.token = await ERC20WrapperMock.new(this.underlying.address, `Wrapped ${name}`, `W${symbol}`);
});
afterEach(async function () {
expect(await this.underlying.balanceOf(this.token.address)).to.be.bignumber.equal(await this.token.totalSupply());
});
it('has a name', async function () {
expect(await this.token.name()).to.equal(`Wrapped ${name}`);
});
it('has a symbol', async function () {
expect(await this.token.symbol()).to.equal(`W${symbol}`);
});
it('has 18 decimals', async function () {
expect(await this.token.decimals()).to.be.bignumber.equal('18');
});
it('has underlying', async function () {
expect(await this.token.underlying()).to.be.bignumber.equal(this.underlying.address);
});
describe('deposit', function () {
it('valid', async function () {
await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder });
const { tx } = await this.token.depositFor(initialHolder, initialSupply, { from: initialHolder });
expectEvent.inTransaction(tx, this.underlying, 'Transfer', {
from: initialHolder,
to: this.token.address,
value: initialSupply,
});
expectEvent.inTransaction(tx, this.token, 'Transfer', {
from: ZERO_ADDRESS,
to: initialHolder,
value: initialSupply,
});
});
it('missing approval', async function () {
await expectRevert(
this.token.depositFor(initialHolder, initialSupply, { from: initialHolder }),
'ERC20: transfer amount exceeds allowance',
);
});
it('missing balance', async function () {
await this.underlying.approve(this.token.address, MAX_UINT256, { from: initialHolder });
await expectRevert(
this.token.depositFor(initialHolder, MAX_UINT256, { from: initialHolder }),
'ERC20: transfer amount exceeds balance',
);
});
it('to other account', async function () {
await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder });
const { tx } = await this.token.depositFor(anotherAccount, initialSupply, { from: initialHolder });
expectEvent.inTransaction(tx, this.underlying, 'Transfer', {
from: initialHolder,
to: this.token.address,
value: initialSupply,
});
expectEvent.inTransaction(tx, this.token, 'Transfer', {
from: ZERO_ADDRESS,
to: anotherAccount,
value: initialSupply,
});
});
});
describe('withdraw', function () {
beforeEach(async function () {
await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder });
await this.token.depositFor(initialHolder, initialSupply, { from: initialHolder });
});
it('missing balance', async function () {
await expectRevert(
this.token.withdrawTo(initialHolder, MAX_UINT256, { from: initialHolder }),
'ERC20: burn amount exceeds balance',
);
});
it('valid', async function () {
const value = new BN(42);
const { tx } = await this.token.withdrawTo(initialHolder, value, { from: initialHolder });
expectEvent.inTransaction(tx, this.underlying, 'Transfer', {
from: this.token.address,
to: initialHolder,
value: value,
});
expectEvent.inTransaction(tx, this.token, 'Transfer', {
from: initialHolder,
to: ZERO_ADDRESS,
value: value,
});
});
it('entire balance', async function () {
const { tx } = await this.token.withdrawTo(initialHolder, initialSupply, { from: initialHolder });
expectEvent.inTransaction(tx, this.underlying, 'Transfer', {
from: this.token.address,
to: initialHolder,
value: initialSupply,
});
expectEvent.inTransaction(tx, this.token, 'Transfer', {
from: initialHolder,
to: ZERO_ADDRESS,
value: initialSupply,
});
});
it('to other account', async function () {
const { tx } = await this.token.withdrawTo(anotherAccount, initialSupply, { from: initialHolder });
expectEvent.inTransaction(tx, this.underlying, 'Transfer', {
from: this.token.address,
to: anotherAccount,
value: initialSupply,
});
expectEvent.inTransaction(tx, this.token, 'Transfer', {
from: initialHolder,
to: ZERO_ADDRESS,
value: initialSupply,
});
});
});
describe('recover', function () {
it('nothing to recover', async function () {
await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder });
await this.token.depositFor(initialHolder, initialSupply, { from: initialHolder });
const { tx } = await this.token.recover(anotherAccount);
expectEvent.inTransaction(tx, this.token, 'Transfer', {
from: ZERO_ADDRESS,
to: anotherAccount,
value: '0',
});
});
it('something to recover', async function () {
await this.underlying.transfer(this.token.address, initialSupply, { from: initialHolder });
const { tx } = await this.token.recover(anotherAccount);
expectEvent.inTransaction(tx, this.token, 'Transfer', {
from: ZERO_ADDRESS,
to: anotherAccount,
value: initialSupply,
});
});
});
describe('erc20 behaviour', function () {
beforeEach(async function () {
await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder });
await this.token.depositFor(initialHolder, initialSupply, { from: initialHolder });
});
shouldBehaveLikeERC20('ERC20', initialSupply, initialHolder, recipient, anotherAccount);
});
});
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment