Contract Overview
Balance: 0 Ether
Ether Value: $0
Transactions: 7052 txns
Token Tracker: �y� /Prices must not be stale to p... (�y� /Pric...)
Misc:
Address Watch: Add To Watch List
Contract Creator: 0x6cca6b463d48b148c0d36608460ff4aafc760384at txn 0x785a3bb53bacf909a04820368655144b67bd8a137c2e80316d4bf93b0020276c
Token Balance:
 Latest 25 transactions from a total of 7052 transactions

TxHash Age From To Value [TxFee]
0x913114466a7a3f978ba65359467a5bd589195b3e9b21ae083ebf33e5b8734b1d14 days 17 hrs ago0xa09e7838e188814640c01d2d135be2c919f451fa  IN   0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0.0001 Ether0.0001313129
0x7e8dab1a08b43c738444546f555c1a773e580e2c59accfd8a4ce46345b968a8114 days 18 hrs ago0xac1ed4fabbd5204e02950d68b6fc8c446ac95362  IN   0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0 Ether0.000202895
0x4d1a639fbba2ba8b4e848adf525f3af29b7dc8f6c85d7c470c5afb41120de85e14 days 18 hrs ago0xac1ed4fabbd5204e02950d68b6fc8c446ac95362  IN   0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0 Ether0.000162316
0xf492aefb5949b7cc2d9f7ec6a401748265990b72d7ea0b04f4f6ce1f0811177114 days 18 hrs ago0xac1ed4fabbd5204e02950d68b6fc8c446ac95362  IN   0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0 Ether0.000162316
0x9a46c91d99353470acee4757a844e6727e5104c037f98cba8753b50c28ad4df914 days 18 hrs ago0xac1ed4fabbd5204e02950d68b6fc8c446ac95362  IN   0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0 Ether0.000162316
0x7c6544f1e3d2f606eef31c41017c628faf5a778731539845a16141a1022dd18c14 days 18 hrs ago0xac1ed4fabbd5204e02950d68b6fc8c446ac95362  IN   0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0 Ether0.000202895
0xe71f3e98862cef50a29f7f1de2dc369e946acc7dc7e8b9af2a2f55cc3e3661b714 days 19 hrs ago0xac1ed4fabbd5204e02950d68b6fc8c446ac95362  IN   0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0 Ether0.000202895
0x45a240a77b4618141efa99889d20d7ae6067f197bf60e32129a730b6388b47f714 days 19 hrs ago0xac1ed4fabbd5204e02950d68b6fc8c446ac95362  IN   0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0 Ether0.000162316
0x4ffe872dda0d009f229fca977206f1c3cd3ff9f8776bf1c3f05a1a744765c8c514 days 19 hrs ago0xac1ed4fabbd5204e02950d68b6fc8c446ac95362  IN   0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0 Ether0.000202895
0x1a045bff78dbc31faf70963cfb1dfabbef03f65c2ce59c466740abd30d30861014 days 19 hrs ago0xac1ed4fabbd5204e02950d68b6fc8c446ac95362  IN   0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0 Ether0.000202895
0xf0f105a7acd0e6ba817f19beea9f27279d5c93ad4410d59b7e7e996e41241bc614 days 19 hrs ago0xac1ed4fabbd5204e02950d68b6fc8c446ac95362  IN   0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0 Ether0.000162316
0xa9928e36dbf1e8960af8fc6abb712189c7e7d64ae1f939660bd25da37d0ad19414 days 19 hrs ago0xb535ac19df533873c2c640df6cd644cfbf8b5d39  IN   0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0 Ether0.00100955
0x9c62b6513247782912822abd9d3c332a3d6b795130762cf422b1cb5e4aaab00314 days 20 hrs ago0xac1ed4fabbd5204e02950d68b6fc8c446ac95362  IN   0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0 Ether0.000324632
0x4bf810ec6db75378a225c157eccd033e677a6435cf9d9d6532d1b7a87f67fa2b14 days 20 hrs ago0xac1ed4fabbd5204e02950d68b6fc8c446ac95362  IN   0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0 Ether0.000162316
0x8f21bb4cf39a744fc259665eb682036474e169264169f8931acabc52389e69d714 days 21 hrs ago0xac1ed4fabbd5204e02950d68b6fc8c446ac95362  IN   0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0 Ether0.00016206
0xe618accccfd3ce0469d6b1d06c3fbc906c5506476a23845d3908751101512b3514 days 21 hrs ago0xac1ed4fabbd5204e02950d68b6fc8c446ac95362  IN   0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0 Ether0.000202895
0xb04beda48d980c62d891066787022df7be2d850270cccd5504519aec5b9d400314 days 21 hrs ago0xac1ed4fabbd5204e02950d68b6fc8c446ac95362  IN   0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0 Ether0.000202895
0x76d64b164590eda5b94228eca0e9bcac85dcf70834954aeded54128444c91bed14 days 21 hrs ago0xac1ed4fabbd5204e02950d68b6fc8c446ac95362  IN   0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0 Ether0.00016206
0xb4d3daa5e0984af542c086fea30b1c8326c5cbdfaca970710487d50650e1402714 days 21 hrs ago0xac1ed4fabbd5204e02950d68b6fc8c446ac95362  IN   0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0 Ether0.00016206
0x264c933c4932e5707cf512ed99ad465f2c6a8f5d8f00a36be1d062c9813313c114 days 21 hrs ago0xac1ed4fabbd5204e02950d68b6fc8c446ac95362  IN   0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0 Ether0.000162316
0xe43607e3b62ec1be4fb28e3e602d73b18fdadd5e699d879e78ac5709f25c2d4f14 days 22 hrs ago0xac1ed4fabbd5204e02950d68b6fc8c446ac95362  IN   0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0 Ether0.000162316
0xfd5c39ab42d373b86c1a2de6334313a297aeb6f1f59b54e1d02d2abd3a66b5aa14 days 22 hrs ago0xac1ed4fabbd5204e02950d68b6fc8c446ac95362  IN   0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0 Ether0.000162316
0x44dde9cfa393b76b51a7fb77c4b25982328711da8df8cc6a0f636b84bea68dfb14 days 22 hrs ago0xac1ed4fabbd5204e02950d68b6fc8c446ac95362  IN   0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0 Ether0.000202895
0xd30411a768b73843d5aaee0003c3d58a71d669ccc93c803b528916fbd2f481f714 days 22 hrs ago0xac1ed4fabbd5204e02950d68b6fc8c446ac95362  IN   0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0 Ether0.000162316
0x97ab8ee0eef91c998e46c2bc481f03b58a2b1620af4b0d74af1e87c026428a1814 days 23 hrs ago0xac1ed4fabbd5204e02950d68b6fc8c446ac95362  IN   0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0 Ether0.000202895
[ Download CSV Export  ] 
 Internal Transactions as a result of Contract Execution
 Latest 25 Internal Txns, Click here To View More View All
ParentTxHash Block Age From To Value
0x913114466a7a3f978ba65359467a5bd589195b3e9b21ae083ebf33e5b8734b1d678666014 days 17 hrs ago0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0xa15184a8c8c3f47a8b54572cdccb30358abfb7a10.0001 Ether
0x06d3dea91866ab746afd1ab7454851f50030ee7d46bec3e635f22d2e202b5f2b676729217 days 22 hrs ago0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0xa15184a8c8c3f47a8b54572cdccb30358abfb7a10.011030553787644856 Ether
0x0b5307346844600d172dd59f56acd64d85d31278a716422e40fac0da472f82c9676724117 days 22 hrs ago0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0xa15184a8c8c3f47a8b54572cdccb30358abfb7a10.005569224399747802 Ether
0xcbdf03ddeec65a5df18aeff8bc39e958035a99034ae9bcd41ae5929d5d9997cd676718117 days 22 hrs ago0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0xa15184a8c8c3f47a8b54572cdccb30358abfb7a10.01 Ether
0x197495d77723d4a8627a5392059f2300d7e26699a26067ff6ad1f7ced95fabc4675242420 days 8 hrs ago0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0xa15184a8c8c3f47a8b54572cdccb30358abfb7a10.14 Ether
0x3be453c715eb27d95606945b63bbcfd3429e45635e7b29c111fc91975d0d7c94674688721 days 6 hrs ago0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0xa15184a8c8c3f47a8b54572cdccb30358abfb7a10.279782008690145205 Ether
0x665053c0fa04a74b6cab6f21b935d93d46bcb0d7c9873c2ca039f9af586ae579674499421 days 13 hrs ago0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0xa15184a8c8c3f47a8b54572cdccb30358abfb7a10.073718897143933243 Ether
0x16bf9e19b2d632c785b20315f5fc5dbae8f70cc0d928f0b8b4ef537ab9909d7a674189622 days 2 hrs ago0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0xa15184a8c8c3f47a8b54572cdccb30358abfb7a12.870047 Ether
0xad8d480ad13514ddc55f45c1fa4b4d30b42718dcaf3d692d4171c1adef239599673628423 days 34 mins ago0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0xa15184a8c8c3f47a8b54572cdccb30358abfb7a14.6928959 Ether
0x6b679e16e4a3f0564d66f596fea23676e62e6e534986aa174004b5a323bbe9de673623323 days 45 mins ago0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0xa15184a8c8c3f47a8b54572cdccb30358abfb7a13 Ether
0x527ef552783afadb5817eacae5fa605b1237b2fe9423b9e801dd58924751a461673620923 days 52 mins ago0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0xa15184a8c8c3f47a8b54572cdccb30358abfb7a17.61 Ether
0x9dbc5cd2e834752574c3a4bdc941215793818cec76eac78eaa32a8c720a9a9ce673619223 days 56 mins ago0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0xa15184a8c8c3f47a8b54572cdccb30358abfb7a17.61 Ether
0x83fdb9dc82f6f3c5018f82a86cbe0811e828974429e2dde355da5d2e41c0e4b8673121523 days 20 hrs ago0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0xa15184a8c8c3f47a8b54572cdccb30358abfb7a10.05 Ether
0xf76b893a17c929c839da44d23be410b2fad14d6fdd98190db4b4369ccba91ea3673092623 days 21 hrs ago0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0xa15184a8c8c3f47a8b54572cdccb30358abfb7a10.34 Ether
0xab1b4496096e3e29153dcc70ad3402041dad1380894e5a4d59d68d9a90db78fc673076623 days 22 hrs ago0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0xa15184a8c8c3f47a8b54572cdccb30358abfb7a10.000005780841291733 Ether
0x693d0a33da01365be7e808bf7e111cb76ad9032f51a82e945a817beceafe7240673073823 days 22 hrs ago0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0xa15184a8c8c3f47a8b54572cdccb30358abfb7a10.001 Ether
0xc8857f1ccb670e09e2a55d70d2ec54137d0ded0ca354669d0298d1940a09c379673030224 days 31 mins ago0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0xa15184a8c8c3f47a8b54572cdccb30358abfb7a17.67 Ether
0x600e41650d4fec1467efb43e4825b662761d6b2992e89a1eba253dfad39b95b0673027524 days 40 mins ago0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0xa15184a8c8c3f47a8b54572cdccb30358abfb7a17.67 Ether
0xce3111f880cf0639902fb5ae412d1380d48a66a922943ef3199d2e24d08a87fe673025624 days 45 mins ago0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0xa15184a8c8c3f47a8b54572cdccb30358abfb7a17.67 Ether
0x57a536df68fe42a384ef35e2ff7b11c8a35281f0e3a4894520dc8db45f5a444c672936424 days 4 hrs ago0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0xa15184a8c8c3f47a8b54572cdccb30358abfb7a10.05 Ether
0x0acbeec0b2ccfb16c0c24595d36d570c4597497aee176e9afb104a1101e60cb2672846224 days 7 hrs ago0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0xa15184a8c8c3f47a8b54572cdccb30358abfb7a10.0017138 Ether
0x41b133dcfc94bf55530cab7deb22d2ee0221b0dee6647e5cfdca12bf95775705672844524 days 7 hrs ago0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0xa15184a8c8c3f47a8b54572cdccb30358abfb7a10.0018215 Ether
0x341979cd980dc7ea3af901b721d2b4178fad8605cbddfa95db6e74722f9bdd05672732824 days 12 hrs ago0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0xa15184a8c8c3f47a8b54572cdccb30358abfb7a10.05 Ether
0xbaec7bdb2912e1c91261bd33d85d7a361fd2cc689695e670e0287534c5769d4c672707424 days 12 hrs ago0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0xa15184a8c8c3f47a8b54572cdccb30358abfb7a10.25 Ether
0xdd4bacbfee5459b6fd8c8954b2048dd07c4f63cb55f95946fe66e62f29f75c32672703624 days 13 hrs ago0x5c545ca7f9d34857664fdce6adc22edcf1d5061f0xa15184a8c8c3f47a8b54572cdccb30358abfb7a10.25 Ether
[ Download CSV Export  ] 
Warning: The Compiled Contract might be susceptible to ExpExponentCleanup (medium/high-severity), EventStructWrongData (very low-severity) SolidityCompiler Bugs.

Contract Source Code Verified (Exact Match)
Contract Name: IssuanceController
Compiler Text: v0.4.24+commit.e67f0147
Optimization Enabled: Yes
Runs (Optimiser):  200



  Contract Source Code   Find Similiar Contracts

/*
-----------------------------------------------------------------
FILE INFORMATION
-----------------------------------------------------------------

file:       Owned.sol
version:    1.1
author:     Anton Jurisevic
            Dominic Romanowski

date:       2018-2-26

-----------------------------------------------------------------
MODULE DESCRIPTION
-----------------------------------------------------------------

An Owned contract, to be inherited by other contracts.
Requires its owner to be explicitly set in the constructor.
Provides an onlyOwner access modifier.

To change owner, the current owner must nominate the next owner,
who then has to accept the nomination. The nomination can be
cancelled before it is accepted by the new owner by having the
previous owner change the nomination (setting it to 0).

-----------------------------------------------------------------
*/

pragma solidity 0.4.24;

/**
 * @title A contract with an owner.
 * @notice Contract ownership can be transferred by first nominating the new owner,
 * who must then accept the ownership, which prevents accidental incorrect ownership transfers.
 */
contract Owned {
    address public owner;
    address public nominatedOwner;

    /**
     * @dev Owned Constructor
     */
    constructor(address _owner)
        public
    {
        require(_owner != address(0), "Owner address cannot be 0");
        owner = _owner;
        emit OwnerChanged(address(0), _owner);
    }

    /**
     * @notice Nominate a new owner of this contract.
     * @dev Only the current owner may nominate a new owner.
     */
    function nominateNewOwner(address _owner)
        external
        onlyOwner
    {
        nominatedOwner = _owner;
        emit OwnerNominated(_owner);
    }

    /**
     * @notice Accept the nomination to be owner.
     */
    function acceptOwnership()
        external
    {
        require(msg.sender == nominatedOwner, "You must be nominated before you can accept ownership");
        emit OwnerChanged(owner, nominatedOwner);
        owner = nominatedOwner;
        nominatedOwner = address(0);
    }

    modifier onlyOwner
    {
        require(msg.sender == owner, "Only the contract owner may perform this action");
        _;
    }

    event OwnerNominated(address newOwner);
    event OwnerChanged(address oldOwner, address newOwner);
}

/*
-----------------------------------------------------------------
FILE INFORMATION
-----------------------------------------------------------------

file:       SelfDestructible.sol
version:    1.2
author:     Anton Jurisevic

date:       2018-05-29

-----------------------------------------------------------------
MODULE DESCRIPTION
-----------------------------------------------------------------

This contract allows an inheriting contract to be destroyed after
its owner indicates an intention and then waits for a period
without changing their mind. All ether contained in the contract
is forwarded to a nominated beneficiary upon destruction.

-----------------------------------------------------------------
*/


/**
 * @title A contract that can be destroyed by its owner after a delay elapses.
 */
