ETH Price: $1,964.81 (-0.80%)

Transaction Decoder

Block:
9687286 at Mar-17-2020 05:58:39 AM +UTC
Transaction Fee:
0.02169512 ETH $42.63
Gas Used:
1,084,756 Gas / 20 Gwei

Account State Difference:

  Address   Before After State Difference Code
0x070cB127...4Ed4F430B
(OMG Network V1: ERC-20 Vault)
0 Eth
Nonce: 0
0 Eth
Nonce: 1
From: 0 To: 18144640459820085742193078045889949321623925746784621769906100382000368947947141266072998600705582200317821932274333207908757642257614868893879075485135979855532628015282677853230954196743763504121261761042509931886361586552682368390334194450302514755444433581673321376008694358442103132915413821467260717488661384818359526368498948573426774547181829923814529097935026288663964196906954751905736376026223778342838632384128368822512214005628979425474115407571096423877443781631205217468362404588719377699639744332072800487168571225168440967551222319493923102961112901537249340569825060284357975123087433878887417767851114025069138701714913167945408583373782994420759299431505280268635989543504316268897823853732853744476343733720784864556347366299570343986819172425607909792753185969854454169559847873928996190472435808535182266452510838391905533567316689447793975625496495934082486282243597357931105466412269312399764515471262389060975689027209181281493136995958037148094047115452692671945302563482091784231620620481553742548733053338407060789412716889772226294252643419626658223412273241573381275923808131087451439975418637730209015381960750283637519357969511006787825653332586874777032413303605788582841153734911355956331537037658978789151871422847178615115421766769698811544147511087227649813049230846975226646372189625614828052319229216018303609319830481660338879493902300452468221652646040637207651962395593234599251910923018898104404552704357087805412696384780014626064020215084398886502638303451519832246986814895884180836131923807575867947857244447376700523176392893257584419017139438772165683518159419876892676213844900500680430650209593403791222019848271969452577581880201477925391616332166869104767652963626656420847101647189034305011962337780587348449382664934128045921491187214499147943112192568342044500490282389244495814264559166389629309347875112008508357094036715719992324652349774944006584117912388608741600268955111437453191857842520341309009642669139805036397606041244888978301457052518698692917509925717591156201022025547687687908292775594212239789014939028909853976468582103971384561811128479571345852263610227881187122198092743651960374021964552908591740644834525975058567398212775574338195340857059603085544328998194085236250490916650021423418108299766553344544564941454862548735917427559372650988030956391888560867152469965063236032010078995580148346613304773979581402606522138627101619705190896159707012683840020641186037986942865337051962923726730181912036789428316249444261810056757087742913458760484918588651259982969200376716110002033217848833824375443790084395818581273499513856581943643865130934832813058456799395959137122547402911475146152547200342644339399778700084510915944397706914261149308262871888975690607756403964467068400984907212974703426006348301373114342345886960460898125004964651155547576281325067378897641303989822889024456278960852243423065206726343734300435605303109281320054834503989132287417275306668098842358059563542026112538754811061898717475685152133578043593238082039669177455360336972959541139641089252442746992849034533305812301261936698748838943777665278155104739332507922864314041157729488661928730256618113759213954440552654549064002628989791934554596076122509647096230407693511422219350711267512903147057941947717225174816345003193503833242161602637130515290286000901620047876622433890984361028766378016300715396478991251773690865997667463794787501981918496030961257324839870345518519305206084064234893335138832433761603698498317352556206844692537409775912291316884509368651111351062737951225302732378558138190846497025454547154244174580738468769183276384068903690275358559816280111113169272977118604998253589381268447540985251201755506853074399726063704766542606112518321522956173425125660800739877126759632418320157378964867142054005240519397294503685788491040377959079590526850166557819451895495285042920487039737654700332408707736547566669932385883204815587684039278598997046121195498540510412779759943066717282967923187420949099885476545729282608205807428419293340102739918650309686053905647995518925201952150105501410652556321301122273052865922008628621275316967223760321811368242210105455373695353951017708508573626367142620058560420739364249918033917682299624581985895667693827312141589871807058955727145430099008288297728998942283300799172202882515229270892867060665928714255839862027352288011970540659134650606925658052819844032311463070294848361582607682932646725211250311003853518306895998437415219029823642022620272458061609639402038642292934242423532247962185031583880243887392910351954499796850195041399250444189050477524754164692955800991350330894870909752326748658345082131151138486173490882118099782346962503117517753488753396455772914769892088307326733335990277950124848830120600832593787160525775400006380487624437278508286784055267043284336469973835294292448829665721819224399573376513538394665504971578600301459781498959708297944555679239520175266902482481420697886401913738936420615460494187857953586986991749798779860129521314921753427466118010704195279536615061738744476158255191938103046188628392033770834714347930631511597224005623677850074166401372665633682563073302850127093758829495607316668577183686038675381445488058796058603161455897155326095662555369652780667287163955780301630014361068153504187989290308091831423658779570480211256039236114702914759253107280202863058854631174993845888293595481822695564121034605374914469142294309336029759313781430420805857180108417232772568990070446240391304684737615909075598543316457415300320816493538403569235761792048235338238459583739103220618797947980379428443551007209273587218047369464488087869132811128115575402559530874412892872145143018042129583387094002542641071440419566525548589043541904029411881122567529772122446197429421462586216732585464150042139363314530419676642468977448711747796985093047355252756092309719804796274911631407122262875659339379995353963115238530425627351092345159973023415251184501299198213356028353388438291505033298057264723092520813686373655713762131608204326771921256715016832773021187666681965045987554801160792815702476084438988133500322929388295268961070790526751667743972463516904810607614771631135060956300757779225808791879407405812431190540265765667631164101588874896036652330697232966107269083833878102330438764483484948246735839457419067429680274301207213745319926752494970732279626366323199663354583030540138698613164565235431327546601486052232697301413556071285216362854906765640262346930749772337452103396101274035161657300954131238236460100601653454468522602529718654087630603760745458928784841763959924353500640071825402070003364779282984938347838335879660328389775220345345110790631423011257359106600341561959528657682799899717202698023769639801263444799129263674922048105847773229873936633601176994693995123126064210475295783201300214798325663469495927686521366708622126010711239282819320747438853516477529056234267048844178228288550503890726093280533969657012479267285597155555632975848544766404547901765597307325375342643747057676767463954093624685473177922668427462246693108628360687340821030385104588056170167314028118826218414390491218417737298220511678811259161679732587211461996753972130225640316957659066773297113529639243323621754702440288880221316885904983534054711885327313554915855934188410727867688200191299384246274851523361701938
0x27b4C9e6...1615D3B21
(OMG Network: Deployer 3)
0.2766831 Eth
Nonce: 4
0.25498798 Eth
Nonce: 5
0.02169512
(F2Pool Old)
5,542.307628691612252676 Eth5,542.329323811612252676 Eth0.02169512

