Contract 0x87930d19b4c98dd08b8b30793d4fb38ce9b6451d 1

 
Txn Hash Method
Block
From
To
Value [Txn Fee]
0x3ef217a9f40a1e7672b625ad7d7e8dfd01322972b5303a5d88702ae4596f4ab8Poke514557022022-11-26 4:59:427 days 11 hrs ago0x0b640b3e91420b495a33d11ee96afb19be2db693 IN  0x87930d19b4c98dd08b8b30793d4fb38ce9b6451d0 FTM0.119411346
0x66019acb2dcc6dd7e29c540306b4b69d03fddc31335301c374dd1df707708855Poke514438742022-11-25 20:56:457 days 20 hrs ago0x0b640b3e91420b495a33d11ee96afb19be2db693 IN  0x87930d19b4c98dd08b8b30793d4fb38ce9b6451d0 FTM0.0238346
0x5ea94cd2a6d72e483066bc10dd2c22f1e0ac561497cf0338626acb67fa00fdcaPoke514287232022-11-25 12:55:008 days 4 hrs ago0x0b640b3e91420b495a33d11ee96afb19be2db693 IN  0x87930d19b4c98dd08b8b30793d4fb38ce9b6451d0 FTM0.120362605223
0xada4d2bb463c23e6b02b88add54acd550cc737a1893e916b4ed2edda3ea2c65aPoke514139832022-11-25 4:53:468 days 12 hrs ago0x0b640b3e91420b495a33d11ee96afb19be2db693 IN  0x87930d19b4c98dd08b8b30793d4fb38ce9b6451d0 FTM0.117496186342
0x5c00043c7351cd82a0bd7eb90625aa36a77ad17f498032bc8ef4bc7bc3fa219aPoke514009262022-11-24 20:52:468 days 20 hrs ago0x0b640b3e91420b495a33d11ee96afb19be2db693 IN  0x87930d19b4c98dd08b8b30793d4fb38ce9b6451d0 FTM0.062264951499
0x2f2c320b19b2fd05db8b54ddcd024aed022459136182759fde2340e471a1b9e6Poke513883722022-11-24 12:50:209 days 4 hrs ago0x0b640b3e91420b495a33d11ee96afb19be2db693 IN  0x87930d19b4c98dd08b8b30793d4fb38ce9b6451d0 FTM0.026574167994
0x5fa8ed20ef92ca5dd3af4dca793774c50d301f9ff916df946837c6eb13cfddf8Poke513722252022-11-24 4:49:009 days 12 hrs ago0x0b640b3e91420b495a33d11ee96afb19be2db693 IN  0x87930d19b4c98dd08b8b30793d4fb38ce9b6451d0 FTM0.041436896199
0x51d0129f4a76d8a948f316abd1723781a9ea6217f090ecabe636a428c59110dfPoke513569632022-11-23 20:48:119 days 20 hrs ago0x0b640b3e91420b495a33d11ee96afb19be2db693 IN  0x87930d19b4c98dd08b8b30793d4fb38ce9b6451d0 FTM0.117496186342
0x8fc9734a2862373e2547aa1099311ab70000d2c800c0022a77843df12b2e3051Poke513412472022-11-23 12:46:2410 days 4 hrs ago0x0b640b3e91420b495a33d11ee96afb19be2db693 IN  0x87930d19b4c98dd08b8b30793d4fb38ce9b6451d0 FTM0.042093266851
0xcbff7273c1588780a4536dc6c9c408ddaffb6c54486ed0c8e55c96c8cbbfb819Poke513263002022-11-23 4:44:4810 days 12 hrs ago0x0b640b3e91420b495a33d11ee96afb19be2db693 IN  0x87930d19b4c98dd08b8b30793d4fb38ce9b6451d0 FTM0.118642753895
0xe097a6179f273b077d583f0c17692e21263aca179c7a2d1b852fab89a1a67c57Poke513083682022-11-22 20:43:3210 days 20 hrs ago0x0b640b3e91420b495a33d11ee96afb19be2db693 IN  0x87930d19b4c98dd08b8b30793d4fb38ce9b6451d0 FTM0.016616500377
0x2f998093af448f114fe084dcea5c5869bcb5a5feaee3ffbb33e971e8612834e4Poke512908322022-11-22 12:42:4311 days 4 hrs ago0x0b640b3e91420b495a33d11ee96afb19be2db693 IN  0x87930d19b4c98dd08b8b30793d4fb38ce9b6451d0 FTM0.134402470412
0x10ce6a3d3ab7eff0d0f6e304e87b2cee78a1f597936237395fbc44dbd913028dPoke512758082022-11-22 4:39:4711 days 12 hrs ago0x0b640b3e91420b495a33d11ee96afb19be2db693 IN  0x87930d19b4c98dd08b8b30793d4fb38ce9b6451d0 FTM0.11601500495
0x5671a2d2586fbb2dfc5a846c65373d38befc8ed42b0912caf201b31a845ab29dPoke512556222022-11-21 20:38:3511 days 20 hrs ago0x0b640b3e91420b495a33d11ee96afb19be2db693 IN  0x87930d19b4c98dd08b8b30793d4fb38ce9b6451d0 FTM0.215081255704
0x205c004ee3ddbdfc06eb173134ee3e5f0b3f4ad42fb58dce5eff034d4ae5ed9aPoke512377052022-11-21 12:37:1412 days 4 hrs ago0x0b640b3e91420b495a33d11ee96afb19be2db693 IN  0x87930d19b4c98dd08b8b30793d4fb38ce9b6451d0 FTM0.041996880058
0xca8956e9903d9c82b544e0486aa12fecea0ad150a18b1afd7cd4c42d0792ed15Poke512216902022-11-21 4:35:3812 days 12 hrs ago0x0b640b3e91420b495a33d11ee96afb19be2db693 IN  0x87930d19b4c98dd08b8b30793d4fb38ce9b6451d0 FTM0.01604735849
0xe99e65ad12f01ed4a23dfb6a0951fc1a83baf1821ae24689e1585555f4ed250ePoke512027422022-11-20 20:34:3912 days 20 hrs ago0x0b640b3e91420b495a33d11ee96afb19be2db693 IN  0x87930d19b4c98dd08b8b30793d4fb38ce9b6451d0 FTM0.115192938022
0x0197939845c5d33d27a62c76285dca33eb97732d9ec787311585fa9a1509a2e3Poke511849682022-11-20 12:29:3113 days 4 hrs ago0x0b640b3e91420b495a33d11ee96afb19be2db693 IN  0x87930d19b4c98dd08b8b30793d4fb38ce9b6451d0 FTM0.11601500495
0xaad8d3170c5640f99ee25eceff0288beef0a947fc7c6466ff7d68d40c40109c1Poke511670332022-11-20 4:28:0313 days 12 hrs ago0x0b640b3e91420b495a33d11ee96afb19be2db693 IN  0x87930d19b4c98dd08b8b30793d4fb38ce9b6451d0 FTM0.158741114446
0x0a1d4d9712d76a32292f571e6fb561bb6e35964a8f5cda74c5087ab769fb93e1Poke511469982022-11-19 20:19:0213 days 20 hrs ago0x0b640b3e91420b495a33d11ee96afb19be2db693 IN  0x87930d19b4c98dd08b8b30793d4fb38ce9b6451d0 FTM0.065714717678
0xf3fd53054640052e58e4d70f75a16c183f962d1cc2fb5b756d61ff4171be162bPoke511270472022-11-19 12:17:5514 days 4 hrs ago0x0b640b3e91420b495a33d11ee96afb19be2db693 IN  0x87930d19b4c98dd08b8b30793d4fb38ce9b6451d0 FTM0.020032041628
0x4fa40920531ce56589ba9c545c1ecfe724aa414a90acab06773bffffc47c737fPoke511090092022-11-19 4:16:5414 days 12 hrs ago0x0b640b3e91420b495a33d11ee96afb19be2db693 IN  0x87930d19b4c98dd08b8b30793d4fb38ce9b6451d0 FTM0.065714717678
0xba27c7923c21f61dc7b57bdb98a6fb1b992791595eea8733757c5d48d11c99d9Poke510900352022-11-18 20:16:0814 days 20 hrs ago0x0b640b3e91420b495a33d11ee96afb19be2db693 IN  0x87930d19b4c98dd08b8b30793d4fb38ce9b6451d0 FTM0.074599309728
0x02c593e7cfc64328b70c1eb83f1e413c1e261d6845a7111c8fe1594f77a149bfPoke510791802022-11-18 12:14:5115 days 4 hrs ago0x0b640b3e91420b495a33d11ee96afb19be2db693 IN  0x87930d19b4c98dd08b8b30793d4fb38ce9b6451d0 FTM0.065714717678
0xfea4b298ddd3ac968fbcee942339237acd556ba97cff095fb277172b3bb51ad5Poke510614652022-11-18 4:13:5915 days 12 hrs ago0x0b640b3e91420b495a33d11ee96afb19be2db693 IN  0x87930d19b4c98dd08b8b30793d4fb38ce9b6451d0 FTM0.023855013238
[ Download CSV Export 
Latest 1 internal transaction
Parent Txn Hash Block From To Value
0x19da3d7b5b45b2660c15fc1e2bbe6b863b878cd6dd783b84afcf944e29af593a384671992022-05-17 21:30:53199 days 19 hrs ago Growth DeFi: Deployer  Contract Creation0 FTM
[ Download CSV Export 
Loading

Similar Match Source Code
Note: This contract matches the deployed ByteCode of the Source Code for Contract 0x91ef85162f18c038f0dc1e01a7a2f4191b2c6ce6

Contract Name:
RateCapOracle

Compiler Version
v0.6.12+commit.27d51765

Optimization Enabled:
No with 200 runs

Other Settings:
default evmVersion, GNU GPLv3 license

Contract Source Code (Solidity)

/**
 *Submitted for verification at FtmScan.com on 2022-05-17
*/

// File: contracts/dss-exec-lib/CollateralOpts.sol

// SPDX-License-Identifier: AGPL-3.0-or-later

pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;

struct CollateralOpts {
    bytes32 ilk;
    address gem;
    address join;
    address clip;
    address calc;
    address pip;
    bool    isLiquidatable;
    bool    isOSM;
    bool    whitelistOSM;
    uint256 ilkDebtCeiling;
    uint256 minVaultAmount;
    uint256 maxLiquidationAmount;
    uint256 liquidationPenalty;
    uint256 ilkStabilityFee;
    uint256 startingPriceFactor;
    uint256 breakerTolerance;
    uint256 auctionDuration;
    uint256 permittedDrop;
    uint256 liquidationRatio;
    uint256 kprFlatReward;
    uint256 kprPctReward;
}

// File: contracts/dss-exec-lib/DssExecLib.sol

//
// DssExecLib.sol -- MakerDAO Executive Spellcrafting Library
//
// Copyright (C) 2020 Maker Ecosystem Growth Holdings, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
pragma solidity ^0.6.12;


interface Initializable {
    function init(bytes32) external;
}

interface Authorizable {
    function rely(address) external;
    function deny(address) external;
}

interface Fileable {
    function file(bytes32, address) external;
    function file(bytes32, uint256) external;
    function file(bytes32, bytes32, uint256) external;
    function file(bytes32, bytes32, address) external;
}

interface Drippable {
    function drip() external returns (uint256);
    function drip(bytes32) external returns (uint256);
}

interface Pricing {
    function poke(bytes32) external;
}

interface ERC20 {
    function decimals() external returns (uint8);
}

interface DssVat {
    function hope(address) external;
    function nope(address) external;
    function ilks(bytes32) external returns (uint256 Art, uint256 rate, uint256 spot, uint256 line, uint256 dust);
    function Line() external view returns (uint256);
    function suck(address, address, uint) external;
}

interface ClipLike {
    function vat() external returns (address);
    function dog() external returns (address);
    function spotter() external view returns (address);
    function calc() external view returns (address);
    function ilk() external returns (bytes32);
}

interface JoinLike {
    function vat() external returns (address);
    function ilk() external returns (bytes32);
    function gem() external returns (address);
    function dec() external returns (uint256);
    function join(address, uint) external;
    function exit(address, uint) external;
}

// Includes Median and OSM functions
/*
interface OracleLike {
    function src() external view returns (address);
    function lift(address[] calldata) external;
    function drop(address[] calldata) external;
    function setBar(uint256) external;
    function kiss(address) external;
    function diss(address) external;
    function kiss(address[] calldata) external;
    function diss(address[] calldata) external;
    function orb0() external view returns (address);
    function orb1() external view returns (address);
}
*/

interface MomLike {
    function setOsm(bytes32, address) external;
    function setPriceTolerance(address, uint256) external;
}

interface RegistryLike {
    function add(address) external;
    function xlip(bytes32) external view returns (address);
}

// https://github.com/makerdao/dss-chain-log
interface ChainlogLike {
    function setVersion(string calldata) external;
    function setIPFS(string calldata) external;
    function setSha256sum(string calldata) external;
    function getAddress(bytes32) external view returns (address);
    function setAddress(bytes32, address) external;
    function removeAddress(bytes32) external;
}

interface IAMLike {
    function ilks(bytes32) external view returns (uint256,uint256,uint48,uint48,uint48);
    function setIlk(bytes32,uint256,uint256,uint256) external;
    function remIlk(bytes32) external;
    function exec(bytes32) external returns (uint256);
}

interface LerpFactoryLike {
    function newLerp(bytes32 name_, address target_, bytes32 what_, uint256 startTime_, uint256 start_, uint256 end_, uint256 duration_) external returns (address);
    function newIlkLerp(bytes32 name_, address target_, bytes32 ilk_, bytes32 what_, uint256 startTime_, uint256 start_, uint256 end_, uint256 duration_) external returns (address);
}

interface LerpLike {
    function tick() external;
}


library DssExecLib {

    /*****************/
    /*** Constants ***/
    /*****************/
    address constant public LOG_BSCMAIN = 0xc1E1d478296F3b0F2CA9Cc88F620de0b791aBf27; // bscmain
    address constant public LOG_AVAXMAIN = 0xd1a85349D73BaA4fFA6737474fdce9347B887cB2; // avaxmain
    address constant public LOG_FTMMAIN = 0x0041DA86f4865ecFCc388c81BEF2DBf9A76fAAD8; // ftmmain

    uint256 constant internal WAD      = 10 ** 18;
    uint256 constant internal RAY      = 10 ** 27;
    uint256 constant internal RAD      = 10 ** 45;
    uint256 constant internal THOUSAND = 10 ** 3;
    uint256 constant internal MILLION  = 10 ** 6;

    uint256 constant internal BPS_ONE_PCT             = 100;
    uint256 constant internal BPS_ONE_HUNDRED_PCT     = 100 * BPS_ONE_PCT;
    uint256 constant internal RATES_ONE_HUNDRED_PCT   = 1000000021979553151239153027;

    /**********************/
    /*** Math Functions ***/
    /**********************/
    function _add(uint256 x, uint256 y) internal pure returns (uint256 z) {
        require((z = x + y) >= x);
    }
    function _sub(uint256 x, uint256 y) internal pure returns (uint256 z) {
        require((z = x - y) <= x);
    }
    function _mul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        require(y == 0 || (z = x * y) / y == x);
    }
    function wmul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = _add(_mul(x, y), WAD / 2) / WAD;
    }
    function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = _add(_mul(x, y), RAY / 2) / RAY;
    }
    function wdiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = _add(_mul(x, WAD), y / 2) / y;
    }
    function rdiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = _add(_mul(x, RAY), y / 2) / y;
    }

    /****************************/
    /*** Core Address Helpers ***/
    /****************************/
    function dai()        internal view returns (address) { return getChangelogAddress("MCD_DAI"); }
    function mkr()        internal view returns (address) { return getChangelogAddress("MCD_GOV"); }
    function vat()        internal view returns (address) { return getChangelogAddress("MCD_VAT"); }
    function cat()        internal view returns (address) { return getChangelogAddress("MCD_CAT"); }
    function dog()        internal view returns (address) { return getChangelogAddress("MCD_DOG"); }
    function jug()        internal view returns (address) { return getChangelogAddress("MCD_JUG"); }
    function pot()        internal view returns (address) { return getChangelogAddress("MCD_POT"); }
    function vow()        internal view returns (address) { return getChangelogAddress("MCD_VOW"); }
    function end()        internal view returns (address) { return getChangelogAddress("MCD_END"); }
    function esm()        internal view returns (address) { return getChangelogAddress("MCD_ESM"); }
    function reg()        internal view returns (address) { return getChangelogAddress("ILK_REGISTRY"); }
    function spotter()    internal view returns (address) { return getChangelogAddress("MCD_SPOT"); }
    function flap()       internal view returns (address) { return getChangelogAddress("MCD_FLAP"); }
    function flop()       internal view returns (address) { return getChangelogAddress("MCD_FLOP"); }
    function osmMom()     internal view returns (address) { return getChangelogAddress("OSM_MOM"); }
    function govGuard()   internal view returns (address) { return getChangelogAddress("GOV_GUARD"); }
    function flipperMom() internal view returns (address) { return getChangelogAddress("FLIPPER_MOM"); }
    function clipperMom() internal view returns (address) { return getChangelogAddress("CLIPPER_MOM"); }
    function pauseProxy() internal view returns (address) { return getChangelogAddress("MCD_PAUSE_PROXY"); }
    function autoLine()   internal view returns (address) { return getChangelogAddress("MCD_IAM_AUTO_LINE"); }
    function daiJoin()    internal view returns (address) { return getChangelogAddress("MCD_JOIN_DAI"); }
    function lerpFab()    internal view returns (address) { return getChangelogAddress("LERP_FAB"); }

    function clip(bytes32 _ilk) internal view returns (address _clip) {
        _clip = RegistryLike(reg()).xlip(_ilk);
    }

    function flip(bytes32 _ilk) internal view returns (address _flip) {
        _flip = RegistryLike(reg()).xlip(_ilk);
    }

    function calc(bytes32 _ilk) internal view returns (address _calc) {
        _calc = ClipLike(clip(_ilk)).calc();
    }

    function getChangelogAddress(bytes32 _key) internal view returns (address) {
        return ChainlogLike(log()).getAddress(_key);
    }

    function log() internal pure returns (address) {
      uint256 _chainId;
      assembly { _chainId := chainid() }
      if (_chainId == 56) return LOG_BSCMAIN;
      if (_chainId == 43114) return LOG_AVAXMAIN;
      if (_chainId == 250) return LOG_FTMMAIN;
      require(false, "unsupported network");
    }

    /****************************/
    /*** Changelog Management ***/
    /****************************/
    /**
        @dev Set an address in the MCD on-chain changelog.
        @param _key Access key for the address (e.g. "MCD_VAT")
        @param _val The address associated with the _key
    */
    function setChangelogAddress(bytes32 _key, address _val) internal {
        ChainlogLike(log()).setAddress(_key, _val);
    }

    /**
        @dev Set version in the MCD on-chain changelog.
        @param _version Changelog version (e.g. "1.1.2")
    */
    function setChangelogVersion(string memory _version) internal {
        ChainlogLike(log()).setVersion(_version);
    }
    /**
        @dev Set IPFS hash of IPFS changelog in MCD on-chain changelog.
        @param _ipfsHash IPFS hash (e.g. "QmefQMseb3AiTapiAKKexdKHig8wroKuZbmLtPLv4u2YwW")
    */
    function setChangelogIPFS(string memory _ipfsHash) internal {
        ChainlogLike(log()).setIPFS(_ipfsHash);
    }
    /**
        @dev Set SHA256 hash in MCD on-chain changelog.
        @param _SHA256Sum SHA256 hash (e.g. "e42dc9d043a57705f3f097099e6b2de4230bca9a020c797508da079f9079e35b")
    */
    function setChangelogSHA256(string memory _SHA256Sum) internal {
        ChainlogLike(log()).setSha256sum(_SHA256Sum);
    }


    /**********************/
    /*** Authorizations ***/
    /**********************/
    /**
        @dev Give an address authorization to perform auth actions on the contract.
        @param _base   The address of the contract where the authorization will be set
        @param _ward   Address to be authorized
    */
    function authorize(address _base, address _ward) internal {
        Authorizable(_base).rely(_ward);
    }
    /**
        @dev Revoke contract authorization from an address.
        @param _base   The address of the contract where the authorization will be revoked
        @param _ward   Address to be deauthorized
    */
    function deauthorize(address _base, address _ward) internal {
        Authorizable(_base).deny(_ward);
    }
    /**
        @dev Delegate vat authority to the specified address.
        @param _usr Address to be authorized
    */
    function delegateVat(address _usr) internal {
        DssVat(vat()).hope(_usr);
    }
    /**
        @dev Revoke vat authority to the specified address.
        @param _usr Address to be deauthorized
    */
    function undelegateVat(address _usr) internal {
        DssVat(vat()).nope(_usr);
    }

    /******************************/
    /*** OfficeHours Management ***/
    /******************************/

    /**
        @dev Returns true if a time is within office hours range
        @param _ts           The timestamp to check, usually block.timestamp
        @param _officeHours  true if office hours is enabled.
        @return              true if time is in castable range
    */
    function canCast(uint40 _ts, bool _officeHours) internal pure returns (bool) {
        if (_officeHours) {
            uint256 day = (_ts / 1 days + 3) % 7;
            if (day >= 5)                 { return false; }  // Can only be cast on a weekday
            uint256 hour = _ts / 1 hours % 24;
            if (hour < 14 || hour >= 21)  { return false; }  // Outside office hours
        }
        return true;
    }

    /**
        @dev Calculate the next available cast time in epoch seconds
        @param _eta          The scheduled time of the spell plus the pause delay
        @param _ts           The current timestamp, usually block.timestamp
        @param _officeHours  true if office hours is enabled.
        @return castTime     The next available cast timestamp
    */
    function nextCastTime(uint40 _eta, uint40 _ts, bool _officeHours) internal pure returns (uint256 castTime) {
        require(_eta != 0);  // "DssExecLib/invalid eta"
        require(_ts  != 0);  // "DssExecLib/invalid ts"
        castTime = _ts > _eta ? _ts : _eta; // Any day at XX:YY

        if (_officeHours) {
            uint256 day    = (castTime / 1 days + 3) % 7;
            uint256 hour   = castTime / 1 hours % 24;
            uint256 minute = castTime / 1 minutes % 60;
            uint256 second = castTime % 60;

            if (day >= 5) {
                castTime += (6 - day) * 1 days;                 // Go to Sunday XX:YY
                castTime += (24 - hour + 14) * 1 hours;         // Go to 14:YY UTC Monday
                castTime -= minute * 1 minutes + second;        // Go to 14:00 UTC
            } else {
                if (hour >= 21) {
                    if (day == 4) castTime += 2 days;           // If Friday, fast forward to Sunday XX:YY
                    castTime += (24 - hour + 14) * 1 hours;     // Go to 14:YY UTC next day
                    castTime -= minute * 1 minutes + second;    // Go to 14:00 UTC
                } else if (hour < 14) {
                    castTime += (14 - hour) * 1 hours;          // Go to 14:YY UTC same day
                    castTime -= minute * 1 minutes + second;    // Go to 14:00 UTC
                }
            }
        }
    }

    /**************************/
    /*** Accumulating Rates ***/
    /**************************/
    /**
        @dev Update rate accumulation for the Dai Savings Rate (DSR).
    */
    function accumulateDSR() internal {
        Drippable(pot()).drip();
    }
    /**
        @dev Update rate accumulation for the stability fees of a given collateral type.
        @param _ilk   Collateral type
    */
    function accumulateCollateralStabilityFees(bytes32 _ilk) internal {
        Drippable(jug()).drip(_ilk);
    }

    /*********************/
    /*** Price Updates ***/
    /*********************/
    /**
        @dev Update price of a given collateral type.
        @param _ilk   Collateral type
    */
    function updateCollateralPrice(bytes32 _ilk) internal {
        Pricing(spotter()).poke(_ilk);
    }

    /****************************/
    /*** System Configuration ***/
    /****************************/
    /**
        @dev Set a contract in another contract, defining the relationship (ex. set a new Calc contract in Clip)
        @param _base   The address of the contract where the new contract address will be filed
        @param _what   Name of contract to file
        @param _addr   Address of contract to file
    */
    function setContract(address _base, bytes32 _what, address _addr) internal {
        Fileable(_base).file(_what, _addr);
    }
    /**
        @dev Set a contract in another contract, defining the relationship (ex. set a new Calc contract in a Clip)
        @param _base   The address of the contract where the new contract address will be filed
        @param _ilk    Collateral type
        @param _what   Name of contract to file
        @param _addr   Address of contract to file
    */
    function setContract(address _base, bytes32 _ilk, bytes32 _what, address _addr) internal {
        Fileable(_base).file(_ilk, _what, _addr);
    }
    /**
        @dev Set a value in a contract, via a governance authorized File pattern.
        @param _base   The address of the contract where the new contract address will be filed
        @param _what   Name of tag for the value (e.x. "Line")
        @param _amt    The value to set or update
    */
    function setValue(address _base, bytes32 _what, uint256 _amt) internal {
        Fileable(_base).file(_what, _amt);
    }
    /**
        @dev Set an ilk-specific value in a contract, via a governance authorized File pattern.
        @param _base   The address of the contract where the new value will be filed
        @param _ilk    Collateral type
        @param _what   Name of tag for the value (e.x. "Line")
        @param _amt    The value to set or update
    */
    function setValue(address _base, bytes32 _ilk, bytes32 _what, uint256 _amt) internal {
        Fileable(_base).file(_ilk, _what, _amt);
    }

    /******************************/
    /*** System Risk Parameters ***/
    /******************************/
    // function setGlobalDebtCeiling(uint256 _amount) public { setGlobalDebtCeiling(vat(), _amount); }
    /**
        @dev Set the global debt ceiling. Amount will be converted to the correct internal precision.
        @param _amount The amount to set in DAI (ex. 10m DAI amount == 10000000)
    */
    function setGlobalDebtCeiling(uint256 _amount) internal {
        require(_amount < WAD);  // "LibDssExec/incorrect-global-Line-precision"
        setValue(vat(), "Line", _amount * RAD);
    }
    /**
        @dev Increase the global debt ceiling by a specific amount. Amount will be converted to the correct internal precision.
        @param _amount The amount to add in DAI (ex. 10m DAI amount == 10000000)
    */
    function increaseGlobalDebtCeiling(uint256 _amount) internal {
        require(_amount < WAD);  // "LibDssExec/incorrect-Line-increase-precision"
        address _vat = vat();
        setValue(_vat, "Line", _add(DssVat(_vat).Line(), _amount * RAD));
    }
    /**
        @dev Decrease the global debt ceiling by a specific amount. Amount will be converted to the correct internal precision.
        @param _amount The amount to reduce in DAI (ex. 10m DAI amount == 10000000)
    */
    function decreaseGlobalDebtCeiling(uint256 _amount) internal {
        require(_amount < WAD);  // "LibDssExec/incorrect-Line-decrease-precision"
        address _vat = vat();
        setValue(_vat, "Line", _sub(DssVat(_vat).Line(), _amount * RAD));
    }
    /**
        @dev Set the Dai Savings Rate. See: docs/rates.txt
        @param _rate   The accumulated rate (ex. 4% => 1000000001243680656318820312)
        @param _doDrip `true` to accumulate interest owed
    */
    function setDSR(uint256 _rate, bool _doDrip) internal {
        require((_rate >= RAY) && (_rate <= RATES_ONE_HUNDRED_PCT));  // "LibDssExec/dsr-out-of-bounds"
        if (_doDrip) Drippable(pot()).drip();
        setValue(pot(), "dsr", _rate);
    }
    /**
        @dev Set the DAI amount for system surplus auctions. Amount will be converted to the correct internal precision.
        @param _amount The amount to set in DAI (ex. 10m DAI amount == 10000000)
    */
    function setSurplusAuctionAmount(uint256 _amount) internal {
        require(_amount < WAD);  // "LibDssExec/incorrect-vow-bump-precision"
        setValue(vow(), "bump", _amount * RAD);
    }
    /**
        @dev Set the DAI amount for system surplus buffer, must be exceeded before surplus auctions start. Amount will be converted to the correct internal precision.
        @param _amount The amount to set in DAI (ex. 10m DAI amount == 10000000)
    */
    function setSurplusBuffer(uint256 _amount) internal {
        require(_amount < WAD);  // "LibDssExec/incorrect-vow-hump-precision"
        setValue(vow(), "hump", _amount * RAD);
    }
    /**
        @dev Set minimum bid increase for surplus auctions. Amount will be converted to the correct internal precision.
        @dev Equation used for conversion is (1 + pct / 10,000) * WAD
        @param _pct_bps The pct, in basis points, to set in integer form (x100). (ex. 5% = 5 * 100 = 500)
    */
    function setMinSurplusAuctionBidIncrease(uint256 _pct_bps) internal {
        require(_pct_bps < BPS_ONE_HUNDRED_PCT);  // "LibDssExec/incorrect-flap-beg-precision"
        setValue(flap(), "beg", _add(WAD, wdiv(_pct_bps, BPS_ONE_HUNDRED_PCT)));
    }
    /**
        @dev Set bid duration for surplus auctions.
        @param _duration Amount of time for bids. (in seconds)
    */
    function setSurplusAuctionBidDuration(uint256 _duration) internal {
        setValue(flap(), "ttl", _duration);
    }
    /**
        @dev Set total auction duration for surplus auctions.
        @param _duration Amount of time for auctions. (in seconds)
    */
    function setSurplusAuctionDuration(uint256 _duration) internal {
        setValue(flap(), "tau", _duration);
    }
    /**
        @dev Set the number of seconds that pass before system debt is auctioned for MKR tokens.
        @param _duration Duration in seconds
    */
    function setDebtAuctionDelay(uint256 _duration) internal {
        setValue(vow(), "wait", _duration);
    }
    /**
        @dev Set the DAI amount for system debt to be covered by each debt auction. Amount will be converted to the correct internal precision.
        @param _amount The amount to set in DAI (ex. 10m DAI amount == 10000000)
    */
    function setDebtAuctionDAIAmount(uint256 _amount) internal {
        require(_amount < WAD);  // "LibDssExec/incorrect-vow-sump-precision"
        setValue(vow(), "sump", _amount * RAD);
    }
    /**
        @dev Set the starting MKR amount to be auctioned off to cover system debt in debt auctions. Amount will be converted to the correct internal precision.
        @param _amount The amount to set in MKR (ex. 250 MKR amount == 250)
    */
    function setDebtAuctionMKRAmount(uint256 _amount) internal {
        require(_amount < WAD);  // "LibDssExec/incorrect-vow-dump-precision"
        setValue(vow(), "dump", _amount * WAD);
    }
    /**
        @dev Set minimum bid increase for debt auctions. Amount will be converted to the correct internal precision.
        @dev Equation used for conversion is (1 + pct / 10,000) * WAD
        @param _pct_bps    The pct, in basis points, to set in integer form (x100). (ex. 5% = 5 * 100 = 500)
    */
    function setMinDebtAuctionBidIncrease(uint256 _pct_bps) internal {
        require(_pct_bps < BPS_ONE_HUNDRED_PCT);  // "LibDssExec/incorrect-flap-beg-precision"
        setValue(flop(), "beg", _add(WAD, wdiv(_pct_bps, BPS_ONE_HUNDRED_PCT)));
    }
    /**
        @dev Set bid duration for debt auctions.
        @param _duration Amount of time for bids.
    */
    function setDebtAuctionBidDuration(uint256 _duration) internal {
        setValue(flop(), "ttl", _duration);
    }
    /**
        @dev Set total auction duration for debt auctions.
        @param _duration Amount of time for auctions.
    */
    function setDebtAuctionDuration(uint256 _duration) internal {
        setValue(flop(), "tau", _duration);
    }
    /**
        @dev Set the rate of increasing amount of MKR out for auction during debt auctions. Amount will be converted to the correct internal precision.
        @dev MKR amount is increased by this rate every "tick" (if auction duration has passed and no one has bid on the MKR)
        @dev Equation used for conversion is (1 + pct / 10,000) * WAD
        @param _pct_bps    The pct, in basis points, to set in integer form (x100). (ex. 5% = 5 * 100 = 500)
    */
    function setDebtAuctionMKRIncreaseRate(uint256 _pct_bps) internal {
        setValue(flop(), "pad", _add(WAD, wdiv(_pct_bps, BPS_ONE_HUNDRED_PCT)));
    }
    /**
        @dev Set the maximum total DAI amount that can be out for liquidation in the system at any point. Amount will be converted to the correct internal precision.
        @param _amount The amount to set in DAI (ex. 250,000 DAI amount == 250000)
    */
    function setMaxTotalDAILiquidationAmount(uint256 _amount) internal {
        require(_amount < WAD);  // "LibDssExec/incorrect-dog-Hole-precision"
        setValue(dog(), "Hole", _amount * RAD);
    }
    /**
        @dev (LIQ 1.2) Set the maximum total DAI amount that can be out for liquidation in the system at any point. Amount will be converted to the correct internal precision.
        @param _amount The amount to set in DAI (ex. 250,000 DAI amount == 250000)
    */
    function setMaxTotalDAILiquidationAmountLEGACY(uint256 _amount) internal {
        require(_amount < WAD);  // "LibDssExec/incorrect-cat-box-amount"
        setValue(cat(), "box", _amount * RAD);
    }
    /**
        @dev Set the duration of time that has to pass during emergency shutdown before collateral can start being claimed by DAI holders.
        @param _duration Time in seconds to set for ES processing time
    */
    function setEmergencyShutdownProcessingTime(uint256 _duration) internal {
        setValue(end(), "wait", _duration);
    }
    /**
        @dev Set the global stability fee (is not typically used, currently is 0).
            Many of the settings that change weekly rely on the rate accumulator
            described at https://docs.makerdao.com/smart-contract-modules/rates-module
            To check this yourself, use the following rate calculation (example 8%):

            $ bc -l <<< 'scale=27; e( l(1.08)/(60 * 60 * 24 * 365) )'

            A table of rates can also be found at:
            https://ipfs.io/ipfs/QmefQMseb3AiTapiAKKexdKHig8wroKuZbmLtPLv4u2YwW
        @param _rate   The accumulated rate (ex. 4% => 1000000001243680656318820312)
    */
    function setGlobalStabilityFee(uint256 _rate) internal {
        require((_rate >= RAY) && (_rate <= RATES_ONE_HUNDRED_PCT));  // "LibDssExec/global-stability-fee-out-of-bounds"
        setValue(jug(), "base", _rate);
    }
    /**
        @dev Set the value of DAI in the reference asset (e.g. $1 per DAI). Value will be converted to the correct internal precision.
        @dev Equation used for conversion is value * RAY / 1000
        @param _value The value to set as integer (x1000) (ex. $1.025 == 1025)
    */
    function setDAIReferenceValue(uint256 _value) internal {
        require(_value < WAD);  // "LibDssExec/incorrect-par-precision"
        setValue(spotter(), "par", rdiv(_value, 1000));
    }

    /*****************************/
    /*** Collateral Management ***/
    /*****************************/
    /**
        @dev Set a collateral debt ceiling. Amount will be converted to the correct internal precision.
        @param _ilk    The ilk to update (ex. bytes32("ETH-A"))
        @param _amount The amount to set in DAI (ex. 10m DAI amount == 10000000)
    */
    function setIlkDebtCeiling(bytes32 _ilk, uint256 _amount) internal {
        require(_amount < WAD);  // "LibDssExec/incorrect-ilk-line-precision"
        setValue(vat(), _ilk, "line", _amount * RAD);
    }
    /**
        @dev Increase a collateral debt ceiling. Amount will be converted to the correct internal precision.
        @param _ilk    The ilk to update (ex. bytes32("ETH-A"))
        @param _amount The amount to increase in DAI (ex. 10m DAI amount == 10000000)
        @param _global If true, increases the global debt ceiling by _amount
    */
    function increaseIlkDebtCeiling(bytes32 _ilk, uint256 _amount, bool _global) internal {
        require(_amount < WAD);  // "LibDssExec/incorrect-ilk-line-precision"
        address _vat = vat();
        (,,,uint256 line_,) = DssVat(_vat).ilks(_ilk);
        setValue(_vat, _ilk, "line", _add(line_, _amount * RAD));
        if (_global) { increaseGlobalDebtCeiling(_amount); }
    }
    /**
        @dev Decrease a collateral debt ceiling. Amount will be converted to the correct internal precision.
        @param _ilk    The ilk to update (ex. bytes32("ETH-A"))
        @param _amount The amount to decrease in DAI (ex. 10m DAI amount == 10000000)
        @param _global If true, decreases the global debt ceiling by _amount
    */
    function decreaseIlkDebtCeiling(bytes32 _ilk, uint256 _amount, bool _global) internal {
        require(_amount < WAD);  // "LibDssExec/incorrect-ilk-line-precision"
        address _vat = vat();
        (,,,uint256 line_,) = DssVat(_vat).ilks(_ilk);
        setValue(_vat, _ilk, "line", _sub(line_, _amount * RAD));
        if (_global) { decreaseGlobalDebtCeiling(_amount); }
    }
    /**
        @dev Set the parameters for an ilk in the "MCD_IAM_AUTO_LINE" auto-line
        @param _ilk    The ilk to update (ex. bytes32("ETH-A"))
        @param _amount The Maximum value (ex. 100m DAI amount == 100000000)
        @param _gap    The amount of Dai per step (ex. 5m Dai == 5000000)
        @param _ttl    The amount of time (in seconds)
    */
    function setIlkAutoLineParameters(bytes32 _ilk, uint256 _amount, uint256 _gap, uint256 _ttl) internal {
        require(_amount < WAD);  // "LibDssExec/incorrect-auto-line-amount-precision"
        require(_gap < WAD);  // "LibDssExec/incorrect-auto-line-gap-precision"
        IAMLike(autoLine()).setIlk(_ilk, _amount * RAD, _gap * RAD, _ttl);
    }
    /**
        @dev Set the debt ceiling for an ilk in the "MCD_IAM_AUTO_LINE" auto-line without updating the time values
        @param _ilk    The ilk to update (ex. bytes32("ETH-A"))
        @param _amount The Maximum value (ex. 100m DAI amount == 100000000)
    */
    function setIlkAutoLineDebtCeiling(bytes32 _ilk, uint256 _amount) internal {
        address _autoLine = autoLine();
        (, uint256 gap, uint48 ttl,,) = IAMLike(_autoLine).ilks(_ilk);
        require(gap != 0 && ttl != 0);  // "LibDssExec/auto-line-not-configured"
        IAMLike(_autoLine).setIlk(_ilk, _amount * RAD, uint256(gap), uint256(ttl));
    }
    /**
        @dev Remove an ilk in the "MCD_IAM_AUTO_LINE" auto-line
        @param _ilk    The ilk to remove (ex. bytes32("ETH-A"))
    */
    function removeIlkFromAutoLine(bytes32 _ilk) internal {
        IAMLike(autoLine()).remIlk(_ilk);
    }
    /**
        @dev Set a collateral minimum vault amount. Amount will be converted to the correct internal precision.
        @param _ilk    The ilk to update (ex. bytes32("ETH-A"))
        @param _amount The amount to set in DAI (ex. 10m DAI amount == 10000000)
    */
    function setIlkMinVaultAmount(bytes32 _ilk, uint256 _amount) internal {
        require(_amount < WAD);  // "LibDssExec/incorrect-ilk-dust-precision"
        setValue(vat(), _ilk, "dust", _amount * RAD);
        (bool ok,) = clip(_ilk).call(abi.encodeWithSignature("upchost()")); ok;
    }
    /**
        @dev Set a collateral liquidation penalty. Amount will be converted to the correct internal precision.
        @dev Equation used for conversion is (1 + pct / 10,000) * WAD
        @param _ilk    The ilk to update (ex. bytes32("ETH-A"))
        @param _pct_bps    The pct, in basis points, to set in integer form (x100). (ex. 10.25% = 10.25 * 100 = 1025)
    */
    function setIlkLiquidationPenalty(bytes32 _ilk, uint256 _pct_bps) internal {
        require(_pct_bps < BPS_ONE_HUNDRED_PCT);  // "LibDssExec/incorrect-ilk-chop-precision"
        setValue(dog(), _ilk, "chop", _add(WAD, wdiv(_pct_bps, BPS_ONE_HUNDRED_PCT)));
        (bool ok,) = clip(_ilk).call(abi.encodeWithSignature("upchost()")); ok;
    }
    /**
        @dev Set max DAI amount for liquidation per vault for collateral. Amount will be converted to the correct internal precision.
        @param _ilk    The ilk to update (ex. bytes32("ETH-A"))
        @param _amount The amount to set in DAI (ex. 10m DAI amount == 10000000)
    */
    function setIlkMaxLiquidationAmount(bytes32 _ilk, uint256 _amount) internal {
        require(_amount < WAD);  // "LibDssExec/incorrect-ilk-hole-precision"
        setValue(dog(), _ilk, "hole", _amount * RAD);
    }
    /**
        @dev Set a collateral liquidation ratio. Amount will be converted to the correct internal precision.
        @dev Equation used for conversion is pct * RAY / 10,000
        @param _ilk    The ilk to update (ex. bytes32("ETH-A"))
        @param _pct_bps    The pct, in basis points, to set in integer form (x100). (ex. 150% = 150 * 100 = 15000)
    */
    function setIlkLiquidationRatio(bytes32 _ilk, uint256 _pct_bps) internal {
        require(_pct_bps < 10 * BPS_ONE_HUNDRED_PCT); // "LibDssExec/incorrect-ilk-mat-precision" // Fails if pct >= 1000%
        require(_pct_bps >= BPS_ONE_HUNDRED_PCT); // the liquidation ratio has to be bigger or equal to 100%
        setValue(spotter(), _ilk, "mat", rdiv(_pct_bps, BPS_ONE_HUNDRED_PCT));
    }
    /**
        @dev Set an auction starting multiplier. Amount will be converted to the correct internal precision.
        @dev Equation used for conversion is pct * RAY / 10,000
        @param _ilk      The ilk to update (ex. bytes32("ETH-A"))
        @param _pct_bps  The pct, in basis points, to set in integer form (x100). (ex. 1.3x starting multiplier = 130% = 13000)
    */
    function setStartingPriceMultiplicativeFactor(bytes32 _ilk, uint256 _pct_bps) internal {
        require(_pct_bps < 10 * BPS_ONE_HUNDRED_PCT); // "LibDssExec/incorrect-ilk-mat-precision" // Fails if gt 10x
        require(_pct_bps >= BPS_ONE_HUNDRED_PCT); // fail if start price is less than OSM price
        setValue(clip(_ilk), "buf", rdiv(_pct_bps, BPS_ONE_HUNDRED_PCT));
    }

    /**
        @dev Set the amout of time before an auction resets.
        @param _ilk      The ilk to update (ex. bytes32("ETH-A"))
        @param _duration Amount of time before auction resets (in seconds).
    */
    function setAuctionTimeBeforeReset(bytes32 _ilk, uint256 _duration) internal {
        setValue(clip(_ilk), "tail", _duration);
    }

    /**
        @dev Percentage drop permitted before auction reset
        @param _ilk     The ilk to update (ex. bytes32("ETH-A"))
        @param _pct_bps The pct, in basis points, of drop to permit (x100).
    */
    function setAuctionPermittedDrop(bytes32 _ilk, uint256 _pct_bps) internal {
        require(_pct_bps < BPS_ONE_HUNDRED_PCT); // "LibDssExec/incorrect-clip-cusp-value"
        setValue(clip(_ilk), "cusp", rdiv(_pct_bps, BPS_ONE_HUNDRED_PCT));
    }

    /**
        @dev Percentage of tab to suck from vow to incentivize keepers. Amount will be converted to the correct internal precision.
        @param _ilk     The ilk to update (ex. bytes32("ETH-A"))
        @param _pct_bps The pct, in basis points, of the tab to suck. (0.01% == 1)
    */
    function setKeeperIncentivePercent(bytes32 _ilk, uint256 _pct_bps) internal {
        require(_pct_bps < BPS_ONE_HUNDRED_PCT); // "LibDssExec/incorrect-clip-chip-precision"
        setValue(clip(_ilk), "chip", wdiv(_pct_bps, BPS_ONE_HUNDRED_PCT));
    }

    /**
        @dev Set max DAI amount for flat rate keeper incentive. Amount will be converted to the correct internal precision.
        @param _ilk    The ilk to update (ex. bytes32("ETH-A"))
        @param _amount The amount to set in DAI (ex. 1000 DAI amount == 1000)
    */
    function setKeeperIncentiveFlatRate(bytes32 _ilk, uint256 _amount) internal {
        require(_amount < WAD); // "LibDssExec/incorrect-clip-tip-precision"
        setValue(clip(_ilk), "tip", _amount * RAD);
    }

    /**
        @dev Sets the circuit breaker price tolerance in the clipper mom.
            This is somewhat counter-intuitive,
             to accept a 25% price drop, use a value of 75%
        @param _clip    The clipper to set the tolerance for
        @param _pct_bps The pct, in basis points, to set in integer form (x100). (ex. 5% = 5 * 100 = 500)
    */
    function setLiquidationBreakerPriceTolerance(address _clip, uint256 _pct_bps) internal {
        require(_pct_bps < BPS_ONE_HUNDRED_PCT);  // "LibDssExec/incorrect-clippermom-price-tolerance"
        MomLike(clipperMom()).setPriceTolerance(_clip, rdiv(_pct_bps, BPS_ONE_HUNDRED_PCT));
    }

    /**
        @dev Set the stability fee for a given ilk.
            Many of the settings that change weekly rely on the rate accumulator
            described at https://docs.makerdao.com/smart-contract-modules/rates-module
            To check this yourself, use the following rate calculation (example 8%):

            $ bc -l <<< 'scale=27; e( l(1.08)/(60 * 60 * 24 * 365) )'

            A table of rates can also be found at:
            https://ipfs.io/ipfs/QmefQMseb3AiTapiAKKexdKHig8wroKuZbmLtPLv4u2YwW

        @param _ilk    The ilk to update (ex. bytes32("ETH-A") )
        @param _rate   The accumulated rate (ex. 4% => 1000000001243680656318820312)
        @param _doDrip `true` to accumulate stability fees for the collateral
    */
    function setIlkStabilityFee(bytes32 _ilk, uint256 _rate, bool _doDrip) internal {
        require((_rate >= RAY) && (_rate <= RATES_ONE_HUNDRED_PCT));  // "LibDssExec/ilk-stability-fee-out-of-bounds"
        address _jug = jug();
        if (_doDrip) Drippable(_jug).drip(_ilk);

        setValue(_jug, _ilk, "duty", _rate);
    }


    /*************************/
    /*** Abacus Management ***/
    /*************************/

    /**
        @dev Set the number of seconds from the start when the auction reaches zero price.
        @dev Abacus:LinearDecrease only.
        @param _calc     The address of the LinearDecrease pricing contract
        @param _duration Amount of time for auctions.
    */
    function setLinearDecrease(address _calc, uint256 _duration) internal {
        setValue(_calc, "tau", _duration);
    }

    /**
        @dev Set the number of seconds for each price step.
        @dev Abacus:StairstepExponentialDecrease only.
        @param _calc     The address of the StairstepExponentialDecrease pricing contract
        @param _duration Length of time between price drops [seconds]
        @param _pct_bps Per-step multiplicative factor in basis points. (ex. 99% == 9900)
    */
    function setStairstepExponentialDecrease(address _calc, uint256 _duration, uint256 _pct_bps) internal {
        require(_pct_bps < BPS_ONE_HUNDRED_PCT); // DssExecLib/cut-too-high
        setValue(_calc, "cut", rdiv(_pct_bps, BPS_ONE_HUNDRED_PCT));
        setValue(_calc, "step", _duration);
    }
    /**
        @dev Set the number of seconds for each price step. (99% cut = 1% price drop per step)
             Amounts will be converted to the correct internal precision.
        @dev Abacus:ExponentialDecrease only
        @param _calc     The address of the ExponentialDecrease pricing contract
        @param _pct_bps Per-step multiplicative factor in basis points. (ex. 99% == 9900)
    */
    function setExponentialDecrease(address _calc, uint256 _pct_bps) internal {
        require(_pct_bps < BPS_ONE_HUNDRED_PCT); // DssExecLib/cut-too-high
        setValue(_calc, "cut", rdiv(_pct_bps, BPS_ONE_HUNDRED_PCT));
    }

    /*************************/
    /*** Oracle Management ***/
    /*************************/
    /**
        @dev Allows an oracle to read prices from its source feeds
        @param _oracle  An OSM or LP oracle contract
    */
    /*
    function whitelistOracleMedians(address _oracle) public {
        (bool ok, bytes memory data) = _oracle.call(abi.encodeWithSignature("orb0()"));
        if (ok) {
            // Token is an LP oracle
            address median0 = abi.decode(data, (address));
            addReaderToWhitelistCall(median0, _oracle);
            addReaderToWhitelistCall(OracleLike(_oracle).orb1(), _oracle);
        } else {
            // Standard OSM
            addReaderToWhitelistCall(OracleLike(_oracle).src(), _oracle);
        }
    }
    */
    /**
        @dev Adds an address to the OSM or Median's reader whitelist, allowing the address to read prices.
        @param _oracle        Oracle Security Module (OSM) or Median core contract address
        @param _reader     Address to add to whitelist
    */
    /*
    function addReaderToWhitelist(address _oracle, address _reader) public {
        OracleLike(_oracle).kiss(_reader);
    }
    */
    /**
        @dev Removes an address to the OSM or Median's reader whitelist, disallowing the address to read prices.
        @param _oracle     Oracle Security Module (OSM) or Median core contract address
        @param _reader     Address to remove from whitelist
    */
    /*
    function removeReaderFromWhitelist(address _oracle, address _reader) public {
        OracleLike(_oracle).diss(_reader);
    }
    */
    /**
        @dev Adds an address to the OSM or Median's reader whitelist, allowing the address to read prices.
        @param _oracle  OSM or Median core contract address
        @param _reader  Address to add to whitelist
    */
    function addReaderToWhitelistCall(address _oracle, address _reader) internal {
        (bool ok,) = _oracle.call(abi.encodeWithSignature("kiss(address)", _reader)); ok;
    }
    /**
        @dev Removes an address to the OSM or Median's reader whitelist, disallowing the address to read prices.
        @param _oracle  Oracle Security Module (OSM) or Median core contract address
        @param _reader  Address to remove from whitelist
    */
    function removeReaderFromWhitelistCall(address _oracle, address _reader) internal {
        (bool ok,) = _oracle.call(abi.encodeWithSignature("diss(address)", _reader)); ok;
    }
    /**
        @dev Sets the minimum number of valid messages from whitelisted oracle feeds needed to update median price.
        @param _median     Median core contract address
        @param _minQuorum  Minimum number of valid messages from whitelisted oracle feeds needed to update median price (NOTE: MUST BE ODD NUMBER)
    */
    /*
    function setMedianWritersQuorum(address _median, uint256 _minQuorum) public {
        OracleLike(_median).setBar(_minQuorum);
    }
    */
    /**
        @dev Add OSM address to OSM mom, allowing it to be frozen by governance.
        @param _osm        Oracle Security Module (OSM) core contract address
        @param _ilk        Collateral type using OSM
    */
    function allowOSMFreeze(address _osm, bytes32 _ilk) internal {
        MomLike(osmMom()).setOsm(_ilk, _osm);
    }


    /*****************************/
    /*** Collateral Onboarding ***/
    /*****************************/

    /**
        @dev Performs basic functions and sanity checks to add a new collateral type to the MCD system
        @param _ilk      Collateral type key code [Ex. "ETH-A"]
        @param _gem      Address of token contract
        @param _join     Address of join adapter
        @param _clip     Address of liquidation agent
        @param _calc     Address of the pricing function
        @param _pip      Address of price feed
    */
    function addCollateralBase(
        bytes32 _ilk,
        address _gem,
        address _join,
        address _clip,
        address _calc,
        address _pip
    ) internal {
        // Sanity checks
        address _vat = vat();
        address _dog = dog();
        address _spotter = spotter();
        require(JoinLike(_join).vat() == _vat);     // "join-vat-not-match"
        require(JoinLike(_join).ilk() == _ilk);     // "join-ilk-not-match"
        require(JoinLike(_join).gem() == _gem);     // "join-gem-not-match"
        require(JoinLike(_join).dec() ==
                   ERC20(_gem).decimals());         // "join-dec-not-match"
        require(ClipLike(_clip).vat() == _vat);     // "clip-vat-not-match"
        require(ClipLike(_clip).dog() == _dog);     // "clip-dog-not-match"
        require(ClipLike(_clip).ilk() == _ilk);     // "clip-ilk-not-match"
        require(ClipLike(_clip).spotter() == _spotter);  // "clip-ilk-not-match"

        // Set the token PIP in the Spotter
        setContract(spotter(), _ilk, "pip", _pip);

        // Set the ilk Clipper in the Dog
        setContract(_dog, _ilk, "clip", _clip);
        // Set vow in the clip
        setContract(_clip, "vow", vow());
        // Set the pricing function for the Clipper
        setContract(_clip, "calc", _calc);

        // Init ilk in Vat & Jug
        Initializable(_vat).init(_ilk);  // Vat
        Initializable(jug()).init(_ilk);  // Jug

        // Allow ilk Join to modify Vat registry
        authorize(_vat, _join);
        // Allow ilk Join to suck dai for keepers
        authorize(_vat, _clip);
        // Allow the ilk Clipper to reduce the Dog hole on deal()
        authorize(_dog, _clip);
        // Allow Dog to kick auctions in ilk Clipper
        authorize(_clip, _dog);
        // Allow End to yank auctions in ilk Clipper
        authorize(_clip, end());
        // Authorize the ESM to execute in the clipper
        authorize(_clip, esm());

        // Add new ilk to the IlkRegistry
        RegistryLike(reg()).add(_join);
    }

    // Complete collateral onboarding logic.
    function addNewCollateral(CollateralOpts memory co) internal {
        // Add the collateral to the system.
        addCollateralBase(co.ilk, co.gem, co.join, co.clip, co.calc, co.pip);
        address clipperMom_ = clipperMom();

        if (!co.isLiquidatable) {
            // Disallow Dog to kick auctions in ilk Clipper
            setValue(co.clip, "stopped", 3);
        } else {
            // Grant ClipperMom access to the ilk Clipper
            authorize(co.clip, clipperMom_);
        }

        if(co.isOSM) { // If pip == OSM
            require(false, "unsupported");
/*
            // Allow OsmMom to access to the TOKEN OSM
            authorize(co.pip, osmMom());
            if (co.whitelistOSM) { // If median is src in OSM
                // Whitelist OSM to read the Median data (only necessary if it is the first time the token is being added to an ilk)
                whitelistOracleMedians(co.pip);
            }
            // Whitelist Spotter to read the OSM data (only necessary if it is the first time the token is being added to an ilk)
            addReaderToWhitelist(co.pip, spotter());
            // Whitelist Clipper on pip
            addReaderToWhitelist(co.pip, co.clip);
            // Allow the clippermom to access the feed
            addReaderToWhitelist(co.pip, clipperMom_);
            // Whitelist End to read the OSM data (only necessary if it is the first time the token is being added to an ilk)
            addReaderToWhitelist(co.pip, end());
            // Set TOKEN OSM in the OsmMom for new ilk
            allowOSMFreeze(co.pip, co.ilk);
*/
        }
        // Increase the global debt ceiling by the ilk ceiling
        increaseGlobalDebtCeiling(co.ilkDebtCeiling);
        // Set the ilk debt ceiling
        setIlkDebtCeiling(co.ilk, co.ilkDebtCeiling);
        // Set the ilk dust
        setIlkMinVaultAmount(co.ilk, co.minVaultAmount);
        // Set the hole size
        setIlkMaxLiquidationAmount(co.ilk, co.maxLiquidationAmount);
        // Set the ilk liquidation penalty
        setIlkLiquidationPenalty(co.ilk, co.liquidationPenalty);

        // Set the ilk stability fee
        setIlkStabilityFee(co.ilk, co.ilkStabilityFee, true);

        // Set the auction starting price multiplier
        setStartingPriceMultiplicativeFactor(co.ilk, co.startingPriceFactor);

        // Set the amount of time before an auction resets.
        setAuctionTimeBeforeReset(co.ilk, co.auctionDuration);

        // Set the allowed auction drop percentage before reset
        setAuctionPermittedDrop(co.ilk, co.permittedDrop);

        // Set the ilk min collateralization ratio
        setIlkLiquidationRatio(co.ilk, co.liquidationRatio);

        // Set the price tolerance in the liquidation circuit breaker
        setLiquidationBreakerPriceTolerance(co.clip, co.breakerTolerance);

        // Set a flat rate for the keeper reward
        setKeeperIncentiveFlatRate(co.ilk, co.kprFlatReward);

        // Set the percentage of liquidation as keeper award
        setKeeperIncentivePercent(co.ilk, co.kprPctReward);

        // Update ilk spot value in Vat
        updateCollateralPrice(co.ilk);
    }

    /***************/
    /*** Payment ***/
    /***************/
    /**
        @dev Send a payment in ERC20 DAI from the surplus buffer.
        @param _target The target address to send the DAI to.
        @param _amount The amount to send in DAI (ex. 10m DAI amount == 10000000)
    */
    function sendPaymentFromSurplusBuffer(address _target, uint256 _amount) internal {
        require(_amount < WAD);  // "LibDssExec/incorrect-ilk-line-precision"
        DssVat(vat()).suck(vow(), address(this), _amount * RAD);
        JoinLike(daiJoin()).exit(_target, _amount * WAD);
    }

    /************/
    /*** Misc ***/
    /************/
    /**
        @dev Initiate linear interpolation on an administrative value over time.
        @param _name        The label for this lerp instance
        @param _target      The target contract
        @param _what        The target parameter to adjust
        @param _startTime   The time for this lerp
        @param _start       The start value for the target parameter
        @param _end         The end value for the target parameter
        @param _duration    The duration of the interpolation
    */
    function linearInterpolation(bytes32 _name, address _target, bytes32 _what, uint256 _startTime, uint256 _start, uint256 _end, uint256 _duration) internal returns (address) {
        address lerp = LerpFactoryLike(lerpFab()).newLerp(_name, _target, _what, _startTime, _start, _end, _duration);
        Authorizable(_target).rely(lerp);
        LerpLike(lerp).tick();
        return lerp;
    }
    /**
        @dev Initiate linear interpolation on an administrative value over time.
        @param _name        The label for this lerp instance
        @param _target      The target contract
        @param _ilk         The ilk to target
        @param _what        The target parameter to adjust
        @param _startTime   The time for this lerp
        @param _start       The start value for the target parameter
        @param _end         The end value for the target parameter
        @param _duration    The duration of the interpolation
    */
    function linearInterpolation(bytes32 _name, address _target, bytes32 _ilk, bytes32 _what, uint256 _startTime, uint256 _start, uint256 _end, uint256 _duration) internal returns (address) {
        address lerp = LerpFactoryLike(lerpFab()).newIlkLerp(_name, _target, _ilk, _what, _startTime, _start, _end, _duration);
        Authorizable(_target).rely(lerp);
        LerpLike(lerp).tick();
        return lerp;
    }
}