contract SelfDestructible is Owned {
	
	uint public initiationTime;
	bool public selfDestructInitiated;
	address public selfDestructBeneficiary;
	uint public constant SELFDESTRUCT_DELAY = 4 weeks;

	/**
	 * @dev Constructor
	 * @param _owner The account which controls this contract.
	 */
	constructor(address _owner)
	    Owned(_owner)
	    public
	{
		require(_owner != address(0), "Owner must not be the zero address");
		selfDestructBeneficiary = _owner;
		emit SelfDestructBeneficiaryUpdated(_owner);
	}

	/**
	 * @notice Set the beneficiary address of this contract.
	 * @dev Only the contract owner may call this. The provided beneficiary must be non-null.
	 * @param _beneficiary The address to pay any eth contained in this contract to upon self-destruction.
	 */
	function setSelfDestructBeneficiary(address _beneficiary)
		external
		onlyOwner
	{
		require(_beneficiary != address(0), "Beneficiary must not be the zero address");
		selfDestructBeneficiary = _beneficiary;
		emit SelfDestructBeneficiaryUpdated(_beneficiary);
	}

	/**
	 * @notice Begin the self-destruction counter of this contract.
	 * Once the delay has elapsed, the contract may be self-destructed.
	 * @dev Only the contract owner may call this.
	 */
	function initiateSelfDestruct()
		external
		onlyOwner
	{
		initiationTime = now;
		selfDestructInitiated = true;
		emit SelfDestructInitiated(SELFDESTRUCT_DELAY);
	}

	/**
	 * @notice Terminate and reset the self-destruction timer.
	 * @dev Only the contract owner may call this.
	 */
	function terminateSelfDestruct()
		external
		onlyOwner
	{
		initiationTime = 0;
		selfDestructInitiated = false;
		emit SelfDestructTerminated();
	}

	/**
	 * @notice If the self-destruction delay has elapsed, destroy this contract and
	 * remit any ether it owns to the beneficiary address.
	 * @dev Only the contract owner may call this.
	 */
	function selfDestruct()
		external
		onlyOwner
	{
		require(selfDestructInitiated, "Self destruct has not yet been initiated");
		require(initiationTime + SELFDESTRUCT_DELAY < now, "Self destruct delay has not yet elapsed");
		address beneficiary = selfDestructBeneficiary;
		emit SelfDestructed(beneficiary);
		selfdestruct(beneficiary);
	}

	event SelfDestructTerminated();
	event SelfDestructed(address beneficiary);
	event SelfDestructInitiated(uint selfDestructDelay);
	event SelfDestructBeneficiaryUpdated(address newBeneficiary);
}


/*
-----------------------------------------------------------------
FILE INFORMATION
-----------------------------------------------------------------

file:       Pausable.sol
version:    1.0
author:     Kevin Brown

date:       2018-05-22

-----------------------------------------------------------------
MODULE DESCRIPTION
-----------------------------------------------------------------

This contract allows an inheriting contract to be marked as
paused. It also defines a modifier which can be used by the
inheriting contract to prevent actions while paused.

-----------------------------------------------------------------
*/


/**
 * @title A contract that can be paused by its owner
 */
contract Pausable is Owned {
    
    uint public lastPauseTime;
    bool public paused;

    /**
     * @dev Constructor
     * @param _owner The account which controls this contract.
     */
    constructor(address _owner)
        Owned(_owner)
        public
    {
        // Paused will be false, and lastPauseTime will be 0 upon initialisation
    }

    /**
     * @notice Change the paused state of the contract
     * @dev Only the contract owner may call this.
     */
    function setPaused(bool _paused)
        external
        onlyOwner
    {
        // Ensure we're actually changing the state before we do anything
        if (_paused == paused) {
            return;
        }

        // Set our paused state.
        paused = _paused;
        
        // If applicable, set the last pause time.
        if (paused) {
            lastPauseTime = now;
        }

        // Let everyone know that our pause state has changed.
        emit PauseChanged(paused);
    }

    event PauseChanged(bool isPaused);

    modifier notPaused {
        require(!paused, "This action cannot be performed while the contract is paused");
        _;
    }
}


/*
-----------------------------------------------------------------
FILE INFORMATION
-----------------------------------------------------------------

file:       SafeDecimalMath.sol
version:    1.0
author:     Anton Jurisevic

date:       2018-2-5

checked:    Mike Spain
approved:   Samuel Brooks

-----------------------------------------------------------------
MODULE DESCRIPTION
-----------------------------------------------------------------

A fixed point decimal library that provides basic mathematical
operations, and checks for unsafe arguments, for example that
would lead to overflows.

Exceptions are thrown whenever those unsafe operations
occur.

-----------------------------------------------------------------
*/


/**
 * @title Safely manipulate unsigned fixed-point decimals at a given precision level.
 * @dev Functions accepting uints in this contract and derived contracts
 * are taken to be such fixed point decimals (including fiat, ether, and nomin quantities).
 */
contract SafeDecimalMath {

    /* Number of decimal places in the representation. */
    uint8 public constant decimals = 18;

    /* The number representing 1.0. */
    uint public constant UNIT = 10 ** uint(decimals);

    /**
     * @return True iff adding x and y will not overflow.
     */
    function addIsSafe(uint x, uint y)
        pure
        internal
        returns (bool)
    {
        return x + y >= y;
    }

    /**
     * @return The result of adding x and y, throwing an exception in case of overflow.
     */
    function safeAdd(uint x, uint y)
        pure
        internal
        returns (uint)
    {
        require(x + y >= y, "Safe add failed");
        return x + y;
    }

    /**
     * @return True iff subtracting y from x will not overflow in the negative direction.
     */
    function subIsSafe(uint x, uint y)
        pure
        internal
        returns (bool)
    {
        return y <= x;
    }

    /**
     * @return The result of subtracting y from x, throwing an exception in case of overflow.
     */
    function safeSub(uint x, uint y)
        pure
        internal
        returns (uint)
    {
        require(y <= x, "Safe sub failed");
        return x - y;
    }

    /**
     * @return True iff multiplying x and y would not overflow.
     */
    function mulIsSafe(uint x, uint y)
        pure
        internal
        returns (bool)
    {
        if (x == 0) {
            return true;
        }
        return (x * y) / x == y;
    }

    /**
     * @return The result of multiplying x and y, throwing an exception in case of overflow.
     */
    function safeMul(uint x, uint y)
        pure
        internal
        returns (uint)
    {
        if (x == 0) {
            return 0;
        }
        uint p = x * y;
        require(p / x == y, "Safe mul failed");
        return p;
    }

    /**
     * @return The result of multiplying x and y, interpreting the operands as fixed-point
     * decimals. Throws an exception in case of overflow.
     * 
     * @dev A unit factor is divided out after the product of x and y is evaluated,
     * so that product must be less than 2**256.
     * Incidentally, the internal division always rounds down: one could have rounded to the nearest integer,
     * but then one would be spending a significant fraction of a cent (of order a microether
     * at present gas prices) in order to save less than one part in 0.5 * 10^18 per operation, if the operands
     * contain small enough fractional components. It would also marginally diminish the 
     * domain this function is defined upon. 
     */
    function safeMul_dec(uint x, uint y)
        pure
        internal
        returns (uint)
    {
        /* Divide by UNIT to remove the extra factor introduced by the product. */
        return safeMul(x, y) / UNIT;

    }

    /**
     * @return True iff the denominator of x/y is nonzero.
     */
    function divIsSafe(uint x, uint y)
        pure
        internal
        returns (bool)
    {
        return y != 0;
    }

    /**
     * @return The result of dividing x by y, throwing an exception if the divisor is zero.
     */
    function safeDiv(uint x, uint y)
        pure
        internal
        returns (uint)
    {
        /* Although a 0 denominator already throws an exception,
         * it is equivalent to a THROW operation, which consumes all gas.
         * A require statement emits REVERT instead, which remits remaining gas. */
        require(y != 0, "Denominator cannot be zero");
        return x / y;
    }

    /**
     * @return The result of dividing x by y, interpreting the operands as fixed point decimal numbers.
     * @dev Throws an exception in case of overflow or zero divisor; x must be less than 2^256 / UNIT.
     * Internal rounding is downward: a similar caveat holds as with safeDecMul().
     */
    function safeDiv_dec(uint x, uint y)
        pure
        internal
        returns (uint)
    {
        /* Reintroduce the UNIT factor that will be divided out by y. */
        return safeDiv(safeMul(x, UNIT), y);
    }

    /**
     * @dev Convert an unsigned integer to a unsigned fixed-point decimal.
     * Throw an exception if the result would be out of range.
     */
    function intToDec(uint i)
        pure
        internal
        returns (uint)
    {
        return safeMul(i, UNIT);
    }
}


/*
-----------------------------------------------------------------
FILE INFORMATION
-----------------------------------------------------------------

file:       State.sol
version:    1.1
author:     Dominic Romanowski
            Anton Jurisevic

date:       2018-05-15

-----------------------------------------------------------------
MODULE DESCRIPTION
-----------------------------------------------------------------

This contract is used side by side with external state token
contracts, such as Havven and Nomin.
It provides an easy way to upgrade contract logic while
maintaining all user balances and allowances. This is designed
to make the changeover as easy as possible, since mappings
are not so cheap or straightforward to migrate.

The first deployed contract would create this state contract,
using it as its store of balances.
When a new contract is deployed, it links to the existing
state contract, whose owner would then change its associated
contract to the new one.

-----------------------------------------------------------------
*/


contract State is Owned {
    // the address of the contract that can modify variables
    // this can only be changed by the owner of this contract
    address public associatedContract;


    constructor(address _owner, address _associatedContract)
        Owned(_owner)
        public
    {
        associatedContract = _associatedContract;
        emit AssociatedContractUpdated(_associatedContract);
    }

    /* ========== SETTERS ========== */

    // Change the associated contract to a new address
    function setAssociatedContract(address _associatedContract)
        external
        onlyOwner
    {
        associatedContract = _associatedContract;
        emit AssociatedContractUpdated(_associatedContract);
    }

    /* ========== MODIFIERS ========== */

    modifier onlyAssociatedContract
    {
        require(msg.sender == associatedContract, "Only the associated contract can perform this action");
        _;
    }

    /* ========== EVENTS ========== */

    event AssociatedContractUpdated(address associatedContract);
}


/*
-----------------------------------------------------------------
FILE INFORMATION
-----------------------------------------------------------------

file:       TokenState.sol
version:    1.1
author:     Dominic Romanowski
            Anton Jurisevic

date:       2018-05-15

-----------------------------------------------------------------
MODULE DESCRIPTION
-----------------------------------------------------------------

A contract that holds the state of an ERC20 compliant token.

This contract is used side by side with external state token
contracts, such as Havven and Nomin.
It provides an easy way to upgrade contract logic while
maintaining all user balances and allowances. This is designed
to make the changeover as easy as possible, since mappings
are not so cheap or straightforward to migrate.

The first deployed contract would create this state contract,
using it as its store of balances.
When a new contract is deployed, it links to the existing
state contract, whose owner would then change its associated
contract to the new one.

-----------------------------------------------------------------
*/


/**
 * @title ERC20 Token State
 * @notice Stores balance information of an ERC20 token contract.
 */
contract TokenState is State {

    /* ERC20 fields. */
    mapping(address => uint) public balanceOf;
    mapping(address => mapping(address => uint)) public allowance;

    /**
     * @dev Constructor
     * @param _owner The address which controls this contract.
     * @param _associatedContract The ERC20 contract whose state this composes.
     */
    constructor(address _owner, address _associatedContract)
        State(_owner, _associatedContract)
        public
    {}

    /* ========== SETTERS ========== */

    /**
     * @notice Set ERC20 allowance.
     * @dev Only the associated contract may call this.
     * @param tokenOwner The authorising party.
     * @param spender The authorised party.
     * @param value The total value the authorised party may spend on the
     * authorising party's behalf.
     */
    function setAllowance(address tokenOwner, address spender, uint value)
        external
        onlyAssociatedContract
    {
        allowance[tokenOwner][spender] = value;
    }

    /**
     * @notice Set the balance in a given account
     * @dev Only the associated contract may call this.
     * @param account The account whose value to set.
     * @param value The new balance of the given account.
     */
    function setBalanceOf(address account, uint value)
        external
        onlyAssociatedContract
    {
        balanceOf[account] = value;
    }
}


/*
-----------------------------------------------------------------
FILE INFORMATION
-----------------------------------------------------------------

file:       Proxy.sol
version:    1.3
author:     Anton Jurisevic

date:       2018-05-29

-----------------------------------------------------------------
MODULE DESCRIPTION
-----------------------------------------------------------------

A proxy contract that, if it does not recognise the function
being called on it, passes all value and call data to an
underlying target contract.

This proxy has the capacity to toggle between DELEGATECALL
and CALL style proxy functionality.

The former executes in the proxy's context, and so will preserve 
msg.sender and store data at the proxy address. The latter will not.
Therefore, any contract the proxy wraps in the CALL style must
implement the Proxyable interface, in order that it can pass msg.sender
into the underlying contract as the state parameter, messageSender.

-----------------------------------------------------------------
*/


contract Proxy is Owned {

    Proxyable public target;
    bool public useDELEGATECALL;

    constructor(address _owner)
        Owned(_owner)
        public
    {}

    function setTarget(Proxyable _target)
        external
        onlyOwner
    {
        target = _target;
        emit TargetUpdated(_target);
    }

    function setUseDELEGATECALL(bool value) 
        external
        onlyOwner
    {
        useDELEGATECALL = value;
    }

    function _emit(bytes callData, uint numTopics,
                   bytes32 topic1, bytes32 topic2,
                   bytes32 topic3, bytes32 topic4)
        external
        onlyTarget
    {
        uint size = callData.length;
        bytes memory _callData = callData;

        assembly {
            /* The first 32 bytes of callData contain its length (as specified by the abi). 
             * Length is assumed to be a uint256 and therefore maximum of 32 bytes
             * in length. It is also leftpadded to be a multiple of 32 bytes.
             * This means moving call_data across 32 bytes guarantees we correctly access
             * the data itself. */
            switch numTopics
            case 0 {
                log0(add(_callData, 32), size)
            } 
            case 1 {
                log1(add(_callData, 32), size, topic1)
            }
            case 2 {
                log2(add(_callData, 32), size, topic1, topic2)
            }
            case 3 {
                log3(add(_callData, 32), size, topic1, topic2, topic3)
            }
            case 4 {
                log4(add(_callData, 32), size, topic1, topic2, topic3, topic4)
            }
        }
    }

    function()
        external
        payable
    {
        if (useDELEGATECALL) {
            assembly {
                /* Copy call data into free memory region. */
                let free_ptr := mload(0x40)
                calldatacopy(free_ptr, 0, calldatasize)

                /* Forward all gas and call data to the target contract. */
                let result := delegatecall(gas, sload(target_slot), free_ptr, calldatasize, 0, 0)
                returndatacopy(free_ptr, 0, returndatasize)

                /* Revert if the call failed, otherwise return the result. */
                if iszero(result) { revert(free_ptr, returndatasize) }
                return(free_ptr, returndatasize)
            }
        } else {
            /* Here we are as above, but must send the messageSender explicitly 
             * since we are using CALL rather than DELEGATECALL. */
            target.setMessageSender(msg.sender);
            assembly {
                let free_ptr := mload(0x40)
                calldatacopy(free_ptr, 0, calldatasize)

                /* We must explicitly forward ether to the underlying contract as well. */
                let result := call(gas, sload(target_slot), callvalue, free_ptr, calldatasize, 0, 0)
                returndatacopy(free_ptr, 0, returndatasize)

                if iszero(result) { revert(free_ptr, returndatasize) }
                return(free_ptr, returndatasize)
            }
        }
    }

    modifier onlyTarget {
        require(Proxyable(msg.sender) == target, "This action can only be performed by the proxy target");
        _;
    }

    event TargetUpdated(Proxyable newTarget);
}


/*
-----------------------------------------------------------------
FILE INFORMATION
-----------------------------------------------------------------

file:       Proxyable.sol
version:    1.1
author:     Anton Jurisevic

date:       2018-05-15

checked:    Mike Spain
approved:   Samuel Brooks

-----------------------------------------------------------------
MODULE DESCRIPTION
-----------------------------------------------------------------

A proxyable contract that works hand in hand with the Proxy contract
to allow for anyone to interact with the underlying contract both
directly and through the proxy.

-----------------------------------------------------------------
*/


// This contract should be treated like an abstract contract
contract Proxyable is Owned {
    /* The proxy this contract exists behind. */
    Proxy public proxy;

    /* The caller of the proxy, passed through to this contract.
     * Note that every function using this member must apply the onlyProxy or
     * optionalProxy modifiers, otherwise their invocations can use stale values. */ 
    address messageSender; 

    constructor(address _proxy, address _owner)
        Owned(_owner)
        public
    {
        proxy = Proxy(_proxy);
        emit ProxyUpdated(_proxy);
    }

    function setProxy(address _proxy)
        external
        onlyOwner
    {
        proxy = Proxy(_proxy);
        emit ProxyUpdated(_proxy);
    }

    function setMessageSender(address sender)
        external
        onlyProxy
    {
        messageSender = sender;
    }

    modifier onlyProxy {
        require(Proxy(msg.sender) == proxy, "Only the proxy can call this function");
        _;
    }

    modifier optionalProxy
    {
        if (Proxy(msg.sender) != proxy) {
            messageSender = msg.sender;
        }
        _;
    }

    modifier optionalProxy_onlyOwner
    {
        if (Proxy(msg.sender) != proxy) {
            messageSender = msg.sender;
        }
        require(messageSender == owner, "This action can only be performed by the owner");
        _;
    }

    event ProxyUpdated(address proxyAddress);
}


