Skip to content

Instantly share code, notes, and snippets.

@talbaneth
Created January 21, 2022 17:59
Show Gist options
  • Save talbaneth/54c5c108f50535ca8b9434de418c110f to your computer and use it in GitHub Desktop.
Save talbaneth/54c5c108f50535ca8b9434de418c110f to your computer and use it in GitHub Desktop.
// 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