// File: contracts/dss-exec-lib/DssAction.sol

//
// DssAction.sol -- DSS Executive Spell Actions
//
// Copyright (C) 2020 Maker Ecosystem Growth Holdings, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

pragma solidity ^0.6.12;


abstract contract DssAction {

    using DssExecLib for *;

    // Modifier used to limit execution time when office hours is enabled
    modifier limited {
        require(DssExecLib.canCast(uint40(block.timestamp), officeHours()), "Outside office hours");
        _;
    }

    // Office Hours defaults to true by default.
    //   To disable office hours, override this function and
    //    return false in the inherited action.
    function officeHours() public virtual pure returns (bool) {
        return true;
    }

    // DssExec calls execute. We limit this function subject to officeHours modifier.
    function execute() external limited {
        actions();
    }

    // DssAction developer must override `actions()` and place all actions to be called inside.
    //   The DssExec function will call this subject to the officeHours limiter
    //   By keeping this function public we allow simulations of `execute()` on the actions outside of the cast time.
    function actions() public virtual;

    // Provides a descriptive tag for bot consumption
    // This should be modified weekly to provide a summary of the actions
    // Hash: seth keccak -- "$(wget https://<executive-vote-canonical-post> -q -O - 2>/dev/null)"
    function description() external virtual view returns (string memory);

    // Returns the next available cast time
    function nextCastTime(uint256 eta) external view returns (uint256 castTime) {
        require(eta <= uint40(-1));
        castTime = DssExecLib.nextCastTime(uint40(eta), uint40(block.timestamp), officeHours());
    }
}

