pragma solidity ^0.5.12;
contract ReserveLike {
function depositToken(address, string memory, bytes memory, uint) public;
}
contract WrappedDaiLike {
function setProxy(address) public;
function setReserve(address) public;
uint public totalSupply;
function approve(address, uint) public returns (bool);
function mint(address, uint) public;
function burn(address, uint) public;
}
contract DaiLike {
function approve(address, uint) public returns (bool);
function transferFrom(address, address, uint) public returns (bool);
}
contract JoinLike {
VatLike public vat;
DaiLike public dai;
function join(address, uint) public;
function exit(address, uint) public;
}
contract PotLike {
mapping(address => uint) public pie;
uint public chi;
VatLike public vat;
uint public rho;
function drip() public returns (uint);
function join(uint) public;
function exit(uint) public;
}
contract VatLike {
mapping(address => uint) public dai;
function hope(address) public;
function move(address, address, uint) public;
}
contract DaiProxy {
string public constant version = "0511";
// --- Owner ---
address public owner;
modifier onlyOwner {
require(msg.sender == owner);
_;
}
event SetOwner(address owner);
function setOwner(address _owner) public onlyOwner {
owner = _owner;
emit SetOwner(_owner);
}
// --- State ---
enum State { Ready, Running, Killed }
State public state = State.Ready;
modifier notStarted {
require(state == State.Ready);
_;
}
modifier notPaused {
require(state == State.Running);
_;
}
// --- Math ---
uint constant ONE = 10 ** 27;
function add(uint a, uint b) private pure returns (uint) {
require(a <= uint(-1) - b);
return a + b;
}
function sub(uint a, uint b) private pure returns (uint) {
require(a >= b);
return a - b;
}
function mul(uint a, uint b) private pure returns (uint) {
require(b == 0 || a <= uint(-1) / b);
return a * b;
}
function div(uint a, uint b) private pure returns (uint) {
require(b != 0);
return a / b;
}
function ceil(uint a, uint b) private pure returns (uint) {
require(b != 0);
uint r = a / b;
return a > r * b ? r + 1 : r;
}
function muldiv(uint a, uint b, uint c) private pure returns (uint) {
uint safe = 1 << (256 - 32); // 2.696e67
uint mask = (1 << 32) - 1;
require(c != 0 && c < safe);
if (b == 0) return 0;
if (a < b) (a, b) = (b, a);
uint p = a / c;
uint r = a % c;
uint res = 0;
while (true) { // most 8 times
uint v = b & mask;
res = add(res, add(mul(p, v), r * v / c));
b >>= 32;
if (b == 0) break;
require(p < safe);
p <<= 32;
r <<= 32;
p = add(p, r / c);
r %= c;
}
return res;
}
// --- Contracts & Constructor ---
DaiLike public Dai;
JoinLike public Join;
PotLike public Pot;
VatLike public Vat;
ReserveLike public Reserve;
WrappedDaiLike public EDai;
WrappedDaiLike public ODai;
event SetReserve(address reserve);
constructor(address dai, address join, address pot, address vat, address eDai, address oDai) public {
owner = msg.sender;
Dai = DaiLike(dai);
Join = JoinLike(join);
Pot = PotLike(pot);
Vat = VatLike(vat);
EDai = WrappedDaiLike(eDai);
ODai = WrappedDaiLike(oDai);
require(address(Join.dai()) == dai);
require(address(Join.vat()) == vat);
require(address(Pot.vat()) == vat);
Vat.hope(pot); // Pot.join
Vat.hope(join); // Join.exit
require(Dai.approve(join, uint(-1))); // Join.join -> dai.burn
}
function setReserve(address reserve) public onlyOwner {
require(EDai.approve(address(Reserve), 0));
require(ODai.approve(address(Reserve), 0));
Reserve = ReserveLike(reserve);
EDai.setReserve(reserve);
ODai.setReserve(reserve);
// approve for Reserve.depositToken
require(EDai.approve(reserve, uint(-1)));
require(ODai.approve(reserve, uint(-1)));
emit SetReserve(reserve);
}
modifier onlyEDai {
require(msg.sender == address(EDai));
_;
}
modifier onlyODai {
require(msg.sender == address(ODai));
_;
}
// --- Integration ---
function chi() private returns (uint) {
return now > Pot.rho() ? Pot.drip() : Pot.chi();
}
function joinDai(uint dai) private {
require(Dai.transferFrom(msg.sender, address(this), dai));
Join.join(address(this), dai);
uint vat = Vat.dai(address(this));
Pot.join(div(vat, chi()));
}
function exitDai(address to, uint dai) private {
uint vat = Vat.dai(address(this));
uint req = mul(dai, ONE);
if (req > vat) {
uint pot = ceil(req - vat, chi());
Pot.exit(pot);
}
Join.exit(to, dai);
}
function mintODai(address to, uint dai) private returns (uint) {
uint wad = dai;
if (ODai.totalSupply() != 0) {
uint pie = Pot.pie(address(this));
uint vat = Vat.dai(address(this));
// 기존 rad
uint rad = sub(add(mul(pie, chi()), vat), mul(EDai.totalSupply(), ONE));
// rad : supply = dai * ONE : wad
wad = muldiv(ODai.totalSupply(), mul(dai, ONE), rad);
}
joinDai(dai);
ODai.mint(to, wad);
return wad;
}
function depositEDai(string memory toChain, uint dai, bytes memory to) public notPaused {
require(dai > 0);
joinDai(dai);
EDai.mint(address(this), dai);
Reserve.depositToken(address(EDai), toChain, to, dai);
}
function depositODai(string memory toChain, uint dai, bytes memory to) public notPaused {
require(dai > 0);
uint wad = mintODai(address(this), dai);
Reserve.depositToken(address(ODai), toChain, to, wad);
}
function swapFromEDai(address from, address to, uint dai) private {
EDai.burn(from, dai);
exitDai(to, dai);
}
function swapFromODai(address from, address to, uint wad) private {
uint pie = Pot.pie(address(this));
uint vat = Vat.dai(address(this));
// 기존 rad
uint rad = sub(add(mul(pie, chi()), vat), mul(EDai.totalSupply(), ONE));
// rad : supply = dai * ONE : wad
uint dai = muldiv(rad, wad, mul(ODai.totalSupply(), ONE));
ODai.burn(from, wad);
exitDai(to, dai);
}
function withdrawEDai(address to, uint dai) public onlyEDai notPaused {
require(dai > 0);
swapFromEDai(address(Reserve), to, dai);
}
function withdrawODai(address to, uint wad) public onlyODai notPaused {
require(wad > 0);
swapFromODai(address(Reserve), to, wad);
}
function swapToEDai(uint dai) public notPaused {
require(dai > 0);
joinDai(dai);
EDai.mint(msg.sender, dai);
}
function swapToODai(uint dai) public notPaused {
require(dai > 0);
mintODai(msg.sender, dai);
}
function swapFromEDai(uint dai) public notPaused {
require(dai > 0);
swapFromEDai(msg.sender, msg.sender, dai);
}
function swapFromODai(uint wad) public notPaused {
require(wad > 0);
swapFromODai(msg.sender, msg.sender, wad);
}
// --- Migration ---
DaiProxy public NewProxy;
event SetNewProxy(address proxy);
event StartProxy(address prev);
event KillProxy(address next, bool mig);
modifier onlyNewProxy {
require(msg.sender == address(NewProxy));
_;
}
function setNewProxy(address proxy) public onlyOwner {
NewProxy = DaiProxy(proxy);
emit SetNewProxy(proxy);
}
function killProxy(address to) public notPaused onlyOwner {
state = State.Killed;
chi();
Pot.exit(Pot.pie(address(this)));
Join.exit(to, Vat.dai(address(this)) / ONE);
emit KillProxy(to, false);
}
function migrateProxy() public notPaused onlyNewProxy {
state = State.Killed;
EDai.setProxy(address(NewProxy));
ODai.setProxy(address(NewProxy));
chi();
Pot.exit(Pot.pie(address(this)));
Vat.move(address(this), address(NewProxy), Vat.dai(address(this)));
emit KillProxy(address(NewProxy), true);
}
function startProxy(address oldProxy) public notStarted onlyOwner {
state = State.Running;
if (oldProxy != address(0)) {
DaiProxy(oldProxy).migrateProxy();
uint vat = Vat.dai(address(this));
Pot.join(div(vat, chi()));
}
emit StartProxy(oldProxy);
}
}
{
"compilationTarget": {
"DaiProxy.sol": "DaiProxy"
},
"evmVersion": "petersburg",
"libraries": {},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"dai","type":"address"},{"internalType":"address","name":"join","type":"address"},{"internalType":"address","name":"pot","type":"address"},{"internalType":"address","name":"vat","type":"address"},{"internalType":"address","name":"eDai","type":"address"},{"internalType":"address","name":"oDai","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"next","type":"address"},{"indexed":false,"internalType":"bool","name":"mig","type":"bool"}],"name":"KillProxy","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"proxy","type":"address"}],"name":"SetNewProxy","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"}],"name":"SetOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"reserve","type":"address"}],"name":"SetReserve","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"prev","type":"address"}],"name":"StartProxy","type":"event"},{"constant":true,"inputs":[],"name":"Dai","outputs":[{"internalType":"contract DaiLike","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"EDai","outputs":[{"internalType":"contract WrappedDaiLike","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"Join","outputs":[{"internalType":"contract JoinLike","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"NewProxy","outputs":[{"internalType":"contract DaiProxy","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"ODai","outputs":[{"internalType":"contract WrappedDaiLike","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"Pot","outputs":[{"internalType":"contract PotLike","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"Reserve","outputs":[{"internalType":"contract ReserveLike","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"Vat","outputs":[{"internalType":"contract VatLike","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"string","name":"toChain","type":"string"},{"internalType":"uint256","name":"dai","type":"uint256"},{"internalType":"bytes","name":"to","type":"bytes"}],"name":"depositEDai","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"string","name":"toChain","type":"string"},{"internalType":"uint256","name":"dai","type":"uint256"},{"internalType":"bytes","name":"to","type":"bytes"}],"name":"depositODai","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"killProxy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"migrateProxy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"proxy","type":"address"}],"name":"setNewProxy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"reserve","type":"address"}],"name":"setReserve","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"oldProxy","type":"address"}],"name":"startProxy","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"state","outputs":[{"internalType":"enum DaiProxy.State","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"dai","type":"uint256"}],"name":"swapFromEDai","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"swapFromODai","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"dai","type":"uint256"}],"name":"swapToEDai","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"dai","type":"uint256"}],"name":"swapToODai","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"dai","type":"uint256"}],"name":"withdrawEDai","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"wad","type":"uint256"}],"name":"withdrawODai","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]