Execution Trace

Erc20Vault.60806040( )
pragma solidity 0.5.11;
import "./Vault.sol";
import "./verifiers/IErc20DepositVerifier.sol";
import "../framework/PlasmaFramework.sol";
import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol";
import "openzeppelin-solidity/contracts/token/ERC20/SafeERC20.sol";
contract Erc20Vault is Vault {
    using SafeERC20 for IERC20;
    event Erc20Withdrawn(
        address indexed receiver,
        address indexed token,
        uint256 amount
    );
    event DepositCreated(
        address indexed depositor,
        uint256 indexed blknum,
        address indexed token,
        uint256 amount
    );
    constructor(PlasmaFramework _framework) public Vault(_framework) {}
    /**
     * @notice Deposits approved amount of ERC20 token(s) into the contract
     * Once the deposit is recognized, the owner (depositor) can transact on the OmiseGO Network
     * The approve function of the ERC20 token contract must be called before calling this function
     * for at least the amount that is deposited into the contract
     * @param depositTx RLP-encoded transaction to act as the deposit
     */
    function deposit(bytes calldata depositTx) external {
        address depositVerifier = super.getEffectiveDepositVerifier();
        require(depositVerifier != address(0), "Deposit verifier has not been set");
        (address depositor, address token, uint256 amount) = IErc20DepositVerifier(depositVerifier)
            .verify(depositTx, msg.sender, address(this));
        IERC20(token).safeTransferFrom(depositor, address(this), amount);
        uint256 blknum = super.submitDepositBlock(depositTx);
        emit DepositCreated(msg.sender, blknum, token, amount);
    }
    /**
    * @notice Withdraw ERC20 tokens that have successfully exited from the OmiseGO Network
    * @param receiver Address of the recipient
    * @param token Address of ERC20 token contract
    * @param amount Amount to transfer
    */
    function withdraw(address payable receiver, address token, uint256 amount) external onlyFromNonQuarantinedExitGame {
        IERC20(token).safeTransfer(receiver, amount);
        emit Erc20Withdrawn(receiver, token, amount);
    }
}
pragma solidity 0.5.11;
import "./models/BlockModel.sol";
import "./registries/VaultRegistry.sol";
import "../utils/OnlyFromAddress.sol";
/**
* @notice Controls the logic and functions for block submissions in PlasmaFramework
* @dev There are two types of blocks: child block and deposit block
*      Each child block has an interval of 'childBlockInterval'
*      The interval is preserved for deposits. Each deposit results in one deposit block.
*      For instance, a child block would be in block 1000 and the next deposit would result in block 1001.
*
*      Only the authority address can perform a block submission.
*      Details on limitations for the authority address can be found here: https://github.com/omisego/elixir-omg#managing-the-operator-address
*/
contract BlockController is OnlyFromAddress, VaultRegistry {
    address public authority;
    uint256 public childBlockInterval;
    uint256 public nextChildBlock;
    uint256 public nextDeposit;
    bool public isChildChainActivated;
    mapping (uint256 => BlockModel.Block) public blocks; // block number => Block data
    event BlockSubmitted(
        uint256 blknum
    );
    event ChildChainActivated(
        address authority
    );
    constructor(
        uint256 _interval,
        uint256 _minExitPeriod,
        uint256 _initialImmuneVaults,
        address _authority
    )
        public
        VaultRegistry(_minExitPeriod, _initialImmuneVaults)
    {
        authority = _authority;
        childBlockInterval = _interval;
        nextChildBlock = childBlockInterval;
        nextDeposit = 1;
        isChildChainActivated = false;
    }
    /**
     * @notice Activates the child chain so that child chain can start to submit child blocks to root chain
     * @notice Can only be called once by the authority.
     * @notice Sets isChildChainActivated to true and emits the ChildChainActivated event.
     * @dev This is a preserved action for authority account to start its nonce with 1.
     *      Child chain rely ethereum nonce to protect re-org: https://git.io/JecDG
     *      see discussion: https://git.io/JenaT, https://git.io/JecDO
     */
    function activateChildChain() external onlyFrom(authority) {
        require(isChildChainActivated == false, "Child chain already activated");
        isChildChainActivated = true;
        emit ChildChainActivated(authority);
    }
    /**
     * @notice Allows the authority to submit the Merkle root of a Plasma block
     * @dev emit BlockSubmitted event
     * @dev Block number jumps 'childBlockInterval' per submission
     * @dev See discussion in https://github.com/omisego/plasma-contracts/issues/233
     * @param _blockRoot Merkle root of the Plasma block
     */
    function submitBlock(bytes32 _blockRoot) external onlyFrom(authority) {
        require(isChildChainActivated == true, "Child chain has not been activated by authority address yet");
        uint256 submittedBlockNumber = nextChildBlock;
        blocks[submittedBlockNumber] = BlockModel.Block({
            root: _blockRoot,
            timestamp: block.timestamp
        });
        nextChildBlock += childBlockInterval;
        nextDeposit = 1;
        emit BlockSubmitted(submittedBlockNumber);
    }
    /**
     * @notice Submits a block for deposit
     * @dev Block number adds 1 per submission; it's possible to have at most 'childBlockInterval' deposit blocks between two child chain blocks
     * @param _blockRoot Merkle root of the Plasma block
     * @return The deposit block number
     */
    function submitDepositBlock(bytes32 _blockRoot) public onlyFromNonQuarantinedVault returns (uint256) {
        require(isChildChainActivated == true, "Child chain has not been activated by authority address yet");
        require(nextDeposit < childBlockInterval, "Exceeded limit of deposits per child block interval");
        uint256 blknum = nextDepositBlock();
        blocks[blknum] = BlockModel.Block({
            root : _blockRoot,
            timestamp : block.timestamp
        });
        nextDeposit++;
        return blknum;
    }
    function nextDepositBlock() public view returns (uint256) {
        return nextChildBlock - childBlockInterval + nextDeposit;
    }
    function isDeposit(uint256 blockNum) public view returns (bool) {
        require(blocks[blockNum].timestamp != 0, "Block does not exist");
        return blockNum % childBlockInterval != 0;
    }
}
pragma solidity 0.5.11;
pragma experimental ABIEncoderV2;
import "./interfaces/IExitProcessor.sol";
import "./registries/ExitGameRegistry.sol";
import "./utils/PriorityQueue.sol";
import "./utils/ExitPriority.sol";
import "../utils/PosLib.sol";
/**
 * @notice Controls the logic and functions for ExitGame to interact with the PlasmaFramework
 *         Plasma M(ore)VP relies on exit priority to secure the user from invalid transactions
 *         The priority queue ensures the exit is processed with the exit priority
 *         For details, see the Plasma MVP spec: https://ethresear.ch/t/minimal-viable-plasma/426
 */
contract ExitGameController is ExitGameRegistry {
    // exit hashed (priority, vault id, token) => IExitProcessor
    mapping (bytes32 => IExitProcessor) public delegations;
    // hashed (vault id, token) => PriorityQueue
    mapping (bytes32 => PriorityQueue) public exitsQueues;
    // outputId => exitId
    mapping (bytes32 => uint160) public outputsFinalizations;
    bool private mutex = false;
    event ExitQueueAdded(
        uint256 vaultId,
        address token
    );
    event ProcessedExitsNum(
        uint256 processedNum,
        uint256 vaultId,
        address token
    );
    event ExitQueued(
        uint160 indexed exitId,
        uint256 priority
    );
    constructor(uint256 _minExitPeriod, uint256 _initialImmuneExitGames)
        public
        ExitGameRegistry(_minExitPeriod, _initialImmuneExitGames)
    {
    }
    /**
     * @dev Prevents reentrant calls by using a mutex.
     */
    modifier nonReentrant() {
        require(!mutex, "Reentrant call");
        mutex = true;
        _;
        assert(mutex);
        mutex = false;
    }
    /**
     * @notice Activates non reentrancy mode
     *         Guards against reentering into publicly accessible code that modifies state related to exits
     * @dev Accessible only from non quarantined exit games, uses a mutex
     */
    function activateNonReentrant() external onlyFromNonQuarantinedExitGame() {
        require(!mutex, "Reentrant call");
        mutex = true;
    }
    /**
     * @notice Deactivates non reentrancy mode
     * @dev Accessible only from non quarantined exit games, uses a mutex
     */
    function deactivateNonReentrant() external onlyFromNonQuarantinedExitGame() {
        assert(mutex);
        mutex = false;
    }
    /**
     * @notice Checks if the queue for a specified token was created
     * @param vaultId ID of the vault that handles the token
     * @param token Address of the token
     * @return bool Defines whether the queue for a token was created
     */
    function hasExitQueue(uint256 vaultId, address token) public view returns (bool) {
        bytes32 key = exitQueueKey(vaultId, token);
        return hasExitQueue(key);
    }
    /**
     * @notice Adds queue to the Plasma framework
     * @dev The queue is created as a new contract instance
     * @param vaultId ID of the vault
     * @param token Address of the token
     */
    function addExitQueue(uint256 vaultId, address token) external {
        require(vaultId != 0, "Vault ID must not be 0");
        bytes32 key = exitQueueKey(vaultId, token);
        require(!hasExitQueue(key), "Exit queue exists");
        exitsQueues[key] = new PriorityQueue();
        emit ExitQueueAdded(vaultId, token);
    }
    /**
     * @notice Enqueue exits from exit game contracts is a function that places the exit into the
     *         priority queue to enforce the priority of exit during 'processExits'
     * @dev emits ExitQueued event, which can be used to back trace the priority inside the queue
     * @dev Caller of this function should add "pragma experimental ABIEncoderV2;" on top of file
     * @dev Priority (exitableAt, txPos, exitId) must be unique per queue. Do not enqueue when the same priority is already in the queue.
     * @param vaultId Vault ID of the vault that stores exiting funds
     * @param token Token for the exit
     * @param exitableAt The earliest time a specified exit can be processed
     * @param txPos Transaction position for the exit priority. For SE it should be the exit tx, for IFE it should be the youngest input tx position.
     * @param exitId ID used by the exit processor contract to determine how to process the exit
     * @param exitProcessor The exit processor contract, called during "processExits"
     * @return A unique priority number computed for the exit
     */
    function enqueue(
        uint256 vaultId,
        address token,
        uint64 exitableAt,
        PosLib.Position calldata txPos,
        uint160 exitId,
        IExitProcessor exitProcessor
    )
        external
        onlyFromNonQuarantinedExitGame
        returns (uint256)
    {
        bytes32 key = exitQueueKey(vaultId, token);
        require(hasExitQueue(key), "The queue for the (vaultId, token) pair is not yet added to the Plasma framework");
        PriorityQueue queue = exitsQueues[key];
        uint256 priority = ExitPriority.computePriority(exitableAt, txPos, exitId);
        queue.insert(priority);
        bytes32 delegationKey = getDelegationKey(priority, vaultId, token);
        require(address(delegations[delegationKey]) == address(0), "The same priority is already enqueued");
        delegations[delegationKey] = exitProcessor;
        emit ExitQueued(exitId, priority);
        return priority;
    }
    /**
     * @notice Processes any exits that have completed the challenge period. Exits are processed according to the exit priority.
     * @dev Emits ProcessedExitsNum event
     * @param vaultId Vault ID of the vault that stores exiting funds
     * @param token The token type to process
     * @param topExitId Unique identifier for prioritizing the first exit to process. Set to zero to skip this check.
     * @param maxExitsToProcess Maximum number of exits to process
     * @return Total number of processed exits
     */
    function processExits(uint256 vaultId, address token, uint160 topExitId, uint256 maxExitsToProcess) external nonReentrant {
        bytes32 key = exitQueueKey(vaultId, token);
        require(hasExitQueue(key), "The token is not yet added to the Plasma framework");
        PriorityQueue queue = exitsQueues[key];
        require(queue.currentSize() > 0, "Exit queue is empty");
        uint256 uniquePriority = queue.getMin();
        uint160 exitId = ExitPriority.parseExitId(uniquePriority);
        require(topExitId == 0 || exitId == topExitId,
            "Top exit ID of the queue is different to the one specified");
        bytes32 delegationKey = getDelegationKey(uniquePriority, vaultId, token);
        IExitProcessor processor = delegations[delegationKey];
        uint256 processedNum = 0;
        while (processedNum < maxExitsToProcess && ExitPriority.parseExitableAt(uniquePriority) < block.timestamp) {
            delete delegations[delegationKey];
            queue.delMin();
            processedNum++;
            processor.processExit(exitId, vaultId, token);
            if (queue.currentSize() == 0) {
                break;
            }
            uniquePriority = queue.getMin();
            delegationKey = getDelegationKey(uniquePriority, vaultId, token);
            exitId = ExitPriority.parseExitId(uniquePriority);
            processor = delegations[delegationKey];
        }
        emit ProcessedExitsNum(processedNum, vaultId, token);
    }
    /**
     * @notice Checks whether any of the output with the given outputIds is already spent
     * @param _outputIds Output IDs to check
     */
    function isAnyInputFinalizedByOtherExit(bytes32[] calldata _outputIds, uint160 exitId) external view returns (bool) {
        for (uint i = 0; i < _outputIds.length; i++) {
            uint160 finalizedExitId = outputsFinalizations[_outputIds[i]];
            if (finalizedExitId != 0 && finalizedExitId != exitId) {
                return true;
            }
        }
        return false;
    }
    /**
     * @notice Batch flags already spent outputs (only not already spent)
     * @param outputIds Output IDs to flag
     */
    function batchFlagOutputsFinalized(bytes32[] calldata outputIds, uint160 exitId) external onlyFromNonQuarantinedExitGame {
        for (uint i = 0; i < outputIds.length; i++) {
            require(outputIds[i] != bytes32(""), "Should not flag with empty outputId");
            if (outputsFinalizations[outputIds[i]] == 0) {
                outputsFinalizations[outputIds[i]] = exitId;
            }
        }
    }
    /**
     * @notice Flags a single output as spent if it is not flagged already
     * @param outputId The output ID to flag as spent
     */
    function flagOutputFinalized(bytes32 outputId, uint160 exitId) external onlyFromNonQuarantinedExitGame {
        require(outputId != bytes32(""), "Should not flag with empty outputId");
        if (outputsFinalizations[outputId] == 0) {
            outputsFinalizations[outputId] = exitId;
        }
    }
     /**
     * @notice Checks whether output with a given outputId is finalized
     * @param outputId Output ID to check
     */
    function isOutputFinalized(bytes32 outputId) external view returns (bool) {
        return outputsFinalizations[outputId] != 0;
    }
    function getNextExit(uint256 vaultId, address token) external view returns (uint256) {
        bytes32 key = exitQueueKey(vaultId, token);
        return exitsQueues[key].getMin();
    }
    function exitQueueKey(uint256 vaultId, address token) private pure returns (bytes32) {
        return keccak256(abi.encodePacked(vaultId, token));
    }
    function hasExitQueue(bytes32 queueKey) private view returns (bool) {
        return address(exitsQueues[queueKey]) != address(0);
    }
    function getDelegationKey(uint256 priority, uint256 vaultId, address token) private pure returns (bytes32) {
        return keccak256(abi.encodePacked(priority, vaultId, token));
    }
}
pragma solidity 0.5.11;
pragma experimental ABIEncoderV2;
import "./BlockController.sol";
import "./ExitGameController.sol";
import "./registries/VaultRegistry.sol";
import "./registries/ExitGameRegistry.sol";
contract PlasmaFramework is VaultRegistry, ExitGameRegistry, ExitGameController, BlockController {
    uint256 public constant CHILD_BLOCK_INTERVAL = 1000;
    /**
     * The minimum finalization period is the Plasma guarantee that all exits are safe provided the user takes action within the specified time period
     * When the child chain is rogue, user should start their exit and challenge any invalid exit within this period
     * An exit can be processed/finalized after minimum two finalization periods from its inclusion position, unless it is an exit for a deposit,
     * which would use one finalization period, instead of two
     *
     * For the Abstract Layer Design, OmiseGO also uses some multitude of this period to update its framework
     * See also ExitGameRegistry.sol, VaultRegistry.sol, and Vault.sol for more information on the update waiting time (the quarantined period)
     *
     * MVP: https://ethresear.ch/t/minimal-viable-plasma/426
     * MoreVP: https://github.com/omisego/elixir-omg/blob/master/docs/morevp.md#timeline
     * Special period for deposit: https://git.io/JecCV
     */
    uint256 public minExitPeriod;
    address private maintainer;
    string public version;
    constructor(
        uint256 _minExitPeriod,
        uint256 _initialImmuneVaults,
        uint256 _initialImmuneExitGames,
        address _authority,
        address _maintainer
    )
        public
        BlockController(CHILD_BLOCK_INTERVAL, _minExitPeriod, _initialImmuneVaults, _authority)
        ExitGameController(_minExitPeriod, _initialImmuneExitGames)
    {
        minExitPeriod = _minExitPeriod;
        maintainer = _maintainer;
    }
    function getMaintainer() public view returns (address) {
        return maintainer;
    }
    /**
     * @notice Gets the semantic version of the current deployed contracts
    */
    function getVersion() external view returns (string memory) {
        return version;
    }
    
    /**
     * @notice Sets the semantic version of the current deployed contracts
     * @param _version is semver string
     */
    function setVersion(string memory _version) public onlyFrom(getMaintainer()) {
        version = _version;
    }
}pragma solidity 0.5.11;
/**
 * @notice Protocols for the PlasmaFramework
 */