/*
-----------------------------------------------------------------
FILE INFORMATION
-----------------------------------------------------------------

file:       ExternStateToken.sol
version:    1.0
author:     Kevin Brown
date:       2018-08-06

-----------------------------------------------------------------
MODULE DESCRIPTION
-----------------------------------------------------------------

This contract offers a modifer that can prevent reentrancy on
particular actions. It will not work if you put it on multiple
functions that can be called from each other. Specifically guard
external entry points to the contract with the modifier only.

-----------------------------------------------------------------
*/

contract ReentrancyPreventer {
    /* ========== MODIFIERS ========== */
    bool isInFunctionBody = false;

    modifier preventReentrancy {
        require(!isInFunctionBody, "Reverted to prevent reentrancy");
        isInFunctionBody = true;
        _;
        isInFunctionBody = false;
    }
}

/*
-----------------------------------------------------------------
FILE INFORMATION
-----------------------------------------------------------------

file:       ExternStateToken.sol
version:    1.3
author:     Anton Jurisevic
            Dominic Romanowski

date:       2018-05-29

-----------------------------------------------------------------
MODULE DESCRIPTION
-----------------------------------------------------------------

A partial ERC20 token contract, designed to operate with a proxy.
To produce a complete ERC20 token, transfer and transferFrom
tokens must be implemented, using the provided _byProxy internal
functions.
This contract utilises an external state for upgradeability.

-----------------------------------------------------------------
*/


/**
 * @title ERC20 Token contract, with detached state and designed to operate behind a proxy.
 */
contract ExternStateToken is SafeDecimalMath, SelfDestructible, Proxyable, ReentrancyPreventer {

    /* ========== STATE VARIABLES ========== */

    /* Stores balances and allowances. */
    TokenState public tokenState;

    /* Other ERC20 fields.
     * Note that the decimals field is defined in SafeDecimalMath.*/
    string public name;
    string public symbol;
    uint public totalSupply;

    /**
     * @dev Constructor.
     * @param _proxy The proxy associated with this contract.
     * @param _name Token's ERC20 name.
     * @param _symbol Token's ERC20 symbol.
     * @param _totalSupply The total supply of the token.
     * @param _tokenState The TokenState contract address.
     * @param _owner The owner of this contract.
     */
    constructor(address _proxy, TokenState _tokenState,
                string _name, string _symbol, uint _totalSupply,
                address _owner)
        SelfDestructible(_owner)
        Proxyable(_proxy, _owner)
        public
    {
        name = _name;
        symbol = _symbol;
        totalSupply = _totalSupply;
        tokenState = _tokenState;
    }

    /* ========== VIEWS ========== */

    /**
     * @notice Returns the ERC20 allowance of one party to spend on behalf of another.
     * @param owner The party authorising spending of their funds.
     * @param spender The party spending tokenOwner's funds.
     */
    function allowance(address owner, address spender)
        public
        view
        returns (uint)
    {
        return tokenState.allowance(owner, spender);
    }

    /**
     * @notice Returns the ERC20 token balance of a given account.
     */
    function balanceOf(address account)
        public
        view
        returns (uint)
    {
        return tokenState.balanceOf(account);
    }

    /* ========== MUTATIVE FUNCTIONS ========== */

    /**
     * @notice Set the address of the TokenState contract.
     * @dev This can be used to "pause" transfer functionality, by pointing the tokenState at 0x000..
     * as balances would be unreachable.
     */ 
    function setTokenState(TokenState _tokenState)
        external
        optionalProxy_onlyOwner
    {
        tokenState = _tokenState;
        emitTokenStateUpdated(_tokenState);
    }

    function _internalTransfer(address from, address to, uint value) 
        internal
        preventReentrancy
        returns (bool)
    { 
        /* Disallow transfers to irretrievable-addresses. */
        require(to != address(0), "Cannot transfer to the 0 address");
        require(to != address(this), "Cannot transfer to the underlying contract");
        require(to != address(proxy), "Cannot transfer to the proxy contract");

        /* Insufficient balance will be handled by the safe subtraction. */
        tokenState.setBalanceOf(from, safeSub(tokenState.balanceOf(from), value));
        tokenState.setBalanceOf(to, safeAdd(tokenState.balanceOf(to), value));

        /*
        If we're transferring to a contract and it implements the havvenTokenFallback function, call it.
        This isn't ERC223 compliant because:
           1. We don't revert if the contract doesn't implement havvenTokenFallback.
              This is because many DEXes and other contracts that expect to work with the standard
              approve / transferFrom workflow don't implement tokenFallback but can still process our tokens as
              usual, so it feels very harsh and likely to cause trouble if we add this restriction after having
              previously gone live with a vanilla ERC20.
           2. We don't pass the bytes parameter.
              This is because of this solidity bug: https://github.com/ethereum/solidity/issues/2884
           3. We also don't let the user use a custom tokenFallback. We figure as we're already not standards
              compliant, there won't be a use case where users can't just implement our specific function.

        As such we've called the function havvenTokenFallback to be clear that we are not following the standard.
        */

        // Is the to address a contract? We can check the code size on that address and know.
        uint length;

        // solium-disable-next-line security/no-inline-assembly
        assembly {
            // Retrieve the size of the code on the recipient address
            length := extcodesize(to)
        }

        // If there's code there, it's a contract
        if (length > 0) {
            // Now we need to optionally call havvenTokenFallback(address from, uint value).
            // We can't call it the normal way because that reverts when the recipient doesn't implement the function.
            // We'll use .call(), which means we need the function selector. We've pre-computed
            // abi.encodeWithSignature("havvenTokenFallback(address,uint256)"), to save some gas.

            // solium-disable-next-line security/no-low-level-calls
            to.call(0xcbff5d96, messageSender, value);

            // And yes, we specifically don't care if this call fails, so we're not checking the return value.
        }

        // Emit a standard ERC20 transfer event
        emitTransfer(from, to, value);

        return true;
    }

    /**
     * @dev Perform an ERC20 token transfer. Designed to be called by transfer functions possessing
     * the onlyProxy or optionalProxy modifiers.
     */
    function _transfer_byProxy(address from, address to, uint value)
        internal
        returns (bool)
    {
        return _internalTransfer(from, to, value);
    }

    /**
     * @dev Perform an ERC20 token transferFrom. Designed to be called by transferFrom functions
     * possessing the optionalProxy or optionalProxy modifiers.
     */
    function _transferFrom_byProxy(address sender, address from, address to, uint value)
        internal
        returns (bool)
    {
        /* Insufficient allowance will be handled by the safe subtraction. */
        tokenState.setAllowance(from, sender, safeSub(tokenState.allowance(from, sender), value));
        return _internalTransfer(from, to, value);
    }

    /**
     * @notice Approves spender to transfer on the message sender's behalf.
     */
    function approve(address spender, uint value)
        public
        optionalProxy
        returns (bool)
    {
        address sender = messageSender;

        tokenState.setAllowance(sender, spender, value);
        emitApproval(sender, spender, value);
        return true;
    }

    /* ========== EVENTS ========== */

    event Transfer(address indexed from, address indexed to, uint value);
    bytes32 constant TRANSFER_SIG = keccak256("Transfer(address,address,uint256)");
    function emitTransfer(address from, address to, uint value) internal {
        proxy._emit(abi.encode(value), 3, TRANSFER_SIG, bytes32(from), bytes32(to), 0);
    }

    event Approval(address indexed owner, address indexed spender, uint value);
    bytes32 constant APPROVAL_SIG = keccak256("Approval(address,address,uint256)");
    function emitApproval(address owner, address spender, uint value) internal {
        proxy._emit(abi.encode(value), 3, APPROVAL_SIG, bytes32(owner), bytes32(spender), 0);
    }

    event TokenStateUpdated(address newTokenState);
    bytes32 constant TOKENSTATEUPDATED_SIG = keccak256("TokenStateUpdated(address)");
    function emitTokenStateUpdated(address newTokenState) internal {
        proxy._emit(abi.encode(newTokenState), 1, TOKENSTATEUPDATED_SIG, 0, 0, 0);
    }
}


/*
-----------------------------------------------------------------
FILE INFORMATION
-----------------------------------------------------------------

file:       FeeToken.sol
version:    1.3
author:     Anton Jurisevic
            Dominic Romanowski
            Kevin Brown

date:       2018-05-29

-----------------------------------------------------------------
MODULE DESCRIPTION
-----------------------------------------------------------------

A token which also has a configurable fee rate
charged on its transfers. This is designed to be overridden in
order to produce an ERC20-compliant token.

These fees accrue into a pool, from which a nominated authority
may withdraw.

This contract utilises an external state for upgradeability.

-----------------------------------------------------------------
*/


/**
 * @title ERC20 Token contract, with detached state.
 * Additionally charges fees on each transfer.
 */
contract FeeToken is ExternStateToken {

    /* ========== STATE VARIABLES ========== */

    /* ERC20 members are declared in ExternStateToken. */

    /* A percentage fee charged on each transfer. */
    uint public transferFeeRate;
    /* Fee may not exceed 10%. */
    uint constant MAX_TRANSFER_FEE_RATE = UNIT / 10;
    /* The address with the authority to distribute fees. */
    address public feeAuthority;
    /* The address that fees will be pooled in. */
    address public constant FEE_ADDRESS = 0xfeefeefeefeefeefeefeefeefeefeefeefeefeef;


    /* ========== CONSTRUCTOR ========== */

    /**
     * @dev Constructor.
     * @param _proxy The proxy associated with this contract.
     * @param _name Token's ERC20 name.
     * @param _symbol Token's ERC20 symbol.
     * @param _totalSupply The total supply of the token.
     * @param _transferFeeRate The fee rate to charge on transfers.
     * @param _feeAuthority The address which has the authority to withdraw fees from the accumulated pool.
     * @param _owner The owner of this contract.
     */
    constructor(address _proxy, TokenState _tokenState, string _name, string _symbol, uint _totalSupply,
                uint _transferFeeRate, address _feeAuthority, address _owner)
        ExternStateToken(_proxy, _tokenState,
                         _name, _symbol, _totalSupply,
                         _owner)
        public
    {
        feeAuthority = _feeAuthority;

        /* Constructed transfer fee rate should respect the maximum fee rate. */
        require(_transferFeeRate <= MAX_TRANSFER_FEE_RATE, "Constructed transfer fee rate should respect the maximum fee rate");
        transferFeeRate = _transferFeeRate;
    }

    /* ========== SETTERS ========== */

    /**
     * @notice Set the transfer fee, anywhere within the range 0-10%.
     * @dev The fee rate is in decimal format, with UNIT being the value of 100%.
     */
    function setTransferFeeRate(uint _transferFeeRate)
        external
        optionalProxy_onlyOwner
    {
        require(_transferFeeRate <= MAX_TRANSFER_FEE_RATE, "Transfer fee rate must be below MAX_TRANSFER_FEE_RATE");
        transferFeeRate = _transferFeeRate;
        emitTransferFeeRateUpdated(_transferFeeRate);
    }

    /**
     * @notice Set the address of the user/contract responsible for collecting or
     * distributing fees.
     */
    function setFeeAuthority(address _feeAuthority)
        public
        optionalProxy_onlyOwner
    {
        feeAuthority = _feeAuthority;
        emitFeeAuthorityUpdated(_feeAuthority);
    }

    /* ========== VIEWS ========== */

    /**
     * @notice Calculate the Fee charged on top of a value being sent
     * @return Return the fee charged
     */
    function transferFeeIncurred(uint value)
        public
        view
        returns (uint)
    {
        return safeMul_dec(value, transferFeeRate);
        /* Transfers less than the reciprocal of transferFeeRate should be completely eaten up by fees.
         * This is on the basis that transfers less than this value will result in a nil fee.
         * Probably too insignificant to worry about, but the following code will achieve it.
         *      if (fee == 0 && transferFeeRate != 0) {
         *          return _value;
         *      }
         *      return fee;
         */
    }

    /**
     * @notice The value that you would need to send so that the recipient receives
     * a specified value.
     */
    function transferPlusFee(uint value)
        external
        view
        returns (uint)
    {
        return safeAdd(value, transferFeeIncurred(value));
    }

    /**
     * @notice The amount the recipient will receive if you send a certain number of tokens.
     */
    function amountReceived(uint value)
        public
        view
        returns (uint)
    {
        return safeDiv_dec(value, safeAdd(UNIT, transferFeeRate));
    }

    /**
     * @notice Collected fees sit here until they are distributed.
     * @dev The balance of the nomin contract itself is the fee pool.
     */
    function feePool()
        external
        view
        returns (uint)
    {
        return tokenState.balanceOf(FEE_ADDRESS);
    }

    /* ========== MUTATIVE FUNCTIONS ========== */

    /**
     * @notice Base of transfer functions
     */
    function _internalTransfer(address from, address to, uint amount, uint fee)
        internal
        returns (bool)
    {
        /* Disallow transfers to irretrievable-addresses. */
        require(to != address(0), "Cannot transfer to the 0 address");
        require(to != address(this), "Cannot transfer to the underlying contract");
        require(to != address(proxy), "Cannot transfer to the proxy contract");

        /* Insufficient balance will be handled by the safe subtraction. */
        tokenState.setBalanceOf(from, safeSub(tokenState.balanceOf(from), safeAdd(amount, fee)));
        tokenState.setBalanceOf(to, safeAdd(tokenState.balanceOf(to), amount));
        tokenState.setBalanceOf(FEE_ADDRESS, safeAdd(tokenState.balanceOf(FEE_ADDRESS), fee));

        /* Emit events for both the transfer itself and the fee. */
        emitTransfer(from, to, amount);
        emitTransfer(from, FEE_ADDRESS, fee);

        return true;
    }

    /**
     * @notice ERC20 friendly transfer function.
     */
    function _transfer_byProxy(address sender, address to, uint value)
        internal
        returns (bool)
    {
        uint received = amountReceived(value);
        uint fee = safeSub(value, received);

        return _internalTransfer(sender, to, received, fee);
    }

    /**
     * @notice ERC20 friendly transferFrom function.
     */
    function _transferFrom_byProxy(address sender, address from, address to, uint value)
        internal
        returns (bool)
    {
        /* The fee is deducted from the amount sent. */
        uint received = amountReceived(value);
        uint fee = safeSub(value, received);

        /* Reduce the allowance by the amount we're transferring.
         * The safeSub call will handle an insufficient allowance. */
        tokenState.setAllowance(from, sender, safeSub(tokenState.allowance(from, sender), value));

        return _internalTransfer(from, to, received, fee);
    }

    /**
     * @notice Ability to transfer where the sender pays the fees (not ERC20)
     */
    function _transferSenderPaysFee_byProxy(address sender, address to, uint value)
        internal
        returns (bool)
    {
        /* The fee is added to the amount sent. */
        uint fee = transferFeeIncurred(value);
        return _internalTransfer(sender, to, value, fee);
    }

    /**
     * @notice Ability to transferFrom where they sender pays the fees (not ERC20).
     */
    function _transferFromSenderPaysFee_byProxy(address sender, address from, address to, uint value)
        internal
        returns (bool)
    {
        /* The fee is added to the amount sent. */
        uint fee = transferFeeIncurred(value);
        uint total = safeAdd(value, fee);

        /* Reduce the allowance by the amount we're transferring. */
        tokenState.setAllowance(from, sender, safeSub(tokenState.allowance(from, sender), total));

        return _internalTransfer(from, to, value, fee);
    }

    /**
     * @notice Withdraw tokens from the fee pool into a given account.
     * @dev Only the fee authority may call this.
     */
    function withdrawFees(address account, uint value)
        external
        onlyFeeAuthority
        returns (bool)
    {
        require(account != address(0), "Must supply an account address to withdraw fees");

        /* 0-value withdrawals do nothing. */
        if (value == 0) {
            return false;
        }

        /* Safe subtraction ensures an exception is thrown if the balance is insufficient. */
        tokenState.setBalanceOf(FEE_ADDRESS, safeSub(tokenState.balanceOf(FEE_ADDRESS), value));
        tokenState.setBalanceOf(account, safeAdd(tokenState.balanceOf(account), value));

        emitFeesWithdrawn(account, value);
        emitTransfer(FEE_ADDRESS, account, value);

        return true;
    }

    /**
     * @notice Donate tokens from the sender's balance into the fee pool.
     */
    function donateToFeePool(uint n)
        external
        optionalProxy
        returns (bool)
    {
        address sender = messageSender;
        /* Empty donations are disallowed. */
        uint balance = tokenState.balanceOf(sender);
        require(balance != 0, "Must have a balance in order to donate to the fee pool");

        /* safeSub ensures the donor has sufficient balance. */
        tokenState.setBalanceOf(sender, safeSub(balance, n));
        tokenState.setBalanceOf(FEE_ADDRESS, safeAdd(tokenState.balanceOf(FEE_ADDRESS), n));

        emitFeesDonated(sender, n);
        emitTransfer(sender, FEE_ADDRESS, n);

        return true;
    }


    /* ========== MODIFIERS ========== */

    modifier onlyFeeAuthority
    {
        require(msg.sender == feeAuthority, "Only the fee authority can do this action");
        _;
    }


    /* ========== EVENTS ========== */

    event TransferFeeRateUpdated(uint newFeeRate);
    bytes32 constant TRANSFERFEERATEUPDATED_SIG = keccak256("TransferFeeRateUpdated(uint256)");
    function emitTransferFeeRateUpdated(uint newFeeRate) internal {
        proxy._emit(abi.encode(newFeeRate), 1, TRANSFERFEERATEUPDATED_SIG, 0, 0, 0);
    }

    event FeeAuthorityUpdated(address newFeeAuthority);
    bytes32 constant FEEAUTHORITYUPDATED_SIG = keccak256("FeeAuthorityUpdated(address)");
    function emitFeeAuthorityUpdated(address newFeeAuthority) internal {
        proxy._emit(abi.encode(newFeeAuthority), 1, FEEAUTHORITYUPDATED_SIG, 0, 0, 0);
    } 

    event FeesWithdrawn(address indexed account, uint value);
    bytes32 constant FEESWITHDRAWN_SIG = keccak256("FeesWithdrawn(address,uint256)");
    function emitFeesWithdrawn(address account, uint value) internal {
        proxy._emit(abi.encode(value), 2, FEESWITHDRAWN_SIG, bytes32(account), 0, 0);
    }

    event FeesDonated(address indexed donor, uint value);
    bytes32 constant FEESDONATED_SIG = keccak256("FeesDonated(address,uint256)");
    function emitFeesDonated(address donor, uint value) internal {
        proxy._emit(abi.encode(value), 2, FEESDONATED_SIG, bytes32(donor), 0, 0);
    }
}


