/**
 *Submitted for verification at Etherscan.io on 2020-05-24
*/

/*
                                                                 ,╖╗#▒▓▓▓▓▓╣╬╣▓▓▓▓▒#╗╗╓,
                                                           ,╗@▓╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬▓▓╗╖
                                                       ╓#▓╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╝▀╠╠▄╣╝╜"""╙╙▀╝╝╣╬╬╬╬▓▌╖
                                                    ╓▓╣╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬▀`╓å▓▓▓╙  ,▄▓▓██▓▓▓▄▄▄▄▄╠╠╙╠▄▄
                                                 ╓@╣╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬▌  ê`'     *▀▀▀▀▀▀▀▓██████████████▄
                                               ╔▓╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬                      ╙▀████████████▌
                                             ╓▓╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬                         ╙████████████▌
                                           ,▓╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬▓▀                          ╗▄█████████████▄
                                          é╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬▓▌   #╙                       ╙▀█████████████▓
                                         ╣╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬▀              ╙▓╬╣▓▄            ╙▀▀███████████µ
                                        ▓╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬▀╣╝╙             ╒▓╬╬╬╬╬╬▓         ╙████████████████µ
                                       ▓╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬▌              ╖╖╖▄▓╬╬╬╬╬╬╬▓         █████████████████µ
                                      ╣╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬        ,#▓╣╬╬▓╬╬╬╬╬╬╬╬╬╬╬╬▌         ▓█████████████████
                                     ]╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╓╖     ]╣╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╣╨          ██████████████████▌
                                     ▓╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬▓▌╖,   ╙╠╠▓╬╬╬╬╬╬╬╬╬▓╝╙           ╫███████████████████
                                    ]╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╝▀╙              ▓████████████████████▌
                                    ║╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╝▀╙`                 ▄███████████████████████
                                    ╟╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬▓╝▀╙                     ,▄█████████████████████████
                                    ╟╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╝╜`                       ▄▓████████████████████████████
                                    ║╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╣▀`                     ,▄▄▓████████████████████████████████
                                    ▐╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬▓╙                       ,,,▄╠▓██████████████████████████████▌
                                     ╣╬╬╬╬╬╬╬╬╬╬╬╬╬╬▓╙╔▒`               ╓▄▓████████████████████████████████████████⌐
                                     ╚╬╬╬╬╬╬╬╬╬╬╬╬╬▓▓╣▓              ▄▓████████████████████████████████████████████
                                      ▓╬╬╬╬╬╬╬╬╬╬╬╬╬╬╬             ▄██████████████████████████████████████████████⌐
                                       ╣╬╬╬╬╬╬╬╬╬╬╬╬╬╛           ▄███████████████████████████████████████████████▌
                                       └╣╬╬╬╬╬╬╬╬╬╬╬▓           ▄███████████████████████████████████████████████▌
                                        └▓╬╬╬╬╬╬╬╬╬╬Γ          ]███████████████████████████████████████████████▀
                                          ╣╬╬╬╬╬╬╬╬╬⌐          ╫████████████████████████████████▀▀▀▀▀▓████████╜
                                           ╙╬╬╬╬╬╬╬╬⌐          ╟███████████████████████████▀╙    ,▄▓▓▓▓▓████▓
                                             ╫╬╬╬╬╬╬b           ████████████████████████▀`    ,Φ▀▀█████████╙
                                               ╫╬╬╬╬▌╟           ██████████████████▀╓▀─       ▄▓█████████▀
                                                 ╚╣╬▓╣▓           └▀████████████▀`         ╓▓█████████▓╙
                                                   ╙╝╬╬▓             .▄▄▓█▀▀▀`           ▄▓█████████▀
                                                      ╙▀▓▄                            ƒ,▓███████▀▀
                                                          "                        ╓▓█▓█████▀▀└
                                                                               ╓▄▓████▀▀╙└

 ██████╗██╗  ██╗██╗     ██████╗  █████╗ ███████╗████████╗ ██████╗ ██╗  ██╗███████╗███╗   ██╗    ██████╗ ██╗   ██╗     ██╗██╗███╗   ██╗ ██████╗██╗  ██╗
██╔════╝██║  ██║██║    ██╔════╝ ██╔══██╗██╔════╝╚══██╔══╝██╔═══██╗██║ ██╔╝██╔════╝████╗  ██║    ██╔══██╗╚██╗ ██╔╝    ███║██║████╗  ██║██╔════╝██║  ██║
██║     ███████║██║    ██║  ███╗███████║███████╗   ██║   ██║   ██║█████╔╝ █████╗  ██╔██╗ ██║    ██████╔╝ ╚████╔╝     ╚██║██║██╔██╗ ██║██║     ███████║
██║     ██╔══██║██║    ██║   ██║██╔══██║╚════██║   ██║   ██║   ██║██╔═██╗ ██╔══╝  ██║╚██╗██║    ██╔══██╗  ╚██╔╝       ██║██║██║╚██╗██║██║     ██╔══██║
╚██████╗██║  ██║██║    ╚██████╔╝██║  ██║███████║   ██║   ╚██████╔╝██║  ██╗███████╗██║ ╚████║    ██████╔╝   ██║        ██║██║██║ ╚████║╚██████╗██║  ██║
 ╚═════╝╚═╝  ╚═╝╚═╝     ╚═════╝ ╚═╝  ╚═╝╚══════╝   ╚═╝    ╚═════╝ ╚═╝  ╚═╝╚══════╝╚═╝  ╚═══╝    ╚═════╝    ╚═╝        ╚═╝╚═╝╚═╝  ╚═══╝ ╚═════╝╚═╝  ╚═╝

                                                             Copyright by 1inch Corporation
                                                                 https://1inch.exchange

---
Deployer wallet address:
0x7E1E3334130355799F833ffec2D731BCa3E68aF6

Signed raw transaction for chainId 1:
 
---
*/
// File: @openzeppelin/contracts/math/Math.sol