library Protocol {
    uint8 constant internal MVP_VALUE = 1;
    uint8 constant internal MORE_VP_VALUE = 2;
    // solhint-disable-next-line func-name-mixedcase
    function MVP() internal pure returns (uint8) {
        return MVP_VALUE;
    }
    // solhint-disable-next-line func-name-mixedcase
    function MORE_VP() internal pure returns (uint8) {
        return MORE_VP_VALUE;
    }
    function isValidProtocol(uint8 protocol) internal pure returns (bool) {
        return protocol == MVP_VALUE || protocol == MORE_VP_VALUE;
    }
}
pragma solidity 0.5.11;
/**
 * @dev An interface that allows custom logic to process exits for different requirements.
 *      This interface is used to dispatch to each custom processor when 'processExits' is called on PlasmaFramework.
 */
interface IExitProcessor {
    /**
     * @dev Function interface for processing exits.
     * @param exitId Unique ID for exit per tx type
     * @param vaultId ID of the vault that funds the exit
     * @param token Address of the token contract
     */
    function processExit(uint160 exitId, uint256 vaultId, address token) external;
}
pragma solidity 0.5.11;
library BlockModel {
    /**
     * @notice Block data structure that is stored in the contract
     * @param root The Merkle root block hash of the Plasma blocks
     * @param timestamp The timestamp, in seconds, when the block is saved
     */
    struct Block {
        bytes32 root;
        uint256 timestamp;
    }
}
pragma solidity 0.5.11;
import "openzeppelin-solidity/contracts/utils/Address.sol";
import "../Protocol.sol";
import "../utils/Quarantine.sol";
import "../../utils/OnlyFromAddress.sol";
contract ExitGameRegistry is OnlyFromAddress {
    using Quarantine for Quarantine.Data;
    mapping(uint256 => address) private _exitGames; // txType => exit game contract address
    mapping(address => uint256) private _exitGameToTxType; // exit game contract address => tx type
    mapping(uint256 => uint8) private _protocols; // tx type => protocol (MVP/MORE_VP)
    Quarantine.Data private _exitGameQuarantine;
    event ExitGameRegistered(
        uint256 txType,
        address exitGameAddress,
        uint8 protocol
    );
    /**
     * @dev It takes at least 3 * minExitPeriod before each new exit game contract is able to start protecting existing transactions
     *      see: https://github.com/omisego/plasma-contracts/issues/172
     *           https://github.com/omisego/plasma-contracts/issues/197
     */
    constructor (uint256 _minExitPeriod, uint256 _initialImmuneExitGames)
        public
    {
        _exitGameQuarantine.quarantinePeriod = 4 * _minExitPeriod;
        _exitGameQuarantine.immunitiesRemaining = _initialImmuneExitGames;
    }
    /**
     * @notice A modifier to verify that the call is from a non-quarantined exit game
     */
    modifier onlyFromNonQuarantinedExitGame() {
        require(_exitGameToTxType[msg.sender] != 0, "The call is not from a registered exit game contract");
        require(!_exitGameQuarantine.isQuarantined(msg.sender), "ExitGame is quarantined");
        _;
    }
    /**
     * @notice interface to get the 'maintainer' address.
     * @dev see discussion here: https://git.io/Je8is
     */
    function getMaintainer() public view returns (address);
    /**
     * @notice Checks whether the contract is safe to use and is not under quarantine
     * @dev Exposes information about exit games quarantine
     * @param _contract Address of the exit game contract
     * @return boolean Whether the contract is safe to use and is not under quarantine
     */
    function isExitGameSafeToUse(address _contract) public view returns (bool) {
        return _exitGameToTxType[_contract] != 0 && !_exitGameQuarantine.isQuarantined(_contract);
    }
    /**
     * @notice Registers an exit game within the PlasmaFramework. Only the maintainer can call the function.
     * @dev Emits ExitGameRegistered event to notify clients
     * @param _txType The tx type where the exit game wants to register
     * @param _contract Address of the exit game contract
     * @param _protocol The transaction protocol, either 1 for MVP or 2 for MoreVP
     */
    function registerExitGame(uint256 _txType, address _contract, uint8 _protocol) public onlyFrom(getMaintainer()) {
        require(_txType != 0, "Should not register with tx type 0");
        require(Address.isContract(_contract), "Should not register with a non-contract address");
        require(_exitGames[_txType] == address(0), "The tx type is already registered");
        require(_exitGameToTxType[_contract] == 0, "The exit game contract is already registered");
        require(Protocol.isValidProtocol(_protocol), "Invalid protocol value");
        _exitGames[_txType] = _contract;
        _exitGameToTxType[_contract] = _txType;
        _protocols[_txType] = _protocol;
        _exitGameQuarantine.quarantine(_contract);
        emit ExitGameRegistered(_txType, _contract, _protocol);
    }
    /**
     * @notice Public getter for retrieving protocol with tx type
     */
    function protocols(uint256 _txType) public view returns (uint8) {
        return _protocols[_txType];
    }
    /**
     * @notice Public getter for retrieving exit game address with tx type
     */
    function exitGames(uint256 _txType) public view returns (address) {
        return _exitGames[_txType];
    }
    /**
     * @notice Public getter for retrieving tx type with exit game address
     */
    function exitGameToTxType(address _exitGame) public view returns (uint256) {
        return _exitGameToTxType[_exitGame];
    }
}
pragma solidity 0.5.11;
import "openzeppelin-solidity/contracts/utils/Address.sol";
import "../utils/Quarantine.sol";
import "../../utils/OnlyFromAddress.sol";
contract VaultRegistry is OnlyFromAddress {
    using Quarantine for Quarantine.Data;
    mapping(uint256 => address) private _vaults; // vault id => vault address
    mapping(address => uint256) private _vaultToId; // vault address => vault id
    Quarantine.Data private _vaultQuarantine;
    event VaultRegistered(
        uint256 vaultId,
        address vaultAddress
    );
    /**
     * @dev It takes at least 2 minExitPeriod for each new vault contract to start.
     *      This is to protect deposit transactions already in mempool,
     *      and also make sure user only needs to SE within first week when invalid vault is registered.
     *      see: https://github.com/omisego/plasma-contracts/issues/412
     *           https://github.com/omisego/plasma-contracts/issues/173
     */
    constructor(uint256 _minExitPeriod, uint256 _initialImmuneVaults)
        public
    {
        _vaultQuarantine.quarantinePeriod = 2 * _minExitPeriod;
        _vaultQuarantine.immunitiesRemaining = _initialImmuneVaults;
    }
    /**
     * @notice interface to get the 'maintainer' address.
     * @dev see discussion here: https://git.io/Je8is
     */
    function getMaintainer() public view returns (address);
    /**
     * @notice A modifier to check that the call is from a non-quarantined vault
     */
    modifier onlyFromNonQuarantinedVault() {
        require(_vaultToId[msg.sender] > 0, "The call is not from a registered vault");
        require(!_vaultQuarantine.isQuarantined(msg.sender), "Vault is quarantined");
        _;
    }
    /**
     * @notice Register a vault within the PlasmaFramework. Only a maintainer can make the call.
     * @dev emits VaultRegistered event to notify clients
     * @param _vaultId The ID for the vault contract to register
     * @param _vaultAddress Address of the vault contract
     */
    function registerVault(uint256 _vaultId, address _vaultAddress) public onlyFrom(getMaintainer()) {
        require(_vaultId != 0, "Should not register with vault ID 0");
        require(Address.isContract(_vaultAddress), "Should not register with a non-contract address");
        require(_vaults[_vaultId] == address(0), "The vault ID is already registered");
        require(_vaultToId[_vaultAddress] == 0, "The vault contract is already registered");
        _vaults[_vaultId] = _vaultAddress;
        _vaultToId[_vaultAddress] = _vaultId;
        _vaultQuarantine.quarantine(_vaultAddress);
        emit VaultRegistered(_vaultId, _vaultAddress);
    }
    /**
     * @notice Public getter for retrieving vault address with vault ID
     */
    function vaults(uint256 _vaultId) public view returns (address) {
        return _vaults[_vaultId];
    }
    /**
     * @notice Public getter for retrieving vault ID with vault address
     */
    function vaultToId(address _vaultAddress) public view returns (uint256) {
        return _vaultToId[_vaultAddress];
    }
}
pragma solidity 0.5.11;
import "../../utils/PosLib.sol";
library ExitPriority {
    using PosLib for PosLib.Position;
    /**
     * @dev Returns an exit priority for a given UTXO position and a unique ID.
     * The priority for Plasma M(ore)VP protocol is a combination of 'exitableAt' and 'txPos'.
     * Since 'exitableAt' only provides granularity of block, add 'txPos' to provide priority for a transaction.
     * @notice Detailed explanation on field lengths can be found at https://github.com/omisego/plasma-contracts/pull/303#discussion_r328850572
     * @param exitId Unique exit identifier
     * @return An exit priority
     *   Anatomy of returned value, most significant bits first
     *   42 bits  - timestamp in seconds (exitable_at); we can represent dates until year 141431
     *   54 bits  - blocknum * 10^5 + txindex; 54 bits represent all transactions for 85 years. Be aware that child chain block number jumps with the interval of CHILD_BLOCK_INTERVAL, which would be 1000 in production.
     *   160 bits - exit id
     */
    function computePriority(uint64 exitableAt, PosLib.Position memory txPos, uint160 exitId)
        internal
        pure
        returns (uint256)
    {
        return (uint256(exitableAt) << 214) | (txPos.getTxPositionForExitPriority() << 160) | uint256(exitId);
    }
    function parseExitableAt(uint256 priority) internal pure returns (uint64) {
        return uint64(priority >> 214);
    }
    function parseExitId(uint256 priority) internal pure returns (uint160) {
        // Exit ID uses only 160 least significant bits
        return uint160(priority);
    }
}
pragma solidity 0.5.11;
import "../../utils/OnlyFromAddress.sol";
import "openzeppelin-solidity/contracts/math/SafeMath.sol";
/**
 * @title PriorityQueue
 * @dev Min-heap priority queue implementation
 */