// File: contracts/ds-note/note.sol

/// note.sol -- the `note' modifier, for logging calls as events

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity >=0.4.23;

contract DSNote {
    event LogNote(
        bytes4   indexed  sig,
        address  indexed  guy,
        bytes32  indexed  foo,
        bytes32  indexed  bar,
        uint256           wad,
        bytes             fax
    ) anonymous;

    modifier note {
        bytes32 foo;
        bytes32 bar;
        uint256 wad;

        assembly {
            foo := calldataload(4)
            bar := calldataload(36)
            wad := callvalue()
        }

        _;

        emit LogNote(msg.sig, msg.sender, foo, bar, wad, msg.data);
    }
}

// File: contracts/ds-auth/auth.sol

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity >=0.4.23;

interface DSAuthority {
    function canCall(
        address src, address dst, bytes4 sig
    ) external view returns (bool);
}

contract DSAuthEvents {
    event LogSetAuthority (address indexed authority);
    event LogSetOwner     (address indexed owner);
}

contract DSAuth is DSAuthEvents {
    DSAuthority  public  authority;
    address      public  owner;

    constructor() public {
        owner = msg.sender;
        emit LogSetOwner(msg.sender);
    }

    function setOwner(address owner_)
        public
        virtual
        auth
    {
        owner = owner_;
        emit LogSetOwner(owner);
    }

    function setAuthority(DSAuthority authority_)
        public
        virtual
        auth
    {
        authority = authority_;
        emit LogSetAuthority(address(authority));
    }

    modifier auth {
        require(isAuthorized(msg.sender, msg.sig), "ds-auth-unauthorized");
        _;
    }

    function isAuthorized(address src, bytes4 sig) internal view returns (bool) {
        if (src == address(this)) {
            return true;
        } else if (src == owner) {
            return true;
        } else if (authority == DSAuthority(address(0))) {
            return false;
        } else {
            return authority.canCall(src, address(this), sig);
        }
    }
}

// File: contracts/ds-pause/pause.sol

// Copyright (C) 2019 David Terry <[email protected]>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

pragma solidity >=0.4.23;



contract DSPause is DSAuth, DSNote {

    // --- admin ---

    modifier wait { require(msg.sender == address(proxy), "ds-pause-undelayed-call"); _; }

    function setOwner(address owner_) public override wait {
        owner = owner_;
        emit LogSetOwner(owner);
    }
    function setAuthority(DSAuthority authority_) public override wait {
        authority = authority_;
        emit LogSetAuthority(address(authority));
    }
    function setDelay(uint delay_) public note wait {
        delay = delay_;
    }

    // --- math ---

    function _add(uint x, uint y) internal pure returns (uint z) {
        z = x + y;
        require(z >= x, "ds-pause-addition-overflow");
    }

    // --- data ---

    mapping (bytes32 => bool) public plans;
    DSPauseProxy public proxy;
    uint         public delay;

    // --- init ---

    constructor(uint delay_, address owner_, DSAuthority authority_) public {
        delay = delay_;
        owner = owner_;
        authority = authority_;
        proxy = new DSPauseProxy();
    }

    // --- util ---

    function hash(address usr, bytes32 tag, bytes memory fax, uint eta)
        internal pure
        returns (bytes32)
    {
        return keccak256(abi.encode(usr, tag, fax, eta));
    }

    function soul(address usr)
        internal view
        returns (bytes32 tag)
    {
        assembly { tag := extcodehash(usr) }
    }

    // --- operations ---

    function plot(address usr, bytes32 tag, bytes memory fax, uint eta)
        public note auth
    {
        require(eta >= _add(now, delay), "ds-pause-delay-not-respected");
        plans[hash(usr, tag, fax, eta)] = true;
    }

    function drop(address usr, bytes32 tag, bytes memory fax, uint eta)
        public note auth
    {
        plans[hash(usr, tag, fax, eta)] = false;
    }

    function exec(address usr, bytes32 tag, bytes memory fax, uint eta)
        public note
        returns (bytes memory out)
    {
        require(plans[hash(usr, tag, fax, eta)], "ds-pause-unplotted-plan");
        require(soul(usr) == tag,                "ds-pause-wrong-codehash");
        require(now >= eta,                      "ds-pause-premature-exec");

        plans[hash(usr, tag, fax, eta)] = false;

        out = proxy.exec(usr, fax);
        require(proxy.owner() == address(this), "ds-pause-illegal-storage-change");
    }
}

// plans are executed in an isolated storage context to protect the pause from
// malicious storage modification during plan execution
contract DSPauseProxy {
    address public owner;
    modifier auth { require(msg.sender == owner, "ds-pause-proxy-unauthorized"); _; }
    constructor() public { owner = msg.sender; }

    function exec(address usr, bytes memory fax)
        public auth
        returns (bytes memory out)
    {
        bool ok;
        (ok, out) = usr.delegatecall(fax);
        require(ok, "ds-pause-delegatecall-error");
    }
}

// File: contracts/dss-chain-log/ChainLog.sol

/// ChainLog.sol - An on-chain governance-managed contract registry

// Copyright (C) 2020 Maker Ecosystem Growth Holdings, INC.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

pragma solidity ^0.6.7;

/// @title An on-chain governance-managed contract registry
/// @notice Publicly readable data; mutating functions must be called by an authorized user
contract ChainLog {

    event Rely(address usr);
    event Deny(address usr);
    event UpdateVersion(string version);
    event UpdateSha256sum(string sha256sum);
    event UpdateIPFS(string ipfs);
    event UpdateAddress(bytes32 key, address addr);
    event RemoveAddress(bytes32 key);

    // --- Auth ---
    mapping (address => uint) public wards;
    function rely(address usr) external auth { wards[usr] = 1; emit Rely(usr); }
    function deny(address usr) external auth { wards[usr] = 0; emit Deny(usr); }
    modifier auth {
        require(wards[msg.sender] == 1, "ChainLog/not-authorized");
        _;
    }

    struct Location {
        uint256  pos;
        address  addr;
    }
    mapping (bytes32 => Location) location;

    bytes32[] public keys;

    string public version;
    string public sha256sum;
    string public ipfs;

    constructor() public {
        wards[msg.sender] = 1;
        setVersion("0.0.0");
        setAddress("CHANGELOG", address(this));
    }

    /// @notice Set the "version" of the current changelog
    /// @param _version The version string (optional)
    function setVersion(string memory _version) public auth {
        version = _version;
        emit UpdateVersion(_version);
    }

    /// @notice Set the "sha256sum" of some current external changelog
    /// @dev designed to store sha256 of changelog.makerdao.com hosted log
    /// @param _sha256sum The sha256 sum (optional)
    function setSha256sum(string memory _sha256sum) public auth {
        sha256sum = _sha256sum;
        emit UpdateSha256sum(_sha256sum);
    }

    /// @notice Set the IPFS hash of a pinned changelog
    /// @dev designed to store IPFS pin hash that can retreive changelog json
    /// @param _ipfs The ipfs pin hash of an ipfs hosted log (optional)
    function setIPFS(string memory _ipfs) public auth {
        ipfs = _ipfs;
        emit UpdateIPFS(_ipfs);
    }

    /// @notice Set the key-value pair for a changelog item
    /// @param _key  the changelog key (ex. MCD_VAT)
    /// @param _addr the address to the contract
    function setAddress(bytes32 _key, address _addr) public auth {
        if (count() > 0 && _key == keys[location[_key].pos]) {
            location[_key].addr = _addr;   // Key exists in keys (update)
        } else {
            _addAddress(_key, _addr);      // Add key to keys array
        }
        emit UpdateAddress(_key, _addr);
    }

    /// @notice Removes the key from the keys list()
    /// @dev removes the item from the array but moves the last element to it's place
    //   WARNING: To save the expense of shifting an array on-chain,
    //     this will replace the key to be deleted with the last key
    //     in the array, and can therefore result in keys being out
    //     of order. Use this only if you intend to reorder the list(),
    //     otherwise consider using `setAddress("KEY", address(0));`
    /// @param _key the key to be removed
    function removeAddress(bytes32 _key) public auth {
        _removeAddress(_key);
        emit RemoveAddress(_key);
    }

    /// @notice Returns the number of keys being tracked in the keys array
    /// @return the number of keys as uint256
    function count() public view returns (uint256) {
        return keys.length;
    }

    /// @notice Returns the key and address of an item in the changelog array (for enumeration)
    /// @dev _index is 0-indexed to the underlying array
    /// @return a tuple containing the key and address associated with that key
    function get(uint256 _index) public view returns (bytes32, address) {
        return (keys[_index], location[keys[_index]].addr);
    }

    /// @notice Returns the list of keys being tracked by the changelog
    /// @dev May fail if keys is too large, if so, call count() and iterate with get()
    function list() public view returns (bytes32[] memory) {
        return keys;
    }

    /// @notice Returns the address for a particular key
    /// @param _key a bytes32 key (ex. MCD_VAT)
    /// @return addr the contract address associated with the key
    function getAddress(bytes32 _key) public view returns (address addr) {
        addr = location[_key].addr;
        require(addr != address(0), "dss-chain-log/invalid-key");
    }

    function _addAddress(bytes32 _key, address _addr) internal {
        keys.push(_key);
        location[keys[keys.length - 1]] = Location(
            keys.length - 1,
            _addr
        );
    }

    function _removeAddress(bytes32 _key) internal {
        uint256 index = location[_key].pos;       // Get pos in array
        require(keys[index] == _key, "dss-chain-log/invalid-key");
        bytes32 move  = keys[keys.length - 1];    // Get last key
        keys[index] = move;                       // Replace
        location[move].pos = index;               // Update array pos
        keys.pop();                               // Trim last key
        delete location[_key];                    // Delete struct data
    }
}

// File: contracts/dss-exec-lib/DssExec.sol

//
// DssExec.sol -- MakerDAO Executive Spell Template
//
// Copyright (C) 2020 Maker Ecosystem Growth Holdings, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

pragma solidity ^0.6.12;





contract DssExec {

    ChainLog      immutable public log;
    uint256                 public eta;
    bytes                   public sig;
    bool                    public done;
    bytes32       immutable public tag;
    address       immutable public action;
    uint256       immutable public expiration;
    DSPause       immutable public pause;

    // Provides a descriptive tag for bot consumption
    // This should be modified weekly to provide a summary of the actions
    // Hash: seth keccak -- "$(wget https://<executive-vote-canonical-post> -q -O - 2>/dev/null)"
    function description() external view returns (string memory) {
        return DssAction(action).description();
    }

    function officeHours() external view returns (bool) {
        return DssAction(action).officeHours();
    }

    function nextCastTime() external view returns (uint256 castTime) {
        return DssAction(action).nextCastTime(eta);
    }

    // @param _description  A string description of the spell
    // @param _expiration   The timestamp this spell will expire. (Ex. now + 30 days)
    // @param _spellAction  The address of the spell action
    constructor(uint256 _expiration, address _spellAction) public {
	address _log = DssExecLib.log();

        log         = ChainLog(_log);
        pause       = DSPause(ChainLog(_log).getAddress("MCD_PAUSE"));
        expiration  = _expiration;
        action      = _spellAction;

        sig = abi.encodeWithSignature("execute()");
        bytes32 _tag;                    // Required for assembly access
        address _action = _spellAction;  // Required for assembly access
        assembly { _tag := extcodehash(_action) }
        tag = _tag;
    }

    function schedule() public {
        require(now <= expiration, "This contract has expired");
        require(eta == 0, "This spell has already been scheduled");
        eta = now + DSPause(pause).delay();
        pause.plot(action, tag, sig, eta);
    }

    function cast() public {
        require(!done, "spell-already-cast");
        done = true;
        pause.exec(action, tag, sig, eta);
    }
}

// File: contracts/dss/vat.sol

/// vat.sol -- Dai CDP database

// Copyright (C) 2018 Rain <[email protected]>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

pragma solidity >=0.5.12;


contract Vat is DSNote {
    // --- Auth ---
    mapping (address => uint) public wards;
    function rely(address usr) external note auth { require(live == 1, "Vat/not-live"); wards[usr] = 1; }
    function deny(address usr) external note auth { require(live == 1, "Vat/not-live"); wards[usr] = 0; }
    modifier auth {
        require(wards[msg.sender] == 1, "Vat/not-authorized");
        _;
    }

    mapping(address => mapping (address => uint)) public can;
    function hope(address usr) external note { can[msg.sender][usr] = 1; }
    function nope(address usr) external note { can[msg.sender][usr] = 0; }
    function wish(address bit, address usr) internal view returns (bool) {
        return either(bit == usr, can[bit][usr] == 1);
    }

    // --- Data ---
    struct Ilk {
        uint256 Art;   // Total Normalised Debt     [wad]
        uint256 rate;  // Accumulated Rates         [ray]
        uint256 spot;  // Price with Safety Margin  [ray]
        uint256 line;  // Debt Ceiling              [rad]
        uint256 dust;  // Urn Debt Floor            [rad]
    }
    struct Urn {
        uint256 ink;   // Locked Collateral  [wad]
        uint256 art;   // Normalised Debt    [wad]
    }

    mapping (bytes32 => Ilk)                       public ilks;
    mapping (bytes32 => mapping (address => Urn )) public urns;
    mapping (bytes32 => mapping (address => uint)) public gem;  // [wad]
    mapping (address => uint256)                   public dai;  // [rad]
    mapping (address => uint256)                   public sin;  // [rad]

    uint256 public debt;  // Total Dai Issued    [rad]
    uint256 public vice;  // Total Unbacked Dai  [rad]
    uint256 public Line;  // Total Debt Ceiling  [rad]
    uint256 public live;  // Active Flag

    // --- Init ---
    constructor() public {
        wards[msg.sender] = 1;
        live = 1;
    }

    // --- Math ---
    function _add(uint x, int y) internal pure returns (uint z) {
        z = x + uint(y);
        require(y >= 0 || z <= x);
        require(y <= 0 || z >= x);
    }
    function _sub(uint x, int y) internal pure returns (uint z) {
        z = x - uint(y);
        require(y <= 0 || z <= x);
        require(y >= 0 || z >= x);
    }
    function _mul(uint x, int y) internal pure returns (int z) {
        z = int(x) * y;
        require(int(x) >= 0);
        require(y == 0 || z / y == int(x));
    }
    function _add(uint x, uint y) internal pure returns (uint z) {
        require((z = x + y) >= x);
    }
    function _sub(uint x, uint y) internal pure returns (uint z) {
        require((z = x - y) <= x);
    }
    function _mul(uint x, uint y) internal pure returns (uint z) {
        require(y == 0 || (z = x * y) / y == x);
    }

    // --- Administration ---
    function init(bytes32 ilk) external note auth {
        require(ilks[ilk].rate == 0, "Vat/ilk-already-init");
        ilks[ilk].rate = 10 ** 27;
    }
    function file(bytes32 what, uint data) external note auth {
        require(live == 1, "Vat/not-live");
        if (what == "Line") Line = data;
        else revert("Vat/file-unrecognized-param");
    }
    function file(bytes32 ilk, bytes32 what, uint data) external note auth {
        require(live == 1, "Vat/not-live");
        if (what == "spot") ilks[ilk].spot = data;
        else if (what == "line") ilks[ilk].line = data;
        else if (what == "dust") ilks[ilk].dust = data;
        else revert("Vat/file-unrecognized-param");
    }
    function cage() external note auth {
        live = 0;
    }

    // --- Fungibility ---
    function slip(bytes32 ilk, address usr, int256 wad) external note auth {
        gem[ilk][usr] = _add(gem[ilk][usr], wad);
    }
    function flux(bytes32 ilk, address src, address dst, uint256 wad) external note {
        require(wish(src, msg.sender), "Vat/not-allowed");
        gem[ilk][src] = _sub(gem[ilk][src], wad);
        gem[ilk][dst] = _add(gem[ilk][dst], wad);
    }
    function move(address src, address dst, uint256 rad) external note {
        require(wish(src, msg.sender), "Vat/not-allowed");
        dai[src] = _sub(dai[src], rad);
        dai[dst] = _add(dai[dst], rad);
    }

    function either(bool x, bool y) internal pure returns (bool z) {
        assembly{ z := or(x, y)}
    }
    function both(bool x, bool y) internal pure returns (bool z) {
        assembly{ z := and(x, y)}
    }

    // --- CDP Manipulation ---
    function frob(bytes32 i, address u, address v, address w, int dink, int dart) external note {
        // system is live
        require(live == 1, "Vat/not-live");

        Urn memory urn = urns[i][u];
        Ilk memory ilk = ilks[i];
        // ilk has been initialised
        require(ilk.rate != 0, "Vat/ilk-not-init");

        urn.ink = _add(urn.ink, dink);
        urn.art = _add(urn.art, dart);
        ilk.Art = _add(ilk.Art, dart);

        int dtab = _mul(ilk.rate, dart);
        uint tab = _mul(ilk.rate, urn.art);
        debt     = _add(debt, dtab);

        // either debt has decreased, or debt ceilings are not exceeded
        require(either(dart <= 0, both(_mul(ilk.Art, ilk.rate) <= ilk.line, debt <= Line)), "Vat/ceiling-exceeded");
        // urn is either less risky than before, or it is safe
        require(either(both(dart <= 0, dink >= 0), tab <= _mul(urn.ink, ilk.spot)), "Vat/not-safe");

        // urn is either more safe, or the owner consents
        require(either(both(dart <= 0, dink >= 0), wish(u, msg.sender)), "Vat/not-allowed-u");
        // collateral src consents
        require(either(dink <= 0, wish(v, msg.sender)), "Vat/not-allowed-v");
        // debt dst consents
        require(either(dart >= 0, wish(w, msg.sender)), "Vat/not-allowed-w");

        // urn has no debt, or a non-dusty amount
        require(either(urn.art == 0, tab >= ilk.dust), "Vat/dust");

        gem[i][v] = _sub(gem[i][v], dink);
        dai[w]    = _add(dai[w],    dtab);

        urns[i][u] = urn;
        ilks[i]    = ilk;
    }
    // --- CDP Fungibility ---
    function fork(bytes32 ilk, address src, address dst, int dink, int dart) external note {
        Urn storage u = urns[ilk][src];
        Urn storage v = urns[ilk][dst];
        Ilk storage i = ilks[ilk];

        u.ink = _sub(u.ink, dink);
        u.art = _sub(u.art, dart);
        v.ink = _add(v.ink, dink);
        v.art = _add(v.art, dart);

        uint utab = _mul(u.art, i.rate);
        uint vtab = _mul(v.art, i.rate);

        // both sides consent
        require(both(wish(src, msg.sender), wish(dst, msg.sender)), "Vat/not-allowed");

        // both sides safe
        require(utab <= _mul(u.ink, i.spot), "Vat/not-safe-src");
        require(vtab <= _mul(v.ink, i.spot), "Vat/not-safe-dst");

        // both sides non-dusty
        require(either(utab >= i.dust, u.art == 0), "Vat/dust-src");
        require(either(vtab >= i.dust, v.art == 0), "Vat/dust-dst");
    }
    // --- CDP Confiscation ---
    function grab(bytes32 i, address u, address v, address w, int dink, int dart) external note auth {
        Urn storage urn = urns[i][u];
        Ilk storage ilk = ilks[i];

        urn.ink = _add(urn.ink, dink);
        urn.art = _add(urn.art, dart);
        ilk.Art = _add(ilk.Art, dart);

        int dtab = _mul(ilk.rate, dart);

        gem[i][v] = _sub(gem[i][v], dink);
        sin[w]    = _sub(sin[w],    dtab);
        vice      = _sub(vice,      dtab);
    }

    // --- Settlement ---
    function heal(uint rad) external note {
        address u = msg.sender;
        sin[u] = _sub(sin[u], rad);
        dai[u] = _sub(dai[u], rad);
        vice   = _sub(vice,   rad);
        debt   = _sub(debt,   rad);
    }
    function suck(address u, address v, uint rad) external note auth {
        sin[u] = _add(sin[u], rad);
        dai[v] = _add(dai[v], rad);
        vice   = _add(vice,   rad);
        debt   = _add(debt,   rad);
    }

    // --- Rates ---
    function fold(bytes32 i, address u, int rate) external note auth {
        require(live == 1, "Vat/not-live");
        Ilk storage ilk = ilks[i];
        ilk.rate = _add(ilk.rate, rate);
        int rad  = _mul(ilk.Art, rate);
        dai[u]   = _add(dai[u], rad);
        debt     = _add(debt,   rad);
    }
}

// File: contracts/ds-math/math.sol

/// math.sol -- mixin for inline numerical wizardry

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity >0.4.13;

contract DSMath {
    function add(uint x, uint y) internal pure returns (uint z) {
        require((z = x + y) >= x, "ds-math-add-overflow");
    }
    function sub(uint x, uint y) internal pure returns (uint z) {
        require((z = x - y) <= x, "ds-math-sub-underflow");
    }
    function mul(uint x, uint y) internal pure returns (uint z) {
        require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow");
    }

    function min(uint x, uint y) internal pure returns (uint z) {
        return x <= y ? x : y;
    }
    function max(uint x, uint y) internal pure returns (uint z) {
        return x >= y ? x : y;
    }
    function imin(int x, int y) internal pure returns (int z) {
        return x <= y ? x : y;
    }
    function imax(int x, int y) internal pure returns (int z) {
        return x >= y ? x : y;
    }

    uint constant WAD = 10 ** 18;
    uint constant RAY = 10 ** 27;

    //rounds to zero if x*y < WAD / 2
    function wmul(uint x, uint y) internal pure returns (uint z) {
        z = add(mul(x, y), WAD / 2) / WAD;
    }
    //rounds to zero if x*y < WAD / 2
    function rmul(uint x, uint y) internal pure returns (uint z) {
        z = add(mul(x, y), RAY / 2) / RAY;
    }
    //rounds to zero if x*y < WAD / 2
    function wdiv(uint x, uint y) internal pure returns (uint z) {
        z = add(mul(x, WAD), y / 2) / y;
    }
    //rounds to zero if x*y < RAY / 2
    function rdiv(uint x, uint y) internal pure returns (uint z) {
        z = add(mul(x, RAY), y / 2) / y;
    }

    // This famous algorithm is called "exponentiation by squaring"
    // and calculates x^n with x as fixed-point and n as regular unsigned.
    //
    // It's O(log n), instead of O(n) for naive repeated multiplication.
    //
    // These facts are why it works:
    //
    //  If n is even, then x^n = (x^2)^(n/2).
    //  If n is odd,  then x^n = x * x^(n-1),
    //   and applying the equation for even x gives
    //    x^n = x * (x^2)^((n-1) / 2).
    //
    //  Also, EVM division is flooring and
    //    floor[(n-1) / 2] = floor[n / 2].
    //
    function rpow(uint x, uint n) internal pure returns (uint z) {
        z = n % 2 != 0 ? x : RAY;

        for (n /= 2; n != 0; n /= 2) {
            x = rmul(x, x);

            if (n % 2 != 0) {
                z = rmul(z, x);
            }
        }
    }
}

// File: contracts/ds-token/token.sol

/// token.sol -- ERC20 implementation with minting and burning

// Copyright (C) 2015, 2016, 2017  DappHub, LLC

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

pragma solidity >=0.4.23;




contract DSToken is DSMath, DSAuth {
    bool                                              public  stopped;
    uint256                                           public  totalSupply;
    mapping (address => uint256)                      public  balanceOf;
    mapping (address => mapping (address => uint256)) public  allowance;
    string                                            public  symbol;
    uint8                                             public  decimals = 18; // standard token precision. override to customize
    string                                            public  name = "";     // Optional token name


    constructor(string memory symbol_) public {
        symbol = symbol_;
    }

    event Approval(address indexed src, address indexed guy, uint wad);
    event Transfer(address indexed src, address indexed dst, uint wad);
    event Mint(address indexed guy, uint wad);
    event Burn(address indexed guy, uint wad);
    event Stop();
    event Start();

    modifier stoppable {
        require(!stopped, "ds-stop-is-stopped");
        _;
    }

    function approve(address guy) external returns (bool) {
        return approve(guy, uint(-1));
    }

    function approve(address guy, uint wad) public stoppable returns (bool) {
        allowance[msg.sender][guy] = wad;

        emit Approval(msg.sender, guy, wad);

        return true;
    }

    function transfer(address dst, uint wad) external returns (bool) {
        return transferFrom(msg.sender, dst, wad);
    }

    function transferFrom(address src, address dst, uint wad)
        public
        stoppable
        returns (bool)
    {
        if (src != msg.sender && allowance[src][msg.sender] != uint(-1)) {
            require(allowance[src][msg.sender] >= wad, "ds-token-insufficient-approval");
            allowance[src][msg.sender] = sub(allowance[src][msg.sender], wad);
        }

        require(balanceOf[src] >= wad, "ds-token-insufficient-balance");
        balanceOf[src] = sub(balanceOf[src], wad);
        balanceOf[dst] = add(balanceOf[dst], wad);

        emit Transfer(src, dst, wad);

        return true;
    }

    /*
    function push(address dst, uint wad) external {
        transferFrom(msg.sender, dst, wad);
    }

    function pull(address src, uint wad) external {
        transferFrom(src, msg.sender, wad);
    }

    function move(address src, address dst, uint wad) external {
        transferFrom(src, dst, wad);
    }
    */


    function mint(uint wad) external {
        mint(msg.sender, wad);
    }

    function burn(uint wad) external {
        burn(msg.sender, wad);
    }

    function mint(address guy, uint wad) public auth stoppable {
        balanceOf[guy] = add(balanceOf[guy], wad);
        totalSupply = add(totalSupply, wad);
        emit Mint(guy, wad);
    }

    function burn(address guy, uint wad) public auth stoppable {
        if (guy != msg.sender && allowance[guy][msg.sender] != uint(-1)) {
            require(allowance[guy][msg.sender] >= wad, "ds-token-insufficient-approval");
            allowance[guy][msg.sender] = sub(allowance[guy][msg.sender], wad);
        }

        require(balanceOf[guy] >= wad, "ds-token-insufficient-balance");
        balanceOf[guy] = sub(balanceOf[guy], wad);
        totalSupply = sub(totalSupply, wad);
        emit Burn(guy, wad);
    }

    function stop() public auth {
        stopped = true;
        emit Stop();
    }

    function start() public auth {
        stopped = false;
        emit Start();
    }


    function setName(string memory name_) public auth {
        name = name_;
    }
}