pragma solidity ^0.6.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow, so we distribute
        return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
    }
}

// File: @openzeppelin/contracts/math/SafeMath.sol

pragma solidity ^0.6.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

// File: @openzeppelin/contracts/token/ERC20/IERC20.sol

pragma solidity ^0.6.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: contracts/ChiToken.sol

pragma solidity ^0.6.0;





abstract contract ERC20WithoutTotalSupply is IERC20 {
    using SafeMath for uint256;

    mapping(address => uint256) private _balances;
    mapping(address => mapping(address => uint256)) private _allowances;

    function balanceOf(address account) public view override returns (uint256) {
        return _balances[account];
    }

    function allowance(address owner, address spender) public view override returns (uint256) {
        return _allowances[owner][spender];
    }

    function transfer(address recipient, uint256 amount) public override returns (bool) {
        _transfer(msg.sender, recipient, amount);
        return true;
    }

    function approve(address spender, uint256 amount) public override returns (bool) {
        _approve(msg.sender, spender, amount);
        return true;
    }

    function transferFrom(address sender, address recipient, uint256 amount) public override returns (bool) {
        _transfer(sender, recipient, amount);
        _approve(sender, msg.sender, _allowances[sender][msg.sender].sub(amount, "ERC20: transfer amount exceeds allowance"));
        return true;
    }

    function _transfer(address sender, address recipient, uint256 amount) internal {
        _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
        _balances[recipient] = _balances[recipient].add(amount);
        emit Transfer(sender, recipient, amount);
    }

    function _approve(address owner, address spender, uint256 amount) internal {
        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    function _mint(address account, uint256 amount) internal {
        _balances[account] = _balances[account].add(amount);
        emit Transfer(address(0), account, amount);
    }

    function _burn(address account, uint256 amount) internal {
        _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
        emit Transfer(account, address(0), amount);
    }

    function _burnFrom(address account, uint256 amount) internal {
        _burn(account, amount);
        _approve(account, msg.sender, _allowances[account][msg.sender].sub(amount, "ERC20: burn amount exceeds allowance"));
    }
}


contract ChiToken is IERC20, ERC20WithoutTotalSupply {
    string constant public name = "Chi Gastoken by 1inch";
    string constant public symbol = "CHI";
    uint8 constant public decimals = 0;

    uint256 public totalMinted;
    uint256 public totalBurned;

    function totalSupply() public view override returns(uint256) {
        return totalMinted.sub(totalBurned);
    }

    function mint(uint256 value) public {
        uint256 offset = totalMinted;
        assembly {
            mstore(0, 0x746d4946c0e9F43F4Dee607b0eF1fA1c3318585733ff6000526015600bf30000)

            for {let i := div(value, 32)} i {i := sub(i, 1)} {
                pop(create2(0, 0, 30, add(offset, 0))) pop(create2(0, 0, 30, add(offset, 1)))
                pop(create2(0, 0, 30, add(offset, 2))) pop(create2(0, 0, 30, add(offset, 3)))
                pop(create2(0, 0, 30, add(offset, 4))) pop(create2(0, 0, 30, add(offset, 5)))
                pop(create2(0, 0, 30, add(offset, 6))) pop(create2(0, 0, 30, add(offset, 7)))
                pop(create2(0, 0, 30, add(offset, 8))) pop(create2(0, 0, 30, add(offset, 9)))
                pop(create2(0, 0, 30, add(offset, 10))) pop(create2(0, 0, 30, add(offset, 11)))
                pop(create2(0, 0, 30, add(offset, 12))) pop(create2(0, 0, 30, add(offset, 13)))
                pop(create2(0, 0, 30, add(offset, 14))) pop(create2(0, 0, 30, add(offset, 15)))
                pop(create2(0, 0, 30, add(offset, 16))) pop(create2(0, 0, 30, add(offset, 17)))
                pop(create2(0, 0, 30, add(offset, 18))) pop(create2(0, 0, 30, add(offset, 19)))
                pop(create2(0, 0, 30, add(offset, 20))) pop(create2(0, 0, 30, add(offset, 21)))
                pop(create2(0, 0, 30, add(offset, 22))) pop(create2(0, 0, 30, add(offset, 23)))
                pop(create2(0, 0, 30, add(offset, 24))) pop(create2(0, 0, 30, add(offset, 25)))
                pop(create2(0, 0, 30, add(offset, 26))) pop(create2(0, 0, 30, add(offset, 27)))
                pop(create2(0, 0, 30, add(offset, 28))) pop(create2(0, 0, 30, add(offset, 29)))
                pop(create2(0, 0, 30, add(offset, 30))) pop(create2(0, 0, 30, add(offset, 31)))
                offset := add(offset, 32)
            }

            for {let i := and(value, 0x1F)} i {i := sub(i, 1)} {
                pop(create2(0, 0, 30, offset))
                offset := add(offset, 1)
            }
        }

        _mint(msg.sender, value);
        totalMinted = offset;
    }

    function computeAddress2(uint256 salt) public view returns (address) {
        bytes32 _data = keccak256(
            abi.encodePacked(bytes1(0xff), address(this), salt, bytes32(0x3c1644c68e5d6cb380c36d1bf847fdbc0c7ac28030025a2fc5e63cce23c16348))
        );
        return address(uint256(_data));
    }

    function _destroyChildren(uint256 value) internal {
        uint256 _totalBurned = totalBurned;
        for (uint256 i = 0; i < value; i++) {
            computeAddress2(_totalBurned + i).call("");
        }
        totalBurned = _totalBurned + value;
    }

    function free(uint256 value) public returns (uint256)  {
        _burn(msg.sender, value);
        _destroyChildren(value);
        return value;
    }

    function freeUpTo(uint256 value) public returns (uint256) {
        return free(Math.min(value, balanceOf(msg.sender)));
    }

    function freeFrom(address from, uint256 value) public returns (uint256) {
        _burnFrom(from, value);
        _destroyChildren(value);
        return value;
    }

    function freeFromUpTo(address from, uint256 value) public returns (uint256) {
        return freeFrom(from, Math.min(Math.min(value, balanceOf(from)), allowance(from, msg.sender)));
    }
}