contract UpgradeableStandardToken is StandardToken {
    address public upgradeAddress;
    uint256 public upgradeTimestamp;

    //  The contract is initialized with an upgrade timestamp close to the heat death of the universe.
    constructor() public {
        upgradeAddress = address(0);
        //  Set the timestamp of the upgrade to some time close to the heat death of the universe.
        upgradeTimestamp = MAX_UINT256;
    }

    // Forward ERC20 methods to upgraded contract after the upgrade timestamp has been reached
    function transfer(address _to, uint256 _value) public returns (bool success) {
        if (now > upgradeTimestamp) {
            return UpgradedStandardToken(upgradeAddress).transferByLegacy(msg.sender, _to, _value);
        } else {
            return super.transfer(_to, _value);
        }
    }

    // Forward ERC20 methods to upgraded contract after the upgrade timestamp has been reached
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
        if (now > upgradeTimestamp) {
            return UpgradedStandardToken(upgradeAddress).transferFromByLegacy(msg.sender, _from, _to, _value);
        } else {
            return super.transferFrom(_from, _to, _value);
        }
    }

    // Forward ERC20 methods to upgraded contract after the upgrade timestamp has been reached
    function balanceOf(address who) public view returns (uint256 balance) {
        if (now > upgradeTimestamp) {
            return UpgradedStandardToken(upgradeAddress).balanceOf(who);
        } else {
            return super.balanceOf(who);
        }
    }

    // Forward ERC20 methods to upgraded contract after the upgrade timestamp has been reached
    function approve(address _spender, uint256 _value) public onlyPayloadSize(2 * 32) returns (bool success) {
        if (now > upgradeTimestamp) {
            return UpgradedStandardToken(upgradeAddress).approveByLegacy(msg.sender, _spender, _value);
        } else {
            return super.approve(_spender, _value);
        }
    }

    function increaseApproval(address _spender, uint _addedValue) public returns (bool success) {
        if (now > upgradeTimestamp) {
            return UpgradedStandardToken(upgradeAddress).increaseApprovalByLegacy(msg.sender, _spender, _addedValue);
        } else {
            return super.increaseApproval(_spender, _addedValue);
        }
    }

    function decreaseApproval(address _spender, uint _subtractedValue) public returns (bool success) {
        if (now > upgradeTimestamp) {
            return UpgradedStandardToken(upgradeAddress).decreaseApprovalByLegacy(msg.sender, _spender, _subtractedValue);
        } else {
            return super.decreaseApproval(_spender, _subtractedValue);
        }
    }

    // Forward ERC20 methods to upgraded contract after the upgrade timestamp has been reached
    function allowance(address _owner, address _spender) public view returns (uint256 remaining) {
        if (now > upgradeTimestamp) {
            return StandardToken(upgradeAddress).allowance(_owner, _spender);
        } else {
            return super.allowance(_owner, _spender);
        }
    }

    // Upgrade this contract with a new one, it will auto-activate 12 weeks later
    function upgrade(address _upgradeAddress) public onlyOwner {
        require(now < upgradeTimestamp);
        require(_upgradeAddress != address(0));

        upgradeAddress = _upgradeAddress;
        upgradeTimestamp = now.add(12 weeks);
        emit Upgrading(_upgradeAddress, upgradeTimestamp);
    }

    // Called when contract is upgrading
    event Upgrading(address newAddress, uint256 timestamp);
}
// @title Upgradeable standard token
// @dev The upgradeable contract interface
// @dev
// @dev They have to ensure msg.sender to be the contract address
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
    if (now > upgradeTimestamp) {
        return UpgradedStandardToken(upgradeAddress).transferFromByLegacy(msg.sender, _from, _to, _value);
    } else {
        return super.transferFrom(_from, _to, _value);
    }
}

// Forward ERC20 methods to upgraded contract after the upgrade timestamp has been reached