// File: contracts/dss/flap.sol

/// flap.sol -- Surplus auction

// Copyright (C) 2018 Rain <[email protected]>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

pragma solidity >=0.5.12;




/*
   This thing lets you sell some dai in return for gems.

 - `lot` dai in return for bid
 - `bid` gems paid
 - `ttl` single bid lifetime
 - `beg` minimum bid increase
 - `end` max auction duration
*/

contract Flapper is DSNote {
    // --- Auth ---
    mapping (address => uint) public wards;
    function rely(address usr) external note auth { wards[usr] = 1; }
    function deny(address usr) external note auth { wards[usr] = 0; }
    modifier auth {
        require(wards[msg.sender] == 1, "Flapper/not-authorized");
        _;
    }

    // --- Data ---
    struct Bid {
        uint256 bid;  // gems paid               [wad]
        uint256 lot;  // dai in return for bid   [rad]
        address guy;  // high bidder
        uint48  tic;  // bid expiry time         [unix epoch time]
        uint48  end;  // auction expiry time     [unix epoch time]
    }

    mapping (uint => Bid) public bids;

    Vat      public   vat;  // CDP Engine
    DSToken  public   gem;

    uint256  constant ONE = 1.00E18;
    uint256  public   beg = 1.05E18;  // 5% minimum bid increase
    uint48   public   ttl = 3 hours;  // 3 hours bid duration         [seconds]
    uint48   public   tau = 2 days;   // 2 days total auction length  [seconds]
    uint256  public kicks = 0;
    uint256  public live;  // Active Flag

    // --- Events ---
    event Kick(
      uint256 id,
      uint256 lot,
      uint256 bid
    );

    // --- Init ---
    constructor(address vat_, address gem_) public {
        wards[msg.sender] = 1;
        vat = Vat(vat_);
        gem = DSToken(gem_);
        live = 1;
    }

    // --- Math ---
    function add(uint48 x, uint48 y) internal pure returns (uint48 z) {
        require((z = x + y) >= x);
    }
    function mul(uint x, uint y) internal pure returns (uint z) {
        require(y == 0 || (z = x * y) / y == x);
    }

    // --- Admin ---
    function file(bytes32 what, uint data) external note auth {
        if (what == "beg") beg = data;
        else if (what == "ttl") ttl = uint48(data);
        else if (what == "tau") tau = uint48(data);
        else revert("Flapper/file-unrecognized-param");
    }

    // --- Auction ---
    function kick(uint lot, uint bid) external auth returns (uint id) {
        require(live == 1, "Flapper/not-live");
        require(kicks < uint(-1), "Flapper/overflow");
        id = ++kicks;

        bids[id].bid = bid;
        bids[id].lot = lot;
        bids[id].guy = msg.sender;  // configurable??
        bids[id].end = add(uint48(now), tau);

        vat.move(msg.sender, address(this), lot);

        emit Kick(id, lot, bid);
    }
    function tick(uint id) external note {
        require(bids[id].end < now, "Flapper/not-finished");
        require(bids[id].tic == 0, "Flapper/bid-already-placed");
        bids[id].end = add(uint48(now), tau);
    }
    function tend(uint id, uint lot, uint bid) external note {
        require(live == 1, "Flapper/not-live");
        require(bids[id].guy != address(0), "Flapper/guy-not-set");
        require(bids[id].tic > now || bids[id].tic == 0, "Flapper/already-finished-tic");
        require(bids[id].end > now, "Flapper/already-finished-end");

        require(lot == bids[id].lot, "Flapper/lot-not-matching");
        require(bid >  bids[id].bid, "Flapper/bid-not-higher");
        require(mul(bid, ONE) >= mul(beg, bids[id].bid), "Flapper/insufficient-increase");

        if (msg.sender != bids[id].guy) {
            gem.transferFrom(msg.sender, bids[id].guy, bids[id].bid);
            bids[id].guy = msg.sender;
        }
        gem.transferFrom(msg.sender, address(this), bid - bids[id].bid);

        bids[id].bid = bid;
        bids[id].tic = add(uint48(now), ttl);
    }
    function deal(uint id) external note {
        require(live == 1, "Flapper/not-live");
        require(bids[id].tic != 0 && (bids[id].tic < now || bids[id].end < now), "Flapper/not-finished");
        vat.move(address(this), bids[id].guy, bids[id].lot);
        uint256 bid = bids[id].bid;
        try gem.burn(bid) {} catch { gem.transfer(address(0xdead), bid); }
        delete bids[id];
    }

    function cage(uint rad) external note auth {
       live = 0;
       vat.move(address(this), msg.sender, rad);
    }
    function yank(uint id) external note {
        require(live == 0, "Flapper/still-live");
        require(bids[id].guy != address(0), "Flapper/guy-not-set");
        gem.transferFrom(address(this), bids[id].guy, bids[id].bid);
        delete bids[id];
    }
}

// File: contracts/dss/flop.sol

/// flop.sol -- Debt auction

// Copyright (C) 2018 Rain <[email protected]>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

pragma solidity >=0.5.12;

//import { Vow } from "./vow.sol"; // cycle



/*
   This thing creates gems on demand in return for dai.

 - `lot` gems in return for bid
 - `bid` dai paid
 - `gal` receives dai income
 - `ttl` single bid lifetime
 - `beg` minimum bid increase
 - `end` max auction duration
*/

contract Flopper is DSNote {
    // --- Auth ---
    mapping (address => uint) public wards;
    function rely(address usr) external note auth { wards[usr] = 1; }
    function deny(address usr) external note auth { wards[usr] = 0; }
    modifier auth {
        require(wards[msg.sender] == 1, "Flopper/not-authorized");
        _;
    }

    // --- Data ---
    struct Bid {
        uint256 bid;  // dai paid                [rad]
        uint256 lot;  // gems in return for bid  [wad]
        address guy;  // high bidder
        uint48  tic;  // bid expiry time         [unix epoch time]
        uint48  end;  // auction expiry time     [unix epoch time]
    }

    mapping (uint => Bid) public bids;

    Vat      public   vat;  // CDP Engine
    DSToken  public   gem;

    uint256  constant ONE = 1.00E18;
    uint256  public   beg = 1.05E18;  // 5% minimum bid increase
    uint256  public   pad = 1.50E18;  // 50% lot increase for tick
    uint48   public   ttl = 3 hours;  // 3 hours bid lifetime         [seconds]
    uint48   public   tau = 2 days;   // 2 days total auction length  [seconds]
    uint256  public kicks = 0;
    uint256  public live;             // Active Flag
    address  public vow;              // not used until shutdown

    // --- Events ---
    event Kick(
      uint256 id,
      uint256 lot,
      uint256 bid,
      address indexed gal
    );

    // --- Init ---
    constructor(address vat_, address gem_) public {
        wards[msg.sender] = 1;
        vat = Vat(vat_);
        gem = DSToken(gem_);
        live = 1;
    }

    // --- Math ---
    function add(uint48 x, uint48 y) internal pure returns (uint48 z) {
        require((z = x + y) >= x);
    }
    function mul(uint x, uint y) internal pure returns (uint z) {
        require(y == 0 || (z = x * y) / y == x);
    }
    function min(uint x, uint y) internal pure returns (uint z) {
        if (x > y) { z = y; } else { z = x; }
    }

    // --- Admin ---
    function file(bytes32 what, uint data) external note auth {
        if (what == "beg") beg = data;
        else if (what == "pad") pad = data;
        else if (what == "ttl") ttl = uint48(data);
        else if (what == "tau") tau = uint48(data);
        else revert("Flopper/file-unrecognized-param");
    }

    // --- Auction ---
    function kick(address gal, uint lot, uint bid) external auth returns (uint id) {
        require(live == 1, "Flopper/not-live");
        require(kicks < uint(-1), "Flopper/overflow");
        id = ++kicks;

        bids[id].bid = bid;
        bids[id].lot = lot;
        bids[id].guy = gal;
        bids[id].end = add(uint48(now), tau);

        emit Kick(id, lot, bid, gal);
    }
    function tick(uint id) external note {
        require(bids[id].end < now, "Flopper/not-finished");
        require(bids[id].tic == 0, "Flopper/bid-already-placed");
        bids[id].lot = mul(pad, bids[id].lot) / ONE;
        bids[id].end = add(uint48(now), tau);
    }
    function dent(uint id, uint lot, uint bid) external note {
        require(live == 1, "Flopper/not-live");
        require(bids[id].guy != address(0), "Flopper/guy-not-set");
        require(bids[id].tic > now || bids[id].tic == 0, "Flopper/already-finished-tic");
        require(bids[id].end > now, "Flopper/already-finished-end");

        require(bid == bids[id].bid, "Flopper/not-matching-bid");
        require(lot <  bids[id].lot, "Flopper/lot-not-lower");
        require(mul(beg, lot) <= mul(bids[id].lot, ONE), "Flopper/insufficient-decrease");

        if (msg.sender != bids[id].guy) {
            vat.move(msg.sender, bids[id].guy, bid);

            // on first dent, clear as much Ash as possible
            if (bids[id].tic == 0) {
                uint Ash = Vow(bids[id].guy).Ash();
                Vow(bids[id].guy).kiss(min(bid, Ash));
            }

            bids[id].guy = msg.sender;
        }

        bids[id].lot = lot;
        bids[id].tic = add(uint48(now), ttl);
    }
    function deal(uint id) external note {
        require(live == 1, "Flopper/not-live");
        require(bids[id].tic != 0 && (bids[id].tic < now || bids[id].end < now), "Flopper/not-finished");
        gem.mint(bids[id].guy, bids[id].lot); // will fail if mint is unavailable
        delete bids[id];
    }

    // --- Shutdown ---
    function cage() external note auth {
       live = 0;
       vow = msg.sender;
    }
    function yank(uint id) external note {
        require(live == 0, "Flopper/still-live");
        require(bids[id].guy != address(0), "Flopper/guy-not-set");
        vat.suck(vow, bids[id].guy, bids[id].bid);
        delete bids[id];
    }
}

// File: contracts/dss/vow.sol

/// vow.sol -- Dai settlement module

// Copyright (C) 2018 Rain <[email protected]>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

pragma solidity >=0.5.12;





contract Vow is DSNote {
    // --- Auth ---
    mapping (address => uint) public wards;
    function rely(address usr) external note auth { require(live == 1, "Vow/not-live"); wards[usr] = 1; }
    function deny(address usr) external note auth { wards[usr] = 0; }
    modifier auth {
        require(wards[msg.sender] == 1, "Vow/not-authorized");
        _;
    }

    // --- Data ---
    Vat      public vat;       // CDP Engine
    Flapper  public flapper;   // Surplus Auction House
    Flopper  public flopper;   // Debt Auction House

    mapping (uint256 => uint256) public sin;  // debt queue
    uint256 public Sin;   // Queued debt            [rad]
    uint256 public Ash;   // On-auction debt        [rad]

    uint256 public wait;  // Flop delay             [seconds]
    uint256 public dump;  // Flop initial lot size  [wad]
    uint256 public sump;  // Flop fixed bid size    [rad]

    uint256 public bump;  // Flap fixed lot size    [rad]
    uint256 public hump;  // Surplus buffer         [rad]

    uint256 public live;  // Active Flag

    // --- Init ---
    constructor(address vat_, address flapper_, address flopper_) public {
        wards[msg.sender] = 1;
        vat     = Vat(vat_);
        flapper = Flapper(flapper_);
        flopper = Flopper(flopper_);
        vat.hope(flapper_);
        live = 1;
    }

    // --- Math ---
    function add(uint x, uint y) internal pure returns (uint z) {
        require((z = x + y) >= x);
    }
    function sub(uint x, uint y) internal pure returns (uint z) {
        require((z = x - y) <= x);
    }
    function min(uint x, uint y) internal pure returns (uint z) {
        return x <= y ? x : y;
    }

    // --- Administration ---
    function file(bytes32 what, uint data) external note auth {
        if (what == "wait") wait = data;
        else if (what == "bump") bump = data;
        else if (what == "sump") sump = data;
        else if (what == "dump") dump = data;
        else if (what == "hump") hump = data;
        else revert("Vow/file-unrecognized-param");
    }

    function file(bytes32 what, address data) external note auth {
        if (what == "flapper") {
            vat.nope(address(flapper));
            flapper = Flapper(data);
            vat.hope(data);
        }
        else if (what == "flopper") flopper = Flopper(data);
        else revert("Vow/file-unrecognized-param");
    }

    // Push to debt-queue
    function fess(uint tab) external note auth {
        sin[now] = add(sin[now], tab);
        Sin = add(Sin, tab);
    }
    // Pop from debt-queue
    function flog(uint era) external note {
        require(add(era, wait) <= now, "Vow/wait-not-finished");
        Sin = sub(Sin, sin[era]);
        sin[era] = 0;
    }

    // Debt settlement
    function heal(uint rad) external note {
        require(rad <= vat.dai(address(this)), "Vow/insufficient-surplus");
        require(rad <= sub(sub(vat.sin(address(this)), Sin), Ash), "Vow/insufficient-debt");
        vat.heal(rad);
    }
    function kiss(uint rad) external note {
        require(rad <= Ash, "Vow/not-enough-ash");
        require(rad <= vat.dai(address(this)), "Vow/insufficient-surplus");
        Ash = sub(Ash, rad);
        vat.heal(rad);
    }

    // Debt auction
    function flop() external note returns (uint id) {
        require(sump <= sub(sub(vat.sin(address(this)), Sin), Ash), "Vow/insufficient-debt");
        require(vat.dai(address(this)) == 0, "Vow/surplus-not-zero");
        Ash = add(Ash, sump);
        id = flopper.kick(address(this), dump, sump);
    }
    // Surplus auction
    function flap() external note returns (uint id) {
        require(vat.dai(address(this)) >= add(add(vat.sin(address(this)), bump), hump), "Vow/insufficient-surplus");
        require(sub(sub(vat.sin(address(this)), Sin), Ash) == 0, "Vow/debt-not-zero");
        id = flapper.kick(bump, 0);
    }

    function cage() external note auth {
        require(live == 1, "Vow/not-live");
        live = 0;
        Sin = 0;
        Ash = 0;
        flapper.cage(vat.dai(address(flapper)));
        flopper.cage();
        vat.heal(min(vat.dai(address(this)), vat.sin(address(this))));
    }
}

// File: contracts/dss/dog.sol

/// dog.sol -- Dai liquidation module 2.0

// Copyright (C) 2020-2021 Maker Ecosystem Growth Holdings, INC.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

pragma solidity >=0.6.12;


//import { Clipper } from "./clip.sol"; // cycle

contract Dog {
    // --- Auth ---
    mapping (address => uint256) public wards;
    function rely(address usr) external auth { wards[usr] = 1; emit Rely(usr); }
    function deny(address usr) external auth { wards[usr] = 0; emit Deny(usr); }
    modifier auth {
        require(wards[msg.sender] == 1, "Dog/not-authorized");
        _;
    }

    // --- Data ---
    struct Ilk {
        address clip;  // Liquidator
        uint256 chop;  // Liquidation Penalty                                          [wad]
        uint256 hole;  // Max DAI needed to cover debt+fees of active auctions per ilk [rad]
        uint256 dirt;  // Amt DAI needed to cover debt+fees of active auctions per ilk [rad]
    }

    Vat     immutable public vat;  // CDP Engine

    mapping (bytes32 => Ilk) public ilks;

    Vow     public vow;   // Debt Engine
    uint256 public live;  // Active Flag
    uint256 public Hole;  // Max DAI needed to cover debt+fees of active auctions [rad]
    uint256 public Dirt;  // Amt DAI needed to cover debt+fees of active auctions [rad]

    // --- Events ---
    event Rely(address indexed usr);
    event Deny(address indexed usr);

    event File(bytes32 indexed what, uint256 data);
    event File(bytes32 indexed what, address data);
    event File(bytes32 indexed ilk, bytes32 indexed what, uint256 data);
    event File(bytes32 indexed ilk, bytes32 indexed what, address clip);

    event Bark(
      bytes32 indexed ilk,
      address indexed urn,
      uint256 ink,
      uint256 art,
      uint256 due,
      address clip,
      uint256 indexed id
    );
    event Digs(bytes32 indexed ilk, uint256 rad);
    event Cage();

    // --- Init ---
    constructor(address vat_) public {
        vat = Vat(vat_);
        live = 1;
        wards[msg.sender] = 1;
        emit Rely(msg.sender);
    }

    // --- Math ---
    uint256 constant WAD = 10 ** 18;

    function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = x <= y ? x : y;
    }
    function add(uint256 x, uint256 y) internal pure returns (uint256 z) {
        require((z = x + y) >= x);
    }
    function sub(uint256 x, uint256 y) internal pure returns (uint256 z) {
        require((z = x - y) <= x);
    }
    function mul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        require(y == 0 || (z = x * y) / y == x);
    }

    // --- Administration ---
    function file(bytes32 what, address data) external auth {
        if (what == "vow") vow = Vow(data);
        else revert("Dog/file-unrecognized-param");
        emit File(what, data);
    }
    function file(bytes32 what, uint256 data) external auth {
        if (what == "Hole") Hole = data;
        else revert("Dog/file-unrecognized-param");
        emit File(what, data);
    }
    function file(bytes32 ilk, bytes32 what, uint256 data) external auth {
        if (what == "chop") {
            require(data >= WAD, "Dog/file-chop-lt-WAD");
            ilks[ilk].chop = data;
        } else if (what == "hole") ilks[ilk].hole = data;
        else revert("Dog/file-unrecognized-param");
        emit File(ilk, what, data);
    }
    function file(bytes32 ilk, bytes32 what, address clip) external auth {
        if (what == "clip") {
            require(ilk == Clipper(clip).ilk(), "Dog/file-ilk-neq-clip.ilk");
            ilks[ilk].clip = clip;
        } else revert("Dog/file-unrecognized-param");
        emit File(ilk, what, clip);
    }

    function chop(bytes32 ilk) external view returns (uint256) {
        return ilks[ilk].chop;
    }

    // --- CDP Liquidation: all bark and no bite ---
    //
    // Liquidate a Vault and start a Dutch auction to sell its collateral for DAI.
    //
    // The third argument is the address that will receive the liquidation reward, if any.
    //
    // The entire Vault will be liquidated except when the target amount of DAI to be raised in
    // the resulting auction (debt of Vault + liquidation penalty) causes either Dirt to exceed
    // Hole or ilk.dirt to exceed ilk.hole by an economically significant amount. In that
    // case, a partial liquidation is performed to respect the global and per-ilk limits on
    // outstanding DAI target. The one exception is if the resulting auction would likely
    // have too little collateral to be interesting to Keepers (debt taken from Vault < ilk.dust),
    // in which case the function reverts. Please refer to the code and comments within if
    // more detail is desired.
    function bark(bytes32 ilk, address urn, address kpr) external returns (uint256 id) {
        require(live == 1, "Dog/not-live");

        (uint256 ink, uint256 art) = vat.urns(ilk, urn);
        Ilk memory milk = ilks[ilk];
        uint256 dart;
        uint256 rate;
        uint256 dust;
        {
            uint256 spot;
            (,rate, spot,, dust) = vat.ilks(ilk);
            require(spot > 0 && mul(ink, spot) < mul(art, rate), "Dog/not-unsafe");

            // Get the minimum value between:
            // 1) Remaining space in the general Hole
            // 2) Remaining space in the collateral hole
            require(Hole > Dirt && milk.hole > milk.dirt, "Dog/liquidation-limit-hit");
            uint256 room = min(Hole - Dirt, milk.hole - milk.dirt);

            // uint256.max()/(RAD*WAD) = 115,792,089,237,316
            dart = min(art, mul(room, WAD) / rate / milk.chop);

            // Partial liquidation edge case logic
            if (art > dart) {
                if (mul(art - dart, rate) < dust) {

                    // If the leftover Vault would be dusty, just liquidate it entirely.
                    // This will result in at least one of dirt_i > hole_i or Dirt > Hole becoming true.
                    // The amount of excess will be bounded above by ceiling(dust_i * chop_i / WAD).
                    // This deviation is assumed to be small compared to both hole_i and Hole, so that
                    // the extra amount of target DAI over the limits intended is not of economic concern.
                    dart = art;
                } else {

                    // In a partial liquidation, the resulting auction should also be non-dusty.
                    require(mul(dart, rate) >= dust, "Dog/dusty-auction-from-partial-liquidation");
                }
            }
        }

        uint256 dink = mul(ink, dart) / art;

        require(dink > 0, "Dog/null-auction");
        require(dart <= 2**255 && dink <= 2**255, "Dog/overflow");

        vat.grab(
            ilk, urn, milk.clip, address(vow), -int256(dink), -int256(dart)
        );

        uint256 due = mul(dart, rate);
        vow.fess(due);

        {   // Avoid stack too deep
            // This calcuation will overflow if dart*rate exceeds ~10^14
            uint256 tab = mul(due, milk.chop) / WAD;
            Dirt = add(Dirt, tab);
            ilks[ilk].dirt = add(milk.dirt, tab);

            id = Clipper(milk.clip).kick({
                tab: tab,
                lot: dink,
                usr: urn,
                kpr: kpr
            });
        }

        emit Bark(ilk, urn, dink, dart, due, milk.clip, id);
    }

    function digs(bytes32 ilk, uint256 rad) external auth {
        Dirt = sub(Dirt, rad);
        ilks[ilk].dirt = sub(ilks[ilk].dirt, rad);
        emit Digs(ilk, rad);
    }

    function cage() external auth {
        live = 0;
        emit Cage();
    }
}

// File: contracts/dss/spot.sol

/// spot.sol -- Spotter

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

pragma solidity >=0.5.12;



interface PipLike {
    function peek() external view returns (bytes32, bool);
    function read() external view returns (bytes32);
}

contract Spotter is DSNote {
    // --- Auth ---
    mapping (address => uint) public wards;
    function rely(address guy) external note auth { wards[guy] = 1;  }
    function deny(address guy) external note auth { wards[guy] = 0; }
    modifier auth {
        require(wards[msg.sender] == 1, "Spotter/not-authorized");
        _;
    }

    // --- Data ---
    struct Ilk {
        PipLike pip;  // Price Feed
        uint256 mat;  // Liquidation ratio [ray]
    }

    mapping (bytes32 => Ilk) public ilks;

    Vat     public vat;  // CDP Engine
    uint256 public par;  // ref per dai [ray]

    uint256 public live;

    // --- Events ---
    event Poke(
      bytes32 ilk,
      bytes32 val,  // [wad]
      uint256 spot  // [ray]
    );

    // --- Init ---
    constructor(address vat_) public {
        wards[msg.sender] = 1;
        vat = Vat(vat_);
        par = ONE;
        live = 1;
    }

    // --- Math ---
    uint constant ONE = 10 ** 27;

    function mul(uint x, uint y) internal pure returns (uint z) {
        require(y == 0 || (z = x * y) / y == x);
    }
    function rdiv(uint x, uint y) internal pure returns (uint z) {
        z = mul(x, ONE) / y;
    }

    // --- Administration ---
    function file(bytes32 ilk, bytes32 what, address pip_) external note auth {
        require(live == 1, "Spotter/not-live");
        if (what == "pip") ilks[ilk].pip = PipLike(pip_);
        else revert("Spotter/file-unrecognized-param");
    }
    function file(bytes32 what, uint data) external note auth {
        require(live == 1, "Spotter/not-live");
        if (what == "par") par = data;
        else revert("Spotter/file-unrecognized-param");
    }
    function file(bytes32 ilk, bytes32 what, uint data) external note auth {
        require(live == 1, "Spotter/not-live");
        if (what == "mat") ilks[ilk].mat = data;
        else revert("Spotter/file-unrecognized-param");
    }

    // --- Update value ---
    function poke(bytes32 ilk) external {
        (bytes32 val, bool has) = ilks[ilk].pip.peek();
        uint256 spot = has ? rdiv(rdiv(mul(uint(val), 10 ** 9), par), ilks[ilk].mat) : 0;
        vat.file(ilk, "spot", spot);
        emit Poke(ilk, val, spot);
    }

    function cage() external note auth {
        live = 0;
    }
}

// File: contracts/dss/abaci.sol

// Copyright (C) 2020 Maker Ecosystem Growth Holdings, INC.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

pragma solidity >=0.6.12;

interface Abacus {
    // 1st arg: initial price               [ray]
    // 2nd arg: seconds since auction start [seconds]
    // returns: current auction price       [ray]
    function price(uint256, uint256) external view returns (uint256);
}

contract LinearDecrease is Abacus {

    // --- Auth ---
    mapping (address => uint256) public wards;
    function rely(address usr) external auth { wards[usr] = 1; emit Rely(usr); }
    function deny(address usr) external auth { wards[usr] = 0; emit Deny(usr); }
    modifier auth {
        require(wards[msg.sender] == 1, "LinearDecrease/not-authorized");
        _;
    }

    // --- Data ---
    uint256 public tau;  // Seconds after auction start when the price reaches zero [seconds]

    // --- Events ---
    event Rely(address indexed usr);
    event Deny(address indexed usr);

    event File(bytes32 indexed what, uint256 data);

    // --- Init ---
    constructor() public {
        wards[msg.sender] = 1;
        emit Rely(msg.sender);
    }

    // --- Administration ---
    function file(bytes32 what, uint256 data) external auth {
        if (what ==  "tau") tau = data;
        else revert("LinearDecrease/file-unrecognized-param");
        emit File(what, data);
    }

    // --- Math ---
    uint256 constant RAY = 10 ** 27;
    function add(uint256 x, uint256 y) internal pure returns (uint256 z) {
        require((z = x + y) >= x);
    }
    function mul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        require(y == 0 || (z = x * y) / y == x);
    }
    function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = x * y;
        require(y == 0 || z / y == x);
        z = z / RAY;
    }

    // Price calculation when price is decreased linearly in proportion to time:
    // tau: The number of seconds after the start of the auction where the price will hit 0
    // top: Initial price
    // dur: current seconds since the start of the auction
    //
    // Returns y = top * ((tau - dur) / tau)
    //
    // Note the internal call to mul multiples by RAY, thereby ensuring that the rmul calculation
    // which utilizes top and tau (RAY values) is also a RAY value.
    function price(uint256 top, uint256 dur) override external view returns (uint256) {
        if (dur >= tau) return 0;
        return rmul(top, mul(tau - dur, RAY) / tau);
    }
}