contract PriorityQueue is OnlyFromAddress {
    using SafeMath for uint256;
    struct Queue {
        uint256[] heapList;
        uint256 currentSize;
    }
    Queue public queue;
    address public framework;
    constructor() public {
        queue.heapList = [0];
        queue.currentSize = 0;
        // it is expected that this should be called by PlasmaFramework
        // and only PlasmaFramework contract can add things to the queue
        framework = msg.sender;
    }
    /**
     * @notice Gets num of elements in the queue
     */
    function currentSize() external view returns (uint256) {
        return queue.currentSize;
    }
    /**
     * @notice Gets all elements in the queue
     */
    function heapList() external view returns (uint256[] memory) {
        return queue.heapList;
    }
    /**
     * @notice Inserts an element into the queue by the framework
     * @dev Does not perform deduplication
     */
    function insert(uint256 _element) external onlyFrom(framework) {
        queue.heapList.push(_element);
        queue.currentSize = queue.currentSize.add(1);
        percUp(queue, queue.currentSize);
    }
    /**
     * @notice Deletes the smallest element from the queue by the framework
     * @dev Fails when queue is empty
     * @return The smallest element in the priority queue
     */
    function delMin() external onlyFrom(framework) returns (uint256) {
        require(queue.currentSize > 0, "Queue is empty");
        uint256 retVal = queue.heapList[1];
        queue.heapList[1] = queue.heapList[queue.currentSize];
        delete queue.heapList[queue.currentSize];
        queue.currentSize = queue.currentSize.sub(1);
        percDown(queue, 1);
        queue.heapList.length = queue.heapList.length.sub(1);
        return retVal;
    }
    /**
     * @notice Returns the smallest element from the queue
     * @dev Fails when queue is empty
     * @return The smallest element in the priority queue
     */
    function getMin() external view returns (uint256) {
        require(queue.currentSize > 0, "Queue is empty");
        return queue.heapList[1];
    }
    function percUp(Queue storage self, uint256 pointer) private {
        uint256 i = pointer;
        uint256 j = i;
        uint256 newVal = self.heapList[i];
        while (newVal < self.heapList[i.div(2)]) {
            self.heapList[i] = self.heapList[i.div(2)];
            i = i.div(2);
        }
        if (i != j) {
            self.heapList[i] = newVal;
        }
    }
    function percDown(Queue storage self, uint256 pointer) private {
        uint256 i = pointer;
        uint256 j = i;
        uint256 newVal = self.heapList[i];
        uint256 mc = minChild(self, i);
        while (mc <= self.currentSize && newVal > self.heapList[mc]) {
            self.heapList[i] = self.heapList[mc];
            i = mc;
            mc = minChild(self, i);
        }
        if (i != j) {
            self.heapList[i] = newVal;
        }
    }
    function minChild(Queue storage self, uint256 i) private view returns (uint256) {
        if (i.mul(2).add(1) > self.currentSize) {
            return i.mul(2);
        } else {
            if (self.heapList[i.mul(2)] < self.heapList[i.mul(2).add(1)]) {
                return i.mul(2);
            } else {
                return i.mul(2).add(1);
            }
        }
    }
}
pragma solidity 0.5.11;
/**
 * @notice Provides a way to quarantine (disable) contracts for a specified period of time
 * @dev The immunitiesRemaining member allows deployment to the platform with some
 * pre-verified contracts that don't get quarantined
 */
