Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- GnGToken
- Optimization enabled
- true
- Compiler version
- v0.8.17+commit.8df45f5f
- Optimization runs
- 200
- EVM Version
- default
- Verified at
- 2024-09-26T15:32:00.274407Z
Contract source code
// SPDX-License-Identifier: No License (None)
pragma solidity 0.8.17;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
}
abstract contract MinterSetup {
bool public setup_mode = true;
mapping (address => bool) public minters;
modifier onlyMinter()
{
require(minters[msg.sender], "Only minter is allowed to do this");
_;
}
modifier onlySetupMode()
{
require(setup_mode, "This is only allowed in setup mode");
_;
}
}
abstract contract IERC223Recipient {
/**
* @dev Standard ERC223 function that will handle incoming token transfers.
*
* @param _from Token sender address.
* @param _value Amount of tokens.
* @param _data Transaction metadata.
*/
function tokenReceived(address _from, uint _value, bytes memory _data) external virtual;
}
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC223 {
/**
* @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 Returns the amount of tokens owned by `account`.
*/
function decimals() external view returns (uint8);
/**
* @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);
function transfer(address recipient, uint256 amount, bytes calldata data) 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);
event TransferData(bytes);
/**
* @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);
}
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*/
function isContract(address account) internal view returns (bool) {
// According to EIP-1052, 0x0 is the value returned for not-yet created accounts
// and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
// for accounts without code, i.e. `keccak256('')`
bytes32 codehash;
bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
// solhint-disable-next-line no-inline-assembly
assembly { codehash := extcodehash(account) }
return (codehash != accountHash && codehash != 0x0);
}
}
/**
* @dev Implementation of the {IERC223} interface by @Dexaran. This contract
* is intended to be backwards compatible with {IERC20} and {transferFrom},
* {approve}, {increaseAllowance}, {decreaseAllowance} functions were
* implemented for compatibility purposes.
*
* 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}.
*/
contract ERC223 is IERC223, MinterSetup {
using Address for address;
mapping (address => uint256) private _balances;
mapping (address => mapping (address => uint256)) private _allowances;
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 new_name, string memory new_symbol) {
_name = new_name;
_symbol = new_symbol;
_decimals = 18;
}
function standard() public pure returns (string memory)
{
return "erc223";
}
/**
* @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. 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;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC223-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 virtual override returns (bool) {
_transfer(msg.sender, recipient, amount, new bytes(0));
return true;
}
/**
* @dev See {IERC223-transfer}.
*
* Requirements:
*
* - `recipient` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*
*/
function transfer(address recipient, uint256 amount, bytes calldata data) public virtual override returns (bool) {
_transfer(msg.sender, recipient, amount, data);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override 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 virtual override returns (bool) {
_transferFrom(sender, recipient, amount);
_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 virtual 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 virtual returns (bool) {
_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, bytes memory data) internal virtual {
require(sender != address(0), "ERC223: transfer from the zero address");
require(recipient != address(0), "ERC223: transfer to the zero address");
_beforeTokenTransfer(sender, recipient, amount);
_balances[sender] = _balances[sender] - amount;
_balances[recipient] = _balances[recipient] + amount;
if(recipient.isContract())
{
IERC223Recipient(recipient).tokenReceived(sender, amount, data);
}
emit Transfer(sender, recipient, amount);
emit TransferData(data);
}
function _transferFrom(address sender, address recipient, uint256 amount) internal virtual {
require(sender != address(0), "ERC223: transfer from the zero address");
require(recipient != address(0), "ERC223: transfer to the zero address");
_beforeTokenTransfer(sender, recipient, amount);
_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 virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
_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 virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
_balances[account] -= amount;
_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 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 { }
}
/**
* @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.
*/
contract Ownable {
address internal _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
/**
* @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 == msg.sender, "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) && newOwner != address(this), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
// GnG default ERC223 token.
contract GnGToken is ERC223("Games and Goblins token", "GnG"), Ownable {
function rescueERC20(address token, address to) external onlyOwner {
uint256 value = IERC223(token).balanceOf(address(this));
IERC223(token).transfer(to, value);
}
constructor() {
address msgSender = msg.sender;
_owner = msg.sender;
_mint(msg.sender, 500000000 * 10 ** 18);
emit OwnershipTransferred(address(0), msgSender);
}
function disableSetup() public onlyOwner onlySetupMode
{
setup_mode = false;
}
function getChainId() internal view returns (uint) {
uint256 chainId;
assembly { chainId := chainid() }
return chainId;
}
}
// This contract is a Test Pricefeed. It always returns fixed values
// but its ABI is similar to the real PriceFeed
// deploy on Callisto mainnet.
contract PriceFeed
{
// returns token price in USD with 18 decimals
function getPrice(address token) external view returns(uint256 price)
{
if(token==0x0000000000000000000000000000000000000001) return 3187227770000000; // CLO
if(token==0xeb5B7d171d00e4Df2b3185e1e27f9f1A447200eF) return 9604863230000000; // SOY
if(token==0x84a8509CbAa982A35fFbc3cd7c1eBbe9534b6C60) return 4756345080000000; // CLOE
}
}
contract ICO is IERC223Recipient, Ownable, ReentrancyGuard
{
bool public claiming_enabled = true;
uint256 public vesting_allocation;
string public contractName = "NOT INITIALIZED";
uint256 public min_purchase; // Minimum amount of GNG tokens that a user must purchase.
address public GnGToken_address;
uint256 public start_timestamp;
uint256 public end_timestamp;
address public priceFeed = 0x9bFc3046ea26f8B09D3E85bd22AEc96C80D957e3; // Price Feed oracle. Address is valid for CLO mainnet.
uint256 public tokenPricePer10000; // Price of 10000 GNG tokens in USD
// value 300 would mean that 1 GNG = 0.03 USD.
//address public admin = msg.sender; // This address can execute SETUP function of the contract and modify acceptable pairs
// it cannot access funds however.
uint256 public vesting_period_duration = 2592000; // 30 days in seconds.
uint256 public instant_delivery = 200; // % that will be delivered instantly upon completing the deposit
// to ICO contract. The value will be divided by 1000
// 200 is 20%. (200/1000 = 0.2);
//uint256 public vesting_period_percentage = 200; // % that will become available for claiming at each Vesting Period. Will be divided by 1000.
uint256 public vesting_periods_total = 6; // A total number of vesting periods. After that much rewards were claimed no vesting will be paid.
struct Purchase
{
uint256 amountGNG;
uint256 vesting_timestamp;
uint256 amount_per_period;
uint256 claims_count;
}
mapping (address => Purchase) public purchases;
// This modifier prevents purchases that can be made before or after the ICO dates of the contract.
// NOTE! this modifier allows the code of the function to execute first,
// therefore `owner` of the ICO contract will be able to deposit ERC223 GNG to the contract
// before the `ICO start date` and the `tokenReceived()` function will be invoked
// but it will end execution with `return` prior to the execution of the modifier code.
modifier ICOstarted()
{
_;
require(block.timestamp >= start_timestamp && block.timestamp <= end_timestamp, "Incorrect timing");
}
struct asset
{
// uint256 rate; // Determines how much GnG tokens a user will receive per 1000 "asset tokens" deposited.
// bool native_currency; // true for CLO, false for tokens.
address contract_address; // For tokens - address of the "asset token" contract.
// For CLO - 0x0000000000000000000000000000000000000001
string name; // Name of the accepted pair, for convenience purposes only.
}
mapping (uint256 => asset) public assets; // ID => asset_struct; ID = 0 is for native currency of the chain.
mapping (address => uint256) public asset_index; // address of token contract => ID of asset.
constructor() {
_owner = msg.sender;
assets[0].name = "Native";
assets[0].contract_address = 0x0000000000000000000000000000000000000001;
}
function _finalisePayment(uint256 _reward_amount, address _buyer) internal
{
uint256 _instant_delivery = _reward_amount * instant_delivery / 1000;
purchases[_buyer].amountGNG += (_reward_amount - _instant_delivery); // Increment by _reward_amount because it can be not the first purchase
// from this address.
// Save this values for recognition reasons only
// to record "initial vesting" amount of each user.
purchases[_buyer].vesting_timestamp = end_timestamp;
purchases[_buyer].amount_per_period += (_reward_amount - _instant_delivery) / vesting_periods_total;
vesting_allocation += (_reward_amount - _instant_delivery);
IERC223(GnGToken_address).transfer(_buyer, _instant_delivery);
}
function claim(address _receiver) public
{
require(claiming_enabled, "ICO: Claiming is disabled by the owner.");
require(purchases[_receiver].vesting_timestamp + vesting_period_duration < block.timestamp, "ICO: No vesting reward available for claiming.");
require(purchases[_receiver].claims_count < vesting_periods_total, "ICO: Total vesting reward is already claimed.");
uint256 _num_periods = (block.timestamp - purchases[_receiver].vesting_timestamp) / vesting_period_duration;
purchases[_receiver].vesting_timestamp += (_num_periods * vesting_period_duration);
if(purchases[_receiver].claims_count + _num_periods > vesting_periods_total)
{
_num_periods = vesting_periods_total - purchases[_receiver].claims_count;
purchases[_receiver].claims_count = vesting_periods_total;
}
else
{
purchases[_receiver].claims_count += _num_periods;
}
IERC223(GnGToken_address).transfer(_receiver, purchases[_receiver].amount_per_period * _num_periods);
}
// This function accepts NATIVE CURRENCY (CLO on Callisto chain),
// this function is used to purchase GNG tokens via CLO deposit.
receive() external payable ICOstarted() nonReentrant()
{
uint256 _GNG_balance = IERC223(GnGToken_address).balanceOf(address(this));
uint256 _price = PriceFeed(priceFeed).getPrice(0x0000000000000000000000000000000000000001);
require(_price != 0, "ICO: Price Feed error");
require(_GNG_balance - vesting_allocation > 1e18, "ICO: There are less than 1 GNG token in the contract. ICO is ended.");
require(msg.value >= 1e18, "ICO: Min CLO deposit criteria is not met");
uint256 _refund_amount = 0;
// User is buying GnG token and paying with a native currency.
//uint256 _reward = assets[0].rate * msg.value / 1000; // Old calculation function for manual price update version.
// `PriceFeedData/1e18 * msg.value / 1e18` ==>> This is value that was paid in USD
// `USD value / tokenPricePer10000 * 10000 * 1e18` ==>> this is final value of the tokens that will be paid respecting decimals
// since both PriceFeedData and GNG token have 18 decimals we will simply remove `/1e18` and `*1e18` from the equation.
uint256 _reward = _price * msg.value / tokenPricePer10000 * 10000 /1e18;
// Check edge cases
if(_reward > _GNG_balance - vesting_allocation)
{
uint256 _old_reward = _reward;
_reward = _GNG_balance - vesting_allocation;
uint256 _reward_overflow = _old_reward - _reward;
_refund_amount = (_reward_overflow * tokenPricePer10000 / 10000 ) * 1e18 / _price ;
}
require(_reward >= min_purchase, "ICO: Minimum purchase criteria is not met");
//IERC223(GnGToken_address).transfer(msg.sender, _reward);
_finalisePayment(_reward, msg.sender);
if(_refund_amount > 0)
{
payable(msg.sender).transfer(_refund_amount);
}
}
function buy(address _token_contract, // Address of the contract of the token that will be deposited as the payment.
uint256 _value_to_deposit) // How much tokens will be used to pay for acquiring tokens from ICO
// IMPORTANT! This is not the amount of tokens that the user will receive,
// this is the amount of token that the user will PAY.
// The amount must be >= approved amount.
external ICOstarted() nonReentrant()
{
uint256 _GNG_balance = IERC223(GnGToken_address).balanceOf(address(this));
uint256 _price = PriceFeed(priceFeed).getPrice(_token_contract);
require(_price != 0, "ICO: Price Feed does not contain info about this token.");
require(_GNG_balance - vesting_allocation > 1e18, "ICO: There are less than 1 GNG token in the contract. ICO is ended.");
require(asset_index[_token_contract] != 0, "ICO: Invalid asset deposit.");
require(_value_to_deposit >= 1e18, "ICO: Min ERC20 deposit criteria is not met");
uint256 _refund_amount = 0;
// PriceFeedData * _value_to_deposit / decimals ==>>
uint256 _reward = _price * _value_to_deposit / tokenPricePer10000 * 10000 /1e18;
// Check edge cases
if(_reward > _GNG_balance - vesting_allocation)
{
uint256 _old_reward = _reward;
_reward = _GNG_balance - vesting_allocation;
uint256 _reward_overflow = _old_reward - _reward;
//_refund_amount = _reward_overflow * 1000 / assets[asset_index[_token_contract]].rate; // Old calculation function
/// 200 * 1e18 / 10000 * 250 / PriceFeed * 1e18 * 1e18
_refund_amount = (_reward_overflow * tokenPricePer10000 / 10000 ) * 1e18 / _price;
}
IERC223(_token_contract).transferFrom(msg.sender, address(this), (_value_to_deposit - _refund_amount) );
require(_reward >= min_purchase, "ICO: Minimum purchase criteria is not met");
//IERC223(GnGToken_address).transfer(msg.sender, _reward);
_finalisePayment(_reward, msg.sender);
}
function tokenReceived(address _from, uint _value, bytes memory _data) external override ICOstarted() nonReentrant()
{
// Incoming transaction of a ERC223 token is handled here
// here `msg.sender` is the address of the token contract which is being deposited
// `msg.value` = 0
// `_from` is the address of the user who initiated the transfer
// `_value` is the amount of ERC223 tokens being deposited.
// Owner can deposit GNG token to the ICO contract and this function will be invoked.
require(_value >= 1e18, "ICO: Min ERC223 deposit criteria is not met");
uint256 _refund_amount = 0;
if(msg.sender == GnGToken_address && _from == owner())
{
// Deposit of GnG token by the owner. Do nothing and accept the deposit.
// Stop execution preventing the execution of the ICOstarted() modifier.
return;
}
if(asset_index[msg.sender] != 0)
{
uint256 _GNG_balance = IERC223(GnGToken_address).balanceOf(address(this));
uint256 _price = PriceFeed(priceFeed).getPrice(msg.sender);
require(_price != 0, "ICO: Price Feed does not contain info about this token.");
require(_GNG_balance - vesting_allocation > 1e18, "ICO: There are less than 1 GNG token in the contract. ICO is ended.");
// User is buying GnG token and paying with a token from "acceptable tokens list".
//uint256 _reward = assets[asset_index[msg.sender]].rate * _value / 1000; // Old calculation function.
uint256 _reward = _price * _value / tokenPricePer10000 * 10000 /1e18;
// Check edge cases
if(_reward > _GNG_balance - vesting_allocation)
{
uint256 _old_reward = _reward;
_reward = _GNG_balance - vesting_allocation;
uint256 _reward_overflow = _old_reward - _reward;
//_refund_amount = (_reward_overflow / 10000 * tokenPricePer10000) / PriceFeed(priceFeed).getPrice(msg.sender) * 1e18;
_refund_amount = (_reward_overflow * tokenPricePer10000 / 10000 ) * 1e18 / _price ;
}
require(_reward >= min_purchase, "ICO: Minimum purchase criteria is not met");
//IERC223(GnGToken_address).transfer(_from, _reward);
_finalisePayment(_reward, _from);
if(_refund_amount > 0)
{
IERC223(msg.sender).transfer(_from, _refund_amount);
}
}
else
{
// User is depositing a token which is not in "acceptable tokens list"
// Revert transaction and stop the execution.
revert();
}
}
// Function that returns info about acceptable payment options
// _id = 0 is for native currency (CLO).
function get_depositable_asset(uint256 _id) external view returns (string memory name, uint256 rate, address token_contract)
{
return (assets[_id].name, PriceFeed(priceFeed).getPrice(assets[_id].contract_address), assets[_id].contract_address);
}
// This function serves the purpose of prediction of the reward that a user can acquire by depositing
// `_amount_of_payment` quantity of tokens `_token_address` to the contract
function get_reward(uint256 _amount_of_payment, address _token_address) external view returns (uint256 reward, string memory name)
{
/// 3176591470000000 /1e18 * 200 * 1e18 / 200 * 10000
uint256 _reward = PriceFeed(priceFeed).getPrice(_token_address) * _amount_of_payment * 10000 / tokenPricePer10000/ 1e18;
return (_reward, assets[asset_index[_token_address]].name);
}
function modify_asset(uint256 _id, address _token_contract, string memory _name) external onlyOwner
{
require (_token_contract != address(0));
assets[_id].contract_address = _token_contract;
assets[_id].name = _name;
asset_index[_token_contract] = _id;
}
// Special emergency function to rescue stuck ERC20 tokens that were accidentally deposited.
function ERC20Rescue(address erc20token) public onlyOwner
{
IERC223(erc20token).transfer(owner(), IERC223(erc20token).balanceOf(address(this)));
}
// Function that allows owner to withdraw tokens.
function withdraw(uint256 _id) public onlyOwner
{
if(_id == 0)
{
// Withdrawing native currency.
payable(owner()).transfer(address(this).balance);
}
else
{
// Withdrawing a token.
IERC223( assets[_id].contract_address ).transfer(owner(), IERC223( assets[_id].contract_address ).balanceOf( address(this) ));
}
}
// Function that allows owner to withdraw tokens.
function withdrawGNG(uint256 _amount) public onlyOwner
{
IERC223(GnGToken_address).transfer(owner(), _amount );
}
function setup_contract(address _GNG, uint256 _min_purchase, uint256 _start_UNIX, uint256 _end_UNIX, address _priceFeed, uint256 _targetPrice, string calldata _name) public onlyOwner
{
require(_GNG != address(0), "Invalid GNG address");
require(_priceFeed != address(0), "Invalid PriceFeed address");
GnGToken_address = _GNG;
start_timestamp = _start_UNIX;
end_timestamp = _end_UNIX;
min_purchase = _min_purchase;
priceFeed = _priceFeed;
contractName = _name;
tokenPricePer10000 = _targetPrice;
}
function setup_vesting(uint256 _vesting_period, uint256 _instant_delivery, uint256 _num_periods) public onlyOwner
{
vesting_period_duration = _vesting_period;
instant_delivery = _instant_delivery;
vesting_periods_total = _num_periods;
}
// Emergency function that allows the owner of the contract to call any code
// from any other "template contract" on behalf of the ICO contract.
function delegateCall(address _to, bytes calldata _data) external onlyOwner
{
(bool success, bytes memory data) = _to.delegatecall(_data);
}
function set_claiming(bool _claiming_enabled) public onlyOwner
{
claiming_enabled = _claiming_enabled;
}
}
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[]},{"type":"event","name":"Approval","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"address","name":"spender","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"Transfer","inputs":[{"type":"address","name":"from","internalType":"address","indexed":true},{"type":"address","name":"to","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"TransferData","inputs":[{"type":"bytes","name":"","internalType":"bytes","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"allowance","inputs":[{"type":"address","name":"owner","internalType":"address"},{"type":"address","name":"spender","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"approve","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"balanceOf","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"decimals","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"decreaseAllowance","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"subtractedValue","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"disableSetup","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"increaseAllowance","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"addedValue","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"minters","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"name","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"rescueERC20","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"address","name":"to","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"setup_mode","inputs":[]},{"type":"function","stateMutability":"pure","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"standard","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"symbol","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalSupply","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transfer","inputs":[{"type":"address","name":"recipient","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transfer","inputs":[{"type":"address","name":"recipient","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"bytes","name":"data","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transferFrom","inputs":[{"type":"address","name":"sender","internalType":"address"},{"type":"address","name":"recipient","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]}]
Contract Creation Code
0x60806040526000805460ff191660011790553480156200001e57600080fd5b506040518060400160405280601781526020017f47616d657320616e6420476f626c696e7320746f6b656e00000000000000000081525060405180604001604052806003815260200162476e4760e81b81525081600590816200008291906200029b565b5060066200009182826200029b565b5050600780543361010081026001600160a81b0319909216919091176012179091559050620000cd816b019d971e4fe8401e740000006200010a565b6040516001600160a01b038216906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3506200038f565b6001600160a01b038216620001655760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015260640160405180910390fd5b806004600082825462000179919062000367565b90915550506001600160a01b03821660009081526002602052604081208054839290620001a890849062000367565b90915550506040518181526001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b505050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200022257607f821691505b6020821081036200024357634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620001f257600081815260208120601f850160051c81016020861015620002725750805b601f850160051c820191505b8181101562000293578281556001016200027e565b505050505050565b81516001600160401b03811115620002b757620002b7620001f7565b620002cf81620002c884546200020d565b8462000249565b602080601f831160018114620003075760008415620002ee5750858301515b600019600386901b1c1916600185901b17855562000293565b600085815260208120601f198616915b82811015620003385788860151825594840194600190910190840162000317565b5085821015620003575787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b808201808211156200038957634e487b7160e01b600052601160045260246000fd5b92915050565b610fdd806200039f6000396000f3fe608060405234801561001057600080fd5b506004361061012c5760003560e01c80638da5cb5b116100ad578063b28fc6a311610071578063b28fc6a314610286578063be45fd6214610293578063dd62ed3e146102a6578063f2fde38b146102df578063f46eccc4146102f257600080fd5b80638da5cb5b1461022757806395d89b4114610250578063a457c2d714610258578063a9059cbb1461026b578063a9b9cd1e1461027e57600080fd5b806339509351116100f457806339509351146101ac5780635a3b7e42146101bf5780635d799f87146101e157806370a08231146101f6578063715018a61461021f57600080fd5b806306fdde0314610131578063095ea7b31461014f57806318160ddd1461017257806323b872dd14610184578063313ce56714610197575b600080fd5b610139610315565b6040516101469190610c96565b60405180910390f35b61016261015d366004610ccc565b6103a7565b6040519015158152602001610146565b6004545b604051908152602001610146565b610162610192366004610cf6565b6103be565b60075460405160ff9091168152602001610146565b6101626101ba366004610ccc565b610410565b60408051808201909152600681526565726332323360d01b6020820152610139565b6101f46101ef366004610d32565b610447565b005b610176610204366004610d65565b6001600160a01b031660009081526002602052604090205490565b6101f4610567565b60075461010090046001600160a01b03166040516001600160a01b039091168152602001610146565b6101396105e6565b610162610266366004610ccc565b6105f5565b610162610279366004610ccc565b61062c565b6101f461064b565b6000546101629060ff1681565b6101626102a1366004610d80565b6106e3565b6101766102b4366004610d32565b6001600160a01b03918216600090815260036020908152604080832093909416825291909152205490565b6101f46102ed366004610d65565b610732565b610162610300366004610d65565b60016020526000908152604090205460ff1681565b60606005805461032490610e07565b80601f016020809104026020016040519081016040528092919081815260200182805461035090610e07565b801561039d5780601f106103725761010080835404028352916020019161039d565b820191906000526020600020905b81548152906001019060200180831161038057829003601f168201915b5050505050905090565b60006103b4338484610844565b5060015b92915050565b60006103cb848484610969565b6001600160a01b038416600090815260036020908152604080832033808552925290912054610406918691610401908690610e57565b610844565b5060019392505050565b3360008181526003602090815260408083206001600160a01b038716845290915281205490916103b4918590610401908690610e6a565b60075461010090046001600160a01b0316331461047f5760405162461bcd60e51b815260040161047690610e7d565b60405180910390fd5b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa1580156104c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104ea9190610eb2565b60405163a9059cbb60e01b81526001600160a01b038481166004830152602482018390529192509084169063a9059cbb906044016020604051808303816000875af115801561053d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105619190610ecb565b50505050565b60075461010090046001600160a01b031633146105965760405162461bcd60e51b815260040161047690610e7d565b60075460405160009161010090046001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a360078054610100600160a81b0319169055565b60606006805461032490610e07565b3360008181526003602090815260408083206001600160a01b038716845290915281205490916103b4918590610401908690610e57565b604080516000808252602082019092526103b490339085908590610a5d565b60075461010090046001600160a01b0316331461067a5760405162461bcd60e51b815260040161047690610e7d565b60005460ff166106d75760405162461bcd60e51b815260206004820152602260248201527f54686973206973206f6e6c7920616c6c6f77656420696e207365747570206d6f604482015261646560f01b6064820152608401610476565b6000805460ff19169055565b600061072733868686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610a5d92505050565b506001949350505050565b60075461010090046001600160a01b031633146107615760405162461bcd60e51b815260040161047690610e7d565b6001600160a01b0381161580159061078257506001600160a01b0381163014155b6107dd5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610476565b6007546040516001600160a01b0380841692610100900416907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600780546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b6001600160a01b0383166108a65760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610476565b6001600160a01b0382166109075760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610476565b6001600160a01b0383811660008181526003602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b6001600160a01b03831661098f5760405162461bcd60e51b815260040161047690610eed565b6001600160a01b0382166109b55760405162461bcd60e51b815260040161047690610f33565b6001600160a01b0383166000908152600260205260409020546109d9908290610e57565b6001600160a01b038085166000908152600260205260408082209390935590841681522054610a09908290610e6a565b6001600160a01b0380841660008181526002602052604090819020939093559151908516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9061095c9085815260200190565b6001600160a01b038416610a835760405162461bcd60e51b815260040161047690610eed565b6001600160a01b038316610aa95760405162461bcd60e51b815260040161047690610f33565b6001600160a01b038416600090815260026020526040902054610acd908390610e57565b6001600160a01b038086166000908152600260205260408082209390935590851681522054610afd908390610e6a565b6001600160a01b038416600081815260026020526040902091909155610b2290610c14565b15610b8a576040516344a1f60160e11b81526001600160a01b03841690638943ec0290610b5790879086908690600401610f77565b600060405180830381600087803b158015610b7157600080fd5b505af1158015610b85573d6000803e3d6000fd5b505050505b826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610bcf91815260200190565b60405180910390a37f3ba9136826ac751de05d770d8d34fa4440ada49a5fb0e9aa1678aece66dad97681604051610c069190610c96565b60405180910390a150505050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590610c4857508115155b949350505050565b6000815180845260005b81811015610c7657602081850181015186830182015201610c5a565b506000602082860101526020601f19601f83011685010191505092915050565b602081526000610ca96020830184610c50565b9392505050565b80356001600160a01b0381168114610cc757600080fd5b919050565b60008060408385031215610cdf57600080fd5b610ce883610cb0565b946020939093013593505050565b600080600060608486031215610d0b57600080fd5b610d1484610cb0565b9250610d2260208501610cb0565b9150604084013590509250925092565b60008060408385031215610d4557600080fd5b610d4e83610cb0565b9150610d5c60208401610cb0565b90509250929050565b600060208284031215610d7757600080fd5b610ca982610cb0565b60008060008060608587031215610d9657600080fd5b610d9f85610cb0565b935060208501359250604085013567ffffffffffffffff80821115610dc357600080fd5b818701915087601f830112610dd757600080fd5b813581811115610de657600080fd5b886020828501011115610df857600080fd5b95989497505060200194505050565b600181811c90821680610e1b57607f821691505b602082108103610e3b57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b818103818111156103b8576103b8610e41565b808201808211156103b8576103b8610e41565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b600060208284031215610ec457600080fd5b5051919050565b600060208284031215610edd57600080fd5b81518015158114610ca957600080fd5b60208082526026908201527f4552433232333a207472616e736665722066726f6d20746865207a65726f206160408201526564647265737360d01b606082015260800190565b60208082526024908201527f4552433232333a207472616e7366657220746f20746865207a65726f206164646040820152637265737360e01b606082015260800190565b60018060a01b0384168152826020820152606060408201526000610f9e6060830184610c50565b9594505050505056fea2646970667358221220aa7a5a8002bcd0c2e18b4e4dc71287041555e4303e6684677d65a42c0445848764736f6c63430008110033
Deployed ByteCode
0x608060405234801561001057600080fd5b506004361061012c5760003560e01c80638da5cb5b116100ad578063b28fc6a311610071578063b28fc6a314610286578063be45fd6214610293578063dd62ed3e146102a6578063f2fde38b146102df578063f46eccc4146102f257600080fd5b80638da5cb5b1461022757806395d89b4114610250578063a457c2d714610258578063a9059cbb1461026b578063a9b9cd1e1461027e57600080fd5b806339509351116100f457806339509351146101ac5780635a3b7e42146101bf5780635d799f87146101e157806370a08231146101f6578063715018a61461021f57600080fd5b806306fdde0314610131578063095ea7b31461014f57806318160ddd1461017257806323b872dd14610184578063313ce56714610197575b600080fd5b610139610315565b6040516101469190610c96565b60405180910390f35b61016261015d366004610ccc565b6103a7565b6040519015158152602001610146565b6004545b604051908152602001610146565b610162610192366004610cf6565b6103be565b60075460405160ff9091168152602001610146565b6101626101ba366004610ccc565b610410565b60408051808201909152600681526565726332323360d01b6020820152610139565b6101f46101ef366004610d32565b610447565b005b610176610204366004610d65565b6001600160a01b031660009081526002602052604090205490565b6101f4610567565b60075461010090046001600160a01b03166040516001600160a01b039091168152602001610146565b6101396105e6565b610162610266366004610ccc565b6105f5565b610162610279366004610ccc565b61062c565b6101f461064b565b6000546101629060ff1681565b6101626102a1366004610d80565b6106e3565b6101766102b4366004610d32565b6001600160a01b03918216600090815260036020908152604080832093909416825291909152205490565b6101f46102ed366004610d65565b610732565b610162610300366004610d65565b60016020526000908152604090205460ff1681565b60606005805461032490610e07565b80601f016020809104026020016040519081016040528092919081815260200182805461035090610e07565b801561039d5780601f106103725761010080835404028352916020019161039d565b820191906000526020600020905b81548152906001019060200180831161038057829003601f168201915b5050505050905090565b60006103b4338484610844565b5060015b92915050565b60006103cb848484610969565b6001600160a01b038416600090815260036020908152604080832033808552925290912054610406918691610401908690610e57565b610844565b5060019392505050565b3360008181526003602090815260408083206001600160a01b038716845290915281205490916103b4918590610401908690610e6a565b60075461010090046001600160a01b0316331461047f5760405162461bcd60e51b815260040161047690610e7d565b60405180910390fd5b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa1580156104c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104ea9190610eb2565b60405163a9059cbb60e01b81526001600160a01b038481166004830152602482018390529192509084169063a9059cbb906044016020604051808303816000875af115801561053d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105619190610ecb565b50505050565b60075461010090046001600160a01b031633146105965760405162461bcd60e51b815260040161047690610e7d565b60075460405160009161010090046001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a360078054610100600160a81b0319169055565b60606006805461032490610e07565b3360008181526003602090815260408083206001600160a01b038716845290915281205490916103b4918590610401908690610e57565b604080516000808252602082019092526103b490339085908590610a5d565b60075461010090046001600160a01b0316331461067a5760405162461bcd60e51b815260040161047690610e7d565b60005460ff166106d75760405162461bcd60e51b815260206004820152602260248201527f54686973206973206f6e6c7920616c6c6f77656420696e207365747570206d6f604482015261646560f01b6064820152608401610476565b6000805460ff19169055565b600061072733868686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610a5d92505050565b506001949350505050565b60075461010090046001600160a01b031633146107615760405162461bcd60e51b815260040161047690610e7d565b6001600160a01b0381161580159061078257506001600160a01b0381163014155b6107dd5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610476565b6007546040516001600160a01b0380841692610100900416907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600780546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b6001600160a01b0383166108a65760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610476565b6001600160a01b0382166109075760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610476565b6001600160a01b0383811660008181526003602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b6001600160a01b03831661098f5760405162461bcd60e51b815260040161047690610eed565b6001600160a01b0382166109b55760405162461bcd60e51b815260040161047690610f33565b6001600160a01b0383166000908152600260205260409020546109d9908290610e57565b6001600160a01b038085166000908152600260205260408082209390935590841681522054610a09908290610e6a565b6001600160a01b0380841660008181526002602052604090819020939093559151908516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9061095c9085815260200190565b6001600160a01b038416610a835760405162461bcd60e51b815260040161047690610eed565b6001600160a01b038316610aa95760405162461bcd60e51b815260040161047690610f33565b6001600160a01b038416600090815260026020526040902054610acd908390610e57565b6001600160a01b038086166000908152600260205260408082209390935590851681522054610afd908390610e6a565b6001600160a01b038416600081815260026020526040902091909155610b2290610c14565b15610b8a576040516344a1f60160e11b81526001600160a01b03841690638943ec0290610b5790879086908690600401610f77565b600060405180830381600087803b158015610b7157600080fd5b505af1158015610b85573d6000803e3d6000fd5b505050505b826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610bcf91815260200190565b60405180910390a37f3ba9136826ac751de05d770d8d34fa4440ada49a5fb0e9aa1678aece66dad97681604051610c069190610c96565b60405180910390a150505050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590610c4857508115155b949350505050565b6000815180845260005b81811015610c7657602081850181015186830182015201610c5a565b506000602082860101526020601f19601f83011685010191505092915050565b602081526000610ca96020830184610c50565b9392505050565b80356001600160a01b0381168114610cc757600080fd5b919050565b60008060408385031215610cdf57600080fd5b610ce883610cb0565b946020939093013593505050565b600080600060608486031215610d0b57600080fd5b610d1484610cb0565b9250610d2260208501610cb0565b9150604084013590509250925092565b60008060408385031215610d4557600080fd5b610d4e83610cb0565b9150610d5c60208401610cb0565b90509250929050565b600060208284031215610d7757600080fd5b610ca982610cb0565b60008060008060608587031215610d9657600080fd5b610d9f85610cb0565b935060208501359250604085013567ffffffffffffffff80821115610dc357600080fd5b818701915087601f830112610dd757600080fd5b813581811115610de657600080fd5b886020828501011115610df857600080fd5b95989497505060200194505050565b600181811c90821680610e1b57607f821691505b602082108103610e3b57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b818103818111156103b8576103b8610e41565b808201808211156103b8576103b8610e41565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b600060208284031215610ec457600080fd5b5051919050565b600060208284031215610edd57600080fd5b81518015158114610ca957600080fd5b60208082526026908201527f4552433232333a207472616e736665722066726f6d20746865207a65726f206160408201526564647265737360d01b606082015260800190565b60208082526024908201527f4552433232333a207472616e7366657220746f20746865207a65726f206164646040820152637265737360e01b606082015260800190565b60018060a01b0384168152826020820152606060408201526000610f9e6060830184610c50565b9594505050505056fea2646970667358221220aa7a5a8002bcd0c2e18b4e4dc71287041555e4303e6684677d65a42c0445848764736f6c63430008110033