/*
-----------------------------------------------------------------
FILE INFORMATION
-----------------------------------------------------------------

file:       Nomin.sol
version:    1.2
author:     Anton Jurisevic
            Mike Spain
            Dominic Romanowski
            Kevin Brown

date:       2018-05-29

-----------------------------------------------------------------
MODULE DESCRIPTION
-----------------------------------------------------------------

Havven-backed nomin stablecoin contract.

This contract issues nomins, which are tokens worth 1 USD each.

Nomins are issuable by Havven holders who have to lock up some
value of their havvens to issue H * Cmax nomins. Where Cmax is
some value less than 1.

A configurable fee is charged on nomin transfers and deposited
into a common pot, which havven holders may withdraw from once
per fee period.

-----------------------------------------------------------------
*/


contract Nomin is FeeToken {

    /* ========== STATE VARIABLES ========== */

    Havven public havven;

    // Accounts which have lost the privilege to transact in nomins.
    mapping(address => bool) public frozen;

    // Nomin transfers incur a 15 bp fee by default.
    uint constant TRANSFER_FEE_RATE = 15 * UNIT / 10000;
    string constant TOKEN_NAME = "Nomin USD";
    string constant TOKEN_SYMBOL = "nUSD";

    /* ========== CONSTRUCTOR ========== */

    constructor(address _proxy, TokenState _tokenState, Havven _havven,
                uint _totalSupply,
                address _owner)
        FeeToken(_proxy, _tokenState,
                 TOKEN_NAME, TOKEN_SYMBOL, _totalSupply,
                 TRANSFER_FEE_RATE,
                 _havven, // The havven contract is the fee authority.
                 _owner)
        public
    {
        require(_proxy != 0, "_proxy cannot be 0");
        require(address(_havven) != 0, "_havven cannot be 0");
        require(_owner != 0, "_owner cannot be 0");

        // It should not be possible to transfer to the fee pool directly (or confiscate its balance).
        frozen[FEE_ADDRESS] = true;
        havven = _havven;
    }

    /* ========== SETTERS ========== */

    function setHavven(Havven _havven)
        external
        optionalProxy_onlyOwner
    {
        // havven should be set as the feeAuthority after calling this depending on
        // havven's internal logic
        havven = _havven;
        setFeeAuthority(_havven);
        emitHavvenUpdated(_havven);
    }


    /* ========== MUTATIVE FUNCTIONS ========== */

    /* Override ERC20 transfer function in order to check
     * whether the recipient account is frozen. Note that there is
     * no need to check whether the sender has a frozen account,
     * since their funds have already been confiscated,
     * and no new funds can be transferred to it.*/
    function transfer(address to, uint value)
        public
        optionalProxy
        returns (bool)
    {
        require(!frozen[to], "Cannot transfer to frozen address");
        return _transfer_byProxy(messageSender, to, value);
    }

    /* Override ERC20 transferFrom function in order to check
     * whether the recipient account is frozen. */
    function transferFrom(address from, address to, uint value)
        public
        optionalProxy
        returns (bool)
    {
        require(!frozen[to], "Cannot transfer to frozen address");
        return _transferFrom_byProxy(messageSender, from, to, value);
    }

    function transferSenderPaysFee(address to, uint value)
        public
        optionalProxy
        returns (bool)
    {
        require(!frozen[to], "Cannot transfer to frozen address");
        return _transferSenderPaysFee_byProxy(messageSender, to, value);
    }

    function transferFromSenderPaysFee(address from, address to, uint value)
        public
        optionalProxy
        returns (bool)
    {
        require(!frozen[to], "Cannot transfer to frozen address");
        return _transferFromSenderPaysFee_byProxy(messageSender, from, to, value);
    }

    /* The owner may allow a previously-frozen contract to once
     * again accept and transfer nomins. */
    function unfreezeAccount(address target)
        external
        optionalProxy_onlyOwner
    {
        require(frozen[target] && target != FEE_ADDRESS, "Account must be frozen, and cannot be the fee address");
        frozen[target] = false;
        emitAccountUnfrozen(target);
    }

    /* Allow havven to issue a certain number of
     * nomins from an account. */
    function issue(address account, uint amount)
        external
        onlyHavven
    {
        tokenState.setBalanceOf(account, safeAdd(tokenState.balanceOf(account), amount));
        totalSupply = safeAdd(totalSupply, amount);
        emitTransfer(address(0), account, amount);
        emitIssued(account, amount);
    }

    /* Allow havven to burn a certain number of
     * nomins from an account. */
    function burn(address account, uint amount)
        external
        onlyHavven
    {
        tokenState.setBalanceOf(account, safeSub(tokenState.balanceOf(account), amount));
        totalSupply = safeSub(totalSupply, amount);
        emitTransfer(account, address(0), amount);
        emitBurned(account, amount);
    }

    /* ========== MODIFIERS ========== */

    modifier onlyHavven() {
        require(Havven(msg.sender) == havven, "Only the Havven contract can perform this action");
        _;
    }

    /* ========== EVENTS ========== */

    event HavvenUpdated(address newHavven);
    bytes32 constant HAVVENUPDATED_SIG = keccak256("HavvenUpdated(address)");
    function emitHavvenUpdated(address newHavven) internal {
        proxy._emit(abi.encode(newHavven), 1, HAVVENUPDATED_SIG, 0, 0, 0);
    }

    event AccountFrozen(address indexed target, uint balance);
    bytes32 constant ACCOUNTFROZEN_SIG = keccak256("AccountFrozen(address,uint256)");
    function emitAccountFrozen(address target, uint balance) internal {
        proxy._emit(abi.encode(balance), 2, ACCOUNTFROZEN_SIG, bytes32(target), 0, 0);
    }

    event AccountUnfrozen(address indexed target);
    bytes32 constant ACCOUNTUNFROZEN_SIG = keccak256("AccountUnfrozen(address)");
    function emitAccountUnfrozen(address target) internal {
        proxy._emit(abi.encode(), 2, ACCOUNTUNFROZEN_SIG, bytes32(target), 0, 0);
    }

    event Issued(address indexed account, uint amount);
    bytes32 constant ISSUED_SIG = keccak256("Issued(address,uint256)");
    function emitIssued(address account, uint amount) internal {
        proxy._emit(abi.encode(amount), 2, ISSUED_SIG, bytes32(account), 0, 0);
    }

    event Burned(address indexed account, uint amount);
    bytes32 constant BURNED_SIG = keccak256("Burned(address,uint256)");
    function emitBurned(address account, uint amount) internal {
        proxy._emit(abi.encode(amount), 2, BURNED_SIG, bytes32(account), 0, 0);
    }
}


/*
-----------------------------------------------------------------
FILE INFORMATION
-----------------------------------------------------------------

file:       LimitedSetup.sol
version:    1.1
author:     Anton Jurisevic

date:       2018-05-15

-----------------------------------------------------------------
MODULE DESCRIPTION
-----------------------------------------------------------------

A contract with a limited setup period. Any function modified
with the setup modifier will cease to work after the
conclusion of the configurable-length post-construction setup period.

-----------------------------------------------------------------
*/


/**
 * @title Any function decorated with the modifier this contract provides
 * deactivates after a specified setup period.
 */
contract LimitedSetup {

    uint setupExpiryTime;

    /**
     * @dev LimitedSetup Constructor.
     * @param setupDuration The time the setup period will last for.
     */
    constructor(uint setupDuration)
        public
    {
        setupExpiryTime = now + setupDuration;
    }

    modifier onlyDuringSetup
    {
        require(now < setupExpiryTime, "Can only perform this action during setup");
        _;
    }
}


/*
-----------------------------------------------------------------
FILE INFORMATION
-----------------------------------------------------------------

file:       HavvenEscrow.sol
version:    1.1
author:     Anton Jurisevic
            Dominic Romanowski
            Mike Spain

date:       2018-05-29

-----------------------------------------------------------------
MODULE DESCRIPTION
-----------------------------------------------------------------

This contract allows the foundation to apply unique vesting
schedules to havven funds sold at various discounts in the token
sale. HavvenEscrow gives users the ability to inspect their
vested funds, their quantities and vesting dates, and to withdraw
the fees that accrue on those funds.

The fees are handled by withdrawing the entire fee allocation
for all havvens inside the escrow contract, and then allowing
the contract itself to subdivide that pool up proportionally within
itself. Every time the fee period rolls over in the main Havven
contract, the HavvenEscrow fee pool is remitted back into the
main fee pool to be redistributed in the next fee period.

-----------------------------------------------------------------
*/


/**
 * @title A contract to hold escrowed havvens and free them at given schedules.
 */
contract HavvenEscrow is SafeDecimalMath, Owned, LimitedSetup(8 weeks) {
    /* The corresponding Havven contract. */
    Havven public havven;

    /* Lists of (timestamp, quantity) pairs per account, sorted in ascending time order.
     * These are the times at which each given quantity of havvens vests. */
    mapping(address => uint[2][]) public vestingSchedules;

    /* An account's total vested havven balance to save recomputing this for fee extraction purposes. */
    mapping(address => uint) public totalVestedAccountBalance;

    /* The total remaining vested balance, for verifying the actual havven balance of this contract against. */
    uint public totalVestedBalance;

    uint constant TIME_INDEX = 0;
    uint constant QUANTITY_INDEX = 1;

    /* Limit vesting entries to disallow unbounded iteration over vesting schedules. */
    uint constant MAX_VESTING_ENTRIES = 20;


    /* ========== CONSTRUCTOR ========== */

    constructor(address _owner, Havven _havven)
        Owned(_owner)
        public
    {
        havven = _havven;
    }


    /* ========== SETTERS ========== */

    function setHavven(Havven _havven)
        external
        onlyOwner
    {
        havven = _havven;
        emit HavvenUpdated(_havven);
    }


    /* ========== VIEW FUNCTIONS ========== */

    /**
     * @notice A simple alias to totalVestedAccountBalance: provides ERC20 balance integration.
     */
    function balanceOf(address account)
        public
        view
        returns (uint)
    {
        return totalVestedAccountBalance[account];
    }

    /**
     * @notice The number of vesting dates in an account's schedule.
     */
    function numVestingEntries(address account)
        public
        view
        returns (uint)
    {
        return vestingSchedules[account].length;
    }

    /**
     * @notice Get a particular schedule entry for an account.
     * @return A pair of uints: (timestamp, havven quantity).
     */
    function getVestingScheduleEntry(address account, uint index)
        public
        view
        returns (uint[2])
    {
        return vestingSchedules[account][index];
    }

    /**
     * @notice Get the time at which a given schedule entry will vest.
     */
    function getVestingTime(address account, uint index)
        public
        view
        returns (uint)
    {
        return getVestingScheduleEntry(account,index)[TIME_INDEX];
    }

    /**
     * @notice Get the quantity of havvens associated with a given schedule entry.
     */
    function getVestingQuantity(address account, uint index)
        public
        view
        returns (uint)
    {
        return getVestingScheduleEntry(account,index)[QUANTITY_INDEX];
    }

    /**
     * @notice Obtain the index of the next schedule entry that will vest for a given user.
     */
    function getNextVestingIndex(address account)
        public
        view
        returns (uint)
    {
        uint len = numVestingEntries(account);
        for (uint i = 0; i < len; i++) {
            if (getVestingTime(account, i) != 0) {
                return i;
            }
        }
        return len;
    }

    /**
     * @notice Obtain the next schedule entry that will vest for a given user.
     * @return A pair of uints: (timestamp, havven quantity). */
    function getNextVestingEntry(address account)
        public
        view
        returns (uint[2])
    {
        uint index = getNextVestingIndex(account);
        if (index == numVestingEntries(account)) {
            return [uint(0), 0];
        }
        return getVestingScheduleEntry(account, index);
    }

    /**
     * @notice Obtain the time at which the next schedule entry will vest for a given user.
     */
    function getNextVestingTime(address account)
        external
        view
        returns (uint)
    {
        return getNextVestingEntry(account)[TIME_INDEX];
    }

    /**
     * @notice Obtain the quantity which the next schedule entry will vest for a given user.
     */
    function getNextVestingQuantity(address account)
        external
        view
        returns (uint)
    {
        return getNextVestingEntry(account)[QUANTITY_INDEX];
    }


    /* ========== MUTATIVE FUNCTIONS ========== */

    /**
     * @notice Withdraws a quantity of havvens back to the havven contract.
     * @dev This may only be called by the owner during the contract's setup period.
     */
    function withdrawHavvens(uint quantity)
        external
        onlyOwner
        onlyDuringSetup
    {
        havven.transfer(havven, quantity);
    }

    /**
     * @notice Destroy the vesting information associated with an account.
     */
    function purgeAccount(address account)
        external
        onlyOwner
        onlyDuringSetup
    {
        delete vestingSchedules[account];
        totalVestedBalance = safeSub(totalVestedBalance, totalVestedAccountBalance[account]);
        delete totalVestedAccountBalance[account];
    }

    /**
     * @notice Add a new vesting entry at a given time and quantity to an account's schedule.
     * @dev A call to this should be accompanied by either enough balance already available
     * in this contract, or a corresponding call to havven.endow(), to ensure that when
     * the funds are withdrawn, there is enough balance, as well as correctly calculating
     * the fees.
     * This may only be called by the owner during the contract's setup period.
     * Note; although this function could technically be used to produce unbounded
     * arrays, it's only in the foundation's command to add to these lists.
     * @param account The account to append a new vesting entry to.
     * @param time The absolute unix timestamp after which the vested quantity may be withdrawn.
     * @param quantity The quantity of havvens that will vest.
     */
    function appendVestingEntry(address account, uint time, uint quantity)
        public
        onlyOwner
        onlyDuringSetup
    {
        /* No empty or already-passed vesting entries allowed. */
        require(now < time, "Time must be in the future");
        require(quantity != 0, "Quantity cannot be zero");

        /* There must be enough balance in the contract to provide for the vesting entry. */
        totalVestedBalance = safeAdd(totalVestedBalance, quantity);
        require(totalVestedBalance <= havven.balanceOf(this), "Must be enough balance in the contract to provide for the vesting entry");

        /* Disallow arbitrarily long vesting schedules in light of the gas limit. */
        uint scheduleLength = vestingSchedules[account].length;
        require(scheduleLength <= MAX_VESTING_ENTRIES, "Vesting schedule is too long");

        if (scheduleLength == 0) {
            totalVestedAccountBalance[account] = quantity;
        } else {
            /* Disallow adding new vested havvens earlier than the last one.
             * Since entries are only appended, this means that no vesting date can be repeated. */
            require(getVestingTime(account, numVestingEntries(account) - 1) < time, "Cannot add new vested entries earlier than the last one");
            totalVestedAccountBalance[account] = safeAdd(totalVestedAccountBalance[account], quantity);
        }

        vestingSchedules[account].push([time, quantity]);
    }

    /**
     * @notice Construct a vesting schedule to release a quantities of havvens
     * over a series of intervals.
     * @dev Assumes that the quantities are nonzero
     * and that the sequence of timestamps is strictly increasing.
     * This may only be called by the owner during the contract's setup period.
     */
    function addVestingSchedule(address account, uint[] times, uint[] quantities)
        external
        onlyOwner
        onlyDuringSetup
    {
        for (uint i = 0; i < times.length; i++) {
            appendVestingEntry(account, times[i], quantities[i]);
        }

    }

    /**
     * @notice Allow a user to withdraw any havvens in their schedule that have vested.
     */
    function vest()
        external
    {
        uint numEntries = numVestingEntries(msg.sender);
        uint total;
        for (uint i = 0; i < numEntries; i++) {
            uint time = getVestingTime(msg.sender, i);
            /* The list is sorted; when we reach the first future time, bail out. */
            if (time > now) {
                break;
            }
            uint qty = getVestingQuantity(msg.sender, i);
            if (qty == 0) {
                continue;
            }

            vestingSchedules[msg.sender][i] = [0, 0];
            total = safeAdd(total, qty);
        }

        if (total != 0) {
            totalVestedBalance = safeSub(totalVestedBalance, total);
            totalVestedAccountBalance[msg.sender] = safeSub(totalVestedAccountBalance[msg.sender], total);
            havven.transfer(msg.sender, total);
            emit Vested(msg.sender, now, total);
        }
    }


    /* ========== EVENTS ========== */

    event HavvenUpdated(address newHavven);

    event Vested(address indexed beneficiary, uint time, uint value);
}


