Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00Token Holdings
Latest 25 from a total of 8,532 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Approve | 20932399 | 32 hrs ago | IN | 0 ETH | 0.00044775 | ||||
Approve | 20916299 | 3 days ago | IN | 0 ETH | 0.00061283 | ||||
Approve | 20905842 | 5 days ago | IN | 0 ETH | 0.00026749 | ||||
Approve | 20901000 | 5 days ago | IN | 0 ETH | 0.00081982 | ||||
Transfer | 20900111 | 5 days ago | IN | 0 ETH | 0.00037054 | ||||
Transfer | 20892395 | 6 days ago | IN | 0 ETH | 0.00041163 | ||||
Transfer | 20891960 | 6 days ago | IN | 0 ETH | 0.00018336 | ||||
Transfer | 20891919 | 6 days ago | IN | 0 ETH | 0.00027558 | ||||
Approve | 20891421 | 7 days ago | IN | 0 ETH | 0.00028214 | ||||
Approve | 20891416 | 7 days ago | IN | 0 ETH | 0.00025057 | ||||
Transfer | 20869606 | 10 days ago | IN | 0 ETH | 0.00049256 | ||||
Transfer | 20869603 | 10 days ago | IN | 0 ETH | 0.00081291 | ||||
Approve | 20866293 | 10 days ago | IN | 0 ETH | 0.00047035 | ||||
Transfer | 20862119 | 11 days ago | IN | 0 ETH | 0.00031458 | ||||
Approve | 20859747 | 11 days ago | IN | 0 ETH | 0.00034605 | ||||
Approve | 20859735 | 11 days ago | IN | 0 ETH | 0.00027766 | ||||
Approve | 20857738 | 11 days ago | IN | 0 ETH | 0.00053276 | ||||
Transfer | 20850627 | 12 days ago | IN | 0 ETH | 0.0001693 | ||||
Approve | 20850608 | 12 days ago | IN | 0 ETH | 0.00028965 | ||||
Approve | 20846776 | 13 days ago | IN | 0 ETH | 0.00040561 | ||||
Transfer | 20843969 | 13 days ago | IN | 0 ETH | 0.00069239 | ||||
Transfer | 20843922 | 13 days ago | IN | 0 ETH | 0.00078283 | ||||
Approve | 20829607 | 15 days ago | IN | 0 ETH | 0.00148107 | ||||
Transfer | 20823122 | 16 days ago | IN | 0 ETH | 0.00089799 | ||||
Approve | 20811691 | 18 days ago | IN | 0 ETH | 0.00123696 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
DSToken
Compiler Version
v0.8.9+commit.e5eed63a
Contract Source Code (Solidity Standard Json-Input format)
/// token.sol -- ERC20 implementation with minting and burning // Copyright (C) 2015, 2016, 2017 DappHub, LLC // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU 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 General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.4.23; 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 auth { owner = owner_; emit LogSetOwner(owner); } function setAuthority(DSAuthority authority_) public 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 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, type(uint256).max); } 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] != type(uint256).max) { 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] != type(uint256).max) { 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_; } }
// SPDX-License-Identifier: AGPL-3.0-or-later /// join.sol -- Basic token adapters // Copyright (C) 2018 Rain <[email protected]> // // 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.8.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). interface GemLike { function decimals() external view returns (uint); function transfer(address,uint) external returns (bool); function transferFrom(address,address,uint) external returns (bool); } interface DSTokenLike { function mint(address,uint) external; function burn(address,uint) external; } interface VatLike { function slip(bytes32,address,int) external; function move(address,address,uint) external; } /* 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. - `USBJoin`: For connecting internal USB 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 { // --- Auth --- mapping (address => uint) 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, "GemJoin/not-authorized"); _; } VatLike public vat; // CDP Engine bytes32 public ilk; // Collateral Type GemLike public gem; uint public dec; uint public live; // Active Flag // Events event Rely(address indexed usr); event Deny(address indexed usr); event Join(address indexed usr, uint256 wad); event Exit(address indexed usr, uint256 wad); event Cage(); constructor(address vat_, bytes32 ilk_, address gem_) public { wards[msg.sender] = 1; live = 1; vat = VatLike(vat_); ilk = ilk_; gem = GemLike(gem_); dec = gem.decimals(); emit Rely(msg.sender); } function cage() external auth { live = 0; emit Cage(); } function join(address usr, uint wad) external { 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"); emit Join(usr, wad); } function exit(address usr, uint wad) external { require(wad <= 2 ** 255, "GemJoin/overflow"); vat.slip(ilk, msg.sender, -int(wad)); require(gem.transfer(usr, wad), "GemJoin/failed-transfer"); emit Exit(usr, wad); } } contract USBJoin { // --- Auth --- mapping (address => uint) 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, "USBJoin/not-authorized"); _; } VatLike public vat; // CDP Engine DSTokenLike public USB; // Stablecoin Token uint public live; // Active Flag // Events event Rely(address indexed usr); event Deny(address indexed usr); event Join(address indexed usr, uint256 wad); event Exit(address indexed usr, uint256 wad); event Cage(); constructor(address vat_, address USB_) public { wards[msg.sender] = 1; live = 1; vat = VatLike(vat_); USB = DSTokenLike(USB_); } function cage() external auth { live = 0; emit Cage(); } 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 { vat.move(address(this), usr, mul(ONE, wad)); USB.burn(msg.sender, wad); emit Join(usr, wad); } function exit(address usr, uint wad) external { require(live == 1, "USBJoin/not-live"); vat.move(msg.sender, address(this), mul(ONE, wad)); USB.mint(usr, wad); emit Exit(usr, wad); } }
// SPDX-License-Identifier: AGPL-3.0-or-later /// clip.sol -- USB auction module 2.0 // // 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.8.0; interface VatLike { function move(address,address,uint256) external; function flux(bytes32,address,address,uint256) external; function ilks(bytes32) external returns (uint256, uint256, uint256, uint256, uint256); function suck(address,address,uint256) external; } interface PipLike { function peek() external returns (bytes32, bool); } interface SpotterLike { function par() external returns (uint256); function ilks(bytes32) external returns (PipLike, uint256); } interface DogLike { function chop(bytes32) external returns (uint256); function digs(bytes32, uint256) external; } interface ClipperCallee { function clipperCall(address, uint256, uint256, bytes calldata) external; } interface AbacusLike { function price(uint256, uint256) external view returns (uint256); } 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 VatLike immutable public vat; // Core CDP Engine DogLike public dog; // Liquidation module address public vow; // Recipient of USB raised in auctions SpotterLike public spotter; // Collateral price module AbacusLike 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; // USB 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 = VatLike(vat_); spotter = SpotterLike(spotter_); dog = DogLike(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 = SpotterLike(data); else if (what == "dog") dog = DogLike(data); else if (what == "vow") vow = data; else if (what == "calc") calc = AbacusLike(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 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 USB. 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 USB than their assigned USB target,`tab`; // thus, if `amt` would cost more USB than `tab` at the current price, the // amount of collateral purchased will instead be just enough to collect `tab` USB. // // 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 USB 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 (USB / 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 // USB needed to buy a slice of this sale owe = mul(slice, price); // Don't collect more than tab of USB 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 DogLike dog_ = dog; if (data.length > 0 && who != address(vat) && who != address(dog_)) { ClipperCallee(who).clipperCall(msg.sender, owe, slice, data); } // Get USB from caller vat.move(msg.sender, vow, owe); // Removes USB 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) = VatLike(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); } }
/// VoteProxy.sol // 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/>. // vote w/ a hot or cold wallet using a proxy identity pragma solidity >=0.4.24; interface TokenLike { function balanceOf(address) external view returns (uint256); function approve(address, uint256) external; function pull(address, uint256) external; function push(address, uint256) external; } interface ChiefLike { function GOV() external view returns (TokenLike); function IOU() external view returns (TokenLike); function deposits(address) external view returns (uint256); function lock(uint256) external; function free(uint256) external; function vote(address[] calldata) external returns (bytes32); function vote(bytes32) external; } contract VoteProxy { address public cold; address public hot; TokenLike public gov; TokenLike public iou; ChiefLike public chief; constructor(address _chief, address _cold, address _hot) public { chief = ChiefLike(_chief); cold = _cold; hot = _hot; gov = chief.GOV(); iou = chief.IOU(); gov.approve(address(chief), type(uint256).max); iou.approve(address(chief), type(uint256).max); } modifier auth() { require(msg.sender == hot || msg.sender == cold, "Sender must be a Cold or Hot Wallet"); _; } function lock(uint256 wad) public auth { gov.pull(cold, wad); // mkr from cold chief.lock(wad); // mkr out, ious in } function free(uint256 wad) public auth { chief.free(wad); // ious out, mkr in gov.push(cold, wad); // mkr to cold } function freeAll() public auth { chief.free(chief.deposits(address(this))); gov.push(cold, gov.balanceOf(address(this))); } function vote(address[] memory yays) public auth returns (bytes32) { return chief.vote(yays); } function vote(bytes32 slate) public auth { chief.vote(slate); } }
// SPDX-License-Identifier: AGPL-3.0-or-later /// flop.sol -- Debt auction // Copyright (C) 2018 Rain <[email protected]> // // 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.8.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). interface VatLike { function move(address,address,uint) external; function suck(address,address,uint) external; } interface GemLike { function mint(address,uint) external; } interface VowLike { function Ash() external returns (uint); function kiss(uint) external; } /* This thing creates gems on demand in return for USB. - `lot` gems in return for bid - `bid` USB paid - `gal` receives USB income - `ttl` single bid lifetime - `beg` minimum bid increase - `end` max auction duration */ contract Flopper { // --- Auth --- mapping (address => uint) 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, "Flopper/not-authorized"); _; } // --- Data --- struct Bid { uint256 bid; // USB 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; VatLike public vat; // CDP Engine GemLike 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 = VatLike(vat_); gem = GemLike(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 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 < type(uint256).max, "Flopper/overflow"); id = ++kicks; bids[id].bid = bid; bids[id].lot = lot; bids[id].guy = gal; bids[id].end = add(uint48(block.timestamp), tau); emit Kick(id, lot, bid, gal); } function tick(uint id) external { require(bids[id].end < block.timestamp, "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(block.timestamp), tau); } function dent(uint id, uint lot, uint bid) external { require(live == 1, "Flopper/not-live"); require(bids[id].guy != address(0), "Flopper/guy-not-set"); require(bids[id].tic > block.timestamp || bids[id].tic == 0, "Flopper/already-finished-tic"); require(bids[id].end > block.timestamp, "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 = VowLike(bids[id].guy).Ash(); VowLike(bids[id].guy).kiss(min(bid, Ash)); } bids[id].guy = msg.sender; } bids[id].lot = lot; bids[id].tic = add(uint48(block.timestamp), ttl); } function deal(uint id) external { require(live == 1, "Flopper/not-live"); require(bids[id].tic != 0 && (bids[id].tic < block.timestamp || bids[id].end < block.timestamp), "Flopper/not-finished"); gem.mint(bids[id].guy, bids[id].lot); delete bids[id]; } // --- Shutdown --- function cage() external auth { live = 0; vow = msg.sender; } function yank(uint id) external { 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]; } }
// SPDX-License-Identifier: AGPL-3.0-or-later /// cat.sol -- USB liquidation module // Copyright (C) 2018 Rain <[email protected]> // // 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.8.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). interface Kicker { function kick(address urn, address gal, uint256 tab, uint256 lot, uint256 bid) external returns (uint256); } interface VatLike { function ilks(bytes32) external view returns ( uint256 Art, // [wad] uint256 rate, // [ray] uint256 spot, // [ray] uint256 line, // [rad] uint256 dust // [rad] ); function urns(bytes32,address) external view returns ( uint256 ink, // [wad] uint256 art // [wad] ); function grab(bytes32,address,address,address,int256,int256) external; function hope(address) external; function nope(address) external; } interface VowLike { function fess(uint256) external; } contract Cat { // --- 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, "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 VatLike public vat; // CDP Engine VowLike public vow; // Debt Engine uint256 public box; // Max USB out for liquidation [rad] uint256 public litter; // Balance of USB 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 = VatLike(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 auth { if (what == "vow") vow = VowLike(data); else revert("Cat/file-unrecognized-param"); } function file(bytes32 what, uint256 data) external auth { if (what == "box") box = data; else revert("Cat/file-unrecognized-param"); } function file(bytes32 ilk, bytes32 what, uint256 data) external 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 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 USB. 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 auth { litter = sub(litter, rad); } function cage() external auth { live = 0; } }
// SPDX-License-Identifier: AGPL-3.0-or-later /// vow.sol -- USB settlement module // Copyright (C) 2018 Rain <[email protected]> // // 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.8.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). interface FlopLike { function kick(address gal, uint lot, uint bid) external returns (uint); function cage() external; function live() external returns (uint); } interface FlapLike { function kick(uint lot, uint bid) external returns (uint); function cage(uint) external; function live() external returns (uint); } interface VatLike { function USB (address) external view returns (uint); function sin (address) external view returns (uint); function heal(uint256) external; function hope(address) external; function nope(address) external; } contract Vow { // --- Auth --- mapping (address => uint) public wards; function rely(address usr) external auth { require(live == 1, "Vow/not-live"); wards[usr] = 1; } function deny(address usr) external auth { wards[usr] = 0; } modifier auth { require(wards[msg.sender] == 1, "Vow/not-authorized"); _; } // --- Data --- VatLike public vat; // CDP Engine FlapLike public flapper; // Surplus Auction House FlopLike 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 = VatLike(vat_); flapper = FlapLike(flapper_); flopper = FlopLike(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 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 auth { if (what == "flapper") { vat.nope(address(flapper)); flapper = FlapLike(data); vat.hope(data); } else if (what == "flopper") flopper = FlopLike(data); else revert("Vow/file-unrecognized-param"); } // Push to debt-queue function fess(uint tab) external auth { sin[block.timestamp] = add(sin[block.timestamp], tab); Sin = add(Sin, tab); } // Pop from debt-queue function flog(uint era) external { require(add(era, wait) <= block.timestamp, "Vow/wait-not-finished"); Sin = sub(Sin, sin[era]); sin[era] = 0; } // Debt settlement function heal(uint rad) external { require(rad <= vat.USB(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 { require(rad <= Ash, "Vow/not-enough-ash"); require(rad <= vat.USB(address(this)), "Vow/insufficient-surplus"); Ash = sub(Ash, rad); vat.heal(rad); } // Debt auction function flop() external returns (uint id) { require(sump <= sub(sub(vat.sin(address(this)), Sin), Ash), "Vow/insufficient-debt"); require(vat.USB(address(this)) == 0, "Vow/surplus-not-zero"); Ash = add(Ash, sump); id = flopper.kick(address(this), dump, sump); } // Surplus auction function flap() external returns (uint id) { require(vat.USB(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 auth { require(live == 1, "Vow/not-live"); live = 0; Sin = 0; Ash = 0; flapper.cage(vat.USB(address(flapper))); flopper.cage(); vat.heal(min(vat.USB(address(this)), vat.sin(address(this)))); } }
// SPDX-License-Identifier: AGPL-3.0-or-later /// end.sol -- global settlement engine // // 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.8.0; interface VatLike { function dai(address) external view returns (uint256); function ilks(bytes32 ilk) external returns ( uint256 Art, // [wad] uint256 rate, // [ray] uint256 spot, // [ray] uint256 line, // [rad] uint256 dust // [rad] ); function urns(bytes32 ilk, address urn) external returns ( uint256 ink, // [wad] uint256 art // [wad] ); function debt() external returns (uint256); function move(address src, address dst, uint256 rad) external; function hope(address) external; function flux(bytes32 ilk, address src, address dst, uint256 rad) external; function grab(bytes32 i, address u, address v, address w, int256 dink, int256 dart) external; function suck(address u, address v, uint256 rad) external; function cage() external; } interface CatLike { function ilks(bytes32) external returns ( address flip, uint256 chop, // [ray] uint256 lump // [rad] ); function cage() external; } interface DogLike { function ilks(bytes32) external returns ( address clip, uint256 chop, uint256 hole, uint256 dirt ); function cage() external; } interface PotLike { function cage() external; } interface VowLike { function cage() external; } interface FlipLike { function bids(uint256 id) external view returns ( uint256 bid, // [rad] uint256 lot, // [wad] address guy, uint48 tic, // [unix epoch time] uint48 end, // [unix epoch time] address usr, address gal, uint256 tab // [rad] ); function yank(uint256 id) external; } interface ClipLike { function sales(uint256 id) external view returns ( uint256 pos, uint256 tab, uint256 lot, address usr, uint96 tic, uint256 top ); function yank(uint256 id) external; } interface PipLike { function read() external view returns (bytes32); } interface SpotLike { function par() external view returns (uint256); function ilks(bytes32) external view returns ( PipLike pip, uint256 mat // [ray] ); function cage() external; } /* 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 --- VatLike public vat; // CDP Engine CatLike public cat; DogLike public dog; VowLike public vow; // Debt Engine PotLike public pot; SpotLike 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 = VatLike(data); else if (what == "cat") cat = CatLike(data); else if (what == "dog") dog = DogLike(data); else if (what == "vow") vow = VowLike(data); else if (what == "pot") pot = PotLike(data); else if (what == "spot") spot = SpotLike(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); ClipLike clip = ClipLike(_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); FlipLike flip = FlipLike(_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); } }
// DsrManager.sol // 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.8.0; interface VatLike { function hope(address) external; } interface PotLike { function vat() external view returns (address); function chi() external view returns (uint256); function rho() external view returns (uint256); function drip() external returns (uint256); function join(uint256) external; function exit(uint256) external; } interface JoinLike { function USB() external view returns (address); function join(address, uint256) external; function exit(address, uint256) external; } interface GemLike { function transferFrom(address,address,uint256) external returns (bool); function approve(address,uint256) external returns (bool); } contract DsrManager { PotLike public pot; GemLike public USB; JoinLike public USBJoin; uint256 public supply; mapping (address => uint256) public pieOf; event Join(address indexed dst, uint256 wad); event Exit(address indexed dst, uint256 wad); uint256 constant RAY = 10 ** 27; 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 rmul(uint256 x, uint256 y) internal pure returns (uint256 z) { // always rounds down z = mul(x, y) / RAY; } function rdiv(uint256 x, uint256 y) internal pure returns (uint256 z) { // always rounds down z = mul(x, RAY) / y; } function rdivup(uint256 x, uint256 y) internal pure returns (uint256 z) { // always rounds up z = add(mul(x, RAY), sub(y, 1)) / y; } constructor(address pot_, address USBJoin_) public { pot = PotLike(pot_); USBJoin = JoinLike(USBJoin_); USB = GemLike(USBJoin.USB()); VatLike vat = VatLike(pot.vat()); vat.hope(address(USBJoin)); vat.hope(address(pot)); USB.approve(address(USBJoin), type(uint256).max); } function USBBalance(address usr) external returns (uint256 wad) { uint256 chi = (block.timestamp > pot.rho()) ? pot.drip() : pot.chi(); wad = rmul(chi, pieOf[usr]); } // wad is denominated in USB function join(address dst, uint256 wad) external { uint256 chi = (block.timestamp > pot.rho()) ? pot.drip() : pot.chi(); uint256 pie = rdiv(wad, chi); pieOf[dst] = add(pieOf[dst], pie); supply = add(supply, pie); USB.transferFrom(msg.sender, address(this), wad); USBJoin.join(address(this), wad); pot.join(pie); emit Join(dst, wad); } // wad is denominated in USB function exit(address dst, uint256 wad) external { uint256 chi = (block.timestamp > pot.rho()) ? pot.drip() : pot.chi(); uint256 pie = rdivup(wad, chi); require(pieOf[msg.sender] >= pie, "insufficient-balance"); pieOf[msg.sender] = sub(pieOf[msg.sender], pie); supply = sub(supply, pie); pot.exit(pie); uint256 amt = rmul(chi, pie); USBJoin.exit(dst, amt); emit Exit(dst, amt); } function exitAll(address dst) external { uint256 chi = (block.timestamp > pot.rho()) ? pot.drip() : pot.chi(); uint256 pie = pieOf[msg.sender]; pieOf[msg.sender] = 0; supply = sub(supply, pie); pot.exit(pie); uint256 amt = rmul(chi, pie); USBJoin.exit(dst, amt); emit Exit(dst, amt); } }
// SPDX-License-Identifier: AGPL-3.0-or-later /// flip.sol -- Collateral auction // Copyright (C) 2018 Rain <[email protected]> // // 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.8.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). interface VatLike { function move(address,address,uint256) external; function flux(bytes32,address,address,uint256) external; } interface CatLike { function claw(uint256) external; } /* This thing lets you flip some gems for a given amount of USB. Once the given amount of USB is raised, gems are forgone instead. - `lot` gems in return for bid - `tab` total USB wanted - `bid` USB paid - `gal` receives USB 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; // USB 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 USB wanted [rad] } mapping (uint256 => Bid) public bids; VatLike 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; CatLike 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 = VatLike(vat_); cat = CatLike(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 = CatLike(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 < type(uint256).max, "Flipper/overflow"); id = ++kicks; bids[id].bid = bid; bids[id].lot = lot; bids[id].guy = msg.sender; // configurable?? bids[id].end = add(uint48(block.timestamp), 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 < block.timestamp, "Flipper/not-finished"); require(bids[id].tic == 0, "Flipper/bid-already-placed"); bids[id].end = add(uint48(block.timestamp), tau); } function tend(uint256 id, uint256 lot, uint256 bid) external { require(bids[id].guy != address(0), "Flipper/guy-not-set"); require(bids[id].tic > block.timestamp || bids[id].tic == 0, "Flipper/already-finished-tic"); require(bids[id].end > block.timestamp, "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(block.timestamp), ttl); } function dent(uint256 id, uint256 lot, uint256 bid) external { require(bids[id].guy != address(0), "Flipper/guy-not-set"); require(bids[id].tic > block.timestamp || bids[id].tic == 0, "Flipper/already-finished-tic"); require(bids[id].end > block.timestamp, "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(block.timestamp), ttl); } function deal(uint256 id) external { require(bids[id].tic != 0 && (bids[id].tic < block.timestamp || bids[id].end < block.timestamp), "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]; } }
// SPDX-License-Identifier: AGPL-3.0-or-later /// flap.sol -- Surplus auction // Copyright (C) 2018 Rain <[email protected]> // // 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.8.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). interface VatLike { function move(address,address,uint) external; } interface GemLike { function move(address,address,uint) external; function burn(address,uint) external; } /* This thing lets you sell some USB in return for gems. - `lot` USB in return for bid - `bid` gems paid - `ttl` single bid lifetime - `beg` minimum bid increase - `end` max auction duration */ contract Flapper { // --- Auth --- mapping (address => uint) 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, "Flapper/not-authorized"); _; } // --- Data --- struct Bid { uint256 bid; // gems paid [wad] uint256 lot; // USB 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; VatLike public vat; // CDP Engine GemLike 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 = VatLike(vat_); gem = GemLike(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 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 < type(uint256).max, "Flapper/overflow"); id = ++kicks; bids[id].bid = bid; bids[id].lot = lot; bids[id].guy = msg.sender; // configurable?? bids[id].end = add(uint48(block.timestamp), tau); vat.move(msg.sender, address(this), lot); emit Kick(id, lot, bid); } function tick(uint id) external { require(bids[id].end < block.timestamp, "Flapper/not-finished"); require(bids[id].tic == 0, "Flapper/bid-already-placed"); bids[id].end = add(uint48(block.timestamp), tau); } function tend(uint id, uint lot, uint bid) external { require(live == 1, "Flapper/not-live"); require(bids[id].guy != address(0), "Flapper/guy-not-set"); require(bids[id].tic > block.timestamp || bids[id].tic == 0, "Flapper/already-finished-tic"); require(bids[id].end > block.timestamp, "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.move(msg.sender, bids[id].guy, bids[id].bid); bids[id].guy = msg.sender; } gem.move(msg.sender, address(this), bid - bids[id].bid); bids[id].bid = bid; bids[id].tic = add(uint48(block.timestamp), ttl); } function deal(uint id) external { require(live == 1, "Flapper/not-live"); require(bids[id].tic != 0 && (bids[id].tic < block.timestamp || bids[id].end < block.timestamp), "Flapper/not-finished"); vat.move(address(this), bids[id].guy, bids[id].lot); gem.burn(address(this), bids[id].bid); delete bids[id]; } function cage(uint rad) external auth { live = 0; vat.move(address(this), msg.sender, rad); } function yank(uint id) external { require(live == 0, "Flapper/still-live"); require(bids[id].guy != address(0), "Flapper/guy-not-set"); gem.move(address(this), bids[id].guy, bids[id].bid); delete bids[id]; } }
// SPDX-License-Identifier: AGPL-3.0-or-later /// spot.sol -- Spotter // 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.8.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). interface VatLike { function file(bytes32, bytes32, uint) external; } interface PipLike { function peek() external returns (bytes32, bool); } contract Spotter { // --- Auth --- mapping (address => uint) public wards; function rely(address guy) external auth { wards[guy] = 1; } function deny(address guy) external 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; VatLike public vat; // CDP Engine uint256 public par; // ref per USB [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 = VatLike(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 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 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 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 auth { live = 0; } }
// SPDX-License-Identifier: AGPL-3.0-or-later /// jug.sol -- USB Lending Rate // Copyright (C) 2018 Rain <[email protected]> // // 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.8.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). interface VatLike { function ilks(bytes32) external returns ( uint256 Art, // [wad] uint256 rate // [ray] ); function fold(bytes32,address,int) external; } contract Jug { // --- Auth --- mapping (address => uint) 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, "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; VatLike 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 = VatLike(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 auth { Ilk storage i = ilks[ilk]; require(i.duty == 0, "Jug/ilk-already-init"); i.duty = ONE; i.rho = block.timestamp; } function file(bytes32 ilk, bytes32 what, uint data) external auth { require(block.timestamp == 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 auth { if (what == "base") base = data; else revert("Jug/file-unrecognized-param"); } function file(bytes32 what, address data) external auth { if (what == "vow") vow = data; else revert("Jug/file-unrecognized-param"); } // --- Stability Fee Collection --- function drip(bytes32 ilk) external returns (uint rate) { require(block.timestamp >= ilks[ilk].rho, "Jug/invalid-now"); (, uint prev) = vat.ilks(ilk); rate = rmul(rpow(add(base, ilks[ilk].duty), block.timestamp - ilks[ilk].rho, ONE), prev); vat.fold(ilk, vow, diff(rate, prev)); ilks[ilk].rho = block.timestamp; } }
// SPDX-License-Identifier: AGPL-3.0-or-later /// vat.sol -- USB CDP database // Copyright (C) 2018 Rain <[email protected]> // // 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.8.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). contract Vat { // --- Auth --- mapping (address => uint) public wards; function rely(address usr) external auth { require(live == 1, "Vat/not-live"); wards[usr] = 1; } function deny(address usr) external 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 { 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 USB; // [rad] mapping (address => uint256) public sin; // [rad] uint256 public debt; // Total USB Issued [rad] uint256 public vice; // Total Unbacked USB [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 auth { require(ilks[ilk].rate == 0, "Vat/ilk-already-init"); ilks[ilk].rate = 10 ** 27; } function file(bytes32 what, uint data) external 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 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 auth { live = 0; } // --- Fungibility --- function slip(bytes32 ilk, address usr, int256 wad) external auth { gem[ilk][usr] = add(gem[ilk][usr], wad); } function flux(bytes32 ilk, address src, address dst, uint256 wad) external { 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 { require(wish(src, msg.sender), "Vat/not-allowed"); USB[src] = sub(USB[src], rad); USB[dst] = add(USB[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 { // 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); USB[w] = add(USB[w], dtab); urns[i][u] = urn; ilks[i] = ilk; } // --- CDP Fungibility --- function fork(bytes32 ilk, address src, address dst, int dink, int dart) external { 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 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 { address u = msg.sender; sin[u] = sub(sin[u], rad); USB[u] = sub(USB[u], rad); vice = sub(vice, rad); debt = sub(debt, rad); } function suck(address u, address v, uint rad) external auth { sin[u] = add(sin[u], rad); USB[v] = add(USB[v], rad); vice = add(vice, rad); debt = add(debt, rad); } // --- Rates --- function fold(bytes32 i, address u, int rate) external auth { require(live == 1, "Vat/not-live"); Ilk storage ilk = ilks[i]; ilk.rate = add(ilk.rate, rate); int rad = mul(ilk.Art, rate); USB[u] = add(USB[u], rad); debt = add(debt, rad); } }
// SPDX-License-Identifier: AGPL-3.0-or-later // Copyright (C) 2017, 2018, 2019 dbrock, rain, mrchico // 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.8.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). contract USB { // --- Auth --- mapping (address => uint) public wards; function rely(address guy) external auth { wards[guy] = 1; } function deny(address guy) external auth { wards[guy] = 0; } modifier auth { require(wards[msg.sender] == 1, "USB/not-authorized"); _; } // --- ERC20 Data --- string public constant name = "USB Stablecoin"; string public constant symbol = "USB"; 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, "USB/insufficient-balance"); if (src != msg.sender && allowance[src][msg.sender] != type(uint256).max) { require(allowance[src][msg.sender] >= wad, "USB/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, "USB/insufficient-balance"); if (usr != msg.sender && allowance[usr][msg.sender] != type(uint256).max) { require(allowance[usr][msg.sender] >= wad, "USB/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), "USB/invalid-address-0"); require(holder == ecrecover(digest, v, r, s), "USB/invalid-permit"); require(expiry == 0 || block.timestamp <= expiry, "USB/permit-expired"); require(nonce == nonces[holder]++, "USB/invalid-nonce"); uint wad = allowed ? type(uint256).max : 0; allowance[holder][spender] = wad; emit Approval(holder, spender, wad); } }
// SPDX-License-Identifier: AGPL-3.0-or-later /// DssProxyActions.sol // 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 GemLike { function approve(address, uint) external; function transfer(address, uint) external; function transferFrom(address, address, uint) external; function deposit() external payable; function withdraw(uint) external; } interface ManagerLike { function cdpCan(address, uint, address) external view returns (uint); function ilks(uint) external view returns (bytes32); function owns(uint) external view returns (address); function urns(uint) external view returns (address); function vat() external view returns (address); function open(bytes32, address) external returns (uint); function give(uint, address) external; function cdpAllow(uint, address, uint) external; function urnAllow(address, uint) external; function frob(uint, int, int) external; function flux(uint, address, uint) external; function move(uint, address, uint) external; function exit(address, uint, address, uint) external; function quit(uint, address) external; function enter(address, uint) external; function shift(uint, uint) external; } interface VatLike { function can(address, address) external view returns (uint); function ilks(bytes32) external view returns (uint, uint, uint, uint, uint); function USB(address) external view returns (uint); function urns(bytes32, address) external view returns (uint, uint); function frob(bytes32, address, address, address, int, int) external; function hope(address) external; function move(address, address, uint) external; } interface GemJoinLike { function dec() external returns (uint); function gem() external returns (GemLike); function join(address, uint) external payable; function exit(address, uint) external; } interface GNTJoinLike { function bags(address) external view returns (address); function make(address) external returns (address); } interface USBJoinLike { function vat() external returns (VatLike); function USB() external returns (GemLike); function join(address, uint) external payable; function exit(address, uint) external; } interface HopeLike { function hope(address) external; function nope(address) external; } interface EndLike { function fix(bytes32) external view returns (uint); function cash(bytes32, uint) external; function free(bytes32) external; function pack(uint) external; function skim(bytes32, address) external; } interface JugLike { function drip(bytes32) external returns (uint); } interface PotLike { function pie(address) external view returns (uint); function drip() external returns (uint); function join(uint) external; function exit(uint) external; } interface ProxyRegistryLike { function proxies(address) external view returns (address); function build(address) external returns (address); } interface ProxyLike { function owner() external view returns (address); } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // WARNING: These functions meant to be used as a a library for a DSProxy. Some are unsafe if you call them directly. // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! contract Common { uint256 constant RAY = 10 ** 27; // Internal functions function mul(uint x, uint y) internal pure returns (uint z) { require(y == 0 || (z = x * y) / y == x, "mul-overflow"); } // Public functions function USBJoin_join(address apt, address urn, uint wad) public { // Gets USB from the user's wallet USBJoinLike(apt).USB().transferFrom(msg.sender, address(this), wad); // Approves adapter to take the USB amount USBJoinLike(apt).USB().approve(apt, wad); // Joins USB into the vat USBJoinLike(apt).join(urn, wad); } } contract DssProxyActions is Common { // Internal functions function sub(uint x, uint y) internal pure returns (uint z) { require((z = x - y) <= x, "sub-overflow"); } function toInt(uint x) internal pure returns (int y) { y = int(x); require(y >= 0, "int-overflow"); } function toRad(uint wad) internal pure returns (uint rad) { rad = mul(wad, 10 ** 27); } function convertTo18(address gemJoin, uint256 amt) internal returns (uint256 wad) { // For those collaterals that have less than 18 decimals precision we need to do the conversion before passing to frob function // Adapters will automatically handle the difference of precision wad = mul( amt, 10 ** (18 - GemJoinLike(gemJoin).dec()) ); } function _getDrawDart( address vat, address jug, address urn, bytes32 ilk, uint wad ) internal returns (int dart) { // Updates stability fee rate uint rate = JugLike(jug).drip(ilk); // Gets USB balance of the urn in the vat uint USB = VatLike(vat).USB(urn); // If there was already enough USB in the vat balance, just exits it without adding more debt if (USB < mul(wad, RAY)) { // Calculates the needed dart so together with the existing USB in the vat is enough to exit wad amount of USB tokens dart = toInt(sub(mul(wad, RAY), USB) / rate); // This is neeeded due lack of precision. It might need to sum an extra dart wei (for the given USB wad amount) dart = mul(uint(dart), rate) < mul(wad, RAY) ? dart + 1 : dart; } } function _getWipeDart( address vat, uint USB, address urn, bytes32 ilk ) internal view returns (int dart) { // Gets actual rate from the vat (, uint rate,,,) = VatLike(vat).ilks(ilk); // Gets actual art value of the urn (, uint art) = VatLike(vat).urns(ilk, urn); // Uses the whole USB balance in the vat to reduce the debt dart = toInt(USB / rate); // Checks the calculated dart is not higher than urn.art (total debt), otherwise uses its value dart = uint(dart) <= art ? - dart : - toInt(art); } function _getWipeAllWad( address vat, address usr, address urn, bytes32 ilk ) internal view returns (uint wad) { // Gets actual rate from the vat (, uint rate,,,) = VatLike(vat).ilks(ilk); // Gets actual art value of the urn (, uint art) = VatLike(vat).urns(ilk, urn); // Gets actual USB amount in the urn uint USB = VatLike(vat).USB(usr); uint rad = sub(mul(art, rate), USB); wad = rad / RAY; // If the rad precision has some dust, it will need to request for 1 extra wad wei wad = mul(wad, RAY) < rad ? wad + 1 : wad; } // Public functions function transfer(address gem, address dst, uint amt) public { GemLike(gem).transfer(dst, amt); } function ethJoin_join(address apt, address urn) public payable { // Wraps ETH in WETH GemJoinLike(apt).gem().deposit{value:(msg.value)}(); // Approves adapter to take the WETH amount GemJoinLike(apt).gem().approve(address(apt), msg.value); // Joins WETH collateral into the vat GemJoinLike(apt).join(urn, msg.value); } function gemJoin_join(address apt, address urn, uint amt, bool transferFrom) public { // Only executes for tokens that have approval/transferFrom implementation if (transferFrom) { // Gets token from the user's wallet GemJoinLike(apt).gem().transferFrom(msg.sender, address(this), amt); // Approves adapter to take the token amount GemJoinLike(apt).gem().approve(apt, amt); } // Joins token collateral into the vat GemJoinLike(apt).join(urn, amt); } function hope( address obj, address usr ) public { HopeLike(obj).hope(usr); } function nope( address obj, address usr ) public { HopeLike(obj).nope(usr); } function open( address manager, bytes32 ilk, address usr ) public returns (uint cdp) { cdp = ManagerLike(manager).open(ilk, usr); } function give( address manager, uint cdp, address usr ) public { ManagerLike(manager).give(cdp, usr); } function giveToProxy( address proxyRegistry, address manager, uint cdp, address dst ) public { // Gets actual proxy address address proxy = ProxyRegistryLike(proxyRegistry).proxies(dst); // Checks if the proxy address already existed and dst address is still the owner if (proxy == address(0) || ProxyLike(proxy).owner() != dst) { uint csize; assembly { csize := extcodesize(dst) } // We want to avoid creating a proxy for a contract address that might not be able to handle proxies, then losing the CDP require(csize == 0, "Dst-is-a-contract"); // Creates the proxy for the dst address proxy = ProxyRegistryLike(proxyRegistry).build(dst); } // Transfers CDP to the dst proxy give(manager, cdp, proxy); } function cdpAllow( address manager, uint cdp, address usr, uint ok ) public { ManagerLike(manager).cdpAllow(cdp, usr, ok); } function urnAllow( address manager, address usr, uint ok ) public { ManagerLike(manager).urnAllow(usr, ok); } function flux( address manager, uint cdp, address dst, uint wad ) public { ManagerLike(manager).flux(cdp, dst, wad); } function move( address manager, uint cdp, address dst, uint rad ) public { ManagerLike(manager).move(cdp, dst, rad); } function frob( address manager, uint cdp, int dink, int dart ) public { ManagerLike(manager).frob(cdp, dink, dart); } function quit( address manager, uint cdp, address dst ) public { ManagerLike(manager).quit(cdp, dst); } function enter( address manager, address src, uint cdp ) public { ManagerLike(manager).enter(src, cdp); } function shift( address manager, uint cdpSrc, uint cdpOrg ) public { ManagerLike(manager).shift(cdpSrc, cdpOrg); } function makeGemBag( address gemJoin ) public returns (address bag) { bag = GNTJoinLike(gemJoin).make(address(this)); } function lockETH( address manager, address ethJoin, uint cdp ) public payable { // Receives ETH amount, converts it to WETH and joins it into the vat ethJoin_join(ethJoin, address(this)); // Locks WETH amount into the CDP VatLike(ManagerLike(manager).vat()).frob( ManagerLike(manager).ilks(cdp), ManagerLike(manager).urns(cdp), address(this), address(this), toInt(msg.value), 0 ); } function safeLockETH( address manager, address ethJoin, uint cdp, address owner ) public payable { require(ManagerLike(manager).owns(cdp) == owner, "owner-missmatch"); lockETH(manager, ethJoin, cdp); } function lockGem( address manager, address gemJoin, uint cdp, uint amt, bool transferFrom ) public { // Takes token amount from user's wallet and joins into the vat gemJoin_join(gemJoin, address(this), amt, transferFrom); // Locks token amount into the CDP VatLike(ManagerLike(manager).vat()).frob( ManagerLike(manager).ilks(cdp), ManagerLike(manager).urns(cdp), address(this), address(this), toInt(convertTo18(gemJoin, amt)), 0 ); } function safeLockGem( address manager, address gemJoin, uint cdp, uint amt, bool transferFrom, address owner ) public { require(ManagerLike(manager).owns(cdp) == owner, "owner-missmatch"); lockGem(manager, gemJoin, cdp, amt, transferFrom); } function freeETH( address manager, address ethJoin, uint cdp, uint wad ) public { // Unlocks WETH amount from the CDP frob(manager, cdp, -toInt(wad), 0); // Moves the amount from the CDP urn to proxy's address flux(manager, cdp, address(this), wad); // Exits WETH amount to proxy address as a token GemJoinLike(ethJoin).exit(address(this), wad); // Converts WETH to ETH GemJoinLike(ethJoin).gem().withdraw(wad); // Sends ETH back to the user's wallet payable(msg.sender).transfer(wad); } function freeGem( address manager, address gemJoin, uint cdp, uint amt ) public { uint wad = convertTo18(gemJoin, amt); // Unlocks token amount from the CDP frob(manager, cdp, -toInt(wad), 0); // Moves the amount from the CDP urn to proxy's address flux(manager, cdp, address(this), wad); // Exits token amount to the user's wallet as a token GemJoinLike(gemJoin).exit(msg.sender, amt); } function exitETH( address manager, address ethJoin, uint cdp, uint wad ) public { // Moves the amount from the CDP urn to proxy's address flux(manager, cdp, address(this), wad); // Exits WETH amount to proxy address as a token GemJoinLike(ethJoin).exit(address(this), wad); // Converts WETH to ETH GemJoinLike(ethJoin).gem().withdraw(wad); // Sends ETH back to the user's wallet payable(msg.sender).transfer(wad); } function exitGem( address manager, address gemJoin, uint cdp, uint amt ) public { // Moves the amount from the CDP urn to proxy's address flux(manager, cdp, address(this), convertTo18(gemJoin, amt)); // Exits token amount to the user's wallet as a token GemJoinLike(gemJoin).exit(msg.sender, amt); } function draw( address manager, address jug, address USBJoin, uint cdp, uint wad ) public { address urn = ManagerLike(manager).urns(cdp); address vat = ManagerLike(manager).vat(); bytes32 ilk = ManagerLike(manager).ilks(cdp); // Generates debt in the CDP frob(manager, cdp, 0, _getDrawDart(vat, jug, urn, ilk, wad)); // Moves the USB amount (balance in the vat in rad) to proxy's address move(manager, cdp, address(this), toRad(wad)); // Allows adapter to access to proxy's USB balance in the vat if (VatLike(vat).can(address(this), address(USBJoin)) == 0) { VatLike(vat).hope(USBJoin); } // Exits USB to the user's wallet as a token USBJoinLike(USBJoin).exit(msg.sender, wad); } function wipe( address manager, address USBJoin, uint cdp, uint wad ) public { address vat = ManagerLike(manager).vat(); address urn = ManagerLike(manager).urns(cdp); bytes32 ilk = ManagerLike(manager).ilks(cdp); address own = ManagerLike(manager).owns(cdp); if (own == address(this) || ManagerLike(manager).cdpCan(own, cdp, address(this)) == 1) { // Joins USB amount into the vat USBJoin_join(USBJoin, urn, wad); // Paybacks debt to the CDP frob(manager, cdp, 0, _getWipeDart(vat, VatLike(vat).USB(urn), urn, ilk)); } else { // Joins USB amount into the vat USBJoin_join(USBJoin, address(this), wad); // Paybacks debt to the CDP VatLike(vat).frob( ilk, urn, address(this), address(this), 0, _getWipeDart(vat, wad * RAY, urn, ilk) ); } } function safeWipe( address manager, address USBJoin, uint cdp, uint wad, address owner ) public { require(ManagerLike(manager).owns(cdp) == owner, "owner-missmatch"); wipe(manager, USBJoin, cdp, wad); } function wipeAll( address manager, address USBJoin, uint cdp ) public { address vat = ManagerLike(manager).vat(); address urn = ManagerLike(manager).urns(cdp); bytes32 ilk = ManagerLike(manager).ilks(cdp); (, uint art) = VatLike(vat).urns(ilk, urn); address own = ManagerLike(manager).owns(cdp); if (own == address(this) || ManagerLike(manager).cdpCan(own, cdp, address(this)) == 1) { // Joins USB amount into the vat USBJoin_join(USBJoin, urn, _getWipeAllWad(vat, urn, urn, ilk)); // Paybacks debt to the CDP frob(manager, cdp, 0, -int(art)); } else { // Joins USB amount into the vat USBJoin_join(USBJoin, address(this), _getWipeAllWad(vat, address(this), urn, ilk)); // Paybacks debt to the CDP VatLike(vat).frob( ilk, urn, address(this), address(this), 0, -int(art) ); } } function safeWipeAll( address manager, address USBJoin, uint cdp, address owner ) public { require(ManagerLike(manager).owns(cdp) == owner, "owner-missmatch"); wipeAll(manager, USBJoin, cdp); } function lockETHAndDraw( address manager, address jug, address ethJoin, address USBJoin, uint cdp, uint wadD ) public payable { address urn = ManagerLike(manager).urns(cdp); address vat = ManagerLike(manager).vat(); bytes32 ilk = ManagerLike(manager).ilks(cdp); // Receives ETH amount, converts it to WETH and joins it into the vat ethJoin_join(ethJoin, urn); // Locks WETH amount into the CDP and generates debt frob(manager, cdp, toInt(msg.value), _getDrawDart(vat, jug, urn, ilk, wadD)); // Moves the USB amount (balance in the vat in rad) to proxy's address move(manager, cdp, address(this), toRad(wadD)); // Allows adapter to access to proxy's USB balance in the vat if (VatLike(vat).can(address(this), address(USBJoin)) == 0) { VatLike(vat).hope(USBJoin); } // Exits USB to the user's wallet as a token USBJoinLike(USBJoin).exit(msg.sender, wadD); } function openLockETHAndDraw( address manager, address jug, address ethJoin, address USBJoin, bytes32 ilk, uint wadD ) public payable returns (uint cdp) { cdp = open(manager, ilk, address(this)); lockETHAndDraw(manager, jug, ethJoin, USBJoin, cdp, wadD); } function lockGemAndDraw( address manager, address jug, address gemJoin, address USBJoin, uint cdp, uint amtC, uint wadD, bool transferFrom ) public { address urn = ManagerLike(manager).urns(cdp); address vat = ManagerLike(manager).vat(); bytes32 ilk = ManagerLike(manager).ilks(cdp); // Takes token amount from user's wallet and joins into the vat gemJoin_join(gemJoin, urn, amtC, transferFrom); // Locks token amount into the CDP and generates debt frob(manager, cdp, toInt(convertTo18(gemJoin, amtC)), _getDrawDart(vat, jug, urn, ilk, wadD)); // Moves the USB amount (balance in the vat in rad) to proxy's address move(manager, cdp, address(this), toRad(wadD)); // Allows adapter to access to proxy's USB balance in the vat if (VatLike(vat).can(address(this), address(USBJoin)) == 0) { VatLike(vat).hope(USBJoin); } // Exits USB to the user's wallet as a token USBJoinLike(USBJoin).exit(msg.sender, wadD); } function openLockGemAndDraw( address manager, address jug, address gemJoin, address USBJoin, bytes32 ilk, uint amtC, uint wadD, bool transferFrom ) public returns (uint cdp) { cdp = open(manager, ilk, address(this)); lockGemAndDraw(manager, jug, gemJoin, USBJoin, cdp, amtC, wadD, transferFrom); } function openLockGNTAndDraw( address manager, address jug, address gntJoin, address USBJoin, bytes32 ilk, uint amtC, uint wadD ) public returns (address bag, uint cdp) { // Creates bag (if doesn't exist) to hold GNT bag = GNTJoinLike(gntJoin).bags(address(this)); if (bag == address(0)) { bag = makeGemBag(gntJoin); } // Transfer funds to the funds which previously were sent to the proxy GemLike(GemJoinLike(gntJoin).gem()).transfer(bag, amtC); cdp = openLockGemAndDraw(manager, jug, gntJoin, USBJoin, ilk, amtC, wadD, false); } function wipeAndFreeETH( address manager, address ethJoin, address USBJoin, uint cdp, uint wadC, uint wadD ) public { address urn = ManagerLike(manager).urns(cdp); // Joins USB amount into the vat USBJoin_join(USBJoin, urn, wadD); // Paybacks debt to the CDP and unlocks WETH amount from it frob( manager, cdp, -toInt(wadC), _getWipeDart(ManagerLike(manager).vat(), VatLike(ManagerLike(manager).vat()).USB(urn), urn, ManagerLike(manager).ilks(cdp)) ); // Moves the amount from the CDP urn to proxy's address flux(manager, cdp, address(this), wadC); // Exits WETH amount to proxy address as a token GemJoinLike(ethJoin).exit(address(this), wadC); // Converts WETH to ETH GemJoinLike(ethJoin).gem().withdraw(wadC); // Sends ETH back to the user's wallet payable(msg.sender).transfer(wadC); } function wipeAllAndFreeETH( address manager, address ethJoin, address USBJoin, uint cdp, uint wadC ) public { address vat = ManagerLike(manager).vat(); address urn = ManagerLike(manager).urns(cdp); bytes32 ilk = ManagerLike(manager).ilks(cdp); (, uint art) = VatLike(vat).urns(ilk, urn); // Joins USB amount into the vat USBJoin_join(USBJoin, urn, _getWipeAllWad(vat, urn, urn, ilk)); // Paybacks debt to the CDP and unlocks WETH amount from it frob( manager, cdp, -toInt(wadC), -int(art) ); // Moves the amount from the CDP urn to proxy's address flux(manager, cdp, address(this), wadC); // Exits WETH amount to proxy address as a token GemJoinLike(ethJoin).exit(address(this), wadC); // Converts WETH to ETH GemJoinLike(ethJoin).gem().withdraw(wadC); // Sends ETH back to the user's wallet payable(msg.sender).transfer(wadC); } function wipeAndFreeGem( address manager, address gemJoin, address USBJoin, uint cdp, uint amtC, uint wadD ) public { address urn = ManagerLike(manager).urns(cdp); // Joins USB amount into the vat USBJoin_join(USBJoin, urn, wadD); uint wadC = convertTo18(gemJoin, amtC); // Paybacks debt to the CDP and unlocks token amount from it frob( manager, cdp, -toInt(wadC), _getWipeDart(ManagerLike(manager).vat(), VatLike(ManagerLike(manager).vat()).USB(urn), urn, ManagerLike(manager).ilks(cdp)) ); // Moves the amount from the CDP urn to proxy's address flux(manager, cdp, address(this), wadC); // Exits token amount to the user's wallet as a token GemJoinLike(gemJoin).exit(msg.sender, amtC); } function wipeAllAndFreeGem( address manager, address gemJoin, address USBJoin, uint cdp, uint amtC ) public { address vat = ManagerLike(manager).vat(); address urn = ManagerLike(manager).urns(cdp); bytes32 ilk = ManagerLike(manager).ilks(cdp); (, uint art) = VatLike(vat).urns(ilk, urn); // Joins USB amount into the vat USBJoin_join(USBJoin, urn, _getWipeAllWad(vat, urn, urn, ilk)); uint wadC = convertTo18(gemJoin, amtC); // Paybacks debt to the CDP and unlocks token amount from it frob( manager, cdp, -toInt(wadC), -int(art) ); // Moves the amount from the CDP urn to proxy's address flux(manager, cdp, address(this), wadC); // Exits token amount to the user's wallet as a token GemJoinLike(gemJoin).exit(msg.sender, amtC); } } contract DssProxyActionsEnd is Common { // Internal functions function _free( address manager, address end, uint cdp ) internal returns (uint ink) { bytes32 ilk = ManagerLike(manager).ilks(cdp); address urn = ManagerLike(manager).urns(cdp); VatLike vat = VatLike(ManagerLike(manager).vat()); uint art; (ink, art) = vat.urns(ilk, urn); // If CDP still has debt, it needs to be paid if (art > 0) { EndLike(end).skim(ilk, urn); (ink,) = vat.urns(ilk, urn); } // Approves the manager to transfer the position to proxy's address in the vat if (vat.can(address(this), address(manager)) == 0) { vat.hope(manager); } // Transfers position from CDP to the proxy address ManagerLike(manager).quit(cdp, address(this)); // Frees the position and recovers the collateral in the vat registry EndLike(end).free(ilk); } // Public functions function freeETH( address manager, address ethJoin, address end, uint cdp ) public { uint wad = _free(manager, end, cdp); // Exits WETH amount to proxy address as a token GemJoinLike(ethJoin).exit(address(this), wad); // Converts WETH to ETH GemJoinLike(ethJoin).gem().withdraw(wad); // Sends ETH back to the user's wallet payable(msg.sender).transfer(wad); } function freeGem( address manager, address gemJoin, address end, uint cdp ) public { uint amt = _free(manager, end, cdp) / 10 ** (18 - GemJoinLike(gemJoin).dec()); // Exits token amount to the user's wallet as a token GemJoinLike(gemJoin).exit(msg.sender, amt); } function pack( address USBJoin, address end, uint wad ) public { USBJoin_join(USBJoin, address(this), wad); VatLike vat = USBJoinLike(USBJoin).vat(); // Approves the end to take out USB from the proxy's balance in the vat if (vat.can(address(this), address(end)) == 0) { vat.hope(end); } EndLike(end).pack(wad); } function cashETH( address ethJoin, address end, bytes32 ilk, uint wad ) public { EndLike(end).cash(ilk, wad); uint wadC = mul(wad, EndLike(end).fix(ilk)) / RAY; // Exits WETH amount to proxy address as a token GemJoinLike(ethJoin).exit(address(this), wadC); // Converts WETH to ETH GemJoinLike(ethJoin).gem().withdraw(wadC); // Sends ETH back to the user's wallet payable(msg.sender).transfer(wadC); } function cashGem( address gemJoin, address end, bytes32 ilk, uint wad ) public { EndLike(end).cash(ilk, wad); // Exits token amount to the user's wallet as a token uint amt = mul(wad, EndLike(end).fix(ilk)) / RAY / 10 ** (18 - GemJoinLike(gemJoin).dec()); GemJoinLike(gemJoin).exit(msg.sender, amt); } } contract DssProxyActionsDsr is Common { function join( address USBJoin, address pot, uint wad ) public { VatLike vat = USBJoinLike(USBJoin).vat(); // Executes drip to get the chi rate updated to rho == now, otherwise join will fail uint chi = PotLike(pot).drip(); // Joins wad amount to the vat balance USBJoin_join(USBJoin, address(this), wad); // Approves the pot to take out USB from the proxy's balance in the vat if (vat.can(address(this), address(pot)) == 0) { vat.hope(pot); } // Joins the pie value (equivalent to the USB wad amount) in the pot PotLike(pot).join(mul(wad, RAY) / chi); } function exit( address USBJoin, address pot, uint wad ) public { VatLike vat = USBJoinLike(USBJoin).vat(); // Executes drip to count the savings accumulated until this moment uint chi = PotLike(pot).drip(); // Calculates the pie value in the pot equivalent to the USB wad amount uint pie = mul(wad, RAY) / chi; // Exits USB from the pot PotLike(pot).exit(pie); // Checks the actual balance of USB in the vat after the pot exit uint bal = USBJoinLike(USBJoin).vat().USB(address(this)); // Allows adapter to access to proxy's USB balance in the vat if (vat.can(address(this), address(USBJoin)) == 0) { vat.hope(USBJoin); } // It is necessary to check if due rounding the exact wad amount can be exited by the adapter. // Otherwise it will do the maximum USB balance in the vat USBJoinLike(USBJoin).exit( msg.sender, bal >= mul(wad, RAY) ? wad : bal / RAY ); } function exitAll( address USBJoin, address pot ) public { VatLike vat = USBJoinLike(USBJoin).vat(); // Executes drip to count the savings accumulated until this moment uint chi = PotLike(pot).drip(); // Gets the total pie belonging to the proxy address uint pie = PotLike(pot).pie(address(this)); // Exits USB from the pot PotLike(pot).exit(pie); // Allows adapter to access to proxy's USB balance in the vat if (vat.can(address(this), address(USBJoin)) == 0) { vat.hope(USBJoin); } // Exits the USB amount corresponding to the value of pie USBJoinLike(USBJoin).exit(msg.sender, mul(chi, pie) / RAY); } }
// SPDX-License-Identifier: AGPL-3.0-or-later /// pot.sol -- USB Savings Rate // Copyright (C) 2018 Rain <[email protected]> // // 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.8.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). /* "Savings USB" is obtained when USB is deposited into this contract. Each "Savings USB" accrues USB interest at the "USB Savings Rate". This contract does not implement a user tradeable token and is intended to be used with adapters. --- `save` your `USB` in the `pot` --- - `dsr`: the USB Savings Rate - `pie`: user balance of Savings USB - `join`: start saving some USB - `exit`: remove some USB - `drip`: perform rate collection */ interface VatLike { function move(address,address,uint256) external; function suck(address,address,uint256) external; } contract Pot { // --- Auth --- mapping (address => uint) public wards; function rely(address guy) external auth { wards[guy] = 1; } function deny(address guy) external auth { wards[guy] = 0; } modifier auth { require(wards[msg.sender] == 1, "Pot/not-authorized"); _; } // --- Data --- mapping (address => uint256) public pie; // Normalised Savings USB [wad] uint256 public Pie; // Total Normalised Savings USB [wad] uint256 public dsr; // The USB Savings Rate [ray] uint256 public chi; // The Rate Accumulator [ray] VatLike 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 = VatLike(vat_); dsr = ONE; chi = ONE; rho = block.timestamp; 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 auth { require(live == 1, "Pot/not-live"); require(block.timestamp == rho, "Pot/rho-not-updated"); if (what == "dsr") dsr = data; else revert("Pot/file-unrecognized-param"); } function file(bytes32 what, address addr) external auth { if (what == "vow") vow = addr; else revert("Pot/file-unrecognized-param"); } function cage() external auth { live = 0; dsr = ONE; } // --- Savings Rate Accumulation --- function drip() external returns (uint tmp) { require(block.timestamp >= rho, "Pot/invalid-now"); tmp = rmul(rpow(dsr, block.timestamp - rho, ONE), chi); uint chi_ = sub(tmp, chi); chi = tmp; rho = block.timestamp; vat.suck(address(vow), address(this), mul(Pie, chi_)); } // --- Savings USB Management --- function join(uint wad) external { require(block.timestamp == 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 { pie[msg.sender] = sub(pie[msg.sender], wad); Pie = sub(Pie, wad); vat.move(address(this), msg.sender, mul(chi, wad)); } }
// SPDX-License-Identifier: AGPL-3.0-or-later /// dog.sol -- Dai liquidation module 2.0 // // 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.8.0; interface ClipperLike { function ilk() external view returns (bytes32); function kick( uint256 tab, uint256 lot, address usr, address kpr ) external returns (uint256); } interface VatLike { function ilks(bytes32) external view returns ( uint256 Art, // [wad] uint256 rate, // [ray] uint256 spot, // [ray] uint256 line, // [rad] uint256 dust // [rad] ); function urns(bytes32,address) external view returns ( uint256 ink, // [wad] uint256 art // [wad] ); function grab(bytes32,address,address,address,int256,int256) external; function hope(address) external; function nope(address) external; } interface VowLike { function fess(uint256) external; } 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] } VatLike immutable public vat; // CDP Engine mapping (bytes32 => Ilk) public ilks; VowLike 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 = VatLike(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 = VowLike(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 == ClipperLike(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 = ClipperLike(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(); } }
// SPDX-License-Identifier: AGPL-3.0-or-later /// DssCdpManager.sol // 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.8.0; interface VatLike { function urns(bytes32, address) external view returns (uint, uint); function hope(address) external; function flux(bytes32, address, address, uint) external; function move(address, address, uint) external; function frob(bytes32, address, address, address, int, int) external; function fork(bytes32, address, address, int, int) external; } contract UrnHandler { constructor(address vat) public { VatLike(vat).hope(msg.sender); } } contract DssCdpManager { address public vat; uint public cdpi; // Auto incremental mapping (uint => address) public urns; // CDPId => UrnHandler mapping (uint => List) public list; // CDPId => Prev & Next CDPIds (double linked list) mapping (uint => address) public owns; // CDPId => Owner mapping (uint => bytes32) public ilks; // CDPId => Ilk mapping (address => uint) public first; // Owner => First CDPId mapping (address => uint) public last; // Owner => Last CDPId mapping (address => uint) public count; // Owner => Amount of CDPs mapping ( address => mapping ( uint => mapping ( address => uint ) ) ) public cdpCan; // Owner => CDPId => Allowed Addr => True/False mapping ( address => mapping ( address => uint ) ) public urnCan; // Urn => Allowed Addr => True/False struct List { uint prev; uint next; } event NewCdp(address indexed usr, address indexed own, uint indexed cdp); modifier cdpAllowed( uint cdp ) { require(msg.sender == owns[cdp] || cdpCan[owns[cdp]][cdp][msg.sender] == 1, "cdp-not-allowed"); _; } modifier urnAllowed( address urn ) { require(msg.sender == urn || urnCan[urn][msg.sender] == 1, "urn-not-allowed"); _; } constructor(address vat_) public { vat = vat_; } 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 toInt(uint x) internal pure returns (int y) { y = int(x); require(y >= 0); } // Allow/disallow a usr address to manage the cdp. function cdpAllow( uint cdp, address usr, uint ok ) public cdpAllowed(cdp) { cdpCan[owns[cdp]][cdp][usr] = ok; } // Allow/disallow a usr address to quit to the the sender urn. function urnAllow( address usr, uint ok ) public { urnCan[msg.sender][usr] = ok; } // Open a new cdp for a given usr address. function open( bytes32 ilk, address usr ) public returns (uint) { require(usr != address(0), "usr-address-0"); cdpi = add(cdpi, 1); urns[cdpi] = address(new UrnHandler(vat)); owns[cdpi] = usr; ilks[cdpi] = ilk; // Add new CDP to double linked list and pointers if (first[usr] == 0) { first[usr] = cdpi; } if (last[usr] != 0) { list[cdpi].prev = last[usr]; list[last[usr]].next = cdpi; } last[usr] = cdpi; count[usr] = add(count[usr], 1); emit NewCdp(msg.sender, usr, cdpi); return cdpi; } // Give the cdp ownership to a dst address. function give( uint cdp, address dst ) public cdpAllowed(cdp) { require(dst != address(0), "dst-address-0"); require(dst != owns[cdp], "dst-already-owner"); // Remove transferred CDP from double linked list of origin user and pointers if (list[cdp].prev != 0) { list[list[cdp].prev].next = list[cdp].next; // Set the next pointer of the prev cdp (if exists) to the next of the transferred one } if (list[cdp].next != 0) { // If wasn't the last one list[list[cdp].next].prev = list[cdp].prev; // Set the prev pointer of the next cdp to the prev of the transferred one } else { // If was the last one last[owns[cdp]] = list[cdp].prev; // Update last pointer of the owner } if (first[owns[cdp]] == cdp) { // If was the first one first[owns[cdp]] = list[cdp].next; // Update first pointer of the owner } count[owns[cdp]] = sub(count[owns[cdp]], 1); // Transfer ownership owns[cdp] = dst; // Add transferred CDP to double linked list of destiny user and pointers list[cdp].prev = last[dst]; list[cdp].next = 0; if (last[dst] != 0) { list[last[dst]].next = cdp; } if (first[dst] == 0) { first[dst] = cdp; } last[dst] = cdp; count[dst] = add(count[dst], 1); } // Frob the cdp keeping the generated USB or collateral freed in the cdp urn address. function frob( uint cdp, int dink, int dart ) public cdpAllowed(cdp) { address urn = urns[cdp]; VatLike(vat).frob( ilks[cdp], urn, urn, urn, dink, dart ); } // Transfer wad amount of cdp collateral from the cdp address to a dst address. function flux( uint cdp, address dst, uint wad ) public cdpAllowed(cdp) { VatLike(vat).flux(ilks[cdp], urns[cdp], dst, wad); } // Transfer wad amount of any type of collateral (ilk) from the cdp address to a dst address. // This function has the purpose to take away collateral from the system that doesn't correspond to the cdp but was sent there wrongly. function flux( bytes32 ilk, uint cdp, address dst, uint wad ) public cdpAllowed(cdp) { VatLike(vat).flux(ilk, urns[cdp], dst, wad); } // Transfer wad amount of USB from the cdp address to a dst address. function move( uint cdp, address dst, uint rad ) public cdpAllowed(cdp) { VatLike(vat).move(urns[cdp], dst, rad); } // Quit the system, migrating the cdp (ink, art) to a different dst urn function quit( uint cdp, address dst ) public cdpAllowed(cdp) urnAllowed(dst) { (uint ink, uint art) = VatLike(vat).urns(ilks[cdp], urns[cdp]); VatLike(vat).fork( ilks[cdp], urns[cdp], dst, toInt(ink), toInt(art) ); } // Import a position from src urn to the urn owned by cdp function enter( address src, uint cdp ) public urnAllowed(src) cdpAllowed(cdp) { (uint ink, uint art) = VatLike(vat).urns(ilks[cdp], src); VatLike(vat).fork( ilks[cdp], src, urns[cdp], toInt(ink), toInt(art) ); } // Move a position from cdpSrc urn to the cdpDst urn function shift( uint cdpSrc, uint cdpDst ) public cdpAllowed(cdpSrc) cdpAllowed(cdpDst) { require(ilks[cdpSrc] == ilks[cdpDst], "non-matching-cdps"); (uint ink, uint art) = VatLike(vat).urns(ilks[cdpSrc], urns[cdpSrc]); VatLike(vat).fork( ilks[cdpSrc], urns[cdpSrc], urns[cdpDst], toInt(ink), toInt(art) ); } }
// SPDX-License-Identifier: AGPL-3.0-or-later // // 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.8.0; 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)); } }
{ "metadata": { "useLiteralContent": true }, "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"string","name":"symbol_","type":"string"}],"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":false,"inputs":[{"indexed":true,"internalType":"address","name":"guy","type":"address"},{"indexed":false,"internalType":"uint256","name":"wad","type":"uint256"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"authority","type":"address"}],"name":"LogSetAuthority","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"LogSetOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"guy","type":"address"},{"indexed":false,"internalType":"uint256","name":"wad","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[],"name":"Start","type":"event"},{"anonymous":false,"inputs":[],"name":"Stop","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":[{"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":"guy","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"guy","type":"address"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"authority","outputs":[{"internalType":"contract DSAuthority","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"guy","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"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"move","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"pull","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"push","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract DSAuthority","name":"authority_","type":"address"}],"name":"setAuthority","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name_","type":"string"}],"name":"setName","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"start","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stopped","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","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"}]
Contract Creation Code
6006805460ff1916601217905560a06040819052600060808190526200002891600791620000b4565b503480156200003657600080fd5b50604051620014ed380380620014ed833981016040819052620000599162000170565b600180546001600160a01b031916339081179091556040517fce241d7ca1f669fee44b6fc00b8eba2df3bb514eed0f6f668f8f89096e81ed9490600090a28051620000ac906005906020840190620000b4565b505062000289565b828054620000c2906200024c565b90600052602060002090601f016020900481019282620000e6576000855562000131565b82601f106200010157805160ff191683800117855562000131565b8280016001018555821562000131579182015b828111156200013157825182559160200191906001019062000114565b506200013f92915062000143565b5090565b5b808211156200013f576000815560010162000144565b634e487b7160e01b600052604160045260246000fd5b600060208083850312156200018457600080fd5b82516001600160401b03808211156200019c57600080fd5b818501915085601f830112620001b157600080fd5b815181811115620001c657620001c66200015a565b604051601f8201601f19908116603f01168101908382118183101715620001f157620001f16200015a565b8160405282815288868487010111156200020a57600080fd5b600093505b828410156200022e57848401860151818501870152928501926200020f565b82841115620002405760008684830101525b98975050505050505050565b600181811c908216806200026157607f821691505b602082108114156200028357634e487b7160e01b600052602260045260246000fd5b50919050565b61125480620002996000396000f3fe608060405234801561001057600080fd5b50600436106101735760003560e01c80638da5cb5b116100de578063bb35783b11610097578063c47f002711610071578063c47f002714610339578063daea85c51461034c578063dd62ed3e1461035f578063f2d5d56b1461038a57600080fd5b8063bb35783b1461030b578063be9a65551461031e578063bf7e214f1461032657600080fd5b80638da5cb5b1461028c57806395d89b41146102b75780639dc29fac146102bf578063a0712d68146102d2578063a9059cbb146102e5578063b753a98c146102f857600080fd5b8063313ce56711610130578063313ce5671461020057806340c10f191461021f57806342966c681461023257806370a082311461024557806375f12b21146102655780637a9e5e4b1461027957600080fd5b806306fdde031461017857806307da68f514610196578063095ea7b3146101a057806313af4035146101c357806318160ddd146101d657806323b872dd146101ed575b600080fd5b61018061039d565b60405161018d9190610f15565b60405180910390f35b61019e61042b565b005b6101b36101ae366004610f7f565b6104a4565b604051901515815260200161018d565b61019e6101d1366004610fab565b610536565b6101df60025481565b60405190815260200161018d565b6101b36101fb366004610fc8565b6105b2565b60065461020d9060ff1681565b60405160ff909116815260200161018d565b61019e61022d366004610f7f565b610808565b61019e610240366004611009565b6108f3565b6101df610253366004610fab565b60036020526000908152604090205481565b6001546101b390600160a01b900460ff1681565b61019e610287366004610fab565b610900565b60015461029f906001600160a01b031681565b6040516001600160a01b03909116815260200161018d565b61018061097a565b61019e6102cd366004610f7f565b610987565b61019e6102e0366004611009565b610bdb565b6101b36102f3366004610f7f565b610be5565b61019e610306366004610f7f565b610bf9565b61019e610319366004610fc8565b610c09565b61019e610c1a565b60005461029f906001600160a01b031681565b61019e610347366004611038565b610c84565b6101b361035a366004610fab565b610ccd565b6101df61036d3660046110e9565b600460209081526000928352604080842090915290825290205481565b61019e610398366004610f7f565b610cdb565b600780546103aa90611122565b80601f01602080910402602001604051908101604052809291908181526020018280546103d690611122565b80156104235780601f106103f857610100808354040283529160200191610423565b820191906000526020600020905b81548152906001019060200180831161040657829003601f168201915b505050505081565b610441336000356001600160e01b031916610ce6565b6104665760405162461bcd60e51b815260040161045d9061115d565b60405180910390fd5b6001805460ff60a01b1916600160a01b1790556040517fbedf0f4abfe86d4ffad593d9607fe70e83ea706033d44d24b3b6283cf3fc4f6b90600090a1565b600154600090600160a01b900460ff16156104d15760405162461bcd60e51b815260040161045d9061118b565b3360008181526004602090815260408083206001600160a01b03881680855290835292819020869055518581529192917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a35060015b92915050565b61054c336000356001600160e01b031916610ce6565b6105685760405162461bcd60e51b815260040161045d9061115d565b600180546001600160a01b0319166001600160a01b0383169081179091556040517fce241d7ca1f669fee44b6fc00b8eba2df3bb514eed0f6f668f8f89096e81ed9490600090a250565b600154600090600160a01b900460ff16156105df5760405162461bcd60e51b815260040161045d9061118b565b6001600160a01b038416331480159061061d57506001600160a01b038416600090815260046020908152604080832033845290915290205460001914155b156106e8576001600160a01b03841660009081526004602090815260408083203384529091529020548211156106955760405162461bcd60e51b815260206004820152601e60248201527f64732d746f6b656e2d696e73756666696369656e742d617070726f76616c0000604482015260640161045d565b6001600160a01b03841660009081526004602090815260408083203384529091529020546106c39083610dd1565b6001600160a01b03851660009081526004602090815260408083203384529091529020555b6001600160a01b0384166000908152600360205260409020548211156107505760405162461bcd60e51b815260206004820152601d60248201527f64732d746f6b656e2d696e73756666696369656e742d62616c616e6365000000604482015260640161045d565b6001600160a01b0384166000908152600360205260409020546107739083610dd1565b6001600160a01b0380861660009081526003602052604080822093909355908516815220546107a29083610e27565b6001600160a01b0380851660008181526003602052604090819020939093559151908616907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906107f69086815260200190565b60405180910390a35060019392505050565b61081e336000356001600160e01b031916610ce6565b61083a5760405162461bcd60e51b815260040161045d9061115d565b600154600160a01b900460ff16156108645760405162461bcd60e51b815260040161045d9061118b565b6001600160a01b0382166000908152600360205260409020546108879082610e27565b6001600160a01b0383166000908152600360205260409020556002546108ad9082610e27565b6002556040518181526001600160a01b038316907f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885906020015b60405180910390a25050565b6108fd3382610987565b50565b610916336000356001600160e01b031916610ce6565b6109325760405162461bcd60e51b815260040161045d9061115d565b600080546001600160a01b0319166001600160a01b038316908117825560405190917f1abebea81bfa2637f28358c371278fb15ede7ea8dd28d2e03b112ff6d936ada491a250565b600580546103aa90611122565b61099d336000356001600160e01b031916610ce6565b6109b95760405162461bcd60e51b815260040161045d9061115d565b600154600160a01b900460ff16156109e35760405162461bcd60e51b815260040161045d9061118b565b6001600160a01b0382163314801590610a2157506001600160a01b038216600090815260046020908152604080832033845290915290205460001914155b15610aec576001600160a01b0382166000908152600460209081526040808320338452909152902054811115610a995760405162461bcd60e51b815260206004820152601e60248201527f64732d746f6b656e2d696e73756666696369656e742d617070726f76616c0000604482015260640161045d565b6001600160a01b0382166000908152600460209081526040808320338452909152902054610ac79082610dd1565b6001600160a01b03831660009081526004602090815260408083203384529091529020555b6001600160a01b038216600090815260036020526040902054811115610b545760405162461bcd60e51b815260206004820152601d60248201527f64732d746f6b656e2d696e73756666696369656e742d62616c616e6365000000604482015260640161045d565b6001600160a01b038216600090815260036020526040902054610b779082610dd1565b6001600160a01b038316600090815260036020526040902055600254610b9d9082610dd1565b6002556040518181526001600160a01b038316907fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5906020016108e7565b6108fd3382610808565b6000610bf23384846105b2565b9392505050565b610c043383836105b2565b505050565b610c148383836105b2565b50505050565b610c30336000356001600160e01b031916610ce6565b610c4c5760405162461bcd60e51b815260040161045d9061115d565b6001805460ff60a01b191690556040517f1b55ba3aa851a46be3b365aee5b5c140edd620d578922f3e8466d2cbd96f954b90600090a1565b610c9a336000356001600160e01b031916610ce6565b610cb65760405162461bcd60e51b815260040161045d9061115d565b8051610cc9906007906020840190610e7c565b5050565b6000610530826000196104a4565b610c048233836105b2565b60006001600160a01b038316301415610d0157506001610530565b6001546001600160a01b0384811691161415610d1f57506001610530565b6000546001600160a01b0316610d3757506000610530565b60005460405163b700961360e01b81526001600160a01b0385811660048301523060248301526001600160e01b0319851660448301529091169063b70096139060640160206040518083038186803b158015610d9257600080fd5b505afa158015610da6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dca91906111b7565b9050610530565b600082610dde83826111ef565b91508111156105305760405162461bcd60e51b815260206004820152601560248201527464732d6d6174682d7375622d756e646572666c6f7760581b604482015260640161045d565b600082610e348382611206565b91508110156105305760405162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6164642d6f766572666c6f7760601b604482015260640161045d565b828054610e8890611122565b90600052602060002090601f016020900481019282610eaa5760008555610ef0565b82601f10610ec357805160ff1916838001178555610ef0565b82800160010185558215610ef0579182015b82811115610ef0578251825591602001919060010190610ed5565b50610efc929150610f00565b5090565b5b80821115610efc5760008155600101610f01565b600060208083528351808285015260005b81811015610f4257858101830151858201604001528201610f26565b81811115610f54576000604083870101525b50601f01601f1916929092016040019392505050565b6001600160a01b03811681146108fd57600080fd5b60008060408385031215610f9257600080fd5b8235610f9d81610f6a565b946020939093013593505050565b600060208284031215610fbd57600080fd5b8135610bf281610f6a565b600080600060608486031215610fdd57600080fd5b8335610fe881610f6a565b92506020840135610ff881610f6a565b929592945050506040919091013590565b60006020828403121561101b57600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b60006020828403121561104a57600080fd5b813567ffffffffffffffff8082111561106257600080fd5b818401915084601f83011261107657600080fd5b81358181111561108857611088611022565b604051601f8201601f19908116603f011681019083821181831017156110b0576110b0611022565b816040528281528760208487010111156110c957600080fd5b826020860160208301376000928101602001929092525095945050505050565b600080604083850312156110fc57600080fd5b823561110781610f6a565b9150602083013561111781610f6a565b809150509250929050565b600181811c9082168061113657607f821691505b6020821081141561115757634e487b7160e01b600052602260045260246000fd5b50919050565b602080825260149082015273191ccb585d5d1a0b5d5b985d5d1a1bdc9a5e995960621b604082015260600190565b602080825260129082015271191ccb5cdd1bdc0b5a5ccb5cdd1bdc1c195960721b604082015260600190565b6000602082840312156111c957600080fd5b81518015158114610bf257600080fd5b634e487b7160e01b600052601160045260246000fd5b600082821015611201576112016111d9565b500390565b60008219821115611219576112196111d9565b50019056fea2646970667358221220780540f0938d325d7cbb843f51227fdc319aa11340808828c0a3396b00e830fb64736f6c63430008090033000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000044652494e00000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101735760003560e01c80638da5cb5b116100de578063bb35783b11610097578063c47f002711610071578063c47f002714610339578063daea85c51461034c578063dd62ed3e1461035f578063f2d5d56b1461038a57600080fd5b8063bb35783b1461030b578063be9a65551461031e578063bf7e214f1461032657600080fd5b80638da5cb5b1461028c57806395d89b41146102b75780639dc29fac146102bf578063a0712d68146102d2578063a9059cbb146102e5578063b753a98c146102f857600080fd5b8063313ce56711610130578063313ce5671461020057806340c10f191461021f57806342966c681461023257806370a082311461024557806375f12b21146102655780637a9e5e4b1461027957600080fd5b806306fdde031461017857806307da68f514610196578063095ea7b3146101a057806313af4035146101c357806318160ddd146101d657806323b872dd146101ed575b600080fd5b61018061039d565b60405161018d9190610f15565b60405180910390f35b61019e61042b565b005b6101b36101ae366004610f7f565b6104a4565b604051901515815260200161018d565b61019e6101d1366004610fab565b610536565b6101df60025481565b60405190815260200161018d565b6101b36101fb366004610fc8565b6105b2565b60065461020d9060ff1681565b60405160ff909116815260200161018d565b61019e61022d366004610f7f565b610808565b61019e610240366004611009565b6108f3565b6101df610253366004610fab565b60036020526000908152604090205481565b6001546101b390600160a01b900460ff1681565b61019e610287366004610fab565b610900565b60015461029f906001600160a01b031681565b6040516001600160a01b03909116815260200161018d565b61018061097a565b61019e6102cd366004610f7f565b610987565b61019e6102e0366004611009565b610bdb565b6101b36102f3366004610f7f565b610be5565b61019e610306366004610f7f565b610bf9565b61019e610319366004610fc8565b610c09565b61019e610c1a565b60005461029f906001600160a01b031681565b61019e610347366004611038565b610c84565b6101b361035a366004610fab565b610ccd565b6101df61036d3660046110e9565b600460209081526000928352604080842090915290825290205481565b61019e610398366004610f7f565b610cdb565b600780546103aa90611122565b80601f01602080910402602001604051908101604052809291908181526020018280546103d690611122565b80156104235780601f106103f857610100808354040283529160200191610423565b820191906000526020600020905b81548152906001019060200180831161040657829003601f168201915b505050505081565b610441336000356001600160e01b031916610ce6565b6104665760405162461bcd60e51b815260040161045d9061115d565b60405180910390fd5b6001805460ff60a01b1916600160a01b1790556040517fbedf0f4abfe86d4ffad593d9607fe70e83ea706033d44d24b3b6283cf3fc4f6b90600090a1565b600154600090600160a01b900460ff16156104d15760405162461bcd60e51b815260040161045d9061118b565b3360008181526004602090815260408083206001600160a01b03881680855290835292819020869055518581529192917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a35060015b92915050565b61054c336000356001600160e01b031916610ce6565b6105685760405162461bcd60e51b815260040161045d9061115d565b600180546001600160a01b0319166001600160a01b0383169081179091556040517fce241d7ca1f669fee44b6fc00b8eba2df3bb514eed0f6f668f8f89096e81ed9490600090a250565b600154600090600160a01b900460ff16156105df5760405162461bcd60e51b815260040161045d9061118b565b6001600160a01b038416331480159061061d57506001600160a01b038416600090815260046020908152604080832033845290915290205460001914155b156106e8576001600160a01b03841660009081526004602090815260408083203384529091529020548211156106955760405162461bcd60e51b815260206004820152601e60248201527f64732d746f6b656e2d696e73756666696369656e742d617070726f76616c0000604482015260640161045d565b6001600160a01b03841660009081526004602090815260408083203384529091529020546106c39083610dd1565b6001600160a01b03851660009081526004602090815260408083203384529091529020555b6001600160a01b0384166000908152600360205260409020548211156107505760405162461bcd60e51b815260206004820152601d60248201527f64732d746f6b656e2d696e73756666696369656e742d62616c616e6365000000604482015260640161045d565b6001600160a01b0384166000908152600360205260409020546107739083610dd1565b6001600160a01b0380861660009081526003602052604080822093909355908516815220546107a29083610e27565b6001600160a01b0380851660008181526003602052604090819020939093559151908616907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906107f69086815260200190565b60405180910390a35060019392505050565b61081e336000356001600160e01b031916610ce6565b61083a5760405162461bcd60e51b815260040161045d9061115d565b600154600160a01b900460ff16156108645760405162461bcd60e51b815260040161045d9061118b565b6001600160a01b0382166000908152600360205260409020546108879082610e27565b6001600160a01b0383166000908152600360205260409020556002546108ad9082610e27565b6002556040518181526001600160a01b038316907f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885906020015b60405180910390a25050565b6108fd3382610987565b50565b610916336000356001600160e01b031916610ce6565b6109325760405162461bcd60e51b815260040161045d9061115d565b600080546001600160a01b0319166001600160a01b038316908117825560405190917f1abebea81bfa2637f28358c371278fb15ede7ea8dd28d2e03b112ff6d936ada491a250565b600580546103aa90611122565b61099d336000356001600160e01b031916610ce6565b6109b95760405162461bcd60e51b815260040161045d9061115d565b600154600160a01b900460ff16156109e35760405162461bcd60e51b815260040161045d9061118b565b6001600160a01b0382163314801590610a2157506001600160a01b038216600090815260046020908152604080832033845290915290205460001914155b15610aec576001600160a01b0382166000908152600460209081526040808320338452909152902054811115610a995760405162461bcd60e51b815260206004820152601e60248201527f64732d746f6b656e2d696e73756666696369656e742d617070726f76616c0000604482015260640161045d565b6001600160a01b0382166000908152600460209081526040808320338452909152902054610ac79082610dd1565b6001600160a01b03831660009081526004602090815260408083203384529091529020555b6001600160a01b038216600090815260036020526040902054811115610b545760405162461bcd60e51b815260206004820152601d60248201527f64732d746f6b656e2d696e73756666696369656e742d62616c616e6365000000604482015260640161045d565b6001600160a01b038216600090815260036020526040902054610b779082610dd1565b6001600160a01b038316600090815260036020526040902055600254610b9d9082610dd1565b6002556040518181526001600160a01b038316907fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5906020016108e7565b6108fd3382610808565b6000610bf23384846105b2565b9392505050565b610c043383836105b2565b505050565b610c148383836105b2565b50505050565b610c30336000356001600160e01b031916610ce6565b610c4c5760405162461bcd60e51b815260040161045d9061115d565b6001805460ff60a01b191690556040517f1b55ba3aa851a46be3b365aee5b5c140edd620d578922f3e8466d2cbd96f954b90600090a1565b610c9a336000356001600160e01b031916610ce6565b610cb65760405162461bcd60e51b815260040161045d9061115d565b8051610cc9906007906020840190610e7c565b5050565b6000610530826000196104a4565b610c048233836105b2565b60006001600160a01b038316301415610d0157506001610530565b6001546001600160a01b0384811691161415610d1f57506001610530565b6000546001600160a01b0316610d3757506000610530565b60005460405163b700961360e01b81526001600160a01b0385811660048301523060248301526001600160e01b0319851660448301529091169063b70096139060640160206040518083038186803b158015610d9257600080fd5b505afa158015610da6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dca91906111b7565b9050610530565b600082610dde83826111ef565b91508111156105305760405162461bcd60e51b815260206004820152601560248201527464732d6d6174682d7375622d756e646572666c6f7760581b604482015260640161045d565b600082610e348382611206565b91508110156105305760405162461bcd60e51b815260206004820152601460248201527364732d6d6174682d6164642d6f766572666c6f7760601b604482015260640161045d565b828054610e8890611122565b90600052602060002090601f016020900481019282610eaa5760008555610ef0565b82601f10610ec357805160ff1916838001178555610ef0565b82800160010185558215610ef0579182015b82811115610ef0578251825591602001919060010190610ed5565b50610efc929150610f00565b5090565b5b80821115610efc5760008155600101610f01565b600060208083528351808285015260005b81811015610f4257858101830151858201604001528201610f26565b81811115610f54576000604083870101525b50601f01601f1916929092016040019392505050565b6001600160a01b03811681146108fd57600080fd5b60008060408385031215610f9257600080fd5b8235610f9d81610f6a565b946020939093013593505050565b600060208284031215610fbd57600080fd5b8135610bf281610f6a565b600080600060608486031215610fdd57600080fd5b8335610fe881610f6a565b92506020840135610ff881610f6a565b929592945050506040919091013590565b60006020828403121561101b57600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b60006020828403121561104a57600080fd5b813567ffffffffffffffff8082111561106257600080fd5b818401915084601f83011261107657600080fd5b81358181111561108857611088611022565b604051601f8201601f19908116603f011681019083821181831017156110b0576110b0611022565b816040528281528760208487010111156110c957600080fd5b826020860160208301376000928101602001929092525095945050505050565b600080604083850312156110fc57600080fd5b823561110781610f6a565b9150602083013561111781610f6a565b809150509250929050565b600181811c9082168061113657607f821691505b6020821081141561115757634e487b7160e01b600052602260045260246000fd5b50919050565b602080825260149082015273191ccb585d5d1a0b5d5b985d5d1a1bdc9a5e995960621b604082015260600190565b602080825260129082015271191ccb5cdd1bdc0b5a5ccb5cdd1bdc1c195960721b604082015260600190565b6000602082840312156111c957600080fd5b81518015158114610bf257600080fd5b634e487b7160e01b600052601160045260246000fd5b600082821015611201576112016111d9565b500390565b60008219821115611219576112196111d9565b50019056fea2646970667358221220780540f0938d325d7cbb843f51227fdc319aa11340808828c0a3396b00e830fb64736f6c63430008090033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000044652494e00000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : symbol_ (string): FRIN
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000020
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000004
Arg [2] : 4652494e00000000000000000000000000000000000000000000000000000000
Deployed Bytecode Sourcemap
4444:3610:13:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4975:67;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;7797:80;;;:::i;:::-;;5641:189;;;;;;:::i;:::-;;:::i;:::-;;;1237:14:20;;1230:22;1212:41;;1200:2;1185:18;5641:189:13;1072:187:20;1298:130:13;;;;;;:::i;:::-;;:::i;4556:69::-;;;;;;;;;1662:25:20;;;1650:2;1635:18;4556:69:13;1516:177:20;5965:625:13;;;;;;:::i;:::-;;:::i;4847:71::-;;;;;;;;;;;;2331:4:20;2319:17;;;2301:36;;2289:2;2274:18;4847:71:13;2159:184:20;7066:191:13;;;;;;:::i;:::-;;:::i;6989:71::-;;;;;;:::i;:::-;;:::i;4631:67::-;;;;;;:::i;:::-;;;;;;;;;;;;;;4485:65;;;;;-1:-1:-1;;;4485:65:13;;;;;;1434:167;;;;;;:::i;:::-;;:::i;1165:26::-;;;;;-1:-1:-1;;;;;1165:26:13;;;;;;-1:-1:-1;;;;;2970:32:20;;;2952:51;;2940:2;2925:18;1165:26:13;2806:203:20;4777:64:13;;;:::i;7263:528::-;;;;;;:::i;:::-;;:::i;6912:71::-;;;;;;:::i;:::-;;:::i;5836:123::-;;;;;;:::i;:::-;;:::i;6596:97::-;;;;;;:::i;:::-;;:::i;6802:103::-;;;;;;:::i;:::-;;:::i;7883:83::-;;;:::i;1129:30::-;;;;;-1:-1:-1;;;;;1129:30:13;;;7973:79;;;;;;:::i;:::-;;:::i;5526:109::-;;;;;;:::i;:::-;;:::i;4704:67::-;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;6699:97;;;;;;:::i;:::-;;:::i;4975:67::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;7797:80::-;1639:33;1652:10;1664:7;;-1:-1:-1;;;;;;1664:7:13;1639:12;:33::i;:::-;1631:66;;;;-1:-1:-1;;;1631:66:13;;;;;;;:::i;:::-;;;;;;;;;7845:4:::1;7835:14:::0;;-1:-1:-1;;;;7835:14:13::1;-1:-1:-1::0;;;7835:14:13::1;::::0;;7864:6:::1;::::0;::::1;::::0;7835:14;;7864:6:::1;7797:80::o:0;5641:189::-;5472:7;;5707:4;;-1:-1:-1;;;5472:7:13;;;;5471:8;5463:39;;;;-1:-1:-1;;;5463:39:13;;;;;;;:::i;:::-;5733:10:::1;5723:21;::::0;;;:9:::1;:21;::::0;;;;;;;-1:-1:-1;;;;;5723:26:13;::::1;::::0;;;;;;;;;;:32;;;5771:30;1662:25:20;;;5723:26:13;;5733:10;5771:30:::1;::::0;1635:18:20;5771:30:13::1;;;;;;;-1:-1:-1::0;5819:4:13::1;5512:1;5641:189:::0;;;;:::o;1298:130::-;1639:33;1652:10;1664:7;;-1:-1:-1;;;;;;1664:7:13;1639:12;:33::i;:::-;1631:66;;;;-1:-1:-1;;;1631:66:13;;;;;;;:::i;:::-;1374:5:::1;:14:::0;;-1:-1:-1;;;;;;1374:14:13::1;-1:-1:-1::0;;;;;1374:14:13;::::1;::::0;;::::1;::::0;;;1403:18:::1;::::0;::::1;::::0;-1:-1:-1;;1403:18:13::1;1298:130:::0;:::o;5965:625::-;5472:7;;6073:4;;-1:-1:-1;;;5472:7:13;;;;5471:8;5463:39;;;;-1:-1:-1;;;5463:39:13;;;;;;;:::i;:::-;-1:-1:-1;;;;;6097:17:13;::::1;6104:10;6097:17;::::0;::::1;::::0;:68:::1;;-1:-1:-1::0;;;;;;6118:14:13;::::1;;::::0;;;:9:::1;:14;::::0;;;;;;;6133:10:::1;6118:26:::0;;;;;;;;-1:-1:-1;;6118:47:13::1;;6097:68;6093:254;;;-1:-1:-1::0;;;;;6189:14:13;::::1;;::::0;;;:9:::1;:14;::::0;;;;;;;6204:10:::1;6189:26:::0;;;;;;;;:33;-1:-1:-1;6189:33:13::1;6181:76;;;::::0;-1:-1:-1;;;6181:76:13;;5978:2:20;6181:76:13::1;::::0;::::1;5960:21:20::0;6017:2;5997:18;;;5990:30;6056:32;6036:18;;;6029:60;6106:18;;6181:76:13::1;5776:354:20::0;6181:76:13::1;-1:-1:-1::0;;;;;6304:14:13;::::1;;::::0;;;:9:::1;:14;::::0;;;;;;;6319:10:::1;6304:26:::0;;;;;;;;6300:36:::1;::::0;6332:3;6300::::1;:36::i;:::-;-1:-1:-1::0;;;;;6271:14:13;::::1;;::::0;;;:9:::1;:14;::::0;;;;;;;6286:10:::1;6271:26:::0;;;;;;;:65;6093:254:::1;-1:-1:-1::0;;;;;6365:14:13;::::1;;::::0;;;:9:::1;:14;::::0;;;;;:21;-1:-1:-1;6365:21:13::1;6357:63;;;::::0;-1:-1:-1;;;6357:63:13;;6337:2:20;6357:63:13::1;::::0;::::1;6319:21:20::0;6376:2;6356:18;;;6349:30;6415:31;6395:18;;;6388:59;6464:18;;6357:63:13::1;6135:353:20::0;6357:63:13::1;-1:-1:-1::0;;;;;6451:14:13;::::1;;::::0;;;:9:::1;:14;::::0;;;;;6447:24:::1;::::0;6467:3;6447::::1;:24::i;:::-;-1:-1:-1::0;;;;;6430:14:13;;::::1;;::::0;;;:9:::1;:14;::::0;;;;;:41;;;;6502:14;;::::1;::::0;;;;6498:24:::1;::::0;6518:3;6498::::1;:24::i;:::-;-1:-1:-1::0;;;;;6481:14:13;;::::1;;::::0;;;:9:::1;:14;::::0;;;;;;:41;;;;6538:23;;;;::::1;::::0;::::1;::::0;::::1;::::0;6557:3;1662:25:20;;1650:2;1635:18;;1516:177;6538:23:13::1;;;;;;;;-1:-1:-1::0;6579:4:13::1;5965:625:::0;;;;;:::o;7066:191::-;1639:33;1652:10;1664:7;;-1:-1:-1;;;;;;1664:7:13;1639:12;:33::i;:::-;1631:66;;;;-1:-1:-1;;;1631:66:13;;;;;;;:::i;:::-;5472:7:::1;::::0;-1:-1:-1;;;5472:7:13;::::1;;;5471:8;5463:39;;;;-1:-1:-1::0;;;5463:39:13::1;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;7156:14:13;::::2;;::::0;;;:9:::2;:14;::::0;;;;;7152:24:::2;::::0;7172:3;7152::::2;:24::i;:::-;-1:-1:-1::0;;;;;7135:14:13;::::2;;::::0;;;:9:::2;:14;::::0;;;;:41;7204:11:::2;::::0;7200:21:::2;::::0;7217:3;7200::::2;:21::i;:::-;7186:11;:35:::0;7236:14:::2;::::0;1662:25:20;;;-1:-1:-1;;;;;7236:14:13;::::2;::::0;::::2;::::0;1650:2:20;1635:18;7236:14:13::2;;;;;;;;7066:191:::0;;:::o;6989:71::-;7032:21;7037:10;7049:3;7032:4;:21::i;:::-;6989:71;:::o;1434:167::-;1639:33;1652:10;1664:7;;-1:-1:-1;;;;;;1664:7:13;1639:12;:33::i;:::-;1631:66;;;;-1:-1:-1;;;1631:66:13;;;;;;;:::i;:::-;1522:9:::1;:22:::0;;-1:-1:-1;;;;;;1522:22:13::1;-1:-1:-1::0;;;;;1522:22:13;::::1;::::0;;::::1;::::0;;1559:35:::1;::::0;1522:22;;1559:35:::1;::::0;::::1;1434:167:::0;:::o;4777:64::-;;;;;;;:::i;7263:528::-;1639:33;1652:10;1664:7;;-1:-1:-1;;;;;;1664:7:13;1639:12;:33::i;:::-;1631:66;;;;-1:-1:-1;;;1631:66:13;;;;;;;:::i;:::-;5472:7:::1;::::0;-1:-1:-1;;;5472:7:13;::::1;;;5471:8;5463:39;;;;-1:-1:-1::0;;;5463:39:13::1;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;7336:17:13;::::2;7343:10;7336:17;::::0;::::2;::::0;:68:::2;;-1:-1:-1::0;;;;;;7357:14:13;::::2;;::::0;;;:9:::2;:14;::::0;;;;;;;7372:10:::2;7357:26:::0;;;;;;;;-1:-1:-1;;7357:47:13::2;;7336:68;7332:254;;;-1:-1:-1::0;;;;;7428:14:13;::::2;;::::0;;;:9:::2;:14;::::0;;;;;;;7443:10:::2;7428:26:::0;;;;;;;;:33;-1:-1:-1;7428:33:13::2;7420:76;;;::::0;-1:-1:-1;;;7420:76:13;;5978:2:20;7420:76:13::2;::::0;::::2;5960:21:20::0;6017:2;5997:18;;;5990:30;6056:32;6036:18;;;6029:60;6106:18;;7420:76:13::2;5776:354:20::0;7420:76:13::2;-1:-1:-1::0;;;;;7543:14:13;::::2;;::::0;;;:9:::2;:14;::::0;;;;;;;7558:10:::2;7543:26:::0;;;;;;;;7539:36:::2;::::0;7571:3;7539::::2;:36::i;:::-;-1:-1:-1::0;;;;;7510:14:13;::::2;;::::0;;;:9:::2;:14;::::0;;;;;;;7525:10:::2;7510:26:::0;;;;;;;:65;7332:254:::2;-1:-1:-1::0;;;;;7604:14:13;::::2;;::::0;;;:9:::2;:14;::::0;;;;;:21;-1:-1:-1;7604:21:13::2;7596:63;;;::::0;-1:-1:-1;;;7596:63:13;;6337:2:20;7596:63:13::2;::::0;::::2;6319:21:20::0;6376:2;6356:18;;;6349:30;6415:31;6395:18;;;6388:59;6464:18;;7596:63:13::2;6135:353:20::0;7596:63:13::2;-1:-1:-1::0;;;;;7690:14:13;::::2;;::::0;;;:9:::2;:14;::::0;;;;;7686:24:::2;::::0;7706:3;7686::::2;:24::i;:::-;-1:-1:-1::0;;;;;7669:14:13;::::2;;::::0;;;:9:::2;:14;::::0;;;;:41;7738:11:::2;::::0;7734:21:::2;::::0;7751:3;7734::::2;:21::i;:::-;7720:11;:35:::0;7770:14:::2;::::0;1662:25:20;;;-1:-1:-1;;;;;7770:14:13;::::2;::::0;::::2;::::0;1650:2:20;1635:18;7770:14:13::2;1516:177:20::0;6912:71:13;6955:21;6960:10;6972:3;6955:4;:21::i;5836:123::-;5895:4;5918:34;5931:10;5943:3;5948;5918:12;:34::i;:::-;5911:41;5836:123;-1:-1:-1;;;5836:123:13:o;6596:97::-;6652:34;6665:10;6677:3;6682;6652:12;:34::i;:::-;;6596:97;;:::o;6802:103::-;6871:27;6884:3;6889;6894;6871:12;:27::i;:::-;;6802:103;;;:::o;7883:83::-;1639:33;1652:10;1664:7;;-1:-1:-1;;;;;;1664:7:13;1639:12;:33::i;:::-;1631:66;;;;-1:-1:-1;;;1631:66:13;;;;;;;:::i;:::-;7922:7:::1;:15:::0;;-1:-1:-1;;;;7922:15:13::1;::::0;;7952:7:::1;::::0;::::1;::::0;7932:5:::1;::::0;7952:7:::1;7883:83::o:0;7973:79::-;1639:33;1652:10;1664:7;;-1:-1:-1;;;;;;1664:7:13;1639:12;:33::i;:::-;1631:66;;;;-1:-1:-1;;;1631:66:13;;;;;;;:::i;:::-;8033:12;;::::1;::::0;:4:::1;::::0;:12:::1;::::0;::::1;::::0;::::1;:::i;:::-;;7973:79:::0;:::o;5526:109::-;5574:4;5597:31;5605:3;-1:-1:-1;;5597:7:13;:31::i;6699:97::-;6755:34;6768:3;6773:10;6785:3;6755:12;:34::i;1721:379::-;1791:4;-1:-1:-1;;;;;1811:20:13;;1826:4;1811:20;1807:287;;;-1:-1:-1;1854:4:13;1847:11;;1807:287;1886:5;;-1:-1:-1;;;;;1879:12:13;;;1886:5;;1879:12;1875:219;;;-1:-1:-1;1914:4:13;1907:11;;1875:219;1972:1;1939:9;-1:-1:-1;;;;;1939:9:13;1935:159;;-1:-1:-1;1998:5:13;1991:12;;1935:159;2041:9;;:42;;-1:-1:-1;;;2041:42:13;;-1:-1:-1;;;;;6749:15:20;;;2041:42:13;;;6731:34:20;2072:4:13;6781:18:20;;;6774:43;-1:-1:-1;;;;;;6853:33:20;;6833:18;;;6826:61;2041:9:13;;;;:17;;6666:18:20;;2041:42:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;2034:49;;;;2257:127;2309:6;2350:1;2340:5;2344:1;2350;2340:5;:::i;:::-;2336:9;;;2335:16;;2327:50;;;;-1:-1:-1;;;2327:50:13;;7644:2:20;2327:50:13;;;7626:21:20;7683:2;7663:18;;;7656:30;-1:-1:-1;;;7702:18:20;;;7695:51;7763:18;;2327:50:13;7442:345:20;2126:126:13;2178:6;2219:1;2209:5;2213:1;2219;2209:5;:::i;:::-;2205:9;;;2204:16;;2196:49;;;;-1:-1:-1;;;2196:49:13;;8127:2:20;2196:49:13;;;8109:21:20;8166:2;8146:18;;;8139:30;-1:-1:-1;;;8185:18:20;;;8178:50;8245:18;;2196:49:13;7925:344:20;-1:-1:-1;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;14:597:20;126:4;155:2;184;173:9;166:21;216:6;210:13;259:6;254:2;243:9;239:18;232:34;284:1;294:140;308:6;305:1;302:13;294:140;;;403:14;;;399:23;;393:30;369:17;;;388:2;365:26;358:66;323:10;;294:140;;;452:6;449:1;446:13;443:91;;;522:1;517:2;508:6;497:9;493:22;489:31;482:42;443:91;-1:-1:-1;595:2:20;574:15;-1:-1:-1;;570:29:20;555:45;;;;602:2;551:54;;14:597;-1:-1:-1;;;14:597:20:o;616:131::-;-1:-1:-1;;;;;691:31:20;;681:42;;671:70;;737:1;734;727:12;752:315;820:6;828;881:2;869:9;860:7;856:23;852:32;849:52;;;897:1;894;887:12;849:52;936:9;923:23;955:31;980:5;955:31;:::i;:::-;1005:5;1057:2;1042:18;;;;1029:32;;-1:-1:-1;;;752:315:20:o;1264:247::-;1323:6;1376:2;1364:9;1355:7;1351:23;1347:32;1344:52;;;1392:1;1389;1382:12;1344:52;1431:9;1418:23;1450:31;1475:5;1450:31;:::i;1698:456::-;1775:6;1783;1791;1844:2;1832:9;1823:7;1819:23;1815:32;1812:52;;;1860:1;1857;1850:12;1812:52;1899:9;1886:23;1918:31;1943:5;1918:31;:::i;:::-;1968:5;-1:-1:-1;2025:2:20;2010:18;;1997:32;2038:33;1997:32;2038:33;:::i;:::-;1698:456;;2090:7;;-1:-1:-1;;;2144:2:20;2129:18;;;;2116:32;;1698:456::o;2348:180::-;2407:6;2460:2;2448:9;2439:7;2435:23;2431:32;2428:52;;;2476:1;2473;2466:12;2428:52;-1:-1:-1;2499:23:20;;2348:180;-1:-1:-1;2348:180:20:o;3243:127::-;3304:10;3299:3;3295:20;3292:1;3285:31;3335:4;3332:1;3325:15;3359:4;3356:1;3349:15;3375:922;3444:6;3497:2;3485:9;3476:7;3472:23;3468:32;3465:52;;;3513:1;3510;3503:12;3465:52;3553:9;3540:23;3582:18;3623:2;3615:6;3612:14;3609:34;;;3639:1;3636;3629:12;3609:34;3677:6;3666:9;3662:22;3652:32;;3722:7;3715:4;3711:2;3707:13;3703:27;3693:55;;3744:1;3741;3734:12;3693:55;3780:2;3767:16;3802:2;3798;3795:10;3792:36;;;3808:18;;:::i;:::-;3883:2;3877:9;3851:2;3937:13;;-1:-1:-1;;3933:22:20;;;3957:2;3929:31;3925:40;3913:53;;;3981:18;;;4001:22;;;3978:46;3975:72;;;4027:18;;:::i;:::-;4067:10;4063:2;4056:22;4102:2;4094:6;4087:18;4142:7;4137:2;4132;4128;4124:11;4120:20;4117:33;4114:53;;;4163:1;4160;4153:12;4114:53;4219:2;4214;4210;4206:11;4201:2;4193:6;4189:15;4176:46;4264:1;4242:15;;;4259:2;4238:24;4231:35;;;;-1:-1:-1;4246:6:20;3375:922;-1:-1:-1;;;;;3375:922:20:o;4302:388::-;4370:6;4378;4431:2;4419:9;4410:7;4406:23;4402:32;4399:52;;;4447:1;4444;4437:12;4399:52;4486:9;4473:23;4505:31;4530:5;4505:31;:::i;:::-;4555:5;-1:-1:-1;4612:2:20;4597:18;;4584:32;4625:33;4584:32;4625:33;:::i;:::-;4677:7;4667:17;;;4302:388;;;;;:::o;4695:380::-;4774:1;4770:12;;;;4817;;;4838:61;;4892:4;4884:6;4880:17;4870:27;;4838:61;4945:2;4937:6;4934:14;4914:18;4911:38;4908:161;;;4991:10;4986:3;4982:20;4979:1;4972:31;5026:4;5023:1;5016:15;5054:4;5051:1;5044:15;4908:161;;4695:380;;;:::o;5080:344::-;5282:2;5264:21;;;5321:2;5301:18;;;5294:30;-1:-1:-1;;;5355:2:20;5340:18;;5333:50;5415:2;5400:18;;5080:344::o;5429:342::-;5631:2;5613:21;;;5670:2;5650:18;;;5643:30;-1:-1:-1;;;5704:2:20;5689:18;;5682:48;5762:2;5747:18;;5429:342::o;6898:277::-;6965:6;7018:2;7006:9;6997:7;6993:23;6989:32;6986:52;;;7034:1;7031;7024:12;6986:52;7066:9;7060:16;7119:5;7112:13;7105:21;7098:5;7095:32;7085:60;;7141:1;7138;7131:12;7180:127;7241:10;7236:3;7232:20;7229:1;7222:31;7272:4;7269:1;7262:15;7296:4;7293:1;7286:15;7312:125;7352:4;7380:1;7377;7374:8;7371:34;;;7385:18;;:::i;:::-;-1:-1:-1;7422:9:20;;7312:125::o;7792:128::-;7832:3;7863:1;7859:6;7856:1;7853:13;7850:39;;;7869:18;;:::i;:::-;-1:-1:-1;7905:9:20;;7792:128::o
Swarm Source
ipfs://780540f0938d325d7cbb843f51227fdc319aa11340808828c0a3396b00e830fb
Loading...
Loading
Loading...
Loading
OVERVIEW
Fringe Finance is a lending and stablecoin platform which accepts a wide range of smaller-cap ERC20 tokens as collateral for stablecoin loans. Deploy small-cap capital in the DeFi ecosystem without foregoing the upside.Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.