library Quarantine {
    struct Data {
        mapping(address => uint256) store;
        uint256 quarantinePeriod;
        uint256 immunitiesRemaining;
    }
    /**
     * @notice Checks whether a contract is quarantined
     */
    function isQuarantined(Data storage _self, address _contractAddress) internal view returns (bool) {
        return block.timestamp < _self.store[_contractAddress];
    }
    /**
     * @notice Places a contract into quarantine
     * @param _contractAddress The address of the contract
     */
    function quarantine(Data storage _self, address _contractAddress) internal {
        require(_contractAddress != address(0), "An empty address cannot be quarantined");
        require(_self.store[_contractAddress] == 0, "The contract is already quarantined");
        if (_self.immunitiesRemaining == 0) {
            _self.store[_contractAddress] = block.timestamp + _self.quarantinePeriod;
        } else {
            _self.immunitiesRemaining--;
        }
    }
}
pragma solidity 0.5.11;
contract OnlyFromAddress {
    modifier onlyFrom(address caller) {
        require(msg.sender == caller, "Caller address is unauthorized");
        _;
    }
}
pragma solidity 0.5.11;
import "openzeppelin-solidity/contracts/math/SafeMath.sol";
/**
 * @dev UTXO position = (blknum * BLOCK_OFFSET + txIndex * TX_OFFSET + outputIndex).
 * TX position = (blknum * BLOCK_OFFSET + txIndex * TX_OFFSET)
 */