/*
-----------------------------------------------------------------
FILE INFORMATION
-----------------------------------------------------------------

file:       Havven.sol
version:    1.2
author:     Anton Jurisevic
            Dominic Romanowski

date:       2018-05-15

-----------------------------------------------------------------
MODULE DESCRIPTION
-----------------------------------------------------------------

Havven token contract. Havvens are transferable ERC20 tokens,
and also give their holders the following privileges.
An owner of havvens may participate in nomin confiscation votes, they
may also have the right to issue nomins at the discretion of the
foundation for this version of the contract.

After a fee period terminates, the duration and fees collected for that
period are computed, and the next period begins. Thus an account may only
withdraw the fees owed to them for the previous period, and may only do
so once per period. Any unclaimed fees roll over into the common pot for
the next period.

== Average Balance Calculations ==

The fee entitlement of a havven holder is proportional to their average
issued nomin balance over the last fee period. This is computed by
measuring the area under the graph of a user's issued nomin balance over
time, and then when a new fee period begins, dividing through by the
duration of the fee period.

We need only update values when the balances of an account is modified.
This occurs when issuing or burning for issued nomin balances,
and when transferring for havven balances. This is for efficiency,
and adds an implicit friction to interacting with havvens.
A havven holder pays for his own recomputation whenever he wants to change
his position, which saves the foundation having to maintain a pot dedicated
to resourcing this.

A hypothetical user's balance history over one fee period, pictorially:

      s ____
       |    |
       |    |___ p
       |____|___|___ __ _  _
       f    t   n

Here, the balance was s between times f and t, at which time a transfer
occurred, updating the balance to p, until n, when the present transfer occurs.
When a new transfer occurs at time n, the balance being p,
we must:

  - Add the area p * (n - t) to the total area recorded so far
  - Update the last transfer time to n

So if this graph represents the entire current fee period,
the average havvens held so far is ((t-f)*s + (n-t)*p) / (n-f).
The complementary computations must be performed for both sender and
recipient.

Note that a transfer keeps global supply of havvens invariant.
The sum of all balances is constant, and unmodified by any transfer.
So the sum of all balances multiplied by the duration of a fee period is also
constant, and this is equivalent to the sum of the area of every user's
time/balance graph. Dividing through by that duration yields back the total
havven supply. So, at the end of a fee period, we really do yield a user's
average share in the havven supply over that period.

A slight wrinkle is introduced if we consider the time r when the fee period
rolls over. Then the previous fee period k-1 is before r, and the current fee
period k is afterwards. If the last transfer took place before r,
but the latest transfer occurred afterwards:

k-1       |        k
      s __|_
       |  | |
       |  | |____ p
       |__|_|____|___ __ _  _
          |
       f  | t    n
          r

In this situation the area (r-f)*s contributes to fee period k-1, while
the area (t-r)*s contributes to fee period k. We will implicitly consider a
zero-value transfer to have occurred at time r. Their fee entitlement for the
previous period will be finalised at the time of their first transfer during the
current fee period, or when they query or withdraw their fee entitlement.

In the implementation, the duration of different fee periods may be slightly irregular,
as the check that they have rolled over occurs only when state-changing havven
operations are performed.

== Issuance and Burning ==

In this version of the havven contract, nomins can only be issued by
those that have been nominated by the havven foundation. Nomins are assumed
to be valued at $1, as they are a stable unit of account.

All nomins issued require a proportional value of havvens to be locked,
where the proportion is governed by the current issuance ratio. This
means for every $1 of Havvens locked up, $(issuanceRatio) nomins can be issued.
i.e. to issue 100 nomins, 100/issuanceRatio dollars of havvens need to be locked up.

To determine the value of some amount of havvens(H), an oracle is used to push
the price of havvens (P_H) in dollars to the contract. The value of H
would then be: H * P_H.

Any havvens that are locked up by this issuance process cannot be transferred.
The amount that is locked floats based on the price of havvens. If the price
of havvens moves up, less havvens are locked, so they can be issued against,
or transferred freely. If the price of havvens moves down, more havvens are locked,
even going above the initial wallet balance.

-----------------------------------------------------------------
*/


/**
 * @title Havven ERC20 contract.
 * @notice The Havven contracts does not only facilitate transfers and track balances,
 * but it also computes the quantity of fees each havven holder is entitled to.
 */
