Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
LiquidatorBalanceInfo
Compiler Version
v0.5.16+commit.9c3226ce
Contract Source Code (Solidity)
/**
*Submitted for verification at Etherscan.io on 2020-12-02
*/
/*
B.PROTOCOL TERMS OF USE
=======================
THE TERMS OF USE CONTAINED HEREIN (THESE “TERMS”) GOVERN YOUR USE OF B.PROTOCOL, WHICH IS A DECENTRALIZED PROTOCOL ON THE ETHEREUM BLOCKCHAIN (the “PROTOCOL”) THAT enables a backstop liquidity mechanism FOR DECENTRALIZED LENDING PLATFORMS (“DLPs”).
PLEASE READ THESE TERMS CAREFULLY AT https://github.com/backstop-protocol/Terms-and-Conditions, INCLUDING ALL DISCLAIMERS AND RISK FACTORS, BEFORE USING THE PROTOCOL. BY USING THE PROTOCOL, YOU ARE IRREVOCABLY CONSENTING TO BE BOUND BY THESE TERMS.
IF YOU DO NOT AGREE TO ALL OF THESE TERMS, DO NOT USE THE PROTOCOL. YOUR RIGHT TO USE THE PROTOCOL IS SUBJECT AND DEPENDENT BY YOUR AGREEMENT TO ALL TERMS AND CONDITIONS SET FORTH HEREIN, WHICH AGREEMENT SHALL BE EVIDENCED BY YOUR USE OF THE PROTOCOL.
Minors Prohibited: The Protocol is not directed to individuals under the age of eighteen (18) or the age of majority in your jurisdiction if the age of majority is greater. If you are under the age of eighteen or the age of majority (if greater), you are not authorized to access or use the Protocol. By using the Protocol, you represent and warrant that you are above such age.
License; No Warranties; Limitation of Liability;
(a) The software underlying the Protocol is licensed for use in accordance with the 3-clause BSD License, which can be accessed here: https://opensource.org/licenses/BSD-3-Clause.
(b) THE PROTOCOL IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS", “WITH ALL FAULTS” and “AS AVAILABLE” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
(c) IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
pragma solidity ^0.5.12;
pragma experimental ABIEncoderV2;
contract Math {
// --- 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);
}
uint constant RAY = 10 ** 27;
function rdiv(uint x, uint y) internal pure returns (uint z) {
z = mul(x, RAY) / y;
}
function rmul(uint x, uint y) internal pure returns (uint z) {
z = mul(x, y) / RAY;
}
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)
}
}
}
}
}
function toInt(uint x) internal pure returns (int y) {
y = int(x);
require(y >= 0);
}
}
contract LibNote {
event LogNote(
bytes4 indexed sig,
address indexed usr,
bytes32 indexed arg1,
bytes32 indexed arg2,
bytes data
) anonymous;
modifier note {
_;
assembly {
// log an 'anonymous' event with a constant 6 words of calldata
// and four indexed topics: selector, caller, arg1 and arg2
let mark := msize() // end of memory ensures zero
mstore(0x40, add(mark, 288)) // update free memory pointer
mstore(mark, 0x20) // bytes type data offset
mstore(add(mark, 0x20), 224) // bytes size (padded)
calldatacopy(add(mark, 0x40), 0, 224) // bytes payload
log4(mark, 288, // calldata
shl(224, shr(224, calldataload(0))), // msg.sig
caller(), // msg.sender
calldataload(4), // arg1
calldataload(36) // arg2
)
}
}
}
contract BCdpScoreLike {
function updateScore(uint cdp, bytes32 ilk, int dink, int dart, uint time) external;
}
contract BCdpScoreConnector {
BCdpScoreLike public score;
mapping(uint => uint) public left;
constructor(BCdpScoreLike score_) public {
score = score_;
}
function setScore(BCdpScoreLike bcdpScore) internal {
score = bcdpScore;
}
function updateScore(uint cdp, bytes32 ilk, int dink, int dart, uint time) internal {
if(left[cdp] == 0) score.updateScore(cdp, ilk, dink, dart, time);
}
function quitScore(uint cdp) internal {
if(left[cdp] == 0) left[cdp] = now;
}
}
contract UrnHandler {
constructor(address vat) public {
VatLike(vat).hope(msg.sender);
}
}
contract DssCdpManager is LibNote {
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 note 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 note 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 DAI or collateral freed in the cdp urn address.
function frob(
uint cdp,
int dink,
int dart
) public note 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 note 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 note cdpAllowed(cdp) {
VatLike(vat).flux(ilk, urns[cdp], dst, wad);
}
// Transfer wad amount of DAI from the cdp address to a dst address.
function move(
uint cdp,
address dst,
uint rad
) public note 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 note 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 note 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 note 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)
);
}
}
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(0)) {
return false;
} else {
return authority.canCall(src, address(this), sig);
}
}
}
contract VatLike {
function urns(bytes32, address) public view returns (uint, uint);
function hope(address) external;
function flux(bytes32, address, address, uint) public;
function move(address, address, uint) public;
function frob(bytes32, address, address, address, int, int) public;
function fork(bytes32, address, address, int, int) public;
function ilks(bytes32 ilk) public view returns(uint Art, uint rate, uint spot, uint line, uint dust);
function dai(address usr) external view returns(uint);
}
contract CatLike {
function ilks(bytes32) public returns(address flip, uint256 chop, uint256 lump);
}
contract EndLike {
function cat() public view returns(CatLike);
}
contract PriceFeedLike {
function read(bytes32 ilk) external view returns(bytes32);
}
contract LiquidationMachine is DssCdpManager, BCdpScoreConnector, Math {
VatLike public vat;
EndLike public end;
address public pool;
PriceFeedLike public real;
mapping(uint => uint) public tic; // time of bite
mapping(uint => uint) public cushion; // how much was topped in art units
uint constant public GRACE = 1 hours;
uint constant public WAD = 1e18;
mapping (uint => bool) public out;
modifier onlyPool {
require(msg.sender == pool, "not-pool");
_;
}
constructor(VatLike vat_, EndLike end_, address pool_, PriceFeedLike real_) public {
vat = vat_;
end = end_;
pool = pool_;
real = real_;
}
function setPool(address newPool) internal {
pool = newPool;
}
function quitBLiquidation(uint cdp) internal {
untop(cdp);
out[cdp] = true;
}
function topup(uint cdp, uint dtopup) external onlyPool {
if(out[cdp]) return;
address urn = urns[cdp];
bytes32 ilk = ilks[cdp];
(, uint rate,,,) = vat.ilks(ilk);
uint dtab = mul(rate, dtopup);
vat.move(pool, address(this), dtab);
vat.frob(ilk, urn, urn, address(this), 0, -toInt(dtopup));
cushion[cdp] = add(cushion[cdp], dtopup);
}
function bitten(uint cdp) public view returns(bool) {
return tic[cdp] + GRACE > now;
}
function untop(uint cdp) internal {
require(! bitten(cdp), "untop: cdp was already bitten");
uint top = cushion[cdp];
if(top == 0) return; // nothing to do
bytes32 ilk = ilks[cdp];
address urn = urns[cdp];
(, uint rate,,,) = vat.ilks(ilk);
uint dtab = mul(rate, top);
cushion[cdp] = 0;
// move topping to pool
vat.frob(ilk, urn, urn, urn, 0, toInt(top));
vat.move(urn, pool, dtab);
}
function untopByPool(uint cdp) external onlyPool {
untop(cdp);
}
function doBite(uint dart, bytes32 ilk, address urn, uint dink) internal {
(, uint rate,,,) = vat.ilks(ilk);
uint dtab = mul(rate, dart);
vat.move(pool, address(this), dtab);
vat.frob(ilk, urn, urn, address(this), 0, -toInt(dart));
vat.frob(ilk, urn, msg.sender, urn, -toInt(dink), 0);
}
function calcDink(uint dart, uint rate, bytes32 ilk) internal returns(uint dink) {
(, uint chop,) = end.cat().ilks(ilk);
uint tab = mul(mul(dart, rate), chop) / WAD;
bytes32 realtimePrice = real.read(ilk);
dink = rmul(tab, WAD) / uint(realtimePrice);
}
function bite(uint cdp, uint dart) external onlyPool returns(uint dink){
address urn = urns[cdp];
bytes32 ilk = ilks[cdp];
(uint ink, uint art) = vat.urns(ilk, urn);
art = add(art, cushion[cdp]);
(, uint rate, uint spotValue,,) = vat.ilks(ilk);
require(dart <= art, "debt is too low");
// verify cdp is unsafe now
if(! bitten(cdp)) {
require(mul(art, rate) > mul(ink, spotValue), "bite: cdp is safe");
require(cushion[cdp] > 0, "bite: not-topped");
tic[cdp] = now;
}
dink = calcDink(dart, rate, ilk);
updateScore(cdp, ilk, -toInt(dink), -toInt(dart), now);
uint usedCushion = mul(cushion[cdp], dart) / art;
cushion[cdp] = sub(cushion[cdp], usedCushion);
uint bart = sub(dart, usedCushion);
doBite(bart, ilk, urn, dink);
}
}
contract BCdpManager is BCdpScoreConnector, LiquidationMachine, DSAuth {
constructor(address vat_, address end_, address pool_, address real_, address score_) public
DssCdpManager(vat_)
LiquidationMachine(VatLike(vat_), EndLike(end_), pool_, PriceFeedLike(real_))
BCdpScoreConnector(BCdpScoreLike(score_))
{
}
// Frob the cdp keeping the generated DAI or collateral freed in the cdp urn address.
function frob(
uint cdp,
int dink,
int dart
) public cdpAllowed(cdp) {
bytes32 ilk = ilks[cdp];
untop(cdp);
updateScore(cdp, ilk, dink, dart, now);
super.frob(cdp, dink, dart);
}
// Quit the system, migrating the cdp (ink, art) to a different dst urn
function quit(
uint cdp,
address dst
) public cdpAllowed(cdp) urnAllowed(dst) {
address urn = urns[cdp];
bytes32 ilk = ilks[cdp];
untop(cdp);
(uint ink, uint art) = vat.urns(ilk, urn);
updateScore(cdp, ilk, -toInt(ink), -toInt(art), now);
super.quit(cdp, dst);
}
// Import a position from src urn to the urn owned by cdp
function enter(
address src,
uint cdp
) public urnAllowed(src) cdpAllowed(cdp) {
bytes32 ilk = ilks[cdp];
untop(cdp);
(uint ink, uint art) = vat.urns(ilk, src);
updateScore(cdp, ilk, toInt(ink), toInt(art), now);
super.enter(src, cdp);
}
// Move a position from cdpSrc urn to the cdpDst urn
function shift(
uint cdpSrc,
uint cdpDst
) public cdpAllowed(cdpSrc) cdpAllowed(cdpDst) {
bytes32 ilkSrc = ilks[cdpSrc];
untop(cdpSrc);
untop(cdpDst);
address src = urns[cdpSrc];
(uint inkSrc, uint artSrc) = vat.urns(ilkSrc, src);
updateScore(cdpSrc, ilkSrc, -toInt(inkSrc), -toInt(artSrc), now);
updateScore(cdpDst, ilkSrc, toInt(inkSrc), toInt(artSrc), now);
super.shift(cdpSrc, cdpDst);
}
///////////////// B specific control functions /////////////////////////////
function quitB(uint cdp) external cdpAllowed(cdp) note {
quitScore(cdp);
quitBLiquidation(cdp);
}
function setScoreContract(BCdpScoreLike _score) external auth {
super.setScore(_score);
}
function setPoolContract(address _pool) external auth {
super.setPool(_pool);
}
}
contract Context {
// Empty internal constructor, to prevent people from mistakenly deploying
// an instance of this contract, which should be used via inheritance.
constructor () internal { }
// solhint-disable-previous-line no-empty-blocks
function _msgSender() internal view returns (address payable) {
return msg.sender;
}
function _msgData() internal view returns (bytes memory) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data;
}
}
contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor () internal {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(isOwner(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Returns true if the caller is the current owner.
*/
function isOwner() public view returns (bool) {
return _msgSender() == _owner;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public onlyOwner {
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
*/
function _transferOwnership(address newOwner) internal {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
contract ScoringMachine is Ownable {
struct AssetScore {
// total score so far
uint score;
// current balance
uint balance;
// time when last update was
uint last;
}
// user is bytes32 (will be the sha3 of address or cdp number)
mapping(bytes32 => mapping(bytes32 => AssetScore[])) public checkpoints;
mapping(bytes32 => mapping(bytes32 => AssetScore)) public userScore;
bytes32 constant public GLOBAL_USER = bytes32(0x0);
uint public start; // start time of the campaign;
function spin() external onlyOwner { // start a new round
start = now;
}
function assetScore(AssetScore storage score, uint time, uint spinStart) internal view returns(uint) {
uint last = score.last;
uint currentScore = score.score;
if(last < spinStart) {
last = spinStart;
currentScore = 0;
}
return add(currentScore, mul(score.balance, sub(time, last)));
}
function addCheckpoint(bytes32 user, bytes32 asset) internal {
checkpoints[user][asset].push(userScore[user][asset]);
}
function updateAssetScore(bytes32 user, bytes32 asset, int dbalance, uint time) internal {
AssetScore storage score = userScore[user][asset];
if(score.last < start) addCheckpoint(user, asset);
score.score = assetScore(score, time, start);
score.balance = add(score.balance, dbalance);
score.last = time;
}
function updateScore(bytes32 user, bytes32 asset, int dbalance, uint time) internal {
updateAssetScore(user, asset, dbalance, time);
updateAssetScore(GLOBAL_USER, asset, dbalance, time);
}
function getScore(bytes32 user, bytes32 asset, uint time, uint spinStart, uint checkPointHint) public view returns(uint score) {
if(time >= userScore[user][asset].last) return assetScore(userScore[user][asset], time, spinStart);
// else - check the checkpoints
uint checkpointsLen = checkpoints[user][asset].length;
if(checkpointsLen == 0) return 0;
// hint is invalid
if(checkpoints[user][asset][checkPointHint].last < time) checkPointHint = checkpointsLen - 1;
for(uint i = checkPointHint ; ; i--){
if(checkpoints[user][asset][i].last <= time) return assetScore(checkpoints[user][asset][i], time, spinStart);
}
// this supposed to be unreachable
return 0;
}
function getCurrentBalance(bytes32 user, bytes32 asset) public view returns(uint balance) {
balance = userScore[user][asset].balance;
}
// Math functions without errors
// ==============================
function add(uint x, uint y) internal pure returns (uint z) {
z = x + y;
if(!(z >= x)) return 0;
return z;
}
function add(uint x, int y) internal pure returns (uint z) {
z = x + uint(y);
if(!(y >= 0 || z <= x)) return 0;
if(!(y <= 0 || z >= x)) return 0;
return z;
}
function sub(uint x, uint y) internal pure returns (uint z) {
if(!(y <= x)) return 0;
z = x - y;
return z;
}
function mul(uint x, uint y) internal pure returns (uint z) {
if (x == 0) return 0;
z = x * y;
if(!(z / x == y)) return 0;
return z;
}
}
contract BCdpScore is ScoringMachine {
BCdpManager public manager;
modifier onlyManager {
require(msg.sender == address(manager), "not-manager");
_;
}
function setManager(address newManager) external onlyOwner {
manager = BCdpManager(newManager);
}
function user(uint cdp) public pure returns(bytes32) {
return keccak256(abi.encodePacked("BCdpScore", cdp));
}
function artAsset(bytes32 ilk) public pure returns(bytes32) {
return keccak256(abi.encodePacked("BCdpScore", "art", ilk));
}
function updateScore(uint cdp, bytes32 ilk, int dink, int dart, uint time) external onlyManager {
dink; // shh compiler warning
updateScore(user(cdp), artAsset(ilk), dart, time);
}
function slashScore(uint maliciousCdp) external {
address urn = manager.urns(maliciousCdp);
bytes32 ilk = manager.ilks(maliciousCdp);
(, uint realArt) = manager.vat().urns(ilk, urn);
bytes32 maliciousUser = user(maliciousCdp);
bytes32 asset = artAsset(ilk);
uint left = BCdpScoreConnector(address(manager)).left(maliciousCdp);
realArt = left > 0 ? 0 : realArt;
uint startTime = left > 0 ? left : now;
uint calculatedArt = getCurrentBalance(maliciousUser, asset);
require(realArt < calculatedArt, "slashScore-cdp-is-ok");
int dart = int(realArt) - int(calculatedArt);
uint time = sub(startTime, 30 days);
if(time < start) time = start;
updateScore(maliciousUser, asset, dart, time);
}
function getArtScore(uint cdp, bytes32 ilk, uint time, uint spinStart) public view returns(uint) {
return getScore(user(cdp), artAsset(ilk), time, spinStart, 0);
}
function getArtGlobalScore(bytes32 ilk, uint time, uint spinStart) public view returns(uint) {
return getScore(GLOBAL_USER, artAsset(ilk), time, spinStart, 0);
}
}
contract JarConnector is Math {
BCdpScore public score;
BCdpManager public man;
bytes32[] public ilks;
// ilk => supported
mapping(bytes32 => bool) public milks;
// end of every round
uint[2] public end;
// start time of every round
uint[2] public start;
uint public round;
constructor(
bytes32[] memory _ilks,
uint[2] memory _duration
) public {
ilks = _ilks;
for(uint i = 0; i < _ilks.length; i++) {
milks[_ilks[i]] = true;
}
end[0] = now + _duration[0];
end[1] = now + _duration[0] + _duration[1];
round = 0;
}
function setManager(address _manager) public {
require(man == BCdpManager(0), "manager-already-set");
man = BCdpManager(_manager);
score = BCdpScore(address(man.score()));
}
// callable by anyone
function spin() public {
if(round == 0) {
round++;
score.spin();
start[0] = score.start();
}
if(round == 1 && now > end[0]) {
round++;
score.spin();
start[1] = score.start();
}
if(round == 2 && now > end[1]) {
round++;
// score is not counted anymore, and this must be followed by contract upgrade
score.spin();
}
}
function getUserScore(bytes32 user) external view returns (uint) {
if(round == 0) return 0;
uint cdp = uint(user);
bytes32 ilk = man.ilks(cdp);
// Should return 0 score for unsupported ilk
if( ! milks[ilk]) return 0;
if(round == 1) return 2 * score.getArtScore(cdp, ilk, now, start[0]);
uint firstRoundScore = 2 * score.getArtScore(cdp, ilk, start[1], start[0]);
uint time = now;
if(round > 2) time = end[1];
return add(score.getArtScore(cdp, ilk, time, start[1]), firstRoundScore);
}
function getGlobalScore() external view returns (uint) {
if(round == 0) return 0;
if(round == 1) return 2 * getArtGlobalScore(now, start[0]);
uint firstRoundScore = 2 * getArtGlobalScore(start[1], start[0]);
uint time = now;
if(round > 2) time = end[1];
return add(getArtGlobalScore(time, start[1]), firstRoundScore);
}
function getGlobalScore(bytes32 ilk) external view returns (uint) {
if(round == 0) return 0;
if(round == 1) return 2 * score.getArtGlobalScore(ilk, now, start[0]);
uint firstRoundScore = 2 * score.getArtGlobalScore(ilk, start[1], start[0]);
uint time = now;
if(round > 2) time = end[1];
return add(score.getArtGlobalScore(ilk, time, start[1]), firstRoundScore);
}
function getArtGlobalScore(uint time, uint spinStart) internal view returns (uint totalScore) {
for(uint i = 0; i < ilks.length; i++) {
totalScore = add(totalScore, score.getArtGlobalScore(ilks[i], time, spinStart));
}
}
function toUser(bytes32 user) external view returns (address) {
return man.owns(uint(user));
}
}
contract JugLike {
function ilks(bytes32 ilk) public view returns(uint duty, uint rho);
function base() public view returns(uint);
}
contract SpotLike {
function par() external view returns (uint256);
function ilks(bytes32 ilk) external view returns (address pip, uint mat);
}
contract OSMLike {
function peep() external view returns(bytes32, bool);
function hop() external view returns(uint16);
function zzz() external view returns(uint64);
}
contract DaiToUsdPriceFeed {
function getMarketPrice(uint marketId) public view returns (uint);
}
contract Pool is Math, DSAuth, LibNote {
uint public constant DAI_MARKET_ID = 3;
address[] public members;
mapping(bytes32 => bool) public ilks;
uint public minArt; // min debt to share among members
uint public shrn; // share profit % numerator
uint public shrd; // share profit % denumerator
mapping(address => uint) public rad; // mapping from member to its dai balance in rad
VatLike public vat;
BCdpManager public man;
SpotLike public spot;
JugLike public jug;
address public jar;
DaiToUsdPriceFeed public dai2usd;
mapping(uint => CdpData) internal cdpData;
mapping(bytes32 => OSMLike) public osm; // mapping from ilk to osm
struct CdpData {
uint art; // topup in art units
uint cushion; // cushion in rad units
address[] members; // liquidators that are in
uint[] bite; // how much was already bitten
}
modifier onlyMember {
bool member = false;
for(uint i = 0 ; i < members.length ; i++) {
if(members[i] == msg.sender) {
member = true;
break;
}
}
require(member, "not-member");
_;
}
constructor(address vat_, address jar_, address spot_, address jug_, address dai2usd_) public {
spot = SpotLike(spot_);
jug = JugLike(jug_);
vat = VatLike(vat_);
jar = jar_;
dai2usd = DaiToUsdPriceFeed(dai2usd_);
}
function getCdpData(uint cdp) external view returns(uint art, uint cushion, address[] memory members_, uint[] memory bite) {
art = cdpData[cdp].art;
cushion = cdpData[cdp].cushion;
members_ = cdpData[cdp].members;
bite = cdpData[cdp].bite;
}
function setCdpManager(BCdpManager man_) external auth note {
man = man_;
vat.hope(address(man));
}
function setOsm(bytes32 ilk_, address osm_) external auth note {
osm[ilk_] = OSMLike(osm_);
}
function setMembers(address[] calldata members_) external auth note {
members = members_;
}
function setIlk(bytes32 ilk, bool set) external auth note {
ilks[ilk] = set;
}
function setMinArt(uint minArt_) external auth note {
minArt = minArt_;
}
function setDaiToUsdPriceFeed(address dai2usd_) external auth note {
dai2usd = DaiToUsdPriceFeed(dai2usd_);
}
function setProfitParams(uint num, uint den) external auth note {
require(num < den, "invalid-profit-params");
shrn = num;
shrd = den;
}
function emergencyExecute(address target, bytes calldata data) external auth note {
(bool succ,) = target.call(data);
require(succ, "emergencyExecute: failed");
}
function deposit(uint radVal) external onlyMember note {
vat.move(msg.sender, address(this), radVal);
rad[msg.sender] = add(rad[msg.sender], radVal);
}
function withdraw(uint radVal) external note {
require(rad[msg.sender] >= radVal, "withdraw: insufficient-balance");
rad[msg.sender] = sub(rad[msg.sender], radVal);
vat.move(address(this), msg.sender, radVal);
}
function getIndex(address[] storage array, address elm) internal view returns(uint) {
for(uint i = 0 ; i < array.length ; i++) {
if(array[i] == elm) return i;
}
return uint(-1);
}
function removeElement(address[] memory array, uint index) internal pure returns(address[] memory newArray) {
if(index >= array.length) {
newArray = array;
}
else {
newArray = new address[](array.length - 1);
for(uint i = 0 ; i < array.length ; i++) {
if(i == index) continue;
if(i < index) newArray[i] = array[i];
else newArray[i-1] = array[i];
}
}
}
function chooseMember(uint cdp, uint radVal, address[] memory candidates) public view returns(address[] memory winners) {
if(candidates.length == 0) return candidates;
// A bit of randomness to choose winners. We don't need pure randomness, its ok even if a
// liquidator can predict his winning in the future.
uint chosen = uint(keccak256(abi.encodePacked(cdp, now / 1 hours))) % candidates.length;
address winner = candidates[chosen];
if(rad[winner] < radVal) return chooseMember(cdp, radVal, removeElement(candidates, chosen));
winners = new address[](1);
winners[0] = candidates[chosen];
return winners;
}
function chooseMembers(uint radVal, address[] memory candidates) public view returns(address[] memory winners) {
if(candidates.length == 0) return candidates;
uint need = add(1, radVal / candidates.length);
for(uint i = 0 ; i < candidates.length ; i++) {
if(rad[candidates[i]] < need) {
return chooseMembers(radVal, removeElement(candidates, i));
}
}
winners = candidates;
}
function calcCushion(bytes32 ilk, uint ink, uint art, uint nextSpot) public view returns(uint dart, uint dtab) {
(, uint prev, uint currSpot,,) = vat.ilks(ilk);
if(currSpot <= nextSpot) return (0, 0);
uint hop = uint(osm[ilk].hop());
uint next = add(uint(osm[ilk].zzz()), hop);
(uint duty, uint rho) = jug.ilks(ilk);
require(next >= rho, "calcCushion: next-in-the-past");
// note that makerdao governance could change jug.base() before the actual
// liquidation happens. but there is 48 hours time lock on makerdao votes
// so liquidators should withdraw their funds if they think such event will
// happen
uint nextRate = rmul(rpow(add(jug.base(), duty), next - rho, RAY), prev);
uint nextnextRate = rmul(rpow(add(jug.base(), duty), hop, RAY), nextRate);
if(mul(nextRate, art) > mul(ink, currSpot)) return (0, 0); // prevent L attack
if(mul(nextRate, art) <= mul(ink, nextSpot)) return (0, 0);
uint maxArt = mul(ink, nextSpot) / nextnextRate;
dart = sub(art, maxArt);
dart = add(1 ether, dart); // compensate for rounding errors
dtab = mul(dart, prev); // provide a cushion according to current rate
}
function hypoTopAmount(uint cdp) internal view returns(uint dart, uint dtab, uint art, bool should) {
address urn = man.urns(cdp);
bytes32 ilk = man.ilks(cdp);
uint ink;
(ink, art) = vat.urns(ilk, urn);
if(! ilks[ilk]) return (0, 0, art, false);
(bytes32 peep, bool valid) = osm[ilk].peep();
// price feed invalid
if(! valid) return (0, 0, art, false);
// too early to topup
should = (now >= add(uint(osm[ilk].zzz()), uint(osm[ilk].hop())/2));
(, uint mat) = spot.ilks(ilk);
uint par = spot.par();
uint nextVatSpot = rdiv(rdiv(mul(uint(peep), uint(10 ** 9)), par), mat);
(dart, dtab) = calcCushion(ilk, ink, art, nextVatSpot);
}
function topAmount(uint cdp) public view returns(uint dart, uint dtab, uint art) {
bool should;
(dart, dtab, art, should) = hypoTopAmount(cdp);
if(! should) return (0, 0, art);
}
function resetCdp(uint cdp) internal {
address[] memory winners = cdpData[cdp].members;
if(winners.length == 0) return;
uint art = cdpData[cdp].art;
uint cushion = cdpData[cdp].cushion;
uint perUserArt = cdpData[cdp].art / winners.length;
for(uint i = 0 ; i < winners.length ; i++) {
if(perUserArt <= cdpData[cdp].bite[i]) continue; // nothing to refund
uint refundArt = sub(perUserArt, cdpData[cdp].bite[i]);
rad[winners[i]] = add(rad[winners[i]], mul(refundArt, cushion)/art);
}
cdpData[cdp].art = 0;
cdpData[cdp].cushion = 0;
delete cdpData[cdp].members;
delete cdpData[cdp].bite;
}
function setCdp(uint cdp, address[] memory winners, uint art, uint dradVal) internal {
uint drad = add(1, dradVal / winners.length); // round up
for(uint i = 0 ; i < winners.length ; i++) {
rad[winners[i]] = sub(rad[winners[i]], drad);
}
cdpData[cdp].art = art;
cdpData[cdp].cushion = dradVal;
cdpData[cdp].members = winners;
cdpData[cdp].bite = new uint[](winners.length);
}
function topupInfo(uint cdp) public view returns(uint dart, uint dtab, uint art, bool should, address[] memory winners) {
(dart, dtab, art, should) = hypoTopAmount(cdp);
if(art < minArt) {
winners = chooseMember(cdp, uint(dtab), members);
}
else winners = chooseMembers(uint(dtab), members);
}
function topup(uint cdp) external onlyMember note {
require(man.cushion(cdp) == 0, "topup: already-topped");
require(! man.bitten(cdp), "topup: already-bitten");
(uint dart, uint dtab, uint art, bool should, address[] memory winners) = topupInfo(cdp);
require(should, "topup: no-need");
require(dart > 0, "topup: 0-dart");
resetCdp(cdp);
require(winners.length > 0, "topup: members-are-broke");
// for small amounts, only winner can topup
if(art < minArt) require(winners[0] == msg.sender, "topup: only-winner-can-topup");
setCdp(cdp, winners, uint(art), uint(dtab));
man.topup(cdp, uint(dart));
}
function untop(uint cdp) external onlyMember note {
require(man.cushion(cdp) == 0, "untop: should-be-untopped-by-user");
resetCdp(cdp);
}
function bite(uint cdp, uint dart, uint minInk) external onlyMember note returns(uint dMemberInk){
uint index = getIndex(cdpData[cdp].members, msg.sender);
uint availBite = availBite(cdp, index);
require(dart <= availBite, "bite: debt-too-small");
cdpData[cdp].bite[index] = add(cdpData[cdp].bite[index], dart);
uint dink = man.bite(cdp, dart);
// update user rad
bytes32 ilk = man.ilks(cdp);
(,uint rate,,,) = vat.ilks(ilk);
uint cushionPortion = mul(cdpData[cdp].cushion, dart) / cdpData[cdp].art;
rad[msg.sender] = sub(rad[msg.sender], sub(mul(dart, rate), cushionPortion));
// DAI to USD rate, scale 1e18
uint d2uPrice = dai2usd.getMarketPrice(DAI_MARKET_ID);
// dMemberInk = debt * 1.065 * d2uPrice
// dMemberInk = dink * (shrn/shrd) * (d2uPrice/1e18)
dMemberInk = mul(mul(dink, shrn), d2uPrice) / mul(shrd, uint(1 ether));
// To protect edge case when 1 DAI > 1.13 USD
if(dMemberInk > dink) dMemberInk = dink;
// Remaining to Jar
uint userInk = sub(dink, dMemberInk);
require(dMemberInk >= minInk, "bite: low-dink");
vat.flux(ilk, address(this), jar, userInk);
vat.flux(ilk, address(this), msg.sender, dMemberInk);
}
function availBite(uint cdp, address member) public view returns (uint) {
uint index = getIndex(cdpData[cdp].members, member);
return availBite(cdp, index);
}
function availBite(uint cdp, uint index) internal view returns (uint) {
if(index == uint(-1)) return 0;
uint numMembers = cdpData[cdp].members.length;
uint maxArt = cdpData[cdp].art / numMembers;
// give dust to first member
if(index == 0) {
uint dust = cdpData[cdp].art % numMembers;
maxArt = add(maxArt, dust);
}
uint availArt = sub(maxArt, cdpData[cdp].bite[index]);
address urn = man.urns(cdp);
bytes32 ilk = man.ilks(cdp);
(,uint art) = vat.urns(ilk, urn);
uint remainingArt = add(art, man.cushion(cdp));
return availArt < remainingArt ? availArt : remainingArt;
}
}
contract ChainlinkLike {
function latestAnswer() external view returns (int256);
}
contract LiquidatorInfo is Math {
struct VaultInfo {
bytes32 collateralType;
uint collateralInWei;
uint debtInDaiWei;
uint liquidationPrice;
uint expectedEthReturnWithCurrentPrice;
bool expectedEthReturnBetterThanChainlinkPrice;
}
struct CushionInfo {
uint cushionSizeInWei;
uint numLiquidators;
uint cushionSizeInWeiIfAllHaveBalance;
uint numLiquidatorsIfAllHaveBalance;
bool shouldProvideCushion;
bool shouldProvideCushionIfAllHaveBalance;
uint minimumTimeBeforeCallingTopup;
bool canCallTopupNow;
bool shouldCallUntop;
bool isToppedUp;
}
struct BiteInfo {
uint availableBiteInArt;
uint availableBiteInDaiWei;
uint minimumTimeBeforeCallingBite;
bool canCallBiteNow;
}
struct CdpInfo {
uint cdp;
uint blockNumber;
VaultInfo vault;
CushionInfo cushion;
BiteInfo bite;
}
// Struct to store local vars. This avoid stack too deep error
struct CdpDataVars {
uint cdpArt;
uint cushion;
address[] cdpWinners;
uint[] bite;
}
LiquidationMachine manager;
VatLike public vat;
Pool pool;
SpotLike spot;
ChainlinkLike chainlink;
uint constant RAY = 1e27;
constructor(LiquidationMachine manager_, address chainlink_) public {
manager = manager_;
vat = VatLike(address(manager.vat()));
pool = Pool(manager.pool());
spot = SpotLike(address(pool.spot()));
chainlink = ChainlinkLike(chainlink_);
}
function getExpectedEthReturn(bytes32 collateralType, uint daiDebt, uint currentPriceFeedValue) public returns(uint) {
// get chope value
(,uint chop,) = manager.end().cat().ilks(collateralType);
uint biteIlk = mul(chop, daiDebt) / currentPriceFeedValue;
// DAI to USD rate, scale 1e18
uint d2uPrice = pool.dai2usd().getMarketPrice(pool.DAI_MARKET_ID());
uint shrn = pool.shrn();
uint shrd = pool.shrd();
return mul(mul(biteIlk, shrn), d2uPrice) / mul(shrd, uint(1 ether));
}
function getVaultInfo(uint cdp, uint currentPriceFeedValue) public returns(VaultInfo memory info) {
address urn = manager.urns(cdp);
info.collateralType = manager.ilks(cdp);
uint cushion = manager.cushion(cdp);
uint art;
(info.collateralInWei, art) = vat.urns(info.collateralType, urn);
if(info.collateralInWei == 0) return info;
(,uint rate,,,) = vat.ilks(info.collateralType);
info.debtInDaiWei = mul(add(art, cushion), rate) / RAY;
(, uint mat) = spot.ilks(info.collateralType);
info.liquidationPrice = mul(info.debtInDaiWei, mat) / mul(info.collateralInWei, RAY / 1e18);
if(currentPriceFeedValue > 0) {
info.expectedEthReturnWithCurrentPrice = getExpectedEthReturn(info.collateralType, info.debtInDaiWei, currentPriceFeedValue);
}
int chainlinkPrice = chainlink.latestAnswer();
uint chainlinkEthReturn = 0;
if(chainlinkPrice > 0) {
chainlinkEthReturn = mul(info.debtInDaiWei, uint(chainlinkPrice)) / 1 ether;
}
info.expectedEthReturnBetterThanChainlinkPrice =
info.expectedEthReturnWithCurrentPrice > chainlinkEthReturn;
}
function getCushionInfo(uint cdp, address me, uint numMembers) public view returns(CushionInfo memory info) {
CdpDataVars memory c;
(c.cdpArt, c.cushion, c.cdpWinners, c.bite) = pool.getCdpData(cdp);
for(uint i = 0 ; i < c.cdpWinners.length ; i++) {
if(me == c.cdpWinners[i]) {
uint perUserArt = c.cdpArt / c.cdpWinners.length;
info.shouldCallUntop = manager.cushion(cdp) == 0 && c.cushion > 0 && c.bite[i] < perUserArt;
info.isToppedUp = c.bite[i] < perUserArt;
break;
}
}
(uint dart, uint dtab, uint art, bool should, address[] memory winners) = pool.topupInfo(cdp);
info.numLiquidators = winners.length;
info.cushionSizeInWei = dtab / RAY;
if(dart == 0) {
if(info.isToppedUp) {
info.numLiquidatorsIfAllHaveBalance = winners.length;
info.cushionSizeInWei = c.cushion / RAY;
}
return info;
}
if(art < pool.minArt()) {
info.cushionSizeInWeiIfAllHaveBalance = info.cushionSizeInWei;
info.numLiquidatorsIfAllHaveBalance = 1;
info.shouldProvideCushion = false;
for(uint i = 0 ; i < winners.length ; i++) {
if(me == winners[i]) info.shouldProvideCushion = true;
}
uint chosen = uint(keccak256(abi.encodePacked(cdp, now / 1 hours))) % numMembers;
info.shouldProvideCushionIfAllHaveBalance = (pool.members(chosen) == me);
}
else {
info.cushionSizeInWeiIfAllHaveBalance = info.cushionSizeInWei / numMembers;
info.numLiquidatorsIfAllHaveBalance = numMembers;
info.shouldProvideCushion = true;
info.shouldProvideCushionIfAllHaveBalance = true;
}
info.canCallTopupNow = !info.isToppedUp && should && info.shouldProvideCushion;
bytes32 ilk = manager.ilks(cdp);
uint topupTime = add(uint(pool.osm(ilk).zzz()), uint(pool.osm(ilk).hop())/2);
info.minimumTimeBeforeCallingTopup = (now >= topupTime) ? 0 : sub(topupTime, now);
}
function getBiteInfo(uint cdp, address me) public view returns(BiteInfo memory info) {
info.availableBiteInArt = pool.availBite(cdp, me);
bytes32 ilk = manager.ilks(cdp);
uint priceUpdateTime = add(uint(pool.osm(ilk).zzz()), uint(pool.osm(ilk).hop()));
info.minimumTimeBeforeCallingBite = (now >= priceUpdateTime) ? 0 : sub(priceUpdateTime, now);
if(info.availableBiteInArt == 0) return info;
address u = manager.urns(cdp);
(,uint rate, uint currSpot,,) = vat.ilks(ilk);
info.availableBiteInDaiWei = mul(rate, info.availableBiteInArt) / RAY;
(uint ink, uint art) = vat.urns(ilk, u);
uint cushion = manager.cushion(cdp);
info.canCallBiteNow = (mul(ink, currSpot) < mul(add(art, cushion), rate)) || manager.bitten(cdp);
}
function getNumMembers() public returns(uint) {
for(uint i = 0 ; /* infinite loop */ ; i++) {
(bool result,) = address(pool).call(abi.encodeWithSignature("members(uint256)", i));
if(! result) return i;
}
}
function getCdpData(uint startCdp, uint endCdp, address me, uint currentPriceFeedValue) public returns(CdpInfo[] memory info) {
uint numMembers = getNumMembers();
info = new CdpInfo[](add(sub(endCdp, startCdp), uint(1)));
for(uint cdp = startCdp ; cdp <= endCdp ; cdp++) {
uint index = cdp - startCdp;
info[index].cdp = cdp;
info[index].blockNumber = block.number;
info[index].vault = getVaultInfo(cdp, currentPriceFeedValue);
info[index].cushion = getCushionInfo(cdp, me, numMembers);
info[index].bite = getBiteInfo(cdp, me);
}
}
}
contract FlatLiquidatorInfo is LiquidatorInfo {
constructor(LiquidationMachine manager_, address chainlink_) public LiquidatorInfo(manager_, chainlink_) {}
function getVaultInfoFlat(uint cdp, uint currentPriceFeedValue) external
returns(bytes32 collateralType, uint collateralInWei, uint debtInDaiWei, uint liquidationPrice,
uint expectedEthReturnWithCurrentPrice, bool expectedEthReturnBetterThanChainlinkPrice) {
VaultInfo memory info = getVaultInfo(cdp, currentPriceFeedValue);
collateralType = info.collateralType;
collateralInWei = info.collateralInWei;
debtInDaiWei = info.debtInDaiWei;
liquidationPrice = info.liquidationPrice;
expectedEthReturnWithCurrentPrice = info.expectedEthReturnWithCurrentPrice;
expectedEthReturnBetterThanChainlinkPrice = info.expectedEthReturnBetterThanChainlinkPrice;
}
function getCushionInfoFlat(uint cdp, address me, uint numMembers) external view
returns(uint cushionSizeInWei, uint numLiquidators, uint cushionSizeInWeiIfAllHaveBalance,
uint numLiquidatorsIfAllHaveBalance, bool shouldProvideCushion, bool shouldProvideCushionIfAllHaveBalance,
bool canCallTopupNow, bool shouldCallUntop, uint minimumTimeBeforeCallingTopup,
bool isToppedUp) {
CushionInfo memory info = getCushionInfo(cdp, me, numMembers);
cushionSizeInWei = info.cushionSizeInWei;
numLiquidators = info.numLiquidators;
cushionSizeInWeiIfAllHaveBalance = info.cushionSizeInWeiIfAllHaveBalance;
numLiquidatorsIfAllHaveBalance = info.numLiquidatorsIfAllHaveBalance;
shouldProvideCushion = info.shouldProvideCushion;
shouldProvideCushionIfAllHaveBalance = info.shouldProvideCushionIfAllHaveBalance;
canCallTopupNow = info.canCallTopupNow;
shouldCallUntop = info.shouldCallUntop;
minimumTimeBeforeCallingTopup = info.minimumTimeBeforeCallingTopup;
isToppedUp = info.isToppedUp;
}
function getBiteInfoFlat(uint cdp, address me) external view
returns(uint availableBiteInArt, uint availableBiteInDaiWei, bool canCallBiteNow,uint minimumTimeBeforeCallingBite) {
BiteInfo memory info = getBiteInfo(cdp, me);
availableBiteInArt = info.availableBiteInArt;
availableBiteInDaiWei = info.availableBiteInDaiWei;
canCallBiteNow = info.canCallBiteNow;
minimumTimeBeforeCallingBite = info.minimumTimeBeforeCallingBite;
}
}
contract ERC20Like {
function balanceOf(address guy) public view returns(uint);
}
contract VatBalanceLike {
function gem(bytes32 ilk, address user) external view returns(uint);
function dai(address user) external view returns(uint);
}
contract LiquidatorBalanceInfo is Math {
struct BalanceInfo {
uint blockNumber;
uint ethBalance;
uint wethBalance;
uint daiBalance;
uint vatDaiBalanceInWei;
uint vatEthBalanceInWei;
uint poolDaiBalanceInWei;
}
function getTotalCushion(address me, address pool, uint startCdp, uint endCdp)
public view returns(uint cushionInArt) {
for(uint cdp = startCdp ; cdp <= endCdp ; cdp++) {
(uint topupArt, uint cushion, address[] memory members, uint[] memory bite) = Pool(pool).getCdpData(cdp);
for(uint m = 0 ; topupArt > 0 && m < members.length ; m++) {
uint perUserArt = topupArt / members.length;
if(perUserArt <= bite[m]) continue;
if(members[m] == me) {
uint refundArt = sub(perUserArt, bite[m]);
cushionInArt = add(cushionInArt, mul(refundArt, cushion)/topupArt);
break;
}
}
}
cushionInArt = cushionInArt / RAY;
}
function getTotalCushion(address me, address pool)
public view returns(uint cushionInArt) {
uint startCdp = 1;
uint endCdp = Pool(pool).man().cdpi();
cushionInArt = getTotalCushion(me, pool, startCdp, endCdp);
}
function getBalanceInfo(address me, address pool, address vat, bytes32 ilk, address dai, address weth)
public view returns(BalanceInfo memory info) {
info.blockNumber = block.number;
info.ethBalance = me.balance;
info.wethBalance = ERC20Like(weth).balanceOf(me);
info.daiBalance = ERC20Like(dai).balanceOf(me);
info.vatDaiBalanceInWei = VatBalanceLike(vat).dai(me) / RAY;
info.vatEthBalanceInWei = VatBalanceLike(vat).gem(ilk, me);
info.poolDaiBalanceInWei = Pool(pool).rad(me) / RAY;
}
function getBalanceInfoFlat(address me, address pool, address vat, bytes32 ilk, address dai, address weth)
public view returns(uint blockNumber, uint ethBalance, uint wethBalance, uint daiBalance, uint vatDaiBalanceInWei,
uint vatEthBalanceInWei, uint poolDaiBalanceInWei) {
BalanceInfo memory info = getBalanceInfo(me, pool, vat, ilk, dai, weth);
blockNumber = info.blockNumber;
ethBalance = info.ethBalance;
wethBalance = info.wethBalance;
daiBalance = info.daiBalance;
vatDaiBalanceInWei = info.vatDaiBalanceInWei;
vatEthBalanceInWei = info.vatEthBalanceInWei;
poolDaiBalanceInWei = info.poolDaiBalanceInWei;
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"constant":true,"inputs":[{"internalType":"address","name":"me","type":"address"},{"internalType":"address","name":"pool","type":"address"},{"internalType":"address","name":"vat","type":"address"},{"internalType":"bytes32","name":"ilk","type":"bytes32"},{"internalType":"address","name":"dai","type":"address"},{"internalType":"address","name":"weth","type":"address"}],"name":"getBalanceInfo","outputs":[{"components":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"uint256","name":"ethBalance","type":"uint256"},{"internalType":"uint256","name":"wethBalance","type":"uint256"},{"internalType":"uint256","name":"daiBalance","type":"uint256"},{"internalType":"uint256","name":"vatDaiBalanceInWei","type":"uint256"},{"internalType":"uint256","name":"vatEthBalanceInWei","type":"uint256"},{"internalType":"uint256","name":"poolDaiBalanceInWei","type":"uint256"}],"internalType":"struct LiquidatorBalanceInfo.BalanceInfo","name":"info","type":"tuple"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"me","type":"address"},{"internalType":"address","name":"pool","type":"address"},{"internalType":"address","name":"vat","type":"address"},{"internalType":"bytes32","name":"ilk","type":"bytes32"},{"internalType":"address","name":"dai","type":"address"},{"internalType":"address","name":"weth","type":"address"}],"name":"getBalanceInfoFlat","outputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"uint256","name":"ethBalance","type":"uint256"},{"internalType":"uint256","name":"wethBalance","type":"uint256"},{"internalType":"uint256","name":"daiBalance","type":"uint256"},{"internalType":"uint256","name":"vatDaiBalanceInWei","type":"uint256"},{"internalType":"uint256","name":"vatEthBalanceInWei","type":"uint256"},{"internalType":"uint256","name":"poolDaiBalanceInWei","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"me","type":"address"},{"internalType":"address","name":"pool","type":"address"},{"internalType":"uint256","name":"startCdp","type":"uint256"},{"internalType":"uint256","name":"endCdp","type":"uint256"}],"name":"getTotalCushion","outputs":[{"internalType":"uint256","name":"cushionInArt","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"me","type":"address"},{"internalType":"address","name":"pool","type":"address"}],"name":"getTotalCushion","outputs":[{"internalType":"uint256","name":"cushionInArt","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}]Contract Creation Code
608060405234801561001057600080fd5b50610c5a806100206000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c8063432e766814610051578063bf8a8b211461007a578063c4c529b6146100a0578063f6b07a4f146100c0575b600080fd5b61006461005f36600461087b565b6100d3565b6040516100719190610afd565b60405180910390f35b61008d61008836600461087b565b6103a7565b6040516100719796959493929190610b19565b6100b36100ae366004610902565b61040b565b6040516100719190610b0b565b6100b36100ce366004610841565b610593565b6100db6106de565b4381526001600160a01b038088163160208301526040516370a0823160e01b8152908316906370a0823190610114908a90600401610acd565b60206040518083038186803b15801561012c57600080fd5b505afa158015610140573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506101649190810190610989565b604080830191909152516370a0823160e01b81526001600160a01b038416906370a0823190610197908a90600401610acd565b60206040518083038186803b1580156101af57600080fd5b505afa1580156101c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506101e79190810190610989565b6060820152604051633612d9a360e11b81526b033b2e3c9fd0803ce8000000906001600160a01b03871690636c25b34690610226908b90600401610acd565b60206040518083038186803b15801561023e57600080fd5b505afa158015610252573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506102769190810190610989565b8161027d57fe5b04608082015260405163214414d560e01b81526001600160a01b0386169063214414d5906102b19087908b90600401610adb565b60206040518083038186803b1580156102c957600080fd5b505afa1580156102dd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506103019190810190610989565b60a082015260405163754434f960e01b81526b033b2e3c9fd0803ce8000000906001600160a01b0388169063754434f990610340908b90600401610acd565b60206040518083038186803b15801561035857600080fd5b505afa15801561036c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506103909190810190610989565b8161039757fe5b0460c08201529695505050505050565b60008060008060008060006103ba6106de565b6103c88e8e8e8e8e8e6100d3565b905080600001519750806020015196508060400151955080606001519450806080015193508060a0015192508060c0015191505096509650965096509650965096565b6000825b82811161057b57600080606080886001600160a01b031663aee779ef866040518263ffffffff1660e01b81526004016104489190610b0b565b60006040518083038186803b15801561046057600080fd5b505afa158015610474573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261049c91908101906109a7565b9296509094509250905060005b6000851180156104b95750825181105b1561056a576000835186816104ca57fe5b0490508282815181106104d957fe5b602002602001015181116104ed5750610562565b8b6001600160a01b031684838151811061050357fe5b60200260200101516001600160a01b031614156105605760006105398285858151811061052c57fe5b6020026020010151610694565b9050610557898861054a848a6106aa565b8161055157fe5b046106ce565b9850505061056a565b505b6001016104a9565b50506001909301925061040f915050565b506b033b2e3c9fd0803ce80000009004949350505050565b600080600190506000836001600160a01b03166310cd2dc76040518163ffffffff1660e01b815260040160206040518083038186803b1580156105d557600080fd5b505afa1580156105e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061060d9190810190610963565b6001600160a01b031663b3d178f26040518163ffffffff1660e01b815260040160206040518083038186803b15801561064557600080fd5b505afa158015610659573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061067d9190810190610989565b905061068b8585848461040b565b95945050505050565b808203828111156106a457600080fd5b92915050565b60008115806106c5575050808202828282816106c257fe5b04145b6106a457600080fd5b808201828110156106a457600080fd5b6040518060e00160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b80356106a481610bee565b80516106a481610bee565b600082601f83011261074257600080fd5b815161075561075082610ba8565b610b81565b9150818183526020840193506020810190508385602084028201111561077a57600080fd5b60005b838110156107a657816107908882610726565b845250602092830192919091019060010161077d565b5050505092915050565b600082601f8301126107c157600080fd5b81516107cf61075082610ba8565b915081818352602084019350602081019050838560208402820111156107f457600080fd5b60005b838110156107a6578161080a8882610836565b84525060209283019291909101906001016107f7565b80356106a481610c05565b80516106a481610c0e565b80516106a481610c05565b6000806040838503121561085457600080fd5b6000610860858561071b565b92505060206108718582860161071b565b9150509250929050565b60008060008060008060c0878903121561089457600080fd5b60006108a0898961071b565b96505060206108b189828a0161071b565b95505060406108c289828a0161071b565b94505060606108d389828a01610820565b93505060806108e489828a0161071b565b92505060a06108f589828a0161071b565b9150509295509295509295565b6000806000806080858703121561091857600080fd5b6000610924878761071b565b94505060206109358782880161071b565b935050604061094687828801610820565b925050606061095787828801610820565b91505092959194509250565b60006020828403121561097557600080fd5b6000610981848461082b565b949350505050565b60006020828403121561099b57600080fd5b60006109818484610836565b600080600080608085870312156109bd57600080fd5b60006109c98787610836565b94505060206109da87828801610836565b935050604085015167ffffffffffffffff8111156109f757600080fd5b610a0387828801610731565b925050606085015167ffffffffffffffff811115610a2057600080fd5b610957878288016107b0565b610a3581610bc9565b82525050565b610a3581610bd4565b805160e0830190610a558482610a3b565b506020820151610a686020850182610a3b565b506040820151610a7b6040850182610a3b565b506060820151610a8e6060850182610a3b565b506080820151610aa16080850182610a3b565b5060a0820151610ab460a0850182610a3b565b5060c0820151610ac760c0850182610a3b565b50505050565b602081016106a48284610a2c565b60408101610ae98285610a3b565b610af66020830184610a2c565b9392505050565b60e081016106a48284610a44565b602081016106a48284610a3b565b60e08101610b27828a610a3b565b610b346020830189610a3b565b610b416040830188610a3b565b610b4e6060830187610a3b565b610b5b6080830186610a3b565b610b6860a0830185610a3b565b610b7560c0830184610a3b565b98975050505050505050565b60405181810167ffffffffffffffff81118282101715610ba057600080fd5b604052919050565b600067ffffffffffffffff821115610bbf57600080fd5b5060209081020190565b60006106a482610be2565b90565b60006106a482610bc9565b6001600160a01b031690565b610bf781610bc9565b8114610c0257600080fd5b50565b610bf781610bd4565b610bf781610bd756fea365627a7a72315820952aa9b7c688a36adc611a738fdf79c6891b9675e99d074f237af159c70f78546c6578706572696d656e74616cf564736f6c63430005100040
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061004c5760003560e01c8063432e766814610051578063bf8a8b211461007a578063c4c529b6146100a0578063f6b07a4f146100c0575b600080fd5b61006461005f36600461087b565b6100d3565b6040516100719190610afd565b60405180910390f35b61008d61008836600461087b565b6103a7565b6040516100719796959493929190610b19565b6100b36100ae366004610902565b61040b565b6040516100719190610b0b565b6100b36100ce366004610841565b610593565b6100db6106de565b4381526001600160a01b038088163160208301526040516370a0823160e01b8152908316906370a0823190610114908a90600401610acd565b60206040518083038186803b15801561012c57600080fd5b505afa158015610140573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506101649190810190610989565b604080830191909152516370a0823160e01b81526001600160a01b038416906370a0823190610197908a90600401610acd565b60206040518083038186803b1580156101af57600080fd5b505afa1580156101c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506101e79190810190610989565b6060820152604051633612d9a360e11b81526b033b2e3c9fd0803ce8000000906001600160a01b03871690636c25b34690610226908b90600401610acd565b60206040518083038186803b15801561023e57600080fd5b505afa158015610252573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506102769190810190610989565b8161027d57fe5b04608082015260405163214414d560e01b81526001600160a01b0386169063214414d5906102b19087908b90600401610adb565b60206040518083038186803b1580156102c957600080fd5b505afa1580156102dd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506103019190810190610989565b60a082015260405163754434f960e01b81526b033b2e3c9fd0803ce8000000906001600160a01b0388169063754434f990610340908b90600401610acd565b60206040518083038186803b15801561035857600080fd5b505afa15801561036c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506103909190810190610989565b8161039757fe5b0460c08201529695505050505050565b60008060008060008060006103ba6106de565b6103c88e8e8e8e8e8e6100d3565b905080600001519750806020015196508060400151955080606001519450806080015193508060a0015192508060c0015191505096509650965096509650965096565b6000825b82811161057b57600080606080886001600160a01b031663aee779ef866040518263ffffffff1660e01b81526004016104489190610b0b565b60006040518083038186803b15801561046057600080fd5b505afa158015610474573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261049c91908101906109a7565b9296509094509250905060005b6000851180156104b95750825181105b1561056a576000835186816104ca57fe5b0490508282815181106104d957fe5b602002602001015181116104ed5750610562565b8b6001600160a01b031684838151811061050357fe5b60200260200101516001600160a01b031614156105605760006105398285858151811061052c57fe5b6020026020010151610694565b9050610557898861054a848a6106aa565b8161055157fe5b046106ce565b9850505061056a565b505b6001016104a9565b50506001909301925061040f915050565b506b033b2e3c9fd0803ce80000009004949350505050565b600080600190506000836001600160a01b03166310cd2dc76040518163ffffffff1660e01b815260040160206040518083038186803b1580156105d557600080fd5b505afa1580156105e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061060d9190810190610963565b6001600160a01b031663b3d178f26040518163ffffffff1660e01b815260040160206040518083038186803b15801561064557600080fd5b505afa158015610659573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061067d9190810190610989565b905061068b8585848461040b565b95945050505050565b808203828111156106a457600080fd5b92915050565b60008115806106c5575050808202828282816106c257fe5b04145b6106a457600080fd5b808201828110156106a457600080fd5b6040518060e00160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b80356106a481610bee565b80516106a481610bee565b600082601f83011261074257600080fd5b815161075561075082610ba8565b610b81565b9150818183526020840193506020810190508385602084028201111561077a57600080fd5b60005b838110156107a657816107908882610726565b845250602092830192919091019060010161077d565b5050505092915050565b600082601f8301126107c157600080fd5b81516107cf61075082610ba8565b915081818352602084019350602081019050838560208402820111156107f457600080fd5b60005b838110156107a6578161080a8882610836565b84525060209283019291909101906001016107f7565b80356106a481610c05565b80516106a481610c0e565b80516106a481610c05565b6000806040838503121561085457600080fd5b6000610860858561071b565b92505060206108718582860161071b565b9150509250929050565b60008060008060008060c0878903121561089457600080fd5b60006108a0898961071b565b96505060206108b189828a0161071b565b95505060406108c289828a0161071b565b94505060606108d389828a01610820565b93505060806108e489828a0161071b565b92505060a06108f589828a0161071b565b9150509295509295509295565b6000806000806080858703121561091857600080fd5b6000610924878761071b565b94505060206109358782880161071b565b935050604061094687828801610820565b925050606061095787828801610820565b91505092959194509250565b60006020828403121561097557600080fd5b6000610981848461082b565b949350505050565b60006020828403121561099b57600080fd5b60006109818484610836565b600080600080608085870312156109bd57600080fd5b60006109c98787610836565b94505060206109da87828801610836565b935050604085015167ffffffffffffffff8111156109f757600080fd5b610a0387828801610731565b925050606085015167ffffffffffffffff811115610a2057600080fd5b610957878288016107b0565b610a3581610bc9565b82525050565b610a3581610bd4565b805160e0830190610a558482610a3b565b506020820151610a686020850182610a3b565b506040820151610a7b6040850182610a3b565b506060820151610a8e6060850182610a3b565b506080820151610aa16080850182610a3b565b5060a0820151610ab460a0850182610a3b565b5060c0820151610ac760c0850182610a3b565b50505050565b602081016106a48284610a2c565b60408101610ae98285610a3b565b610af66020830184610a2c565b9392505050565b60e081016106a48284610a44565b602081016106a48284610a3b565b60e08101610b27828a610a3b565b610b346020830189610a3b565b610b416040830188610a3b565b610b4e6060830187610a3b565b610b5b6080830186610a3b565b610b6860a0830185610a3b565b610b7560c0830184610a3b565b98975050505050505050565b60405181810167ffffffffffffffff81118282101715610ba057600080fd5b604052919050565b600067ffffffffffffffff821115610bbf57600080fd5b5060209081020190565b60006106a482610be2565b90565b60006106a482610bc9565b6001600160a01b031690565b610bf781610bc9565b8114610c0257600080fd5b50565b610bf781610bd4565b610bf781610bd756fea365627a7a72315820952aa9b7c688a36adc611a738fdf79c6891b9675e99d074f237af159c70f78546c6578706572696d656e74616cf564736f6c63430005100040
Deployed Bytecode Sourcemap
57278:2685:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;57278:2685:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;58657:565;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;59230:730;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;57568:817;;;;;;;;;:::i;:::-;;;;;;;;58393:256;;;;;;;;;:::i;58657:565::-;58789:23;;:::i;:::-;58846:12;58827:31;;-1:-1:-1;;;;;58887:10:0;;;;58869:15;;;:28;58927:29;;-1:-1:-1;;;58927:29:0;;:25;;;;;;:29;;58887:2;;58927:29;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;58927:29:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;58927:29:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;58927:29:0;;;;;;;;;58908:16;;;;:48;;;;58985:28;-1:-1:-1;;;58985:28:0;;-1:-1:-1;;;;;58985:24:0;;;;;:28;;59010:2;;58985:28;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;58985:28:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;58985:28:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;58985:28:0;;;;;;;;;58967:15;;;:46;59050:27;;-1:-1:-1;;;59050:27:0;;3242:8;;-1:-1:-1;;;;;59050:23:0;;;;;:27;;59074:2;;59050:27;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;59050:27:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;59050:27:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;59050:27:0;;;;;;;;;:33;;;;;;59024:23;;;:59;59120:32;;-1:-1:-1;;;59120:32:0;;-1:-1:-1;;;;;59120:23:0;;;;;:32;;59144:3;;59149:2;;59120:32;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;59120:32:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;59120:32:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;59120:32:0;;;;;;;;;59094:23;;;:58;59190:18;;-1:-1:-1;;;59190:18:0;;3242:8;;-1:-1:-1;;;;;59190:14:0;;;;;:18;;59205:2;;59190:18;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;59190:18:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;59190:18:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;59190:18:0;;;;;;;;;:24;;;;;;59163;;;:51;:4;58657:565;-1:-1:-1;;;;;;58657:565:0:o;59230:730::-;59366:16;59384:15;59401:16;59419:15;59436:23;59490;59515:24;59554:23;;:::i;:::-;59580:45;59595:2;59599:4;59605:3;59610;59615;59620:4;59580:14;:45::i;:::-;59554:71;;59650:4;:16;;;59636:30;;59690:4;:15;;;59677:28;;59730:4;:16;;;59716:30;;59770:4;:15;;;59757:28;;59817:4;:23;;;59796:44;;59872:4;:23;;;59851:44;;59928:4;:24;;;59906:46;;59230:730;;;;;;;;;;;;;;:::o;57568:817::-;57676:17;57723:8;57708:624;57741:6;57734:3;:13;57708:624;;57773:13;57788:12;57802:24;57828:18;57855:4;-1:-1:-1;;;;;57850:21:0;;57872:3;57850:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;57850:26:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;57850:26:0;;;;;;39:16:-1;36:1;17:17;2:54;101:4;57850:26:0;80:15:-1;;;-1:-1;;76:31;65:43;;120:4;113:20;57850:26:0;;;;;;;;;57772:104;;-1:-1:-1;57772:104:0;;-1:-1:-1;57772:104:0;-1:-1:-1;57772:104:0;-1:-1:-1;57895:6:0;57891:430;57919:1;57908:8;:12;:34;;;;;57928:7;:14;57924:1;:18;57908:34;57891:430;;;57969:15;57998:7;:14;57987:8;:25;;;;;;57969:43;;58048:4;58053:1;58048:7;;;;;;;;;;;;;;58034:10;:21;58031:34;;58057:8;;;58031:34;58101:2;-1:-1:-1;;;;;58087:16:0;:7;58095:1;58087:10;;;;;;;;;;;;;;-1:-1:-1;;;;;58087:16:0;;58084:222;;;58128:14;58145:24;58149:10;58161:4;58166:1;58161:7;;;;;;;;;;;;;;58145:3;:24::i;:::-;58128:41;;58207:51;58211:12;58249:8;58225:23;58229:9;58240:7;58225:3;:23::i;:::-;:32;;;;;;58207:3;:51::i;:::-;58192:66;;58281:5;;;;58084:222;57891:430;;57945:3;;57891:430;;;-1:-1:-1;;57750:5:0;;;;;-1:-1:-1;57708:624:0;;-1:-1:-1;;57708:624:0;;-1:-1:-1;3242:8:0;58359:18;;;;-1:-1:-1;;;;57568:817:0:o;58393:256::-;58473:17;58505:13;58521:1;58505:17;;58533:11;58552:4;-1:-1:-1;;;;;58547:14:0;;:16;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;58547:16:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;58547:16:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;58547:16:0;;;;;;;;;-1:-1:-1;;;;;58547:21:0;;:23;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;58547:23:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;58547:23:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;58547:23:0;;;;;;;;;58533:37;;58598:43;58614:2;58618:4;58624:8;58634:6;58598:15;:43::i;:::-;58583:58;58393:256;-1:-1:-1;;;;;58393:256:0:o;2986:104::-;3070:5;;;3065:16;;;;3057:25;;;;;;2986:104;;;;:::o;3096:118::-;3148:6;3175;;;:30;;-1:-1:-1;;3190:5:0;;;3204:1;3199;3190:5;3199:1;3185:15;;;;;:20;3175:30;3167:39;;;;;2876:104;2960:5;;;2955:16;;;;2947:25;;;;;57278:2685;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;5:130:-1:-;72:20;;97:33;72:20;97:33;;142:134;220:13;;238:33;220:13;238:33;;301:722;;429:3;422:4;414:6;410:17;406:27;396:2;;447:1;444;437:12;396:2;477:6;471:13;499:80;514:64;571:6;514:64;;;499:80;;;490:89;;596:5;621:6;614:5;607:21;651:4;643:6;639:17;629:27;;673:4;668:3;664:14;657:21;;726:6;773:3;765:4;757:6;753:17;748:3;744:27;741:36;738:2;;;790:1;787;780:12;738:2;815:1;800:217;825:6;822:1;819:13;800:217;;;883:3;905:48;949:3;937:10;905:48;;;893:61;;-1:-1;977:4;968:14;;;;996;;;;;847:1;840:9;800:217;;;804:14;389:634;;;;;;;;1049:722;;1177:3;1170:4;1162:6;1158:17;1154:27;1144:2;;1195:1;1192;1185:12;1144:2;1225:6;1219:13;1247:80;1262:64;1319:6;1262:64;;1247:80;1238:89;;1344:5;1369:6;1362:5;1355:21;1399:4;1391:6;1387:17;1377:27;;1421:4;1416:3;1412:14;1405:21;;1474:6;1521:3;1513:4;1505:6;1501:17;1496:3;1492:27;1489:36;1486:2;;;1538:1;1535;1528:12;1486:2;1563:1;1548:217;1573:6;1570:1;1567:13;1548:217;;;1631:3;1653:48;1697:3;1685:10;1653:48;;;1641:61;;-1:-1;1725:4;1716:14;;;;1744;;;;;1595:1;1588:9;1548:217;;1779:130;1846:20;;1871:33;1846:20;1871:33;;1916:174;2014:13;;2032:53;2014:13;2032:53;;2234:134;2312:13;;2330:33;2312:13;2330:33;;2375:366;;;2496:2;2484:9;2475:7;2471:23;2467:32;2464:2;;;2512:1;2509;2502:12;2464:2;2547:1;2564:53;2609:7;2589:9;2564:53;;;2554:63;;2526:97;2654:2;2672:53;2717:7;2708:6;2697:9;2693:22;2672:53;;;2662:63;;2633:98;2458:283;;;;;;2748:869;;;;;;;2937:3;2925:9;2916:7;2912:23;2908:33;2905:2;;;2954:1;2951;2944:12;2905:2;2989:1;3006:53;3051:7;3031:9;3006:53;;;2996:63;;2968:97;3096:2;3114:53;3159:7;3150:6;3139:9;3135:22;3114:53;;;3104:63;;3075:98;3204:2;3222:53;3267:7;3258:6;3247:9;3243:22;3222:53;;;3212:63;;3183:98;3312:2;3330:53;3375:7;3366:6;3355:9;3351:22;3330:53;;;3320:63;;3291:98;3420:3;3439:53;3484:7;3475:6;3464:9;3460:22;3439:53;;;3429:63;;3399:99;3529:3;3548:53;3593:7;3584:6;3573:9;3569:22;3548:53;;;3538:63;;3508:99;2899:718;;;;;;;;;3624:617;;;;;3779:3;3767:9;3758:7;3754:23;3750:33;3747:2;;;3796:1;3793;3786:12;3747:2;3831:1;3848:53;3893:7;3873:9;3848:53;;;3838:63;;3810:97;3938:2;3956:53;4001:7;3992:6;3981:9;3977:22;3956:53;;;3946:63;;3917:98;4046:2;4064:53;4109:7;4100:6;4089:9;4085:22;4064:53;;;4054:63;;4025:98;4154:2;4172:53;4217:7;4208:6;4197:9;4193:22;4172:53;;;4162:63;;4133:98;3741:500;;;;;;;;4248:303;;4383:2;4371:9;4362:7;4358:23;4354:32;4351:2;;;4399:1;4396;4389:12;4351:2;4434:1;4451:84;4527:7;4507:9;4451:84;;;4441:94;4345:206;-1:-1;;;;4345:206;4558:263;;4673:2;4661:9;4652:7;4648:23;4644:32;4641:2;;;4689:1;4686;4679:12;4641:2;4724:1;4741:64;4797:7;4777:9;4741:64;;4828:930;;;;;5044:3;5032:9;5023:7;5019:23;5015:33;5012:2;;;5061:1;5058;5051:12;5012:2;5096:1;5113:64;5169:7;5149:9;5113:64;;;5103:74;;5075:108;5214:2;5232:64;5288:7;5279:6;5268:9;5264:22;5232:64;;;5222:74;;5193:109;5354:2;5343:9;5339:18;5333:25;5378:18;5370:6;5367:30;5364:2;;;5410:1;5407;5400:12;5364:2;5430:89;5511:7;5502:6;5491:9;5487:22;5430:89;;;5420:99;;5312:213;5577:2;5566:9;5562:18;5556:25;5601:18;5593:6;5590:30;5587:2;;;5633:1;5630;5623:12;5587:2;5653:89;5734:7;5725:6;5714:9;5710:22;5653:89;;5765:113;5848:24;5866:5;5848:24;;;5843:3;5836:37;5830:48;;;5885:113;5968:24;5986:5;5968:24;;6096:1323;6320:23;;6247:4;6238:14;;;6349:63;6242:3;6320:23;6349:63;;;6267:151;6497:4;6490:5;6486:16;6480:23;6509:63;6566:4;6561:3;6557:14;6543:12;6509:63;;;6428:150;6658:4;6651:5;6647:16;6641:23;6670:63;6727:4;6722:3;6718:14;6704:12;6670:63;;;6588:151;6818:4;6811:5;6807:16;6801:23;6830:63;6887:4;6882:3;6878:14;6864:12;6830:63;;;6749:150;6986:4;6979:5;6975:16;6969:23;6998:63;7055:4;7050:3;7046:14;7032:12;6998:63;;;6909:158;7154:4;7147:5;7143:16;7137:23;7166:63;7223:4;7218:3;7214:14;7200:12;7166:63;;;7077:158;7323:4;7316:5;7312:16;7306:23;7335:63;7392:4;7387:3;7383:14;7369:12;7335:63;;;7245:159;6220:1199;;;;7656:213;7774:2;7759:18;;7788:71;7763:9;7832:6;7788:71;;7876:324;8022:2;8007:18;;8036:71;8011:9;8080:6;8036:71;;;8118:72;8186:2;8175:9;8171:18;8162:6;8118:72;;;7993:207;;;;;;8207:330;8383:3;8368:19;;8398:129;8372:9;8500:6;8398:129;;8544:213;8662:2;8647:18;;8676:71;8651:9;8720:6;8676:71;;8764:883;9050:3;9035:19;;9065:71;9039:9;9109:6;9065:71;;;9147:72;9215:2;9204:9;9200:18;9191:6;9147:72;;;9230;9298:2;9287:9;9283:18;9274:6;9230:72;;;9313;9381:2;9370:9;9366:18;9357:6;9313:72;;;9396:73;9464:3;9453:9;9449:19;9440:6;9396:73;;;9480;9548:3;9537:9;9533:19;9524:6;9480:73;;;9564;9632:3;9621:9;9617:19;9608:6;9564:73;;;9021:626;;;;;;;;;;;9654:256;9716:2;9710:9;9742:17;;;9817:18;9802:34;;9838:22;;;9799:62;9796:2;;;9874:1;9871;9864:12;9796:2;9890;9883:22;9694:216;;-1:-1;9694:216;9917:304;;10076:18;10068:6;10065:30;10062:2;;;10108:1;10105;10098:12;10062:2;-1:-1;10143:4;10131:17;;;10196:15;;9999:222;10539:91;;10601:24;10619:5;10601:24;;10637:72;10699:5;10682:27;10716:111;;10798:24;10816:5;10798:24;;10834:121;-1:-1;;;;;10896:54;;10879:76;11041:117;11110:24;11128:5;11110:24;;;11103:5;11100:35;11090:2;;11149:1;11146;11139:12;11090:2;11084:74;;11165:117;11234:24;11252:5;11234:24;;11289:157;11378:44;11416:5;11378:44;
Swarm Source
bzzr://952aa9b7c688a36adc611a738fdf79c6891b9675e99d074f237af159c70f7854
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.