Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
262 lines (228 sloc) 9.21 KB
/// vat.sol -- Dai CDP database
// Copyright (C) 2018 Rain <rainbreak@riseup.net>
//
// 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.0;
contract Vat {
// --- 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); _; }
mapping(address => mapping (address => uint)) public can;
function hope(address usr) external { can[msg.sender][usr] = 1; }
function nope(address usr) external { 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; // Access Flag
// --- Logs ---
event LogNote(
bytes4 indexed sig,
bytes32 indexed arg1,
bytes32 indexed arg2,
bytes32 indexed arg3,
bytes data
) anonymous;
modifier note {
_;
assembly {
// log an 'anonymous' event with a constant 6 words of calldata
// and four indexed topics: the selector and the first three args
let mark := msize // end of memory ensures zero
mstore(0x40, add(mark, 288)) // update free memory pointer
mstore(mark, 0x20) // bytes type data offset
mstore(add(mark, 0x20), 224) // bytes size (padded)
calldatacopy(add(mark, 0x40), 0, 224) // bytes payload
log4(mark, 288, // calldata
shl(224, shr(224, calldataload(0))), // msg.sig
calldataload(4), // arg1
calldataload(36), // arg2
calldataload(68) // arg3
)
}
}
// --- 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);
ilks[ilk].rate = 10 ** 27;
}
function file(bytes32 what, uint data) external note auth {
if (what == "Line") Line = data;
}
function file(bytes32 ilk, bytes32 what, uint data) external note auth {
if (what == "spot") ilks[ilk].spot = data;
if (what == "line") ilks[ilk].line = data;
if (what == "dust") ilks[ilk].dust = data;
}
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));
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));
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);
Urn memory urn = urns[i][u];
Ilk memory ilk = ilks[i];
// ilk has been initialised
require(ilk.rate != 0);
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(urn.art, ilk.rate);
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)));
// urn is either less risky than before, or it is safe
require(either(both(dart <= 0, dink >= 0), tab <= mul(urn.ink, ilk.spot)));
// urn is either more safe, or the owner consents
require(either(both(dart <= 0, dink >= 0), wish(u, msg.sender)));
// collateral src consents
require(either(dink <= 0, wish(v, msg.sender)));
// debt dst consents
require(either(dart >= 0, wish(w, msg.sender)));
// urn has no debt, or a non-dusty amount
require(either(urn.art == 0, tab >= ilk.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(wish(src, msg.sender) && wish(dst, msg.sender));
// both sides safe
require(utab <= mul(u.ink, i.spot));
require(vtab <= mul(v.ink, i.spot));
// both sides non-dusty
require(utab >= i.dust || u.art == 0);
require(vtab >= i.dust || v.art == 0);
}
// --- 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);
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);
}
}
You can’t perform that action at this time.