contract Havven is ExternStateToken {

    /* ========== STATE VARIABLES ========== */

    /* A struct for handing values associated with average balance calculations */
    struct IssuanceData {
        /* Sums of balances*duration in the current fee period.
        /* range: decimals; units: havven-seconds */
        uint currentBalanceSum;
        /* The last period's average balance */
        uint lastAverageBalance;
        /* The last time the data was calculated */
        uint lastModified;
    }

    /* Issued nomin balances for individual fee entitlements */
    mapping(address => IssuanceData) public issuanceData;
    /* The total number of issued nomins for determining fee entitlements */
    IssuanceData public totalIssuanceData;

    /* The time the current fee period began */
    uint public feePeriodStartTime;
    /* The time the last fee period began */
    uint public lastFeePeriodStartTime;

    /* Fee periods will roll over in no shorter a time than this. 
     * The fee period cannot actually roll over until a fee-relevant
     * operation such as withdrawal or a fee period duration update occurs,
     * so this is just a target, and the actual duration may be slightly longer. */
    uint public feePeriodDuration = 4 weeks;
    /* ...and must target between 1 day and six months. */
    uint constant MIN_FEE_PERIOD_DURATION = 1 days;
    uint constant MAX_FEE_PERIOD_DURATION = 26 weeks;

    /* The quantity of nomins that were in the fee pot at the time */
    /* of the last fee rollover, at feePeriodStartTime. */
    uint public lastFeesCollected;

    /* Whether a user has withdrawn their last fees */
    mapping(address => bool) public hasWithdrawnFees;

    Nomin public nomin;
    HavvenEscrow public escrow;

    /* The address of the oracle which pushes the havven price to this contract */
    address public oracle;
    /* The price of havvens written in UNIT */
    uint public price;
    /* The time the havven price was last updated */
    uint public lastPriceUpdateTime;
    /* How long will the contract assume the price of havvens is correct */
    uint public priceStalePeriod = 3 hours;

    /* A quantity of nomins greater than this ratio
     * may not be issued against a given value of havvens. */
    uint public issuanceRatio = UNIT / 5;
    /* No more nomins may be issued than the value of havvens backing them. */
    uint constant MAX_ISSUANCE_RATIO = UNIT;

    /* Whether the address can issue nomins or not. */
    mapping(address => bool) public isIssuer;
    /* The number of currently-outstanding nomins the user has issued. */
    mapping(address => uint) public nominsIssued;

    uint constant HAVVEN_SUPPLY = 1e8 * UNIT;
    uint constant ORACLE_FUTURE_LIMIT = 10 minutes;
    string constant TOKEN_NAME = "Havven";
    string constant TOKEN_SYMBOL = "HAV";
    
    /* ========== CONSTRUCTOR ========== */

    /**
     * @dev Constructor
     * @param _tokenState A pre-populated contract containing token balances.
     * If the provided address is 0x0, then a fresh one will be constructed with the contract owning all tokens.
     * @param _owner The owner of this contract.
     */
    constructor(address _proxy, TokenState _tokenState, address _owner, address _oracle,
                uint _price, address[] _issuers, Havven _oldHavven)
        ExternStateToken(_proxy, _tokenState, TOKEN_NAME, TOKEN_SYMBOL, HAVVEN_SUPPLY, _owner)
        public
    {
        oracle = _oracle;
        price = _price;
        lastPriceUpdateTime = now;

        uint i;
        if (_oldHavven == address(0)) {
            feePeriodStartTime = now;
            lastFeePeriodStartTime = now - feePeriodDuration;
            for (i = 0; i < _issuers.length; i++) {
                isIssuer[_issuers[i]] = true;
            }
        } else {
            feePeriodStartTime = _oldHavven.feePeriodStartTime();
            lastFeePeriodStartTime = _oldHavven.lastFeePeriodStartTime();

            uint cbs;
            uint lab;
            uint lm;
            (cbs, lab, lm) = _oldHavven.totalIssuanceData();
            totalIssuanceData.currentBalanceSum = cbs;
            totalIssuanceData.lastAverageBalance = lab;
            totalIssuanceData.lastModified = lm;

            for (i = 0; i < _issuers.length; i++) {
                address issuer = _issuers[i];
                isIssuer[issuer] = true;
                uint nomins = _oldHavven.nominsIssued(issuer);
                if (nomins == 0) {
                    // It is not valid in general to skip those with no currently-issued nomins.
                    // But for this release, issuers with nonzero issuanceData have current issuance.
                    continue;
                }
                (cbs, lab, lm) = _oldHavven.issuanceData(issuer);
                nominsIssued[issuer] = nomins;
                issuanceData[issuer].currentBalanceSum = cbs;
                issuanceData[issuer].lastAverageBalance = lab;
                issuanceData[issuer].lastModified = lm;
            }
        }

    }

    /* ========== SETTERS ========== */

    /**
     * @notice Set the associated Nomin contract to collect fees from.
     * @dev Only the contract owner may call this.
     */
    function setNomin(Nomin _nomin)
        external
        optionalProxy_onlyOwner
    {
        nomin = _nomin;
        emitNominUpdated(_nomin);
    }

    /**
     * @notice Set the associated havven escrow contract.
     * @dev Only the contract owner may call this.
     */
    function setEscrow(HavvenEscrow _escrow)
        external
        optionalProxy_onlyOwner
    {
        escrow = _escrow;
        emitEscrowUpdated(_escrow);
    }

    /**
     * @notice Set the targeted fee period duration.
     * @dev Only callable by the contract owner. The duration must fall within
     * acceptable bounds (1 day to 26 weeks). Upon resetting this the fee period
     * may roll over if the target duration was shortened sufficiently.
     */
    function setFeePeriodDuration(uint duration)
        external
        optionalProxy_onlyOwner
    {
        require(MIN_FEE_PERIOD_DURATION <= duration && duration <= MAX_FEE_PERIOD_DURATION,
            "Duration must be between MIN_FEE_PERIOD_DURATION and MAX_FEE_PERIOD_DURATION");
        feePeriodDuration = duration;
        emitFeePeriodDurationUpdated(duration);
        rolloverFeePeriodIfElapsed();
    }

    /**
     * @notice Set the Oracle that pushes the havven price to this contract
     */
    function setOracle(address _oracle)
        external
        optionalProxy_onlyOwner
    {
        oracle = _oracle;
        emitOracleUpdated(_oracle);
    }

    /**
     * @notice Set the stale period on the updated havven price
     * @dev No max/minimum, as changing it wont influence anything but issuance by the foundation
     */
    function setPriceStalePeriod(uint time)
        external
        optionalProxy_onlyOwner
    {
        priceStalePeriod = time;
    }

    /**
     * @notice Set the issuanceRatio for issuance calculations.
     * @dev Only callable by the contract owner.
     */
    function setIssuanceRatio(uint _issuanceRatio)
        external
        optionalProxy_onlyOwner
    {
        require(_issuanceRatio <= MAX_ISSUANCE_RATIO, "New issuance ratio must be less than or equal to MAX_ISSUANCE_RATIO");
        issuanceRatio = _issuanceRatio;
        emitIssuanceRatioUpdated(_issuanceRatio);
    }

    /**
     * @notice Set whether the specified can issue nomins or not.
     */
    function setIssuer(address account, bool value)
        external
        optionalProxy_onlyOwner
    {
        isIssuer[account] = value;
        emitIssuersUpdated(account, value);
    }

    /* ========== VIEWS ========== */

    function issuanceCurrentBalanceSum(address account)
        external
        view
        returns (uint)
    {
        return issuanceData[account].currentBalanceSum;
    }

    function issuanceLastAverageBalance(address account)
        external
        view
        returns (uint)
    {
        return issuanceData[account].lastAverageBalance;
    }

    function issuanceLastModified(address account)
        external
        view
        returns (uint)
    {
        return issuanceData[account].lastModified;
    }

    function totalIssuanceCurrentBalanceSum()
        external
        view
        returns (uint)
    {
        return totalIssuanceData.currentBalanceSum;
    }

    function totalIssuanceLastAverageBalance()
        external
        view
        returns (uint)
    {
        return totalIssuanceData.lastAverageBalance;
    }

    function totalIssuanceLastModified()
        external
        view
        returns (uint)
    {
        return totalIssuanceData.lastModified;
    }

    /* ========== MUTATIVE FUNCTIONS ========== */

    /**
     * @notice ERC20 transfer function.
     */
    function transfer(address to, uint value)
        public
        optionalProxy
        returns (bool)
    {
        address sender = messageSender;
        require(nominsIssued[sender] == 0 || value <= transferableHavvens(sender), "Value to transfer exceeds available havvens");
        /* Perform the transfer: if there is a problem,
         * an exception will be thrown in this call. */
        _transfer_byProxy(sender, to, value);

        return true;
    }

    /**
     * @notice ERC20 transferFrom function.
     */
    function transferFrom(address from, address to, uint value)
        public
        optionalProxy
        returns (bool)
    {
        address sender = messageSender;
        require(nominsIssued[from] == 0 || value <= transferableHavvens(from), "Value to transfer exceeds available havvens");
        /* Perform the transfer: if there is a problem,
         * an exception will be thrown in this call. */
        _transferFrom_byProxy(sender, from, to, value);

        return true;
    }

    /**
     * @notice Compute the last period's fee entitlement for the message sender
     * and then deposit it into their nomin account.
     */
    function withdrawFees()
        external
        optionalProxy
    {
        address sender = messageSender;
        rolloverFeePeriodIfElapsed();
        /* Do not deposit fees into frozen accounts. */
        require(!nomin.frozen(sender), "Cannot deposit fees into frozen accounts");

        /* Check the period has rolled over first. */
        updateIssuanceData(sender, nominsIssued[sender], nomin.totalSupply());

        /* Only allow accounts to withdraw fees once per period. */
        require(!hasWithdrawnFees[sender], "Fees have already been withdrawn in this period");

        uint feesOwed;
        uint lastTotalIssued = totalIssuanceData.lastAverageBalance;

        if (lastTotalIssued > 0) {
            /* Sender receives a share of last period's collected fees proportional
             * with their average fraction of the last period's issued nomins. */
            feesOwed = safeDiv_dec(
                safeMul_dec(issuanceData[sender].lastAverageBalance, lastFeesCollected),
                lastTotalIssued
            );
        }

        hasWithdrawnFees[sender] = true;

        if (feesOwed != 0) {
            nomin.withdrawFees(sender, feesOwed);
        }
        emitFeesWithdrawn(messageSender, feesOwed);
    }

    /**
     * @notice Update the havven balance averages since the last transfer
     * or entitlement adjustment.
     * @dev Since this updates the last transfer timestamp, if invoked
     * consecutively, this function will do nothing after the first call.
     * Also, this will adjust the total issuance at the same time.
     */
    function updateIssuanceData(address account, uint preBalance, uint lastTotalSupply)
        internal
    {
        /* update the total balances first */
        totalIssuanceData = computeIssuanceData(lastTotalSupply, totalIssuanceData);

        if (issuanceData[account].lastModified < feePeriodStartTime) {
            hasWithdrawnFees[account] = false;
        }

        issuanceData[account] = computeIssuanceData(preBalance, issuanceData[account]);
    }


    /**
     * @notice Compute the new IssuanceData on the old balance
     */
    function computeIssuanceData(uint preBalance, IssuanceData preIssuance)
        internal
        view
        returns (IssuanceData)
    {

        uint currentBalanceSum = preIssuance.currentBalanceSum;
        uint lastAverageBalance = preIssuance.lastAverageBalance;
        uint lastModified = preIssuance.lastModified;

        if (lastModified < feePeriodStartTime) {
            if (lastModified < lastFeePeriodStartTime) {
                /* The balance was last updated before the previous fee period, so the average
                 * balance in this period is their pre-transfer balance. */
                lastAverageBalance = preBalance;
            } else {
                /* The balance was last updated during the previous fee period. */
                /* No overflow or zero denominator problems, since lastFeePeriodStartTime < feePeriodStartTime < lastModified. 
                 * implies these quantities are strictly positive. */
                uint timeUpToRollover = feePeriodStartTime - lastModified;
                uint lastFeePeriodDuration = feePeriodStartTime - lastFeePeriodStartTime;
                uint lastBalanceSum = safeAdd(currentBalanceSum, safeMul(preBalance, timeUpToRollover));
                lastAverageBalance = lastBalanceSum / lastFeePeriodDuration;
            }
            /* Roll over to the next fee period. */
            currentBalanceSum = safeMul(preBalance, now - feePeriodStartTime);
        } else {
            /* The balance was last updated during the current fee period. */
            currentBalanceSum = safeAdd(
                currentBalanceSum,
                safeMul(preBalance, now - lastModified)
            );
        }

        return IssuanceData(currentBalanceSum, lastAverageBalance, now);
    }

    /**
     * @notice Recompute and return the given account's last average balance.
     */
    function recomputeLastAverageBalance(address account)
        external
        returns (uint)
    {
        updateIssuanceData(account, nominsIssued[account], nomin.totalSupply());
        return issuanceData[account].lastAverageBalance;
    }

    /**
     * @notice Issue nomins against the sender's havvens.
     * @dev Issuance is only allowed if the havven price isn't stale and the sender is an issuer.
     */
    function issueNomins(uint amount)
        public
        optionalProxy
        requireIssuer(messageSender)
        /* No need to check if price is stale, as it is checked in issuableNomins. */
    {
        address sender = messageSender;
        require(amount <= remainingIssuableNomins(sender), "Amount must be less than or equal to remaining issuable nomins");
        uint lastTot = nomin.totalSupply();
        uint preIssued = nominsIssued[sender];
        nomin.issue(sender, amount);
        nominsIssued[sender] = safeAdd(preIssued, amount);
        updateIssuanceData(sender, preIssued, lastTot);
    }

    function issueMaxNomins()
        external
        optionalProxy
    {
        issueNomins(remainingIssuableNomins(messageSender));
    }

    /**
     * @notice Burn nomins to clear issued nomins/free havvens.
     */
    function burnNomins(uint amount)
        /* it doesn't matter if the price is stale or if the user is an issuer, as non-issuers have issued no nomins.*/
        external
        optionalProxy
    {
        address sender = messageSender;

        uint lastTot = nomin.totalSupply();
        uint preIssued = nominsIssued[sender];
        /* nomin.burn does a safeSub on balance (so it will revert if there are not enough nomins). */
        nomin.burn(sender, amount);
        /* This safe sub ensures amount <= number issued */
        nominsIssued[sender] = safeSub(preIssued, amount);
        updateIssuanceData(sender, preIssued, lastTot);
    }

    /**
     * @notice Check if the fee period has rolled over. If it has, set the new fee period start
     * time, and record the fees collected in the nomin contract.
     */
    function rolloverFeePeriodIfElapsed()
        public
    {
        /* If the fee period has rolled over... */
        if (now >= feePeriodStartTime + feePeriodDuration) {
            lastFeesCollected = nomin.feePool();
            lastFeePeriodStartTime = feePeriodStartTime;
            feePeriodStartTime = now;
            emitFeePeriodRollover(now);
        }
    }

    /* ========== Issuance/Burning ========== */

    /**
     * @notice The maximum nomins an issuer can issue against their total havven quantity. This ignores any
     * already issued nomins.
     */
    function maxIssuableNomins(address issuer)
        view
        public
        priceNotStale
        returns (uint)
    {
        if (!isIssuer[issuer]) {
            return 0;
        }
        if (escrow != HavvenEscrow(0)) {
            uint totalOwnedHavvens = safeAdd(tokenState.balanceOf(issuer), escrow.balanceOf(issuer));
            return safeMul_dec(HAVtoUSD(totalOwnedHavvens), issuanceRatio);
        } else {
            return safeMul_dec(HAVtoUSD(tokenState.balanceOf(issuer)), issuanceRatio);
        }
    }

    /**
     * @notice The remaining nomins an issuer can issue against their total havven quantity.
     */
    function remainingIssuableNomins(address issuer)
        view
        public
        returns (uint)
    {
        uint issued = nominsIssued[issuer];
        uint max = maxIssuableNomins(issuer);
        if (issued > max) {
            return 0;
        } else {
            return safeSub(max, issued);
        }
    }

    /**
     * @notice The total havvens owned by this account, both escrowed and unescrowed,
     * against which nomins can be issued.
     * This includes those already being used as collateral (locked), and those
     * available for further issuance (unlocked).
     */
    function collateral(address account)
        public
        view
        returns (uint)
    {
        uint bal = tokenState.balanceOf(account);
        if (escrow != address(0)) {
            bal = safeAdd(bal, escrow.balanceOf(account));
        }
        return bal;
    }

    /**
     * @notice The collateral that would be locked by issuance, which can exceed the account's actual collateral.
     */
    function issuanceDraft(address account)
        public
        view
        returns (uint)
    {
        uint issued = nominsIssued[account];
        if (issued == 0) {
            return 0;
        }
        return USDtoHAV(safeDiv_dec(issued, issuanceRatio));
    }

    /**
     * @notice Collateral that has been locked due to issuance, and cannot be
     * transferred to other addresses. This is capped at the account's total collateral.
     */
    function lockedCollateral(address account)
        public
        view
        returns (uint)
    {
        uint debt = issuanceDraft(account);
        uint collat = collateral(account);
        if (debt > collat) {
            return collat;
        }
        return debt;
    }

    /**
     * @notice Collateral that is not locked and available for issuance.
     */
    function unlockedCollateral(address account)
        public
        view
        returns (uint)
    {
        uint locked = lockedCollateral(account);
        uint collat = collateral(account);
        return safeSub(collat, locked);
    }

    /**
     * @notice The number of havvens that are free to be transferred by an account.
     * @dev If they have enough available Havvens, it could be that
     * their havvens are escrowed, however the transfer would then
     * fail. This means that escrowed havvens are locked first,
     * and then the actual transferable ones.
     */
    function transferableHavvens(address account)
        public
        view
        returns (uint)
    {
        uint draft = issuanceDraft(account);
        uint collat = collateral(account);
        // In the case where the issuanceDraft exceeds the collateral, nothing is free
        if (draft > collat) {
            return 0;
        }

        uint bal = balanceOf(account);
        // In the case where the draft exceeds the escrow, but not the whole collateral
        //   return the fraction of the balance that remains free
        if (draft > safeSub(collat, bal)) {
            return safeSub(collat, draft);
        }
        // In the case where the draft doesn't exceed the escrow, return the entire balance
        return bal;
    }

    /**
     * @notice The value in USD for a given amount of HAV
     */
    function HAVtoUSD(uint hav_dec)
        public
        view
        priceNotStale
        returns (uint)
    {
        return safeMul_dec(hav_dec, price);
    }

    /**
     * @notice The value in HAV for a given amount of USD
     */
    function USDtoHAV(uint usd_dec)
        public
        view
        priceNotStale
        returns (uint)
    {
        return safeDiv_dec(usd_dec, price);
    }

    /**
     * @notice Access point for the oracle to update the price of havvens.
     */
    function updatePrice(uint newPrice, uint timeSent)
        external
        onlyOracle  /* Should be callable only by the oracle. */
    {
        /* Must be the most recently sent price, but not too far in the future.
         * (so we can't lock ourselves out of updating the oracle for longer than this) */
        require(lastPriceUpdateTime < timeSent && timeSent < now + ORACLE_FUTURE_LIMIT,
            "Time sent must be bigger than the last update, and must be less than now + ORACLE_FUTURE_LIMIT");

        price = newPrice;
        lastPriceUpdateTime = timeSent;
        emitPriceUpdated(newPrice, timeSent);

        /* Check the fee period rollover within this as the price should be pushed every 15min. */
        rolloverFeePeriodIfElapsed();
    }

    /**
     * @notice Check if the price of havvens hasn't been updated for longer than the stale period.
     */
    function priceIsStale()
        public
        view
        returns (bool)
    {
        return safeAdd(lastPriceUpdateTime, priceStalePeriod) < now;
    }

    /* ========== MODIFIERS ========== */

    modifier requireIssuer(address account)
    {
        require(isIssuer[account], "Must be issuer to perform this action");
        _;
    }

    modifier onlyOracle
    {
        require(msg.sender == oracle, "Must be oracle to perform this action");
        _;
    }

    modifier priceNotStale
    {
        require(!priceIsStale(), "Price must not be stale to perform this action");
        _;
    }

    /* ========== EVENTS ========== */

    event PriceUpdated(uint newPrice, uint timestamp);
    bytes32 constant PRICEUPDATED_SIG = keccak256("PriceUpdated(uint256,uint256)");
    function emitPriceUpdated(uint newPrice, uint timestamp) internal {
        proxy._emit(abi.encode(newPrice, timestamp), 1, PRICEUPDATED_SIG, 0, 0, 0);
    }

    event IssuanceRatioUpdated(uint newRatio);
    bytes32 constant ISSUANCERATIOUPDATED_SIG = keccak256("IssuanceRatioUpdated(uint256)");
    function emitIssuanceRatioUpdated(uint newRatio) internal {
        proxy._emit(abi.encode(newRatio), 1, ISSUANCERATIOUPDATED_SIG, 0, 0, 0);
    }

    event FeePeriodRollover(uint timestamp);
    bytes32 constant FEEPERIODROLLOVER_SIG = keccak256("FeePeriodRollover(uint256)");
    function emitFeePeriodRollover(uint timestamp) internal {
        proxy._emit(abi.encode(timestamp), 1, FEEPERIODROLLOVER_SIG, 0, 0, 0);
    } 

    event FeePeriodDurationUpdated(uint duration);
    bytes32 constant FEEPERIODDURATIONUPDATED_SIG = keccak256("FeePeriodDurationUpdated(uint256)");
    function emitFeePeriodDurationUpdated(uint duration) internal {
        proxy._emit(abi.encode(duration), 1, FEEPERIODDURATIONUPDATED_SIG, 0, 0, 0);
    } 

    event FeesWithdrawn(address indexed account, uint value);
    bytes32 constant FEESWITHDRAWN_SIG = keccak256("FeesWithdrawn(address,uint256)");
    function emitFeesWithdrawn(address account, uint value) internal {
        proxy._emit(abi.encode(value), 2, FEESWITHDRAWN_SIG, bytes32(account), 0, 0);
    }

    event OracleUpdated(address newOracle);
    bytes32 constant ORACLEUPDATED_SIG = keccak256("OracleUpdated(address)");
    function emitOracleUpdated(address newOracle) internal {
        proxy._emit(abi.encode(newOracle), 1, ORACLEUPDATED_SIG, 0, 0, 0);
    }

    event NominUpdated(address newNomin);
    bytes32 constant NOMINUPDATED_SIG = keccak256("NominUpdated(address)");
    function emitNominUpdated(address newNomin) internal {
        proxy._emit(abi.encode(newNomin), 1, NOMINUPDATED_SIG, 0, 0, 0);
    }

    event EscrowUpdated(address newEscrow);
    bytes32 constant ESCROWUPDATED_SIG = keccak256("EscrowUpdated(address)");
    function emitEscrowUpdated(address newEscrow) internal {
        proxy._emit(abi.encode(newEscrow), 1, ESCROWUPDATED_SIG, 0, 0, 0);
    }

    event IssuersUpdated(address indexed account, bool indexed value);
    bytes32 constant ISSUERSUPDATED_SIG = keccak256("IssuersUpdated(address,bool)");
    function emitIssuersUpdated(address account, bool value) internal {
        proxy._emit(abi.encode(), 3, ISSUERSUPDATED_SIG, bytes32(account), bytes32(value ? 1 : 0), 0);
    }

}


/*
-----------------------------------------------------------------
FILE INFORMATION -----------------------------------------------------------------

file:       IssuanceController.sol
version:    2.0
author:     Kevin Brown

date:       2018-07-18

-----------------------------------------------------------------
MODULE DESCRIPTION
-----------------------------------------------------------------

Issuance controller contract. The issuance controller provides
a way for users to acquire nomins (Nomin.sol) and havvens
(Havven.sol) by paying ETH and a way for users to acquire havvens
(Havven.sol) by paying nomins. Users can also deposit their nomins
and allow other users to purchase them with ETH. The ETH is sent
to the user who offered their nomins for sale.

This smart contract contains a balance of each currency, and
allows the owner of the contract (the Havven Foundation) to
manage the available balance of havven at their discretion, while
users are allowed to deposit and withdraw their own nomin deposits
if they have not yet been taken up by another user.

-----------------------------------------------------------------
*/


/**
 * @title Issuance Controller Contract.
 */