library PosLib {
    struct Position {
        uint64 blockNum;
        uint16 txIndex;
        uint16 outputIndex;
    }
    uint256 constant internal BLOCK_OFFSET = 1000000000;
    uint256 constant internal TX_OFFSET = 10000;
    
    uint256 constant internal MAX_OUTPUT_INDEX = TX_OFFSET - 1;
    // since we are using merkle tree of depth 16, max tx index size is 2^16 - 1
    uint256 constant internal MAX_TX_INDEX = 2 ** 16 - 1;
    // in ExitPriority, only 54 bits are reserved for both blockNum and txIndex
    uint256 constant internal MAX_BLOCK_NUM = ((2 ** 54 - 1) - MAX_TX_INDEX) / (BLOCK_OFFSET / TX_OFFSET);
    /**
     * @notice Returns transaction position which is an utxo position of zero index output
     * @param pos UTXO position of the output
     * @return Position of a transaction
     */
    function toStrictTxPos(Position memory pos)
        internal
        pure
        returns (Position memory)
    {
        return Position(pos.blockNum, pos.txIndex, 0);
    }
    /**
     * @notice Used for calculating exit priority
     * @param pos UTXO position for the output
     * @return Identifier of the transaction
     */
    function getTxPositionForExitPriority(Position memory pos)
        internal
        pure
        returns (uint256)
    {
        return encode(pos) / TX_OFFSET;
    }
    /**
     * @notice Encodes a position
     * @param pos Position
     * @return Position encoded as an integer
     */
    function encode(Position memory pos) internal pure returns (uint256) {
        require(pos.outputIndex <= MAX_OUTPUT_INDEX, "Invalid output index");
        require(pos.blockNum <= MAX_BLOCK_NUM, "Invalid block number");
        return pos.blockNum * BLOCK_OFFSET + pos.txIndex * TX_OFFSET + pos.outputIndex;
    }
    /**
     * @notice Decodes a position from an integer value
     * @param pos Encoded position
     * @return Position
     */
    function decode(uint256 pos) internal pure returns (Position memory) {
        uint256 blockNum = pos / BLOCK_OFFSET;
        uint256 txIndex = (pos % BLOCK_OFFSET) / TX_OFFSET;
        uint16 outputIndex = uint16(pos % TX_OFFSET);
        require(blockNum <= MAX_BLOCK_NUM, "blockNum exceeds max size allowed in PlasmaFramework");
        require(txIndex <= MAX_TX_INDEX, "txIndex exceeds the size of uint16");
        return Position(uint64(blockNum), uint16(txIndex), outputIndex);
    }
}
pragma solidity 0.5.11;
import "../framework/PlasmaFramework.sol";
import "../utils/OnlyFromAddress.sol";
/**
 * @notice Base contract for vault implementation
 * @dev This is the functionality to swap "deposit verifier"
 *      Setting a new deposit verifier allows an upgrade to a new deposit tx type without upgrading the vault
 */
