diff --git a/contracts/erc20/base/ERC20.sol b/contracts/erc20/base/ERC20.sol deleted file mode 100644 index 71dfb52..0000000 --- a/contracts/erc20/base/ERC20.sol +++ /dev/null @@ -1,235 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.9; - -import "./IERC20.sol"; -import "../../common/Initializable.sol"; - -/** - * @dev Implementation of the {IERC20} interface. - * - * This implementation is agnostic to the way tokens are created. This means - * that a supply mechanism has to be added in a derived contract using {_mint}. - * For a generic mechanism see {ERC20Mintable}. - * - * TIP: For a detailed writeup see our guide - * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How - * to implement supply mechanisms]. - * - * We have followed general OpenZeppelin guidelines: functions revert instead - * of returning `false` on failure. This behavior is nonetheless conventional - * and does not conflict with the expectations of ERC20 applications. - * - * Additionally, an {Approval} event is emitted on calls to {transferFrom}. - * This allows applications to reconstruct the allowance for all accounts just - * by listening to said events. Other implementations of the EIP may not emit - * these events, as it isn't required by the specification. - * - * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} - * functions have been added to mitigate the well-known issues around setting - * allowances. See {IERC20-approve}. - */ -contract ERC20 is Initializable, IERC20 { - mapping(address => uint256) private _balances; - - mapping(address => mapping(address => uint256)) private _allowances; - - uint256 private _totalSupply; - - /** - * @dev See {IERC20-totalSupply}. - */ - function totalSupply() public view returns (uint256) { - return _totalSupply; - } - - /** - * @dev See {IERC20-balanceOf}. - */ - function balanceOf(address account) public view returns (uint256) { - return _balances[account]; - } - - /** - * @dev See {IERC20-transfer}. - * - * Requirements: - * - * - `recipient` cannot be the zero address. - * - the caller must have a balance of at least `amount`. - */ - function transfer(address recipient, uint256 amount) public returns (bool) { - _transfer(msg.sender, recipient, amount); - return true; - } - - /** - * @dev See {IERC20-allowance}. - */ - function allowance(address owner, address spender) public view returns (uint256) { - return _allowances[owner][spender]; - } - - /** - * @dev See {IERC20-approve}. - * - * Requirements: - * - * - `spender` cannot be the zero address. - */ - function approve(address spender, uint256 amount) public returns (bool) { - _approve(msg.sender, spender, amount); - return true; - } - - /** - * @dev See {IERC20-transferFrom}. - * - * Emits an {Approval} event indicating the updated allowance. This is not - * required by the EIP. See the note at the beginning of {ERC20}; - * - * Requirements: - * - `sender` and `recipient` cannot be the zero address. - * - `sender` must have a balance of at least `amount`. - * - the caller must have allowance for `sender`'s tokens of at least - * `amount`. - */ - function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) { - _transfer(sender, recipient, amount); - require(amount <= _allowances[sender][msg.sender], "ERC20: transfer amount exceeds allowance"); - _approve(sender, msg.sender, _allowances[sender][msg.sender] - amount); - return true; - } - - /** - * @dev Atomically increases the allowance granted to `spender` by the caller. - * - * This is an alternative to {approve} that can be used as a mitigation for - * problems described in {IERC20-approve}. - * - * Emits an {Approval} event indicating the updated allowance. - * - * Requirements: - * - * - `spender` cannot be the zero address. - */ - function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { - _approve(msg.sender, spender, _allowances[msg.sender][spender] + addedValue); - return true; - } - - /** - * @dev Atomically decreases the allowance granted to `spender` by the caller. - * - * This is an alternative to {approve} that can be used as a mitigation for - * problems described in {IERC20-approve}. - * - * Emits an {Approval} event indicating the updated allowance. - * - * Requirements: - * - * - `spender` cannot be the zero address. - * - `spender` must have allowance for the caller of at least - * `subtractedValue`. - */ - function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { - require(subtractedValue <= _allowances[msg.sender][spender], "ERC20: decreased allowance below zero"); - _approve(msg.sender, spender, _allowances[msg.sender][spender] - subtractedValue); - return true; - } - - /** - * @dev Moves tokens `amount` from `sender` to `recipient`. - * - * This is internal function is equivalent to {transfer}, and can be used to - * e.g. implement automatic token fees, slashing mechanisms, etc. - * - * Emits a {Transfer} event. - * - * Requirements: - * - * - `sender` cannot be the zero address. - * - `recipient` cannot be the zero address. - * - `sender` must have a balance of at least `amount`. - */ - function _transfer(address sender, address recipient, uint256 amount) internal { - require(sender != address(0), "ERC20: transfer from the zero address"); - require(recipient != address(0), "ERC20: transfer to the zero address"); - - require(_balances[sender] >= amount, "ERC20: transfer amount exceeds balance"); - _balances[sender] = _balances[sender] - amount; - _balances[recipient] = _balances[recipient] + amount; - emit Transfer(sender, recipient, amount); - } - - /** @dev Creates `amount` tokens and assigns them to `account`, increasing - * the total supply. - * - * Emits a {Transfer} event with `from` set to the zero address. - * - * Requirements - * - * - `to` cannot be the zero address. - */ - function _mint(address account, uint256 amount) internal { - require(account != address(0), "ERC20: mint to the zero address"); - - _totalSupply = _totalSupply + amount; - _balances[account] = _balances[account] + amount; - emit Transfer(address(0), account, amount); - } - - /** - * @dev Destroys `amount` tokens from `account`, reducing the - * total supply. - * - * Emits a {Transfer} event with `to` set to the zero address. - * - * Requirements - * - * - `account` cannot be the zero address. - * - `account` must have at least `amount` tokens. - */ - function _burn(address account, uint256 amount) internal { - require(account != address(0), "ERC20: burn from the zero address"); - - require(_balances[account] >= amount, "ERC20: burn amount exceeds balance"); - _balances[account] = _balances[account] - amount; - _totalSupply = _totalSupply - amount; - emit Transfer(account, address(0), amount); - } - - /** - * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. - * - * This is internal function is equivalent to `approve`, and can be used to - * e.g. set automatic allowances for certain subsystems, etc. - * - * Emits an {Approval} event. - * - * Requirements: - * - * - `owner` cannot be the zero address. - * - `spender` cannot be the zero address. - */ - function _approve(address owner, address spender, uint256 amount) internal { - require(owner != address(0), "ERC20: approve from the zero address"); - require(spender != address(0), "ERC20: approve to the zero address"); - - _allowances[owner][spender] = amount; - emit Approval(owner, spender, amount); - } - - /** - * @dev Destroys `amount` tokens from `account`.`amount` is then deducted - * from the caller's allowance. - * - * See {_burn} and {_approve}. - */ - function _burnFrom(address account, uint256 amount) internal { - _burn(account, amount); - require(amount <= _allowances[account][msg.sender], "ERC20: burn amount exceeds allowance"); - _approve(account, msg.sender, _allowances[account][msg.sender] - amount); - } - - uint256[50] private ______gap; -} diff --git a/contracts/erc20/base/ERC20Burnable.sol b/contracts/erc20/base/ERC20Burnable.sol deleted file mode 100644 index 9b5aa0f..0000000 --- a/contracts/erc20/base/ERC20Burnable.sol +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.9; - -import "./ERC20.sol"; - -/** - * @title Burnable Token - * @dev Token that can be irreversibly burned (destroyed). - */ -contract ERC20Burnable is ERC20 { - /** - * @dev Burns a specific amount of tokens. - * @param value The amount of token to be burned. - */ - function burn(uint256 value) public { - _burn(msg.sender, value); - } - - /** - * @dev Burns a specific amount of tokens from the target address and decrements allowance - * @param from address The address which you want to send tokens from - * @param value uint256 The amount of token to be burned - */ - function burnFrom(address from, uint256 value) public { - _burnFrom(from, value); - } -} diff --git a/contracts/erc20/base/ERC20Detailed.sol b/contracts/erc20/base/ERC20Detailed.sol deleted file mode 100644 index 1380dcf..0000000 --- a/contracts/erc20/base/ERC20Detailed.sol +++ /dev/null @@ -1,58 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.9; - -import "../../common/Initializable.sol"; -import {ERC20} from "./ERC20.sol"; - -/** - * @dev Optional functions from the ERC20 standard. - */ -contract ERC20Detailed is ERC20 { - string private _name; - string private _symbol; - uint8 private _decimals; - - /** - * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of - * these values are immutable: they can only be set once during - * construction. - */ - function initialize(string memory tokenName, string memory tokenSymbol, uint8 tokenDecimals) internal initializer { - _name = tokenName; - _symbol = tokenSymbol; - _decimals = tokenDecimals; - } - - /** - * @dev Returns the name of the token. - */ - function name() public view returns (string memory) { - return _name; - } - - /** - * @dev Returns the symbol of the token, usually a shorter version of the - * name. - */ - function symbol() public view returns (string memory) { - return _symbol; - } - - /** - * @dev Returns the number of decimals used to get its user representation. - * For example, if `decimals` equals `2`, a balance of `505` tokens should - * be displayed to a user as `5,05` (`505 / 10 ** 2`). - * - * Tokens usually opt for a value of 18, imitating the relationship between - * Ether and Wei. - * - * NOTE: This information is only used for _display_ purposes: it in - * no way affects any of the arithmetic of the contract, including - * {IERC20-balanceOf} and {IERC20-transfer}. - */ - function decimals() public view returns (uint8) { - return _decimals; - } - - uint256[50] private ______gap; -} diff --git a/contracts/erc20/base/ERC20Mintable.sol b/contracts/erc20/base/ERC20Mintable.sol deleted file mode 100644 index 63981be..0000000 --- a/contracts/erc20/base/ERC20Mintable.sol +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.9; - -import "./ERC20.sol"; -import "./MinterRole.sol"; - -/** - * @title ERC20Mintable - * @dev ERC20 minting logic - */ -contract ERC20Mintable is ERC20, MinterRole { - event MintingFinished(); - - bool private _mintingFinished = false; - - modifier onlyBeforeMintingFinished() { - require(!_mintingFinished); - _; - } - - /** - * @return true if the minting is finished. - */ - function mintingFinished() public view returns (bool) { - return _mintingFinished; - } - - /** - * @dev Function to mint tokens - * @param to The address that will receive the minted tokens. - * @param amount The amount of tokens to mint. - * @return A boolean that indicates if the operation was successful. - */ - function mint(address to, uint256 amount) public onlyMinter onlyBeforeMintingFinished returns (bool) { - _mint(to, amount); - return true; - } - - /** - * @dev Function to stop minting new tokens. - * @return True if the operation was successful. - */ - function finishMinting() public onlyMinter onlyBeforeMintingFinished returns (bool) { - _mintingFinished = true; - emit MintingFinished(); - return true; - } -} diff --git a/contracts/erc20/base/IERC20.sol b/contracts/erc20/base/IERC20.sol deleted file mode 100644 index 5fbe198..0000000 --- a/contracts/erc20/base/IERC20.sol +++ /dev/null @@ -1,77 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED - -pragma solidity ^0.8.9; - -/** - * @dev Interface of the ERC20 standard as defined in the EIP. - */ -interface IERC20 { - /** - * @dev Returns the amount of tokens in existence. - */ - function totalSupply() external view returns (uint256); - - /** - * @dev Returns the amount of tokens owned by `account`. - */ - function balanceOf(address account) external view returns (uint256); - - /** - * @dev Moves `amount` tokens from the caller's account to `recipient`. - * - * Returns a boolean value indicating whether the operation succeeded. - * - * Emits a {Transfer} event. - */ - function transfer(address recipient, uint256 amount) external returns (bool); - - /** - * @dev Returns the remaining number of tokens that `spender` will be - * allowed to spend on behalf of `owner` through {transferFrom}. This is - * zero by default. - * - * This value changes when {approve} or {transferFrom} are called. - */ - function allowance(address owner, address spender) external view returns (uint256); - - /** - * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. - * - * Returns a boolean value indicating whether the operation succeeded. - * - * IMPORTANT: Beware that changing an allowance with this method brings the risk - * that someone may use both the old and the new allowance by unfortunate - * transaction ordering. One possible solution to mitigate this race - * condition is to first reduce the spender's allowance to 0 and set the - * desired value afterwards: - * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 - * - * Emits an {Approval} event. - */ - function approve(address spender, uint256 amount) external returns (bool); - - /** - * @dev Moves `amount` tokens from `sender` to `recipient` using the - * allowance mechanism. `amount` is then deducted from the caller's - * allowance. - * - * Returns a boolean value indicating whether the operation succeeded. - * - * Emits a {Transfer} event. - */ - function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); - - /** - * @dev Emitted when `value` tokens are moved from one account (`from`) to - * another (`to`). - * - * Note that `value` may be zero. - */ - event Transfer(address indexed from, address indexed to, uint256 value); - - /** - * @dev Emitted when the allowance of a `spender` for an `owner` is set by - * a call to {approve}. `value` is the new allowance. - */ - event Approval(address indexed owner, address indexed spender, uint256 value); -} diff --git a/contracts/erc20/base/MinterRole.sol b/contracts/erc20/base/MinterRole.sol deleted file mode 100644 index 627a786..0000000 --- a/contracts/erc20/base/MinterRole.sol +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.9; - -import "./Roles.sol"; - -contract MinterRole { - using Roles for Roles.Role; - - event MinterAdded(address indexed account); - event MinterRemoved(address indexed account); - - Roles.Role private minters; - - modifier onlyMinter() { - require(isMinter(msg.sender)); - _; - } - - function isMinter(address account) public view returns (bool) { - return minters.has(account); - } - - function renounceMinter() public { - minters.remove(msg.sender); - } - - function _removeMinter(address account) internal { - minters.remove(account); - emit MinterRemoved(account); - } - - function _addMinter(address account) internal { - minters.add(account); - emit MinterAdded(account); - } - - uint256[50] private ______gap; -} diff --git a/contracts/erc20/base/Roles.sol b/contracts/erc20/base/Roles.sol deleted file mode 100644 index 77bea09..0000000 --- a/contracts/erc20/base/Roles.sol +++ /dev/null @@ -1,37 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.9; - -/** - * @title Roles - * @dev Library for managing addresses assigned to a Role. - */ -library Roles { - struct Role { - mapping(address => bool) bearer; - } - - /** - * @dev give an account access to this role - */ - function add(Role storage role, address account) internal { - require(account != address(0)); - role.bearer[account] = true; - } - - /** - * @dev remove an account's access to this role - */ - function remove(Role storage role, address account) internal { - require(account != address(0)); - role.bearer[account] = false; - } - - /** - * @dev check if an account has this role - * @return bool - */ - function has(Role storage role, address account) internal view returns (bool) { - require(account != address(0)); - return role.bearer[account]; - } -} diff --git a/contracts/sfc/SFC.sol b/contracts/sfc/SFC.sol index eff0b6c..0f7e31d 100644 --- a/contracts/sfc/SFC.sol +++ b/contracts/sfc/SFC.sol @@ -75,6 +75,10 @@ contract SFC is SFCBase, Version { return getEpochSnapshot[epoch].offlineBlocks[validatorID]; } + function getEpochEndBlock(uint256 epoch) public view returns (uint256) { + return getEpochSnapshot[epoch].endBlock; + } + function rewardsStash(address delegator, uint256 validatorID) public view returns (uint256) { Rewards memory stash = _rewardsStash[delegator][validatorID]; return stash.lockupBaseReward + stash.lockupExtraReward + stash.unlockedReward; @@ -361,6 +365,7 @@ contract SFC is SFCBase, Version { currentSealedEpoch = currentEpoch(); snapshot.endTime = _now(); + snapshot.endBlock = block.number; snapshot.baseRewardPerSecond = c.baseRewardPerSecond(); snapshot.totalSupply = totalSupply; } diff --git a/contracts/sfc/SFCI.sol b/contracts/sfc/SFCI.sol index 40d90f2..205fff2 100644 --- a/contracts/sfc/SFCI.sol +++ b/contracts/sfc/SFCI.sol @@ -44,6 +44,7 @@ interface SFCI { view returns ( uint256 endTime, + uint256 endBlock, uint256 epochFee, uint256 totalBaseRewardWeight, uint256 totalTxRewardWeight, @@ -137,6 +138,8 @@ interface SFCI { function getEpochOfflineBlocks(uint256 epoch, uint256 validatorID) external view returns (uint256); + function getEpochEndBlock(uint256 epoch) external view returns (uint256); + function rewardsStash(address delegator, uint256 validatorID) external view returns (uint256); function getLockedStake(address delegator, uint256 toValidatorID) external view returns (uint256); diff --git a/contracts/sfc/SFCState.sol b/contracts/sfc/SFCState.sol index ec74fdd..313dc39 100644 --- a/contracts/sfc/SFCState.sol +++ b/contracts/sfc/SFCState.sol @@ -71,6 +71,7 @@ contract SFCState is Initializable, Ownable { mapping(uint256 => uint256) offlineBlocks; uint256[] validatorIDs; uint256 endTime; + uint256 endBlock; uint256 epochFee; uint256 totalBaseRewardWeight; uint256 totalTxRewardWeight; diff --git a/contracts/test/UnitTestSFC.sol b/contracts/test/UnitTestSFC.sol index 88374bb..263d8db 100644 --- a/contracts/test/UnitTestSFC.sol +++ b/contracts/test/UnitTestSFC.sol @@ -120,6 +120,7 @@ interface SFCUnitTestI { view returns ( uint256 endTime, + uint256 endBlock, uint256 epochFee, uint256 totalBaseRewardWeight, uint256 totalTxRewardWeight, @@ -215,6 +216,8 @@ interface SFCUnitTestI { function getEpochOfflineBlocks(uint256 epoch, uint256 validatorID) external view returns (uint256); + function getEpochEndBlock(uint256 epoch) external view returns (uint256); + function rewardsStash(address delegator, uint256 validatorID) external view returns (uint256); function getLockedStake(address delegator, uint256 toValidatorID) external view returns (uint256); diff --git a/test/SFC.ts b/test/SFC.ts index d18df86..d21cc0a 100644 --- a/test/SFC.ts +++ b/test/SFC.ts @@ -414,6 +414,16 @@ describe('SFC', () => { expect(await this.sfc.currentEpoch.call()).to.equal(6); expect(await this.sfc.currentSealedEpoch()).to.equal(5); }); + + it('Should succeed and return endBlock', async function () { + const epochNumber = await this.sfc.currentEpoch(); + await this.sfc.enableNonNodeCalls(); + await this.sfc.sealEpoch([100, 101, 102], [100, 101, 102], [100, 101, 102], [100, 101, 102], 0); + const lastBlock = await ethers.provider.getBlockNumber(); + // endBlock is on second position + expect((await this.sfc.getEpochSnapshot(epochNumber))[1]).to.equal(lastBlock); + expect(await this.sfc.getEpochEndBlock(epochNumber)).to.equal(lastBlock); + }); }); });