contract IssuanceController is SafeDecimalMath, SelfDestructible, Pausable {

    /* ========== STATE VARIABLES ========== */
    Havven public havven;
    Nomin public nomin;

    // Address where the ether raised is transfered to
    address public fundsWallet;

    /* The address of the oracle which pushes the USD price havvens and ether to this contract */
    address public oracle;
    /* Do not allow the oracle to submit times any further forward into the future than
       this constant. */
    uint constant ORACLE_FUTURE_LIMIT = 10 minutes;

    /* How long will the contract assume the price of any asset is correct */
    uint public priceStalePeriod = 3 hours;

    /* The time the prices were last updated */
    uint public lastPriceUpdateTime;
    /* The USD price of havvens denominated in UNIT */
    uint public usdToHavPrice;
    /* The USD price of ETH denominated in UNIT */
    uint public usdToEthPrice;
    
    /* ========== CONSTRUCTOR ========== */

    /**
     * @dev Constructor
     * @param _owner The owner of this contract.
     * @param _fundsWallet The recipient of ETH and Nomins that are sent to this contract while exchanging.
     * @param _havven The Havven contract we'll interact with for balances and sending.
     * @param _nomin The Nomin contract we'll interact with for balances and sending.
     * @param _oracle The address which is able to update price information.
     * @param _usdToEthPrice The current price of ETH in USD, expressed in UNIT.
     * @param _usdToHavPrice The current price of Havven in USD, expressed in UNIT.
     */
    constructor(
        // Ownable
        address _owner,

        // Funds Wallet
        address _fundsWallet,

        // Other contracts needed
        Havven _havven,
        Nomin _nomin,

        // Oracle values - Allows for price updates
        address _oracle,
        uint _usdToEthPrice,
        uint _usdToHavPrice
    )
        /* Owned is initialised in SelfDestructible */
        SelfDestructible(_owner)
        Pausable(_owner)
        public
    {
        fundsWallet = _fundsWallet;
        havven = _havven;
        nomin = _nomin;
        oracle = _oracle;
        usdToEthPrice = _usdToEthPrice;
        usdToHavPrice = _usdToHavPrice;
        lastPriceUpdateTime = now;
    }

    /* ========== SETTERS ========== */

    /**
     * @notice Set the funds wallet where ETH raised is held
     * @param _fundsWallet The new address to forward ETH and Nomins to
     */
    function setFundsWallet(address _fundsWallet)
        external
        onlyOwner
    {
        fundsWallet = _fundsWallet;
        emit FundsWalletUpdated(fundsWallet);
    }
    
    /**
     * @notice Set the Oracle that pushes the havven price to this contract
     * @param _oracle The new oracle address
     */
    function setOracle(address _oracle)
        external
        onlyOwner
    {
        oracle = _oracle;
        emit OracleUpdated(oracle);
    }

    /**
     * @notice Set the Nomin contract that the issuance controller uses to issue Nomins.
     * @param _nomin The new nomin contract target
     */
    function setNomin(Nomin _nomin)
        external
        onlyOwner
    {
        nomin = _nomin;
        emit NominUpdated(_nomin);
    }

    /**
     * @notice Set the Havven contract that the issuance controller uses to issue Havvens.
     * @param _havven The new havven contract target
     */
    function setHavven(Havven _havven)
        external
        onlyOwner
    {
        havven = _havven;
        emit HavvenUpdated(_havven);
    }

    /**
     * @notice Set the stale period on the updated price variables
     * @param _time The new priceStalePeriod
     */
    function setPriceStalePeriod(uint _time)
        external
        onlyOwner 
    {
        priceStalePeriod = _time;
        emit PriceStalePeriodUpdated(priceStalePeriod);
    }

    /* ========== MUTATIVE FUNCTIONS ========== */
    /**
     * @notice Access point for the oracle to update the prices of havvens / eth.
     * @param newEthPrice The current price of ether in USD, specified to 18 decimal places.
     * @param newHavvenPrice The current price of havvens in USD, specified to 18 decimal places.
     * @param timeSent The timestamp from the oracle when the transaction was created. This ensures we don't consider stale prices as current in times of heavy network congestion.
     */
    function updatePrices(uint newEthPrice, uint newHavvenPrice, uint timeSent)
        external
        onlyOracle
    {
        /* Must be the most recently sent price, but not too far in the future.
         * (so we can't lock ourselves out of updating the oracle for longer than this) */
        require(lastPriceUpdateTime < timeSent && timeSent < now + ORACLE_FUTURE_LIMIT, 
            "Time sent must be bigger than the last update, and must be less than now + ORACLE_FUTURE_LIMIT");

        usdToEthPrice = newEthPrice;
        usdToHavPrice = newHavvenPrice;
        lastPriceUpdateTime = timeSent;

        emit PricesUpdated(usdToEthPrice, usdToHavPrice, lastPriceUpdateTime);
    }

    /**
     * @notice Fallback function (exchanges ETH to nUSD)
     */
    function ()
        external
        payable
    {
        exchangeEtherForNomins();
    } 

    /**
     * @notice Exchange ETH to nUSD.
     */
    function exchangeEtherForNomins()
        public 
        payable
        pricesNotStale
        notPaused
        returns (uint) // Returns the number of Nomins (nUSD) received
    {
        // The multiplication works here because usdToEthPrice is specified in
        // 18 decimal places, just like our currency base.
        uint requestedToPurchase = safeMul_dec(msg.value, usdToEthPrice);

        // Store the ETH in our funds wallet
        fundsWallet.transfer(msg.value);

        // Send the nomins.
        // Note: Fees are calculated by the Nomin contract, so when 
        //       we request a specific transfer here, the fee is
        //       automatically deducted and sent to the fee pool.
        nomin.transfer(msg.sender, requestedToPurchase);

        emit Exchange("ETH", msg.value, "nUSD", requestedToPurchase);

        return requestedToPurchase;
    }

    /**
     * @notice Exchange ETH to nUSD while insisting on a particular rate. This allows a user to
     *         exchange while protecting against frontrunning by the contract owner on the exchange rate.
     * @param guaranteedRate The exchange rate (ether price) which must be honored or the call will revert.
     */
    function exchangeEtherForNominsAtRate(uint guaranteedRate)
        public
        payable
        pricesNotStale
        notPaused
        returns (uint) // Returns the number of Nomins (nUSD) received
    {
        require(guaranteedRate == usdToEthPrice);

        return exchangeEtherForNomins();
    }


    /**
     * @notice Exchange ETH to HAV.
     */
    function exchangeEtherForHavvens()
        public 
        payable
        pricesNotStale
        notPaused
        returns (uint) // Returns the number of Havvens (HAV) received
    {
        // How many Havvens are they going to be receiving?
        uint havvensToSend = havvensReceivedForEther(msg.value);

        // Store the ETH in our funds wallet
        fundsWallet.transfer(msg.value);

        // And send them the Havvens.
        havven.transfer(msg.sender, havvensToSend);

        emit Exchange("ETH", msg.value, "HAV", havvensToSend);

        return havvensToSend;
    }

    /**
     * @notice Exchange ETH to HAV while insisting on a particular set of rates. This allows a user to
     *         exchange while protecting against frontrunning by the contract owner on the exchange rates.
     * @param guaranteedEtherRate The ether exchange rate which must be honored or the call will revert.
     * @param guaranteedHavvenRate The havven exchange rate which must be honored or the call will revert.
     */
    function exchangeEtherForHavvensAtRate(uint guaranteedEtherRate, uint guaranteedHavvenRate)
        public
        payable
        pricesNotStale
        notPaused
        returns (uint) // Returns the number of Havvens (HAV) received
    {
        require(guaranteedEtherRate == usdToEthPrice);
        require(guaranteedHavvenRate == usdToHavPrice);

        return exchangeEtherForHavvens();
    }


    /**
     * @notice Exchange nUSD for Havvens
     * @param nominAmount The amount of nomins the user wishes to exchange.
     */
    function exchangeNominsForHavvens(uint nominAmount)
        public 
        pricesNotStale
        notPaused
        returns (uint) // Returns the number of Havvens (HAV) received
    {
        // How many Havvens are they going to be receiving?
        uint havvensToSend = havvensReceivedForNomins(nominAmount);
        
        // Ok, transfer the Nomins to our address.
        nomin.transferFrom(msg.sender, this, nominAmount);

        // And send them the Havvens.
        havven.transfer(msg.sender, havvensToSend);

        emit Exchange("nUSD", nominAmount, "HAV", havvensToSend);

        return havvensToSend; 
    }

    /**
     * @notice Exchange nUSD for Havvens while insisting on a particular rate. This allows a user to
     *         exchange while protecting against frontrunning by the contract owner on the exchange rate.
     * @param nominAmount The amount of nomins the user wishes to exchange.
     * @param guaranteedRate A rate (havven price) the caller wishes to insist upon.
     */
    function exchangeNominsForHavvensAtRate(uint nominAmount, uint guaranteedRate)
        public 
        pricesNotStale
        notPaused
        returns (uint) // Returns the number of Havvens (HAV) received
    {
        require(guaranteedRate == usdToHavPrice);

        return exchangeNominsForHavvens(nominAmount);
    }
    
    /**
     * @notice Allows the owner to withdraw havvens from this contract if needed.
     * @param amount The amount of havvens to attempt to withdraw (in 18 decimal places).
     */
    function withdrawHavvens(uint amount)
        external
        onlyOwner
    {
        havven.transfer(owner, amount);
        
        // We don't emit our own events here because we assume that anyone
        // who wants to watch what the Issuance Controller is doing can
        // just watch ERC20 events from the Nomin and/or Havven contracts
        // filtered to our address.
    }

    /**
     * @notice Withdraw nomins: Allows the owner to withdraw nomins from this contract if needed.
     * @param amount The amount of nomins to attempt to withdraw (in 18 decimal places).
     */
    function withdrawNomins(uint amount)
        external
        onlyOwner
    {
        nomin.transfer(owner, amount);
        
        // We don't emit our own events here because we assume that anyone
        // who wants to watch what the Issuance Controller is doing can
        // just watch ERC20 events from the Nomin and/or Havven contracts
        // filtered to our address.
    }

    /* ========== VIEWS ========== */
    /**
     * @notice Check if the prices haven't been updated for longer than the stale period.
     */
    function pricesAreStale()
        public
        view
        returns (bool)
    {
        return safeAdd(lastPriceUpdateTime, priceStalePeriod) < now;
    }

    /**
     * @notice Calculate how many havvens you will receive if you transfer
     *         an amount of nomins.
     * @param amount The amount of nomins (in 18 decimal places) you want to ask about
     */
    function havvensReceivedForNomins(uint amount)
        public 
        view
        returns (uint)
    {
        // How many nomins would we receive after the transfer fee?
        uint nominsReceived = nomin.amountReceived(amount);

        // And what would that be worth in havvens based on the current price?
        return safeDiv_dec(nominsReceived, usdToHavPrice);
    }

    /**
     * @notice Calculate how many havvens you will receive if you transfer
     *         an amount of ether.
     * @param amount The amount of ether (in wei) you want to ask about
     */
    function havvensReceivedForEther(uint amount)
        public 
        view
        returns (uint)
    {
        // How much is the ETH they sent us worth in nUSD (ignoring the transfer fee)?
        uint valueSentInNomins = safeMul_dec(amount, usdToEthPrice); 

        // Now, how many HAV will that USD amount buy?
        return havvensReceivedForNomins(valueSentInNomins);
    }

    /**
     * @notice Calculate how many nomins you will receive if you transfer
     *         an amount of ether.
     * @param amount The amount of ether (in wei) you want to ask about
     */
    function nominsReceivedForEther(uint amount)
        public 
        view
        returns (uint)
    {
        // How many nomins would that amount of ether be worth?
        uint nominsTransferred = safeMul_dec(amount, usdToEthPrice);

        // And how many of those would you receive after a transfer (deducting the transfer fee)
        return nomin.amountReceived(nominsTransferred);
    }
    
    /* ========== MODIFIERS ========== */

    modifier onlyOracle
    {
        require(msg.sender == oracle, "Must be oracle to perform this action");
        _;
    }

    modifier pricesNotStale
    {
        require(!pricesAreStale(), "Prices must not be stale to perform this action");
        _;
    }

    /* ========== EVENTS ========== */

    event FundsWalletUpdated(address newFundsWallet);
    event OracleUpdated(address newOracle);
    event NominUpdated(Nomin newNominContract);
    event HavvenUpdated(Havven newHavvenContract);
    event PriceStalePeriodUpdated(uint priceStalePeriod);
    event PricesUpdated(uint newEthPrice, uint newHavvenPrice, uint timeSent);
    event Exchange(string fromCurrency, uint fromAmount, string toCurrency, uint toAmount);
}

    Contract ABI  
[{"constant":false,"inputs":[{"name":"_owner","type":"address"}],"name":"nominateNewOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_paused","type":"bool"}],"name":"setPaused","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"initiationTime","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"amount","type":"uint256"}],"name":"withdrawHavvens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"amount","type":"uint256"}],"name":"havvensReceivedForEther","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_beneficiary","type":"address"}],"name":"setSelfDestructBeneficiary","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"fundsWallet","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"priceStalePeriod","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_time","type":"uint256"}],"name":"setPriceStalePeriod","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"nominAmount","type":"uint256"},{"name":"guaranteedRate","type":"uint256"}],"name":"exchangeNominsForHavvensAtRate","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"terminateSelfDestruct","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"pricesAreStale","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newEthPrice","type":"uint256"},{"name":"newHavvenPrice","type":"uint256"},{"name":"timeSent","type":"uint256"}],"name":"updatePrices","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"exchangeEtherForHavvens","outputs":[{"name":"","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[],"name":"exchangeEtherForNomins","outputs":[{"name":"","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"nominAmount","type":"uint256"}],"name":"exchangeNominsForHavvens","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"lastPriceUpdateTime","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_havven","type":"address"}],"name":"setHavven","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"nominatedOwner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"amount","type":"uint256"}],"name":"havvensReceivedForNomins","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_nomin","type":"address"}],"name":"setNomin","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"paused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"guaranteedRate","type":"uint256"}],"name":"exchangeEtherForNominsAtRate","outputs":[{"name":"","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"_fundsWallet","type":"address"}],"name":"setFundsWallet","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"acceptOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_oracle","type":"address"}],"name":"setOracle","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"oracle","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"lastPauseTime","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"havven","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"selfDestruct","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"UNIT","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SELFDESTRUCT_DELAY","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"amount","type":"uint256"}],"name":"nominsReceivedForEther","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"selfDestructInitiated","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"usdToEthPrice","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"guaranteedEtherRate","type":"uint256"},{"name":"guaranteedHavvenRate","type":"uint256"}],"name":"exchangeEtherForHavvensAtRate","outputs":[{"name":"","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[],"name":"initiateSelfDestruct","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"usdToHavPrice","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"selfDestructBeneficiary","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"nomin","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"amount","type":"uint256"}],"name":"withdrawNomins","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_owner","type":"address"},{"name":"_fundsWallet","type":"address"},{"name":"_havven","type":"address"},{"name":"_nomin","type":"address"},{"name":"_oracle","type":"address"},{"name":"_usdToEthPrice","type":"uint256"},{"name":"_usdToHavPrice","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":false,"name":"newFundsWallet","type":"address"}],"name":"FundsWalletUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"newOracle","type":"address"}],"name":"OracleUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"newNominContract","type":"address"}],"name":"NominUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"newHavvenContract","type":"address"}],"name":"HavvenUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"priceStalePeriod","type":"uint256"}],"name":"PriceStalePeriodUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"newEthPrice","type":"uint256"},{"indexed":false,"name":"newHavvenPrice","type":"uint256"},{"indexed":false,"name":"timeSent","type":"uint256"}],"name":"PricesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"fromCurrency","type":"string"},{"indexed":false,"name":"fromAmount","type":"uint256"},{"indexed":false,"name":"toCurrency","type":"string"},{"indexed":false,"name":"toAmount","type":"uint256"}],"name":"Exchange","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"isPaused","type":"bool"}],"name":"PauseChanged","type":"event"},{"anonymous":false,"inputs":[],"name":"SelfDestructTerminated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"beneficiary","type":"address"}],"name":"SelfDestructed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"selfDestructDelay","type":"uint256"}],"name":"SelfDestructInitiated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"newBeneficiary","type":"address"}],"name":"SelfDestructBeneficiaryUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"newOwner","type":"address"}],"name":"OwnerNominated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"oldOwner","type":"address"},{"indexed":false,"name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"}]

  Contract Creation Code Switch To Opcodes View