contract Vault is OnlyFromAddress {
    byte private constant LEAF_SALT = 0x00;
    byte private constant NODE_SALT = 0x01;
    event SetDepositVerifierCalled(address nextDepositVerifier);
    PlasmaFramework internal framework;
    bytes32[16] internal zeroHashes; // Pre-computes zero hashes to be used for building merkle tree for deposit block
    /**
     * @notice Stores deposit verifier contract addresses; first contract address is effective until the
     *  `newDepositVerifierMaturityTimestamp`; second contract address becomes effective after that timestamp
    */
    address[2] public depositVerifiers;
    uint256 public newDepositVerifierMaturityTimestamp = 2 ** 255; // point far in the future
    constructor(PlasmaFramework _framework) public {
        framework = _framework;
        zeroHashes = getZeroHashes();
    }
    /**
     * @dev Pre-computes zero hashes to be used for building Merkle tree for deposit block
     */
    function getZeroHashes() private pure returns (bytes32[16] memory) {
        bytes32[16] memory hashes;
        bytes32 zeroHash = keccak256(abi.encodePacked(LEAF_SALT, uint256(0)));
        for (uint i = 0; i < 16; i++) {
            hashes[i] = zeroHash;
            zeroHash = keccak256(abi.encodePacked(NODE_SALT, zeroHash, zeroHash));
        }
        return hashes;
    }
    /**
     * @notice Checks whether the call originates from a non-quarantined exit game contract
    */
    modifier onlyFromNonQuarantinedExitGame() {
        require(
            ExitGameRegistry(framework).isExitGameSafeToUse(msg.sender),
            "Called from a non-registered or quarantined exit game contract"
        );
        _;
    }
    /**
     * @notice Sets the deposit verifier contract, which may be called only by the operator
     * @dev emit SetDepositVerifierCalled
     * @dev When one contract is already set, the next one is effective after 2 * MIN_EXIT_PERIOD.
     *      This is to protect deposit transactions already in mempool,
     *      and also make sure user only needs to SE within first week when invalid vault is registered.
     *
     *      see: https://github.com/omisego/plasma-contracts/issues/412
     *           https://github.com/omisego/plasma-contracts/issues/173
     *
     * @param _verifier Address of the verifier contract
     */
    function setDepositVerifier(address _verifier) public onlyFrom(framework.getMaintainer()) {
        require(_verifier != address(0), "Cannot set an empty address as deposit verifier");
        if (depositVerifiers[0] != address(0)) {
            depositVerifiers[0] = getEffectiveDepositVerifier();
            depositVerifiers[1] = _verifier;
            newDepositVerifierMaturityTimestamp = now + 2 * framework.minExitPeriod();
        } else {
            depositVerifiers[0] = _verifier;
        }
        emit SetDepositVerifierCalled(_verifier);
    }
    /**
     * @notice Retrieves the currently effective deposit verifier contract address
     * @return Contract address of the deposit verifier
     */
    function getEffectiveDepositVerifier() public view returns (address) {
        if (now < newDepositVerifierMaturityTimestamp) {
            return depositVerifiers[0];
        } else {
            return depositVerifiers[1];
        }
    }
    /**
     * @notice Generate and submit a deposit block root to the PlasmaFramework
     * @dev Designed to be called by the contract that inherits Vault
     */
    function submitDepositBlock(bytes memory depositTx) internal returns (uint256) {
        bytes32 root = getDepositBlockRoot(depositTx);
        uint256 depositBlkNum = framework.submitDepositBlock(root);
        return depositBlkNum;
    }
    function getDepositBlockRoot(bytes memory depositTx) private view returns (bytes32) {
        bytes32 root = keccak256(abi.encodePacked(LEAF_SALT, depositTx));
        for (uint i = 0; i < 16; i++) {
            root = keccak256(abi.encodePacked(NODE_SALT, root, zeroHashes[i]));
        }
        return root;
    }
}
pragma solidity 0.5.11;
interface IErc20DepositVerifier {
    /**
     * @notice Verifies a deposit transaction
     * @param depositTx The deposit transaction
     * @param sender The owner of the deposit transaction
     * @param vault The address of the Erc20Vault contract
     * @return Verified (owner, token, amount) of the deposit ERC20 token data
     */
    function verify(bytes calldata depositTx, address sender, address vault)
        external
        view
        returns (address owner, address token, uint256 amount);
}
pragma solidity ^0.5.0;
/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");
        return c;
    }
    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SafeMath: subtraction overflow");
        uint256 c = a - b;
        return c;
    }
    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
        if (a == 0) {
            return 0;
        }
        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");
        return c;
    }
    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0, "SafeMath: division by zero");
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold
        return c;
    }
    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b != 0, "SafeMath: modulo by zero");
        return a % b;
    }
}
pragma solidity ^0.5.0;
/**
 * @dev Interface of the ERC20 standard as defined in the EIP. Does not include
 * the optional functions; to access them see `ERC20Detailed`.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);
    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);
    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a `Transfer` event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);
    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through `transferFrom`. This is
     * zero by default.
     *
     * This value changes when `approve` or `transferFrom` are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);
    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * > Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an `Approval` event.
     */
    function approve(address spender, uint256 amount) external returns (bool);
    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a `Transfer` event.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);
    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to `approve`. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}
pragma solidity ^0.5.0;
import "./IERC20.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";
/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using SafeMath for uint256;
    using Address for address;
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }
    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        // solhint-disable-next-line max-line-length
        require((value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).add(value);
        callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).sub(value);
        callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }
    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves.
        // A Solidity high level call has three parts:
        //  1. The target address is checked to verify it contains contract code
        //  2. The call itself is made, and success asserted
        //  3. The return value is decoded, which in turn checks the size of the returned data.
        // solhint-disable-next-line max-line-length
        require(address(token).isContract(), "SafeERC20: call to non-contract");
        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = address(token).call(data);
        require(success, "SafeERC20: low-level call failed");
        if (returndata.length > 0) { // Return data is optional
            // solhint-disable-next-line max-line-length
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}
pragma solidity ^0.5.0;
/**
 * @dev Collection of functions related to the address type,
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * This test is non-exhaustive, and there may be false-negatives: during the
     * execution of a contract's constructor, its address will be reported as
     * not containing a contract.
     *
     * > It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies in extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.
        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(account) }
        return size > 0;
    }
}