From 300a0f1ed77d26bce46b46c4b0566f4b2725a3b7 Mon Sep 17 00:00:00 2001 From: sudeepjc <52829351+sudeepjc@users.noreply.github.com> Date: Wed, 9 Dec 2020 15:02:50 +0530 Subject: [PATCH] Update FlattenedRigelToken.sol --- FlattenedRigelToken.sol | 660 ++++++++++++++-------------------------- 1 file changed, 234 insertions(+), 426 deletions(-) diff --git a/FlattenedRigelToken.sol b/FlattenedRigelToken.sol index 3bf6f56..bd39efd 100644 --- a/FlattenedRigelToken.sol +++ b/FlattenedRigelToken.sol @@ -1,6 +1,5 @@ -// File: @openzeppelin/contracts/GSN/Context.sol - // SPDX-License-Identifier: MIT +// File: github.com/OpenZeppelin/openzeppelin-contracts/blob/master//contracts/GSN/Context.sol pragma solidity >=0.6.0 <0.8.0; @@ -25,87 +24,7 @@ abstract contract Context { } } -// File: @openzeppelin/contracts/token/ERC20/IERC20.sol - - -pragma solidity >=0.6.0 <0.8.0; - -/** - * @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); -} - -// File: @openzeppelin/contracts/math/SafeMath.sol - +// File: github.com/OpenZeppelin/openzeppelin-contracts/blob/master//contracts/math/SafeMath.sol pragma solidity >=0.6.0 <0.8.0; @@ -265,63 +184,147 @@ library SafeMath { } } -// File: @openzeppelin/contracts/token/ERC20/ERC20.sol +// File: github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol pragma solidity >=0.6.0 <0.8.0; +/** + * @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); +} + +// File: browser/RigelToken.sol + +pragma solidity 0.6.12; + +contract Owned is Context { + address public _owner; + address public _newOwner; + + event OwnershipTransferred(address indexed _from, address indexed _to); + + modifier onlyOwner { + require(_msgSender() == _owner,"RigelToken: Only the Owner of the contract can perform this task"); + _; + } + + function transferOwnership(address newOwner) public onlyOwner { + _newOwner = newOwner; + } + + function acceptOwnership() public { + require(_msgSender() == _newOwner,"RigelToken: Token Contract Ownership has not been set for the address"); + emit OwnershipTransferred(_owner, _newOwner); + _owner = _newOwner; + _newOwner = address(0); + } +} /** * @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 {ERC20PresetMinterPauser}. - * - * 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 Context, IERC20 { + contract RigelToken is IERC20, Owned { + using SafeMath for uint256; + + mapping (address => uint256) private _balances; // Total balance per address (locked + unlocked) - mapping (address => uint256) private _balances; + mapping (address => uint256) private _unlockedTokens; // Unlocked Tokens, available for transfer mapping (address => mapping (address => uint256)) private _allowances; + struct LockRecord { + uint256 lockingPeriod; + uint256 tokens; + bool isUnlocked; + } + + mapping(address => LockRecord[]) records; // Record of Locking periods and tokens per address + uint256 private _totalSupply; string private _name; string private _symbol; uint8 private _decimals; - /** - * @dev Sets the values for {name} and {symbol}, initializes {decimals} with - * a default value of 18. - * - * To select a different value for {decimals}, use {_setupDecimals}. - * - * All three of these values are immutable: they can only be set once during - * construction. - */ - constructor (string memory name_, string memory symbol_) public { - _name = name_; - _symbol = symbol_; + constructor( address owner ) public { + _name = "RigelToken"; + _symbol = "RGP"; _decimals = 18; + _totalSupply = 20000000 * (10 ** 18); + _owner = owner; + _balances[ _owner ] = _totalSupply; + emit Transfer( address(0), _owner, _totalSupply ); } /** @@ -343,14 +346,6 @@ contract ERC20 is Context, IERC20 { * @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. This is the value {ERC20} uses, unless {_setupDecimals} is - * called. - * - * 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; @@ -378,15 +373,30 @@ contract ERC20 is Context, IERC20 { * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ - function transfer(address recipient, uint256 amount) public virtual override returns (bool) { - _transfer(_msgSender(), recipient, amount); + function transfer(address recipient, uint256 amount) public override returns (bool) { + + require(recipient != address(0),"RigelToken: Cannot have recipient as zero address"); + require(_balances[_msgSender()] >= amount,"RigelToken: Insufficient Balance" ); + require(_balances[recipient] + amount >= _balances[recipient],"RigelToken: Balance check failed"); + + // update the unlocked tokens based on time + if(_msgSender() != _owner){ + _updateUnLockedTokens(_msgSender(), amount); + _unlockedTokens[_msgSender()] = _unlockedTokens[_msgSender()].sub(amount); + _unlockedTokens[recipient] = _unlockedTokens[recipient].add(amount); + } + + _balances[_msgSender()] = _balances[_msgSender()].sub(amount); + _balances[recipient] = _balances[recipient].add(amount); + + emit Transfer(_msgSender(),recipient,amount); return true; } /** * @dev See {IERC20-allowance}. */ - function allowance(address owner, address spender) public view virtual override returns (uint256) { + function allowance(address owner, address spender) public view override returns (uint256) { return _allowances[owner][spender]; } @@ -397,8 +407,13 @@ contract ERC20 is Context, IERC20 { * * - `spender` cannot be the zero address. */ - function approve(address spender, uint256 amount) public virtual override returns (bool) { - _approve(_msgSender(), spender, amount); + function approve(address spender, uint256 amount) public override returns (bool) { + + require(spender != address(0), "RigelToken: approve to the zero address"); + + _allowances[_msgSender()][spender] = amount; + emit Approval(_msgSender(), spender, amount); + return true; } @@ -415,302 +430,27 @@ contract ERC20 is Context, IERC20 { * - the caller must have allowance for ``sender``'s tokens of at least * `amount`. */ - function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) { - _transfer(sender, recipient, amount); - _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); - return true; - } + function transferFrom(address sender, address recipient, uint256 amount) public override returns (bool) { - /** - * @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 virtual returns (bool) { - _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); - return true; - } + require(recipient != address(0),"RigelToken: Cannot have recipient as zero address"); + require(sender != address(0),"RigelToken: Cannot have sender as zero address"); + require(_balances[sender] >= amount,"RigelToken: Insufficient Balance" ); + require(_balances[recipient] + amount >= _balances[recipient],"RigelToken: Balance check failed"); + require(amount <= _allowances[sender][_msgSender()],"RigelToken: Check for approved token count"); + + // update the unlocked tokens based on time - /** - * @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 virtual returns (bool) { - _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); - 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 virtual { - require(sender != address(0), "ERC20: transfer from the zero address"); - require(recipient != address(0), "ERC20: transfer to the zero address"); - - _beforeTokenTransfer(sender, recipient, amount); + if(_msgSender() != _owner){ + _updateUnLockedTokens(sender, amount); + _unlockedTokens[sender] = _unlockedTokens[sender].sub(amount); + _unlockedTokens[recipient] = _unlockedTokens[recipient].add(amount); + } - _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); + _balances[sender] = _balances[sender].sub(amount); _balances[recipient] = _balances[recipient].add(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 virtual { - require(account != address(0), "ERC20: mint to the zero address"); - - _beforeTokenTransfer(address(0), account, amount); - - _totalSupply = _totalSupply.add(amount); - _balances[account] = _balances[account].add(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 virtual { - require(account != address(0), "ERC20: burn from the zero address"); - - _beforeTokenTransfer(account, address(0), amount); - - _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); - _totalSupply = _totalSupply.sub(amount); - emit Transfer(account, address(0), amount); - } - - /** - * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. - * - * This 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 virtual { - 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 Sets {decimals} to a value other than the default one of 18. - * - * WARNING: This function should only be called from the constructor. Most - * applications that interact with token contracts will not expect - * {decimals} to ever change, and may work incorrectly if it does. - */ - function _setupDecimals(uint8 decimals_) internal { - _decimals = decimals_; - } - - /** - * @dev Hook that is called before any transfer of tokens. This includes - * minting and burning. - * - * Calling conditions: - * - * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens - * will be to transferred to `to`. - * - when `from` is zero, `amount` tokens will be minted for `to`. - * - when `to` is zero, `amount` of ``from``'s tokens will be 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 _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { } -} - -// File: @openzeppelin/contracts/token/ERC20/ERC20Burnable.sol - - -pragma solidity >=0.6.0 <0.8.0; + _allowances[sender][_msgSender()] = _allowances[sender][_msgSender()].sub(amount); - - -/** - * @dev Extension of {ERC20} that allows token holders to destroy both their own - * tokens and those that they have an allowance for, in a way that can be - * recognized off-chain (via event analysis). - */ -abstract contract ERC20Burnable is Context, ERC20 { - using SafeMath for uint256; - - /** - * @dev Destroys `amount` tokens from the caller. - * - * See {ERC20-_burn}. - */ - function burn(uint256 amount) public virtual { - _burn(_msgSender(), amount); - } - - /** - * @dev Destroys `amount` tokens from `account`, deducting from the caller's - * allowance. - * - * See {ERC20-_burn} and {ERC20-allowance}. - * - * Requirements: - * - * - the caller must have allowance for ``accounts``'s tokens of at least - * `amount`. - */ - function burnFrom(address account, uint256 amount) public virtual { - uint256 decreasedAllowance = allowance(account, _msgSender()).sub(amount, "ERC20: burn amount exceeds allowance"); - - _approve(account, _msgSender(), decreasedAllowance); - _burn(account, amount); - } -} - -// File: @openzeppelin/contracts/access/Ownable.sol - - -pragma solidity >=0.6.0 <0.8.0; - -/** - * @dev Contract module which provides a basic access control mechanism, where - * there is an account (an owner) that can be granted exclusive access to - * specific functions. - * - * By default, the owner account will be the one that deploys the contract. This - * can later be changed with {transferOwnership}. - * - * This module is used through inheritance. It will make available the modifier - * `onlyOwner`, which can be applied to your functions to restrict their use to - * the owner. - */ -abstract contract Ownable is Context { - address private _owner; - - event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); - - /** - * @dev Initializes the contract setting the deployer as the initial owner. - */ - constructor () internal { - address msgSender = _msgSender(); - _owner = msgSender; - emit OwnershipTransferred(address(0), msgSender); - } - - /** - * @dev Returns the address of the current owner. - */ - function owner() public view returns (address) { - return _owner; - } - - /** - * @dev Throws if called by any account other than the owner. - */ - modifier onlyOwner() { - require(_owner == _msgSender(), "Ownable: caller is not the owner"); - _; - } - - /** - * @dev Leaves the contract without owner. It will not be possible to call - * `onlyOwner` functions anymore. Can only be called by the current owner. - * - * NOTE: Renouncing ownership will leave the contract without an owner, - * thereby removing any functionality that is only available to the owner. - */ - function renounceOwnership() public virtual onlyOwner { - emit OwnershipTransferred(_owner, address(0)); - _owner = address(0); - } - - /** - * @dev Transfers ownership of the contract to a new account (`newOwner`). - * Can only be called by the current owner. - */ - function transferOwnership(address newOwner) public virtual onlyOwner { - require(newOwner != address(0), "Ownable: new owner is the zero address"); - emit OwnershipTransferred(_owner, newOwner); - _owner = newOwner; - } -} - -// File: contracts/RigelToken.sol - -pragma solidity ^0.6.0; - - - - - - - contract RigelToken is ERC20, ERC20Burnable, Ownable { - - - constructor() ERC20("RigelToken", "RGP") public { - uint256 totalSupply = 2000000 * (10**18); - _mint(msg.sender, totalSupply); - } - - /** - * @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 onlyOwner virtual override returns (bool) { - _transfer(_msgSender(), recipient, amount); + emit Transfer(sender,recipient,amount); return true; } @@ -720,9 +460,77 @@ pragma solidity ^0.6.0; * See {ERC20-_burn}. */ - function burn(uint256 amount) public onlyOwner virtual override{ - _burn(_msgSender(), amount); + function burn(uint256 amount) public onlyOwner { + + require(_msgSender() != address(0), "ERC20: burn from the zero address"); + + _balances[_msgSender()] = _balances[_msgSender()].sub(amount, "ERC20: burn amount exceeds balance"); + _totalSupply = _totalSupply.sub(amount); + emit Transfer(_msgSender(), address(0), amount); + } + + // ------------------------------------------------------------------------ + // Transfer the balance from token owner's _msgSender() to `to` _msgSender() + // - Owner's _msgSender() must have sufficient balance to transfer + // - 0 value transfers are allowed + // - takes in locking Period to lock the tokens to be used + // - if want to transfer without locking enter 0 in lockingPeriod argument + // ------------------------------------------------------------------------ + function distributeTokens(address to, uint tokens, uint256 lockingPeriod) onlyOwner public returns (bool success) { + // transfer tokens to the "to" address + transfer(to, tokens); + // if there is no lockingPeriod, add tokens to _unlockedTokens per address + if(lockingPeriod == 0) + _unlockedTokens[to] = _unlockedTokens[to].add(tokens); + // if there is a lockingPeriod, add tokens to record mapping + else + _addRecord(to, tokens, lockingPeriod); + return true; } - - + + // ------------------------------------------------------------------------ + // Adds record of addresses with locking period and tokens to lock + // ------------------------------------------------------------------------ + function _addRecord(address to, uint tokens, uint256 lockingPeriod) private { + records[to].push(LockRecord(lockingPeriod,tokens, false)); + } + + // ------------------------------------------------------------------------ + // Checks if there is required amount of unLockedTokens available + // ------------------------------------------------------------------------ + function _updateUnLockedTokens(address _from, uint tokens) private returns (bool success) { + // if _unlockedTokens are greater than "tokens" of "to", initiate transfer + if(_unlockedTokens[_from] >= tokens){ + return true; + } + // if _unlockedTokens are less than "tokens" of "to", update _unlockedTokens by checking record with "now" time + else{ + _updateRecord(_from); + // check if _unlockedTokens are greater than "token" of "to", initiate transfer + if(_unlockedTokens[_from] >= tokens){ + return true; + } + // otherwise revert + else{ + revert("RigelToken: Insufficient unlocked tokens"); + } + } + } + + // ------------------------------------------------------------------------ + // Unlocks the coins if lockingPeriod is expired + // ------------------------------------------------------------------------ + function _updateRecord(address account) private returns (bool success){ + LockRecord[] memory tempRecords = records[account]; + uint256 unlockedTokenCount = 0; + for(uint256 i=0; i < tempRecords.length; i++){ + if(tempRecords[i].lockingPeriod < now && tempRecords[i].isUnlocked == false){ + unlockedTokenCount = unlockedTokenCount.add(tempRecords[i].tokens); + tempRecords[i].isUnlocked = true; + records[account][i] = LockRecord(tempRecords[i].lockingPeriod, tempRecords[i].tokens, tempRecords[i].isUnlocked); + } + } + _unlockedTokens[account] = _unlockedTokens[account].add(unlockedTokenCount); + return true; + } }