6080604052612a3060095534801561001657600080fd5b5060405160e08061252283398101604090815281516020830151918301516060840151608085015160a086015160c0909601519395929391929091868080600160a060020a03811615156100cb57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4f776e657220616464726573732063616e6e6f74206265203000000000000000604482015290519081900360640190fd5b60008054600160a060020a031916600160a060020a038316908117825560408051928352602083019190915280517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c9281900390910190a150600160a060020a03811615156101c157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f4f776e6572206d757374206e6f7420626520746865207a65726f20616464726560448201527f7373000000000000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b60038054600160a060020a038316610100810261010060a860020a03199092169190911790915560408051918252517fd5da63a0b864b315bc04128dedbc93888c8529ee6cf47ce664dc204339228c539181900360200190a1505060078054600160a060020a03978816600160a060020a031991821617909155600580549688166101000261010060a860020a031990971696909617909555600680549487169486169490941790935560088054929095169190931617909255600c55600b555042600a5561228d806102956000396000f30060806040526004361061020e5763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416631627540c811461021957806316c38b3c1461023c57806317c70de41461025657806319dc831a1461027d5780631bca56891461029557806320714f88146102ad5780632194f3a2146102ce57806321cf3514146102ff57806329f3533c146103145780632ff9f0171461032c578063313ce567146103475780633278c960146103725780633d160de9146103875780633ed620a4146103b05780633f541ffc146103ce578063407fb687146103d6578063493b284e146103de57806349b9a7af146103f65780634fa2b0a51461040b57806353a47bb71461042c5780635ae59132146104415780635c8ea7fe146104595780635c975abb1461047a57806362b453181461048f57806364e39b871461049a57806379ba5097146104bb5780637adbf973146104d05780637dc0d1d0146104f15780638da5cb5b1461050657806391b4ded91461051b5780639c4de81f146105305780639cb8a26a146105455780639d8e21771461055a578063a461fc821461056f578063aa2efbad14610584578063b8225dec1461059c578063ba34251b146105b1578063bc64059b146105c6578063bd32aa44146105d4578063c40b8dcf146105e9578063c58aaae6146105fe578063e59160e314610613578063e9c6ed1114610628575b610216610640565b50005b34801561022557600080fd5b5061023a600160a060020a0360043516610871565b005b34801561024857600080fd5b5061023a6004351515610936565b34801561026257600080fd5b5061026b610a0c565b60408051918252519081900360200190f35b34801561028957600080fd5b5061023a600435610a12565b3480156102a157600080fd5b5061026b600435610b09565b3480156102b957600080fd5b5061023a600160a060020a0360043516610b2a565b3480156102da57600080fd5b506102e3610c7d565b60408051600160a060020a039092168252519081900360200190f35b34801561030b57600080fd5b5061026b610c8c565b34801561032057600080fd5b5061023a600435610c92565b34801561033857600080fd5b5061026b600435602435610d31565b34801561035357600080fd5b5061035c610e06565b6040805160ff9092168252519081900360200190f35b34801561037e57600080fd5b5061023a610e0b565b34801561039357600080fd5b5061039c610ea9565b604080519115158252519081900360200190f35b3480156103bc57600080fd5b5061023a600435602435604435610ec0565b61026b611052565b61026b610640565b3480156103ea57600080fd5b5061026b600435611283565b34801561040257600080fd5b5061026b61151e565b34801561041757600080fd5b5061023a600160a060020a0360043516611524565b34801561043857600080fd5b506102e36115f1565b34801561044d57600080fd5b5061026b600435611600565b34801561046557600080fd5b5061023a600160a060020a03600435166116a8565b34801561048657600080fd5b5061039c61176d565b61026b600435611776565b3480156104a657600080fd5b5061023a600160a060020a0360043516611850565b3480156104c757600080fd5b5061023a61191b565b3480156104dc57600080fd5b5061023a600160a060020a0360043516611a23565b3480156104fd57600080fd5b506102e3611aee565b34801561051257600080fd5b506102e3611afd565b34801561052757600080fd5b5061026b611b0c565b34801561053c57600080fd5b506102e3611b12565b34801561055157600080fd5b5061023a611b26565b34801561056657600080fd5b5061026b611ceb565b34801561057b57600080fd5b5061026b611cf7565b34801561059057600080fd5b5061026b600435611cfe565b3480156105a857600080fd5b5061039c611daa565b3480156105bd57600080fd5b5061026b611db3565b61026b600435602435611db9565b3480156105e057600080fd5b5061023a611e9b565b3480156105f557600080fd5b5061026b611f48565b34801561060a57600080fd5b506102e3611f4e565b34801561061f57600080fd5b506102e3611f62565b34801561063457600080fd5b5061023a600435611f71565b60008061064b610ea9565b156106a2576040805160e560020a62461bcd02815260206004820152602f60248201526000805160206122428339815191526044820152600080516020612202833981519152606482015290519081900360840190fd5b60055460ff16156106ff576040805160e560020a62461bcd02815260206004820152603c602482015260008051602061222283398151915260448201526000805160206121c2833981519152606482015290519081900360840190fd5b61070b34600c54612035565b600754604051919250600160a060020a0316903480156108fc02916000818181858888f19350505050158015610745573d6000803e3d6000fd5b506006546040805160e060020a63a9059cbb028152336004820152602481018490529051600160a060020a039092169163a9059cbb916044808201926020929091908290030181600087803b15801561079d57600080fd5b505af11580156107b1573d6000803e3d6000fd5b505050506040513d60208110156107c757600080fd5b5050604080513460208201526060810183905260808082526003908201527f455448000000000000000000000000000000000000000000000000000000000060a082015260c08183018190526004908201527f6e5553440000000000000000000000000000000000000000000000000000000060e082015290517fdb1741ffc6844b04a9284bb6337fb0ccfe543a493ef0ac8e725242201e93d4bd918190036101000190a1919050565b600054600160a060020a031633146108d5576040805160e560020a62461bcd02815260206004820152602f60248201526000805160206121e28339815191526044820152600080516020612202833981519152606482015290519081900360840190fd5b60018054600160a060020a03831673ffffffffffffffffffffffffffffffffffffffff19909116811790915560408051918252517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce229181900360200190a150565b600054600160a060020a0316331461099a576040805160e560020a62461bcd02815260206004820152602f60248201526000805160206121e28339815191526044820152600080516020612202833981519152606482015290519081900360840190fd5b60055460ff16151581151514156109b057610a09565b6005805460ff1916821515179081905560ff16156109cd57426004555b6005546040805160ff90921615158252517f8fb6c181ee25a520cf3dd6565006ef91229fcfe5a989566c2a3b8c115570cec59181900360200190a15b50565b60025481565b600054600160a060020a03163314610a76576040805160e560020a62461bcd02815260206004820152602f60248201526000805160206121e28339815191526044820152600080516020612202833981519152606482015290519081900360840190fd5b600554600080546040805160e060020a63a9059cbb028152600160a060020a0392831660048201526024810186905290516101009094049091169263a9059cbb92604480840193602093929083900390910190829087803b158015610ada57600080fd5b505af1158015610aee573d6000803e3d6000fd5b505050506040513d6020811015610b0457600080fd5b505050565b600080610b1883600c54612035565b9050610b2381611600565b9392505050565b600054600160a060020a03163314610b8e576040805160e560020a62461bcd02815260206004820152602f60248201526000805160206121e28339815191526044820152600080516020612202833981519152606482015290519081900360840190fd5b600160a060020a0381161515610c14576040805160e560020a62461bcd02815260206004820152602860248201527f42656e6566696369617279206d757374206e6f7420626520746865207a65726f60448201527f2061646472657373000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b60038054600160a060020a038316610100810274ffffffffffffffffffffffffffffffffffffffff00199092169190911790915560408051918252517fd5da63a0b864b315bc04128dedbc93888c8529ee6cf47ce664dc204339228c539181900360200190a150565b600754600160a060020a031681565b60095481565b600054600160a060020a03163314610cf6576040805160e560020a62461bcd02815260206004820152602f60248201526000805160206121e28339815191526044820152600080516020612202833981519152606482015290519081900360840190fd5b60098190556040805182815290517f456c8075c5b512d696c9a215b96d7146add8797e2050899ad8a97fd4a648ac939181900360200190a150565b6000610d3b610ea9565b15610d92576040805160e560020a62461bcd02815260206004820152602f60248201526000805160206122428339815191526044820152600080516020612202833981519152606482015290519081900360840190fd5b60055460ff1615610def576040805160e560020a62461bcd02815260206004820152603c602482015260008051602061222283398151915260448201526000805160206121c2833981519152606482015290519081900360840190fd5b600b548214610dfd57600080fd5b610b2383611283565b601281565b600054600160a060020a03163314610e6f576040805160e560020a62461bcd02815260206004820152602f60248201526000805160206121e28339815191526044820152600080516020612202833981519152606482015290519081900360840190fd5b600060028190556003805460ff191690556040517f6adcc7125002935e0aa31697538ebbd65cfddf20431eb6ecdcfc3e238bfd082c9190a1565b600042610eba600a5460095461205b565b10905090565b600854600160a060020a03163314610f48576040805160e560020a62461bcd02815260206004820152602560248201527f4d757374206265206f7261636c6520746f20706572666f726d2074686973206160448201527f6374696f6e000000000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b80600a54108015610f5c5750610258420181105b1515610ffe576040805160e560020a62461bcd02815260206004820152605e60248201527f54696d652073656e74206d75737420626520626967676572207468616e20746860448201527f65206c617374207570646174652c20616e64206d757374206265206c6573732060648201527f7468616e206e6f77202b204f5241434c455f4655545552455f4c494d49540000608482015290519081900360a40190fd5b600c839055600b829055600a819055604080518481526020810184905280820183905290517fa6b830b74e52d7d1140e76252f225dc7bed28782519845600bbd3182341dc1159181900360600190a1505050565b60008061105d610ea9565b156110b4576040805160e560020a62461bcd02815260206004820152602f60248201526000805160206122428339815191526044820152600080516020612202833981519152606482015290519081900360840190fd5b60055460ff1615611111576040805160e560020a62461bcd02815260206004820152603c602482015260008051602061222283398151915260448201526000805160206121c2833981519152606482015290519081900360840190fd5b61111a34610b09565b600754604051919250600160a060020a0316903480156108fc02916000818181858888f19350505050158015611154573d6000803e3d6000fd5b506005546040805160e060020a63a9059cbb028152336004820152602481018490529051610100909204600160a060020a03169163a9059cbb916044808201926020929091908290030181600087803b1580156111b057600080fd5b505af11580156111c4573d6000803e3d6000fd5b505050506040513d60208110156111da57600080fd5b50506040805134602082015260608101839052608080825260039082018190527f455448000000000000000000000000000000000000000000000000000000000060a083015260c08284018190528201527f484156000000000000000000000000000000000000000000000000000000000060e082015290517fdb1741ffc6844b04a9284bb6337fb0ccfe543a493ef0ac8e725242201e93d4bd918190036101000190a1919050565b60008061128e610ea9565b156112e5576040805160e560020a62461bcd02815260206004820152602f60248201526000805160206122428339815191526044820152600080516020612202833981519152606482015290519081900360840190fd5b60055460ff1615611342576040805160e560020a62461bcd02815260206004820152603c602482015260008051602061222283398151915260448201526000805160206121c2833981519152606482015290519081900360840190fd5b61134b83611600565b600654604080517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018790529051929350600160a060020a03909116916323b872dd916064808201926020929091908290030181600087803b1580156113c157600080fd5b505af11580156113d5573d6000803e3d6000fd5b505050506040513d60208110156113eb57600080fd5b50506005546040805160e060020a63a9059cbb028152336004820152602481018490529051610100909204600160a060020a03169163a9059cbb916044808201926020929091908290030181600087803b15801561144857600080fd5b505af115801561145c573d6000803e3d6000fd5b505050506040513d602081101561147257600080fd5b505060408051602081018590526060810183905260808082526004908201527f6e5553440000000000000000000000000000000000000000000000000000000060a082015260c08183018190526003908201527f484156000000000000000000000000000000000000000000000000000000000060e082015290517fdb1741ffc6844b04a9284bb6337fb0ccfe543a493ef0ac8e725242201e93d4bd918190036101000190a192915050565b600a5481565b600054600160a060020a03163314611588576040805160e560020a62461bcd02815260206004820152602f60248201526000805160206121e28339815191526044820152600080516020612202833981519152606482015290519081900360840190fd5b60058054600160a060020a038316610100810274ffffffffffffffffffffffffffffffffffffffff00199092169190911790915560408051918252517f7d83fa33771af200b7fda80813418ffe7eafdbeb2a93f5267ced74abac654a4e9181900360200190a150565b600154600160a060020a031681565b600654604080517f1a463a7d0000000000000000000000000000000000000000000000000000000081526004810184905290516000928392600160a060020a0390911691631a463a7d9160248082019260209290919082900301818787803b15801561166b57600080fd5b505af115801561167f573d6000803e3d6000fd5b505050506040513d602081101561169557600080fd5b5051600b54909150610b239082906120bc565b600054600160a060020a0316331461170c576040805160e560020a62461bcd02815260206004820152602f60248201526000805160206121e28339815191526044820152600080516020612202833981519152606482015290519081900360840190fd5b60068054600160a060020a03831673ffffffffffffffffffffffffffffffffffffffff19909116811790915560408051918252517f114aa3d8eaf9520841f1c7932e26ac23f2644b0d860be54533e21450cc28c02c9181900360200190a150565b60055460ff1681565b6000611780610ea9565b156117d7576040805160e560020a62461bcd02815260206004820152602f60248201526000805160206122428339815191526044820152600080516020612202833981519152606482015290519081900360840190fd5b60055460ff1615611834576040805160e560020a62461bcd02815260206004820152603c602482015260008051602061222283398151915260448201526000805160206121c2833981519152606482015290519081900360840190fd5b600c54821461184257600080fd5b61184a610640565b92915050565b600054600160a060020a031633146118b4576040805160e560020a62461bcd02815260206004820152602f60248201526000805160206121e28339815191526044820152600080516020612202833981519152606482015290519081900360840190fd5b6007805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a03838116919091179182905560408051929091168252517f4deb077bf9c4bc824cc2c989e01a5e53b0a4ecc44c5039d46abc9ffc88f8a050916020908290030190a150565b600154600160a060020a031633146119a3576040805160e560020a62461bcd02815260206004820152603560248201527f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7560448201527f2063616e20616363657074206f776e6572736869700000000000000000000000606482015290519081900360840190fd5b60005460015460408051600160a060020a03938416815292909116602083015280517fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c9281900390910190a1600180546000805473ffffffffffffffffffffffffffffffffffffffff19908116600160a060020a03841617909155169055565b600054600160a060020a03163314611a87576040805160e560020a62461bcd02815260206004820152602f60248201526000805160206121e28339815191526044820152600080516020612202833981519152606482015290519081900360840190fd5b6008805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a03838116919091179182905560408051929091168252517f3df77beb5db05fcdd70a30fc8adf3f83f9501b68579455adbd100b8180940394916020908290030190a150565b600854600160a060020a031681565b600054600160a060020a031681565b60045481565b6005546101009004600160a060020a031681565b60008054600160a060020a03163314611b8b576040805160e560020a62461bcd02815260206004820152602f60248201526000805160206121e28339815191526044820152600080516020612202833981519152606482015290519081900360840190fd5b60035460ff161515611c0d576040805160e560020a62461bcd02815260206004820152602860248201527f53656c6620646573747275637420686173206e6f7420796574206265656e206960448201527f6e69746961746564000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b426224ea0060025401101515611c93576040805160e560020a62461bcd02815260206004820152602760248201527f53656c662064657374727563742064656c617920686173206e6f74207965742060448201527f656c617073656400000000000000000000000000000000000000000000000000606482015290519081900360840190fd5b5060035460408051600160a060020a0361010090930492909216808352905190917f8a09e1677ced846cb537dc2b172043bd05a1a81ad7e0033a7ef8ba762df990b7919081900360200190a180600160a060020a0316ff5b670de0b6b3a764000081565b6224ea0081565b600080611d0d83600c54612035565b600654604080517f1a463a7d000000000000000000000000000000000000000000000000000000008152600481018490529051929350600160a060020a0390911691631a463a7d916024808201926020929091908290030181600087803b158015611d7757600080fd5b505af1158015611d8b573d6000803e3d6000fd5b505050506040513d6020811015611da157600080fd5b50519392505050565b60035460ff1681565b600c5481565b6000611dc3610ea9565b15611e1a576040805160e560020a62461bcd02815260206004820152602f60248201526000805160206122428339815191526044820152600080516020612202833981519152606482015290519081900360840190fd5b60055460ff1615611e77576040805160e560020a62461bcd02815260206004820152603c602482015260008051602061222283398151915260448201526000805160206121c2833981519152606482015290519081900360840190fd5b600c548314611e8557600080fd5b600b548214611e9357600080fd5b610b23611052565b600054600160a060020a03163314611eff576040805160e560020a62461bcd02815260206004820152602f60248201526000805160206121e28339815191526044820152600080516020612202833981519152606482015290519081900360840190fd5b426002556003805460ff19166001179055604080516224ea00815290517fcbd94ca75b8dc45c9d80c77e851670e78843c0d75180cb81db3e2158228fa9a69181900360200190a1565b600b5481565b6003546101009004600160a060020a031681565b600654600160a060020a031681565b600054600160a060020a03163314611fd5576040805160e560020a62461bcd02815260206004820152602f60248201526000805160206121e28339815191526044820152600080516020612202833981519152606482015290519081900360840190fd5b600654600080546040805160e060020a63a9059cbb028152600160a060020a039283166004820152602481018690529051919093169263a9059cbb9260448083019360209390929083900390910190829087803b158015610ada57600080fd5b6000670de0b6b3a764000061204a84846120d9565b81151561205357fe5b049392505050565b60008282018211156120b7576040805160e560020a62461bcd02815260206004820152600f60248201527f5361666520616464206661696c65640000000000000000000000000000000000604482015290519081900360640190fd5b500190565b6000610b236120d384670de0b6b3a76400006120d9565b8361215d565b6000808315156120ec5760009150612156565b508282028284828115156120fc57fe5b0414612152576040805160e560020a62461bcd02815260206004820152600f60248201527f53616665206d756c206661696c65640000000000000000000000000000000000604482015290519081900360640190fd5b8091505b5092915050565b60008115156121b6576040805160e560020a62461bcd02815260206004820152601a60248201527f44656e6f6d696e61746f722063616e6e6f74206265207a65726f000000000000604482015290519081900360640190fd5b818381151561205357fe007768696c652074686520636f6e747261637420697320706175736564000000004f6e6c792074686520636f6e7472616374206f776e6572206d617920706572666f726d207468697320616374696f6e00000000000000000000000000000000005468697320616374696f6e2063616e6e6f7420626520706572666f726d656420507269636573206d757374206e6f74206265207374616c6520746f2070657266a165627a7a72305820a4e86388d15ff16b6d552a05035ccc99d730bb042a1eafe4dca23a50b010c8950029000000000000000000000000b0a23f40de7f776a4f20153e8995ed3e7d7c8487000000000000000000000000a15184a8c8c3f47a8b54572cdccb30358abfb7a1000000000000000000000000d989a04ad891528b571ef73dacaefeb0402a65b300000000000000000000000092812526ebc2f4df9e0b77db74da0803b8f023fa000000000000000000000000ac1ed4fabbd5204e02950d68b6fc8c446ac9536200000000000000000000000000000000000000000000000f6d340be38a6c1ae00000000000000000000000000000000000000000000000000161d3ac8dd65b2a

    Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000b0a23f40de7f776a4f20153e8995ed3e7d7c8487000000000000000000000000a15184a8c8c3f47a8b54572cdccb30358abfb7a1000000000000000000000000d989a04ad891528b571ef73dacaefeb0402a65b300000000000000000000000092812526ebc2f4df9e0b77db74da0803b8f023fa000000000000000000000000ac1ed4fabbd5204e02950d68b6fc8c446ac9536200000000000000000000000000000000000000000000000f6d340be38a6c1ae00000000000000000000000000000000000000000000000000161d3ac8dd65b2a

-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 000000000000000000000000b0a23f40de7f776a4f20153e8995ed3e7d7c8487
Arg [1] : 000000000000000000000000a15184a8c8c3f47a8b54572cdccb30358abfb7a1
Arg [2] : 000000000000000000000000d989a04ad891528b571ef73dacaefeb0402a65b3
Arg [3] : 00000000000000000000000092812526ebc2f4df9e0b77db74da0803b8f023fa
Arg [4] : 000000000000000000000000ac1ed4fabbd5204e02950d68b6fc8c446ac95362
Arg [5] : 00000000000000000000000000000000000000000000000f6d340be38a6c1ae0
Arg [6] : 0000000000000000000000000000000000000000000000000161d3ac8dd65b2a


   Swarm Source:
bzzr://a4e86388d15ff16b6d552a05035ccc99d730bb042a1eafe4dca23a50b010c895

 

View All
Block Age transaction Difficulty GasUsed Reward
View All
Block Age UncleNumber Difficulty GasUsed Reward
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.