Token Mor Stablecoin
Overview ERC-20
Price
$0.98 @ 2.168317 FTM
Fully Diluted Market Cap
Total Supply:
57,737.234469 MOR
Holders:
163 addresses
Transfers:
-
Contract:
Decimals:
18
Official Site:
[ Download CSV Export ]
[ Download CSV Export ]
OVERVIEW
At Growth DeFi focus has been developing a fresh and expansive ecosystem with multiple investment options and providing opportunities for investors to experience an earnings loop.Update? Click here to update the token ICO / general information
# | Exchange | Pair | Price | 24H Volume | % Volume |
---|
Contract Name:
Dai
Compiler Version
v0.6.12+commit.27d51765
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2022-02-18 */ /** *Submitted for verification at snowtrace.io on 2021-11-06 */ /** *Submitted for verification at BscScan.com on 2021-08-28 */ // SPDX-License-Identifier: AGPL-3.0-or-later /// DssDeploy.sol // Copyright (C) 2018-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.5.12; interface DSAuthority { function canCall( address src, address dst, bytes4 sig ) external view returns (bool); } contract DSAuthEvents { event LogSetAuthority (address indexed authority); event LogSetOwner (address indexed owner); } contract DSAuth is DSAuthEvents { DSAuthority public authority; address public owner; constructor() public { owner = msg.sender; emit LogSetOwner(msg.sender); } function setOwner(address owner_) public virtual auth { owner = owner_; emit LogSetOwner(owner); } function setAuthority(DSAuthority authority_) public virtual auth { authority = authority_; emit LogSetAuthority(address(authority)); } modifier auth { require(isAuthorized(msg.sender, msg.sig), "ds-auth-unauthorized"); _; } function isAuthorized(address src, bytes4 sig) internal view returns (bool) { if (src == address(this)) { return true; } else if (src == owner) { return true; } else if (authority == DSAuthority(address(0))) { return false; } else { return authority.canCall(src, address(this), sig); } } } contract DSNote { event LogNote( bytes4 indexed sig, address indexed guy, bytes32 indexed foo, bytes32 indexed bar, uint256 wad, bytes fax ) anonymous; modifier note { bytes32 foo; bytes32 bar; uint256 wad; assembly { foo := calldataload(4) bar := calldataload(36) wad := callvalue() } _; emit LogNote(msg.sig, msg.sender, foo, bar, wad, msg.data); } } contract DSPause is DSAuth, DSNote { // --- admin --- modifier wait { require(msg.sender == address(proxy), "ds-pause-undelayed-call"); _; } function setOwner(address owner_) public override wait { owner = owner_; emit LogSetOwner(owner); } function setAuthority(DSAuthority authority_) public override wait { authority = authority_; emit LogSetAuthority(address(authority)); } function setDelay(uint delay_) public note wait { delay = delay_; } // --- math --- function _add(uint x, uint y) internal pure returns (uint z) { z = x + y; require(z >= x, "ds-pause-addition-overflow"); } // --- data --- mapping (bytes32 => bool) public plans; DSPauseProxy public proxy; uint public delay; // --- init --- constructor(uint delay_, address owner_, DSAuthority authority_) public { delay = delay_; owner = owner_; authority = authority_; proxy = new DSPauseProxy(); } // --- util --- function hash(address usr, bytes32 tag, bytes memory fax, uint eta) internal pure returns (bytes32) { return keccak256(abi.encode(usr, tag, fax, eta)); } function soul(address usr) internal view returns (bytes32 tag) { assembly { tag := extcodehash(usr) } } // --- operations --- function plot(address usr, bytes32 tag, bytes memory fax, uint eta) public note auth { require(eta >= _add(now, delay), "ds-pause-delay-not-respected"); plans[hash(usr, tag, fax, eta)] = true; } function drop(address usr, bytes32 tag, bytes memory fax, uint eta) public note auth { plans[hash(usr, tag, fax, eta)] = false; } function exec(address usr, bytes32 tag, bytes memory fax, uint eta) public note returns (bytes memory out) { require(plans[hash(usr, tag, fax, eta)], "ds-pause-unplotted-plan"); require(soul(usr) == tag, "ds-pause-wrong-codehash"); require(now >= eta, "ds-pause-premature-exec"); plans[hash(usr, tag, fax, eta)] = false; out = proxy.exec(usr, fax); require(proxy.owner() == address(this), "ds-pause-illegal-storage-change"); } } // plans are executed in an isolated storage context to protect the pause from // malicious storage modification during plan execution contract DSPauseProxy { address public owner; modifier auth { require(msg.sender == owner, "ds-pause-proxy-unauthorized"); _; } constructor() public { owner = msg.sender; } function exec(address usr, bytes memory fax) public auth returns (bytes memory out) { bool ok; (ok, out) = usr.delegatecall(fax); require(ok, "ds-pause-delegatecall-error"); } } contract DSMath { function add(uint x, uint y) internal pure returns (uint z) { require((z = x + y) >= x, "ds-math-add-overflow"); } function sub(uint x, uint y) internal pure returns (uint z) { require((z = x - y) <= x, "ds-math-sub-underflow"); } function mul(uint x, uint y) internal pure returns (uint z) { require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow"); } function min(uint x, uint y) internal pure returns (uint z) { return x <= y ? x : y; } function max(uint x, uint y) internal pure returns (uint z) { return x >= y ? x : y; } function imin(int x, int y) internal pure returns (int z) { return x <= y ? x : y; } function imax(int x, int y) internal pure returns (int z) { return x >= y ? x : y; } uint constant WAD = 10 ** 18; uint constant RAY = 10 ** 27; //rounds to zero if x*y < WAD / 2 function wmul(uint x, uint y) internal pure returns (uint z) { z = add(mul(x, y), WAD / 2) / WAD; } //rounds to zero if x*y < WAD / 2 function rmul(uint x, uint y) internal pure returns (uint z) { z = add(mul(x, y), RAY / 2) / RAY; } //rounds to zero if x*y < WAD / 2 function wdiv(uint x, uint y) internal pure returns (uint z) { z = add(mul(x, WAD), y / 2) / y; } //rounds to zero if x*y < RAY / 2 function rdiv(uint x, uint y) internal pure returns (uint z) { z = add(mul(x, RAY), y / 2) / y; } // This famous algorithm is called "exponentiation by squaring" // and calculates x^n with x as fixed-point and n as regular unsigned. // // It's O(log n), instead of O(n) for naive repeated multiplication. // // These facts are why it works: // // If n is even, then x^n = (x^2)^(n/2). // If n is odd, then x^n = x * x^(n-1), // and applying the equation for even x gives // x^n = x * (x^2)^((n-1) / 2). // // Also, EVM division is flooring and // floor[(n-1) / 2] = floor[n / 2]. // function rpow(uint x, uint n) internal pure returns (uint z) { z = n % 2 != 0 ? x : RAY; for (n /= 2; n != 0; n /= 2) { x = rmul(x, x); if (n % 2 != 0) { z = rmul(z, x); } } } } contract DSToken is DSMath, DSAuth { bool public stopped; uint256 public totalSupply; mapping (address => uint256) public balanceOf; mapping (address => mapping (address => uint256)) public allowance; string public symbol; uint8 public decimals = 18; // standard token precision. override to customize string public name = ""; // Optional token name constructor(string memory symbol_) public { symbol = symbol_; } event Approval(address indexed src, address indexed guy, uint wad); event Transfer(address indexed src, address indexed dst, uint wad); event Mint(address indexed guy, uint wad); event Burn(address indexed guy, uint wad); event Stop(); event Start(); modifier stoppable { require(!stopped, "ds-stop-is-stopped"); _; } function approve(address guy) external returns (bool) { return approve(guy, uint(-1)); } function approve(address guy, uint wad) public stoppable returns (bool) { allowance[msg.sender][guy] = wad; emit Approval(msg.sender, guy, wad); return true; } function transfer(address dst, uint wad) external returns (bool) { return transferFrom(msg.sender, dst, wad); } function transferFrom(address src, address dst, uint wad) public stoppable returns (bool) { if (src != msg.sender && allowance[src][msg.sender] != uint(-1)) { require(allowance[src][msg.sender] >= wad, "ds-token-insufficient-approval"); allowance[src][msg.sender] = sub(allowance[src][msg.sender], wad); } require(balanceOf[src] >= wad, "ds-token-insufficient-balance"); balanceOf[src] = sub(balanceOf[src], wad); balanceOf[dst] = add(balanceOf[dst], wad); emit Transfer(src, dst, wad); return true; } /* function push(address dst, uint wad) external { transferFrom(msg.sender, dst, wad); } function pull(address src, uint wad) external { transferFrom(src, msg.sender, wad); } function move(address src, address dst, uint wad) external { transferFrom(src, dst, wad); } */ function mint(uint wad) external { mint(msg.sender, wad); } function burn(uint wad) external { burn(msg.sender, wad); } function mint(address guy, uint wad) public auth stoppable { balanceOf[guy] = add(balanceOf[guy], wad); totalSupply = add(totalSupply, wad); emit Mint(guy, wad); } function burn(address guy, uint wad) public auth stoppable { if (guy != msg.sender && allowance[guy][msg.sender] != uint(-1)) { require(allowance[guy][msg.sender] >= wad, "ds-token-insufficient-approval"); allowance[guy][msg.sender] = sub(allowance[guy][msg.sender], wad); } require(balanceOf[guy] >= wad, "ds-token-insufficient-balance"); balanceOf[guy] = sub(balanceOf[guy], wad); totalSupply = sub(totalSupply, wad); emit Burn(guy, wad); } function stop() public auth { stopped = true; emit Stop(); } function start() public auth { stopped = false; emit Start(); } function setName(string memory name_) public auth { name = name_; } } contract Vat is DSNote { // --- Auth --- mapping (address => uint) public wards; function rely(address usr) external note auth { require(live == 1, "Vat/not-live"); wards[usr] = 1; } function deny(address usr) external note auth { require(live == 1, "Vat/not-live"); wards[usr] = 0; } modifier auth { require(wards[msg.sender] == 1, "Vat/not-authorized"); _; } mapping(address => mapping (address => uint)) public can; function hope(address usr) external note { can[msg.sender][usr] = 1; } function nope(address usr) external note { can[msg.sender][usr] = 0; } function wish(address bit, address usr) internal view returns (bool) { return either(bit == usr, can[bit][usr] == 1); } // --- Data --- struct Ilk { uint256 Art; // Total Normalised Debt [wad] uint256 rate; // Accumulated Rates [ray] uint256 spot; // Price with Safety Margin [ray] uint256 line; // Debt Ceiling [rad] uint256 dust; // Urn Debt Floor [rad] } struct Urn { uint256 ink; // Locked Collateral [wad] uint256 art; // Normalised Debt [wad] } mapping (bytes32 => Ilk) public ilks; mapping (bytes32 => mapping (address => Urn )) public urns; mapping (bytes32 => mapping (address => uint)) public gem; // [wad] mapping (address => uint256) public dai; // [rad] mapping (address => uint256) public sin; // [rad] uint256 public debt; // Total Dai Issued [rad] uint256 public vice; // Total Unbacked Dai [rad] uint256 public Line; // Total Debt Ceiling [rad] uint256 public live; // Active Flag // --- Init --- constructor() public { wards[msg.sender] = 1; live = 1; } // --- Math --- function _add(uint x, int y) internal pure returns (uint z) { z = x + uint(y); require(y >= 0 || z <= x); require(y <= 0 || z >= x); } function _sub(uint x, int y) internal pure returns (uint z) { z = x - uint(y); require(y <= 0 || z <= x); require(y >= 0 || z >= x); } function _mul(uint x, int y) internal pure returns (int z) { z = int(x) * y; require(int(x) >= 0); require(y == 0 || z / y == int(x)); } function _add(uint x, uint y) internal pure returns (uint z) { require((z = x + y) >= x); } function _sub(uint x, uint y) internal pure returns (uint z) { require((z = x - y) <= x); } function _mul(uint x, uint y) internal pure returns (uint z) { require(y == 0 || (z = x * y) / y == x); } // --- Administration --- function init(bytes32 ilk) external note auth { require(ilks[ilk].rate == 0, "Vat/ilk-already-init"); ilks[ilk].rate = 10 ** 27; } function file(bytes32 what, uint data) external note auth { require(live == 1, "Vat/not-live"); if (what == "Line") Line = data; else revert("Vat/file-unrecognized-param"); } function file(bytes32 ilk, bytes32 what, uint data) external note auth { require(live == 1, "Vat/not-live"); if (what == "spot") ilks[ilk].spot = data; else if (what == "line") ilks[ilk].line = data; else if (what == "dust") ilks[ilk].dust = data; else revert("Vat/file-unrecognized-param"); } function cage() external note auth { live = 0; } // --- Fungibility --- function slip(bytes32 ilk, address usr, int256 wad) external note auth { gem[ilk][usr] = _add(gem[ilk][usr], wad); } function flux(bytes32 ilk, address src, address dst, uint256 wad) external note { require(wish(src, msg.sender), "Vat/not-allowed"); gem[ilk][src] = _sub(gem[ilk][src], wad); gem[ilk][dst] = _add(gem[ilk][dst], wad); } function move(address src, address dst, uint256 rad) external note { require(wish(src, msg.sender), "Vat/not-allowed"); dai[src] = _sub(dai[src], rad); dai[dst] = _add(dai[dst], rad); } function either(bool x, bool y) internal pure returns (bool z) { assembly{ z := or(x, y)} } function both(bool x, bool y) internal pure returns (bool z) { assembly{ z := and(x, y)} } // --- CDP Manipulation --- function frob(bytes32 i, address u, address v, address w, int dink, int dart) external note { // system is live require(live == 1, "Vat/not-live"); Urn memory urn = urns[i][u]; Ilk memory ilk = ilks[i]; // ilk has been initialised require(ilk.rate != 0, "Vat/ilk-not-init"); urn.ink = _add(urn.ink, dink); urn.art = _add(urn.art, dart); ilk.Art = _add(ilk.Art, dart); int dtab = _mul(ilk.rate, dart); uint tab = _mul(ilk.rate, urn.art); debt = _add(debt, dtab); // either debt has decreased, or debt ceilings are not exceeded require(either(dart <= 0, both(_mul(ilk.Art, ilk.rate) <= ilk.line, debt <= Line)), "Vat/ceiling-exceeded"); // urn is either less risky than before, or it is safe require(either(both(dart <= 0, dink >= 0), tab <= _mul(urn.ink, ilk.spot)), "Vat/not-safe"); // urn is either more safe, or the owner consents require(either(both(dart <= 0, dink >= 0), wish(u, msg.sender)), "Vat/not-allowed-u"); // collateral src consents require(either(dink <= 0, wish(v, msg.sender)), "Vat/not-allowed-v"); // debt dst consents require(either(dart >= 0, wish(w, msg.sender)), "Vat/not-allowed-w"); // urn has no debt, or a non-dusty amount require(either(urn.art == 0, tab >= ilk.dust), "Vat/dust"); gem[i][v] = _sub(gem[i][v], dink); dai[w] = _add(dai[w], dtab); urns[i][u] = urn; ilks[i] = ilk; } // --- CDP Fungibility --- function fork(bytes32 ilk, address src, address dst, int dink, int dart) external note { Urn storage u = urns[ilk][src]; Urn storage v = urns[ilk][dst]; Ilk storage i = ilks[ilk]; u.ink = _sub(u.ink, dink); u.art = _sub(u.art, dart); v.ink = _add(v.ink, dink); v.art = _add(v.art, dart); uint utab = _mul(u.art, i.rate); uint vtab = _mul(v.art, i.rate); // both sides consent require(both(wish(src, msg.sender), wish(dst, msg.sender)), "Vat/not-allowed"); // both sides safe require(utab <= _mul(u.ink, i.spot), "Vat/not-safe-src"); require(vtab <= _mul(v.ink, i.spot), "Vat/not-safe-dst"); // both sides non-dusty require(either(utab >= i.dust, u.art == 0), "Vat/dust-src"); require(either(vtab >= i.dust, v.art == 0), "Vat/dust-dst"); } // --- CDP Confiscation --- function grab(bytes32 i, address u, address v, address w, int dink, int dart) external note auth { Urn storage urn = urns[i][u]; Ilk storage ilk = ilks[i]; urn.ink = _add(urn.ink, dink); urn.art = _add(urn.art, dart); ilk.Art = _add(ilk.Art, dart); int dtab = _mul(ilk.rate, dart); gem[i][v] = _sub(gem[i][v], dink); sin[w] = _sub(sin[w], dtab); vice = _sub(vice, dtab); } // --- Settlement --- function heal(uint rad) external note { address u = msg.sender; sin[u] = _sub(sin[u], rad); dai[u] = _sub(dai[u], rad); vice = _sub(vice, rad); debt = _sub(debt, rad); } function suck(address u, address v, uint rad) external note auth { sin[u] = _add(sin[u], rad); dai[v] = _add(dai[v], rad); vice = _add(vice, rad); debt = _add(debt, rad); } // --- Rates --- function fold(bytes32 i, address u, int rate) external note auth { require(live == 1, "Vat/not-live"); Ilk storage ilk = ilks[i]; ilk.rate = _add(ilk.rate, rate); int rad = _mul(ilk.Art, rate); dai[u] = _add(dai[u], rad); debt = _add(debt, rad); } } contract Jug is DSNote { // --- Auth --- mapping (address => uint) public wards; function rely(address usr) external note auth { wards[usr] = 1; } function deny(address usr) external note auth { wards[usr] = 0; } modifier auth { require(wards[msg.sender] == 1, "Jug/not-authorized"); _; } // --- Data --- struct Ilk { uint256 duty; // Collateral-specific, per-second stability fee contribution [ray] uint256 rho; // Time of last drip [unix epoch time] } mapping (bytes32 => Ilk) public ilks; Vat public vat; // CDP Engine address public vow; // Debt Engine uint256 public base; // Global, per-second stability fee contribution [ray] // --- Init --- constructor(address vat_) public { wards[msg.sender] = 1; vat = Vat(vat_); } // --- Math --- function rpow(uint x, uint n, uint b) internal pure returns (uint z) { assembly { switch x case 0 {switch n case 0 {z := b} default {z := 0}} default { switch mod(n, 2) case 0 { z := b } default { z := x } let half := div(b, 2) // for rounding. for { n := div(n, 2) } n { n := div(n,2) } { let xx := mul(x, x) if iszero(eq(div(xx, x), x)) { revert(0,0) } let xxRound := add(xx, half) if lt(xxRound, xx) { revert(0,0) } x := div(xxRound, b) if mod(n,2) { let zx := mul(z, x) if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0,0) } let zxRound := add(zx, half) if lt(zxRound, zx) { revert(0,0) } z := div(zxRound, b) } } } } } uint256 constant ONE = 10 ** 27; function _add(uint x, uint y) internal pure returns (uint z) { z = x + y; require(z >= x); } function diff(uint x, uint y) internal pure returns (int z) { z = int(x) - int(y); require(int(x) >= 0 && int(y) >= 0); } function rmul(uint x, uint y) internal pure returns (uint z) { z = x * y; require(y == 0 || z / y == x); z = z / ONE; } // --- Administration --- function init(bytes32 ilk) external note auth { Ilk storage i = ilks[ilk]; require(i.duty == 0, "Jug/ilk-already-init"); i.duty = ONE; i.rho = now; } function file(bytes32 ilk, bytes32 what, uint data) external note auth { require(now == ilks[ilk].rho, "Jug/rho-not-updated"); if (what == "duty") ilks[ilk].duty = data; else revert("Jug/file-unrecognized-param"); } function file(bytes32 what, uint data) external note auth { if (what == "base") base = data; else revert("Jug/file-unrecognized-param"); } function file(bytes32 what, address data) external note auth { if (what == "vow") vow = data; else revert("Jug/file-unrecognized-param"); } // --- Stability Fee Collection --- function drip(bytes32 ilk) external note returns (uint rate) { require(now >= ilks[ilk].rho, "Jug/invalid-now"); (, uint prev,,,) = vat.ilks(ilk); rate = rmul(rpow(_add(base, ilks[ilk].duty), now - ilks[ilk].rho, ONE), prev); vat.fold(ilk, vow, diff(rate, prev)); ilks[ilk].rho = now; } } interface PipLike { function peek() external view returns (bytes32, bool); function read() external view returns (bytes32); } contract Spotter is DSNote { // --- Auth --- mapping (address => uint) public wards; function rely(address guy) external note auth { wards[guy] = 1; } function deny(address guy) external note auth { wards[guy] = 0; } modifier auth { require(wards[msg.sender] == 1, "Spotter/not-authorized"); _; } // --- Data --- struct Ilk { PipLike pip; // Price Feed uint256 mat; // Liquidation ratio [ray] } mapping (bytes32 => Ilk) public ilks; Vat public vat; // CDP Engine uint256 public par; // ref per dai [ray] uint256 public live; // --- Events --- event Poke( bytes32 ilk, bytes32 val, // [wad] uint256 spot // [ray] ); // --- Init --- constructor(address vat_) public { wards[msg.sender] = 1; vat = Vat(vat_); par = ONE; live = 1; } // --- Math --- uint constant ONE = 10 ** 27; function mul(uint x, uint y) internal pure returns (uint z) { require(y == 0 || (z = x * y) / y == x); } function rdiv(uint x, uint y) internal pure returns (uint z) { z = mul(x, ONE) / y; } // --- Administration --- function file(bytes32 ilk, bytes32 what, address pip_) external note auth { require(live == 1, "Spotter/not-live"); if (what == "pip") ilks[ilk].pip = PipLike(pip_); else revert("Spotter/file-unrecognized-param"); } function file(bytes32 what, uint data) external note auth { require(live == 1, "Spotter/not-live"); if (what == "par") par = data; else revert("Spotter/file-unrecognized-param"); } function file(bytes32 ilk, bytes32 what, uint data) external note auth { require(live == 1, "Spotter/not-live"); if (what == "mat") ilks[ilk].mat = data; else revert("Spotter/file-unrecognized-param"); } // --- Update value --- function poke(bytes32 ilk) external { (bytes32 val, bool has) = ilks[ilk].pip.peek(); uint256 spot = has ? rdiv(rdiv(mul(uint(val), 10 ** 9), par), ilks[ilk].mat) : 0; vat.file(ilk, "spot", spot); emit Poke(ilk, val, spot); } function cage() external note auth { live = 0; } } /* "Savings Dai" is obtained when Dai is deposited into this contract. Each "Savings Dai" accrues Dai interest at the "Dai Savings Rate". This contract does not implement a user tradeable token and is intended to be used with adapters. --- `save` your `dai` in the `pot` --- - `dsr`: the Dai Savings Rate - `pie`: user balance of Savings Dai - `join`: start saving some dai - `exit`: remove some dai - `drip`: perform rate collection */ contract Pot is DSNote { // --- Auth --- mapping (address => uint) public wards; function rely(address guy) external note auth { wards[guy] = 1; } function deny(address guy) external note auth { wards[guy] = 0; } modifier auth { require(wards[msg.sender] == 1, "Pot/not-authorized"); _; } // --- Data --- mapping (address => uint256) public pie; // Normalised Savings Dai [wad] uint256 public Pie; // Total Normalised Savings Dai [wad] uint256 public dsr; // The Dai Savings Rate [ray] uint256 public chi; // The Rate Accumulator [ray] Vat public vat; // CDP Engine address public vow; // Debt Engine uint256 public rho; // Time of last drip [unix epoch time] uint256 public live; // Active Flag // --- Init --- constructor(address vat_) public { wards[msg.sender] = 1; vat = Vat(vat_); dsr = ONE; chi = ONE; rho = now; live = 1; } // --- Math --- uint256 constant ONE = 10 ** 27; function rpow(uint x, uint n, uint base) internal pure returns (uint z) { assembly { switch x case 0 {switch n case 0 {z := base} default {z := 0}} default { switch mod(n, 2) case 0 { z := base } default { z := x } let half := div(base, 2) // for rounding. for { n := div(n, 2) } n { n := div(n,2) } { let xx := mul(x, x) if iszero(eq(div(xx, x), x)) { revert(0,0) } let xxRound := add(xx, half) if lt(xxRound, xx) { revert(0,0) } x := div(xxRound, base) if mod(n,2) { let zx := mul(z, x) if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0,0) } let zxRound := add(zx, half) if lt(zxRound, zx) { revert(0,0) } z := div(zxRound, base) } } } } } function rmul(uint x, uint y) internal pure returns (uint z) { z = _mul(x, y) / ONE; } function _add(uint x, uint y) internal pure returns (uint z) { require((z = x + y) >= x); } function _sub(uint x, uint y) internal pure returns (uint z) { require((z = x - y) <= x); } function _mul(uint x, uint y) internal pure returns (uint z) { require(y == 0 || (z = x * y) / y == x); } // --- Administration --- function file(bytes32 what, uint256 data) external note auth { require(live == 1, "Pot/not-live"); require(now == rho, "Pot/rho-not-updated"); if (what == "dsr") dsr = data; else revert("Pot/file-unrecognized-param"); } function file(bytes32 what, address addr) external note auth { if (what == "vow") vow = addr; else revert("Pot/file-unrecognized-param"); } function cage() external note auth { live = 0; dsr = ONE; } // --- Savings Rate Accumulation --- function drip() external note returns (uint tmp) { require(now >= rho, "Pot/invalid-now"); tmp = rmul(rpow(dsr, now - rho, ONE), chi); uint chi_ = _sub(tmp, chi); chi = tmp; rho = now; vat.suck(address(vow), address(this), _mul(Pie, chi_)); } // --- Savings Dai Management --- function join(uint wad) external note { require(now == rho, "Pot/rho-not-updated"); pie[msg.sender] = _add(pie[msg.sender], wad); Pie = _add(Pie, wad); vat.move(msg.sender, address(this), _mul(chi, wad)); } function exit(uint wad) external note { pie[msg.sender] = _sub(pie[msg.sender], wad); Pie = _sub(Pie, wad); vat.move(address(this), msg.sender, _mul(chi, wad)); } } contract Dai is DSNote { // --- Auth --- mapping (address => uint) public wards; function rely(address guy) external note auth { wards[guy] = 1; } function deny(address guy) external note auth { wards[guy] = 0; } modifier auth { require(wards[msg.sender] == 1, "Dai/not-authorized"); _; } // --- ERC20 Data --- string public constant name = "Mor Stablecoin"; string public constant symbol = "MOR"; string public constant version = "1"; uint8 public constant decimals = 18; uint256 public totalSupply; mapping (address => uint) public balanceOf; mapping (address => mapping (address => uint)) public allowance; mapping (address => uint) public nonces; event Approval(address indexed src, address indexed guy, uint wad); event Transfer(address indexed src, address indexed dst, uint wad); // --- Math --- function add(uint x, uint y) internal pure returns (uint z) { require((z = x + y) >= x); } function sub(uint x, uint y) internal pure returns (uint z) { require((z = x - y) <= x); } // --- EIP712 niceties --- bytes32 public DOMAIN_SEPARATOR; // bytes32 public constant PERMIT_TYPEHASH = keccak256("Permit(address holder,address spender,uint256 nonce,uint256 expiry,bool allowed)"); bytes32 public constant PERMIT_TYPEHASH = 0xea2aa0a1be11a07ed86d755c93467f4f82362b452371d1ba94d1715123511acb; constructor(uint256 chainId_) public { wards[msg.sender] = 1; DOMAIN_SEPARATOR = keccak256(abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes(name)), keccak256(bytes(version)), chainId_, address(this) )); } // --- Token --- function transfer(address dst, uint wad) external returns (bool) { return transferFrom(msg.sender, dst, wad); } function transferFrom(address src, address dst, uint wad) public returns (bool) { require(balanceOf[src] >= wad, "Dai/insufficient-balance"); if (src != msg.sender && allowance[src][msg.sender] != uint(-1)) { require(allowance[src][msg.sender] >= wad, "Dai/insufficient-allowance"); allowance[src][msg.sender] = sub(allowance[src][msg.sender], wad); } balanceOf[src] = sub(balanceOf[src], wad); balanceOf[dst] = add(balanceOf[dst], wad); emit Transfer(src, dst, wad); return true; } function mint(address usr, uint wad) external auth { balanceOf[usr] = add(balanceOf[usr], wad); totalSupply = add(totalSupply, wad); emit Transfer(address(0), usr, wad); } function burn(address usr, uint wad) external { require(balanceOf[usr] >= wad, "Dai/insufficient-balance"); if (usr != msg.sender && allowance[usr][msg.sender] != uint(-1)) { require(allowance[usr][msg.sender] >= wad, "Dai/insufficient-allowance"); allowance[usr][msg.sender] = sub(allowance[usr][msg.sender], wad); } balanceOf[usr] = sub(balanceOf[usr], wad); totalSupply = sub(totalSupply, wad); emit Transfer(usr, address(0), wad); } function approve(address usr, uint wad) external returns (bool) { allowance[msg.sender][usr] = wad; emit Approval(msg.sender, usr, wad); return true; } // --- Alias --- /* function push(address usr, uint wad) external { transferFrom(msg.sender, usr, wad); } function pull(address usr, uint wad) external { transferFrom(usr, msg.sender, wad); } function move(address src, address dst, uint wad) external { transferFrom(src, dst, wad); } */ // --- Approve by signature --- function permit(address holder, address spender, uint256 nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s) external { bytes32 digest = keccak256(abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR, keccak256(abi.encode(PERMIT_TYPEHASH, holder, spender, nonce, expiry, allowed)) )); require(holder != address(0), "Dai/invalid-address-0"); require(holder == ecrecover(digest, v, r, s), "Dai/invalid-permit"); require(expiry == 0 || now <= expiry, "Dai/permit-expired"); require(nonce == nonces[holder]++, "Dai/invalid-nonce"); uint wad = allowed ? uint(-1) : 0; allowance[holder][spender] = wad; emit Approval(holder, spender, wad); } } /* Here we provide *adapters* to connect the Vat to arbitrary external token implementations, creating a bounded context for the Vat. The adapters here are provided as working examples: - `GemJoin`: For well behaved ERC20 tokens, with simple transfer semantics. - `ETHJoin`: For native Ether. - `DaiJoin`: For connecting internal Dai balances to an external `DSToken` implementation. In practice, adapter implementations will be varied and specific to individual collateral types, accounting for different transfer semantics and token standards. Adapters need to implement two basic methods: - `join`: enter collateral into the system - `exit`: remove collateral from the system */ contract GemJoin is DSNote { // --- Auth --- mapping (address => uint) public wards; function rely(address usr) external note auth { wards[usr] = 1; } function deny(address usr) external note auth { wards[usr] = 0; } modifier auth { require(wards[msg.sender] == 1, "GemJoin/not-authorized"); _; } Vat public vat; // CDP Engine bytes32 public ilk; // Collateral Type DSToken public gem; uint public dec; uint public live; // Active Flag constructor(address vat_, bytes32 ilk_, address gem_) public { wards[msg.sender] = 1; live = 1; vat = Vat(vat_); ilk = ilk_; gem = DSToken(gem_); dec = gem.decimals(); } function cage() external note auth { live = 0; } function join(address usr, uint wad) external note { require(live == 1, "GemJoin/not-live"); require(int(wad) >= 0, "GemJoin/overflow"); vat.slip(ilk, usr, int(wad)); require(gem.transferFrom(msg.sender, address(this), wad), "GemJoin/failed-transfer"); } function exit(address usr, uint wad) external note { require(wad <= 2 ** 255, "GemJoin/overflow"); vat.slip(ilk, msg.sender, -int(wad)); require(gem.transfer(usr, wad), "GemJoin/failed-transfer"); } } contract DaiJoin is DSNote { // --- Auth --- mapping (address => uint) public wards; function rely(address usr) external note auth { wards[usr] = 1; } function deny(address usr) external note auth { wards[usr] = 0; } modifier auth { require(wards[msg.sender] == 1, "DaiJoin/not-authorized"); _; } Vat public vat; // CDP Engine Dai public dai; // Stablecoin Token uint public live; // Active Flag constructor(address vat_, address dai_) public { wards[msg.sender] = 1; live = 1; vat = Vat(vat_); dai = Dai(dai_); } function cage() external note auth { live = 0; } uint constant ONE = 10 ** 27; function mul(uint x, uint y) internal pure returns (uint z) { require(y == 0 || (z = x * y) / y == x); } function join(address usr, uint wad) external note { vat.move(address(this), usr, mul(ONE, wad)); dai.burn(msg.sender, wad); } function exit(address usr, uint wad) external note { require(live == 1, "DaiJoin/not-live"); vat.move(msg.sender, address(this), mul(ONE, wad)); dai.mint(usr, wad); } } /* This thing lets you sell some dai in return for gems. - `lot` dai in return for bid - `bid` gems paid - `ttl` single bid lifetime - `beg` minimum bid increase - `end` max auction duration */ contract Flapper is DSNote { // --- Auth --- mapping (address => uint) public wards; function rely(address usr) external note auth { wards[usr] = 1; } function deny(address usr) external note auth { wards[usr] = 0; } modifier auth { require(wards[msg.sender] == 1, "Flapper/not-authorized"); _; } // --- Data --- struct Bid { uint256 bid; // gems paid [wad] uint256 lot; // dai in return for bid [rad] address guy; // high bidder uint48 tic; // bid expiry time [unix epoch time] uint48 end; // auction expiry time [unix epoch time] } mapping (uint => Bid) public bids; Vat public vat; // CDP Engine DSToken public gem; uint256 constant ONE = 1.00E18; uint256 public beg = 1.05E18; // 5% minimum bid increase uint48 public ttl = 3 hours; // 3 hours bid duration [seconds] uint48 public tau = 2 days; // 2 days total auction length [seconds] uint256 public kicks = 0; uint256 public live; // Active Flag // --- Events --- event Kick( uint256 id, uint256 lot, uint256 bid ); // --- Init --- constructor(address vat_, address gem_) public { wards[msg.sender] = 1; vat = Vat(vat_); gem = DSToken(gem_); live = 1; } // --- Math --- function add(uint48 x, uint48 y) internal pure returns (uint48 z) { require((z = x + y) >= x); } function mul(uint x, uint y) internal pure returns (uint z) { require(y == 0 || (z = x * y) / y == x); } // --- Admin --- function file(bytes32 what, uint data) external note auth { if (what == "beg") beg = data; else if (what == "ttl") ttl = uint48(data); else if (what == "tau") tau = uint48(data); else revert("Flapper/file-unrecognized-param"); } // --- Auction --- function kick(uint lot, uint bid) external auth returns (uint id) { require(live == 1, "Flapper/not-live"); require(kicks < uint(-1), "Flapper/overflow"); id = ++kicks; bids[id].bid = bid; bids[id].lot = lot; bids[id].guy = msg.sender; // configurable?? bids[id].end = add(uint48(now), tau); vat.move(msg.sender, address(this), lot); emit Kick(id, lot, bid); } function tick(uint id) external note { require(bids[id].end < now, "Flapper/not-finished"); require(bids[id].tic == 0, "Flapper/bid-already-placed"); bids[id].end = add(uint48(now), tau); } function tend(uint id, uint lot, uint bid) external note { require(live == 1, "Flapper/not-live"); require(bids[id].guy != address(0), "Flapper/guy-not-set"); require(bids[id].tic > now || bids[id].tic == 0, "Flapper/already-finished-tic"); require(bids[id].end > now, "Flapper/already-finished-end"); require(lot == bids[id].lot, "Flapper/lot-not-matching"); require(bid > bids[id].bid, "Flapper/bid-not-higher"); require(mul(bid, ONE) >= mul(beg, bids[id].bid), "Flapper/insufficient-increase"); if (msg.sender != bids[id].guy) { gem.transferFrom(msg.sender, bids[id].guy, bids[id].bid); bids[id].guy = msg.sender; } gem.transferFrom(msg.sender, address(this), bid - bids[id].bid); bids[id].bid = bid; bids[id].tic = add(uint48(now), ttl); } function deal(uint id) external note { require(live == 1, "Flapper/not-live"); require(bids[id].tic != 0 && (bids[id].tic < now || bids[id].end < now), "Flapper/not-finished"); vat.move(address(this), bids[id].guy, bids[id].lot); uint256 bid = bids[id].bid; try gem.burn(bid) {} catch { gem.transfer(address(0xdead), bid); } delete bids[id]; } function cage(uint rad) external note auth { live = 0; vat.move(address(this), msg.sender, rad); } function yank(uint id) external note { require(live == 0, "Flapper/still-live"); require(bids[id].guy != address(0), "Flapper/guy-not-set"); gem.transferFrom(address(this), bids[id].guy, bids[id].bid); delete bids[id]; } } /* This thing creates gems on demand in return for dai. - `lot` gems in return for bid - `bid` dai paid - `gal` receives dai income - `ttl` single bid lifetime - `beg` minimum bid increase - `end` max auction duration */ contract Flopper is DSNote { // --- Auth --- mapping (address => uint) public wards; function rely(address usr) external note auth { wards[usr] = 1; } function deny(address usr) external note auth { wards[usr] = 0; } modifier auth { require(wards[msg.sender] == 1, "Flopper/not-authorized"); _; } // --- Data --- struct Bid { uint256 bid; // dai paid [rad] uint256 lot; // gems in return for bid [wad] address guy; // high bidder uint48 tic; // bid expiry time [unix epoch time] uint48 end; // auction expiry time [unix epoch time] } mapping (uint => Bid) public bids; Vat public vat; // CDP Engine DSToken public gem; uint256 constant ONE = 1.00E18; uint256 public beg = 1.05E18; // 5% minimum bid increase uint256 public pad = 1.50E18; // 50% lot increase for tick uint48 public ttl = 3 hours; // 3 hours bid lifetime [seconds] uint48 public tau = 2 days; // 2 days total auction length [seconds] uint256 public kicks = 0; uint256 public live; // Active Flag address public vow; // not used until shutdown // --- Events --- event Kick( uint256 id, uint256 lot, uint256 bid, address indexed gal ); // --- Init --- constructor(address vat_, address gem_) public { wards[msg.sender] = 1; vat = Vat(vat_); gem = DSToken(gem_); live = 1; } // --- Math --- function add(uint48 x, uint48 y) internal pure returns (uint48 z) { require((z = x + y) >= x); } function mul(uint x, uint y) internal pure returns (uint z) { require(y == 0 || (z = x * y) / y == x); } function min(uint x, uint y) internal pure returns (uint z) { if (x > y) { z = y; } else { z = x; } } // --- Admin --- function file(bytes32 what, uint data) external note auth { if (what == "beg") beg = data; else if (what == "pad") pad = data; else if (what == "ttl") ttl = uint48(data); else if (what == "tau") tau = uint48(data); else revert("Flopper/file-unrecognized-param"); } // --- Auction --- function kick(address gal, uint lot, uint bid) external auth returns (uint id) { require(live == 1, "Flopper/not-live"); require(kicks < uint(-1), "Flopper/overflow"); id = ++kicks; bids[id].bid = bid; bids[id].lot = lot; bids[id].guy = gal; bids[id].end = add(uint48(now), tau); emit Kick(id, lot, bid, gal); } function tick(uint id) external note { require(bids[id].end < now, "Flopper/not-finished"); require(bids[id].tic == 0, "Flopper/bid-already-placed"); bids[id].lot = mul(pad, bids[id].lot) / ONE; bids[id].end = add(uint48(now), tau); } function dent(uint id, uint lot, uint bid) external note { require(live == 1, "Flopper/not-live"); require(bids[id].guy != address(0), "Flopper/guy-not-set"); require(bids[id].tic > now || bids[id].tic == 0, "Flopper/already-finished-tic"); require(bids[id].end > now, "Flopper/already-finished-end"); require(bid == bids[id].bid, "Flopper/not-matching-bid"); require(lot < bids[id].lot, "Flopper/lot-not-lower"); require(mul(beg, lot) <= mul(bids[id].lot, ONE), "Flopper/insufficient-decrease"); if (msg.sender != bids[id].guy) { vat.move(msg.sender, bids[id].guy, bid); // on first dent, clear as much Ash as possible if (bids[id].tic == 0) { uint Ash = Vow(bids[id].guy).Ash(); Vow(bids[id].guy).kiss(min(bid, Ash)); } bids[id].guy = msg.sender; } bids[id].lot = lot; bids[id].tic = add(uint48(now), ttl); } function deal(uint id) external note { require(live == 1, "Flopper/not-live"); require(bids[id].tic != 0 && (bids[id].tic < now || bids[id].end < now), "Flopper/not-finished"); gem.mint(bids[id].guy, bids[id].lot); // will fail if mint is unavailable delete bids[id]; } // --- Shutdown --- function cage() external note auth { live = 0; vow = msg.sender; } function yank(uint id) external note { require(live == 0, "Flopper/still-live"); require(bids[id].guy != address(0), "Flopper/guy-not-set"); vat.suck(vow, bids[id].guy, bids[id].bid); delete bids[id]; } } contract Vow is DSNote { // --- Auth --- mapping (address => uint) public wards; function rely(address usr) external note auth { require(live == 1, "Vow/not-live"); wards[usr] = 1; } function deny(address usr) external note auth { wards[usr] = 0; } modifier auth { require(wards[msg.sender] == 1, "Vow/not-authorized"); _; } // --- Data --- Vat public vat; // CDP Engine Flapper public flapper; // Surplus Auction House Flopper public flopper; // Debt Auction House mapping (uint256 => uint256) public sin; // debt queue uint256 public Sin; // Queued debt [rad] uint256 public Ash; // On-auction debt [rad] uint256 public wait; // Flop delay [seconds] uint256 public dump; // Flop initial lot size [wad] uint256 public sump; // Flop fixed bid size [rad] uint256 public bump; // Flap fixed lot size [rad] uint256 public hump; // Surplus buffer [rad] uint256 public live; // Active Flag // --- Init --- constructor(address vat_, address flapper_, address flopper_) public { wards[msg.sender] = 1; vat = Vat(vat_); flapper = Flapper(flapper_); flopper = Flopper(flopper_); vat.hope(flapper_); live = 1; } // --- Math --- function add(uint x, uint y) internal pure returns (uint z) { require((z = x + y) >= x); } function sub(uint x, uint y) internal pure returns (uint z) { require((z = x - y) <= x); } function min(uint x, uint y) internal pure returns (uint z) { return x <= y ? x : y; } // --- Administration --- function file(bytes32 what, uint data) external note auth { if (what == "wait") wait = data; else if (what == "bump") bump = data; else if (what == "sump") sump = data; else if (what == "dump") dump = data; else if (what == "hump") hump = data; else revert("Vow/file-unrecognized-param"); } function file(bytes32 what, address data) external note auth { if (what == "flapper") { vat.nope(address(flapper)); flapper = Flapper(data); vat.hope(data); } else if (what == "flopper") flopper = Flopper(data); else revert("Vow/file-unrecognized-param"); } // Push to debt-queue function fess(uint tab) external note auth { sin[now] = add(sin[now], tab); Sin = add(Sin, tab); } // Pop from debt-queue function flog(uint era) external note { require(add(era, wait) <= now, "Vow/wait-not-finished"); Sin = sub(Sin, sin[era]); sin[era] = 0; } // Debt settlement function heal(uint rad) external note { require(rad <= vat.dai(address(this)), "Vow/insufficient-surplus"); require(rad <= sub(sub(vat.sin(address(this)), Sin), Ash), "Vow/insufficient-debt"); vat.heal(rad); } function kiss(uint rad) external note { require(rad <= Ash, "Vow/not-enough-ash"); require(rad <= vat.dai(address(this)), "Vow/insufficient-surplus"); Ash = sub(Ash, rad); vat.heal(rad); } // Debt auction function flop() external note returns (uint id) { require(sump <= sub(sub(vat.sin(address(this)), Sin), Ash), "Vow/insufficient-debt"); require(vat.dai(address(this)) == 0, "Vow/surplus-not-zero"); Ash = add(Ash, sump); id = flopper.kick(address(this), dump, sump); } // Surplus auction function flap() external note returns (uint id) { require(vat.dai(address(this)) >= add(add(vat.sin(address(this)), bump), hump), "Vow/insufficient-surplus"); require(sub(sub(vat.sin(address(this)), Sin), Ash) == 0, "Vow/debt-not-zero"); id = flapper.kick(bump, 0); } function cage() external note auth { require(live == 1, "Vow/not-live"); live = 0; Sin = 0; Ash = 0; flapper.cage(vat.dai(address(flapper))); flopper.cage(); vat.heal(min(vat.dai(address(this)), vat.sin(address(this)))); } } interface Kicker { function kick(address urn, address gal, uint256 tab, uint256 lot, uint256 bid) external returns (uint256); } contract Cat is DSNote { // --- Auth --- mapping (address => uint256) public wards; function rely(address usr) external note auth { wards[usr] = 1; } function deny(address usr) external note auth { wards[usr] = 0; } modifier auth { require(wards[msg.sender] == 1, "Cat/not-authorized"); _; } // --- Data --- struct Ilk { address flip; // Liquidator uint256 chop; // Liquidation Penalty [wad] uint256 dunk; // Liquidation Quantity [rad] } mapping (bytes32 => Ilk) public ilks; uint256 public live; // Active Flag Vat public vat; // CDP Engine Vow public vow; // Debt Engine uint256 public box; // Max Dai out for liquidation [rad] uint256 public litter; // Balance of Dai out for liquidation [rad] // --- Events --- event Bite( bytes32 indexed ilk, address indexed urn, uint256 ink, uint256 art, uint256 tab, address flip, uint256 id ); // --- Init --- constructor(address vat_) public { wards[msg.sender] = 1; vat = Vat(vat_); live = 1; } // --- Math --- uint256 constant WAD = 10 ** 18; function min(uint256 x, uint256 y) internal pure returns (uint256 z) { if (x > y) { z = y; } else { z = x; } } function add(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x + y) >= x); } function sub(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x - y) <= x); } function mul(uint256 x, uint256 y) internal pure returns (uint256 z) { require(y == 0 || (z = x * y) / y == x); } // --- Administration --- function file(bytes32 what, address data) external note auth { if (what == "vow") vow = Vow(data); else revert("Cat/file-unrecognized-param"); } function file(bytes32 what, uint256 data) external note auth { if (what == "box") box = data; else revert("Cat/file-unrecognized-param"); } function file(bytes32 ilk, bytes32 what, uint256 data) external note auth { if (what == "chop") ilks[ilk].chop = data; else if (what == "dunk") ilks[ilk].dunk = data; else revert("Cat/file-unrecognized-param"); } function file(bytes32 ilk, bytes32 what, address flip) external note auth { if (what == "flip") { vat.nope(ilks[ilk].flip); ilks[ilk].flip = flip; vat.hope(flip); } else revert("Cat/file-unrecognized-param"); } // --- CDP Liquidation --- function bite(bytes32 ilk, address urn) external returns (uint256 id) { (,uint256 rate,uint256 spot,,uint256 dust) = vat.ilks(ilk); (uint256 ink, uint256 art) = vat.urns(ilk, urn); require(live == 1, "Cat/not-live"); require(spot > 0 && mul(ink, spot) < mul(art, rate), "Cat/not-unsafe"); Ilk memory milk = ilks[ilk]; uint256 dart; { uint256 room = sub(box, litter); // test whether the remaining space in the litterbox is dusty require(litter < box && room >= dust, "Cat/liquidation-limit-hit"); dart = min(art, mul(min(milk.dunk, room), WAD) / rate / milk.chop); } uint256 dink = min(ink, mul(ink, dart) / art); require(dart > 0 && dink > 0 , "Cat/null-auction"); require(dart <= 2**255 && dink <= 2**255, "Cat/overflow" ); // This may leave the CDP in a dusty state vat.grab( ilk, urn, address(this), address(vow), -int256(dink), -int256(dart) ); vow.fess(mul(dart, rate)); { // Avoid stack too deep // This calcuation will overflow if dart*rate exceeds ~10^14, // i.e. the maximum dunk is roughly 100 trillion DAI. uint256 tab = mul(mul(dart, rate), milk.chop) / WAD; litter = add(litter, tab); id = Kicker(milk.flip).kick({ urn: urn, gal: address(vow), tab: tab, lot: dink, bid: 0 }); } emit Bite(ilk, urn, dink, dart, mul(dart, rate), milk.flip, id); } function claw(uint256 rad) external note auth { litter = sub(litter, rad); } function cage() external note auth { live = 0; } } // FIXME: This contract was altered compared to the production version. // It doesn't use LibNote anymore. // New deployments of this contract will need to include custom events (TO DO). /* This thing lets you flip some gems for a given amount of dai. Once the given amount of dai is raised, gems are forgone instead. - `lot` gems in return for bid - `tab` total dai wanted - `bid` dai paid - `gal` receives dai income - `usr` receives gem forgone - `ttl` single bid lifetime - `beg` minimum bid increase - `end` max auction duration */ contract Flipper { // --- Auth --- mapping (address => uint256) public wards; function rely(address usr) external auth { wards[usr] = 1; } function deny(address usr) external auth { wards[usr] = 0; } modifier auth { require(wards[msg.sender] == 1, "Flipper/not-authorized"); _; } // --- Data --- struct Bid { uint256 bid; // dai paid [rad] uint256 lot; // gems in return for bid [wad] address guy; // high bidder uint48 tic; // bid expiry time [unix epoch time] uint48 end; // auction expiry time [unix epoch time] address usr; address gal; uint256 tab; // total dai wanted [rad] } mapping (uint256 => Bid) public bids; Vat public vat; // CDP Engine bytes32 public ilk; // collateral type uint256 constant ONE = 1.00E18; uint256 public beg = 1.05E18; // 5% minimum bid increase uint48 public ttl = 3 hours; // 3 hours bid duration [seconds] uint48 public tau = 2 days; // 2 days total auction length [seconds] uint256 public kicks = 0; Cat public cat; // cat liquidation module // --- Events --- event Kick( uint256 id, uint256 lot, uint256 bid, uint256 tab, address indexed usr, address indexed gal ); // --- Init --- constructor(address vat_, address cat_, bytes32 ilk_) public { vat = Vat(vat_); cat = Cat(cat_); ilk = ilk_; wards[msg.sender] = 1; } // --- Math --- function add(uint48 x, uint48 y) internal pure returns (uint48 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); } // --- Admin --- function file(bytes32 what, uint256 data) external auth { if (what == "beg") beg = data; else if (what == "ttl") ttl = uint48(data); else if (what == "tau") tau = uint48(data); else revert("Flipper/file-unrecognized-param"); } function file(bytes32 what, address data) external auth { if (what == "cat") cat = Cat(data); else revert("Flipper/file-unrecognized-param"); } // --- Auction --- function kick(address usr, address gal, uint256 tab, uint256 lot, uint256 bid) public auth returns (uint256 id) { require(kicks < uint256(-1), "Flipper/overflow"); id = ++kicks; bids[id].bid = bid; bids[id].lot = lot; bids[id].guy = msg.sender; // configurable?? bids[id].end = add(uint48(now), tau); bids[id].usr = usr; bids[id].gal = gal; bids[id].tab = tab; vat.flux(ilk, msg.sender, address(this), lot); emit Kick(id, lot, bid, tab, usr, gal); } function tick(uint256 id) external { require(bids[id].end < now, "Flipper/not-finished"); require(bids[id].tic == 0, "Flipper/bid-already-placed"); bids[id].end = add(uint48(now), tau); } function tend(uint256 id, uint256 lot, uint256 bid) external { require(bids[id].guy != address(0), "Flipper/guy-not-set"); require(bids[id].tic > now || bids[id].tic == 0, "Flipper/already-finished-tic"); require(bids[id].end > now, "Flipper/already-finished-end"); require(lot == bids[id].lot, "Flipper/lot-not-matching"); require(bid <= bids[id].tab, "Flipper/higher-than-tab"); require(bid > bids[id].bid, "Flipper/bid-not-higher"); require(mul(bid, ONE) >= mul(beg, bids[id].bid) || bid == bids[id].tab, "Flipper/insufficient-increase"); if (msg.sender != bids[id].guy) { vat.move(msg.sender, bids[id].guy, bids[id].bid); bids[id].guy = msg.sender; } vat.move(msg.sender, bids[id].gal, bid - bids[id].bid); bids[id].bid = bid; bids[id].tic = add(uint48(now), ttl); } function dent(uint256 id, uint256 lot, uint256 bid) external { require(bids[id].guy != address(0), "Flipper/guy-not-set"); require(bids[id].tic > now || bids[id].tic == 0, "Flipper/already-finished-tic"); require(bids[id].end > now, "Flipper/already-finished-end"); require(bid == bids[id].bid, "Flipper/not-matching-bid"); require(bid == bids[id].tab, "Flipper/tend-not-finished"); require(lot < bids[id].lot, "Flipper/lot-not-lower"); require(mul(beg, lot) <= mul(bids[id].lot, ONE), "Flipper/insufficient-decrease"); if (msg.sender != bids[id].guy) { vat.move(msg.sender, bids[id].guy, bid); bids[id].guy = msg.sender; } vat.flux(ilk, address(this), bids[id].usr, bids[id].lot - lot); bids[id].lot = lot; bids[id].tic = add(uint48(now), ttl); } function deal(uint256 id) external { require(bids[id].tic != 0 && (bids[id].tic < now || bids[id].end < now), "Flipper/not-finished"); cat.claw(bids[id].tab); vat.flux(ilk, address(this), bids[id].guy, bids[id].lot); delete bids[id]; } function yank(uint256 id) external auth { require(bids[id].guy != address(0), "Flipper/guy-not-set"); require(bids[id].bid < bids[id].tab, "Flipper/already-dent-phase"); cat.claw(bids[id].tab); vat.flux(ilk, address(this), msg.sender, bids[id].lot); vat.move(msg.sender, bids[id].guy, bids[id].bid); delete bids[id]; } } interface Abacus { // 1st arg: initial price [ray] // 2nd arg: seconds since auction start [seconds] // returns: current auction price [ray] function price(uint256, uint256) external view returns (uint256); } contract LinearDecrease is Abacus { // --- Auth --- mapping (address => uint256) public wards; function rely(address usr) external auth { wards[usr] = 1; emit Rely(usr); } function deny(address usr) external auth { wards[usr] = 0; emit Deny(usr); } modifier auth { require(wards[msg.sender] == 1, "LinearDecrease/not-authorized"); _; } // --- Data --- uint256 public tau; // Seconds after auction start when the price reaches zero [seconds] // --- Events --- event Rely(address indexed usr); event Deny(address indexed usr); event File(bytes32 indexed what, uint256 data); // --- Init --- constructor() public { wards[msg.sender] = 1; emit Rely(msg.sender); } // --- Administration --- function file(bytes32 what, uint256 data) external auth { if (what == "tau") tau = data; else revert("LinearDecrease/file-unrecognized-param"); emit File(what, data); } // --- Math --- uint256 constant RAY = 10 ** 27; function add(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x + y) >= x); } function mul(uint256 x, uint256 y) internal pure returns (uint256 z) { require(y == 0 || (z = x * y) / y == x); } function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) { z = x * y; require(y == 0 || z / y == x); z = z / RAY; } // Price calculation when price is decreased linearly in proportion to time: // tau: The number of seconds after the start of the auction where the price will hit 0 // top: Initial price // dur: current seconds since the start of the auction // // Returns y = top * ((tau - dur) / tau) // // Note the internal call to mul multiples by RAY, thereby ensuring that the rmul calculation // which utilizes top and tau (RAY values) is also a RAY value. function price(uint256 top, uint256 dur) override external view returns (uint256) { if (dur >= tau) return 0; return rmul(top, mul(tau - dur, RAY) / tau); } } contract StairstepExponentialDecrease is Abacus { // --- Auth --- mapping (address => uint256) public wards; function rely(address usr) external auth { wards[usr] = 1; emit Rely(usr); } function deny(address usr) external auth { wards[usr] = 0; emit Deny(usr); } modifier auth { require(wards[msg.sender] == 1, "StairstepExponentialDecrease/not-authorized"); _; } // --- Data --- uint256 public step; // Length of time between price drops [seconds] uint256 public cut; // Per-step multiplicative factor [ray] // --- Events --- event Rely(address indexed usr); event Deny(address indexed usr); event File(bytes32 indexed what, uint256 data); // --- Init --- // @notice: `cut` and `step` values must be correctly set for // this contract to return a valid price constructor() public { wards[msg.sender] = 1; emit Rely(msg.sender); } // --- Administration --- function file(bytes32 what, uint256 data) external auth { if (what == "cut") require((cut = data) <= RAY, "StairstepExponentialDecrease/cut-gt-RAY"); else if (what == "step") step = data; else revert("StairstepExponentialDecrease/file-unrecognized-param"); emit File(what, data); } // --- Math --- uint256 constant RAY = 10 ** 27; function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) { z = x * y; require(y == 0 || z / y == x); z = z / RAY; } // optimized version from dss PR #78 function rpow(uint256 x, uint256 n, uint256 b) internal pure returns (uint256 z) { assembly { switch n case 0 { z := b } default { switch x case 0 { z := 0 } default { switch mod(n, 2) case 0 { z := b } default { z := x } let half := div(b, 2) // for rounding. for { n := div(n, 2) } n { n := div(n,2) } { let xx := mul(x, x) if shr(128, x) { revert(0,0) } let xxRound := add(xx, half) if lt(xxRound, xx) { revert(0,0) } x := div(xxRound, b) if mod(n,2) { let zx := mul(z, x) if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0,0) } let zxRound := add(zx, half) if lt(zxRound, zx) { revert(0,0) } z := div(zxRound, b) } } } } } } // top: initial price // dur: seconds since the auction has started // step: seconds between a price drop // cut: cut encodes the percentage to decrease per step. // For efficiency, the values is set as (1 - (% value / 100)) * RAY // So, for a 1% decrease per step, cut would be (1 - 0.01) * RAY // // returns: top * (cut ^ dur) // // function price(uint256 top, uint256 dur) override external view returns (uint256) { return rmul(top, rpow(cut, dur / step, RAY)); } } // While an equivalent function can be obtained by setting step = 1 in StairstepExponentialDecrease, // this continous (i.e. per-second) exponential decrease has be implemented as it is more gas-efficient // than using the stairstep version with step = 1 (primarily due to 1 fewer SLOAD per price calculation). contract ExponentialDecrease is Abacus { // --- Auth --- mapping (address => uint256) public wards; function rely(address usr) external auth { wards[usr] = 1; emit Rely(usr); } function deny(address usr) external auth { wards[usr] = 0; emit Deny(usr); } modifier auth { require(wards[msg.sender] == 1, "ExponentialDecrease/not-authorized"); _; } // --- Data --- uint256 public cut; // Per-second multiplicative factor [ray] // --- Events --- event Rely(address indexed usr); event Deny(address indexed usr); event File(bytes32 indexed what, uint256 data); // --- Init --- // @notice: `cut` value must be correctly set for // this contract to return a valid price constructor() public { wards[msg.sender] = 1; emit Rely(msg.sender); } // --- Administration --- function file(bytes32 what, uint256 data) external auth { if (what == "cut") require((cut = data) <= RAY, "ExponentialDecrease/cut-gt-RAY"); else revert("ExponentialDecrease/file-unrecognized-param"); emit File(what, data); } // --- Math --- uint256 constant RAY = 10 ** 27; function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) { z = x * y; require(y == 0 || z / y == x); z = z / RAY; } // optimized version from dss PR #78 function rpow(uint256 x, uint256 n, uint256 b) internal pure returns (uint256 z) { assembly { switch n case 0 { z := b } default { switch x case 0 { z := 0 } default { switch mod(n, 2) case 0 { z := b } default { z := x } let half := div(b, 2) // for rounding. for { n := div(n, 2) } n { n := div(n,2) } { let xx := mul(x, x) if shr(128, x) { revert(0,0) } let xxRound := add(xx, half) if lt(xxRound, xx) { revert(0,0) } x := div(xxRound, b) if mod(n,2) { let zx := mul(z, x) if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0,0) } let zxRound := add(zx, half) if lt(zxRound, zx) { revert(0,0) } z := div(zxRound, b) } } } } } } // top: initial price // dur: seconds since the auction has started // cut: cut encodes the percentage to decrease per second. // For efficiency, the values is set as (1 - (% value / 100)) * RAY // So, for a 1% decrease per second, cut would be (1 - 0.01) * RAY // // returns: top * (cut ^ dur) // function price(uint256 top, uint256 dur) override external view returns (uint256) { return rmul(top, rpow(cut, dur, RAY)); } } interface ClipperCallee { function clipperCall(address, uint256, uint256, bytes calldata) external; } contract Clipper { // --- Auth --- mapping (address => uint256) public wards; function rely(address usr) external auth { wards[usr] = 1; emit Rely(usr); } function deny(address usr) external auth { wards[usr] = 0; emit Deny(usr); } modifier auth { require(wards[msg.sender] == 1, "Clipper/not-authorized"); _; } // --- Data --- bytes32 immutable public ilk; // Collateral type of this Clipper Vat immutable public vat; // Core CDP Engine Dog public dog; // Liquidation module address public vow; // Recipient of dai raised in auctions Spotter public spotter; // Collateral price module Abacus public calc; // Current price calculator uint256 public buf; // Multiplicative factor to increase starting price [ray] uint256 public tail; // Time elapsed before auction reset [seconds] uint256 public cusp; // Percentage drop before auction reset [ray] uint64 public chip; // Percentage of tab to suck from vow to incentivize keepers [wad] uint192 public tip; // Flat fee to suck from vow to incentivize keepers [rad] uint256 public chost; // Cache the ilk dust times the ilk chop to prevent excessive SLOADs [rad] uint256 public kicks; // Total auctions uint256[] public active; // Array of active auction ids struct Sale { uint256 pos; // Index in active array uint256 tab; // Dai to raise [rad] uint256 lot; // collateral to sell [wad] address usr; // Liquidated CDP uint96 tic; // Auction start time uint256 top; // Starting price [ray] } mapping(uint256 => Sale) public sales; uint256 internal locked; // Levels for circuit breaker // 0: no breaker // 1: no new kick() // 2: no new kick() or redo() // 3: no new kick(), redo(), or take() uint256 public stopped = 0; // --- Events --- event Rely(address indexed usr); event Deny(address indexed usr); event File(bytes32 indexed what, uint256 data); event File(bytes32 indexed what, address data); event Kick( uint256 indexed id, uint256 top, uint256 tab, uint256 lot, address indexed usr, address indexed kpr, uint256 coin ); event Take( uint256 indexed id, uint256 max, uint256 price, uint256 owe, uint256 tab, uint256 lot, address indexed usr ); event Redo( uint256 indexed id, uint256 top, uint256 tab, uint256 lot, address indexed usr, address indexed kpr, uint256 coin ); event Yank(uint256 id); // --- Init --- constructor(address vat_, address spotter_, address dog_, bytes32 ilk_) public { vat = Vat(vat_); spotter = Spotter(spotter_); dog = Dog(dog_); ilk = ilk_; buf = RAY; wards[msg.sender] = 1; emit Rely(msg.sender); } // --- Synchronization --- modifier lock { require(locked == 0, "Clipper/system-locked"); locked = 1; _; locked = 0; } modifier isStopped(uint256 level) { require(stopped < level, "Clipper/stopped-incorrect"); _; } // --- Administration --- function file(bytes32 what, uint256 data) external auth lock { if (what == "buf") buf = data; else if (what == "tail") tail = data; // Time elapsed before auction reset else if (what == "cusp") cusp = data; // Percentage drop before auction reset else if (what == "chip") chip = uint64(data); // Percentage of tab to incentivize (max: 2^64 - 1 => 18.xxx WAD = 18xx%) else if (what == "tip") tip = uint192(data); // Flat fee to incentivize keepers (max: 2^192 - 1 => 6.277T RAD) else if (what == "stopped") stopped = data; // Set breaker (0, 1, 2, or 3) else revert("Clipper/file-unrecognized-param"); emit File(what, data); } function file(bytes32 what, address data) external auth lock { if (what == "spotter") spotter = Spotter(data); else if (what == "dog") dog = Dog(data); else if (what == "vow") vow = data; else if (what == "calc") calc = Abacus(data); else revert("Clipper/file-unrecognized-param"); emit File(what, data); } // --- Math --- uint256 constant BLN = 10 ** 9; uint256 constant WAD = 10 ** 18; uint256 constant RAY = 10 ** 27; function min(uint256 x, uint256 y) internal pure returns (uint256 z) { z = x <= y ? x : y; } function add(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x + y) >= x); } function sub(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x - y) <= x); } function mul(uint256 x, uint256 y) internal pure returns (uint256 z) { require(y == 0 || (z = x * y) / y == x); } function wmul(uint256 x, uint256 y) internal pure returns (uint256 z) { z = mul(x, y) / WAD; } function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) { z = mul(x, y) / RAY; } function rdiv(uint256 x, uint256 y) internal pure returns (uint256 z) { z = mul(x, RAY) / y; } // --- Auction --- // get the price directly from the OSM // Could get this from rmul(Vat.ilks(ilk).spot, Spotter.mat()) instead, but // if mat has changed since the last poke, the resulting value will be // incorrect. function getFeedPrice() internal view returns (uint256 feedPrice) { (PipLike pip, ) = spotter.ilks(ilk); (bytes32 val, bool has) = pip.peek(); require(has, "Clipper/invalid-price"); feedPrice = rdiv(mul(uint256(val), BLN), spotter.par()); } // start an auction // note: trusts the caller to transfer collateral to the contract // The starting price `top` is obtained as follows: // // top = val * buf / par // // Where `val` is the collateral's unitary value in USD, `buf` is a // multiplicative factor to increase the starting price, and `par` is a // reference per DAI. function kick( uint256 tab, // Debt [rad] uint256 lot, // Collateral [wad] address usr, // Address that will receive any leftover collateral address kpr // Address that will receive incentives ) external auth lock isStopped(1) returns (uint256 id) { // Input validation require(tab > 0, "Clipper/zero-tab"); require(lot > 0, "Clipper/zero-lot"); require(usr != address(0), "Clipper/zero-usr"); id = ++kicks; require(id > 0, "Clipper/overflow"); active.push(id); sales[id].pos = active.length - 1; sales[id].tab = tab; sales[id].lot = lot; sales[id].usr = usr; sales[id].tic = uint96(block.timestamp); uint256 top; top = rmul(getFeedPrice(), buf); require(top > 0, "Clipper/zero-top-price"); sales[id].top = top; // incentive to kick auction uint256 _tip = tip; uint256 _chip = chip; uint256 coin; if (_tip > 0 || _chip > 0) { coin = add(_tip, wmul(tab, _chip)); vat.suck(vow, kpr, coin); } emit Kick(id, top, tab, lot, usr, kpr, coin); } // Reset an auction // See `kick` above for an explanation of the computation of `top`. function redo( uint256 id, // id of the auction to reset address kpr // Address that will receive incentives ) external lock isStopped(2) { // Read auction data address usr = sales[id].usr; uint96 tic = sales[id].tic; uint256 top = sales[id].top; require(usr != address(0), "Clipper/not-running-auction"); // Check that auction needs reset // and compute current price [ray] (bool done,) = status(tic, top); require(done, "Clipper/cannot-reset"); uint256 tab = sales[id].tab; uint256 lot = sales[id].lot; sales[id].tic = uint96(block.timestamp); uint256 feedPrice = getFeedPrice(); top = rmul(feedPrice, buf); require(top > 0, "Clipper/zero-top-price"); sales[id].top = top; // incentive to redo auction uint256 _tip = tip; uint256 _chip = chip; uint256 coin; if (_tip > 0 || _chip > 0) { uint256 _chost = chost; if (tab >= _chost && mul(lot, feedPrice) >= _chost) { coin = add(_tip, wmul(tab, _chip)); vat.suck(vow, kpr, coin); } } emit Redo(id, top, tab, lot, usr, kpr, coin); } // Buy up to `amt` of collateral from the auction indexed by `id`. // // Auctions will not collect more DAI than their assigned DAI target,`tab`; // thus, if `amt` would cost more DAI than `tab` at the current price, the // amount of collateral purchased will instead be just enough to collect `tab` DAI. // // To avoid partial purchases resulting in very small leftover auctions that will // never be cleared, any partial purchase must leave at least `Clipper.chost` // remaining DAI target. `chost` is an asynchronously updated value equal to // (Vat.dust * Dog.chop(ilk) / WAD) where the values are understood to be determined // by whatever they were when Clipper.upchost() was last called. Purchase amounts // will be minimally decreased when necessary to respect this limit; i.e., if the // specified `amt` would leave `tab < chost` but `tab > 0`, the amount actually // purchased will be such that `tab == chost`. // // If `tab <= chost`, partial purchases are no longer possible; that is, the remaining // collateral can only be purchased entirely, or not at all. function take( uint256 id, // Auction id uint256 amt, // Upper limit on amount of collateral to buy [wad] uint256 max, // Maximum acceptable price (DAI / collateral) [ray] address who, // Receiver of collateral and external call address bytes calldata data // Data to pass in external call; if length 0, no call is done ) external lock isStopped(3) { address usr = sales[id].usr; uint96 tic = sales[id].tic; require(usr != address(0), "Clipper/not-running-auction"); uint256 price; { bool done; (done, price) = status(tic, sales[id].top); // Check that auction doesn't need reset require(!done, "Clipper/needs-reset"); } // Ensure price is acceptable to buyer require(max >= price, "Clipper/too-expensive"); uint256 lot = sales[id].lot; uint256 tab = sales[id].tab; uint256 owe; { // Purchase as much as possible, up to amt uint256 slice = min(lot, amt); // slice <= lot // DAI needed to buy a slice of this sale owe = mul(slice, price); // Don't collect more than tab of DAI if (owe > tab) { // Total debt will be paid owe = tab; // owe' <= owe // Adjust slice slice = owe / price; // slice' = owe' / price <= owe / price == slice <= lot } else if (owe < tab && slice < lot) { // If slice == lot => auction completed => dust doesn't matter uint256 _chost = chost; if (tab - owe < _chost) { // safe as owe < tab // If tab <= chost, buyers have to take the entire lot. require(tab > _chost, "Clipper/no-partial-purchase"); // Adjust amount to pay owe = tab - _chost; // owe' <= owe // Adjust slice slice = owe / price; // slice' = owe' / price < owe / price == slice < lot } } // Calculate remaining tab after operation tab = tab - owe; // safe since owe <= tab // Calculate remaining lot after operation lot = lot - slice; // Send collateral to who vat.flux(ilk, address(this), who, slice); // Do external call (if data is defined) but to be // extremely careful we don't allow to do it to the two // contracts which the Clipper needs to be authorized Dog dog_ = dog; if (data.length > 0 && who != address(vat) && who != address(dog_)) { ClipperCallee(who).clipperCall(msg.sender, owe, slice, data); } // Get DAI from caller vat.move(msg.sender, vow, owe); // Removes Dai out for liquidation from accumulator dog_.digs(ilk, lot == 0 ? tab + owe : owe); } if (lot == 0) { _remove(id); } else if (tab == 0) { vat.flux(ilk, address(this), usr, lot); _remove(id); } else { sales[id].tab = tab; sales[id].lot = lot; } emit Take(id, max, price, owe, tab, lot, usr); } function _remove(uint256 id) internal { uint256 _move = active[active.length - 1]; if (id != _move) { uint256 _index = sales[id].pos; active[_index] = _move; sales[_move].pos = _index; } active.pop(); delete sales[id]; } // The number of active auctions function count() external view returns (uint256) { return active.length; } // Return the entire array of active auctions function list() external view returns (uint256[] memory) { return active; } // Externally returns boolean for if an auction needs a redo and also the current price function getStatus(uint256 id) external view returns (bool needsRedo, uint256 price, uint256 lot, uint256 tab) { // Read auction data address usr = sales[id].usr; uint96 tic = sales[id].tic; bool done; (done, price) = status(tic, sales[id].top); needsRedo = usr != address(0) && done; lot = sales[id].lot; tab = sales[id].tab; } // Internally returns boolean for if an auction needs a redo function status(uint96 tic, uint256 top) internal view returns (bool done, uint256 price) { price = calc.price(top, sub(block.timestamp, tic)); done = (sub(block.timestamp, tic) > tail || rdiv(price, top) < cusp); } // Public function to update the cached dust*chop value. function upchost() external { (,,,, uint256 _dust) = Vat(vat).ilks(ilk); chost = wmul(_dust, dog.chop(ilk)); } // Cancel an auction during ES or via governance action. function yank(uint256 id) external auth lock { require(sales[id].usr != address(0), "Clipper/not-running-auction"); dog.digs(ilk, sales[id].tab); vat.flux(ilk, address(this), msg.sender, sales[id].lot); _remove(id); emit Yank(id); } } contract Dog { // --- Auth --- mapping (address => uint256) public wards; function rely(address usr) external auth { wards[usr] = 1; emit Rely(usr); } function deny(address usr) external auth { wards[usr] = 0; emit Deny(usr); } modifier auth { require(wards[msg.sender] == 1, "Dog/not-authorized"); _; } // --- Data --- struct Ilk { address clip; // Liquidator uint256 chop; // Liquidation Penalty [wad] uint256 hole; // Max DAI needed to cover debt+fees of active auctions per ilk [rad] uint256 dirt; // Amt DAI needed to cover debt+fees of active auctions per ilk [rad] } Vat immutable public vat; // CDP Engine mapping (bytes32 => Ilk) public ilks; Vow public vow; // Debt Engine uint256 public live; // Active Flag uint256 public Hole; // Max DAI needed to cover debt+fees of active auctions [rad] uint256 public Dirt; // Amt DAI needed to cover debt+fees of active auctions [rad] // --- Events --- event Rely(address indexed usr); event Deny(address indexed usr); event File(bytes32 indexed what, uint256 data); event File(bytes32 indexed what, address data); event File(bytes32 indexed ilk, bytes32 indexed what, uint256 data); event File(bytes32 indexed ilk, bytes32 indexed what, address clip); event Bark( bytes32 indexed ilk, address indexed urn, uint256 ink, uint256 art, uint256 due, address clip, uint256 indexed id ); event Digs(bytes32 indexed ilk, uint256 rad); event Cage(); // --- Init --- constructor(address vat_) public { vat = Vat(vat_); live = 1; wards[msg.sender] = 1; emit Rely(msg.sender); } // --- Math --- uint256 constant WAD = 10 ** 18; function min(uint256 x, uint256 y) internal pure returns (uint256 z) { z = x <= y ? x : y; } function add(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x + y) >= x); } function sub(uint256 x, uint256 y) internal pure returns (uint256 z) { require((z = x - y) <= x); } function mul(uint256 x, uint256 y) internal pure returns (uint256 z) { require(y == 0 || (z = x * y) / y == x); } // --- Administration --- function file(bytes32 what, address data) external auth { if (what == "vow") vow = Vow(data); else revert("Dog/file-unrecognized-param"); emit File(what, data); } function file(bytes32 what, uint256 data) external auth { if (what == "Hole") Hole = data; else revert("Dog/file-unrecognized-param"); emit File(what, data); } function file(bytes32 ilk, bytes32 what, uint256 data) external auth { if (what == "chop") { require(data >= WAD, "Dog/file-chop-lt-WAD"); ilks[ilk].chop = data; } else if (what == "hole") ilks[ilk].hole = data; else revert("Dog/file-unrecognized-param"); emit File(ilk, what, data); } function file(bytes32 ilk, bytes32 what, address clip) external auth { if (what == "clip") { require(ilk == Clipper(clip).ilk(), "Dog/file-ilk-neq-clip.ilk"); ilks[ilk].clip = clip; } else revert("Dog/file-unrecognized-param"); emit File(ilk, what, clip); } function chop(bytes32 ilk) external view returns (uint256) { return ilks[ilk].chop; } // --- CDP Liquidation: all bark and no bite --- // // Liquidate a Vault and start a Dutch auction to sell its collateral for DAI. // // The third argument is the address that will receive the liquidation reward, if any. // // The entire Vault will be liquidated except when the target amount of DAI to be raised in // the resulting auction (debt of Vault + liquidation penalty) causes either Dirt to exceed // Hole or ilk.dirt to exceed ilk.hole by an economically significant amount. In that // case, a partial liquidation is performed to respect the global and per-ilk limits on // outstanding DAI target. The one exception is if the resulting auction would likely // have too little collateral to be interesting to Keepers (debt taken from Vault < ilk.dust), // in which case the function reverts. Please refer to the code and comments within if // more detail is desired. function bark(bytes32 ilk, address urn, address kpr) external returns (uint256 id) { require(live == 1, "Dog/not-live"); (uint256 ink, uint256 art) = vat.urns(ilk, urn); Ilk memory milk = ilks[ilk]; uint256 dart; uint256 rate; uint256 dust; { uint256 spot; (,rate, spot,, dust) = vat.ilks(ilk); require(spot > 0 && mul(ink, spot) < mul(art, rate), "Dog/not-unsafe"); // Get the minimum value between: // 1) Remaining space in the general Hole // 2) Remaining space in the collateral hole require(Hole > Dirt && milk.hole > milk.dirt, "Dog/liquidation-limit-hit"); uint256 room = min(Hole - Dirt, milk.hole - milk.dirt); // uint256.max()/(RAD*WAD) = 115,792,089,237,316 dart = min(art, mul(room, WAD) / rate / milk.chop); // Partial liquidation edge case logic if (art > dart) { if (mul(art - dart, rate) < dust) { // If the leftover Vault would be dusty, just liquidate it entirely. // This will result in at least one of dirt_i > hole_i or Dirt > Hole becoming true. // The amount of excess will be bounded above by ceiling(dust_i * chop_i / WAD). // This deviation is assumed to be small compared to both hole_i and Hole, so that // the extra amount of target DAI over the limits intended is not of economic concern. dart = art; } else { // In a partial liquidation, the resulting auction should also be non-dusty. require(mul(dart, rate) >= dust, "Dog/dusty-auction-from-partial-liquidation"); } } } uint256 dink = mul(ink, dart) / art; require(dink > 0, "Dog/null-auction"); require(dart <= 2**255 && dink <= 2**255, "Dog/overflow"); vat.grab( ilk, urn, milk.clip, address(vow), -int256(dink), -int256(dart) ); uint256 due = mul(dart, rate); vow.fess(due); { // Avoid stack too deep // This calcuation will overflow if dart*rate exceeds ~10^14 uint256 tab = mul(due, milk.chop) / WAD; Dirt = add(Dirt, tab); ilks[ilk].dirt = add(milk.dirt, tab); id = Clipper(milk.clip).kick({ tab: tab, lot: dink, usr: urn, kpr: kpr }); } emit Bark(ilk, urn, dink, dart, due, milk.clip, id); } function digs(bytes32 ilk, uint256 rad) external auth { Dirt = sub(Dirt, rad); ilks[ilk].dirt = sub(ilks[ilk].dirt, rad); emit Digs(ilk, rad); } function cage() external auth { live = 0; emit Cage(); } } /* This is the `End` and it coordinates Global Settlement. This is an involved, stateful process that takes place over nine steps. First we freeze the system and lock the prices for each ilk. 1. `cage()`: - freezes user entrypoints - cancels flop/flap auctions - starts cooldown period - stops pot drips 2. `cage(ilk)`: - set the cage price for each `ilk`, reading off the price feed We must process some system state before it is possible to calculate the final dai / collateral price. In particular, we need to determine a. `gap`, the collateral shortfall per collateral type by considering under-collateralised CDPs. b. `debt`, the outstanding dai supply after including system surplus / deficit We determine (a) by processing all under-collateralised CDPs with `skim`: 3. `skim(ilk, urn)`: - cancels CDP debt - any excess collateral remains - backing collateral taken We determine (b) by processing ongoing dai generating processes, i.e. auctions. We need to ensure that auctions will not generate any further dai income. In the two-way auction model (Flipper) this occurs when all auctions are in the reverse (`dent`) phase. There are two ways of ensuring this: 4a. i) `wait`: set the cooldown period to be at least as long as the longest auction duration, which needs to be determined by the cage administrator. This takes a fairly predictable time to occur but with altered auction dynamics due to the now varying price of dai. ii) `skip`: cancel all ongoing auctions and seize the collateral. This allows for faster processing at the expense of more processing calls. This option allows dai holders to retrieve their collateral faster. `skip(ilk, id)`: - cancel individual flip auctions in the `tend` (forward) phase - retrieves collateral and debt (including penalty) to owner's CDP - returns dai to last bidder - `dent` (reverse) phase auctions can continue normally Option (i), `wait`, is sufficient (if all auctions were bidded at least once) for processing the system settlement but option (ii), `skip`, will speed it up. Both options are available in this implementation, with `skip` being enabled on a per-auction basis. In the case of the Dutch Auctions model (Clipper) they keep recovering debt during the whole lifetime and there isn't a max duration time guaranteed for the auction to end. So the way to ensure the protocol will not receive extra dai income is: 4b. i) `snip`: cancel all ongoing auctions and seize the collateral. `snip(ilk, id)`: - cancel individual running clip auctions - retrieves remaining collateral and debt (including penalty) to owner's CDP When a CDP has been processed and has no debt remaining, the remaining collateral can be removed. 5. `free(ilk)`: - remove collateral from the caller's CDP - owner can call as needed After the processing period has elapsed, we enable calculation of the final price for each collateral type. 6. `thaw()`: - only callable after processing time period elapsed - assumption that all under-collateralised CDPs are processed - fixes the total outstanding supply of dai - may also require extra CDP processing to cover vow surplus 7. `flow(ilk)`: - calculate the `fix`, the cash price for a given ilk - adjusts the `fix` in the case of deficit / surplus At this point we have computed the final price for each collateral type and dai holders can now turn their dai into collateral. Each unit dai can claim a fixed basket of collateral. Dai holders must first `pack` some dai into a `bag`. Once packed, dai cannot be unpacked and is not transferrable. More dai can be added to a bag later. 8. `pack(wad)`: - put some dai into a bag in preparation for `cash` Finally, collateral can be obtained with `cash`. The bigger the bag, the more collateral can be released. 9. `cash(ilk, wad)`: - exchange some dai from your bag for gems from a specific ilk - the number of gems is limited by how big your bag is */ contract End { // --- Auth --- mapping (address => uint256) public wards; function rely(address usr) external auth { wards[usr] = 1; emit Rely(usr); } function deny(address usr) external auth { wards[usr] = 0; emit Deny(usr); } modifier auth { require(wards[msg.sender] == 1, "End/not-authorized"); _; } // --- Data --- Vat public vat; // CDP Engine Cat public cat; Dog public dog; Vow public vow; // Debt Engine Pot public pot; Spotter public spot; uint256 public live; // Active Flag uint256 public when; // Time of cage [unix epoch time] uint256 public wait; // Processing Cooldown Length [seconds] uint256 public debt; // Total outstanding dai following processing [rad] mapping (bytes32 => uint256) public tag; // Cage price [ray] mapping (bytes32 => uint256) public gap; // Collateral shortfall [wad] mapping (bytes32 => uint256) public Art; // Total debt per ilk [wad] mapping (bytes32 => uint256) public fix; // Final cash price [ray] mapping (address => uint256) public bag; // [wad] mapping (bytes32 => mapping (address => uint256)) public out; // [wad] // --- Events --- event Rely(address indexed usr); event Deny(address indexed usr); event File(bytes32 indexed what, uint256 data); event File(bytes32 indexed what, address data); event Cage(); event Cage(bytes32 indexed ilk); event Snip(bytes32 indexed ilk, uint256 indexed id, address indexed usr, uint256 tab, uint256 lot, uint256 art); event Skip(bytes32 indexed ilk, uint256 indexed id, address indexed usr, uint256 tab, uint256 lot, uint256 art); event Skim(bytes32 indexed ilk, address indexed urn, uint256 wad, uint256 art); event Free(bytes32 indexed ilk, address indexed usr, uint256 ink); event Thaw(); event Flow(bytes32 indexed ilk); event Pack(address indexed usr, uint256 wad); event Cash(bytes32 indexed ilk, address indexed usr, uint256 wad); // --- Init --- constructor() public { wards[msg.sender] = 1; live = 1; emit Rely(msg.sender); } // --- Math --- uint256 constant WAD = 10 ** 18; uint256 constant RAY = 10 ** 27; function add(uint256 x, uint256 y) internal pure returns (uint256 z) { z = x + y; require(z >= 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 min(uint256 x, uint256 y) internal pure returns (uint256 z) { return x <= y ? x : y; } function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) { z = mul(x, y) / RAY; } function wdiv(uint256 x, uint256 y) internal pure returns (uint256 z) { z = mul(x, WAD) / y; } // --- Administration --- function file(bytes32 what, address data) external auth { require(live == 1, "End/not-live"); if (what == "vat") vat = Vat(data); else if (what == "cat") cat = Cat(data); else if (what == "dog") dog = Dog(data); else if (what == "vow") vow = Vow(data); else if (what == "pot") pot = Pot(data); else if (what == "spot") spot = Spotter(data); else revert("End/file-unrecognized-param"); emit File(what, data); } function file(bytes32 what, uint256 data) external auth { require(live == 1, "End/not-live"); if (what == "wait") wait = data; else revert("End/file-unrecognized-param"); emit File(what, data); } // --- Settlement --- function cage() external auth { require(live == 1, "End/not-live"); live = 0; when = block.timestamp; vat.cage(); cat.cage(); dog.cage(); vow.cage(); spot.cage(); pot.cage(); emit Cage(); } function cage(bytes32 ilk) external { require(live == 0, "End/still-live"); require(tag[ilk] == 0, "End/tag-ilk-already-defined"); (Art[ilk],,,,) = vat.ilks(ilk); (PipLike pip,) = spot.ilks(ilk); // par is a ray, pip returns a wad tag[ilk] = wdiv(spot.par(), uint256(pip.read())); emit Cage(ilk); } function snip(bytes32 ilk, uint256 id) external { require(tag[ilk] != 0, "End/tag-ilk-not-defined"); (address _clip,,,) = dog.ilks(ilk); Clipper clip = Clipper(_clip); (, uint256 rate,,,) = vat.ilks(ilk); (, uint256 tab, uint256 lot, address usr,,) = clip.sales(id); vat.suck(address(vow), address(vow), tab); clip.yank(id); uint256 art = tab / rate; Art[ilk] = add(Art[ilk], art); require(int256(lot) >= 0 && int256(art) >= 0, "End/overflow"); vat.grab(ilk, usr, address(this), address(vow), int256(lot), int256(art)); emit Snip(ilk, id, usr, tab, lot, art); } function skip(bytes32 ilk, uint256 id) external { require(tag[ilk] != 0, "End/tag-ilk-not-defined"); (address _flip,,) = cat.ilks(ilk); Flipper flip = Flipper(_flip); (, uint256 rate,,,) = vat.ilks(ilk); (uint256 bid, uint256 lot,,,, address usr,, uint256 tab) = flip.bids(id); vat.suck(address(vow), address(vow), tab); vat.suck(address(vow), address(this), bid); vat.hope(address(flip)); flip.yank(id); uint256 art = tab / rate; Art[ilk] = add(Art[ilk], art); require(int256(lot) >= 0 && int256(art) >= 0, "End/overflow"); vat.grab(ilk, usr, address(this), address(vow), int256(lot), int256(art)); emit Skip(ilk, id, usr, tab, lot, art); } function skim(bytes32 ilk, address urn) external { require(tag[ilk] != 0, "End/tag-ilk-not-defined"); (, uint256 rate,,,) = vat.ilks(ilk); (uint256 ink, uint256 art) = vat.urns(ilk, urn); uint256 owe = rmul(rmul(art, rate), tag[ilk]); uint256 wad = min(ink, owe); gap[ilk] = add(gap[ilk], sub(owe, wad)); require(wad <= 2**255 && art <= 2**255, "End/overflow"); vat.grab(ilk, urn, address(this), address(vow), -int256(wad), -int256(art)); emit Skim(ilk, urn, wad, art); } function free(bytes32 ilk) external { require(live == 0, "End/still-live"); (uint256 ink, uint256 art) = vat.urns(ilk, msg.sender); require(art == 0, "End/art-not-zero"); require(ink <= 2**255, "End/overflow"); vat.grab(ilk, msg.sender, msg.sender, address(vow), -int256(ink), 0); emit Free(ilk, msg.sender, ink); } function thaw() external { require(live == 0, "End/still-live"); require(debt == 0, "End/debt-not-zero"); require(vat.dai(address(vow)) == 0, "End/surplus-not-zero"); require(block.timestamp >= add(when, wait), "End/wait-not-finished"); debt = vat.debt(); emit Thaw(); } function flow(bytes32 ilk) external { require(debt != 0, "End/debt-zero"); require(fix[ilk] == 0, "End/fix-ilk-already-defined"); (, uint256 rate,,,) = vat.ilks(ilk); uint256 wad = rmul(rmul(Art[ilk], rate), tag[ilk]); fix[ilk] = mul(sub(wad, gap[ilk]), RAY) / (debt / RAY); emit Flow(ilk); } function pack(uint256 wad) external { require(debt != 0, "End/debt-zero"); vat.move(msg.sender, address(vow), mul(wad, RAY)); bag[msg.sender] = add(bag[msg.sender], wad); emit Pack(msg.sender, wad); } function cash(bytes32 ilk, uint256 wad) external { require(fix[ilk] != 0, "End/fix-ilk-not-defined"); vat.flux(ilk, address(this), msg.sender, rmul(wad, fix[ilk])); out[ilk][msg.sender] = add(out[ilk][msg.sender], wad); require(out[ilk][msg.sender] <= bag[msg.sender], "End/insufficient-bag-balance"); emit Cash(ilk, msg.sender, wad); } } interface DenyLike { function deny(address) external; } contract ESM { DSToken public immutable gem; // collateral (MKR token) End public immutable end; // cage module address public immutable proxy; // Pause proxy uint256 public immutable min; // minimum activation threshold [wad] mapping(address => uint256) public sum; // per-address balance uint256 public Sum; // total balance event Fire(); event Join(address indexed usr, uint256 wad); constructor(address gem_, address end_, address proxy_, uint256 min_) public { gem = DSToken(gem_); end = End(end_); proxy = proxy_; min = min_; } function revokesGovernanceAccess() external view returns (bool ret) { ret = proxy != address(0); } // -- math -- function add(uint256 x, uint256 y) internal pure returns (uint256 z) { z = x + y; require(z >= x); } function fire() external { require(Sum >= min, "ESM/min-not-reached"); if (proxy != address(0)) { end.vat().deny(proxy); } end.cage(); emit Fire(); } function deny(address target) external { require(Sum >= min, "ESM/min-not-reached"); DenyLike(target).deny(proxy); } function join(uint256 wad) external { require(end.live() == 1, "ESM/system-already-shutdown"); sum[msg.sender] = add(sum[msg.sender], wad); Sum = add(Sum, wad); require(gem.transferFrom(msg.sender, address(this), wad), "ESM/transfer-failed"); emit Join(msg.sender, wad); } function burn() external { uint256 balance = gem.balanceOf(address(this)); try gem.burn(balance) {} catch { gem.transfer(address(0xdead), balance); } } } contract VatFab { function newVat(address owner) public returns (Vat vat) { vat = new Vat(); vat.rely(owner); vat.deny(address(this)); } } contract JugFab { function newJug(address owner, address vat) public returns (Jug jug) { jug = new Jug(vat); jug.rely(owner); jug.deny(address(this)); } } contract VowFab { function newVow(address owner, address vat, address flap, address flop) public returns (Vow vow) { vow = new Vow(vat, flap, flop); vow.rely(owner); vow.deny(address(this)); } } contract CatFab { function newCat(address owner, address vat) public returns (Cat cat) { cat = new Cat(vat); cat.rely(owner); cat.deny(address(this)); } } contract DogFab { function newDog(address owner, address vat) public returns (Dog dog) { dog = new Dog(vat); dog.rely(owner); dog.deny(address(this)); } } contract DaiFab { function newDai(address owner, uint chainId) public returns (Dai dai) { dai = new Dai(chainId); dai.rely(owner); dai.deny(address(this)); } } contract DaiJoinFab { function newDaiJoin(address vat, address dai) public returns (DaiJoin daiJoin) { daiJoin = new DaiJoin(vat, dai); } } contract FlapFab { function newFlap(address owner, address vat, address gov) public returns (Flapper flap) { flap = new Flapper(vat, gov); flap.rely(owner); flap.deny(address(this)); } } contract FlopFab { function newFlop(address owner, address vat, address gov) public returns (Flopper flop) { flop = new Flopper(vat, gov); flop.rely(owner); flop.deny(address(this)); } } contract FlipFab { function newFlip(address owner, address vat, address cat, bytes32 ilk) public returns (Flipper flip) { flip = new Flipper(vat, cat, ilk); flip.rely(owner); flip.deny(address(this)); } } contract ClipFab { function newClip(address owner, address vat, address spotter, address dog, bytes32 ilk) public returns (Clipper clip) { clip = new Clipper(vat, spotter, dog, ilk); clip.rely(owner); clip.deny(address(this)); } } contract SpotFab { function newSpotter(address owner, address vat) public returns (Spotter spotter) { spotter = new Spotter(vat); spotter.rely(owner); spotter.deny(address(this)); } } contract PotFab { function newPot(address owner, address vat) public returns (Pot pot) { pot = new Pot(vat); pot.rely(owner); pot.deny(address(this)); } } contract EndFab { function newEnd(address owner) public returns (End end) { end = new End(); end.rely(owner); end.deny(address(this)); } } contract ESMFab { function newESM(address gov, address end, address proxy, uint min) public returns (ESM esm) { esm = new ESM(gov, end, proxy, min); } } contract PauseFab { function newPause(uint delay, address owner, DSAuthority authority) public returns(DSPause pause) { pause = new DSPause(delay, owner, authority); } } contract DssDeploy is DSAuth { VatFab public vatFab; JugFab public jugFab; VowFab public vowFab; CatFab public catFab; DogFab public dogFab; DaiFab public daiFab; DaiJoinFab public daiJoinFab; FlapFab public flapFab; FlopFab public flopFab; FlipFab public flipFab; ClipFab public clipFab; SpotFab public spotFab; PotFab public potFab; EndFab public endFab; ESMFab public esmFab; PauseFab public pauseFab; Vat public vat; Jug public jug; Vow public vow; Cat public cat; Dog public dog; Dai public dai; DaiJoin public daiJoin; Flapper public flap; Flopper public flop; Spotter public spotter; Pot public pot; End public end; ESM public esm; DSPause public pause; mapping(bytes32 => Ilk) public ilks; uint8 public step = 0; uint256 constant ONE = 10 ** 27; struct Ilk { Flipper flip; Clipper clip; address join; } constructor( VatFab vatFab_, JugFab jugFab_, VowFab vowFab_, CatFab catFab_, DogFab dogFab_, DaiFab daiFab_, DaiJoinFab daiJoinFab_, FlapFab flapFab_, FlopFab flopFab_, FlipFab flipFab_, ClipFab clipFab_, SpotFab spotFab_, PotFab potFab_, EndFab endFab_, ESMFab esmFab_, PauseFab pauseFab_ ) public { vatFab = vatFab_; jugFab = jugFab_; vowFab = vowFab_; catFab = catFab_; dogFab = dogFab_; daiFab = daiFab_; daiJoinFab = daiJoinFab_; flapFab = flapFab_; flopFab = flopFab_; flipFab = flipFab_; clipFab = clipFab_; spotFab = spotFab_; potFab = potFab_; endFab = endFab_; esmFab = esmFab_; pauseFab = pauseFab_; } function rad(uint wad) internal pure returns (uint) { return wad * 10 ** 27; } function updateDeployed( Vat vat_, Jug jug_, Vow vow_, Cat cat_, Dog dog_, Dai dai_, DaiJoin daiJoin_, Flapper flap_, Flopper flop_, Spotter spot_, Pot pot_, End end_, ESM esm_, DSPause pause_ ) external auth { require(address(vat) == address(0), "Already updated"); vat = vat_; jug = jug_; vow = vow_; cat = cat_; dog = dog_; dai = dai_; daiJoin = daiJoin_; flap = flap_; flop = flop_; spotter = spot_; pot = pot_; end = end_; esm = esm_; pause = pause_; } /* function deployVat() public auth { require(address(vatFab) != address(0), "Missing Fabs 1"); require(address(flapFab) != address(0), "Missing Fabs 2"); require(address(vat) == address(0), "VAT already deployed"); vat = vatFab.newVat(address(this)); spotter = spotFab.newSpotter(address(this), address(vat)); // Internal auth vat.rely(address(spotter)); } function deployDai(uint256 chainId) public auth { require(address(vat) != address(0), "Missing previous step"); // Deploy dai = daiFab.newDai(address(this), chainId); daiJoin = daiJoinFab.newDaiJoin(address(vat), address(dai)); dai.rely(address(daiJoin)); } function deployTaxation() public auth { require(address(vat) != address(0), "Missing previous step"); // Deploy jug = jugFab.newJug(address(this), address(vat)); pot = potFab.newPot(address(this), address(vat)); // Internal auth vat.rely(address(jug)); vat.rely(address(pot)); } function deployAuctions(address gov) public auth { require(gov != address(0), "Missing GOV address"); require(address(jug) != address(0), "Missing previous step"); // Deploy flap = flapFab.newFlap(address(this), address(vat), gov); flop = flopFab.newFlop(address(this), address(vat), gov); vow = vowFab.newVow(address(this), address(vat), address(flap), address(flop)); // Internal references set up jug.file("vow", address(vow)); pot.file("vow", address(vow)); // Internal auth vat.rely(address(flop)); flap.rely(address(vow)); flop.rely(address(vow)); } function deployLiquidator() public auth { require(address(vow) != address(0), "Missing previous step"); // Deploy cat = catFab.newCat(address(this), address(vat)); dog = dogFab.newDog(address(this), address(vat)); // Internal references set up cat.file("vow", address(vow)); dog.file("vow", address(vow)); // Internal auth vat.rely(address(cat)); vat.rely(address(dog)); vow.rely(address(cat)); vow.rely(address(dog)); } function deployEnd() public auth { require(address(cat) != address(0), "Missing previous step"); // Deploy end = endFab.newEnd(address(this)); // Internal references set up end.file("vat", address(vat)); end.file("cat", address(cat)); end.file("dog", address(dog)); end.file("vow", address(vow)); end.file("pot", address(pot)); end.file("spot", address(spotter)); // Internal auth vat.rely(address(end)); cat.rely(address(end)); dog.rely(address(end)); vow.rely(address(end)); pot.rely(address(end)); spotter.rely(address(end)); } function deployPause(uint delay, DSAuthority authority) public auth { require(address(dai) != address(0), "Missing previous step"); require(address(end) != address(0), "Missing previous step"); pause = pauseFab.newPause(delay, address(0), authority); vat.rely(address(pause.proxy())); cat.rely(address(pause.proxy())); dog.rely(address(pause.proxy())); vow.rely(address(pause.proxy())); jug.rely(address(pause.proxy())); pot.rely(address(pause.proxy())); spotter.rely(address(pause.proxy())); flap.rely(address(pause.proxy())); flop.rely(address(pause.proxy())); end.rely(address(pause.proxy())); } function deployESM(address gov, uint256 min) public auth { require(address(pause) != address(0), "Missing previous step"); // Deploy ESM esm = esmFab.newESM(gov, address(end), address(pause.proxy()), min); end.rely(address(esm)); vat.rely(address(esm)); } */ function deployCollateralFlip(bytes32 ilk, address join, address pip) public auth { require(ilk != bytes32(""), "Missing ilk name"); require(join != address(0), "Missing join address"); require(pip != address(0), "Missing pip address"); require(address(pause) != address(0), "Missing previous step"); // Deploy ilks[ilk].flip = flipFab.newFlip(address(this), address(vat), address(cat), ilk); ilks[ilk].join = join; Spotter(spotter).file(ilk, "pip", address(pip)); // Set pip // Internal references set up cat.file(ilk, "flip", address(ilks[ilk].flip)); vat.init(ilk); jug.init(ilk); // Internal auth vat.rely(join); cat.rely(address(ilks[ilk].flip)); ilks[ilk].flip.rely(address(cat)); ilks[ilk].flip.rely(address(end)); ilks[ilk].flip.rely(address(esm)); ilks[ilk].flip.rely(address(pause.proxy())); } function deployCollateralClip(bytes32 ilk, address join, address pip, address calc) public auth { require(ilk != bytes32(""), "Missing ilk name"); require(join != address(0), "Missing join address"); require(pip != address(0), "Missing pip address"); require(calc != address(0), "Missing calc address"); require(address(pause) != address(0), "Missing previous step"); // Deploy ilks[ilk].clip = clipFab.newClip(address(this), address(vat), address(spotter), address(dog), ilk); ilks[ilk].join = join; Spotter(spotter).file(ilk, "pip", address(pip)); // Set pip // Internal references set up dog.file(ilk, "clip", address(ilks[ilk].clip)); ilks[ilk].clip.file("vow", address(vow)); ilks[ilk].clip.file("calc", calc); vat.init(ilk); jug.init(ilk); // Internal auth vat.rely(join); vat.rely(address(ilks[ilk].clip)); dog.rely(address(ilks[ilk].clip)); ilks[ilk].clip.rely(address(dog)); ilks[ilk].clip.rely(address(end)); ilks[ilk].clip.rely(address(esm)); ilks[ilk].clip.rely(address(pause.proxy())); } function releaseAuth() public auth { vat.deny(address(this)); cat.deny(address(this)); dog.deny(address(this)); vow.deny(address(this)); jug.deny(address(this)); pot.deny(address(this)); dai.deny(address(this)); spotter.deny(address(this)); flap.deny(address(this)); flop.deny(address(this)); end.deny(address(this)); } function releaseAuthFlip(bytes32 ilk) public auth { ilks[ilk].flip.deny(address(this)); } function releaseAuthClip(bytes32 ilk) public auth { ilks[ilk].clip.deny(address(this)); } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"uint256","name":"chainId_","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"src","type":"address"},{"indexed":true,"internalType":"address","name":"guy","type":"address"},{"indexed":false,"internalType":"uint256","name":"wad","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":true,"inputs":[{"indexed":true,"internalType":"bytes4","name":"sig","type":"bytes4"},{"indexed":true,"internalType":"address","name":"guy","type":"address"},{"indexed":true,"internalType":"bytes32","name":"foo","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"bar","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"wad","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"fax","type":"bytes"}],"name":"LogNote","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"src","type":"address"},{"indexed":true,"internalType":"address","name":"dst","type":"address"},{"indexed":false,"internalType":"uint256","name":"wad","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"usr","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"usr","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"guy","type":"address"}],"name":"deny","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"usr","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"bool","name":"allowed","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"guy","type":"address"}],"name":"rely","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"wards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50604051611ff2380380611ff28339818101604052602081101561003357600080fd5b810190808051906020019092919050505060016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055507f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6040518060400160405280600e81526020017f4d6f7220537461626c65636f696e000000000000000000000000000000000000815250805190602001206040518060400160405280600181526020017f3100000000000000000000000000000000000000000000000000000000000000815250805190602001208330604051602001808681526020018581526020018481526020018381526020018273ffffffffffffffffffffffffffffffffffffffff168152602001955050505050506040516020818303038152906040528051906020012060058190555050611e5f806101936000396000f3fe608060405234801561001057600080fd5b50600436106101215760003560e01c806365fae35e116100ad5780639c52a7f1116100715780639c52a7f1146105fa5780639dc29fac1461063e578063a9059cbb1461068c578063bf353dbb146106f0578063dd62ed3e1461074857610121565b806365fae35e146103dd57806370a08231146104215780637ecebe00146104795780638fcbaf0c146104d157806395d89b411461057757610121565b806330adf81f116100f457806330adf81f146102af578063313ce567146102cd5780633644e515146102ee57806340c10f191461030c57806354fd4d501461035a57610121565b806306fdde0314610126578063095ea7b3146101a957806318160ddd1461020d57806323b872dd1461022b575b600080fd5b61012e6107c0565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561016e578082015181840152602081019050610153565b50505050905090810190601f16801561019b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6101f5600480360360408110156101bf57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506107f9565b60405180821515815260200191505060405180910390f35b6102156108eb565b6040518082815260200191505060405180910390f35b6102976004803603606081101561024157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506108f1565b60405180821515815260200191505060405180910390f35b6102b7610e06565b6040518082815260200191505060405180910390f35b6102d5610e2d565b604051808260ff16815260200191505060405180910390f35b6102f6610e32565b6040518082815260200191505060405180910390f35b6103586004803603604081101561032257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610e38565b005b610362610ff4565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103a2578082015181840152602081019050610387565b50505050905090810190601f1680156103cf5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61041f600480360360208110156103f357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061102d565b005b6104636004803603602081101561043757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506111e5565b6040518082815260200191505060405180910390f35b6104bb6004803603602081101561048f57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506111fd565b6040518082815260200191505060405180910390f35b61057560048036036101008110156104e857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919080359060200190929190803515159060200190929190803560ff1690602001909291908035906020019092919080359060200190929190505050611215565b005b61057f61171f565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156105bf5780820151818401526020810190506105a4565b50505050905090810190601f1680156105ec5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61063c6004803603602081101561061057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611758565b005b61068a6004803603604081101561065457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611910565b005b6106d8600480360360408110156106a257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611da3565b60405180821515815260200191505060405180910390f35b6107326004803603602081101561070657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611db8565b6040518082815260200191505060405180910390f35b6107aa6004803603604081101561075e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611dd0565b6040518082815260200191505060405180910390f35b6040518060400160405280600e81526020017f4d6f7220537461626c65636f696e00000000000000000000000000000000000081525081565b600081600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b60015481565b600081600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410156109a8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f4461692f696e73756666696369656e742d62616c616e6365000000000000000081525060200191505060405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614158015610a8057507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414155b15610c7e5781600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015610b77576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f4461692f696e73756666696369656e742d616c6c6f77616e636500000000000081525060200191505060405180910390fd5b610bfd600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205483611df5565b600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b610cc7600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205483611df5565b600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610d53600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205483611e0f565b600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a3600190509392505050565b7fea2aa0a1be11a07ed86d755c93467f4f82362b452371d1ba94d1715123511acb60001b81565b601281565b60055481565b60016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414610eec576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f4461692f6e6f742d617574686f72697a6564000000000000000000000000000081525060200191505060405180910390fd5b610f35600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482611e0f565b600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610f8460015482611e0f565b6001819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a35050565b6040518060400160405280600181526020017f310000000000000000000000000000000000000000000000000000000000000081525081565b60008060006004359250602435915034905060016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054146110f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f4461692f6e6f742d617574686f72697a6564000000000000000000000000000081525060200191505060405180910390fd5b60016000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081833373ffffffffffffffffffffffffffffffffffffffff166000357fffffffff00000000000000000000000000000000000000000000000000000000167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168460003660405180848152602001806020018281038252848482818152602001925080828437600081840152601f19601f82011690508083019250505094505050505060405180910390a450505050565b60026020528060005260406000206000915090505481565b60046020528060005260406000206000915090505481565b60006005547fea2aa0a1be11a07ed86d755c93467f4f82362b452371d1ba94d1715123511acb60001b8a8a8a8a8a604051602001808781526020018673ffffffffffffffffffffffffffffffffffffffff1681526020018573ffffffffffffffffffffffffffffffffffffffff168152602001848152602001838152602001821515815260200196505050505050506040516020818303038152906040528051906020012060405160200180807f190100000000000000000000000000000000000000000000000000000000000081525060020183815260200182815260200192505050604051602081830303815290604052805190602001209050600073ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff1614156113b4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f4461692f696e76616c69642d616464726573732d30000000000000000000000081525060200191505060405180910390fd5b60018185858560405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa15801561140e573d6000803e3d6000fd5b5050506020604051035173ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff16146114b8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f4461692f696e76616c69642d7065726d6974000000000000000000000000000081525060200191505060405180910390fd5b60008614806114c75750854211155b611539576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f4461692f7065726d69742d65787069726564000000000000000000000000000081525060200191505060405180910390fd5b600460008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008154809291906001019190505587146115fb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260118152602001807f4461692f696e76616c69642d6e6f6e636500000000000000000000000000000081525060200191505060405180910390fd5b60008561160957600061162b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b905080600360008c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508873ffffffffffffffffffffffffffffffffffffffff168a73ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040518082815260200191505060405180910390a350505050505050505050565b6040518060400160405280600381526020017f4d4f52000000000000000000000000000000000000000000000000000000000081525081565b60008060006004359250602435915034905060016000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541461181e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f4461692f6e6f742d617574686f72697a6564000000000000000000000000000081525060200191505060405180910390fd5b60008060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081833373ffffffffffffffffffffffffffffffffffffffff166000357fffffffff00000000000000000000000000000000000000000000000000000000167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168460003660405180848152602001806020018281038252848482818152602001925080828437600081840152601f19601f82011690508083019250505094505050505060405180910390a450505050565b80600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410156119c5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f4461692f696e73756666696369656e742d62616c616e6365000000000000000081525060200191505060405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614158015611a9d57507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205414155b15611c9b5780600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015611b94576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601a8152602001807f4461692f696e73756666696369656e742d616c6c6f77616e636500000000000081525060200191505060405180910390fd5b611c1a600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482611df5565b600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b611ce4600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482611df5565b600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550611d3360015482611df5565b600181905550600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a35050565b6000611db03384846108f1565b905092915050565b60006020528060005260406000206000915090505481565b6003602052816000526040600020602052806000526040600020600091509150505481565b6000828284039150811115611e0957600080fd5b92915050565b6000828284019150811015611e2357600080fd5b9291505056fea2646970667358221220fa48af1e0c670a63657c606ce4da2ae2c4c205ad438f56a53342c7e37afed34464736f6c634300060c003300000000000000000000000000000000000000000000000000000000000000fa
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000000000000000000000000000000000fa
-----Decoded View---------------
Arg [0] : chainId_ (uint256): 250
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000000000000000000000000000000000fa
Deployed ByteCode Sourcemap
31105:5013:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;31476:51;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;34513:183;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;31670:26;;;:::i;:::-;;;;;;;;;;;;;;;;;;;33175:590;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;32520:108;;;:::i;:::-;;;;;;;;;;;;;;;;;;;31626:37;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;32337:31;;;:::i;:::-;;;;;;;;;;;;;;;;;;;33771:206;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;31581:38;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;31201:65;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;31705:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;31845:60;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;35102:1013;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;31534:40;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;31272:65;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;33983:524;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;33044:125;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;31156:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;31775:63;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;31476:51;;;;;;;;;;;;;;;;;;;:::o;34513:183::-;34571:4;34617:3;34588:9;:21;34598:10;34588:21;;;;;;;;;;;;;;;:26;34610:3;34588:26;;;;;;;;;;;;;;;:32;;;;34657:3;34636:30;;34645:10;34636:30;;;34662:3;34636:30;;;;;;;;;;;;;;;;;;34684:4;34677:11;;34513:183;;;;:::o;31670:26::-;;;;:::o;33175:590::-;33258:4;33306:3;33288:9;:14;33298:3;33288:14;;;;;;;;;;;;;;;;:21;;33280:58;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;33360:10;33353:17;;:3;:17;;;;:59;;;;;33409:2;33374:9;:14;33384:3;33374:14;;;;;;;;;;;;;;;:26;33389:10;33374:26;;;;;;;;;;;;;;;;:38;;33353:59;33349:244;;;33467:3;33437:9;:14;33447:3;33437:14;;;;;;;;;;;;;;;:26;33452:10;33437:26;;;;;;;;;;;;;;;;:33;;33429:72;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;33545:36;33549:9;:14;33559:3;33549:14;;;;;;;;;;;;;;;:26;33564:10;33549:26;;;;;;;;;;;;;;;;33577:3;33545;:36::i;:::-;33516:9;:14;33526:3;33516:14;;;;;;;;;;;;;;;:26;33531:10;33516:26;;;;;;;;;;;;;;;:65;;;;33349:244;33620:24;33624:9;:14;33634:3;33624:14;;;;;;;;;;;;;;;;33640:3;33620;:24::i;:::-;33603:9;:14;33613:3;33603:14;;;;;;;;;;;;;;;:41;;;;33672:24;33676:9;:14;33686:3;33676:14;;;;;;;;;;;;;;;;33692:3;33672;:24::i;:::-;33655:9;:14;33665:3;33655:14;;;;;;;;;;;;;;;:41;;;;33726:3;33712:23;;33721:3;33712:23;;;33731:3;33712:23;;;;;;;;;;;;;;;;;;33753:4;33746:11;;33175:590;;;;;:::o;32520:108::-;32562:66;32520:108;;;:::o;31626:37::-;31661:2;31626:37;:::o;32337:31::-;;;;:::o;33771:206::-;31397:1;31376:5;:17;31382:10;31376:17;;;;;;;;;;;;;;;;:22;31368:53;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;33850:24:::1;33854:9;:14;33864:3;33854:14;;;;;;;;;;;;;;;;33870:3;33850;:24::i;:::-;33833:9;:14;33843:3;33833:14;;;;;;;;;;;;;;;:41;;;;33902:21;33906:11;;33919:3;33902;:21::i;:::-;33885:11;:38;;;;33960:3;33939:30;;33956:1;33939:30;;;33965:3;33939:30;;;;;;;;;;;;;;;;;;33771:206:::0;;:::o;31581:38::-;;;;;;;;;;;;;;;;;;;:::o;31201:65::-;2633:11;2655;2677;2745:1;2732:15;2725:22;;2781:2;2768:16;2761:23;;2805:11;2798:18;;31397:1:::1;31376:5;:17:::0;31382:10:::1;31376:17;;;;;;;;;;;;;;;;:22;31368:53;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;31262:1:::2;31249:5;:10:::0;31255:3:::2;31249:10;;;;;;;;;;;;;;;:14;;;;2892:3:::0;2887;2875:10;2858:53;;2866:7;;;;2858:53;;;2897:3;2902:8;;2858:53;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;31201:65;;;;:::o;31705:63::-;;;;;;;;;;;;;;;;;:::o;31845:60::-;;;;;;;;;;;;;;;;;:::o;35102:1013::-;35273:14;35377:16;;32562:66;35433:15;;35488:6;35534:7;35581:5;35626:6;35672:7;35422:258;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;35412:269;;;;;;35313:379;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;35303:390;;;;;;35273:420;;35732:1;35714:20;;:6;:20;;;;35706:54;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;35789:26;35799:6;35807:1;35810;35813;35789:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;35779:36;;:6;:36;;;35771:67;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;35867:1;35857:6;:11;:28;;;;35879:6;35872:3;:13;;35857:28;35849:59;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;35936:6;:14;35943:6;35936:14;;;;;;;;;;;;;;;;:16;;;;;;;;;;;;35927:5;:25;35919:55;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;35985:8;35996:7;:22;;36017:1;35996:22;;;36011:2;35996:22;35985:33;;36058:3;36029:9;:17;36039:6;36029:17;;;;;;;;;;;;;;;:26;36047:7;36029:26;;;;;;;;;;;;;;;:32;;;;36094:7;36077:30;;36086:6;36077:30;;;36103:3;36077:30;;;;;;;;;;;;;;;;;;35102:1013;;;;;;;;;;:::o;31534:40::-;;;;;;;;;;;;;;;;;;;:::o;31272:65::-;2633:11;2655;2677;2745:1;2732:15;2725:22;;2781:2;2768:16;2761:23;;2805:11;2798:18;;31397:1:::1;31376:5;:17:::0;31382:10:::1;31376:17;;;;;;;;;;;;;;;;:22;31368:53;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;31333:1:::2;31320:5:::0;:10:::2;31326:3;31320:10;;;;;;;;;;;;;;;:14;;;;2892:3:::0;2887;2875:10;2858:53;;2866:7;;;;2858:53;;;2897:3;2902:8;;2858:53;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;31272:65;;;;:::o;33983:524::-;34066:3;34048:9;:14;34058:3;34048:14;;;;;;;;;;;;;;;;:21;;34040:58;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;34120:10;34113:17;;:3;:17;;;;:59;;;;;34169:2;34134:9;:14;34144:3;34134:14;;;;;;;;;;;;;;;:26;34149:10;34134:26;;;;;;;;;;;;;;;;:38;;34113:59;34109:244;;;34227:3;34197:9;:14;34207:3;34197:14;;;;;;;;;;;;;;;:26;34212:10;34197:26;;;;;;;;;;;;;;;;:33;;34189:72;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;34305:36;34309:9;:14;34319:3;34309:14;;;;;;;;;;;;;;;:26;34324:10;34309:26;;;;;;;;;;;;;;;;34337:3;34305;:36::i;:::-;34276:9;:14;34286:3;34276:14;;;;;;;;;;;;;;;:26;34291:10;34276:26;;;;;;;;;;;;;;;:65;;;;34109:244;34380:24;34384:9;:14;34394:3;34384:14;;;;;;;;;;;;;;;;34400:3;34380;:24::i;:::-;34363:9;:14;34373:3;34363:14;;;;;;;;;;;;;;;:41;;;;34432:21;34436:11;;34449:3;34432;:21::i;:::-;34415:11;:38;;;;34491:1;34469:30;;34478:3;34469:30;;;34495:3;34469:30;;;;;;;;;;;;;;;;;;33983:524;;:::o;33044:125::-;33103:4;33127:34;33140:10;33152:3;33157;33127:12;:34::i;:::-;33120:41;;33044:125;;;;:::o;31156:38::-;;;;;;;;;;;;;;;;;:::o;31775:63::-;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;32193:104::-;32245:6;32287:1;32281;32277;:5;32273:9;;;32272:16;;32264:25;;;;;;32193:104;;;;:::o;32083:::-;32135:6;32177:1;32171;32167;:5;32163:9;;;32162:16;;32154:25;;;;;;32083:104;;;;:::o
Swarm Source
ipfs://fa48af1e0c670a63657c606ce4da2ae2c4c205ad438f56a53342c7e37afed344