Transactions
Token Transfers
Internal Transactions
Coin Balance History
Logs
Code
Read Contract
Write Contract
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
This contract has been partially verified via Sourcify.
View contract in Sourcify repository
- Contract name:
- DssPsm
- Optimization enabled
- true
- Compiler version
- v0.8.28+commit.7893614a
- Optimization runs
- 200
- EVM Version
- istanbul
- Verified at
- 2026-04-20T14:37:31.330998Z
Constructor Arguments
0000000000000000000000006aafa71c9db937e4088dd2db72375038b744911c0000000000000000000000003fa88872368b9bfea50c35b35fff55c425c8ac530000000000000000000000002030803a2eab2a481f4ff358731c416eead94210
Arg [0] (address) : 0x6aafa71c9db937e4088dd2db72375038b744911c
Arg [1] (address) : 0x3fa88872368b9bfea50c35b35fff55c425c8ac53
Arg [2] (address) : 0x2030803a2eab2a481f4ff358731c416eead94210
DeployNewPsmSpell.sol
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.20;
// ──────────────────────────────────────────────
// INTERFACES
// ──────────────────────────────────────────────
interface GemLike {
function transfer(address dst, uint256 wad) external returns (bool);
function transferFrom(address src, address dst, uint256 wad) external returns (bool);
function approve(address usr, uint256 wad) external returns (bool);
function balanceOf(address usr) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);
function decimals() external view returns (uint8);
}
interface DaiLike is GemLike {
function push(address usr, uint256 wad) external;
function pull(address usr, uint256 wad) external;
function move(address src, address dst, uint256 wad) external;
function mint(address usr, uint256 wad) external;
function burn(address usr, uint256 wad) external;
function permit(address holder, address spender, uint256 nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s) external;
}
interface DaiJoinLike {
function vat() external view returns (address);
function dai() external view returns (address);
function join(address usr, uint256 wad) external;
function exit(address usr, uint256 wad) external;
}
interface VatLike {
function wards(address) external view returns (uint256);
function rely(address) external;
function deny(address) external;
function can(address, address) external view returns (uint256);
function hope(address) external;
function nope(address) external;
function ilks(bytes32) external view returns (uint256, uint256, uint256, uint256, uint256);
function urns(bytes32, address) external view returns (uint256, uint256);
function gem(bytes32, address) external view returns (uint256);
function dai(address) external view returns (uint256);
function sin(address) external view returns (uint256);
function debt() external view returns (uint256);
function vice() external view returns (uint256);
function Line() external view returns (uint256);
function live() external view returns (uint256);
function init(bytes32) external;
function file(bytes32, uint256) external;
function file(bytes32, bytes32, uint256) external;
function cage() external;
function slip(bytes32, address, int256) external;
function flux(bytes32, address, address, uint256) external;
function move(address, address, uint256) external;
function frob(bytes32, address, address, address, int256, int256) external;
function fork(bytes32, address, address, int256, int256) external;
function grab(bytes32, address, address, address, int256, int256) external;
function heal(uint256) external;
function suck(address, address, uint256) external;
function fold(bytes32, address, int256) external;
}
interface GemJoinLike {
function vat() external view returns (address);
function ilk() external view returns (bytes32);
function gem() external view returns (address);
function dec() external view returns (uint8);
function join(address usr, uint256 wad) external;
function exit(address usr, uint256 wad) external;
}
interface SpotterLike {
function rely(address usr) external;
function file(bytes32 ilk, bytes32 what, address pip) external;
function file(bytes32 ilk, bytes32 what, uint256 data) external;
function poke(bytes32 ilk) external;
function par() external view returns (uint256);
function ilks(bytes32) external view returns (PipLike, uint256);
}
interface DogLike {
function rely(address usr) external;
function file(bytes32 ilk, bytes32 what, address clip) external;
function file(bytes32 ilk, bytes32 what, uint256 data) external;
function chop(bytes32) external view returns (uint256);
function digs(bytes32, uint256) external;
}
interface PaiRegistryLike {
function addIlk(bytes32 ilk, address gem, address join, address pip, address clip, address pair, address psm) external;
}
interface ISimpleTWAPOracle {
function getPriceInUsd(address token, uint amountIn) external view returns (uint amountOutDai);
}
interface IERC20 {
function decimals() external view returns (uint8);
}
interface PipLike {
function peek() external view returns (bytes32, bool);
}
interface ClipperCallee {
function clipperCall(address, uint256, uint256, bytes calldata) external;
}
interface AbacusLike {
function price(uint256, uint256) external view returns (uint256);
}
contract Clipper {
// ─── Errors ───
error NotAuthorized();
error SystemLocked();
error StoppedIncorrect();
error FileUnrecognizedParam();
error ZeroTab();
error ZeroLot();
error ZeroUsr();
error Overflow();
error ZeroTopPrice();
error NotRunningAuction();
error CannotReset();
error NeedsReset();
error TooExpensive();
error NoPartialPurchase();
error InvalidPrice();
// ─── Auth ───
mapping(address => uint256) public wards;
modifier auth {
if (wards[msg.sender] != 1) revert NotAuthorized();
_;
}
// ─── Data ───
bytes32 public immutable ilk;
VatLike public immutable vat;
DogLike public dog;
address public vow;
SpotterLike public spotter;
AbacusLike public calc;
uint256 public buf;
uint256 public tail;
uint256 public cusp;
uint64 public chip;
uint192 public tip;
uint256 public chost;
uint256 public kicks;
uint256[] public active;
struct Sale {
uint256 pos;
uint256 tab;
uint256 lot;
address usr;
uint96 tic;
uint256 top;
}
mapping(uint256 => Sale) public sales;
uint256 internal locked;
uint256 public stopped = 0;
// ─── Events ───
event Rely(address indexed usr);
event Deny(address indexed usr);
event File(bytes32 indexed what, uint256 data);
event FileAddress(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 indexed id);
event Upchost(uint256 chost);
// ─── Init ───
constructor(address vat_, address spotter_, address dog_, bytes32 ilk_) {
vat = VatLike(vat_);
spotter = SpotterLike(spotter_);
dog = DogLike(dog_);
ilk = ilk_;
buf = RAY;
wards[msg.sender] = 1;
emit Rely(msg.sender);
}
// ─── Sync ───
modifier lock {
if (locked == 1) revert SystemLocked();
locked = 1;
_;
locked = 0;
}
modifier isStopped(uint256 level) {
if (stopped >= level) revert StoppedIncorrect();
_;
}
// ─── Admin ───
function rely(address usr) external auth { wards[usr] = 1; emit Rely(usr); }
function deny(address usr) external auth { wards[usr] = 0; emit Deny(usr); }
function file(bytes32 what, uint256 data) external auth lock {
if (what == "buf") buf = data;
else if (what == "tail") tail = data;
else if (what == "cusp") cusp = data;
else if (what == "chip") chip = uint64(data);
else if (what == "tip") tip = uint192(data);
else if (what == "stopped") stopped = data;
else revert FileUnrecognizedParam();
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 FileUnrecognizedParam();
emit FileAddress(what, data);
}
// ─── Math ───
uint256 constant BLN = 10 ** 9;
uint256 constant WAD = 10 ** 18;
uint256 constant RAY = 10 ** 27;
function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) {
z = (x * y) / RAY;
}
function rdiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
z = (x * RAY) / y;
}
// ─── Auction ───
function getFeedPrice() internal view returns (uint256 feedPrice) {
(PipLike pip, ) = spotter.ilks(ilk);
(bytes32 val, bool has) = pip.peek();
if (!has) revert InvalidPrice();
feedPrice = rdiv(uint256(val) * BLN, spotter.par());
}
function kick(
uint256 tab, uint256 lot, address usr, address kpr
) external auth lock isStopped(1) returns (uint256 id) {
if (tab == 0) revert ZeroTab();
if (lot == 0) revert ZeroLot();
if (usr == address(0)) revert ZeroUsr();
id = ++kicks;
if (id == 0) revert 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 = rmul(getFeedPrice(), buf);
if (top == 0) revert ZeroTopPrice();
sales[id].top = top;
uint256 _tip = tip;
uint256 _chip = chip;
if (_tip > 0 || _chip > 0) {
uint256 coin = _tip + ((tab * _chip) / WAD);
vat.suck(vow, kpr, coin);
emit Kick(id, top, tab, lot, usr, kpr, coin);
} else {
emit Kick(id, top, tab, lot, usr, kpr, 0);
}
}
function redo(uint256 id, address kpr) external lock isStopped(2) {
address usr = sales[id].usr;
if (usr == address(0)) revert NotRunningAuction();
(bool done,) = status(sales[id].tic, sales[id].top);
if (!done) revert CannotReset();
uint256 tab = sales[id].tab;
uint256 lot = sales[id].lot;
sales[id].tic = uint96(block.timestamp);
uint256 feedPrice = getFeedPrice();
uint256 top = rmul(feedPrice, buf);
if (top == 0) revert ZeroTopPrice();
sales[id].top = top;
uint256 _tip = tip;
uint256 _chip = chip;
if (_tip > 0 || _chip > 0) {
uint256 _chost = chost;
if (tab >= _chost && lot * feedPrice >= _chost) {
uint256 coin = _tip + ((tab * _chip) / WAD);
vat.suck(vow, kpr, coin);
emit Redo(id, top, tab, lot, usr, kpr, coin);
} else {
emit Redo(id, top, tab, lot, usr, kpr, 0);
}
} else {
emit Redo(id, top, tab, lot, usr, kpr, 0);
}
}
function take(
uint256 id, uint256 amt, uint256 max, address who, bytes calldata data
) external lock isStopped(3) {
address usr = sales[id].usr;
if (usr == address(0)) revert NotRunningAuction();
uint256 price;
{
bool done;
(done, price) = status(sales[id].tic, sales[id].top);
if (done) revert NeedsReset();
}
if (max < price) revert TooExpensive();
uint256 lot = sales[id].lot;
uint256 tab = sales[id].tab;
uint256 owe;
{
uint256 slice = lot <= amt ? lot : amt;
owe = slice * price;
if (owe > tab) {
owe = tab;
slice = owe / price;
} else if (owe < tab && slice < lot) {
uint256 _chost = chost;
if (tab - owe < _chost) {
if (tab <= _chost) revert NoPartialPurchase();
owe = tab - _chost;
slice = owe / price;
}
}
tab = tab - owe;
lot = lot - slice;
vat.flux(ilk, address(this), who, slice);
DogLike dog_ = dog;
if (data.length > 0 && who != address(vat) && who != address(dog_)) {
ClipperCallee(who).clipperCall(msg.sender, owe, slice, data);
}
vat.move(msg.sender, vow, owe);
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];
}
function count() external view returns (uint256) { return active.length; }
function list() external view returns (uint256[] memory) { return active; }
function getStatus(uint256 id) external view returns (bool needsRedo, uint256 price, uint256 lot, uint256 tab) {
address usr = sales[id].usr;
bool done;
(done, price) = status(sales[id].tic, sales[id].top);
needsRedo = usr != address(0) && done;
lot = sales[id].lot;
tab = sales[id].tab;
}
function status(uint96 tic, uint256 top) internal view returns (bool done, uint256 price) {
price = calc.price(top, block.timestamp - tic);
done = (block.timestamp - tic > tail || rdiv(price, top) < cusp);
}
function upchost() external {
(,,,, uint256 _dust) = vat.ilks(ilk);
chost = (_dust * dog.chop(ilk)) / WAD;
emit Upchost(chost);
}
function yank(uint256 id) external auth lock {
if (sales[id].usr == address(0)) revert NotRunningAuction();
dog.digs(ilk, sales[id].tab);
vat.flux(ilk, address(this), msg.sender, sales[id].lot);
_remove(id);
emit Yank(id);
}
}
// ──────────────────────────────────────────────
// PipJoin — with configurable floor (default 0.95)
// ──────────────────────────────────────────────
contract PipJoin {
event PriceUpdated(uint256 price, bool ok);
event PriceValidation(uint256 attemptedWad, bool accepted, uint256 minBound, uint256 maxBound);
event PriceBoundsUpdated(uint256 newMin, uint256 newMax);
event FloorUpdated(uint256 newFloor);
struct PriceData {
uint256 val;
bool ok;
}
ISimpleTWAPOracle public immutable oracle;
address public immutable token;
uint8 public immutable dec;
PriceData public spot;
address public ward;
mapping(address => uint256) public bud;
uint256 public constant WAD = 10 ** 18;
uint256 public constant INITIAL_PRICE = 1 * WAD;
uint256 public minPriceWad;
uint256 public maxPriceWad;
uint256 public floor;
constructor(address _oracle, address _token) {
oracle = ISimpleTWAPOracle(_oracle);
token = _token;
uint8 _dec = IERC20(_token).decimals();
require(_dec <= 18, "PipJoin/unsupported-decimals-gt-18");
dec = _dec;
// AUDIT FIX: Changed from 1 to 0.5 WAD. If minPriceWad=1, a 0.949 depeg
// fails the inRange check and returns (0, false), breaking the liquidation feed.
minPriceWad = 5 * 10 ** 17;
maxPriceWad = 10 ** 36;
floor = 95 * 10 ** 16; // 0.95 * WAD
ward = msg.sender;
spot = PriceData(INITIAL_PRICE, false);
emit PriceUpdated(INITIAL_PRICE, false);
emit PriceBoundsUpdated(minPriceWad, maxPriceWad);
emit FloorUpdated(floor);
}
modifier auth() { require(msg.sender == ward, "PipJoin/not-authorized"); _; }
modifier kissed() { require(bud[msg.sender] == 1, "PipJoin/not-whitelisted"); _; }
function setWard(address newWard) external auth { ward = newWard; }
function kiss(address who) external auth { bud[who] = 1; }
function diss(address who) external auth { bud[who] = 0; }
function setPriceBounds(uint256 newMin, uint256 newMax) external auth {
require(newMin > 0 && newMax > newMin, "PipJoin/invalid-bounds");
minPriceWad = newMin;
maxPriceWad = newMax;
emit PriceBoundsUpdated(newMin, newMax);
}
function setFloor(uint256 newFloor) external auth {
require(newFloor <= WAD, "PipJoin/floor-cannot-exceed-1");
floor = newFloor;
emit FloorUpdated(newFloor);
}
function poke() external {
try this.getPrice() returns (uint256 priceWad, bool success) {
if (!success && priceWad > 0) {
emit PriceValidation(priceWad, false, minPriceWad, maxPriceWad);
}
if (success) {
spot = PriceData(priceWad, true);
emit PriceUpdated(priceWad, true);
} else {
spot.ok = false;
emit PriceUpdated(spot.val, false);
}
} catch {
spot.ok = false;
emit PriceUpdated(spot.val, false);
}
}
function getPrice() external view returns (uint256 val, bool success) {
uint256 amountIn = 10 ** uint256(dec);
try oracle.getPriceInUsd(token, amountIn) returns (uint256 priceForOneToken) {
if (priceForOneToken == 0) return (0, false);
uint256 wad = priceForOneToken;
if (wad < floor) {
wad = priceForOneToken; // severe depeg -> report real price
} else {
wad = WAD; // normal range -> always report exactly 1.0
}
bool inRange = (wad >= minPriceWad && wad <= maxPriceWad);
return (inRange ? wad : 0, inRange);
} catch {
return (0, false);
}
}
function peek() external view returns (bytes32, bool) {
return (bytes32(spot.val), spot.ok);
}
function peep() external view kissed returns (bytes32, bool) {
(uint256 priceWad, bool success) = this.getPrice();
return success ? (bytes32(priceWad), true) : (bytes32(spot.val), false);
}
function read() external view returns (uint256) {
require(spot.ok, "PipJoin/invalid-price");
return spot.val;
}
}
// ──────────────────────────────────────────────
// GemJoin (upgraded to 0.8.20)
// ──────────────────────────────────────────────
contract GemJoin {
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, "GemJoin/not-authorized"); _; }
VatLike public vat;
bytes32 public ilk;
GemLike public gem;
uint8 public dec;
uint256 public live;
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_) {
wards[msg.sender] = 1;
live = 1;
vat = VatLike(vat_);
ilk = ilk_;
gem = GemLike(gem_);
dec = gem.decimals();
require(dec <= 18, "GemJoin/unsupported-decimals-gt-18");
emit Rely(msg.sender);
}
function cage() external auth { live = 0; emit Cage(); }
function join(address usr, uint256 wad) external {
require(live == 1, "GemJoin/not-live");
uint256 scaledWad = wad * (10 ** (18 - dec));
require(scaledWad / (10 ** (18 - dec)) == wad, "GemJoin/overflow-on-scale");
vat.slip(ilk, usr, int256(scaledWad));
require(gem.transferFrom(msg.sender, address(this), wad), "GemJoin/failed-transfer");
emit Join(usr, wad);
}
function exit(address usr, uint256 wad) external {
require(live == 1, "GemJoin/not-live");
uint256 factor = 10 ** (18 - dec);
require(wad <= uint256(type(int256).max) / factor, "GemJoin/overflow-on-scale");
uint256 scaledWad = wad * factor;
vat.slip(ilk, msg.sender, -int256(scaledWad));
require(gem.transfer(usr, wad), "GemJoin/failed-transfer");
emit Exit(usr, wad);
}
}
// ──────────────────────────────────────────────
// DssPsm
// ──────────────────────────────────────────────
contract DssPsm {
error NotAuthorized();
error InvalidParam();
error TransferFailed();
error SystemCaged();
error ZeroAmount();
bytes32 public immutable ilk;
address public immutable vat;
address public immutable gemJoin;
GemLike public immutable gem;
DaiLike public immutable dai;
address public immutable daiJoin;
address public immutable vow;
uint256 public immutable to18ConversionFactor;
mapping(address => uint256) public wards;
uint256 public tin;
uint256 public tout;
uint256 public live = 1;
event Rely(address indexed usr);
event Deny(address indexed usr);
event File(bytes32 indexed what, uint256 data);
event SellGem(address indexed owner, uint256 gemAmt, uint256 fee);
event BuyGem(address indexed owner, uint256 gemAmt, uint256 fee);
event Cage();
modifier auth() {
if (wards[msg.sender] == 0) revert NotAuthorized();
_;
}
modifier whenLive() {
if (live == 0) revert SystemCaged();
_;
}
constructor(address _gemJoin, address _daiJoin, address _vow) {
wards[msg.sender] = 1;
emit Rely(msg.sender);
gemJoin = _gemJoin;
daiJoin = _daiJoin;
vow = _vow;
vat = GemJoinLike(_gemJoin).vat();
gem = GemLike(GemJoinLike(_gemJoin).gem());
dai = DaiLike(DaiJoinLike(_daiJoin).dai());
ilk = GemJoinLike(_gemJoin).ilk();
uint8 gemDec = GemJoinLike(_gemJoin).dec();
require(gemDec <= 18, "PSM/gem-decimals-too-high");
to18ConversionFactor = 10 ** (18 - gemDec);
require(dai.approve(_daiJoin, type(uint256).max), "PSM/dai-approve-failed");
require(gem.approve(_gemJoin, type(uint256).max), "PSM/gem-approve-failed");
VatLike(vat).hope(_daiJoin);
VatLike(vat).hope(_gemJoin);
VatLike(vat).hope(address(this));
}
function _safeTransferFrom(GemLike token, address from, address to, uint256 wad) internal {
if (!token.transferFrom(from, to, wad)) revert TransferFailed();
}
function _safeTransfer(GemLike token, address to, uint256 wad) internal {
if (!token.transfer(to, wad)) revert TransferFailed();
}
function rely(address usr) external auth { wards[usr] = 1; emit Rely(usr); }
function deny(address usr) external auth { wards[usr] = 0; emit Deny(usr); }
function file(bytes32 what, uint256 data) external auth {
if (what == "tin") tin = data;
else if (what == "tout") tout = data;
else revert InvalidParam();
emit File(what, data);
}
function cage() external auth { live = 0; emit Cage(); }
function hope(address usr) external auth { VatLike(vat).hope(usr); }
function nope(address usr) external auth { VatLike(vat).nope(usr); }
function sellGem(address usr, uint256 gemAmt) external whenLive {
if (gemAmt == 0) revert ZeroAmount();
uint256 gemAmt18 = gemAmt * to18ConversionFactor;
uint256 fee = (gemAmt18 * tin) / 1e18;
uint256 daiAmt = gemAmt18 - fee;
_safeTransferFrom(gem, msg.sender, address(this), gemAmt);
GemJoinLike(gemJoin).join(address(this), gemAmt);
VatLike(vat).frob(ilk, address(this), address(this), address(this),
int256(gemAmt18), int256(gemAmt18));
VatLike(vat).move(address(this), vow, fee * 1e27);
DaiJoinLike(daiJoin).exit(usr, daiAmt);
emit SellGem(usr, gemAmt, fee);
}
function buyGem(address usr, uint256 gemAmt) external whenLive {
if (gemAmt == 0) revert ZeroAmount();
uint256 gemAmt18 = gemAmt * to18ConversionFactor;
uint256 fee = (gemAmt18 * tout) / 1e18;
uint256 daiAmt = gemAmt18 + fee;
_safeTransferFrom(dai, msg.sender, address(this), daiAmt);
DaiJoinLike(daiJoin).join(address(this), daiAmt);
VatLike(vat).frob(ilk, address(this), address(this), address(this),
-int256(gemAmt18), -int256(gemAmt18));
GemJoinLike(gemJoin).exit(usr, gemAmt);
VatLike(vat).move(address(this), vow, fee * 1e27);
emit BuyGem(usr, gemAmt, fee);
}
uint256 internal constant WAD = 1e18;
uint256 internal constant RAY = 1e27;
}
// ──────────────────────────────────────────────
// Deploy PSM Spell (0.8.20) - PRODUCTION OPTIMIZED
// ──────────────────────────────────────────────
contract DeployPsmSpell {
struct PsmParams {
address vat;
address spotter;
address daiJoin;
address vow;
address gem;
bytes32 ilk;
address oracle;
uint256 tin;
uint256 tout;
uint256 line;
address gemJoin;
address registry;
address dog;
address calc;
uint256 buf;
uint256 tail;
uint256 cusp;
uint256 hole;
uint256 chop;
address exec; // The GovExec contract
}
address public immutable vat;
address public immutable spotter;
address public immutable daiJoin;
address public immutable vow;
bytes32 public immutable ilk;
address public immutable gem;
address public immutable oracle;
uint256 public immutable tin;
uint256 public immutable tout;
uint256 public immutable line;
address public immutable registry;
address public immutable inputGemJoin;
address public immutable dog;
address public immutable calc;
uint256 public immutable buf;
uint256 public immutable tail;
uint256 public immutable cusp;
uint256 public immutable hole;
uint256 public immutable chop;
address public immutable exec;
address public immutable pip;
address public immutable psm;
address public immutable clip;
address public immutable gemJoin;
uint256 constant WAD = 10 ** 18;
uint256 constant RAY = 10 ** 27;
event SpellExecuted(
bytes32 indexed ilk,
address indexed psm,
address indexed clip,
uint256 line,
uint256 tin,
uint256 tout
);
constructor(PsmParams memory params) {
require(params.vat != address(0), "DeployPsmSpell/invalid-vat");
require(params.spotter != address(0), "DeployPsmSpell/invalid-spotter");
require(params.daiJoin != address(0), "DeployPsmSpell/invalid-daiJoin");
require(params.vow != address(0), "DeployPsmSpell/invalid-vow");
require(params.gem != address(0), "DeployPsmSpell/invalid-gem");
require(params.oracle != address(0), "DeployPsmSpell/invalid-oracle");
require(params.line > 0, "DeployPsmSpell/invalid-line");
require(params.dog != address(0), "DeployPsmSpell/invalid-dog");
require(params.calc != address(0), "DeployPsmSpell/invalid-calc");
require(params.exec != address(0), "DeployPsmSpell/invalid-exec");
vat = params.vat;
spotter = params.spotter;
daiJoin = params.daiJoin;
vow = params.vow;
ilk = params.ilk;
gem = params.gem;
oracle = params.oracle;
tin = params.tin;
tout = params.tout;
line = params.line;
registry = params.registry;
inputGemJoin = params.gemJoin;
exec = params.exec;
dog = params.dog;
calc = params.calc;
buf = params.buf == 0 ? 1055 * 10 ** 24 : params.buf;
tail = params.tail == 0 ? 6 hours : params.tail;
cusp = params.cusp == 0 ? 9 * 10 ** 26 : params.cusp;
hole = params.hole;
chop = params.chop == 0 ? WAD : params.chop;
// ==========================================
// PHASE 1: DEPLOY & HANDOFF
// msg.sender is your wallet. We set GovExec as ward.
// ==========================================
// 1. PipJoin
pip = address(new PipJoin(oracle, gem));
PipJoin(pip).kiss(spotter);
PipJoin(pip).setWard(exec); // Overwrites single ward variable. Wallet implicitly removed.
// 2. GemJoin
if (inputGemJoin == address(0)) {
gemJoin = address(new GemJoin(vat, ilk, gem));
GemJoin(gemJoin).rely(exec); // Add exec to mapping
GemJoin(gemJoin).deny(msg.sender); // Explicitly remove wallet from mapping
} else {
gemJoin = inputGemJoin;
}
// 3. PSM
psm = address(new DssPsm(gemJoin, daiJoin, vow));
DssPsm(psm).rely(exec); // Add exec to mapping FIRST
DssPsm(psm).deny(msg.sender); // Remove wallet from mapping SECOND
// 4. Clipper
clip = address(new Clipper(vat, spotter, dog, ilk));
Clipper(clip).rely(exec); // Add exec to mapping FIRST
Clipper(clip).deny(msg.sender); // Remove wallet from mapping SECOND
}
// ==========================================
// PHASE 2: CONFIGURATION
// Runs via GovExec.delegatecall().
// msg.sender seen by Vat/Spotter/Dog is GovExec.
// ==========================================
function execute() external {
// 1. Spotter Config
SpotterLike(spotter).rely(pip);
SpotterLike(spotter).file(ilk, "pip", pip);
SpotterLike(spotter).file(ilk, "mat", RAY);
PipJoin(pip).poke();
SpotterLike(spotter).poke(ilk);
// 2. Vat Config
if (inputGemJoin == address(0)) {
VatLike(vat).init(ilk); // <--- ADD IT HERE
VatLike(vat).rely(gemJoin);
}
VatLike(vat).file(ilk, "line", line);
VatLike(vat).file(ilk, "dust", 0);
// 3. PSM Config
DssPsm(psm).file("tin", tin);
DssPsm(psm).file("tout", tout);
DssPsm(psm).hope(clip);
// 4. Clipper & Dog Config
VatLike(vat).rely(clip);
DogLike(dog).rely(clip);
Clipper(clip).file("vow", vow);
Clipper(clip).file("calc", calc);
Clipper(clip).file("buf", buf);
Clipper(clip).file("tail", tail);
Clipper(clip).file("cusp", cusp);
Clipper(clip).file("tip", 0);
Clipper(clip).file("chip", 0);
DogLike(dog).file(ilk, "clip", clip);
DogLike(dog).file(ilk, "chop", chop);
DogLike(dog).file(ilk, "hole", hole);
Clipper(clip).upchost();
// 5. Registry
if (registry != address(0)) {
PaiRegistryLike(registry).addIlk(ilk, gem, gemJoin, pip, clip, address(0), psm);
}
emit SpellExecuted(ilk, psm, clip, line, tin, tout);
}
// ──────────────────────────────────────────────
// Helpers
// ──────────────────────────────────────────────
function bytes32ToString(bytes32 _bytes32) internal pure returns (string memory) {
bytes memory bytesArray = new bytes(32);
uint256 len = 0;
for (uint256 i = 0; i < 32; i++) {
bytes1 b = _bytes32[i];
if (b == 0x00) break;
bytesArray[len] = b;
len++;
}
bytes memory trimmed = new bytes(len);
for (uint256 i = 0; i < len; i++) trimmed[i] = bytesArray[i];
return string(trimmed);
}
function uintToString(uint256 _i) internal pure returns (string memory) {
if (_i == 0) return "0";
uint256 j = _i;
uint256 len;
while (j != 0) { len++; j /= 10; }
bytes memory bstr = new bytes(len);
uint256 k = len - 1;
while (_i != 0) {
bstr[k--] = bytes1(uint8(48 + _i % 10));
_i /= 10;
}
return string(bstr);
}
}
Compiler Settings
{"remappings":[],"optimizer":{"runs":200,"enabled":true},"metadata":{"bytecodeHash":"ipfs"},"libraries":{},"evmVersion":"istanbul","compilationTarget":{"DeployNewPsmSpell.sol":"DssPsm"}}
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_gemJoin","internalType":"address"},{"type":"address","name":"_daiJoin","internalType":"address"},{"type":"address","name":"_vow","internalType":"address"}]},{"type":"error","name":"InvalidParam","inputs":[]},{"type":"error","name":"NotAuthorized","inputs":[]},{"type":"error","name":"SystemCaged","inputs":[]},{"type":"error","name":"TransferFailed","inputs":[]},{"type":"error","name":"ZeroAmount","inputs":[]},{"type":"event","name":"BuyGem","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"uint256","name":"gemAmt","internalType":"uint256","indexed":false},{"type":"uint256","name":"fee","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Cage","inputs":[],"anonymous":false},{"type":"event","name":"Deny","inputs":[{"type":"address","name":"usr","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"File","inputs":[{"type":"bytes32","name":"what","internalType":"bytes32","indexed":true},{"type":"uint256","name":"data","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Rely","inputs":[{"type":"address","name":"usr","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"SellGem","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"uint256","name":"gemAmt","internalType":"uint256","indexed":false},{"type":"uint256","name":"fee","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"buyGem","inputs":[{"type":"address","name":"usr","internalType":"address"},{"type":"uint256","name":"gemAmt","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"cage","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract DaiLike"}],"name":"dai","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"daiJoin","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"deny","inputs":[{"type":"address","name":"usr","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"file","inputs":[{"type":"bytes32","name":"what","internalType":"bytes32"},{"type":"uint256","name":"data","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract GemLike"}],"name":"gem","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"gemJoin","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"hope","inputs":[{"type":"address","name":"usr","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"ilk","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"live","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"nope","inputs":[{"type":"address","name":"usr","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"rely","inputs":[{"type":"address","name":"usr","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"sellGem","inputs":[{"type":"address","name":"usr","internalType":"address"},{"type":"uint256","name":"gemAmt","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"tin","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"to18ConversionFactor","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"tout","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"vat","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"vow","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"wards","inputs":[{"type":"address","name":"","internalType":"address"}]}]
Contract Creation Code
0x610180604052600160035534801561001657600080fd5b506040516118e33803806118e383398101604081905261003591610606565b3360008181526020819052604080822060019055517fdd0e34038ac38b2a1ce960229778ac48a8719bc900b6c4f8d0475c6e8b385a609190a26001600160a01b0380841660c08190528382166101205290821661014052604080516336569e7760e01b815290516336569e77916004808201926020929091908290030181865afa1580156100c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100eb9190610649565b6001600160a01b031660a0816001600160a01b031681525050826001600160a01b0316637bd2bea76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610142573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101669190610649565b6001600160a01b031660e0816001600160a01b031681525050816001600160a01b031663f4b9fa756040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101e19190610649565b6001600160a01b0316610100816001600160a01b031681525050826001600160a01b031663c5ce281e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610239573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061025d919061066b565b608081815250506000836001600160a01b031663b3bcfa826040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102c89190610684565b905060128160ff1611156103235760405162461bcd60e51b815260206004820152601960248201527f50534d2f67656d2d646563696d616c732d746f6f2d686967680000000000000060448201526064015b60405180910390fd5b61032e8160126106bd565b61033990600a6107c3565b610160526101005160405163095ea7b360e01b81526001600160a01b03858116600483015260001960248301529091169063095ea7b3906044016020604051808303816000875af1158015610392573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103b691906107d2565b6104025760405162461bcd60e51b815260206004820152601660248201527f50534d2f6461692d617070726f76652d6661696c656400000000000000000000604482015260640161031a565b60e05160405163095ea7b360e01b81526001600160a01b03868116600483015260001960248301529091169063095ea7b3906044016020604051808303816000875af1158015610456573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061047a91906107d2565b6104c65760405162461bcd60e51b815260206004820152601660248201527f50534d2f67656d2d617070726f76652d6661696c656400000000000000000000604482015260640161031a565b60a0516040516328ec8bf160e21b81526001600160a01b0385811660048301529091169063a3b22fc490602401600060405180830381600087803b15801561050d57600080fd5b505af1158015610521573d6000803e3d6000fd5b505060a0516040516328ec8bf160e21b81526001600160a01b038881166004830152909116925063a3b22fc49150602401600060405180830381600087803b15801561056c57600080fd5b505af1158015610580573d6000803e3d6000fd5b505060a0516040516328ec8bf160e21b81523060048201526001600160a01b03909116925063a3b22fc49150602401600060405180830381600087803b1580156105c957600080fd5b505af11580156105dd573d6000803e3d6000fd5b50505050505050506107f4565b80516001600160a01b038116811461060157600080fd5b919050565b60008060006060848603121561061b57600080fd5b610624846105ea565b9250610632602085016105ea565b9150610640604085016105ea565b90509250925092565b60006020828403121561065b57600080fd5b610664826105ea565b9392505050565b60006020828403121561067d57600080fd5b5051919050565b60006020828403121561069657600080fd5b815160ff8116811461066457600080fd5b634e487b7160e01b600052601160045260246000fd5b60ff82811682821603908111156106d6576106d66106a7565b92915050565b6001815b6001841115610717578085048111156106fb576106fb6106a7565b600184161561070957908102905b60019390931c9280026106e0565b935093915050565b60008261072e575060016106d6565b8161073b575060006106d6565b8160018114610751576002811461075b57610777565b60019150506106d6565b60ff84111561076c5761076c6106a7565b50506001821b6106d6565b5060208310610133831016604e8410600b841016171561079a575081810a6106d6565b6107a760001984846106dc565b80600019048211156107bb576107bb6106a7565b029392505050565b600061066460ff84168361071f565b6000602082840312156107e457600080fd5b8151801515811461066457600080fd5b60805160a05160c05160e0516101005161012051610140516101605161100c6108d7600039600081816101b60152818161053101526109030152600081816101f4015281816107ce0152610af60152600081816102d2015281816105d30152610bb8015260008181610333015261059001526000818161023601526109620152600081816101360152818161073e01526109a501526000818161018f015281816106390152818161079e01528181610a5e01528181610ac601528181610d180152610dc60152600081816102f9015281816106680152610a16015261100c6000f3fe608060405234801561001057600080fd5b506004361061012c5760003560e01c8063957aa58c116100ad578063c11645bc11610071578063c11645bc146102cd578063c5ce281e146102f4578063dc4d20fa1461031b578063f4b9fa751461032e578063fae036d51461035557600080fd5b8063957aa58c1461026b57806395991276146102745780639c52a7f114610287578063a3b22fc41461029a578063bf353dbb146102ad57600080fd5b8063626cb3c5116100f4578063626cb3c5146101ef57806365fae35e1461021657806369245009146102295780637bd2bea7146102315780638d7ef9bb1461025857600080fd5b806301664f661461013157806329ae81141461017557806336569e771461018a5780634010f777146101b1578063568d4b6f146101e6575b600080fd5b6101587f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b610188610183366004610e93565b61035e565b005b6101587f000000000000000000000000000000000000000000000000000000000000000081565b6101d87f000000000000000000000000000000000000000000000000000000000000000081565b60405190815260200161016c565b6101d860015481565b6101587f000000000000000000000000000000000000000000000000000000000000000081565b610188610224366004610ed1565b610413565b610188610487565b6101587f000000000000000000000000000000000000000000000000000000000000000081565b610188610266366004610ef3565b6104e6565b6101d860035481565b610188610282366004610ef3565b6108b8565b610188610295366004610ed1565b610c57565b6101886102a8366004610ed1565b610cca565b6101d86102bb366004610ed1565b60006020819052908152604090205481565b6101587f000000000000000000000000000000000000000000000000000000000000000081565b6101d87f000000000000000000000000000000000000000000000000000000000000000081565b610188610329366004610ed1565b610d78565b6101587f000000000000000000000000000000000000000000000000000000000000000081565b6101d860025481565b33600090815260208190526040812054900361038d5760405163ea8e4eb560e01b815260040160405180910390fd5b81623a34b760e91b036103a45760018190556103d5565b81631d1bdd5d60e21b036103bc5760028190556103d5565b604051633494a40d60e21b815260040160405180910390fd5b817fe986e40cc8c151830d4f61050f4fb2e4add8567caad2d5f5496f9158e91fe4c78260405161040791815260200190565b60405180910390a25050565b3360009081526020819052604081205490036104425760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b03811660008181526020819052604080822060019055517fdd0e34038ac38b2a1ce960229778ac48a8719bc900b6c4f8d0475c6e8b385a609190a250565b3360009081526020819052604081205490036104b65760405163ea8e4eb560e01b815260040160405180910390fd5b600060038190556040517f2308ed18a14e800c39b86eb6ea43270105955ca385b603b64eca89f98ae8fbda9190a1565b60035460000361050957604051634174f77b60e01b815260040160405180910390fd5b8060000361052a57604051631f2a200560e01b815260040160405180910390fd5b60006105567f000000000000000000000000000000000000000000000000000000000000000083610f33565b90506000670de0b6b3a7640000600254836105719190610f33565b61057b9190610f50565b905060006105898284610f72565b90506105b77f0000000000000000000000000000000000000000000000000000000000000000333084610df5565b604051633b4da69f60e01b8152306004820152602481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690633b4da69f90604401600060405180830381600087803b15801561061f57600080fd5b505af1158015610633573d6000803e3d6000fd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663760887037f00000000000000000000000000000000000000000000000000000000000000003030308861069490610f85565b61069d8a610f85565b6040516001600160e01b031960e089901b16815260048101969096526001600160a01b039485166024870152928416604486015292166064840152608483019190915260a482015260c401600060405180830381600087803b15801561070257600080fd5b505af1158015610716573d6000803e3d6000fd5b505060405163ef693bed60e01b81526001600160a01b038881166004830152602482018890527f000000000000000000000000000000000000000000000000000000000000000016925063ef693bed9150604401600060405180830381600087803b15801561078457600080fd5b505af1158015610798573d6000803e3d6000fd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663bb35783b307f0000000000000000000000000000000000000000000000000000000000000000856b033b2e3c9fd0803ce80000006108059190610f33565b6040516001600160e01b031960e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401600060405180830381600087803b15801561085457600080fd5b505af1158015610868573d6000803e3d6000fd5b505060408051878152602081018690526001600160a01b03891693507f085d06ecf4c34b237767a31c0888e121d89546a77f186f1987c6b8715e1a8caa9250015b60405180910390a25050505050565b6003546000036108db57604051634174f77b60e01b815260040160405180910390fd5b806000036108fc57604051631f2a200560e01b815260040160405180910390fd5b60006109287f000000000000000000000000000000000000000000000000000000000000000083610f33565b90506000670de0b6b3a7640000600154836109439190610f33565b61094d9190610f50565b9050600061095b8284610fa1565b90506109897f0000000000000000000000000000000000000000000000000000000000000000333087610df5565b604051633b4da69f60e01b8152306004820152602481018590527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690633b4da69f90604401600060405180830381600087803b1580156109f157600080fd5b505af1158015610a05573d6000803e3d6000fd5b5050604051637608870360e01b81527f0000000000000000000000000000000000000000000000000000000000000000600482015230602482018190526044820181905260648201526084810186905260a481018690527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031692506376088703915060c401600060405180830381600087803b158015610aac57600080fd5b505af1158015610ac0573d6000803e3d6000fd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663bb35783b307f0000000000000000000000000000000000000000000000000000000000000000856b033b2e3c9fd0803ce8000000610b2d9190610f33565b6040516001600160e01b031960e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401600060405180830381600087803b158015610b7c57600080fd5b505af1158015610b90573d6000803e3d6000fd5b505060405163ef693bed60e01b81526001600160a01b038881166004830152602482018590527f000000000000000000000000000000000000000000000000000000000000000016925063ef693bed9150604401600060405180830381600087803b158015610bfe57600080fd5b505af1158015610c12573d6000803e3d6000fd5b505060408051878152602081018690526001600160a01b03891693507fef75f5a47cc9a929968796ceb84f19e7541617b4577f2c228ea95200e15720819250016108a9565b336000908152602081905260408120549003610c865760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b038116600081815260208190526040808220829055517f184450df2e323acec0ed3b5c7531b81f9b4cdef7914dfd4c0a4317416bb5251b9190a250565b336000908152602081905260408120549003610cf95760405163ea8e4eb560e01b815260040160405180910390fd5b6040516328ec8bf160e21b81526001600160a01b0382811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063a3b22fc4906024015b600060405180830381600087803b158015610d5d57600080fd5b505af1158015610d71573d6000803e3d6000fd5b5050505050565b336000908152602081905260408120549003610da75760405163ea8e4eb560e01b815260040160405180910390fd5b604051636e26907d60e11b81526001600160a01b0382811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063dc4d20fa90602401610d43565b6040516323b872dd60e01b81526001600160a01b0384811660048301528381166024830152604482018390528516906323b872dd906064016020604051808303816000875af1158015610e4c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e709190610fb4565b610e8d576040516312171d8360e31b815260040160405180910390fd5b50505050565b60008060408385031215610ea657600080fd5b50508035926020909101359150565b80356001600160a01b0381168114610ecc57600080fd5b919050565b600060208284031215610ee357600080fd5b610eec82610eb5565b9392505050565b60008060408385031215610f0657600080fd5b610f0f83610eb5565b946020939093013593505050565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610f4a57610f4a610f1d565b92915050565b600082610f6d57634e487b7160e01b600052601260045260246000fd5b500490565b80820180821115610f4a57610f4a610f1d565b6000600160ff1b8201610f9a57610f9a610f1d565b5060000390565b81810381811115610f4a57610f4a610f1d565b600060208284031215610fc657600080fd5b81518015158114610eec57600080fdfea26469706673582212205d9ad6714ce9c2b227deb24c4a848355b353f719cadeb885d144d6c2884be63664736f6c634300081c00330000000000000000000000006aafa71c9db937e4088dd2db72375038b744911c0000000000000000000000003fa88872368b9bfea50c35b35fff55c425c8ac530000000000000000000000002030803a2eab2a481f4ff358731c416eead94210
Deployed ByteCode
0x608060405234801561001057600080fd5b506004361061012c5760003560e01c8063957aa58c116100ad578063c11645bc11610071578063c11645bc146102cd578063c5ce281e146102f4578063dc4d20fa1461031b578063f4b9fa751461032e578063fae036d51461035557600080fd5b8063957aa58c1461026b57806395991276146102745780639c52a7f114610287578063a3b22fc41461029a578063bf353dbb146102ad57600080fd5b8063626cb3c5116100f4578063626cb3c5146101ef57806365fae35e1461021657806369245009146102295780637bd2bea7146102315780638d7ef9bb1461025857600080fd5b806301664f661461013157806329ae81141461017557806336569e771461018a5780634010f777146101b1578063568d4b6f146101e6575b600080fd5b6101587f0000000000000000000000006aafa71c9db937e4088dd2db72375038b744911c81565b6040516001600160a01b0390911681526020015b60405180910390f35b610188610183366004610e93565b61035e565b005b6101587f00000000000000000000000016ca93f2f65d5495c874109fff38d11d39850b6781565b6101d87f000000000000000000000000000000000000000000000000000000000000000181565b60405190815260200161016c565b6101d860015481565b6101587f0000000000000000000000002030803a2eab2a481f4ff358731c416eead9421081565b610188610224366004610ed1565b610413565b610188610487565b6101587f000000000000000000000000efd766ccb38eaf1dfd701853bfce31359239f30581565b610188610266366004610ef3565b6104e6565b6101d860035481565b610188610282366004610ef3565b6108b8565b610188610295366004610ed1565b610c57565b6101886102a8366004610ed1565b610cca565b6101d86102bb366004610ed1565b60006020819052908152604090205481565b6101587f0000000000000000000000003fa88872368b9bfea50c35b35fff55c425c8ac5381565b6101d87f425249444745442d44414900000000000000000000000000000000000000000081565b610188610329366004610ed1565b610d78565b6101587f000000000000000000000000c40c58afff0a8908c392a752f4951eff381aa0b281565b6101d860025481565b33600090815260208190526040812054900361038d5760405163ea8e4eb560e01b815260040160405180910390fd5b81623a34b760e91b036103a45760018190556103d5565b81631d1bdd5d60e21b036103bc5760028190556103d5565b604051633494a40d60e21b815260040160405180910390fd5b817fe986e40cc8c151830d4f61050f4fb2e4add8567caad2d5f5496f9158e91fe4c78260405161040791815260200190565b60405180910390a25050565b3360009081526020819052604081205490036104425760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b03811660008181526020819052604080822060019055517fdd0e34038ac38b2a1ce960229778ac48a8719bc900b6c4f8d0475c6e8b385a609190a250565b3360009081526020819052604081205490036104b65760405163ea8e4eb560e01b815260040160405180910390fd5b600060038190556040517f2308ed18a14e800c39b86eb6ea43270105955ca385b603b64eca89f98ae8fbda9190a1565b60035460000361050957604051634174f77b60e01b815260040160405180910390fd5b8060000361052a57604051631f2a200560e01b815260040160405180910390fd5b60006105567f000000000000000000000000000000000000000000000000000000000000000183610f33565b90506000670de0b6b3a7640000600254836105719190610f33565b61057b9190610f50565b905060006105898284610f72565b90506105b77f000000000000000000000000c40c58afff0a8908c392a752f4951eff381aa0b2333084610df5565b604051633b4da69f60e01b8152306004820152602481018290527f0000000000000000000000003fa88872368b9bfea50c35b35fff55c425c8ac536001600160a01b031690633b4da69f90604401600060405180830381600087803b15801561061f57600080fd5b505af1158015610633573d6000803e3d6000fd5b505050507f00000000000000000000000016ca93f2f65d5495c874109fff38d11d39850b676001600160a01b031663760887037f425249444745442d4441490000000000000000000000000000000000000000003030308861069490610f85565b61069d8a610f85565b6040516001600160e01b031960e089901b16815260048101969096526001600160a01b039485166024870152928416604486015292166064840152608483019190915260a482015260c401600060405180830381600087803b15801561070257600080fd5b505af1158015610716573d6000803e3d6000fd5b505060405163ef693bed60e01b81526001600160a01b038881166004830152602482018890527f0000000000000000000000006aafa71c9db937e4088dd2db72375038b744911c16925063ef693bed9150604401600060405180830381600087803b15801561078457600080fd5b505af1158015610798573d6000803e3d6000fd5b505050507f00000000000000000000000016ca93f2f65d5495c874109fff38d11d39850b676001600160a01b031663bb35783b307f0000000000000000000000002030803a2eab2a481f4ff358731c416eead94210856b033b2e3c9fd0803ce80000006108059190610f33565b6040516001600160e01b031960e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401600060405180830381600087803b15801561085457600080fd5b505af1158015610868573d6000803e3d6000fd5b505060408051878152602081018690526001600160a01b03891693507f085d06ecf4c34b237767a31c0888e121d89546a77f186f1987c6b8715e1a8caa9250015b60405180910390a25050505050565b6003546000036108db57604051634174f77b60e01b815260040160405180910390fd5b806000036108fc57604051631f2a200560e01b815260040160405180910390fd5b60006109287f000000000000000000000000000000000000000000000000000000000000000183610f33565b90506000670de0b6b3a7640000600154836109439190610f33565b61094d9190610f50565b9050600061095b8284610fa1565b90506109897f000000000000000000000000efd766ccb38eaf1dfd701853bfce31359239f305333087610df5565b604051633b4da69f60e01b8152306004820152602481018590527f0000000000000000000000006aafa71c9db937e4088dd2db72375038b744911c6001600160a01b031690633b4da69f90604401600060405180830381600087803b1580156109f157600080fd5b505af1158015610a05573d6000803e3d6000fd5b5050604051637608870360e01b81527f425249444745442d444149000000000000000000000000000000000000000000600482015230602482018190526044820181905260648201526084810186905260a481018690527f00000000000000000000000016ca93f2f65d5495c874109fff38d11d39850b676001600160a01b031692506376088703915060c401600060405180830381600087803b158015610aac57600080fd5b505af1158015610ac0573d6000803e3d6000fd5b505050507f00000000000000000000000016ca93f2f65d5495c874109fff38d11d39850b676001600160a01b031663bb35783b307f0000000000000000000000002030803a2eab2a481f4ff358731c416eead94210856b033b2e3c9fd0803ce8000000610b2d9190610f33565b6040516001600160e01b031960e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401600060405180830381600087803b158015610b7c57600080fd5b505af1158015610b90573d6000803e3d6000fd5b505060405163ef693bed60e01b81526001600160a01b038881166004830152602482018590527f0000000000000000000000003fa88872368b9bfea50c35b35fff55c425c8ac5316925063ef693bed9150604401600060405180830381600087803b158015610bfe57600080fd5b505af1158015610c12573d6000803e3d6000fd5b505060408051878152602081018690526001600160a01b03891693507fef75f5a47cc9a929968796ceb84f19e7541617b4577f2c228ea95200e15720819250016108a9565b336000908152602081905260408120549003610c865760405163ea8e4eb560e01b815260040160405180910390fd5b6001600160a01b038116600081815260208190526040808220829055517f184450df2e323acec0ed3b5c7531b81f9b4cdef7914dfd4c0a4317416bb5251b9190a250565b336000908152602081905260408120549003610cf95760405163ea8e4eb560e01b815260040160405180910390fd5b6040516328ec8bf160e21b81526001600160a01b0382811660048301527f00000000000000000000000016ca93f2f65d5495c874109fff38d11d39850b67169063a3b22fc4906024015b600060405180830381600087803b158015610d5d57600080fd5b505af1158015610d71573d6000803e3d6000fd5b5050505050565b336000908152602081905260408120549003610da75760405163ea8e4eb560e01b815260040160405180910390fd5b604051636e26907d60e11b81526001600160a01b0382811660048301527f00000000000000000000000016ca93f2f65d5495c874109fff38d11d39850b67169063dc4d20fa90602401610d43565b6040516323b872dd60e01b81526001600160a01b0384811660048301528381166024830152604482018390528516906323b872dd906064016020604051808303816000875af1158015610e4c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e709190610fb4565b610e8d576040516312171d8360e31b815260040160405180910390fd5b50505050565b60008060408385031215610ea657600080fd5b50508035926020909101359150565b80356001600160a01b0381168114610ecc57600080fd5b919050565b600060208284031215610ee357600080fd5b610eec82610eb5565b9392505050565b60008060408385031215610f0657600080fd5b610f0f83610eb5565b946020939093013593505050565b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610f4a57610f4a610f1d565b92915050565b600082610f6d57634e487b7160e01b600052601260045260246000fd5b500490565b80820180821115610f4a57610f4a610f1d565b6000600160ff1b8201610f9a57610f9a610f1d565b5060000390565b81810381811115610f4a57610f4a610f1d565b600060208284031215610fc657600080fd5b81518015158114610eec57600080fdfea26469706673582212205d9ad6714ce9c2b227deb24c4a848355b353f719cadeb885d144d6c2884be63664736f6c634300081c0033