contract StairstepExponentialDecrease is Abacus {

    // --- Auth ---
    mapping (address => uint256) public wards;
    function rely(address usr) external auth { wards[usr] = 1; emit Rely(usr); }
    function deny(address usr) external auth { wards[usr] = 0; emit Deny(usr); }
    modifier auth {
        require(wards[msg.sender] == 1, "StairstepExponentialDecrease/not-authorized");
        _;
    }

    // --- Data ---
    uint256 public step; // Length of time between price drops [seconds]
    uint256 public cut;  // Per-step multiplicative factor     [ray]

    // --- Events ---
    event Rely(address indexed usr);
    event Deny(address indexed usr);

    event File(bytes32 indexed what, uint256 data);

    // --- Init ---
    // @notice: `cut` and `step` values must be correctly set for
    //     this contract to return a valid price
    constructor() public {
        wards[msg.sender] = 1;
        emit Rely(msg.sender);
    }

    // --- Administration ---
    function file(bytes32 what, uint256 data) external auth {
        if      (what ==  "cut") require((cut = data) <= RAY, "StairstepExponentialDecrease/cut-gt-RAY");
        else if (what == "step") step = data;
        else revert("StairstepExponentialDecrease/file-unrecognized-param");
        emit File(what, data);
    }

    // --- Math ---
    uint256 constant RAY = 10 ** 27;
    function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = x * y;
        require(y == 0 || z / y == x);
        z = z / RAY;
    }
    // optimized version from dss PR #78
    function rpow(uint256 x, uint256 n, uint256 b) internal pure returns (uint256 z) {
        assembly {
            switch n case 0 { z := b }
            default {
                switch x case 0 { z := 0 }
                default {
                    switch mod(n, 2) case 0 { z := b } default { z := x }
                    let half := div(b, 2)  // for rounding.
                    for { n := div(n, 2) } n { n := div(n,2) } {
                        let xx := mul(x, x)
                        if shr(128, x) { revert(0,0) }
                        let xxRound := add(xx, half)
                        if lt(xxRound, xx) { revert(0,0) }
                        x := div(xxRound, b)
                        if mod(n,2) {
                            let zx := mul(z, x)
                            if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0,0) }
                            let zxRound := add(zx, half)
                            if lt(zxRound, zx) { revert(0,0) }
                            z := div(zxRound, b)
                        }
                    }
                }
            }
        }
    }

    // top: initial price
    // dur: seconds since the auction has started
    // step: seconds between a price drop
    // cut: cut encodes the percentage to decrease per step.
    //   For efficiency, the values is set as (1 - (% value / 100)) * RAY
    //   So, for a 1% decrease per step, cut would be (1 - 0.01) * RAY
    //
    // returns: top * (cut ^ dur)
    //
    //
    function price(uint256 top, uint256 dur) override external view returns (uint256) {
        return rmul(top, rpow(cut, dur / step, RAY));
    }
}

// While an equivalent function can be obtained by setting step = 1 in StairstepExponentialDecrease,
// this continous (i.e. per-second) exponential decrease has be implemented as it is more gas-efficient
// than using the stairstep version with step = 1 (primarily due to 1 fewer SLOAD per price calculation).
contract ExponentialDecrease is Abacus {

    // --- Auth ---
    mapping (address => uint256) public wards;
    function rely(address usr) external auth { wards[usr] = 1; emit Rely(usr); }
    function deny(address usr) external auth { wards[usr] = 0; emit Deny(usr); }
    modifier auth {
        require(wards[msg.sender] == 1, "ExponentialDecrease/not-authorized");
        _;
    }

    // --- Data ---
    uint256 public cut;  // Per-second multiplicative factor [ray]

    // --- Events ---
    event Rely(address indexed usr);
    event Deny(address indexed usr);

    event File(bytes32 indexed what, uint256 data);

    // --- Init ---
    // @notice: `cut` value must be correctly set for
    //     this contract to return a valid price
    constructor() public {
        wards[msg.sender] = 1;
        emit Rely(msg.sender);
    }

    // --- Administration ---
    function file(bytes32 what, uint256 data) external auth {
        if      (what ==  "cut") require((cut = data) <= RAY, "ExponentialDecrease/cut-gt-RAY");
        else revert("ExponentialDecrease/file-unrecognized-param");
        emit File(what, data);
    }

    // --- Math ---
    uint256 constant RAY = 10 ** 27;
    function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = x * y;
        require(y == 0 || z / y == x);
        z = z / RAY;
    }
    // optimized version from dss PR #78
    function rpow(uint256 x, uint256 n, uint256 b) internal pure returns (uint256 z) {
        assembly {
            switch n case 0 { z := b }
            default {
                switch x case 0 { z := 0 }
                default {
                    switch mod(n, 2) case 0 { z := b } default { z := x }
                    let half := div(b, 2)  // for rounding.
                    for { n := div(n, 2) } n { n := div(n,2) } {
                        let xx := mul(x, x)
                        if shr(128, x) { revert(0,0) }
                        let xxRound := add(xx, half)
                        if lt(xxRound, xx) { revert(0,0) }
                        x := div(xxRound, b)
                        if mod(n,2) {
                            let zx := mul(z, x)
                            if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0,0) }
                            let zxRound := add(zx, half)
                            if lt(zxRound, zx) { revert(0,0) }
                            z := div(zxRound, b)
                        }
                    }
                }
            }
        }
    }

    // top: initial price
    // dur: seconds since the auction has started
    // cut: cut encodes the percentage to decrease per second.
    //   For efficiency, the values is set as (1 - (% value / 100)) * RAY
    //   So, for a 1% decrease per second, cut would be (1 - 0.01) * RAY
    //
    // returns: top * (cut ^ dur)
    //
    function price(uint256 top, uint256 dur) override external view returns (uint256) {
        return rmul(top, rpow(cut, dur, RAY));
    }
}

// File: contracts/dss/clip.sol

/// clip.sol -- Dai auction module 2.0

// Copyright (C) 2020-2021 Maker Ecosystem Growth Holdings, INC.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

pragma solidity >=0.6.12;





interface ClipperCallee {
    function clipperCall(address, uint256, uint256, bytes calldata) external;
}

contract Clipper {
    // --- Auth ---
    mapping (address => uint256) public wards;
    function rely(address usr) external auth { wards[usr] = 1; emit Rely(usr); }
    function deny(address usr) external auth { wards[usr] = 0; emit Deny(usr); }
    modifier auth {
        require(wards[msg.sender] == 1, "Clipper/not-authorized");
        _;
    }

    // --- Data ---
    bytes32  immutable public ilk;   // Collateral type of this Clipper
    Vat      immutable public vat;   // Core CDP Engine

    Dog         public dog;      // Liquidation module
    address     public vow;      // Recipient of dai raised in auctions
    Spotter     public spotter;  // Collateral price module
    Abacus      public calc;     // Current price calculator

    uint256 public buf;    // Multiplicative factor to increase starting price                  [ray]
    uint256 public tail;   // Time elapsed before auction reset                                 [seconds]
    uint256 public cusp;   // Percentage drop before auction reset                              [ray]
    uint64  public chip;   // Percentage of tab to suck from vow to incentivize keepers         [wad]
    uint192 public tip;    // Flat fee to suck from vow to incentivize keepers                  [rad]
    uint256 public chost;  // Cache the ilk dust times the ilk chop to prevent excessive SLOADs [rad]

    uint256   public kicks;   // Total auctions
    uint256[] public active;  // Array of active auction ids

    struct Sale {
        uint256 pos;  // Index in active array
        uint256 tab;  // Dai to raise       [rad]
        uint256 lot;  // collateral to sell [wad]
        address usr;  // Liquidated CDP
        uint96  tic;  // Auction start time
        uint256 top;  // Starting price     [ray]
    }
    mapping(uint256 => Sale) public sales;

    uint256 internal locked;

    // Levels for circuit breaker
    // 0: no breaker
    // 1: no new kick()
    // 2: no new kick() or redo()
    // 3: no new kick(), redo(), or take()
    uint256 public stopped = 0;

    // --- Events ---
    event Rely(address indexed usr);
    event Deny(address indexed usr);

    event File(bytes32 indexed what, uint256 data);
    event File(bytes32 indexed what, address data);

    event Kick(
        uint256 indexed id,
        uint256 top,
        uint256 tab,
        uint256 lot,
        address indexed usr,
        address indexed kpr,
        uint256 coin
    );
    event Take(
        uint256 indexed id,
        uint256 max,
        uint256 price,
        uint256 owe,
        uint256 tab,
        uint256 lot,
        address indexed usr
    );
    event Redo(
        uint256 indexed id,
        uint256 top,
        uint256 tab,
        uint256 lot,
        address indexed usr,
        address indexed kpr,
        uint256 coin
    );

    event Yank(uint256 id);

    // --- Init ---
    constructor(address vat_, address spotter_, address dog_, bytes32 ilk_) public {
        vat     = Vat(vat_);
        spotter = Spotter(spotter_);
        dog     = Dog(dog_);
        ilk     = ilk_;
        buf     = RAY;
        wards[msg.sender] = 1;
        emit Rely(msg.sender);
    }

    // --- Synchronization ---
    modifier lock {
        require(locked == 0, "Clipper/system-locked");
        locked = 1;
        _;
        locked = 0;
    }

    modifier isStopped(uint256 level) {
        require(stopped < level, "Clipper/stopped-incorrect");
        _;
    }

    // --- Administration ---
    function file(bytes32 what, uint256 data) external auth lock {
        if      (what == "buf")         buf = data;
        else if (what == "tail")       tail = data;           // Time elapsed before auction reset
        else if (what == "cusp")       cusp = data;           // Percentage drop before auction reset
        else if (what == "chip")       chip = uint64(data);   // Percentage of tab to incentivize (max: 2^64 - 1 => 18.xxx WAD = 18xx%)
        else if (what == "tip")         tip = uint192(data);  // Flat fee to incentivize keepers (max: 2^192 - 1 => 6.277T RAD)
        else if (what == "stopped") stopped = data;           // Set breaker (0, 1, 2, or 3)
        else revert("Clipper/file-unrecognized-param");
        emit File(what, data);
    }
    function file(bytes32 what, address data) external auth lock {
        if (what == "spotter") spotter = Spotter(data);
        else if (what == "dog")    dog = Dog(data);
        else if (what == "vow")    vow = data;
        else if (what == "calc")  calc = Abacus(data);
        else revert("Clipper/file-unrecognized-param");
        emit File(what, data);
    }

    // --- Math ---
    uint256 constant BLN = 10 **  9;
    uint256 constant WAD = 10 ** 18;
    uint256 constant RAY = 10 ** 27;

    function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = x <= y ? x : y;
    }
    function add(uint256 x, uint256 y) internal pure returns (uint256 z) {
        require((z = x + y) >= x);
    }
    function sub(uint256 x, uint256 y) internal pure returns (uint256 z) {
        require((z = x - y) <= x);
    }
    function mul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        require(y == 0 || (z = x * y) / y == x);
    }
    function wmul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = mul(x, y) / WAD;
    }
    function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = mul(x, y) / RAY;
    }
    function rdiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = mul(x, RAY) / y;
    }

    // --- Auction ---

    // get the price directly from the OSM
    // Could get this from rmul(Vat.ilks(ilk).spot, Spotter.mat()) instead, but
    // if mat has changed since the last poke, the resulting value will be
    // incorrect.
    function getFeedPrice() internal view returns (uint256 feedPrice) {
        (PipLike pip, ) = spotter.ilks(ilk);
        (bytes32 val, bool has) = pip.peek();
        require(has, "Clipper/invalid-price");
        feedPrice = rdiv(mul(uint256(val), BLN), spotter.par());
    }

    // start an auction
    // note: trusts the caller to transfer collateral to the contract
    // The starting price `top` is obtained as follows:
    //
    //     top = val * buf / par
    //
    // Where `val` is the collateral's unitary value in USD, `buf` is a
    // multiplicative factor to increase the starting price, and `par` is a
    // reference per DAI.
    function kick(
        uint256 tab,  // Debt                   [rad]
        uint256 lot,  // Collateral             [wad]
        address usr,  // Address that will receive any leftover collateral
        address kpr   // Address that will receive incentives
    ) external auth lock isStopped(1) returns (uint256 id) {
        // Input validation
        require(tab  >          0, "Clipper/zero-tab");
        require(lot  >          0, "Clipper/zero-lot");
        require(usr != address(0), "Clipper/zero-usr");
        id = ++kicks;
        require(id   >          0, "Clipper/overflow");

        active.push(id);

        sales[id].pos = active.length - 1;

        sales[id].tab = tab;
        sales[id].lot = lot;
        sales[id].usr = usr;
        sales[id].tic = uint96(block.timestamp);

        uint256 top;
        top = rmul(getFeedPrice(), buf);
        require(top > 0, "Clipper/zero-top-price");
        sales[id].top = top;

        // incentive to kick auction
        uint256 _tip  = tip;
        uint256 _chip = chip;
        uint256 coin;
        if (_tip > 0 || _chip > 0) {
            coin = add(_tip, wmul(tab, _chip));
            vat.suck(vow, kpr, coin);
        }

        emit Kick(id, top, tab, lot, usr, kpr, coin);
    }

    // Reset an auction
    // See `kick` above for an explanation of the computation of `top`.
    function redo(
        uint256 id,  // id of the auction to reset
        address kpr  // Address that will receive incentives
    ) external lock isStopped(2) {
        // Read auction data
        address usr = sales[id].usr;
        uint96  tic = sales[id].tic;
        uint256 top = sales[id].top;

        require(usr != address(0), "Clipper/not-running-auction");

        // Check that auction needs reset
        // and compute current price [ray]
        (bool done,) = status(tic, top);
        require(done, "Clipper/cannot-reset");

        uint256 tab   = sales[id].tab;
        uint256 lot   = sales[id].lot;
        sales[id].tic = uint96(block.timestamp);

        uint256 feedPrice = getFeedPrice();
        top = rmul(feedPrice, buf);
        require(top > 0, "Clipper/zero-top-price");
        sales[id].top = top;

        // incentive to redo auction
        uint256 _tip  = tip;
        uint256 _chip = chip;
        uint256 coin;
        if (_tip > 0 || _chip > 0) {
            uint256 _chost = chost;
            if (tab >= _chost && mul(lot, feedPrice) >= _chost) {
                coin = add(_tip, wmul(tab, _chip));
                vat.suck(vow, kpr, coin);
            }
        }

        emit Redo(id, top, tab, lot, usr, kpr, coin);
    }

    // Buy up to `amt` of collateral from the auction indexed by `id`.
    // 
    // Auctions will not collect more DAI than their assigned DAI target,`tab`;
    // thus, if `amt` would cost more DAI than `tab` at the current price, the
    // amount of collateral purchased will instead be just enough to collect `tab` DAI.
    //
    // To avoid partial purchases resulting in very small leftover auctions that will
    // never be cleared, any partial purchase must leave at least `Clipper.chost`
    // remaining DAI target. `chost` is an asynchronously updated value equal to
    // (Vat.dust * Dog.chop(ilk) / WAD) where the values are understood to be determined
    // by whatever they were when Clipper.upchost() was last called. Purchase amounts
    // will be minimally decreased when necessary to respect this limit; i.e., if the
    // specified `amt` would leave `tab < chost` but `tab > 0`, the amount actually
    // purchased will be such that `tab == chost`.
    //
    // If `tab <= chost`, partial purchases are no longer possible; that is, the remaining
    // collateral can only be purchased entirely, or not at all.
    function take(
        uint256 id,           // Auction id
        uint256 amt,          // Upper limit on amount of collateral to buy  [wad]
        uint256 max,          // Maximum acceptable price (DAI / collateral) [ray]
        address who,          // Receiver of collateral and external call address
        bytes calldata data   // Data to pass in external call; if length 0, no call is done
    ) external lock isStopped(3) {

        address usr = sales[id].usr;
        uint96  tic = sales[id].tic;

        require(usr != address(0), "Clipper/not-running-auction");

        uint256 price;
        {
            bool done;
            (done, price) = status(tic, sales[id].top);

            // Check that auction doesn't need reset
            require(!done, "Clipper/needs-reset");
        }

        // Ensure price is acceptable to buyer
        require(max >= price, "Clipper/too-expensive");

        uint256 lot = sales[id].lot;
        uint256 tab = sales[id].tab;
        uint256 owe;

        {
            // Purchase as much as possible, up to amt
            uint256 slice = min(lot, amt);  // slice <= lot

            // DAI needed to buy a slice of this sale
            owe = mul(slice, price);

            // Don't collect more than tab of DAI
            if (owe > tab) {
                // Total debt will be paid
                owe = tab;                  // owe' <= owe
                // Adjust slice
                slice = owe / price;        // slice' = owe' / price <= owe / price == slice <= lot
            } else if (owe < tab && slice < lot) {
                // If slice == lot => auction completed => dust doesn't matter
                uint256 _chost = chost;
                if (tab - owe < _chost) {    // safe as owe < tab
                    // If tab <= chost, buyers have to take the entire lot.
                    require(tab > _chost, "Clipper/no-partial-purchase");
                    // Adjust amount to pay
                    owe = tab - _chost;      // owe' <= owe
                    // Adjust slice
                    slice = owe / price;     // slice' = owe' / price < owe / price == slice < lot
                }
            }

            // Calculate remaining tab after operation
            tab = tab - owe;  // safe since owe <= tab
            // Calculate remaining lot after operation
            lot = lot - slice;

            // Send collateral to who
            vat.flux(ilk, address(this), who, slice);

            // Do external call (if data is defined) but to be
            // extremely careful we don't allow to do it to the two
            // contracts which the Clipper needs to be authorized
            Dog dog_ = dog;
            if (data.length > 0 && who != address(vat) && who != address(dog_)) {
                ClipperCallee(who).clipperCall(msg.sender, owe, slice, data);
            }

            // Get DAI from caller
            vat.move(msg.sender, vow, owe);

            // Removes Dai out for liquidation from accumulator
            dog_.digs(ilk, lot == 0 ? tab + owe : owe);
        }

        if (lot == 0) {
            _remove(id);
        } else if (tab == 0) {
            vat.flux(ilk, address(this), usr, lot);
            _remove(id);
        } else {
            sales[id].tab = tab;
            sales[id].lot = lot;
        }

        emit Take(id, max, price, owe, tab, lot, usr);
    }

    function _remove(uint256 id) internal {
        uint256 _move    = active[active.length - 1];
        if (id != _move) {
            uint256 _index   = sales[id].pos;
            active[_index]   = _move;
            sales[_move].pos = _index;
        }
        active.pop();
        delete sales[id];
    }

    // The number of active auctions
    function count() external view returns (uint256) {
        return active.length;
    }

    // Return the entire array of active auctions
    function list() external view returns (uint256[] memory) {
        return active;
    }

    // Externally returns boolean for if an auction needs a redo and also the current price
    function getStatus(uint256 id) external view returns (bool needsRedo, uint256 price, uint256 lot, uint256 tab) {
        // Read auction data
        address usr = sales[id].usr;
        uint96  tic = sales[id].tic;

        bool done;
        (done, price) = status(tic, sales[id].top);

        needsRedo = usr != address(0) && done;
        lot = sales[id].lot;
        tab = sales[id].tab;
    }

    // Internally returns boolean for if an auction needs a redo
    function status(uint96 tic, uint256 top) internal view returns (bool done, uint256 price) {
        price = calc.price(top, sub(block.timestamp, tic));
        done  = (sub(block.timestamp, tic) > tail || rdiv(price, top) < cusp);
    }

    // Public function to update the cached dust*chop value.
    function upchost() external {
        (,,,, uint256 _dust) = Vat(vat).ilks(ilk);
        chost = wmul(_dust, dog.chop(ilk));
    }

    // Cancel an auction during ES or via governance action.
    function yank(uint256 id) external auth lock {
        require(sales[id].usr != address(0), "Clipper/not-running-auction");
        dog.digs(ilk, sales[id].tab);
        vat.flux(ilk, address(this), msg.sender, sales[id].lot);
        _remove(id);
        emit Yank(id);
    }
}

// File: contracts/dss/dai.sol

// Copyright (C) 2017, 2018, 2019 dbrock, rain, mrchico

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

pragma solidity >=0.5.12;


contract Dai is DSNote {
    // --- Auth ---
    mapping (address => uint) public wards;
    function rely(address guy) external note auth { wards[guy] = 1; }
    function deny(address guy) external note auth { wards[guy] = 0; }
    modifier auth {
        require(wards[msg.sender] == 1, "Dai/not-authorized");
        _;
    }

    // --- ERC20 Data ---
    string  public constant name     = "Mor Stablecoin";
    string  public constant symbol   = "MOR";
    string  public constant version  = "1";
    uint8   public constant decimals = 18;
    uint256 public totalSupply;

    mapping (address => uint)                      public balanceOf;
    mapping (address => mapping (address => uint)) public allowance;
    mapping (address => uint)                      public nonces;

    event Approval(address indexed src, address indexed guy, uint wad);
    event Transfer(address indexed src, address indexed dst, uint wad);

    // --- Math ---
    function add(uint x, uint y) internal pure returns (uint z) {
        require((z = x + y) >= x);
    }
    function sub(uint x, uint y) internal pure returns (uint z) {
        require((z = x - y) <= x);
    }

    // --- EIP712 niceties ---
    bytes32 public DOMAIN_SEPARATOR;
    // bytes32 public constant PERMIT_TYPEHASH = keccak256("Permit(address holder,address spender,uint256 nonce,uint256 expiry,bool allowed)");
    bytes32 public constant PERMIT_TYPEHASH = 0xea2aa0a1be11a07ed86d755c93467f4f82362b452371d1ba94d1715123511acb;

    constructor(uint256 chainId_) public {
        wards[msg.sender] = 1;
        DOMAIN_SEPARATOR = keccak256(abi.encode(
            keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
            keccak256(bytes(name)),
            keccak256(bytes(version)),
            chainId_,
            address(this)
        ));
    }

    // --- Token ---
    function transfer(address dst, uint wad) external returns (bool) {
        return transferFrom(msg.sender, dst, wad);
    }
    function transferFrom(address src, address dst, uint wad)
        public returns (bool)
    {
        require(balanceOf[src] >= wad, "Dai/insufficient-balance");
        if (src != msg.sender && allowance[src][msg.sender] != uint(-1)) {
            require(allowance[src][msg.sender] >= wad, "Dai/insufficient-allowance");
            allowance[src][msg.sender] = sub(allowance[src][msg.sender], wad);
        }
        balanceOf[src] = sub(balanceOf[src], wad);
        balanceOf[dst] = add(balanceOf[dst], wad);
        emit Transfer(src, dst, wad);
        return true;
    }
    function mint(address usr, uint wad) external auth {
        balanceOf[usr] = add(balanceOf[usr], wad);
        totalSupply    = add(totalSupply, wad);
        emit Transfer(address(0), usr, wad);
    }
    function burn(address usr, uint wad) external {
        require(balanceOf[usr] >= wad, "Dai/insufficient-balance");
        if (usr != msg.sender && allowance[usr][msg.sender] != uint(-1)) {
            require(allowance[usr][msg.sender] >= wad, "Dai/insufficient-allowance");
            allowance[usr][msg.sender] = sub(allowance[usr][msg.sender], wad);
        }
        balanceOf[usr] = sub(balanceOf[usr], wad);
        totalSupply    = sub(totalSupply, wad);
        emit Transfer(usr, address(0), wad);
    }
    function approve(address usr, uint wad) external returns (bool) {
        allowance[msg.sender][usr] = wad;
        emit Approval(msg.sender, usr, wad);
        return true;
    }

    // --- Alias ---
    /*
    function push(address usr, uint wad) external {
        transferFrom(msg.sender, usr, wad);
    }
    function pull(address usr, uint wad) external {
        transferFrom(usr, msg.sender, wad);
    }
    function move(address src, address dst, uint wad) external {
        transferFrom(src, dst, wad);
    }
    */

    // --- Approve by signature ---
    function permit(address holder, address spender, uint256 nonce, uint256 expiry,
                    bool allowed, uint8 v, bytes32 r, bytes32 s) external
    {
        bytes32 digest =
            keccak256(abi.encodePacked(
                "\x19\x01",
                DOMAIN_SEPARATOR,
                keccak256(abi.encode(PERMIT_TYPEHASH,
                                     holder,
                                     spender,
                                     nonce,
                                     expiry,
                                     allowed))
        ));

        require(holder != address(0), "Dai/invalid-address-0");
        require(holder == ecrecover(digest, v, r, s), "Dai/invalid-permit");
        require(expiry == 0 || now <= expiry, "Dai/permit-expired");
        require(nonce == nonces[holder]++, "Dai/invalid-nonce");
        uint wad = allowed ? uint(-1) : 0;
        allowance[holder][spender] = wad;
        emit Approval(holder, spender, wad);
    }
}

// File: contracts/dss/join.sol

/// join.sol -- Basic token adapters

// Copyright (C) 2018 Rain <[email protected]>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

pragma solidity >=0.5.12;





/*
    Here we provide *adapters* to connect the Vat to arbitrary external
    token implementations, creating a bounded context for the Vat. The
    adapters here are provided as working examples:

      - `GemJoin`: For well behaved ERC20 tokens, with simple transfer
                   semantics.

      - `ETHJoin`: For native Ether.

      - `DaiJoin`: For connecting internal Dai balances to an external
                   `DSToken` implementation.

    In practice, adapter implementations will be varied and specific to
    individual collateral types, accounting for different transfer
    semantics and token standards.

    Adapters need to implement two basic methods:

      - `join`: enter collateral into the system
      - `exit`: remove collateral from the system

*/

contract GemJoin is DSNote {
    // --- Auth ---
    mapping (address => uint) public wards;
    function rely(address usr) external note auth { wards[usr] = 1; }
    function deny(address usr) external note auth { wards[usr] = 0; }
    modifier auth {
        require(wards[msg.sender] == 1, "GemJoin/not-authorized");
        _;
    }

    Vat     public vat;   // CDP Engine
    bytes32 public ilk;   // Collateral Type
    DSToken public gem;
    uint    public dec;
    uint    public live;  // Active Flag

    constructor(address vat_, bytes32 ilk_, address gem_) public {
        wards[msg.sender] = 1;
        live = 1;
        vat = Vat(vat_);
        ilk = ilk_;
        gem = DSToken(gem_);
        dec = gem.decimals();
    }
    function cage() external note auth {
        live = 0;
    }
    function join(address usr, uint wad) external note {
        require(live == 1, "GemJoin/not-live");
        require(int(wad) >= 0, "GemJoin/overflow");
        vat.slip(ilk, usr, int(wad));
        require(gem.transferFrom(msg.sender, address(this), wad), "GemJoin/failed-transfer");
    }
    function exit(address usr, uint wad) external note {
        require(wad <= 2 ** 255, "GemJoin/overflow");
        vat.slip(ilk, msg.sender, -int(wad));
        require(gem.transfer(usr, wad), "GemJoin/failed-transfer");
    }
}

contract DaiJoin is DSNote {
    // --- Auth ---
    mapping (address => uint) public wards;
    function rely(address usr) external note auth { wards[usr] = 1; }
    function deny(address usr) external note auth { wards[usr] = 0; }
    modifier auth {
        require(wards[msg.sender] == 1, "DaiJoin/not-authorized");
        _;
    }

    Vat     public vat;  // CDP Engine
    Dai     public dai;  // Stablecoin Token
    uint    public live; // Active Flag

    constructor(address vat_, address dai_) public {
        wards[msg.sender] = 1;
        live = 1;
        vat = Vat(vat_);
        dai = Dai(dai_);
    }
    function cage() external note auth {
        live = 0;
    }
    uint constant ONE = 10 ** 27;
    function mul(uint x, uint y) internal pure returns (uint z) {
        require(y == 0 || (z = x * y) / y == x);
    }
    function join(address usr, uint wad) external note {
        vat.move(address(this), usr, mul(ONE, wad));
        dai.burn(msg.sender, wad);
    }
    function exit(address usr, uint wad) external note {
        require(live == 1, "DaiJoin/not-live");
        vat.move(msg.sender, address(this), mul(ONE, wad));
        dai.mint(usr, wad);
    }
}

// File: contracts/link-oracle/link-oracle.sol

pragma solidity ^0.6.0;



// https://github.com/smartcontractkit/chainlink/blob/master/contracts/src/v0.6/interfaces/AggregatorV3Interface.sol
interface AggregatorV3Interface {
    function decimals() external view returns (uint8 _decimals);
    function latestRoundData() external view returns (uint80 _roundId, int256 _answer, uint256 _startedAt, uint256 _updatedAt, uint80 _answeredInRound);
}

contract LinkOracle is DSNote, PipLike {

    // --- Auth ---
    mapping (address => uint256) public wards;
    function rely(address _usr) external note auth { wards[_usr] = 1;  }
    function deny(address _usr) external note auth { wards[_usr] = 0; }
    modifier auth {
        require(wards[msg.sender] == 1, "LinkOracle/not-authorized");
        _;
    }

    // --- Math ---
    function mul(uint x, uint y) internal pure returns (uint z) {
        require(y == 0 || (z = x * y) / y == x);
    }

    address public immutable src;     // Price source
    uint256 public immutable factor;  // Price multiplier

    // --- Whitelisting ---
    mapping (address => uint256) public bud;
    modifier toll { require(bud[msg.sender] == 1, "LinkOracle/contract-not-whitelisted"); _; }

    constructor (address _src) public {
        require(_src  != address(0), "LinkOracle/invalid-src-address");
        uint8 _dec = AggregatorV3Interface(_src).decimals();
        require(_dec  <=         18, "LinkOracle/invalid-dec-places");
        wards[msg.sender] = 1;
        src  = _src;
        factor = 10 ** (18 - uint256(_dec));
    }

    function read() external view override toll returns (bytes32) {
        (,int256 price,,,) = AggregatorV3Interface(src).latestRoundData();
        require(price > 0, "LinkOracle/invalid-price-feed");
        return bytes32(mul(uint256(price), factor));
    }

    function peek() external view override toll returns (bytes32,bool) {
        (,int256 price,,,) = AggregatorV3Interface(src).latestRoundData();
        return (bytes32(mul(uint256(price), factor)), price > 0);
    }

    function kiss(address a) external note auth {
        require(a != address(0), "LinkOracle/no-contract-0");
        bud[a] = 1;
    }

    function diss(address a) external note auth {
        bud[a] = 0;
    }

    function kiss(address[] calldata a) external note auth {
        for(uint i = 0; i < a.length; i++) {
            require(a[i] != address(0), "LinkOracle/no-contract-0");
            bud[a[i]] = 1;
        }
    }

    function diss(address[] calldata a) external note auth {
        for(uint i = 0; i < a.length; i++) {
            bud[a[i]] = 0;
        }
    }
}

