Created
January 21, 2022 17:59
-
-
Save talbaneth/54c5c108f50535ca8b9434de418c110f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// hevm: flattened sources of src/DssSpell.sol | |
// SPDX-License-Identifier: AGPL-3.0-or-later | |
pragma solidity =0.6.12 >=0.6.12 <0.7.0; | |
pragma experimental ABIEncoderV2; | |
////// lib/dss-exec-lib/src/CollateralOpts.sol | |
/* pragma solidity ^0.6.12; */ | |
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; | |
} | |
////// lib/dss-exec-lib/src/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; */ | |
/* pragma experimental ABIEncoderV2; */ | |
/* import { CollateralOpts } from "./CollateralOpts.sol"; */ | |
interface Initializable { | |
function init(bytes32) external; | |
} | |
interface Authorizable { | |
function rely(address) external; | |
function deny(address) external; | |
function setAuthority(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 DogLike { | |
function ilks(bytes32) external returns (address clip, uint256 chop, uint256 hole, uint256 dirt); | |
} | |
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_2 { | |
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 returns (uint256); | |
} | |
library DssExecLib { | |
/*****************/ | |
/*** Constants ***/ | |
/*****************/ | |
address constant public LOG = 0xdA0Ab1e0017DEbCd72Be8599041a2aa3bA7e740F; | |
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() public view returns (address) { return getChangelogAddress("MCD_DAI"); } | |
function mkr() public view returns (address) { return getChangelogAddress("MCD_GOV"); } | |
function vat() public view returns (address) { return getChangelogAddress("MCD_VAT"); } | |
function cat() public view returns (address) { return getChangelogAddress("MCD_CAT"); } | |
function dog() public view returns (address) { return getChangelogAddress("MCD_DOG"); } | |
function jug() public view returns (address) { return getChangelogAddress("MCD_JUG"); } | |
function pot() public view returns (address) { return getChangelogAddress("MCD_POT"); } | |
function vow() public view returns (address) { return getChangelogAddress("MCD_VOW"); } | |
function end() public view returns (address) { return getChangelogAddress("MCD_END"); } | |
function esm() public view returns (address) { return getChangelogAddress("MCD_ESM"); } | |
function reg() public view returns (address) { return getChangelogAddress("ILK_REGISTRY"); } | |
function spotter() public view returns (address) { return getChangelogAddress("MCD_SPOT"); } | |
function flap() public view returns (address) { return getChangelogAddress("MCD_FLAP"); } | |
function flop() public view returns (address) { return getChangelogAddress("MCD_FLOP"); } | |
function osmMom() public view returns (address) { return getChangelogAddress("OSM_MOM"); } | |
function govGuard() public view returns (address) { return getChangelogAddress("GOV_GUARD"); } | |
function flipperMom() public view returns (address) { return getChangelogAddress("FLIPPER_MOM"); } | |
function clipperMom() public view returns (address) { return getChangelogAddress("CLIPPER_MOM"); } | |
function pauseProxy() public view returns (address) { return getChangelogAddress("MCD_PAUSE_PROXY"); } | |
function autoLine() public view returns (address) { return getChangelogAddress("MCD_IAM_AUTO_LINE"); } | |
function daiJoin() public view returns (address) { return getChangelogAddress("MCD_JOIN_DAI"); } | |
function lerpFab() public view returns (address) { return getChangelogAddress("LERP_FAB"); } | |
function clip(bytes32 _ilk) public view returns (address _clip) { | |
_clip = RegistryLike(reg()).xlip(_ilk); | |
} | |
function flip(bytes32 _ilk) public view returns (address _flip) { | |
_flip = RegistryLike(reg()).xlip(_ilk); | |
} | |
function calc(bytes32 _ilk) public view returns (address _calc) { | |
_calc = ClipLike(clip(_ilk)).calc(); | |
} | |
function getChangelogAddress(bytes32 _key) public view returns (address) { | |
return ChainlogLike(LOG).getAddress(_key); | |
} | |
/****************************/ | |
/*** 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) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
Authorizable(_base).deny(_ward); | |
} | |
/** | |
@dev Give an address authorization to perform auth actions on the contract. | |
@param _base The address of the contract with a `setAuthority` pattern | |
@param _authority Address to be authorized | |
*/ | |
function setAuthority(address _base, address _authority) public { | |
Authorizable(_base).setAuthority(_authority); | |
} | |
/** | |
@dev Delegate vat authority to the specified address. | |
@param _usr Address to be authorized | |
*/ | |
function delegateVat(address _usr) public { | |
DssVat(vat()).hope(_usr); | |
} | |
/** | |
@dev Revoke vat authority to the specified address. | |
@param _usr Address to be deauthorized | |
*/ | |
function undelegateVat(address _usr) public { | |
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) public 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) public 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() public { | |
Drippable(pot()).drip(); | |
} | |
/** | |
@dev Update rate accumulation for the stability fees of a given collateral type. | |
@param _ilk Collateral type | |
*/ | |
function accumulateCollateralStabilityFees(bytes32 _ilk) public { | |
Drippable(jug()).drip(_ilk); | |
} | |
/*********************/ | |
/*** Price Updates ***/ | |
/*********************/ | |
/** | |
@dev Update price of a given collateral type. | |
@param _ilk Collateral type | |
*/ | |
function updateCollateralPrice(bytes32 _ilk) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
setValue(flop(), "ttl", _duration); | |
} | |
/** | |
@dev Set total auction duration for debt auctions. | |
@param _duration Amount of time for auctions. | |
*/ | |
function setDebtAuctionDuration(uint256 _duration) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
require(_amount < WAD); // "LibDssExec/incorrect-ilk-dust-precision" | |
(,, uint256 _hole,) = DogLike(dog()).ilks(_ilk); | |
require(_amount <= _hole / RAD); // Ensure ilk.hole >= dust | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
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) public { | |
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_2(_oracle).orb1(), _oracle); | |
} else { | |
// Standard OSM | |
addReaderToWhitelistCall(OracleLike_2(_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_2(_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_2(_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) public { | |
(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) public { | |
(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_2(_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) public { | |
MomLike(osmMom()).setOsm(_ilk, _osm); | |
} | |
/*****************************/ | |
/*** Direct Deposit Module ***/ | |
/*****************************/ | |
/** | |
@dev Sets the target rate threshold for a dai direct deposit module (d3m) | |
@dev Aave: Targets the variable borrow rate | |
@param _d3m The address of the D3M contract | |
@param _pct_bps Target rate in basis points. (ex. 4% == 400) | |
*/ | |
function setD3MTargetInterestRate(address _d3m, uint256 _pct_bps) public { | |
require(_pct_bps < BPS_ONE_HUNDRED_PCT); // DssExecLib/bar-too-high | |
setValue(_d3m, "bar", rdiv(_pct_bps, BPS_ONE_HUNDRED_PCT)); | |
} | |
/*****************************/ | |
/*** 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 | |
) public { | |
// 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) public { | |
// 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 | |
// 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 hole size | |
setIlkMaxLiquidationAmount(co.ilk, co.maxLiquidationAmount); | |
// Set the ilk dust | |
setIlkMinVaultAmount(co.ilk, co.minVaultAmount); | |
// 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) public { | |
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) public 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) public returns (address) { | |
address lerp = LerpFactoryLike(lerpFab()).newIlkLerp(_name, _target, _ilk, _what, _startTime, _start, _end, _duration); | |
Authorizable(_target).rely(lerp); | |
LerpLike(lerp).tick(); | |
return lerp; | |
} | |
} | |
////// lib/dss-exec-lib/src/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; */ | |
/* import { DssExecLib } from "./DssExecLib.sol"; */ | |
/* import { CollateralOpts } from "./CollateralOpts.sol"; */ | |
interface OracleLike_1 { | |
function src() external view returns (address); | |
} | |
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 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 returns (uint256 castTime) { | |
require(eta <= uint40(-1)); | |
castTime = DssExecLib.nextCastTime(uint40(eta), uint40(block.timestamp), officeHours()); | |
} | |
} | |
////// lib/dss-exec-lib/src/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; */ | |
interface PauseAbstract { | |
function delay() external view returns (uint256); | |
function plot(address, bytes32, bytes calldata, uint256) external; | |
function exec(address, bytes32, bytes calldata, uint256) external returns (bytes memory); | |
} | |
interface Changelog { | |
function getAddress(bytes32) external view returns (address); | |
} | |
interface SpellAction { | |
function officeHours() external view returns (bool); | |
function description() external view returns (string memory); | |
function nextCastTime(uint256) external view returns (uint256); | |
} | |
contract DssExec { | |
Changelog constant public log = Changelog(0xdA0Ab1e0017DEbCd72Be8599041a2aa3bA7e740F); | |
uint256 public eta; | |
bytes public sig; | |
bool public done; | |
bytes32 immutable public tag; | |
address immutable public action; | |
uint256 immutable public expiration; | |
PauseAbstract 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 SpellAction(action).description(); | |
} | |
function officeHours() external view returns (bool) { | |
return SpellAction(action).officeHours(); | |
} | |
function nextCastTime() external view returns (uint256 castTime) { | |
return SpellAction(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 { | |
pause = PauseAbstract(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 + PauseAbstract(pause).delay(); | |
pause.plot(action, tag, sig, eta); | |
} | |
function cast() public { | |
require(!done, "spell-already-cast"); | |
done = true; | |
pause.exec(action, tag, sig, eta); | |
} | |
} | |
////// src/DssSpellCollateralOnboarding.sol | |
// | |
// Copyright (C) 2021-2022 Dai Foundation | |
// | |
// 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 "dss-exec-lib/DssExecLib.sol"; */ | |
contract DssSpellCollateralOnboardingAction { | |
// --- Rates --- | |
// 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 be found at | |
// https://ipfs.io/ipfs/QmTRiQ3GqjCiRhh1ojzKzgScmSsiwQPLyjhgYSxZASQekj | |
// | |
// --- Math --- | |
// --- DEPLOYED COLLATERAL ADDRESSES --- | |
function onboardNewCollaterals() internal { | |
// ----------------------------- Collateral onboarding ----------------------------- | |
// Add ______________ as a new Vault Type | |
// Poll Link: | |
// DssExecLib.addNewCollateral( | |
// CollateralOpts({ | |
// ilk: , | |
// gem: , | |
// join: , | |
// clip: , | |
// calc: , | |
// pip: , | |
// isLiquidatable: , | |
// isOSM: , | |
// whitelistOSM: , | |
// ilkDebtCeiling: , | |
// minVaultAmount: , | |
// maxLiquidationAmount: , | |
// liquidationPenalty: , | |
// ilkStabilityFee: , | |
// startingPriceFactor: , | |
// breakerTolerance: , | |
// auctionDuration: , | |
// permittedDrop: , | |
// liquidationRatio: , | |
// kprFlatReward: , | |
// kprPctReward: | |
// }) | |
// ); | |
// DssExecLib.setStairstepExponentialDecrease( | |
// CALC_ADDR, | |
// DURATION, | |
// PCT_BPS | |
// ); | |
// DssExecLib.setIlkAutoLineParameters( | |
// ILK, | |
// AMOUNT, | |
// GAP, | |
// TTL | |
// ); | |
// ChainLog Updates | |
// Add the new flip and join to the Chainlog | |
// address constant CHAINLOG = DssExecLib.LOG(); | |
// ChainlogAbstract(CHAINLOG).setAddress("<join-name>", <join-address>); | |
// ChainlogAbstract(CHAINLOG).setAddress("<clip-name>", <clip-address>); | |
// ChainlogAbstract(CHAINLOG).setVersion("<new-version>"); | |
} | |
} | |
////// src/DssSpell.sol | |
// | |
// Copyright (C) 2021-2022 Dai Foundation | |
// | |
// 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 "dss-exec-lib/DssExec.sol"; */ | |
/* import "dss-exec-lib/DssAction.sol"; */ | |
/* import { DssSpellCollateralOnboardingAction } from "./DssSpellCollateralOnboarding.sol"; */ | |
contract DssSpellAction is DssAction, DssSpellCollateralOnboardingAction { | |
// Provides a descriptive tag for bot consumption | |
// This should be modified weekly to provide a summary of the actions | |
// Hash: seth keccak -- "$(wget https://raw.githubusercontent.com/makerdao/community/c421b8a52031169aa55170b752206250ab2d15cf/governance/votes/Executive%20Vote%20-%20January%2021%2C%202022.md -q -O - 2>/dev/null)" | |
string public constant override description = | |
"2022-01-21 MakerDAO Executive Spell | Hash: 0x741fefda04e07fbdcceb7b5e3f9704694f353771154380b3fd13b52ead67837d"; | |
// --- Rates --- | |
uint256 constant ZERO_FIVE_PCT_RATE = 1000000000158153903837946257; | |
uint256 constant TWO_FIVE_PCT_RATE = 1000000000782997609082909351; | |
uint256 constant THREE_PCT_RATE = 1000000000937303470807876289; | |
// Math | |
uint256 constant MILLION = 10**6; | |
// Turn office hours off | |
function officeHours() public override returns (bool) { | |
return false; | |
} | |
function actions() public override { | |
// Includes changes from the DssSpellCollateralOnboardingAction | |
// onboardNewCollaterals(); | |
// ------------------------- Rates updates ----------------------------- | |
// https://vote.makerdao.com/polling/QmVyyjPF?network=mainnet#poll-detail | |
// Decrease the ETH-A Stability Fee from 2.75% to 2.5% | |
DssExecLib.setIlkStabilityFee("ETH-A", TWO_FIVE_PCT_RATE, true); | |
// Decrease the WSTETH-A Stability Fee from 4.0% to 3.0% | |
DssExecLib.setIlkStabilityFee("WSTETH-A", THREE_PCT_RATE, true); | |
// Decrease the GUNIV3DAIUSDC2-A Stability Fee from 1% to 0.5% | |
DssExecLib.setIlkStabilityFee("GUNIV3DAIUSDC2-A", ZERO_FIVE_PCT_RATE, true); | |
// ---------------------- Debt Ceiling updates ------------------------- | |
// https://vote.makerdao.com/polling/QmVyyjPF?network=mainnet#poll-detail | |
// Decrease the LINK-A Maximum Debt Ceiling from 140 million DAI to 100 million DAI. | |
DssExecLib.setIlkAutoLineDebtCeiling("LINK-A", 100 * MILLION); | |
// Decrease the YFI-A Maximum Debt Ceiling (line) from 130 million DAI to 50 million DAI | |
DssExecLib.setIlkAutoLineDebtCeiling("YFI-A", 50 * MILLION); | |
// Decrease the UNI-A Maximum Debt Ceiling (line) from 50 million DAI to 25 million DAI | |
DssExecLib.setIlkAutoLineDebtCeiling("UNI-A", 25 * MILLION); | |
// Decrease the UNIV2UNIETH-A Maximum Debt Ceiling (line) from 20 million DAI to 5 million DAI | |
DssExecLib.setIlkAutoLineDebtCeiling("UNIV2UNIETH-A", 5 * MILLION); | |
// Decrease the GUSD-A Debt Ceiling from 5 million DAI to zero DAI | |
DssExecLib.decreaseIlkDebtCeiling("GUSD-A", 5 * MILLION, true); | |
// Increase the GUNIV3DAIUSDC2-A Maximum Debt Ceiling (line) from 10 million DAI to 500 million DAI | |
DssExecLib.setIlkAutoLineDebtCeiling("GUNIV3DAIUSDC2-A", 500 * MILLION); | |
// ------------------ Liquiduation Ratio updates ----------------------- | |
// https://vote.makerdao.com/polling/QmbFqWGK?network=mainnet#poll-detail | |
// Decrease the GUNIV3DAIUSDC2-A Liquidation Ratio from 105% to 102% | |
DssExecLib.setIlkLiquidationRatio("GUNIV3DAIUSDC2-A", 10200); | |
// ------------------------- AAVE D3M updates -------------------------- | |
// https://vote.makerdao.com/polling/QmVyyjPF?network=mainnet#poll-detail | |
// Decrease the DIRECT-AAVEV2-DAI Target Borrow Rate (bar) from 3.9% to 3.75% | |
DssExecLib.setValue(DssExecLib.getChangelogAddress("MCD_JOIN_DIRECT_AAVEV2_DAI"), "bar", 3.75 * 10**27 / 100); | |
// Increase the DIRECT-AAVEV2-DAI Target Available Debt (gap) from 25 million DAI to 50 million DAI | |
// Increase the DIRECT-AAVEV2-DAI Maximum Debt Ceiling (line) from 100 million DAI to 220 million DAI | |
DssExecLib.setIlkAutoLineParameters("DIRECT-AAVEV2-DAI", 220 * MILLION, 50 * MILLION, 12 hours); | |
} | |
} | |
contract DssSpell is DssExec { | |
constructor() DssExec(block.timestamp + 30 days, address(new DssSpellAction())) public {} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment