Skip to content
This repository has been archived by the owner on Apr 22, 2024. It is now read-only.

Add usdt #200

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 65 additions & 87 deletions src/Goerli-DssSpell.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,33 +13,29 @@
//
// 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;
// Enable ABIEncoderV2 when onboarding collateral through `DssExecLib.addNewCollateral()`
// pragma experimental ABIEncoderV2;

import "dss-exec-lib/DssExec.sol";
import { CollateralOpts } from "dss-exec-lib/CollateralOpts.sol";
import "dss-interfaces/dss/IlkRegistryAbstract.sol";
import "dss-exec-lib/DssAction.sol";
// Enable ABIEncoderV2 when onboarding collateral through `DssExecLib.addNewCollateral()`
pragma experimental ABIEncoderV2;

interface RwaLiquidationLike {
function ilks(bytes32) external view returns (string memory, address, uint48, uint48);
function init(bytes32, uint256, string calldata, uint48) external;
function bump(bytes32 ilk, uint256 val) external;
}

interface ChainlogLike {
function removeAddress(bytes32) external;
interface Authorizable {
function rely(address) external;
function deny(address) external;
function setAuthority(address) external;
}

contract DssSpellAction is DssAction {
// Provides a descriptive tag for bot consumption
string public constant override description = "Goerli Spell";

// Turn office hours off
function officeHours() public override returns (bool) {
return false;
}

// 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%):
Expand All @@ -49,83 +45,65 @@ contract DssSpellAction is DssAction {
// A table of rates can be found at
// https://ipfs.io/ipfs/QmVp4mhhbwWGTfbh2BzwQB9eiBrQBKiqcPRZCaAxNUaar6
//

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

address immutable MIP21_LIQUIDATION_ORACLE = DssExecLib.getChangelogAddress("MIP21_LIQUIDATION_ORACLE");

function _updateDoc(bytes32 ilk, string memory doc) internal {
( , address pip, uint48 tau, ) = RwaLiquidationLike(MIP21_LIQUIDATION_ORACLE).ilks(ilk);
require(pip != address(0), "DssSpell/unexisting-rwa-ilk");

// Init the RwaLiquidationOracle to reset the doc
RwaLiquidationLike(MIP21_LIQUIDATION_ORACLE).init(
ilk, // ilk to update
0, // price ignored if init() has already been called
doc, // new legal document
tau // old tau value
);
}
uint256 internal constant TWO_FIVE_PCT_RATE = 1000000000782997609082909351;
uint256 constant THOUSAND = 10 ** 3;
uint256 constant MILLION = 10 ** 6;
// --- DEPLOYED COLLATERAL ADDRESSES ---
address internal constant USDT = 0xac0d203a8d9dD6EAf444d3DA95a0cfB3dcf9DBc9;
address internal constant VAL_USDT = 0xab6f09c3c3f0d25379690308fd63321bD655d218;
address internal constant PIP_USDT = 0x58b3586bF716e78D3036Af45A3d63a9fAd520f76;
address internal constant MCD_JOIN_USDT_A = 0xC186C13Eca0937697899018AF62B40460d3Cd148;
address internal constant MCD_CLIP_USDT_A = 0x812105Ff1A7546fB5160445E24b96fEf25980Fe8;
address internal constant MCD_CLIP_CALC_USDT_A = 0xecAFd89A7bf2d878aBf3fE903C4e806d8284fd80;
address internal constant ETH_FROM = 0x125fC0CcCDee5ac474062F6358d4d056b0430b84;

function actions() public override {
// -------------------- Update RWA007, RWA008, RWA009 Legal Documents ---------------------
// https://forum.makerdao.com/t/nov-16-2022-executive-contents/18747
//
// Monetalis (RWA007-A) legal update doc
_updateDoc("RWA007-A", "QmejL1CKKN5vCwp9QD1gebnnAM2MJSt9XbF64uy4ptkJtR");
// SG Forge OFH (RWA008-A) legal update doc
_updateDoc("RWA008-A", "QmZ4heYjptvj3ovafADJpXYMFXMyY3yQjkTXpvjFPnAKcy");
// HVB (RWA009-A) legal update doc
_updateDoc("RWA009-A", "QmeRrbDF8MVPQfNe83gWf2qV48jApVigm1WyjEtDXCZ5rT");

// RWA007-A autoline changes:
// - bump oralce price to 500m
// - increase DC to 500m
// - increase autoline `gap` to 100m
//
// https://vote.makerdao.com/polling/QmSfMtTM#poll-detail
DssExecLib.setIlkAutoLineParameters(
"RWA007-A",
500 * MILLION,
100 * MILLION,
1 weeks
);
RwaLiquidationLike(MIP21_LIQUIDATION_ORACLE).bump(
"RWA007-A",
500 * MILLION * WAD
);
DssExecLib.updateCollateralPrice("RWA007-A");

// RETH-A autoline changes:
// - line 5m
// - gap 3m
// - ttl 8h
//
// https://vote.makerdao.com/polling/QmfMswF2#poll-detail
DssExecLib.setIlkAutoLineParameters(
"RETH-A",
5 * MILLION,
3 * MILLION,
8 hours
);

// -------------------- Changelog Update & housekeeping ---------------------

// - Change "RWA007_A_INPUT_CONDUIT_URN" to "RWA007_A_INPUT_CONDUIT"
// - Change "RWA007_A_INPUT_CONDUIT_JAR" to "RWA007_A_JAR_INPUT_CONDUIT"
//
DssExecLib.setChangelogAddress("RWA007_A_INPUT_CONDUIT", DssExecLib.getChangelogAddress("RWA007_A_INPUT_CONDUIT_URN"));
DssExecLib.setChangelogAddress("RWA007_A_JAR_INPUT_CONDUIT", DssExecLib.getChangelogAddress("RWA007_A_INPUT_CONDUIT_JAR"));
ChainlogLike(DssExecLib.LOG).removeAddress("RWA007_A_INPUT_CONDUIT_URN");
ChainlogLike(DssExecLib.LOG).removeAddress("RWA007_A_INPUT_CONDUIT_JAR");

// Bump version
DssExecLib.setChangelogVersion("1.14.5");
// ----------------------------- Collateral onboarding -----------------------------
// Add USDT-A as a new Vault Type
// Poll Link: TODO
// Forum Post: https://forum.makerdao.com/t/USDT-collateral-onboarding-risk-evaluation/18820
CollateralOpts memory co = CollateralOpts({
ilk: "USDT-D",
gem: USDT,
join: MCD_JOIN_USDT_A,
clip: MCD_CLIP_USDT_A,
calc: MCD_CLIP_CALC_USDT_A,
pip: PIP_USDT,
isLiquidatable: true,
isOSM: true,
whitelistOSM: true,
ilkDebtCeiling: 100 * MILLION,
minVaultAmount: 7500,
maxLiquidationAmount: 25 * MILLION,
liquidationPenalty: 1300, // 13% penalty fee
ilkStabilityFee: TWO_FIVE_PCT_RATE, // 1.5% stability fee
startingPriceFactor: 12000, // Auction price begins at 120% of oracle
breakerTolerance: 5000, // Allows for a 50% hourly price drop before disabling liquidations
auctionDuration: 90 minutes,
permittedDrop: 4000, // 40% price drop before reset
liquidationRatio: 10100, // 175% collateralization
kprFlatReward: 300, // 300 Dai
kprPctReward: 10 // 0.1%
});

DssExecLib.addNewCollateral(co);
DssExecLib.setStairstepExponentialDecrease(MCD_CLIP_CALC_USDT_A, 130 seconds, 9900);
DssExecLib.setIlkAutoLineParameters("USDT-D", 20 * MILLION, 3 * MILLION, 8 hours);
IlkRegistryAbstract(DssExecLib.reg()).update("USDT-D");
DssExecLib.setChangelogAddress("USDT", USDT);
DssExecLib.setChangelogAddress("PIP_USDT", PIP_USDT);
DssExecLib.setChangelogAddress("MCD_JOIN_USDT_D", MCD_JOIN_USDT_A);
DssExecLib.setChangelogAddress("MCD_CLIP_USDT_D", MCD_CLIP_USDT_A);
DssExecLib.setChangelogAddress("MCD_CLIP_CALC_USDT_D", MCD_CLIP_CALC_USDT_A);
// Denying the ETH_FROM Address
Authorizable(VAL_USDT).deny(ETH_FROM);
Authorizable(PIP_USDT).deny(ETH_FROM);
Authorizable(MCD_JOIN_USDT_A).deny(ETH_FROM);
Authorizable(MCD_CLIP_USDT_A).deny(ETH_FROM);
Authorizable(MCD_CLIP_CALC_USDT_A).deny(ETH_FROM);
}
}

contract DssSpell is DssExec {
constructor() DssExec(block.timestamp + 30 days, address(new DssSpellAction())) public {}
}
constructor() DssExec(block.timestamp + 30 days, address(new DssSpellAction())) public {
}
}
8 changes: 4 additions & 4 deletions src/Goerli-DssSpell.t.base.sol
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,7 @@ contract GoerliDssSpellTestBase is Config, DSTest, DSMath {
}
uint256 normalizedTestDust = values.collaterals[ilk].dust * RAD;
assertEq(dust, normalizedTestDust, concat("TestError/vat-dust-", ilk));
assertTrue((dust >= RAD && dust < 100 * THOUSAND * RAD) || dust == 0, concat("TestError/vat-dust-range-", ilk)); // eq 0 or gt eq 1 and lt 100k
assertTrue((dust >= RAD && dust <= 100 * THOUSAND * RAD) || dust == 0, concat("TestError/vat-dust-range-", ilk)); // eq 0 or gt eq 1 and lte 100k
}

{
Expand Down Expand Up @@ -636,9 +636,9 @@ contract GoerliDssSpellTestBase is Config, DSTest, DSMath {
assertTrue(clip.buf() >= RAY && clip.buf() <= 2 * RAY, concat("TestError/clip-buf-range-", ilk)); // gte 0% and lte 100%
assertEq(uint256(clip.tail()), values.collaterals[ilk].clip_tail, concat("TestError/clip-tail-", ilk));
if (ilk == "TUSD-A") { // long tail liquidation
assertTrue(clip.tail() >= 1200 && clip.tail() < 30 days, concat("TestError/TUSD-clip-tail-range-", ilk)); // gt eq 20 minutes and lt 10 hours
assertTrue(clip.tail() >= 1200 && clip.tail() <= 30 days, concat("TestError/TUSD-clip-tail-range-", ilk)); // gt eq 20 minutes and lte 30 days
} else {
assertTrue(clip.tail() >= 1200 && clip.tail() < 10 hours, concat("TestError/clip-tail-range-", ilk)); // gt eq 20 minutes and lt 10 hours
assertTrue(clip.tail() >= 1200 && clip.tail() <= 12 hours, concat("TestError/clip-tail-range-", ilk)); // gt eq 20 minutes and lte 12 hours
}
uint256 normalizedTestCusp = (values.collaterals[ilk].clip_cusp) * 10**23;
assertEq(uint256(clip.cusp()), normalizedTestCusp, concat("TestError/clip-cusp-", ilk));
Expand Down Expand Up @@ -857,7 +857,7 @@ contract GoerliDssSpellTestBase is Config, DSTest, DSMath {

(,,,, uint256 dust) = vat.ilks(_ilk);
dust /= RAY;
uint256 amount = 2 * dust * 10 ** uint256(token.decimals()) / (_isOSM ? getOSMPrice(pip) : uint256(DSValueAbstract(pip).read()));
uint256 amount = 4 * dust * 10 ** uint256(token.decimals()) / (_isOSM ? getOSMPrice(pip) : uint256(DSValueAbstract(pip).read()));
uint256 amount18 = token.decimals() == 18 ? amount : amount * 10**(18 - uint256(token.decimals()));
giveTokens(address(token), amount);

Expand Down
Loading