// File: contracts/univ2-lp-oracle/UNIV2LPOracle.sol

/// UNIV2LPOracle.sol

// Copyright (C) 2017-2020 Maker Ecosystem Growth Holdings, INC.

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

///////////////////////////////////////////////////////
//                                                   //
//    Methodology for Calculating LP Token Price     //
//                                                   //
///////////////////////////////////////////////////////

// A naïve approach to calculate the price of LP tokens, assuming the protocol
// fee is zero, is to compute the price of the assets locked in its liquidity
// pool, and divide it by the total amount of LP tokens issued:
//
// (p_0 * r_0 + p_1 * r_1) / LP_supply              (1)
//
// where r_0 and r_1 are the reserves of the two tokens held by the pool, and
// p_0 and p_1 are their respective prices in some reference unit of account.
//
// However, the price of LP tokens (i.e. pool shares) needs to be evaluated
// based on reserve values r_0 and r_1 that cannot be arbitraged, i.e. values
// that give the two halves of the pool equal economic value:
//
// r_0 * p_0 = r_1 * p_1                            (2)
// 
// Furthermore, two-asset constant product pools, neglecting fees, satisfy
// (before and after trades):
//
// r_0 * r_1 = k                                    (3)
//
// Using (2) and (3) we can compute R_i, the arbitrage-free reserve values, in a
// manner that depends only on k (which can be derived from the current reserve
// balances, even if they are far from equilibrium) and market prices p_i
// obtained from a trusted source:
//
// R_0 = sqrt(k * p_1 / p_0)                        (4)
//   and
// R_1 = sqrt(k * p_0 / p_1)                        (5)
//
// The value of an LP token is then, replacing (4) and (5) in (1):
//
// (p_0 * R_0 + p_1 * R_1) / LP_supply
//     = 2 * sqrt(k * p_0 * p_1) / LP_supply        (6)
//
// k can be re-expressed in terms of the current pool reserves r_0 and r_1:
//
// 2 * sqrt((r_0 * p_0) * (r_1 * p_1)) / LP_supply  (7)
//
// The structure of (7) is well-suited for use in fixed-point EVM calculations, as the
// terms (r_0 * p_0) and (r_1 * p_1), being the values of the reserves in the reference unit,
// should have reasonably-bounded sizes. This reduces the likelihood of overflow due to
// tokens with very low prices but large total supplies.

pragma solidity =0.6.12;



interface UniswapV2PairLike {
    function sync()        external;
    function token0()      external view returns (address);
    function token1()      external view returns (address);
    function getReserves() external view returns (uint112,uint112,uint32);  // reserve0, reserve1, blockTimestampLast
}

// Factory for creating Uniswap V2 LP Token Oracle instances
contract UNIV2LPOracleFactory {

    mapping(address => bool) public isOracle;

    event NewUNIV2LPOracle(address owner, address orcl, bytes32 wat, address indexed tok0, address indexed tok1, address orb0, address orb1);

    // Create new Uniswap V2 LP Token Oracle instance
    function build(
        address _owner,
        address _src,
        bytes32 _wat,
        address _orb0,
        address _orb1
        ) public returns (address orcl) {
        address tok0 = UniswapV2PairLike(_src).token0();
        address tok1 = UniswapV2PairLike(_src).token1();
        orcl = address(new UNIV2LPOracle(_src, _wat, _orb0, _orb1));
        UNIV2LPOracle(orcl).rely(_owner);
        UNIV2LPOracle(orcl).deny(address(this));
        isOracle[orcl] = true;
        emit NewUNIV2LPOracle(_owner, orcl, _wat, tok0, tok1, _orb0, _orb1);
    }
}

contract UNIV2LPOracle is PipLike {

    // --- Auth ---
    mapping (address => uint256) public wards;                                       // Addresses with admin authority
    function rely(address _usr) external auth { wards[_usr] = 1; emit Rely(_usr); }  // Add admin
    function deny(address _usr) external auth { wards[_usr] = 0; emit Deny(_usr); }  // Remove admin
    modifier auth {
        require(wards[msg.sender] == 1, "UNIV2LPOracle/not-authorized");
        _;
    }

    address public immutable src;   // Price source

    // hop and zph are packed into single slot to reduce SLOADs;
    // this outweighs the cost from added bitmasking operations.
    uint8   public stopped;         // Stop/start ability to update
    uint16  public hop = 1 hours;   // Minimum time in between price updates
    uint232 public zph;             // Time of last price update plus hop

    bytes32 public immutable wat;   // Label of token whose price is being tracked

    // --- Whitelisting ---
    mapping (address => uint256) public bud;
    modifier toll { require(bud[msg.sender] == 1, "UNIV2LPOracle/contract-not-whitelisted"); _; }

    struct Feed {
        uint128 val;  // Price
        uint128 has;  // Is price valid
    }

    Feed    internal cur;  // Current price  (mem slot 0x3)
    Feed    internal nxt;  // Queued price   (mem slot 0x4)

    // --- Data ---
    uint256 private immutable UNIT_0;  // Numerical representation of one token of token0 (10^decimals) 
    uint256 private immutable UNIT_1;  // Numerical representation of one token of token1 (10^decimals) 

    address public            orb0;  // Oracle for token0, ideally a Medianizer
    address public            orb1;  // Oracle for token1, ideally a Medianizer

    // --- Math ---
    uint256 constant WAD = 10 ** 18;

    function _add(uint256 _x, uint256 _y) internal pure returns (uint256 z) {
        require((z = _x + _y) >= _x, "UNIV2LPOracle/add-overflow");
    }
    function _sub(uint256 _x, uint256 _y) internal pure returns (uint256 z) {
        require((z = _x - _y) <= _x, "UNIV2LPOracle/sub-underflow");
    }
    function _mul(uint256 _x, uint256 _y) internal pure returns (uint256 z) {
        require(_y == 0 || (z = _x * _y) / _y == _x, "UNIV2LPOracle/mul-overflow");
    }

    // FROM https://github.com/abdk-consulting/abdk-libraries-solidity/blob/16d7e1dd8628dfa2f88d5dadab731df7ada70bdd/ABDKMath64x64.sol#L687
    function sqrt (uint256 _x) private pure returns (uint128) {
        if (_x == 0) return 0;
        else {
            uint256 xx = _x;
            uint256 r = 1;
            if (xx >= 0x100000000000000000000000000000000) { xx >>= 128; r <<= 64; }
            if (xx >= 0x10000000000000000) { xx >>= 64; r <<= 32; }
            if (xx >= 0x100000000) { xx >>= 32; r <<= 16; }
            if (xx >= 0x10000) { xx >>= 16; r <<= 8; }
            if (xx >= 0x100) { xx >>= 8; r <<= 4; }
            if (xx >= 0x10) { xx >>= 4; r <<= 2; }
            if (xx >= 0x8) { r <<= 1; }
            r = (r + _x / r) >> 1;
            r = (r + _x / r) >> 1;
            r = (r + _x / r) >> 1;
            r = (r + _x / r) >> 1;
            r = (r + _x / r) >> 1;
            r = (r + _x / r) >> 1;
            r = (r + _x / r) >> 1; // Seven iterations should be enough
            uint256 r1 = _x / r;
            return uint128 (r < r1 ? r : r1);
        }
    }

    // --- Events ---
    event Rely(address indexed usr);
    event Deny(address indexed usr);
    event Step(uint256 hop);
    event Stop();
    event Start();
    event Value(uint128 curVal, uint128 nxtVal);
    event Link(uint256 id, address orb);
    event Kiss(address a);
    event Diss(address a);

    // --- Init ---
    constructor (address _src, bytes32 _wat, address _orb0, address _orb1) public {
        require(_src  != address(0),                        "UNIV2LPOracle/invalid-src-address");
        require(_orb0 != address(0) && _orb1 != address(0), "UNIV2LPOracle/invalid-oracle-address");
        wards[msg.sender] = 1;
        emit Rely(msg.sender);
        src  = _src;
        wat  = _wat;
        uint256 dec0 = uint256(DSToken(UniswapV2PairLike(_src).token0()).decimals());
        require(dec0 <= 18, "UNIV2LPOracle/token0-dec-gt-18");
        UNIT_0 = 10 ** dec0;
        uint256 dec1 = uint256(DSToken(UniswapV2PairLike(_src).token1()).decimals());
        require(dec1 <= 18, "UNIV2LPOracle/token1-dec-gt-18");
        UNIT_1 = 10 ** dec1;
        orb0 = _orb0;
        orb1 = _orb1;
    }

    function stop() external auth {
        stopped = 1;
        delete cur;
        delete nxt;
        zph = 0;
        emit Stop();
    }

    function start() external auth {
        stopped = 0;
        emit Start();
    }

    function step(uint256 _hop) external auth {
        require(_hop <= uint16(-1), "UNIV2LPOracle/invalid-hop");
        hop = uint16(_hop);
        emit Step(_hop);
    }

    function link(uint256 _id, address _orb) external auth {
        require(_orb != address(0), "UNIV2LPOracle/no-contract-0");
        if(_id == 0) {
            orb0 = _orb;
        } else if (_id == 1) {
            orb1 = _orb;
        } else {
            revert("UNIV2LPOracle/invalid-id");
        }
        emit Link(_id, _orb);
    }

    // For consistency with other oracles.
    function zzz() external view returns (uint256) {
        if (zph == 0) return 0;  // backwards compatibility
        return _sub(zph, hop);
    }

    function pass() external view returns (bool) {
        return block.timestamp >= zph;
    }

    function seek() internal returns (uint128 quote) {
        // Sync up reserves of uniswap liquidity pool
        UniswapV2PairLike(src).sync();

        // Get reserves of uniswap liquidity pool
        (uint112 r0, uint112 r1,) = UniswapV2PairLike(src).getReserves();
        require(r0 > 0 && r1 > 0, "UNIV2LPOracle/invalid-reserves");

        // All Oracle prices are priced with 18 decimals against USD
        uint256 p0 = uint256(PipLike(orb0).read());  // Query token0 price from oracle (WAD)
        require(p0 != 0, "UNIV2LPOracle/invalid-oracle-0-price");
        uint256 p1 = uint256(PipLike(orb1).read());  // Query token1 price from oracle (WAD)
        require(p1 != 0, "UNIV2LPOracle/invalid-oracle-1-price");

        // Get LP token supply
        uint256 supply = DSToken(src).totalSupply();

        // This calculation should be overflow-resistant even for tokens with very high or very
        // low prices, as the dollar value of each reserve should lie in a fairly controlled range
        // regardless of the token prices.
        uint256 value0 = _mul(p0, uint256(r0)) / UNIT_0;  // WAD
        uint256 value1 = _mul(p1, uint256(r1)) / UNIT_1;  // WAD
        uint256 preq = _mul(2 * WAD, sqrt(_mul(value0, value1))) / supply;  // Will revert if supply == 0
        require(preq < 2 ** 128, "UNIV2LPOracle/quote-overflow");
        quote = uint128(preq);  // WAD
    }

    function poke() external {

        // Ensure a single SLOAD while avoiding solc's excessive bitmasking bureaucracy.
        uint256 hop_;
        {

            // Block-scoping these variables saves some gas.
            uint256 stopped_;
            uint256 zph_;
            assembly {
                let slot1 := sload(1)
                stopped_  := and(slot1,         0xff  )
                hop_      := and(shr(8, slot1), 0xffff)
                zph_      := shr(24, slot1)
            }

            // When stopped, values are set to zero and should remain such; thus, disallow updating in that case.
            require(stopped_ == 0, "UNIV2LPOracle/is-stopped");

            // Equivalent to requiring that pass() returns true.
            // The logic is repeated instead of calling pass() to save gas
            // (both by eliminating an internal call here, and allowing pass to be external).
            require(block.timestamp >= zph_, "UNIV2LPOracle/not-passed");
        }

        uint128 val = seek();
        require(val != 0, "UNIV2LPOracle/invalid-price");
        Feed memory cur_ = nxt;  // This memory value is used to save an SLOAD later.
        cur = cur_;
        nxt = Feed(val, 1);

        // The below is equivalent to:
        //
        //    zph = block.timestamp + hop
        //
        // but ensures no extra SLOADs are performed.
        //
        // Even if _hop = (2^16 - 1), the maximum possible value, add(timestamp(), _hop)
        // will not overflow (even a 232 bit value) for a very long time.
        //
        // Also, we know stopped was zero, so there is no need to account for it explicitly here.
        assembly {
            sstore(
                1,
                add(
                    // zph value starts 24 bits in
                    shl(24, add(timestamp(), hop_)),

                    // hop value starts 8 bits in
                    shl(8, hop_)
                )
            )
        }

        // Equivalent to emitting Value(cur.val, nxt.val), but averts extra SLOADs.
        emit Value(cur_.val, val);

        // Safe to terminate immediately since no postfix modifiers are applied.
        assembly {
            stop()
        }
    }

    function peek() external view override toll returns (bytes32,bool) {
        return (bytes32(uint256(cur.val)), cur.has == 1);
    }

    function peep() external view toll returns (bytes32,bool) {
        return (bytes32(uint256(nxt.val)), nxt.has == 1);
    }

    function read() external view override toll returns (bytes32) {
        require(cur.has == 1, "UNIV2LPOracle/no-current-value");
        return (bytes32(uint256(cur.val)));
    }

    function kiss(address _a) external auth {
        require(_a != address(0), "UNIV2LPOracle/no-contract-0");
        bud[_a] = 1;
        emit Kiss(_a);
    }

    function kiss(address[] calldata _a) external auth {
        for(uint256 i = 0; i < _a.length; i++) {
            require(_a[i] != address(0), "UNIV2LPOracle/no-contract-0");
            bud[_a[i]] = 1;
            emit Kiss(_a[i]);
        }
    }

    function diss(address _a) external auth {
        bud[_a] = 0;
        emit Diss(_a);
    }

    function diss(address[] calldata _a) external auth {
        for(uint256 i = 0; i < _a.length; i++) {
            bud[_a[i]] = 0;
            emit Diss(_a[i]);
        }
    }
}

// File: contracts/univ2-twap-oracle/univ2-twap-oracle.sol

pragma solidity ^0.6.0;





interface OracleLike
{
    function consultAveragePrice(address _pair, address _token, uint256 _amountIn) external view returns (uint256 _amountOut);
    function updateAveragePrice(address _pair) external;
}

contract UniV2TwapOracle is DSNote, PipLike {

    // --- Auth ---
    mapping (address => uint256) public wards;
    function rely(address _usr) external note auth { wards[_usr] = 1;  }
    function deny(address _usr) external note auth { wards[_usr] = 0; }
    modifier auth {
        require(wards[msg.sender] == 1, "UniV2TwapOracle/not-authorized");
        _;
    }

    // --- Math ---
    function mul(uint x, uint y) internal pure returns (uint z) {
        require(y == 0 || (z = x * y) / y == x);
    }

    address public immutable src;     // Price source (LP)
    address public immutable token;   // Token from the pair (the other must be PSM-pegged coin, like BUSD)
    uint256 public immutable cap;     // Price cap
    uint256 public immutable unit;    // Price unit
    uint256 public immutable factor;  // Price multiplier

    address public stwap;             // Short window TWAP implementation
    address public ltwap;             // Large window TWAP implementation

    address public orb;               // Optional oracle for the other token

    // --- Whitelisting ---
    mapping (address => uint256) public bud;
    modifier toll { require(bud[msg.sender] == 1, "UniV2TwapOracle/contract-not-whitelisted"); _; }

    constructor (address _stwap, address _ltwap, address _src, address _token, uint256 _cap, address _orb) public {
        require(_stwap != address(0), "UniV2TwapOracle/invalid-short-twap-address");
        require(_ltwap != address(0), "UniV2TwapOracle/invalid-long-twap-address");
        require(_src   != address(0), "UniV2TwapOracle/invalid-src-address");
        require(_token != address(0), "UniV2TwapOracle/invalid-token-address");
        address _token0 = UniswapV2PairLike(_src).token0();
        address _token1 = UniswapV2PairLike(_src).token1();
        require(_token == _token0 || _token == _token1, "UniV2TwapOracle/unknown-token-address");
        address _otherToken = _token == _token0 ? _token1 : _token0;
        uint8 _dec = DSToken(_token).decimals();
        require(_dec   <=         18, "UniV2TwapOracle/invalid-dec-places");
        uint8 _odec = DSToken(_otherToken).decimals();
        require(_odec  <=         18, "UniV2TwapOracle/invalid-other-dec-places");
        wards[msg.sender] = 1;
        stwap = _stwap;
        ltwap = _ltwap;
        src  = _src;
        token = _token;
        cap = _cap > 0 ? _cap : uint256(-1);
        unit = 10 ** uint256(_dec);
        factor = 10 ** (18 - uint256(_odec));
        orb = _orb;
    }

    function link(uint256 _id, address _twapOrOrb) external note auth {
        require(_twapOrOrb != address(0), "UniV2TwapOracle/no-contract");
        if(_id == 0) {
            stwap = _twapOrOrb;
        } else if (_id == 1) {
            ltwap = _twapOrOrb;
        } else if (_id == 2) {
            orb = _twapOrOrb;
        } else {
            revert("UniV2TwapOracle/invalid-id");
        }
    }

    function poke() external {
        OracleLike(stwap).updateAveragePrice(src);
        OracleLike(ltwap).updateAveragePrice(src);
    }

    function read() external view override toll returns (bytes32) {
        uint256 sprice = OracleLike(stwap).consultAveragePrice(src, token, unit);
        uint256 lprice = OracleLike(ltwap).consultAveragePrice(src, token, unit);
        uint256 price = sprice < lprice ? sprice : lprice;
        if (price > cap) price = cap;
        require(price > 0, "UniV2TwapOracle/invalid-price-feed");
        uint256 fprice = mul(price, factor);
        if (orb != address(0)) {
          uint256 oprice = uint256(PipLike(orb).read());
          require(oprice > 0, "UniV2TwapOracle/invalid-oracle-price");
          fprice = mul(fprice, oprice) / 1e18;
        }
        return bytes32(fprice);
    }

    function peek() external view override toll returns (bytes32,bool) {
        uint256 sprice = OracleLike(stwap).consultAveragePrice(src, token, unit);
        uint256 lprice = OracleLike(ltwap).consultAveragePrice(src, token, unit);
        uint256 price = sprice < lprice ? sprice : lprice;
        if (price > cap) price = cap;
        uint256 fprice = mul(price, factor);
        if (orb != address(0)) {
          (bytes32 _oprice, bool valid) = PipLike(orb).peek();
          uint256 oprice = valid ? uint256(_oprice) : 0;
          fprice = mul(fprice, oprice) / 1e18;
        }
        return (bytes32(fprice), fprice > 0);
    }

    function kiss(address a) external note auth {
        require(a != address(0), "UniV2TwapOracle/no-contract-0");
        bud[a] = 1;
    }

    function diss(address a) external note auth {
        bud[a] = 0;
    }

    function kiss(address[] calldata a) external note auth {
        for(uint i = 0; i < a.length; i++) {
            require(a[i] != address(0), "UniV2TwapOracle/no-contract-0");
            bud[a[i]] = 1;
        }
    }

    function diss(address[] calldata a) external note auth {
        for(uint i = 0; i < a.length; i++) {
            bud[a[i]] = 0;
        }
    }
}

// File: contracts/vault-oracle/vault-oracle.sol

pragma solidity ^0.6.0;




interface VaultLike {
    function totalSupply() external view returns (uint256 _totalSupply);
    function totalReserve() external view returns (uint256 _totalReserve);
}

contract VaultOracle is DSNote, PipLike {

    // --- Auth ---
    mapping (address => uint256) public wards;
    function rely(address _usr) external note auth { wards[_usr] = 1;  }
    function deny(address _usr) external note auth { wards[_usr] = 0; }
    modifier auth {
        require(wards[msg.sender] == 1, "VaultOracle/not-authorized");
        _;
    }

    // --- Math ---
    function mul(uint x, uint y) internal pure returns (uint z) {
        require(y == 0 || (z = x * y) / y == x);
    }

    address public immutable vault;  // vault for which shares are being priced

    address public orb;              // oracle for the reserve token

    // --- Whitelisting ---
    mapping (address => uint256) public bud;
    modifier toll { require(bud[msg.sender] == 1, "VaultOracle/contract-not-whitelisted"); _; }

    constructor (address _vault, address _reserve, address _orb) public {
        require(_vault   != address(0), "VaultOracle/invalid-vault-address");
        require(_reserve != address(0), "VaultOracle/invalid-reserve-address");
        require(_orb     != address(0), "VaultOracle/invalid-oracle-address");
        require(DSToken(_vault).decimals() == DSToken(_reserve).decimals(), "VaultOracle/token-dec-mismatch");
        wards[msg.sender] = 1;
        vault = _vault;
        orb = _orb;
    }

    function link(address _orb) external note auth {
        require(_orb != address(0), "VaultOracle/no-contract");
        orb = _orb;
    }

    function read() external view override toll returns (bytes32) {
        uint256 reservePrice = uint256(PipLike(orb).read());
        require(reservePrice != 0, "VaultOracle/invalid-oracle-price");

        uint256 reserve = VaultLike(vault).totalReserve();
        uint256 supply = VaultLike(vault).totalSupply();
        require(reserve > 0 && supply > 0, "VaultOracle/empty-vault");

        uint256 sharePrice = mul(reservePrice, reserve) / supply;
        require(sharePrice > 0, "VaultOracle/invalid-price-feed");

        return bytes32(sharePrice);
    }

    function peek() external view override toll returns (bytes32,bool) {
        (bytes32 _reservePrice, bool valid) = PipLike(orb).peek();
        uint256 reservePrice = uint256(_reservePrice);
        if (valid) valid = reservePrice != 0;

        uint256 reserve = VaultLike(vault).totalReserve();
        uint256 supply = VaultLike(vault).totalSupply();
        if (valid) valid = reserve > 0 && supply > 0;

        uint256 sharePrice = supply > 0 ? mul(reservePrice, reserve) / supply : 0;
        if (valid) valid = sharePrice > 0;

        return (bytes32(sharePrice), valid);
    }

    function kiss(address a) external note auth {
        require(a != address(0), "VaultOracle/no-contract-0");
        bud[a] = 1;
    }

    function diss(address a) external note auth {
        bud[a] = 0;
    }

    function kiss(address[] calldata a) external note auth {
        for(uint i = 0; i < a.length; i++) {
            require(a[i] != address(0), "VaultOracle/no-contract-0");
            bud[a[i]] = 1;
        }
    }

    function diss(address[] calldata a) external note auth {
        for(uint i = 0; i < a.length; i++) {
            bud[a[i]] = 0;
        }
    }
}

// File: contracts/ratecap-oracle/ratecap-oracle.sol

pragma solidity ^0.6.12;




interface INonViewableRateProvider
{
	function getRate() external returns (uint256 _rate);
}

contract RateCapOracle is PipLike {

    // --- Auth ---
    mapping (address => uint256) public wards;                                       // Addresses with admin authority
    function rely(address _usr) external auth { wards[_usr] = 1; emit Rely(_usr); }  // Add admin
    function deny(address _usr) external auth { wards[_usr] = 0; emit Deny(_usr); }  // Remove admin
    modifier auth {
        require(wards[msg.sender] == 1, "RateCapOracle/not-authorized");
        _;
    }

    address public src;   // Price source
    address public cap;   // Price cap source

    // hop and zph are packed into single slot to reduce SLOADs;
    // this outweighs the cost from added bitmasking operations.
    uint8   public stopped;         // Stop/start ability to update
    uint16  public hop = 1 hours;   // Minimum time in between price updates
    uint232 public zph;             // Time of last price update plus hop

    // --- Whitelisting ---
    mapping (address => uint256) public bud;
    modifier toll { require(bud[msg.sender] == 1, "RateCapOracle/contract-not-whitelisted"); _; }

    struct Feed {
        uint256 val;  // Price
        bool    has;  // Is price valid
    }

    Feed    internal cur;  // Current price
    Feed    internal nxt;  // Queued price

    address public            orb;   // Oracle for quote token

    function _sub(uint256 _x, uint256 _y) internal pure returns (uint256 z) {
        require((z = _x - _y) <= _x, "RateCapOracle/sub-underflow");
    }
    function _mul(uint256 _x, uint256 _y) internal pure returns (uint256 z) {
        require(_y == 0 || (z = _x * _y) / _y == _x, "RateCapOracle/mul-overflow");
    }

    // --- Events ---
    event Rely(address indexed usr);
    event Deny(address indexed usr);
    event Step(uint256 hop);
    event Stop();
    event Start();
    event Value(uint256 curVal, uint256 nxtVal);
    event Link(uint256 id, address val);
    event Kiss(address a);
    event Diss(address a);

    // --- Init ---
    constructor (address _src, address _cap, address _orb) public {
        require(_src != address(0), "RateCapOracle/invalid-src-address");
        require(_cap != address(0), "RateCapOracle/invalid-cap-address");
        require(_orb != address(0), "RateCapOracle/invalid-oracle-address");
        wards[msg.sender] = 1;
        emit Rely(msg.sender);
        src  = _src;
        cap  = _cap;
        orb = _orb;
    }

    function stop() external auth {
        stopped = 1;
        delete cur;
        delete nxt;
        zph = 0;
        emit Stop();
    }

    function start() external auth {
        stopped = 0;
        emit Start();
    }

    function step(uint256 _hop) external auth {
        require(_hop <= uint16(-1), "RateCapOracle/invalid-hop");
        hop = uint16(_hop);
        emit Step(_hop);
    }

    function link(uint256 _id, address _val) external auth {
        require(_val != address(0), "RateCapOracle/no-contract-0");
        if(_id == 0) {
            src = _val;
        } else if (_id == 1) {
            cap = _val;
        } else if (_id == 2) {
            orb = _val;
        } else {
            revert("RateCapOracle/invalid-id");
        }
        emit Link(_id, _val);
    }

    // For consistency with other oracles.
    function zzz() external view returns (uint256) {
        if (zph == 0) return 0;  // backwards compatibility
        return _sub(zph, hop);
    }

    function pass() external view returns (bool) {
        return block.timestamp >= zph;
    }

    function seek() internal returns (uint256 quote) {
        // All rates are priced assuming 18 decimals
        // Get rate from liquidity pool (WAD)
	uint256 v = INonViewableRateProvider(src).getRate();
        require(v != 0, "RateCapOracle/invalid-src-price");
        // Get rate from limiter (WAD)
	uint256 l = INonViewableRateProvider(cap).getRate();
        require(l != 0, "RateCapOracle/invalid-cap-price");
        // Applies the cap
	if (v > l) v = l;
        // All Oracle prices are priced with 18 decimals against USD
        uint256 p = uint256(PipLike(orb).read());  // Query quote token price from oracle (WAD)
        require(p != 0, "RateCapOracle/invalid-oracle-price");
        return _mul(v, p) / 1e18;
    }

    function poke() external {
        // When stopped, values are set to zero and should remain such; thus, disallow updating in that case.
        require(stopped == 0, "RateCapOracle/is-stopped");
        // Equivalent to requiring that pass() returns true.
        // The logic is repeated instead of calling pass() to save gas
        // (both by eliminating an internal call here, and allowing pass to be external).
        require(block.timestamp >= zph, "RateCapOracle/not-passed");
        uint256 val = seek();
        require(val != 0, "RateCapOracle/invalid-price");
        cur = nxt;
        nxt = Feed(val, true);
        emit Value(cur.val, nxt.val);
    }

    function peek() external view override toll returns (bytes32,bool) {
        return (bytes32(uint256(cur.val)), cur.has);
    }

    function peep() external view toll returns (bytes32,bool) {
        return (bytes32(uint256(nxt.val)), nxt.has);
    }

    function read() external view override toll returns (bytes32) {
        require(cur.has, "RateCapOracle/no-current-value");
        return (bytes32(uint256(cur.val)));
    }

    function kiss(address _a) external auth {
        require(_a != address(0), "RateCapOracle/no-contract-0");
        bud[_a] = 1;
        emit Kiss(_a);
    }

    function kiss(address[] calldata _a) external auth {
        for(uint256 i = 0; i < _a.length; i++) {
            require(_a[i] != address(0), "RateCapOracle/no-contract-0");
            bud[_a[i]] = 1;
            emit Kiss(_a[i]);
        }
    }

    function diss(address _a) external auth {
        bud[_a] = 0;
        emit Diss(_a);
    }

    function diss(address[] calldata _a) external auth {
        for(uint256 i = 0; i < _a.length; i++) {
            bud[_a[i]] = 0;
            emit Diss(_a[i]);
        }
    }
}

// File: contracts/dss-spells/dss-spell-ftmmain-2022-05-05.sol

pragma solidity ^0.6.12;












contract DssSpellAction_ftmmain_2022_05_05 is DssAction
{
	// Hash: seth keccak -- "$(wget https://raw.githubusercontent.com/GrowthDeFi/community/master/governance/votes/Executive%20vote%20-%20May%205%2C%202022.md -q -O - 2>/dev/null)"
	string public constant override description =
		"2022-05-05 GrowthDeFi Executive Spell | Hash: 0xb45c7455ecaf8470c61131c13d2c5c19efdc6e1fa355cccd6e43146452b1daef";

	address constant PIP_BOO = 0x44B0234Eb02443E7B7d1f0EFd9a30eB269E1C859;
	address constant T_XBOO = 0xa48d959AE2E88f1dAA7D5F611E01908106dE7598;
	address constant PIP_XBOO = 0x8f821768282F867C9EEeFbA8CCdA1ca1888c9F8b;

	address constant T_LINSPIRIT = 0xc5713B6a0F26bf0fdC1c52B90cd184D950be515C;
	address constant PIP_LINSPIRIT = 0x87930d19B4C98DD08B8B30793D4fB38cE9B6451d;

	address constant T_STKXBOO = 0x30463d33735677B4E70f956e3dd61c6e94D70DFe;
	address constant PIP_STKXBOO = 0x5D6892332C3BB313d10d3a50413b4e2B79CF3269;
	address constant MCD_JOIN_STKXBOO_A = 0xcbCFC27be6b2eD4eD261AD0E6212534a08c7B1F6;
	address constant MCD_CLIP_STKXBOO_A = 0x52Ee6fBecDd709AD1936e3241946B786979520A1;
	address constant MCD_CLIP_CALC_STKXBOO_A = 0xaf760e33a3a27F54aC018F780aaE06356b70da86;

	address constant PIP_SPOFTMBOO = 0xca70528209917F4D0443Dd3e90C863b19584CCAF;
	address constant T_STKSPOFTMBOOV2 = 0xaebd31E9FFcB222feE947f22369257cEcf1F96CA;
	address constant PIP_STKSPOFTMBOOV2 = 0xbCe5a62C49fcDfe9f834d40c41692612C8CfcE39;
	address constant MCD_JOIN_STKSPOFTMBOOV2_A = 0x7c414040fDd78c4d37131B1C59d051d56bee8645;
	address constant MCD_CLIP_STKSPOFTMBOOV2_A = 0xe55FB11e8322D663Fc2210c5CA8D85D9774A6d36;
	address constant MCD_CLIP_CALC_STKSPOFTMBOOV2_A = 0xA58E169f1C0503f9e736727A427EBf3a061647C7;

	address constant PIP_LQDR = 0x3d4604395595Bb30A8B7754b5dDBF0B3F680564b;
	address constant T_CLQDR = 0x814c66594a22404e101FEcfECac1012D8d75C156;
	address constant PIP_CLQDR = 0x91EF85162F18c038f0dC1e01a7a2F4191b2c6ce6;
	address constant MCD_JOIN_CLQDR_A = 0xe5fb3D583660e57b1f616f89Ae98dfb6e3c37f99;
	address constant MCD_CLIP_CLQDR_A = 0xBfc0a4714C8de532F5a2E9c20185752a902cD262;
	address constant MCD_CLIP_CALC_CLQDR_A = 0x5559771B806099bBc65867b79F971a2601FedD04;

	address constant PIP_SPIRIT = 0x5F6025D6514C6396D4Ba640d6F93966AF5b139B0;
	address constant T_SLINSPIRIT = 0x3F569724ccE63F7F24C5F921D5ddcFe125Add96b;
	address constant PIP_SLINSPIRIT = 0x6296e0B0dD895a66048022131F85653B0C2C3489;
	address constant MCD_JOIN_SLINSPIRIT_A = 0x726d946BBF3d0E6f9e5078D4F5e1f0014c37288F;
	address constant MCD_CLIP_SLINSPIRIT_A = 0x0e7482C50048628858d54AeC7af097765899a0b6;
	address constant MCD_CLIP_CALC_SLINSPIRIT_A = 0xb03d7418bBa8AFD553b8Fa7AED1fE044eFc52950;

	function actions() public override
	{
		// Bumps changelog version
		DssExecLib.setChangelogVersion("1.0.3");

		// ----- ADDS A NEW COLLATERAL STKXBOO -----
		{
			bytes32 _ilk = "STKXBOO-A";

			UniV2TwapOracle(PIP_BOO).kiss(PIP_XBOO);

			// configures the calc
			DssExecLib.setStairstepExponentialDecrease(MCD_CLIP_CALC_STKXBOO_A, 180 seconds, 99_00);

			// wires and configure the new collateral
			CollateralOpts memory co;
			co.ilk = _ilk;
			co.gem = T_STKXBOO;
			co.join = MCD_JOIN_STKXBOO_A;
			co.clip = MCD_CLIP_STKXBOO_A;
			co.calc = MCD_CLIP_CALC_STKXBOO_A;
			co.pip = PIP_STKXBOO;
			co.isLiquidatable = true;
			co.isOSM = false;
			co.whitelistOSM = false;
			co.liquidationRatio = 167_00; // mat
			co.ilkDebtCeiling = 500000; // line
			co.minVaultAmount = 100; // dust
			co.ilkStabilityFee = 1e27; // duty 0%
			co.liquidationPenalty = 15_00; // chop
			co.maxLiquidationAmount = 100000000; // hole
			//co.kprPctReward = 0_00; // chip
			co.kprFlatReward = 5; // tip
			co.startingPriceFactor = 130_00; // buf
			co.auctionDuration = 16800 seconds; // tail
			co.permittedDrop = 40_00; // cusp
			co.breakerTolerance = 50_00; // cm_tolerance
			DssExecLib.addNewCollateral(co);

			// pokes spotter
			DssExecLib.updateCollateralPrice(_ilk);

			// updates change log
			DssExecLib.setChangelogAddress("XBOO", T_XBOO);
			DssExecLib.setChangelogAddress("PIP_XBOO", PIP_XBOO);

			DssExecLib.setChangelogAddress("STKXBOO", T_STKXBOO);
			DssExecLib.setChangelogAddress("PIP_STKXBOO", PIP_STKXBOO);
			DssExecLib.setChangelogAddress("MCD_JOIN_STKXBOO_A", MCD_JOIN_STKXBOO_A);
			DssExecLib.setChangelogAddress("MCD_CLIP_STKXBOO_A", MCD_CLIP_STKXBOO_A);
			DssExecLib.setChangelogAddress("MCD_CLIP_CALC_STKXBOO_A", MCD_CLIP_CALC_STKXBOO_A);
		}

		// ----- ADDS A NEW COLLATERAL STKSPOFTMBOOV2 -----
		{
			bytes32 _ilk = "STKSPOFTMBOOV2-A";

			UNIV2LPOracle(PIP_SPOFTMBOO).kiss(PIP_STKSPOFTMBOOV2);

			// configures the calc
			DssExecLib.setStairstepExponentialDecrease(MCD_CLIP_CALC_STKSPOFTMBOOV2_A, 180 seconds, 99_00);

			// wires and configure the new collateral
			CollateralOpts memory co;
			co.ilk = _ilk;
			co.gem = T_STKSPOFTMBOOV2;
			co.join = MCD_JOIN_STKSPOFTMBOOV2_A;
			co.clip = MCD_CLIP_STKSPOFTMBOOV2_A;
			co.calc = MCD_CLIP_CALC_STKSPOFTMBOOV2_A;
			co.pip = PIP_STKSPOFTMBOOV2;
			co.isLiquidatable = true;
			co.isOSM = false;
			co.whitelistOSM = false;
			co.liquidationRatio = 167_00; // mat
			co.ilkDebtCeiling = 500000; // line
			co.minVaultAmount = 100; // dust
			co.ilkStabilityFee = 1e27; // duty 0%
			co.liquidationPenalty = 15_00; // chop
			co.maxLiquidationAmount = 100000000; // hole
			//co.kprPctReward = 0_00; // chip
			co.kprFlatReward = 5; // tip
			co.startingPriceFactor = 130_00; // buf
			co.auctionDuration = 16800 seconds; // tail
			co.permittedDrop = 40_00; // cusp
			co.breakerTolerance = 50_00; // cm_tolerance
			DssExecLib.addNewCollateral(co);

			// pokes spotter
			DssExecLib.updateCollateralPrice(_ilk);

			// updates change log
			DssExecLib.setChangelogAddress("STKSPOFTMBOOV2", T_STKSPOFTMBOOV2);
			DssExecLib.setChangelogAddress("PIP_STKSPOFTMBOOV2", PIP_STKSPOFTMBOOV2);
			DssExecLib.setChangelogAddress("MCD_JOIN_STKSPOFTMBOOV2_A", MCD_JOIN_STKSPOFTMBOOV2_A);
			DssExecLib.setChangelogAddress("MCD_CLIP_STKSPOFTMBOOV2_A", MCD_CLIP_STKSPOFTMBOOV2_A);
			DssExecLib.setChangelogAddress("MCD_CLIP_CALC_STKSPOFTMBOOV2_A", MCD_CLIP_CALC_STKSPOFTMBOOV2_A);
		}

		// ----- ADDS A NEW COLLATERAL CLQDR -----
		{
			bytes32 _ilk = "CLQDR-A";

			UniV2TwapOracle(PIP_LQDR).kiss(PIP_CLQDR);

			// configures the calc
			DssExecLib.setStairstepExponentialDecrease(MCD_CLIP_CALC_CLQDR_A, 180 seconds, 99_00);

			// wires and configure the new collateral
			CollateralOpts memory co;
			co.ilk = _ilk;
			co.gem = T_CLQDR;
			co.join = MCD_JOIN_CLQDR_A;
			co.clip = MCD_CLIP_CLQDR_A;
			co.calc = MCD_CLIP_CALC_CLQDR_A;
			co.pip = PIP_CLQDR;
			co.isLiquidatable = true;
			co.isOSM = false;
			co.whitelistOSM = false;
			co.liquidationRatio = 200_00; // mat
			co.ilkDebtCeiling = 80000; // line
			co.minVaultAmount = 100; // dust
			co.ilkStabilityFee = 1e27; // duty 0%
			co.liquidationPenalty = 15_00; // chop
			co.maxLiquidationAmount = 100000000; // hole
			//co.kprPctReward = 0_00; // chip
			co.kprFlatReward = 5; // tip
			co.startingPriceFactor = 130_00; // buf
			co.auctionDuration = 16800 seconds; // tail
			co.permittedDrop = 40_00; // cusp
			co.breakerTolerance = 50_00; // cm_tolerance
			DssExecLib.addNewCollateral(co);

			// pokes spotter
			DssExecLib.updateCollateralPrice(_ilk);

			// updates change log
			DssExecLib.setChangelogAddress("CLQDR", T_CLQDR);
			DssExecLib.setChangelogAddress("PIP_CLQDR", PIP_CLQDR);
			DssExecLib.setChangelogAddress("MCD_JOIN_CLQDR_A", MCD_JOIN_CLQDR_A);
			DssExecLib.setChangelogAddress("MCD_CLIP_CLQDR_A", MCD_CLIP_CLQDR_A);
			DssExecLib.setChangelogAddress("MCD_CLIP_CALC_CLQDR_A", MCD_CLIP_CALC_CLQDR_A);
		}

		// ----- ADDS A NEW COLLATERAL SLINSPIRIT -----
		{
			bytes32 _ilk = "SLINSPIRIT-A";

			UniV2TwapOracle(PIP_SPIRIT).kiss(PIP_LINSPIRIT);

			// configures the calc
			DssExecLib.setStairstepExponentialDecrease(MCD_CLIP_CALC_SLINSPIRIT_A, 180 seconds, 99_00);

			// wires and configure the new collateral
			CollateralOpts memory co;
			co.ilk = _ilk;
			co.gem = T_SLINSPIRIT;
			co.join = MCD_JOIN_SLINSPIRIT_A;
			co.clip = MCD_CLIP_SLINSPIRIT_A;
			co.calc = MCD_CLIP_CALC_SLINSPIRIT_A;
			co.pip = PIP_SLINSPIRIT;
			co.isLiquidatable = true;
			co.isOSM = false;
			co.whitelistOSM = false;
			co.liquidationRatio = 167_00; // mat
			co.ilkDebtCeiling = 200000; // line
			co.minVaultAmount = 100; // dust
			co.ilkStabilityFee = 1000000001547125871859122981; // duty 5%
			co.liquidationPenalty = 15_00; // chop
			co.maxLiquidationAmount = 100000000; // hole
			//co.kprPctReward = 0_00; // chip
			co.kprFlatReward = 5; // tip
			co.startingPriceFactor = 130_00; // buf
			co.auctionDuration = 16800 seconds; // tail
			co.permittedDrop = 40_00; // cusp
			co.breakerTolerance = 50_00; // cm_tolerance
			DssExecLib.addNewCollateral(co);

			// pokes spotter
			DssExecLib.updateCollateralPrice(_ilk);

			// updates change log
			DssExecLib.setChangelogAddress("LINSPIRIT", T_LINSPIRIT);
			DssExecLib.setChangelogAddress("PIP_LINSPIRIT", PIP_LINSPIRIT);

			DssExecLib.setChangelogAddress("SLINSPIRIT", T_SLINSPIRIT);
			DssExecLib.setChangelogAddress("PIP_SLINSPIRIT", PIP_SLINSPIRIT);
			DssExecLib.setChangelogAddress("MCD_JOIN_SLINSPIRIT_A", MCD_JOIN_SLINSPIRIT_A);
			DssExecLib.setChangelogAddress("MCD_CLIP_SLINSPIRIT_A", MCD_CLIP_SLINSPIRIT_A);
			DssExecLib.setChangelogAddress("MCD_CLIP_CALC_SLINSPIRIT_A", MCD_CLIP_CALC_SLINSPIRIT_A);
		}
	}
}

// valid for 30 days
contract DssSpell_ftmmain_2022_05_05 is DssExec(block.timestamp + 30 days, address(new DssSpellAction_ftmmain_2022_05_05()))
{
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_src","type":"address"},{"internalType":"address","name":"_cap","type":"address"},{"internalType":"address","name":"_orb","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"usr","type":"address"}],"name":"Deny","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"a","type":"address"}],"name":"Diss","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"a","type":"address"}],"name":"Kiss","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"address","name":"val","type":"address"}],"name":"Link","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"usr","type":"address"}],"name":"Rely","type":"event"},{"anonymous":false,"inputs":[],"name":"Start","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"hop","type":"uint256"}],"name":"Step","type":"event"},{"anonymous":false,"inputs":[],"name":"Stop","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"curVal","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nxtVal","type":"uint256"}],"name":"Value","type":"event"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"bud","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cap","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_usr","type":"address"}],"name":"deny","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_a","type":"address[]"}],"name":"diss","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_a","type":"address"}],"name":"diss","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"hop","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_a","type":"address[]"}],"name":"kiss","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_a","type":"address"}],"name":"kiss","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"address","name":"_val","type":"address"}],"name":"link","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"orb","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pass","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"peek","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"peep","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poke","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"read","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_usr","type":"address"}],"name":"rely","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"src","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"start","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_hop","type":"uint256"}],"name":"step","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stopped","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"wards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"zph","outputs":[{"internalType":"uint232","name":"","type":"uint232"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"zzz","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

6080604052610e10600260156101000a81548161ffff021916908361ffff1602179055503480156200003057600080fd5b5060405162002b1438038062002b14833981810160405281019062000056919062000319565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415620000c9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620000c090620004a7565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156200013c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200013390620004eb565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415620001af576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620001a690620004c9565b60405180910390fd5b60016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055503373ffffffffffffffffffffffffffffffffffffffff167fdd0e34038ac38b2a1ce960229778ac48a8719bc900b6c4f8d0475c6e8b385a6060405160405180910390a282600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600960006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050506200056c565b600081519050620003138162000552565b92915050565b6000806000606084860312156200032f57600080fd5b60006200033f8682870162000302565b9350506020620003528682870162000302565b9250506040620003658682870162000302565b9150509250925092565b60006200037e6021836200050d565b91507f526174654361704f7261636c652f696e76616c69642d7372632d61646472657360008301527f73000000000000000000000000000000000000000000000000000000000000006020830152604082019050919050565b6000620003e66024836200050d565b91507f526174654361704f7261636c652f696e76616c69642d6f7261636c652d61646460008301527f72657373000000000000000000000000000000000000000000000000000000006020830152604082019050919050565b60006200044e6021836200050d565b91507f526174654361704f7261636c652f696e76616c69642d6361702d61646472657360008301527f73000000000000000000000000000000000000000000000000000000000000006020830152604082019050919050565b60006020820190508181036000830152620004c2816200036f565b9050919050565b60006020820190508181036000830152620004e481620003d7565b9050919050565b6000602082019050818103600083015262000506816200043f565b9050919050565b600082825260208201905092915050565b60006200052b8262000532565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6200055d816200051e565b81146200056957600080fd5b50565b612598806200057c6000396000f3fe608060405234801561001057600080fd5b50600436106101585760003560e01c806365c4ce7a116100c3578063a9c52a391161007c578063a9c52a3914610357578063b0b8579b14610375578063be9a655514610393578063bf353dbb1461039d578063f29c29c4146103cd578063ff910783146103e957610158565b806365c4ce7a146102a957806365fae35e146102c557806375f12b21146102e15780639c52a7f1146102ff578063a4dff0a21461031b578063a7a1ed721461033957610158565b80633a1cde75116101155780633a1cde75146101e857806346d4577d146102045780634fce7a2a1461022057806357de26a41461025057806359e02dd71461026e57806365af79091461028d57610158565b806307da68f51461015d5780630e5a6c701461016757806318178358146101865780631b25b65f146101905780632e7dc6af146101ac578063355274ea146101ca575b600080fd5b610165610407565b005b61016f610568565b60405161017d9291906121cf565b60405180910390f35b61018e610611565b005b6101aa60048036038101906101a59190611c4d565b61080e565b005b6101b46109fb565b6040516101c1919061217e565b60405180910390f35b6101d2610a21565b6040516101df919061217e565b60405180910390f35b61020260048036038101906101fd9190611cbb565b610a47565b005b61021e60048036038101906102199190611c4d565b610b86565b005b61023a60048036038101906102359190611c24565b610ce3565b60405161024791906123ee565b60405180910390f35b610258610cfb565b60405161026591906121b4565b60405180910390f35b610276610ddf565b6040516102849291906121cf565b60405180910390f35b6102a760048036038101906102a29190611d0d565b610e88565b005b6102c360048036038101906102be9190611c24565b6110e0565b005b6102df60048036038101906102da9190611c24565b6111e0565b005b6102e96112eb565b6040516102f6919061245b565b60405180910390f35b61031960048036038101906103149190611c24565b6112fe565b005b610323611409565b60405161033091906123ee565b60405180910390f35b6103416114d4565b60405161034e9190612199565b60405180910390f35b61035f611529565b60405161036c91906123d3565b60405180910390f35b61037d611558565b60405161038a91906123b8565b60405180910390f35b61039b61156c565b005b6103b760048036038101906103b29190611c24565b611637565b6040516103c491906123ee565b60405180910390f35b6103e760048036038101906103e29190611c24565b61164f565b005b6103f16117bf565b6040516103fe919061217e565b60405180910390f35b60016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414610488576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161047f90612218565b60405180910390fd5b6001600260146101000a81548160ff021916908360ff16021790555060056000808201600090556001820160006101000a81549060ff0219169055505060076000808201600090556001820160006101000a81549060ff021916905550506000600360006101000a8154817cffffffffffffffffffffffffffffffffffffffffffffffffffffffffff02191690837cffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1602179055507fbedf0f4abfe86d4ffad593d9607fe70e83ea706033d44d24b3b6283cf3fc4f6b60405160405180910390a1565b6000806001600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054146105ed576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105e490612378565b60405180910390fd5b60076000015460001b600760010160009054906101000a900460ff16915091509091565b6000600260149054906101000a900460ff1660ff1614610666576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161065d90612278565b60405180910390fd5b600360009054906101000a90047cffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167cffffffffffffffffffffffffffffffffffffffffffffffffffffffffff164210156106f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106ea90612258565b60405180910390fd5b60006106fd6117e5565b90506000811415610743576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161073a90612398565b60405180910390fd5b60076005600082015481600001556001820160009054906101000a900460ff168160010160006101000a81548160ff02191690831515021790555090505060405180604001604052808281526020016001151581525060076000820151816000015560208201518160010160006101000a81548160ff0219169083151502179055509050507fd0df8930e73a69258b2c5f54b88f056f4a3594e30a976d7e9d02f45cb0c8d72f600560000154600760000154604051610803929190612432565b60405180910390a150565b60016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541461088f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161088690612218565b60405180910390fd5b60005b828290508110156109f657600073ffffffffffffffffffffffffffffffffffffffff168383838181106108c157fe5b90506020020160208101906108d69190611c24565b73ffffffffffffffffffffffffffffffffffffffff16141561092d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161092490612318565b60405180910390fd5b60016004600085858581811061093f57fe5b90506020020160208101906109549190611c24565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055507f6ffc0fabf0709270e42087e84a3bfc36041d3b281266d04ae1962185092fb2448383838181106109bf57fe5b90506020020160208101906109d49190611c24565b6040516109e1919061217e565b60405180910390a18080600101915050610892565b505050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414610ac8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610abf90612218565b60405180910390fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61ffff16811115610b2f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b26906122d8565b60405180910390fd5b80600260156101000a81548161ffff021916908361ffff1602179055507fd5cae49d972f01d170fb2d3409c5f318698639863c0403e59e4af06e0ce9281781604051610b7b91906123ee565b60405180910390a150565b60016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414610c07576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bfe90612218565b60405180910390fd5b60005b82829050811015610cde57600060046000858585818110610c2757fe5b9050602002016020810190610c3c9190611c24565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055507f12fdafd291eb287a54e3416070923d22aa5072f5ee04c4fb8361615e7508a37c838383818110610ca757fe5b9050602002016020810190610cbc9190611c24565b604051610cc9919061217e565b60405180910390a18080600101915050610c0a565b505050565b60046020528060005260406000206000915090505481565b60006001600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414610d7f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d7690612378565b60405180910390fd5b600560010160009054906101000a900460ff16610dd1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610dc890612358565b60405180910390fd5b60056000015460001b905090565b6000806001600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414610e64576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e5b90612378565b60405180910390fd5b60056000015460001b600560010160009054906101000a900460ff16915091509091565b60016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414610f09576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f0090612218565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415610f79576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f7090612318565b60405180910390fd5b6000821415610fc85780600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506110a3565b60018214156110175780600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506110a2565b60028214156110665780600960006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506110a1565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611098906121f8565b60405180910390fd5b5b5b7f57e1d18531e0ed6c4f60bf6039e5719aa115e43e43847525125856433a69f7a782826040516110d4929190612409565b60405180910390a15050565b60016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414611161576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161115890612218565b60405180910390fd5b6000600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055507f12fdafd291eb287a54e3416070923d22aa5072f5ee04c4fb8361615e7508a37c816040516111d5919061217e565b60405180910390a150565b60016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414611261576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161125890612218565b60405180910390fd5b60016000808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508073ffffffffffffffffffffffffffffffffffffffff167fdd0e34038ac38b2a1ce960229778ac48a8719bc900b6c4f8d0475c6e8b385a6060405160405180910390a250565b600260149054906101000a900460ff1681565b60016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541461137f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161137690612218565b60405180910390fd5b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508073ffffffffffffffffffffffffffffffffffffffff167f184450df2e323acec0ed3b5c7531b81f9b4cdef7914dfd4c0a4317416bb5251b60405160405180910390a250565b600080600360009054906101000a90047cffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167cffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16141561146657600090506114d1565b6114ce600360009054906101000a90047cffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167cffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600260159054906101000a900461ffff1661ffff16611ad4565b90505b90565b6000600360009054906101000a90047cffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167cffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16421015905090565b600360009054906101000a90047cffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1681565b600260159054906101000a900461ffff1681565b60016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054146115ed576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016115e490612218565b60405180910390fd5b6000600260146101000a81548160ff021916908360ff1602179055507f1b55ba3aa851a46be3b365aee5b5c140edd620d578922f3e8466d2cbd96f954b60405160405180910390a1565b60006020528060005260406000206000915090505481565b60016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054146116d0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116c790612218565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415611740576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161173790612318565b60405180910390fd5b6001600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055507f6ffc0fabf0709270e42087e84a3bfc36041d3b281266d04ae1962185092fb244816040516117b4919061217e565b60405180910390a150565b600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600080600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663679aefce6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561185257600080fd5b505af1158015611866573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061188a9190611ce4565b905060008114156118d0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118c790612298565b60405180910390fd5b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663679aefce6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561193c57600080fd5b505af1158015611950573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119749190611ce4565b905060008114156119ba576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016119b190612238565b60405180910390fd5b808211156119c6578091505b6000600960009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166357de26a46040518163ffffffff1660e01b815260040160206040518083038186803b158015611a3057600080fd5b505afa158015611a44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a689190611c92565b60001c90506000811415611ab1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611aa8906122f8565b60405180910390fd5b670de0b6b3a7640000611ac48483611b24565b81611acb57fe5b04935050505090565b6000828284039150811115611b1e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b1590612338565b60405180910390fd5b92915050565b600080821480611b415750828283850292508281611b3e57fe5b04145b611b80576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b77906122b8565b60405180910390fd5b92915050565b600081359050611b958161251d565b92915050565b60008083601f840112611bad57600080fd5b8235905067ffffffffffffffff811115611bc657600080fd5b602083019150836020820283011115611bde57600080fd5b9250929050565b600081519050611bf481612534565b92915050565b600081359050611c098161254b565b92915050565b600081519050611c1e8161254b565b92915050565b600060208284031215611c3657600080fd5b6000611c4484828501611b86565b91505092915050565b60008060208385031215611c6057600080fd5b600083013567ffffffffffffffff811115611c7a57600080fd5b611c8685828601611b9b565b92509250509250929050565b600060208284031215611ca457600080fd5b6000611cb284828501611be5565b91505092915050565b600060208284031215611ccd57600080fd5b6000611cdb84828501611bfa565b91505092915050565b600060208284031215611cf657600080fd5b6000611d0484828501611c0f565b91505092915050565b60008060408385031215611d2057600080fd5b6000611d2e85828601611bfa565b9250506020611d3f85828601611b86565b9150509250929050565b611d5281612487565b82525050565b611d6181612499565b82525050565b611d70816124a5565b82525050565b6000611d83601883612476565b91507f526174654361704f7261636c652f696e76616c69642d696400000000000000006000830152602082019050919050565b6000611dc3601c83612476565b91507f526174654361704f7261636c652f6e6f742d617574686f72697a6564000000006000830152602082019050919050565b6000611e03601f83612476565b91507f526174654361704f7261636c652f696e76616c69642d6361702d7072696365006000830152602082019050919050565b6000611e43601883612476565b91507f526174654361704f7261636c652f6e6f742d70617373656400000000000000006000830152602082019050919050565b6000611e83601883612476565b91507f526174654361704f7261636c652f69732d73746f7070656400000000000000006000830152602082019050919050565b6000611ec3601f83612476565b91507f526174654361704f7261636c652f696e76616c69642d7372632d7072696365006000830152602082019050919050565b6000611f03601a83612476565b91507f526174654361704f7261636c652f6d756c2d6f766572666c6f770000000000006000830152602082019050919050565b6000611f43601983612476565b91507f526174654361704f7261636c652f696e76616c69642d686f70000000000000006000830152602082019050919050565b6000611f83602283612476565b91507f526174654361704f7261636c652f696e76616c69642d6f7261636c652d70726960008301527f63650000000000000000000000000000000000000000000000000000000000006020830152604082019050919050565b6000611fe9601b83612476565b91507f526174654361704f7261636c652f6e6f2d636f6e74726163742d3000000000006000830152602082019050919050565b6000612029601b83612476565b91507f526174654361704f7261636c652f7375622d756e646572666c6f7700000000006000830152602082019050919050565b6000612069601e83612476565b91507f526174654361704f7261636c652f6e6f2d63757272656e742d76616c756500006000830152602082019050919050565b60006120a9602683612476565b91507f526174654361704f7261636c652f636f6e74726163742d6e6f742d776869746560008301527f6c697374656400000000000000000000000000000000000000000000000000006020830152604082019050919050565b600061210f601b83612476565b91507f526174654361704f7261636c652f696e76616c69642d707269636500000000006000830152602082019050919050565b61214b816124af565b82525050565b61215a816124dd565b82525050565b61216981612506565b82525050565b61217881612510565b82525050565b60006020820190506121936000830184611d49565b92915050565b60006020820190506121ae6000830184611d58565b92915050565b60006020820190506121c96000830184611d67565b92915050565b60006040820190506121e46000830185611d67565b6121f16020830184611d58565b9392505050565b6000602082019050818103600083015261221181611d76565b9050919050565b6000602082019050818103600083015261223181611db6565b9050919050565b6000602082019050818103600083015261225181611df6565b9050919050565b6000602082019050818103600083015261227181611e36565b9050919050565b6000602082019050818103600083015261229181611e76565b9050919050565b600060208201905081810360008301526122b181611eb6565b9050919050565b600060208201905081810360008301526122d181611ef6565b9050919050565b600060208201905081810360008301526122f181611f36565b9050919050565b6000602082019050818103600083015261231181611f76565b9050919050565b6000602082019050818103600083015261233181611fdc565b9050919050565b600060208201905081810360008301526123518161201c565b9050919050565b600060208201905081810360008301526123718161205c565b9050919050565b600060208201905081810360008301526123918161209c565b9050919050565b600060208201905081810360008301526123b181612102565b9050919050565b60006020820190506123cd6000830184612142565b92915050565b60006020820190506123e86000830184612151565b92915050565b60006020820190506124036000830184612160565b92915050565b600060408201905061241e6000830185612160565b61242b6020830184611d49565b9392505050565b60006040820190506124476000830185612160565b6124546020830184612160565b9392505050565b6000602082019050612470600083018461216f565b92915050565b600082825260208201905092915050565b6000612492826124bd565b9050919050565b60008115159050919050565b6000819050919050565b600061ffff82169050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60007cffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b600060ff82169050919050565b61252681612487565b811461253157600080fd5b50565b61253d816124a5565b811461254857600080fd5b50565b61255481612506565b811461255f57600080fd5b5056fea26469706673582212202644d3094b428fca6b87c78cf3537d64e8b5a22de2d338cc061ca0a8f03b7ff064736f6c634300060c0033000000000000000000000000153f6ce9e1b49d8535aac45db917465e1386f1750000000000000000000000001a148871bf262451f34f13cbcb7917b4fe59cb320000000000000000000000003d4604395595bb30a8b7754b5ddbf0b3f680564b

Deployed ByteCode Sourcemap

180939:6226:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;183425:142;;;:::i;:::-;;186137:120;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;185312:680;;;:::i;:::-;;186618:254;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;181440:18;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;181483;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;183667:172;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;186982:180;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;181917:39;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;186265:176;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;186000:129;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;183847:404;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;186880:94;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;181123:79;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;181664:22;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;181222:79;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;184303:148;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;184459:93;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;181811:18;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;181733:28;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;183575:84;;;:::i;:::-;;181003:41;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;186449:161;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;182256:29;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;183425:142;181378:1;181357:5;:17;181363:10;181357:17;;;;;;;;;;;;;;;;:22;181349:63;;;;;;;;;;;;:::i;:::-;;;;;;;;;183476:1:::1;183466:7;;:11;;;;;;;;;;;;;;;;;;183495:3;;183488:10:::0;::::1;;;;;;;;;;;;;;;;;;;;;;183516:3;;183509:10:::0;::::1;;;;;;;;;;;;;;;;;;;;;;183536:1;183530:3;;:7;;;;;;;;;;;;;;;;;;183553:6;;;;;;;;;;183425:142::o:0;186137:120::-;186181:7;186189:4;182006:1;181987:3;:15;181991:10;181987:15;;;;;;;;;;;;;;;;:20;181979:71;;;;;;;;;;;;:::i;:::-;;;;;;;;;186230:3:::1;:7;;;186214:25;;186241:3;:7;;;;;;;;;;;;186206:43;;;;186137:120:::0;;:::o;185312:680::-;185478:1;185467:7;;;;;;;;;;;:12;;;185459:49;;;;;;;;;;;;:::i;:::-;;;;;;;;;185771:3;;;;;;;;;;;185752:22;;:15;:22;;185744:59;;;;;;;;;;;;:::i;:::-;;;;;;;;;185814:11;185828:6;:4;:6::i;:::-;185814:20;;185860:1;185853:3;:8;;185845:48;;;;;;;;;;;;:::i;:::-;;;;;;;;;185910:3;185904;:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;185930:15;;;;;;;;185935:3;185930:15;;;;185940:4;185930:15;;;;;185924:3;:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;185961:23;185967:3;:7;;;185976:3;:7;;;185961:23;;;;;;;:::i;:::-;;;;;;;;185312:680;:::o;186618:254::-;181378:1;181357:5;:17;181363:10;181357:17;;;;;;;;;;;;;;;;:22;181349:63;;;;;;;;;;;;:::i;:::-;;;;;;;;;186684:9:::1;186680:185;186703:2;;:9;;186699:1;:13;186680:185;;;186759:1;186742:19;;:2;;186745:1;186742:5;;;;;;;;;;;;;;;;;;;;:::i;:::-;:19;;;;186734:59;;;;;;;;;;;;:::i;:::-;;;;;;;;;186821:1;186808:3;:10;186812:2;;186815:1;186812:5;;;;;;;;;;;;;;;;;;;;:::i;:::-;186808:10;;;;;;;;;;;;;;;:14;;;;186842:11;186847:2;;186850:1;186847:5;;;;;;;;;;;;;;;;;;;;:::i;:::-;186842:11;;;;;;:::i;:::-;;;;;;;;186714:3;;;;;;;186680:185;;;;186618:254:::0;;:::o;181440:18::-;;;;;;;;;;;;;:::o;181483:::-;;;;;;;;;;;;;:::o;183667:172::-;181378:1;181357:5;:17;181363:10;181357:17;;;;;;;;;;;;;;;;:22;181349:63;;;;;;;;;;;;:::i;:::-;;;;;;;;;183743:2:::1;183728:18;;:4;:18;;183720:56;;;;;;;;;;;;:::i;:::-;;;;;;;;;183800:4;183787:3;;:18;;;;;;;;;;;;;;;;;;183821:10;183826:4;183821:10;;;;;;:::i;:::-;;;;;;;;183667:172:::0;:::o;186982:180::-;181378:1;181357:5;:17;181363:10;181357:17;;;;;;;;;;;;;;;;:22;181349:63;;;;;;;;;;;;:::i;:::-;;;;;;;;;187048:9:::1;187044:111;187067:2;;:9;;187063:1;:13;187044:111;;;187111:1;187098:3;:10;187102:2;;187105:1;187102:5;;;;;;;;;;;;;;;;;;;;:::i;:::-;187098:10;;;;;;;;;;;;;;;:14;;;;187132:11;187137:2;;187140:1;187137:5;;;;;;;;;;;;;;;;;;;;:::i;:::-;187132:11;;;;;;:::i;:::-;;;;;;;;187078:3;;;;;;;187044:111;;;;186982:180:::0;;:::o;181917:39::-;;;;;;;;;;;;;;;;;:::o;186265:176::-;186318:7;182006:1;181987:3;:15;181991:10;181987:15;;;;;;;;;;;;;;;;:20;181979:71;;;;;;;;;;;;:::i;:::-;;;;;;;;;186346:3:::1;:7;;;;;;;;;;;;186338:50;;;;;;;;;;;;:::i;:::-;;;;;;;;;186423:3;:7;;;186407:25;;186399:34;;186265:176:::0;:::o;186000:129::-;186053:7;186061:4;182006:1;181987:3;:15;181991:10;181987:15;;;;;;;;;;;;;;;;:20;181979:71;;;;;;;;;;;;:::i;:::-;;;;;;;;;186102:3:::1;:7;;;186086:25;;186113:3;:7;;;;;;;;;;;;186078:43;;;;186000:129:::0;;:::o;183847:404::-;181378:1;181357:5;:17;181363:10;181357:17;;;;;;;;;;;;;;;;:22;181349:63;;;;;;;;;;;;:::i;:::-;;;;;;;;;183937:1:::1;183921:18;;:4;:18;;;;183913:58;;;;;;;;;;;;:::i;:::-;;;;;;;;;183992:1;183985:3;:8;183982:231;;;184016:4;184010:3;;:10;;;;;;;;;;;;;;;;;;183982:231;;;184049:1;184042:3;:8;184038:175;;;184073:4;184067:3;;:10;;;;;;;;;;;;;;;;;;184038:175;;;184106:1;184099:3;:8;184095:118;;;184130:4;184124:3;;:10;;;;;;;;;;;;;;;;;;184095:118;;;184167:34;;;;;;;;;;:::i;:::-;;;;;;;;184095:118;184038:175;183982:231;184228:15;184233:3;184238:4;184228:15;;;;;;;:::i;:::-;;;;;;;;183847:404:::0;;:::o;186880:94::-;181378:1;181357:5;:17;181363:10;181357:17;;;;;;;;;;;;;;;;:22;181349:63;;;;;;;;;;;;:::i;:::-;;;;;;;;;186941:1:::1;186931:3;:7;186935:2;186931:7;;;;;;;;;;;;;;;:11;;;;186958:8;186963:2;186958:8;;;;;;:::i;:::-;;;;;;;;186880:94:::0;:::o;181123:79::-;181378:1;181357:5;:17;181363:10;181357:17;;;;;;;;;;;;;;;;:22;181349:63;;;;;;;;;;;;:::i;:::-;;;;;;;;;181181:1:::1;181167:5;:11:::0;181173:4:::1;181167:11;;;;;;;;;;;;;;;:15;;;;181194:4;181189:10;;;;;;;;;;;;181123:79:::0;:::o;181664:22::-;;;;;;;;;;;;;:::o;181222:79::-;181378:1;181357:5;:17;181363:10;181357:17;;;;;;;;;;;;;;;;:22;181349:63;;;;;;;;;;;;:::i;:::-;;;;;;;;;181280:1:::1;181266:5:::0;:11:::1;181272:4;181266:11;;;;;;;;;;;;;;;:15;;;;181293:4;181288:10;;;;;;;;;;;;181222:79:::0;:::o;184303:148::-;184341:7;184372:1;184365:3;;;;;;;;;;;:8;;;184361:22;;;184382:1;184375:8;;;;184361:22;184429:14;184434:3;;;;;;;;;;;184429:14;;184439:3;;;;;;;;;;;184429:14;;:4;:14::i;:::-;184422:21;;184303:148;;:::o;184459:93::-;184498:4;184541:3;;;;;;;;;;;184522:22;;:15;:22;;184515:29;;184459:93;:::o;181811:18::-;;;;;;;;;;;;;:::o;181733:28::-;;;;;;;;;;;;;:::o;183575:84::-;181378:1;181357:5;:17;181363:10;181357:17;;;;;;;;;;;;;;;;:22;181349:63;;;;;;;;;;;;:::i;:::-;;;;;;;;;183627:1:::1;183617:7;;:11;;;;;;;;;;;;;;;;;;183644:7;;;;;;;;;;183575:84::o:0;181003:41::-;;;;;;;;;;;;;;;;;:::o;186449:161::-;181378:1;181357:5;:17;181363:10;181357:17;;;;;;;;;;;;;;;;:22;181349:63;;;;;;;;;;;;:::i;:::-;;;;;;;;;186522:1:::1;186508:16;;:2;:16;;;;186500:56;;;;;;;;;;;;:::i;:::-;;;;;;;;;186577:1;186567:3;:7;186571:2;186567:7;;;;;;;;;;;;;;;:11;;;;186594:8;186599:2;186594:8;;;;;;:::i;:::-;;;;;;;;186449:161:::0;:::o;182256:29::-;;;;;;;;;;;;;:::o;184560:744::-;184594:13;184714:9;184751:3;;;;;;;;;;;184726:37;;;:39;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;184714:51;;184789:1;184784;:6;;184776:50;;;;;;;;;;;;:::i;:::-;;;;;;;;;184870:9;184907:3;;;;;;;;;;;184882:37;;;:39;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;184870:51;;184945:1;184940;:6;;184932:50;;;;;;;;;;;;:::i;:::-;;;;;;;;;185022:1;185018;:5;185014:16;;;185029:1;185025:5;;185014:16;185111:9;185139:3;;;;;;;;;;;185131:17;;;:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;185123:28;;185111:40;;185221:1;185216;:6;;185208:53;;;;;;;;;;;;:::i;:::-;;;;;;;;;185292:4;185279:10;185284:1;185287;185279:4;:10::i;:::-;:17;;;;;;185272:24;;;;;184560:744;:::o;182322:150::-;182383:9;182430:2;182423;182418;:7;182414:11;;;182413:19;;182405:59;;;;;;;;;;;;:::i;:::-;;;;;;;;;182322:150;;;;:::o;182478:165::-;182539:9;182575:1;182569:2;:7;:35;;;;182602:2;182596;182590;182585;:7;182581:11;;;182580:18;;;;;;:24;182569:35;182561:74;;;;;;;;;;;;:::i;:::-;;;;;;;;;182478:165;;;;:::o;5:130:-1:-;;85:6;72:20;63:29;;97:33;124:5;97:33;:::i;:::-;57:78;;;;:::o;160:352::-;;;290:3;283:4;275:6;271:17;267:27;257:2;;308:1;305;298:12;257:2;341:6;328:20;318:30;;368:18;360:6;357:30;354:2;;;400:1;397;390:12;354:2;434:4;426:6;422:17;410:29;;485:3;477:4;469:6;465:17;455:8;451:32;448:41;445:2;;;502:1;499;492:12;445:2;250:262;;;;;:::o;520:134::-;;604:6;598:13;589:22;;616:33;643:5;616:33;:::i;:::-;583:71;;;;:::o;661:130::-;;741:6;728:20;719:29;;753:33;780:5;753:33;:::i;:::-;713:78;;;;:::o;798:134::-;;882:6;876:13;867:22;;894:33;921:5;894:33;:::i;:::-;861:71;;;;:::o;939:241::-;;1043:2;1031:9;1022:7;1018:23;1014:32;1011:2;;;1059:1;1056;1049:12;1011:2;1094:1;1111:53;1156:7;1147:6;1136:9;1132:22;1111:53;:::i;:::-;1101:63;;1073:97;1005:175;;;;:::o;1187:397::-;;;1326:2;1314:9;1305:7;1301:23;1297:32;1294:2;;;1342:1;1339;1332:12;1294:2;1405:1;1394:9;1390:17;1377:31;1428:18;1420:6;1417:30;1414:2;;;1460:1;1457;1450:12;1414:2;1488:80;1560:7;1551:6;1540:9;1536:22;1488:80;:::i;:::-;1470:98;;;;1356:218;1288:296;;;;;:::o;1591:263::-;;1706:2;1694:9;1685:7;1681:23;1677:32;1674:2;;;1722:1;1719;1712:12;1674:2;1757:1;1774:64;1830:7;1821:6;1810:9;1806:22;1774:64;:::i;:::-;1764:74;;1736:108;1668:186;;;;:::o;1861:241::-;;1965:2;1953:9;1944:7;1940:23;1936:32;1933:2;;;1981:1;1978;1971:12;1933:2;2016:1;2033:53;2078:7;2069:6;2058:9;2054:22;2033:53;:::i;:::-;2023:63;;1995:97;1927:175;;;;:::o;2109:263::-;;2224:2;2212:9;2203:7;2199:23;2195:32;2192:2;;;2240:1;2237;2230:12;2192:2;2275:1;2292:64;2348:7;2339:6;2328:9;2324:22;2292:64;:::i;:::-;2282:74;;2254:108;2186:186;;;;:::o;2379:366::-;;;2500:2;2488:9;2479:7;2475:23;2471:32;2468:2;;;2516:1;2513;2506:12;2468:2;2551:1;2568:53;2613:7;2604:6;2593:9;2589:22;2568:53;:::i;:::-;2558:63;;2530:97;2658:2;2676:53;2721:7;2712:6;2701:9;2697:22;2676:53;:::i;:::-;2666:63;;2637:98;2462:283;;;;;:::o;2752:113::-;2835:24;2853:5;2835:24;:::i;:::-;2830:3;2823:37;2817:48;;:::o;2872:104::-;2949:21;2964:5;2949:21;:::i;:::-;2944:3;2937:34;2931:45;;:::o;2983:113::-;3066:24;3084:5;3066:24;:::i;:::-;3061:3;3054:37;3048:48;;:::o;3104:324::-;;3264:67;3328:2;3323:3;3264:67;:::i;:::-;3257:74;;3364:26;3360:1;3355:3;3351:11;3344:47;3419:2;3414:3;3410:12;3403:19;;3250:178;;;:::o;3437:328::-;;3597:67;3661:2;3656:3;3597:67;:::i;:::-;3590:74;;3697:30;3693:1;3688:3;3684:11;3677:51;3756:2;3751:3;3747:12;3740:19;;3583:182;;;:::o;3774:331::-;;3934:67;3998:2;3993:3;3934:67;:::i;:::-;3927:74;;4034:33;4030:1;4025:3;4021:11;4014:54;4096:2;4091:3;4087:12;4080:19;;3920:185;;;:::o;4114:324::-;;4274:67;4338:2;4333:3;4274:67;:::i;:::-;4267:74;;4374:26;4370:1;4365:3;4361:11;4354:47;4429:2;4424:3;4420:12;4413:19;;4260:178;;;:::o;4447:324::-;;4607:67;4671:2;4666:3;4607:67;:::i;:::-;4600:74;;4707:26;4703:1;4698:3;4694:11;4687:47;4762:2;4757:3;4753:12;4746:19;;4593:178;;;:::o;4780:331::-;;4940:67;5004:2;4999:3;4940:67;:::i;:::-;4933:74;;5040:33;5036:1;5031:3;5027:11;5020:54;5102:2;5097:3;5093:12;5086:19;;4926:185;;;:::o;5120:326::-;;5280:67;5344:2;5339:3;5280:67;:::i;:::-;5273:74;;5380:28;5376:1;5371:3;5367:11;5360:49;5437:2;5432:3;5428:12;5421:19;;5266:180;;;:::o;5455:325::-;;5615:67;5679:2;5674:3;5615:67;:::i;:::-;5608:74;;5715:27;5711:1;5706:3;5702:11;5695:48;5771:2;5766:3;5762:12;5755:19;;5601:179;;;:::o;5789:371::-;;5949:67;6013:2;6008:3;5949:67;:::i;:::-;5942:74;;6049:34;6045:1;6040:3;6036:11;6029:55;6118:4;6113:2;6108:3;6104:12;6097:26;6151:2;6146:3;6142:12;6135:19;;5935:225;;;:::o;6169:327::-;;6329:67;6393:2;6388:3;6329:67;:::i;:::-;6322:74;;6429:29;6425:1;6420:3;6416:11;6409:50;6487:2;6482:3;6478:12;6471:19;;6315:181;;;:::o;6505:327::-;;6665:67;6729:2;6724:3;6665:67;:::i;:::-;6658:74;;6765:29;6761:1;6756:3;6752:11;6745:50;6823:2;6818:3;6814:12;6807:19;;6651:181;;;:::o;6841:330::-;;7001:67;7065:2;7060:3;7001:67;:::i;:::-;6994:74;;7101:32;7097:1;7092:3;7088:11;7081:53;7162:2;7157:3;7153:12;7146:19;;6987:184;;;:::o;7180:375::-;;7340:67;7404:2;7399:3;7340:67;:::i;:::-;7333:74;;7440:34;7436:1;7431:3;7427:11;7420:55;7509:8;7504:2;7499:3;7495:12;7488:30;7546:2;7541:3;7537:12;7530:19;;7326:229;;;:::o;7564:327::-;;7724:67;7788:2;7783:3;7724:67;:::i;:::-;7717:74;;7824:29;7820:1;7815:3;7811:11;7804:50;7882:2;7877:3;7873:12;7866:19;;7710:181;;;:::o;7899:110::-;7980:23;7997:5;7980:23;:::i;:::-;7975:3;7968:36;7962:47;;:::o;8016:113::-;8099:24;8117:5;8099:24;:::i;:::-;8094:3;8087:37;8081:48;;:::o;8136:113::-;8219:24;8237:5;8219:24;:::i;:::-;8214:3;8207:37;8201:48;;:::o;8256:107::-;8335:22;8351:5;8335:22;:::i;:::-;8330:3;8323:35;8317:46;;:::o;8370:222::-;;8497:2;8486:9;8482:18;8474:26;;8511:71;8579:1;8568:9;8564:17;8555:6;8511:71;:::i;:::-;8468:124;;;;:::o;8599:210::-;;8720:2;8709:9;8705:18;8697:26;;8734:65;8796:1;8785:9;8781:17;8772:6;8734:65;:::i;:::-;8691:118;;;;:::o;8816:222::-;;8943:2;8932:9;8928:18;8920:26;;8957:71;9025:1;9014:9;9010:17;9001:6;8957:71;:::i;:::-;8914:124;;;;:::o;9045:321::-;;9194:2;9183:9;9179:18;9171:26;;9208:71;9276:1;9265:9;9261:17;9252:6;9208:71;:::i;:::-;9290:66;9352:2;9341:9;9337:18;9328:6;9290:66;:::i;:::-;9165:201;;;;;:::o;9373:416::-;;9573:2;9562:9;9558:18;9550:26;;9623:9;9617:4;9613:20;9609:1;9598:9;9594:17;9587:47;9648:131;9774:4;9648:131;:::i;:::-;9640:139;;9544:245;;;:::o;9796:416::-;;9996:2;9985:9;9981:18;9973:26;;10046:9;10040:4;10036:20;10032:1;10021:9;10017:17;10010:47;10071:131;10197:4;10071:131;:::i;:::-;10063:139;;9967:245;;;:::o;10219:416::-;;10419:2;10408:9;10404:18;10396:26;;10469:9;10463:4;10459:20;10455:1;10444:9;10440:17;10433:47;10494:131;10620:4;10494:131;:::i;:::-;10486:139;;10390:245;;;:::o;10642:416::-;;10842:2;10831:9;10827:18;10819:26;;10892:9;10886:4;10882:20;10878:1;10867:9;10863:17;10856:47;10917:131;11043:4;10917:131;:::i;:::-;10909:139;;10813:245;;;:::o;11065:416::-;;11265:2;11254:9;11250:18;11242:26;;11315:9;11309:4;11305:20;11301:1;11290:9;11286:17;11279:47;11340:131;11466:4;11340:131;:::i;:::-;11332:139;;11236:245;;;:::o;11488:416::-;;11688:2;11677:9;11673:18;11665:26;;11738:9;11732:4;11728:20;11724:1;11713:9;11709:17;11702:47;11763:131;11889:4;11763:131;:::i;:::-;11755:139;;11659:245;;;:::o;11911:416::-;;12111:2;12100:9;12096:18;12088:26;;12161:9;12155:4;12151:20;12147:1;12136:9;12132:17;12125:47;12186:131;12312:4;12186:131;:::i;:::-;12178:139;;12082:245;;;:::o;12334:416::-;;12534:2;12523:9;12519:18;12511:26;;12584:9;12578:4;12574:20;12570:1;12559:9;12555:17;12548:47;12609:131;12735:4;12609:131;:::i;:::-;12601:139;;12505:245;;;:::o;12757:416::-;;12957:2;12946:9;12942:18;12934:26;;13007:9;13001:4;12997:20;12993:1;12982:9;12978:17;12971:47;13032:131;13158:4;13032:131;:::i;:::-;13024:139;;12928:245;;;:::o;13180:416::-;;13380:2;13369:9;13365:18;13357:26;;13430:9;13424:4;13420:20;13416:1;13405:9;13401:17;13394:47;13455:131;13581:4;13455:131;:::i;:::-;13447:139;;13351:245;;;:::o;13603:416::-;;13803:2;13792:9;13788:18;13780:26;;13853:9;13847:4;13843:20;13839:1;13828:9;13824:17;13817:47;13878:131;14004:4;13878:131;:::i;:::-;13870:139;;13774:245;;;:::o;14026:416::-;;14226:2;14215:9;14211:18;14203:26;;14276:9;14270:4;14266:20;14262:1;14251:9;14247:17;14240:47;14301:131;14427:4;14301:131;:::i;:::-;14293:139;;14197:245;;;:::o;14449:416::-;;14649:2;14638:9;14634:18;14626:26;;14699:9;14693:4;14689:20;14685:1;14674:9;14670:17;14663:47;14724:131;14850:4;14724:131;:::i;:::-;14716:139;;14620:245;;;:::o;14872:416::-;;15072:2;15061:9;15057:18;15049:26;;15122:9;15116:4;15112:20;15108:1;15097:9;15093:17;15086:47;15147:131;15273:4;15147:131;:::i;:::-;15139:139;;15043:245;;;:::o;15295:218::-;;15420:2;15409:9;15405:18;15397:26;;15434:69;15500:1;15489:9;15485:17;15476:6;15434:69;:::i;:::-;15391:122;;;;:::o;15520:222::-;;15647:2;15636:9;15632:18;15624:26;;15661:71;15729:1;15718:9;15714:17;15705:6;15661:71;:::i;:::-;15618:124;;;;:::o;15749:222::-;;15876:2;15865:9;15861:18;15853:26;;15890:71;15958:1;15947:9;15943:17;15934:6;15890:71;:::i;:::-;15847:124;;;;:::o;15978:333::-;;16133:2;16122:9;16118:18;16110:26;;16147:71;16215:1;16204:9;16200:17;16191:6;16147:71;:::i;:::-;16229:72;16297:2;16286:9;16282:18;16273:6;16229:72;:::i;:::-;16104:207;;;;;:::o;16318:333::-;;16473:2;16462:9;16458:18;16450:26;;16487:71;16555:1;16544:9;16540:17;16531:6;16487:71;:::i;:::-;16569:72;16637:2;16626:9;16622:18;16613:6;16569:72;:::i;:::-;16444:207;;;;;:::o;16658:214::-;;16781:2;16770:9;16766:18;16758:26;;16795:67;16859:1;16848:9;16844:17;16835:6;16795:67;:::i;:::-;16752:120;;;;:::o;16880:163::-;;16995:6;16990:3;16983:19;17032:4;17027:3;17023:14;17008:29;;16976:67;;;;:::o;17051:91::-;;17113:24;17131:5;17113:24;:::i;:::-;17102:35;;17096:46;;;:::o;17149:85::-;;17222:5;17215:13;17208:21;17197:32;;17191:43;;;:::o;17241:72::-;;17303:5;17292:16;;17286:27;;;:::o;17320:84::-;;17392:6;17385:5;17381:18;17370:29;;17364:40;;;:::o;17411:121::-;;17484:42;17477:5;17473:54;17462:65;;17456:76;;;:::o;17539:139::-;;17612:60;17605:5;17601:72;17590:83;;17584:94;;;:::o;17685:72::-;;17747:5;17736:16;;17730:27;;;:::o;17764:81::-;;17835:4;17828:5;17824:16;17813:27;;17807:38;;;:::o;17852:117::-;17921:24;17939:5;17921:24;:::i;:::-;17914:5;17911:35;17901:2;;17960:1;17957;17950:12;17901:2;17895:74;:::o;17976:117::-;18045:24;18063:5;18045:24;:::i;:::-;18038:5;18035:35;18025:2;;18084:1;18081;18074:12;18025:2;18019:74;:::o;18100:117::-;18169:24;18187:5;18169:24;:::i;:::-;18162:5;18159:35;18149:2;;18208:1;18205;18198:12;18149:2;18143:74;:::o

Swarm Source

ipfs://2644d3094b428fca6b87c78cf3537d64e8b5a22de2d338cc061ca0a8f03b7ff0
Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Validator ID :
0 FTM

Amount Staked
0

Amount Delegated
0

Staking Total
0

Staking Start Epoch
0

Staking Start Time
0

Proof of Importance
0

Origination Score
0

Validation Score
0

Active
0

Online
0

Downtime
0 s
Address Amount claimed Rewards Created On Epoch Created On
Block Uncle Number Difficulty Gas Used Reward
Loading
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.