Transaction Hash:
Block:
9006061 at Nov-26-2019 08:23:28 PM +UTC
Transaction Fee:
0.001526904 ETH
$2.86
Gas Used:
254,484 Gas / 6 Gwei
Emitted Events:
48 |
DSProxy.0x1cff79cd00000000000000000000000000000000000000000000000000000000( 0x1cff79cd00000000000000000000000000000000000000000000000000000000, 0x00000000000000000000000051d0885b47ecd9ad3eecc322407d2c89f70bc00b, 0x000000000000000000000000e4b22d484958e582098a98229a24e8a43801b674, 0x0000000000000000000000000000000000000000000000000000000000000040, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000004000000000, 000000000000000000000000000000000000000000000000000000c41cff79cd, 000000000000000000000000e4b22d484958e582098a98229a24e8a43801b674, 0000000000000000000000000000000000000000000000000000000000000040, 0000000000000000000000000000000000000000000000000000000000000044, 8c544246000000000000000000000000c73e0383f3aff3215e6f04b0331d58ce, cf0ab849000000000000000000000000000000000000000000000002e1acd90d, b88c66a100000000000000000000000000000000000000000000000000000000 )
|
49 |
DSToken.Transfer( src=[Sender] 0x51d0885b47ecd9ad3eecc322407d2c89f70bc00b, dst=[Receiver] DSProxy, wad=53155099154901132961 )
|
50 |
DSToken.Approval( src=[Receiver] DSProxy, guy=ScdMcdMigration, wad=53155099154901132961 )
|
51 |
DSToken.Transfer( src=[Receiver] DSProxy, dst=ScdMcdMigration, wad=53155099154901132961 )
|
52 |
Vat.0x7cdd3fde00000000000000000000000000000000000000000000000000000000( 0x7cdd3fde00000000000000000000000000000000000000000000000000000000, 0x5341490000000000000000000000000000000000000000000000000000000000, 0x000000000000000000000000c73e0383f3aff3215e6f04b0331d58cecf0ab849, 0x000000000000000000000000000000000000000000000002e1acd90db88c66a1, 0000000000000000000000000000000000000000000000000000000000000020, 00000000000000000000000000000000000000000000000000000000000000e0, 7cdd3fde53414900000000000000000000000000000000000000000000000000, 00000000000000000000000000000000c73e0383f3aff3215e6f04b0331d58ce, cf0ab849000000000000000000000000000000000000000000000002e1acd90d, b88c66a100000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000 )
|
53 |
DSToken.Transfer( src=ScdMcdMigration, dst=AuthGemJoin, wad=53155099154901132961 )
|
54 |
AuthGemJoin.0x3b4da69f00000000000000000000000000000000000000000000000000000000( 0x3b4da69f00000000000000000000000000000000000000000000000000000000, 0x000000000000000000000000c73e0383f3aff3215e6f04b0331d58cecf0ab849, 0x000000000000000000000000c73e0383f3aff3215e6f04b0331d58cecf0ab849, 0x000000000000000000000000000000000000000000000002e1acd90db88c66a1, 0000000000000000000000000000000000000000000000000000000000000020, 00000000000000000000000000000000000000000000000000000000000000e0, 3b4da69f000000000000000000000000c73e0383f3aff3215e6f04b0331d58ce, cf0ab849000000000000000000000000000000000000000000000002e1acd90d, b88c66a100000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000 )
|
55 |
Vat.0x7608870300000000000000000000000000000000000000000000000000000000( 0x7608870300000000000000000000000000000000000000000000000000000000, 0x5341490000000000000000000000000000000000000000000000000000000000, 0x000000000000000000000000c73e0383f3aff3215e6f04b0331d58cecf0ab849, 0x000000000000000000000000c73e0383f3aff3215e6f04b0331d58cecf0ab849, 0000000000000000000000000000000000000000000000000000000000000020, 00000000000000000000000000000000000000000000000000000000000000e0, 7608870353414900000000000000000000000000000000000000000000000000, 00000000000000000000000000000000c73e0383f3aff3215e6f04b0331d58ce, cf0ab849000000000000000000000000c73e0383f3aff3215e6f04b0331d58ce, cf0ab849000000000000000000000000c73e0383f3aff3215e6f04b0331d58ce, cf0ab849000000000000000000000000000000000000000000000002e1acd90d, b88c66a1000000000000000000000000000000000000000000000002e1acd90d, b88c66a100000000000000000000000000000000000000000000000000000000 )
|
56 |
Vat.0xbb35783b00000000000000000000000000000000000000000000000000000000( 0xbb35783b00000000000000000000000000000000000000000000000000000000, 0x000000000000000000000000c73e0383f3aff3215e6f04b0331d58cecf0ab849, 0x0000000000000000000000009759a6ac90977b93b58547b4a71c78317f391a28, 0x000000000000000000000000094f8e9cef59acb5d3c781bf4547cabde8000000, 0000000000000000000000000000000000000000000000000000000000000020, 00000000000000000000000000000000000000000000000000000000000000e0, bb35783b000000000000000000000000c73e0383f3aff3215e6f04b0331d58ce, cf0ab8490000000000000000000000009759a6ac90977b93b58547b4a71c7831, 7f391a28000000000000000000000000094f8e9cef59acb5d3c781bf4547cabd, e800000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000 )
|
57 |
Dai.Transfer( src=0x0000000000000000000000000000000000000000, dst=[Receiver] DSProxy, wad=53155099154901132961 )
|
58 |
DaiJoin.0xef693bed00000000000000000000000000000000000000000000000000000000( 0xef693bed00000000000000000000000000000000000000000000000000000000, 0x000000000000000000000000c73e0383f3aff3215e6f04b0331d58cecf0ab849, 0x0000000000000000000000002161d0eabb0d52dae718861402d2c77751b66bae, 0x000000000000000000000000000000000000000000000002e1acd90db88c66a1, 0000000000000000000000000000000000000000000000000000000000000020, 00000000000000000000000000000000000000000000000000000000000000e0, ef693bed0000000000000000000000002161d0eabb0d52dae718861402d2c777, 51b66bae000000000000000000000000000000000000000000000002e1acd90d, b88c66a100000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000 )
|
59 |
Dai.Transfer( src=[Receiver] DSProxy, dst=[Sender] 0x51d0885b47ecd9ad3eecc322407d2c89f70bc00b, wad=53155099154901132961 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x35D1b3F3...259A0492B | (Sky: MCD Vat) | ||||
0x35F61DFB...D5B3a738d
Miner
| (firepool) | 110.473438546317615382 Eth | 110.474965450317615382 Eth | 0.001526904 | |
0x51D0885B...9f70BC00b |
0.832938791298183861 Eth
Nonce: 51
|
0.831411887298183861 Eth
Nonce: 52
| 0.001526904 | ||
0x6B175474...495271d0F | |||||
0x89d24A6b...a23260359 |
Execution Trace
DSProxy.execute( _target=0xe4B22D484958E582098A98229A24e8A43801b674, _data=0x8C544246000000000000000000000000C73E0383F3AFF3215E6F04B0331D58CECF0AB849000000000000000000000000000000000000000000000002E1ACD90DB88C66A1 ) => ( response=0000000000000000000000000000000000000000000000000000000000000000 )
MigrationProxyActions.swapSaiToDai( scdMcdMigration=0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849, wad=53155099154901132961 )
-
ScdMcdMigration.STATICCALL( )
-
SaiTub.STATICCALL( )
-
ScdMcdMigration.STATICCALL( )
-
DaiJoin.CALL( )
-
DSToken.transferFrom( src=0x51D0885B47eCD9ad3eECC322407d2c89f70BC00b, dst=0x2161D0eabB0d52dAe718861402D2c77751B66bAE, wad=53155099154901132961 ) => ( True )
-
DSToken.allowance( src=0x2161D0eabB0d52dAe718861402D2c77751B66bAE, guy=0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849 ) => ( 0 )
-
DSToken.approve( guy=0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849, wad=53155099154901132961 ) => ( True )
ScdMcdMigration.swapSaiToDai( wad=53155099154901132961 )
-
AuthGemJoin.CALL( )
-
DSToken.transferFrom( src=0x2161D0eabB0d52dAe718861402D2c77751B66bAE, dst=0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849, wad=53155099154901132961 ) => ( True )
AuthGemJoin.join( usr=0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849, wad=53155099154901132961 )
-
Vat.slip( ilk=5341490000000000000000000000000000000000000000000000000000000000, usr=0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849, wad=53155099154901132961 )
-
DSToken.transferFrom( src=0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849, dst=0xad37fd42185Ba63009177058208dd1be4b136e6b, wad=53155099154901132961 ) => ( True )
-
-
AuthGemJoin.CALL( )
-
Vat.frob( i=5341490000000000000000000000000000000000000000000000000000000000, u=0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849, v=0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849, w=0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849, dink=53155099154901132961, dart=53155099154901132961 )
DaiJoin.exit( usr=0x2161D0eabB0d52dAe718861402D2c77751B66bAE, wad=53155099154901132961 )
-
-
Dai.transfer( dst=0x51D0885B47eCD9ad3eECC322407d2c89f70BC00b, wad=53155099154901132961 ) => ( True )
-
execute[DSProxy (ln:115)]
read[DSProxy (ln:120)]
write[DSProxy (ln:123)]
execute[DSProxy (ln:126)]
read[DSProxy (ln:120)]
write[DSProxy (ln:123)]
execute[DSProxy (ln:126)]
File 1 of 9: DSProxy
File 2 of 9: DSToken
File 3 of 9: ScdMcdMigration
File 4 of 9: Vat
File 5 of 9: AuthGemJoin
File 6 of 9: Dai
File 7 of 9: DaiJoin
File 8 of 9: MigrationProxyActions
File 9 of 9: SaiTub
// proxy.sol - execute actions atomically through the proxy's identity // Copyright (C) 2017 DappHub, LLC // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. pragma solidity ^0.4.23; contract DSAuthority { function canCall( address src, address dst, bytes4 sig ) public 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(authority); } modifier auth { require(isAuthorized(msg.sender, msg.sig)); _; } 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, this, sig); } } } contract DSNote { event LogNote( bytes4 indexed sig, address indexed guy, bytes32 indexed foo, bytes32 indexed bar, uint wad, bytes fax ) anonymous; modifier note { bytes32 foo; bytes32 bar; assembly { foo := calldataload(4) bar := calldataload(36) } emit LogNote(msg.sig, msg.sender, foo, bar, msg.value, msg.data); _; } } // DSProxy // Allows code execution using a persistant identity This can be very // useful to execute a sequence of atomic actions. Since the owner of // the proxy can be changed, this allows for dynamic ownership models // i.e. a multisig contract DSProxy is DSAuth, DSNote { DSProxyCache public cache; // global cache for contracts constructor(address _cacheAddr) public { require(setCache(_cacheAddr)); } function() public payable { } // use the proxy to execute calldata _data on contract _code function execute(bytes _code, bytes _data) public payable returns (address target, bytes32 response) { target = cache.read(_code); if (target == 0x0) { // deploy contract & store its address in cache target = cache.write(_code); } response = execute(target, _data); } function execute(address _target, bytes _data) public auth note payable returns (bytes32 response) { require(_target != 0x0); // call contract in current context assembly { let succeeded := delegatecall(sub(gas, 5000), _target, add(_data, 0x20), mload(_data), 0, 32) response := mload(0) // load delegatecall output switch iszero(succeeded) case 1 { // throw if delegatecall failed revert(0, 0) } } } //set new cache function setCache(address _cacheAddr) public auth note returns (bool) { require(_cacheAddr != 0x0); // invalid cache address cache = DSProxyCache(_cacheAddr); // overwrite cache return true; } } // DSProxyFactory // This factory deploys new proxy instances through build() // Deployed proxy addresses are logged contract DSProxyFactory { event Created(address indexed sender, address indexed owner, address proxy, address cache); mapping(address=>bool) public isProxy; DSProxyCache public cache = new DSProxyCache(); // deploys a new proxy instance // sets owner of proxy to caller function build() public returns (DSProxy proxy) { proxy = build(msg.sender); } // deploys a new proxy instance // sets custom owner of proxy function build(address owner) public returns (DSProxy proxy) { proxy = new DSProxy(cache); emit Created(msg.sender, owner, address(proxy), address(cache)); proxy.setOwner(owner); isProxy[proxy] = true; } } // DSProxyCache // This global cache stores addresses of contracts previously deployed // by a proxy. This saves gas from repeat deployment of the same // contracts and eliminates blockchain bloat. // By default, all proxies deployed from the same factory store // contracts in the same cache. The cache a proxy instance uses can be // changed. The cache uses the sha3 hash of a contract's bytecode to // lookup the address contract DSProxyCache { mapping(bytes32 => address) cache; function read(bytes _code) public view returns (address) { bytes32 hash = keccak256(_code); return cache[hash]; } function write(bytes _code) public returns (address target) { assembly { target := create(0, add(_code, 0x20), mload(_code)) switch iszero(extcodesize(target)) case 1 { // throw if contract failed to deploy revert(0, 0) } } bytes32 hash = keccak256(_code); cache[hash] = target; } }
File 2 of 9: DSToken
pragma solidity ^0.4.13; ////// lib/ds-math/src/math.sol /// math.sol -- mixin for inline numerical wizardry // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. /* pragma solidity ^0.4.13; */ contract DSMath { 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); } function min(uint x, uint y) internal pure returns (uint z) { return x <= y ? x : y; } function max(uint x, uint y) internal pure returns (uint z) { return x >= y ? x : y; } function imin(int x, int y) internal pure returns (int z) { return x <= y ? x : y; } function imax(int x, int y) internal pure returns (int z) { return x >= y ? x : y; } uint constant WAD = 10 ** 18; uint constant RAY = 10 ** 27; function wmul(uint x, uint y) internal pure returns (uint z) { z = add(mul(x, y), WAD / 2) / WAD; } function rmul(uint x, uint y) internal pure returns (uint z) { z = add(mul(x, y), RAY / 2) / RAY; } function wdiv(uint x, uint y) internal pure returns (uint z) { z = add(mul(x, WAD), y / 2) / y; } function rdiv(uint x, uint y) internal pure returns (uint z) { z = add(mul(x, RAY), y / 2) / y; } // This famous algorithm is called "exponentiation by squaring" // and calculates x^n with x as fixed-point and n as regular unsigned. // // It's O(log n), instead of O(n) for naive repeated multiplication. // // These facts are why it works: // // If n is even, then x^n = (x^2)^(n/2). // If n is odd, then x^n = x * x^(n-1), // and applying the equation for even x gives // x^n = x * (x^2)^((n-1) / 2). // // Also, EVM division is flooring and // floor[(n-1) / 2] = floor[n / 2]. // function rpow(uint x, uint n) internal pure returns (uint z) { z = n % 2 != 0 ? x : RAY; for (n /= 2; n != 0; n /= 2) { x = rmul(x, x); if (n % 2 != 0) { z = rmul(z, x); } } } } ////// lib/ds-stop/lib/ds-auth/src/auth.sol // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. /* pragma solidity ^0.4.13; */ contract DSAuthority { function canCall( address src, address dst, bytes4 sig ) public 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; function DSAuth() public { owner = msg.sender; LogSetOwner(msg.sender); } function setOwner(address owner_) public auth { owner = owner_; LogSetOwner(owner); } function setAuthority(DSAuthority authority_) public auth { authority = authority_; LogSetAuthority(authority); } modifier auth { require(isAuthorized(msg.sender, msg.sig)); _; } 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, this, sig); } } } ////// lib/ds-stop/lib/ds-note/src/note.sol /// note.sol -- the `note' modifier, for logging calls as events // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. /* pragma solidity ^0.4.13; */ contract DSNote { event LogNote( bytes4 indexed sig, address indexed guy, bytes32 indexed foo, bytes32 indexed bar, uint wad, bytes fax ) anonymous; modifier note { bytes32 foo; bytes32 bar; assembly { foo := calldataload(4) bar := calldataload(36) } LogNote(msg.sig, msg.sender, foo, bar, msg.value, msg.data); _; } } ////// lib/ds-stop/src/stop.sol /// stop.sol -- mixin for enable/disable functionality // Copyright (C) 2017 DappHub, LLC // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. /* pragma solidity ^0.4.13; */ /* import "ds-auth/auth.sol"; */ /* import "ds-note/note.sol"; */ contract DSStop is DSNote, DSAuth { bool public stopped; modifier stoppable { require(!stopped); _; } function stop() public auth note { stopped = true; } function start() public auth note { stopped = false; } } ////// lib/erc20/src/erc20.sol /// erc20.sol -- API for the ERC20 token standard // See <https://github.com/ethereum/EIPs/issues/20>. // This file likely does not meet the threshold of originality // required for copyright to apply. As a result, this is free and // unencumbered software belonging to the public domain. /* pragma solidity ^0.4.8; */ contract ERC20Events { event Approval(address indexed src, address indexed guy, uint wad); event Transfer(address indexed src, address indexed dst, uint wad); } contract ERC20 is ERC20Events { function totalSupply() public view returns (uint); function balanceOf(address guy) public view returns (uint); function allowance(address src, address guy) public view returns (uint); function approve(address guy, uint wad) public returns (bool); function transfer(address dst, uint wad) public returns (bool); function transferFrom( address src, address dst, uint wad ) public returns (bool); } ////// src/base.sol /// base.sol -- basic ERC20 implementation // Copyright (C) 2015, 2016, 2017 DappHub, LLC // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. /* pragma solidity ^0.4.13; */ /* import "erc20/erc20.sol"; */ /* import "ds-math/math.sol"; */ contract DSTokenBase is ERC20, DSMath { uint256 _supply; mapping (address => uint256) _balances; mapping (address => mapping (address => uint256)) _approvals; function DSTokenBase(uint supply) public { _balances[msg.sender] = supply; _supply = supply; } function totalSupply() public view returns (uint) { return _supply; } function balanceOf(address src) public view returns (uint) { return _balances[src]; } function allowance(address src, address guy) public view returns (uint) { return _approvals[src][guy]; } function transfer(address dst, uint wad) public returns (bool) { return transferFrom(msg.sender, dst, wad); } function transferFrom(address src, address dst, uint wad) public returns (bool) { if (src != msg.sender) { _approvals[src][msg.sender] = sub(_approvals[src][msg.sender], wad); } _balances[src] = sub(_balances[src], wad); _balances[dst] = add(_balances[dst], wad); Transfer(src, dst, wad); return true; } function approve(address guy, uint wad) public returns (bool) { _approvals[msg.sender][guy] = wad; Approval(msg.sender, guy, wad); return true; } } ////// src/token.sol /// token.sol -- ERC20 implementation with minting and burning // Copyright (C) 2015, 2016, 2017 DappHub, LLC // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. /* pragma solidity ^0.4.13; */ /* import "ds-stop/stop.sol"; */ /* import "./base.sol"; */ contract DSToken is DSTokenBase(0), DSStop { bytes32 public symbol; uint256 public decimals = 18; // standard token precision. override to customize function DSToken(bytes32 symbol_) public { symbol = symbol_; } event Mint(address indexed guy, uint wad); event Burn(address indexed guy, uint wad); function approve(address guy) public stoppable returns (bool) { return super.approve(guy, uint(-1)); } function approve(address guy, uint wad) public stoppable returns (bool) { return super.approve(guy, wad); } function transferFrom(address src, address dst, uint wad) public stoppable returns (bool) { if (src != msg.sender && _approvals[src][msg.sender] != uint(-1)) { _approvals[src][msg.sender] = sub(_approvals[src][msg.sender], wad); } _balances[src] = sub(_balances[src], wad); _balances[dst] = add(_balances[dst], wad); Transfer(src, dst, wad); return true; } function push(address dst, uint wad) public { transferFrom(msg.sender, dst, wad); } function pull(address src, uint wad) public { transferFrom(src, msg.sender, wad); } function move(address src, address dst, uint wad) public { transferFrom(src, dst, wad); } function mint(uint wad) public { mint(msg.sender, wad); } function burn(uint wad) public { burn(msg.sender, wad); } function mint(address guy, uint wad) public auth stoppable { _balances[guy] = add(_balances[guy], wad); _supply = add(_supply, wad); Mint(guy, wad); } function burn(address guy, uint wad) public auth stoppable { if (guy != msg.sender && _approvals[guy][msg.sender] != uint(-1)) { _approvals[guy][msg.sender] = sub(_approvals[guy][msg.sender], wad); } _balances[guy] = sub(_balances[guy], wad); _supply = sub(_supply, wad); Burn(guy, wad); } // Optional token name bytes32 public name = ""; function setName(bytes32 name_) public auth { name = name_; } }
File 3 of 9: ScdMcdMigration
// hevm: flattened sources of /nix/store/nrmi9gk7q94ba1fbhq9bphlbpqd1y8hw-scd-mcd-migration-e730e63/src/ScdMcdMigration.sol pragma solidity =0.5.12; ////// /nix/store/nrmi9gk7q94ba1fbhq9bphlbpqd1y8hw-scd-mcd-migration-e730e63/src/Interfaces.sol /* pragma solidity 0.5.12; */ contract GemLike { function allowance(address, address) public returns (uint); function approve(address, uint) public; function transfer(address, uint) public returns (bool); function transferFrom(address, address, uint) public returns (bool); } contract ValueLike { function peek() public returns (uint, bool); } contract SaiTubLike { function skr() public view returns (GemLike); function gem() public view returns (GemLike); function gov() public view returns (GemLike); function sai() public view returns (GemLike); function pep() public view returns (ValueLike); function vox() public view returns (VoxLike); function bid(uint) public view returns (uint); function ink(bytes32) public view returns (uint); function tag() public view returns (uint); function tab(bytes32) public returns (uint); function rap(bytes32) public returns (uint); function draw(bytes32, uint) public; function shut(bytes32) public; function exit(uint) public; function give(bytes32, address) public; } contract VoxLike { function par() public returns (uint); } contract JoinLike { function ilk() public returns (bytes32); function gem() public returns (GemLike); function dai() public returns (GemLike); function join(address, uint) public; function exit(address, uint) public; } contract VatLike { function ilks(bytes32) public view returns (uint, uint, uint, uint, uint); function hope(address) public; function frob(bytes32, address, address, address, int, int) public; } contract ManagerLike { function vat() public view returns (address); function urns(uint) public view returns (address); function open(bytes32, address) public returns (uint); function frob(uint, int, int) public; function give(uint, address) public; function move(uint, address, uint) public; } contract OtcLike { function getPayAmount(address, address, uint) public view returns (uint); function buyAllAmount(address, uint, address, uint) public; } ////// /nix/store/nrmi9gk7q94ba1fbhq9bphlbpqd1y8hw-scd-mcd-migration-e730e63/src/ScdMcdMigration.sol /* pragma solidity 0.5.12; */ /* import { JoinLike, ManagerLike, SaiTubLike, VatLike } from "./Interfaces.sol"; */ contract ScdMcdMigration { SaiTubLike public tub; VatLike public vat; ManagerLike public cdpManager; JoinLike public saiJoin; JoinLike public wethJoin; JoinLike public daiJoin; constructor( address tub_, // SCD tub contract address address cdpManager_, // MCD manager contract address address saiJoin_, // MCD SAI collateral adapter contract address address wethJoin_, // MCD ETH collateral adapter contract address address daiJoin_ // MCD DAI adapter contract address ) public { tub = SaiTubLike(tub_); cdpManager = ManagerLike(cdpManager_); vat = VatLike(cdpManager.vat()); saiJoin = JoinLike(saiJoin_); wethJoin = JoinLike(wethJoin_); daiJoin = JoinLike(daiJoin_); require(wethJoin.gem() == tub.gem(), "non-matching-weth"); require(saiJoin.gem() == tub.sai(), "non-matching-sai"); tub.gov().approve(address(tub), uint(-1)); tub.skr().approve(address(tub), uint(-1)); tub.sai().approve(address(tub), uint(-1)); tub.sai().approve(address(saiJoin), uint(-1)); wethJoin.gem().approve(address(wethJoin), uint(-1)); daiJoin.dai().approve(address(daiJoin), uint(-1)); vat.hope(address(daiJoin)); } function add(uint x, uint y) internal pure returns (uint z) { require((z = x + y) >= x, "add-overflow"); } function sub(uint x, uint y) internal pure returns (uint z) { require((z = x - y) <= x, "sub-underflow"); } function mul(uint x, uint y) internal pure returns (uint z) { require(y == 0 || (z = x * y) / y == x, "mul-overflow"); } function toInt(uint x) internal pure returns (int y) { y = int(x); require(y >= 0, "int-overflow"); } // Function to swap SAI to DAI // This function is to be used by users that want to get new DAI in exchange of old one (aka SAI) // wad amount has to be <= the value pending to reach the debt ceiling (the minimum between general and ilk one) function swapSaiToDai( uint wad ) external { // Get wad amount of SAI from user's wallet: saiJoin.gem().transferFrom(msg.sender, address(this), wad); // Join the SAI wad amount to the `vat`: saiJoin.join(address(this), wad); // Lock the SAI wad amount to the CDP and generate the same wad amount of DAI vat.frob(saiJoin.ilk(), address(this), address(this), address(this), toInt(wad), toInt(wad)); // Send DAI wad amount as a ERC20 token to the user's wallet daiJoin.exit(msg.sender, wad); } // Function to swap DAI to SAI // This function is to be used by users that want to get SAI in exchange of DAI // wad amount has to be <= the amount of SAI locked (and DAI generated) in the migration contract SAI CDP function swapDaiToSai( uint wad ) external { // Get wad amount of DAI from user's wallet: daiJoin.dai().transferFrom(msg.sender, address(this), wad); // Join the DAI wad amount to the vat: daiJoin.join(address(this), wad); // Payback the DAI wad amount and unlocks the same value of SAI collateral vat.frob(saiJoin.ilk(), address(this), address(this), address(this), -toInt(wad), -toInt(wad)); // Send SAI wad amount as a ERC20 token to the user's wallet saiJoin.exit(msg.sender, wad); } // Function to migrate a SCD CDP to MCD one (needs to be used via a proxy so the code can be kept simpler). Check MigrationProxyActions.sol code for usage. // In order to use migrate function, SCD CDP debtAmt needs to be <= SAI previously deposited in the SAI CDP * (100% - Collateralization Ratio) function migrate( bytes32 cup ) external returns (uint cdp) { // Get values uint debtAmt = tub.tab(cup); // CDP SAI debt uint pethAmt = tub.ink(cup); // CDP locked collateral uint ethAmt = tub.bid(pethAmt); // CDP locked collateral equiv in ETH // Take SAI out from MCD SAI CDP. For this operation is necessary to have a very low collateralization ratio // This is not actually a problem as this ilk will only be accessed by this migration contract, // which will make sure to have the amounts balanced out at the end of the execution. vat.frob( bytes32(saiJoin.ilk()), address(this), address(this), address(this), -toInt(debtAmt), 0 ); saiJoin.exit(address(this), debtAmt); // SAI is exited as a token // Shut SAI CDP and gets WETH back tub.shut(cup); // CDP is closed using the SAI just exited and the MKR previously sent by the user (via the proxy call) tub.exit(pethAmt); // Converts PETH to WETH // Open future user's CDP in MCD cdp = cdpManager.open(wethJoin.ilk(), address(this)); // Join WETH to Adapter wethJoin.join(cdpManager.urns(cdp), ethAmt); // Lock WETH in future user's CDP and generate debt to compensate the SAI used to paid the SCD CDP (, uint rate,,,) = vat.ilks(wethJoin.ilk()); cdpManager.frob( cdp, toInt(ethAmt), toInt(mul(debtAmt, 10 ** 27) / rate + 1) // To avoid rounding issues we add an extra wei of debt ); // Move DAI generated to migration contract (to recover the used funds) cdpManager.move(cdp, address(this), mul(debtAmt, 10 ** 27)); // Re-balance MCD SAI migration contract's CDP vat.frob( bytes32(saiJoin.ilk()), address(this), address(this), address(this), 0, -toInt(debtAmt) ); // Set ownership of CDP to the user cdpManager.give(cdp, msg.sender); } }
File 4 of 9: Vat
// hevm: flattened sources of /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/vat.sol pragma solidity =0.5.12; ////// /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/vat.sol /// vat.sol -- Dai CDP database // Copyright (C) 2018 Rain <[email protected]> // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <https://www.gnu.org/licenses/>. /* pragma solidity 0.5.12; */ contract Vat { // --- Auth --- mapping (address => uint) public wards; function rely(address usr) external note auth { require(live == 1, "Vat/not-live"); wards[usr] = 1; } function deny(address usr) external note auth { require(live == 1, "Vat/not-live"); wards[usr] = 0; } modifier auth { require(wards[msg.sender] == 1, "Vat/not-authorized"); _; } mapping(address => mapping (address => uint)) public can; function hope(address usr) external note { can[msg.sender][usr] = 1; } function nope(address usr) external note { can[msg.sender][usr] = 0; } function wish(address bit, address usr) internal view returns (bool) { return either(bit == usr, can[bit][usr] == 1); } // --- Data --- struct Ilk { uint256 Art; // Total Normalised Debt [wad] uint256 rate; // Accumulated Rates [ray] uint256 spot; // Price with Safety Margin [ray] uint256 line; // Debt Ceiling [rad] uint256 dust; // Urn Debt Floor [rad] } struct Urn { uint256 ink; // Locked Collateral [wad] uint256 art; // Normalised Debt [wad] } mapping (bytes32 => Ilk) public ilks; mapping (bytes32 => mapping (address => Urn )) public urns; mapping (bytes32 => mapping (address => uint)) public gem; // [wad] mapping (address => uint256) public dai; // [rad] mapping (address => uint256) public sin; // [rad] uint256 public debt; // Total Dai Issued [rad] uint256 public vice; // Total Unbacked Dai [rad] uint256 public Line; // Total Debt Ceiling [rad] uint256 public live; // Access Flag // --- Logs --- event LogNote( bytes4 indexed sig, bytes32 indexed arg1, bytes32 indexed arg2, bytes32 indexed arg3, bytes data ) anonymous; modifier note { _; assembly { // log an 'anonymous' event with a constant 6 words of calldata // and four indexed topics: the selector and the first three args let mark := msize // end of memory ensures zero mstore(0x40, add(mark, 288)) // update free memory pointer mstore(mark, 0x20) // bytes type data offset mstore(add(mark, 0x20), 224) // bytes size (padded) calldatacopy(add(mark, 0x40), 0, 224) // bytes payload log4(mark, 288, // calldata shl(224, shr(224, calldataload(0))), // msg.sig calldataload(4), // arg1 calldataload(36), // arg2 calldataload(68) // arg3 ) } } // --- Init --- constructor() public { wards[msg.sender] = 1; live = 1; } // --- Math --- function add(uint x, int y) internal pure returns (uint z) { z = x + uint(y); require(y >= 0 || z <= x); require(y <= 0 || z >= x); } function sub(uint x, int y) internal pure returns (uint z) { z = x - uint(y); require(y <= 0 || z <= x); require(y >= 0 || z >= x); } function mul(uint x, int y) internal pure returns (int z) { z = int(x) * y; require(int(x) >= 0); require(y == 0 || z / y == int(x)); } function add(uint x, uint y) internal pure returns (uint z) { require((z = x + y) >= x); } function sub(uint x, uint y) internal pure returns (uint z) { require((z = x - y) <= x); } function mul(uint x, uint y) internal pure returns (uint z) { require(y == 0 || (z = x * y) / y == x); } // --- Administration --- function init(bytes32 ilk) external note auth { require(ilks[ilk].rate == 0, "Vat/ilk-already-init"); ilks[ilk].rate = 10 ** 27; } function file(bytes32 what, uint data) external note auth { require(live == 1, "Vat/not-live"); if (what == "Line") Line = data; else revert("Vat/file-unrecognized-param"); } function file(bytes32 ilk, bytes32 what, uint data) external note auth { require(live == 1, "Vat/not-live"); if (what == "spot") ilks[ilk].spot = data; else if (what == "line") ilks[ilk].line = data; else if (what == "dust") ilks[ilk].dust = data; else revert("Vat/file-unrecognized-param"); } function cage() external note auth { live = 0; } // --- Fungibility --- function slip(bytes32 ilk, address usr, int256 wad) external note auth { gem[ilk][usr] = add(gem[ilk][usr], wad); } function flux(bytes32 ilk, address src, address dst, uint256 wad) external note { require(wish(src, msg.sender), "Vat/not-allowed"); gem[ilk][src] = sub(gem[ilk][src], wad); gem[ilk][dst] = add(gem[ilk][dst], wad); } function move(address src, address dst, uint256 rad) external note { require(wish(src, msg.sender), "Vat/not-allowed"); dai[src] = sub(dai[src], rad); dai[dst] = add(dai[dst], rad); } function either(bool x, bool y) internal pure returns (bool z) { assembly{ z := or(x, y)} } function both(bool x, bool y) internal pure returns (bool z) { assembly{ z := and(x, y)} } // --- CDP Manipulation --- function frob(bytes32 i, address u, address v, address w, int dink, int dart) external note { // system is live require(live == 1, "Vat/not-live"); Urn memory urn = urns[i][u]; Ilk memory ilk = ilks[i]; // ilk has been initialised require(ilk.rate != 0, "Vat/ilk-not-init"); urn.ink = add(urn.ink, dink); urn.art = add(urn.art, dart); ilk.Art = add(ilk.Art, dart); int dtab = mul(ilk.rate, dart); uint tab = mul(ilk.rate, urn.art); debt = add(debt, dtab); // either debt has decreased, or debt ceilings are not exceeded require(either(dart <= 0, both(mul(ilk.Art, ilk.rate) <= ilk.line, debt <= Line)), "Vat/ceiling-exceeded"); // urn is either less risky than before, or it is safe require(either(both(dart <= 0, dink >= 0), tab <= mul(urn.ink, ilk.spot)), "Vat/not-safe"); // urn is either more safe, or the owner consents require(either(both(dart <= 0, dink >= 0), wish(u, msg.sender)), "Vat/not-allowed-u"); // collateral src consents require(either(dink <= 0, wish(v, msg.sender)), "Vat/not-allowed-v"); // debt dst consents require(either(dart >= 0, wish(w, msg.sender)), "Vat/not-allowed-w"); // urn has no debt, or a non-dusty amount require(either(urn.art == 0, tab >= ilk.dust), "Vat/dust"); gem[i][v] = sub(gem[i][v], dink); dai[w] = add(dai[w], dtab); urns[i][u] = urn; ilks[i] = ilk; } // --- CDP Fungibility --- function fork(bytes32 ilk, address src, address dst, int dink, int dart) external note { Urn storage u = urns[ilk][src]; Urn storage v = urns[ilk][dst]; Ilk storage i = ilks[ilk]; u.ink = sub(u.ink, dink); u.art = sub(u.art, dart); v.ink = add(v.ink, dink); v.art = add(v.art, dart); uint utab = mul(u.art, i.rate); uint vtab = mul(v.art, i.rate); // both sides consent require(both(wish(src, msg.sender), wish(dst, msg.sender)), "Vat/not-allowed"); // both sides safe require(utab <= mul(u.ink, i.spot), "Vat/not-safe-src"); require(vtab <= mul(v.ink, i.spot), "Vat/not-safe-dst"); // both sides non-dusty require(either(utab >= i.dust, u.art == 0), "Vat/dust-src"); require(either(vtab >= i.dust, v.art == 0), "Vat/dust-dst"); } // --- CDP Confiscation --- function grab(bytes32 i, address u, address v, address w, int dink, int dart) external note auth { Urn storage urn = urns[i][u]; Ilk storage ilk = ilks[i]; urn.ink = add(urn.ink, dink); urn.art = add(urn.art, dart); ilk.Art = add(ilk.Art, dart); int dtab = mul(ilk.rate, dart); gem[i][v] = sub(gem[i][v], dink); sin[w] = sub(sin[w], dtab); vice = sub(vice, dtab); } // --- Settlement --- function heal(uint rad) external note { address u = msg.sender; sin[u] = sub(sin[u], rad); dai[u] = sub(dai[u], rad); vice = sub(vice, rad); debt = sub(debt, rad); } function suck(address u, address v, uint rad) external note auth { sin[u] = add(sin[u], rad); dai[v] = add(dai[v], rad); vice = add(vice, rad); debt = add(debt, rad); } // --- Rates --- function fold(bytes32 i, address u, int rate) external note auth { require(live == 1, "Vat/not-live"); Ilk storage ilk = ilks[i]; ilk.rate = add(ilk.rate, rate); int rad = mul(ilk.Art, rate); dai[u] = add(dai[u], rad); debt = add(debt, rad); } }
File 5 of 9: AuthGemJoin
// hevm: flattened sources of /nix/store/k8y52yly1kzii65m0yw5pbidrq3jlajh-dss-deploy-001fb27/src/join.sol pragma solidity =0.5.12; ////// /nix/store/4vip6nyqfd0yhs15md21rzxsk5jgx6sv-dss/dapp/dss/src/lib.sol // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. /* pragma solidity 0.5.12; */ 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 ) } } } ////// /nix/store/k8y52yly1kzii65m0yw5pbidrq3jlajh-dss-deploy-001fb27/src/join.sol /// join.sol -- Non-standard token adapters // Copyright (C) 2018 Rain <[email protected]> // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <https://www.gnu.org/licenses/>. /* pragma solidity 0.5.12; */ /* import "dss/lib.sol"; */ contract VatLike { function slip(bytes32,address,int) public; } // GemJoin2 // For a token that does not return a bool on transfer or transferFrom (like OMG) // This is one way of doing it. Check the balances before and after calling a transfer contract GemLike2 { function decimals() public view returns (uint); function transfer(address,uint) public; function transferFrom(address,address,uint) public; function balanceOf(address) public view returns (uint); function allowance(address,address) public view returns (uint); } contract GemJoin2 is LibNote { // --- Auth --- mapping (address => uint) public wards; function rely(address usr) external note auth { wards[usr] = 1; } function deny(address usr) external note auth { wards[usr] = 0; } modifier auth { require(wards[msg.sender] == 1); _; } VatLike public vat; bytes32 public ilk; GemLike2 public gem; uint public dec; uint public live; // Access Flag constructor(address vat_, bytes32 ilk_, address gem_) public { wards[msg.sender] = 1; live = 1; vat = VatLike(vat_); ilk = ilk_; gem = GemLike2(gem_); dec = gem.decimals(); } function cage() external note auth { live = 0; } function mul(uint x, uint y) internal pure returns (uint z) { require(y == 0 || (z = x * y) / y == x, "GemJoin2/overflow"); } function join(address urn, uint wad) public note { require(live == 1, "GemJoin2/not-live"); require(wad <= 2 ** 255, "GemJoin2/overflow"); vat.slip(ilk, urn, int(wad)); uint256 prevBalance = gem.balanceOf(msg.sender); require(prevBalance >= wad, "GemJoin2/no-funds"); require(gem.allowance(msg.sender, address(this)) >= wad, "GemJoin2/no-allowance"); (bool ok,) = address(gem).call( abi.encodeWithSignature("transferFrom(address,address,uint256)", msg.sender, address(this), wad) ); require(ok, "GemJoin2/failed-transfer"); require(prevBalance - wad == gem.balanceOf(msg.sender), "GemJoin2/failed-transfer"); } function exit(address guy, uint wad) public note { require(wad <= 2 ** 255, "GemJoin2/overflow"); vat.slip(ilk, msg.sender, -int(wad)); uint256 prevBalance = gem.balanceOf(address(this)); require(prevBalance >= wad, "GemJoin2/no-funds"); (bool ok,) = address(gem).call( abi.encodeWithSignature("transfer(address,uint256)", guy, wad) ); require(ok, "GemJoin2/failed-transfer"); require(prevBalance - wad == gem.balanceOf(address(this)), "GemJoin2/failed-transfer"); } } // GemJoin3 // For a token that has a lower precision than 18 and doesn't have decimals field in place (like DGD) contract GemLike3 { function transfer(address,uint) public returns (bool); function transferFrom(address,address,uint) public returns (bool); } contract GemJoin3 is LibNote { // --- Auth --- mapping (address => uint) public wards; function rely(address usr) external note auth { wards[usr] = 1; } function deny(address usr) external note auth { wards[usr] = 0; } modifier auth { require(wards[msg.sender] == 1); _; } VatLike public vat; bytes32 public ilk; GemLike3 public gem; uint public dec; uint public live; // Access Flag constructor(address vat_, bytes32 ilk_, address gem_, uint decimals) public { require(decimals < 18, "GemJoin3/decimals-18-or-higher"); wards[msg.sender] = 1; live = 1; vat = VatLike(vat_); ilk = ilk_; gem = GemLike3(gem_); dec = decimals; } function cage() external note auth { live = 0; } function mul(uint x, uint y) internal pure returns (uint z) { require(y == 0 || (z = x * y) / y == x, "GemJoin3/overflow"); } function join(address urn, uint wad) public note { require(live == 1, "GemJoin3/not-live"); uint wad18 = mul(wad, 10 ** (18 - dec)); require(wad18 <= 2 ** 255, "GemJoin3/overflow"); vat.slip(ilk, urn, int(wad18)); require(gem.transferFrom(msg.sender, address(this), wad), "GemJoin3/failed-transfer"); } function exit(address guy, uint wad) public note { uint wad18 = mul(wad, 10 ** (18 - dec)); require(wad18 <= 2 ** 255, "GemJoin3/overflow"); vat.slip(ilk, msg.sender, -int(wad18)); require(gem.transfer(guy, wad), "GemJoin3/failed-transfer"); } } /// GemJoin4 // Copyright (C) 2019 Lorenzo Manacorda <[email protected]> // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <https://www.gnu.org/licenses/>. // For tokens that do not implement transferFrom (like GNT), meaning the usual adapter // approach won't work: the adapter cannot call transferFrom and therefore // has no way of knowing when users deposit gems into it. // To work around this, we introduce the concept of a bag, which is a trusted // (it's created by the adapter), personalized component (one for each user). // Users first have to create their bag with `GemJoin4.make`, then transfer // gem to it, and then call `GemJoin4.join`, which transfer the gems from the // bag to the adapter. contract GemLike4 { function decimals() public view returns (uint); function balanceOf(address) public returns (uint256); function transfer(address, uint256) public returns (bool); } contract GemBag { address public ada; address public lad; GemLike4 public gem; constructor(address lad_, address gem_) public { ada = msg.sender; lad = lad_; gem = GemLike4(gem_); } function exit(address usr, uint256 wad) external { require(msg.sender == ada || msg.sender == lad, "GemBag/invalid-caller"); require(gem.transfer(usr, wad), "GemBag/failed-transfer"); } } contract GemJoin4 is LibNote { // --- Auth --- mapping (address => uint) public wards; function rely(address usr) external note auth { wards[usr] = 1; } function deny(address usr) external note auth { wards[usr] = 0; } modifier auth { require(wards[msg.sender] == 1); _; } VatLike public vat; bytes32 public ilk; GemLike4 public gem; uint public dec; uint public live; // Access Flag mapping(address => address) public bags; constructor(address vat_, bytes32 ilk_, address gem_) public { wards[msg.sender] = 1; live = 1; vat = VatLike(vat_); ilk = ilk_; gem = GemLike4(gem_); dec = gem.decimals(); } function cage() external note auth { live = 0; } // -- admin -- function make() external returns (address bag) { bag = make(msg.sender); } function make(address usr) public note returns (address bag) { require(bags[usr] == address(0), "GemJoin4/bag-already-exists"); bag = address(new GemBag(address(usr), address(gem))); bags[usr] = bag; } // -- gems -- function join(address urn, uint256 wad) external note { require(live == 1, "GemJoin4/not-live"); require(int256(wad) >= 0, "GemJoin4/negative-amount"); GemBag(bags[msg.sender]).exit(address(this), wad); vat.slip(ilk, urn, int256(wad)); } function exit(address usr, uint256 wad) external note { require(int256(wad) >= 0, "GemJoin4/negative-amount"); vat.slip(ilk, msg.sender, -int256(wad)); require(gem.transfer(usr, wad), "GemJoin4/failed-transfer"); } } // AuthGemJoin // For a token that needs restriction on the sources which are able to execute the join function (like SAI through Migration contract) contract GemLike { function decimals() public view returns (uint); function transfer(address,uint) public returns (bool); function transferFrom(address,address,uint) public returns (bool); } contract AuthGemJoin is LibNote { VatLike public vat; bytes32 public ilk; GemLike public gem; uint public dec; uint public live; // Access Flag // --- Auth --- mapping (address => uint) public wards; function rely(address usr) public note auth { wards[usr] = 1; } function deny(address usr) public note auth { wards[usr] = 0; } modifier auth { require(wards[msg.sender] == 1, "AuthGemJoin/non-authed"); _; } constructor(address vat_, bytes32 ilk_, address gem_) public { wards[msg.sender] = 1; live = 1; vat = VatLike(vat_); ilk = ilk_; gem = GemLike(gem_); dec = gem.decimals(); } function cage() external note auth { live = 0; } function join(address usr, uint wad) public auth note { require(live == 1, "AuthGemJoin/not-live"); require(int(wad) >= 0, "AuthGemJoin/overflow"); vat.slip(ilk, usr, int(wad)); require(gem.transferFrom(msg.sender, address(this), wad), "AuthGemJoin/failed-transfer"); } function exit(address usr, uint wad) public note { require(wad <= 2 ** 255, "AuthGemJoin/overflow"); vat.slip(ilk, msg.sender, -int(wad)); require(gem.transfer(usr, wad), "AuthGemJoin/failed-transfer"); } }
File 6 of 9: Dai
// hevm: flattened sources of /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/dai.sol pragma solidity =0.5.12; ////// /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/lib.sol // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. /* pragma solidity 0.5.12; */ 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 ) } } } ////// /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/dai.sol // Copyright (C) 2017, 2018, 2019 dbrock, rain, mrchico // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <https://www.gnu.org/licenses/>. /* pragma solidity 0.5.12; */ /* import "./lib.sol"; */ contract Dai is LibNote { // --- Auth --- mapping (address => uint) public wards; function rely(address guy) external note auth { wards[guy] = 1; } function deny(address guy) external note auth { wards[guy] = 0; } modifier auth { require(wards[msg.sender] == 1, "Dai/not-authorized"); _; } // --- ERC20 Data --- string public constant name = "Dai Stablecoin"; string public constant symbol = "DAI"; string public constant version = "1"; uint8 public constant decimals = 18; uint256 public totalSupply; mapping (address => uint) public balanceOf; mapping (address => mapping (address => uint)) public allowance; mapping (address => uint) public nonces; event Approval(address indexed src, address indexed guy, uint wad); event Transfer(address indexed src, address indexed dst, uint wad); // --- Math --- function add(uint x, uint y) internal pure returns (uint z) { require((z = x + y) >= x); } function sub(uint x, uint y) internal pure returns (uint z) { require((z = x - y) <= x); } // --- EIP712 niceties --- bytes32 public DOMAIN_SEPARATOR; // bytes32 public constant PERMIT_TYPEHASH = keccak256("Permit(address holder,address spender,uint256 nonce,uint256 expiry,bool allowed)"); bytes32 public constant PERMIT_TYPEHASH = 0xea2aa0a1be11a07ed86d755c93467f4f82362b452371d1ba94d1715123511acb; constructor(uint256 chainId_) public { wards[msg.sender] = 1; DOMAIN_SEPARATOR = keccak256(abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes(name)), keccak256(bytes(version)), chainId_, address(this) )); } // --- Token --- function transfer(address dst, uint wad) external returns (bool) { return transferFrom(msg.sender, dst, wad); } function transferFrom(address src, address dst, uint wad) public returns (bool) { require(balanceOf[src] >= wad, "Dai/insufficient-balance"); if (src != msg.sender && allowance[src][msg.sender] != uint(-1)) { require(allowance[src][msg.sender] >= wad, "Dai/insufficient-allowance"); allowance[src][msg.sender] = sub(allowance[src][msg.sender], wad); } balanceOf[src] = sub(balanceOf[src], wad); balanceOf[dst] = add(balanceOf[dst], wad); emit Transfer(src, dst, wad); return true; } function mint(address usr, uint wad) external auth { balanceOf[usr] = add(balanceOf[usr], wad); totalSupply = add(totalSupply, wad); emit Transfer(address(0), usr, wad); } function burn(address usr, uint wad) external { require(balanceOf[usr] >= wad, "Dai/insufficient-balance"); if (usr != msg.sender && allowance[usr][msg.sender] != uint(-1)) { require(allowance[usr][msg.sender] >= wad, "Dai/insufficient-allowance"); allowance[usr][msg.sender] = sub(allowance[usr][msg.sender], wad); } balanceOf[usr] = sub(balanceOf[usr], wad); totalSupply = sub(totalSupply, wad); emit Transfer(usr, address(0), wad); } function approve(address usr, uint wad) external returns (bool) { allowance[msg.sender][usr] = wad; emit Approval(msg.sender, usr, wad); return true; } // --- Alias --- function push(address usr, uint wad) external { transferFrom(msg.sender, usr, wad); } function pull(address usr, uint wad) external { transferFrom(usr, msg.sender, wad); } function move(address src, address dst, uint wad) external { transferFrom(src, dst, wad); } // --- Approve by signature --- function permit(address holder, address spender, uint256 nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s) external { bytes32 digest = keccak256(abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR, keccak256(abi.encode(PERMIT_TYPEHASH, holder, spender, nonce, expiry, allowed)) )); require(holder != address(0), "Dai/invalid-address-0"); require(holder == ecrecover(digest, v, r, s), "Dai/invalid-permit"); require(expiry == 0 || now <= expiry, "Dai/permit-expired"); require(nonce == nonces[holder]++, "Dai/invalid-nonce"); uint wad = allowed ? uint(-1) : 0; allowance[holder][spender] = wad; emit Approval(holder, spender, wad); } }
File 7 of 9: DaiJoin
// hevm: flattened sources of /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/join.sol pragma solidity =0.5.12; ////// /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/lib.sol // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. /* pragma solidity 0.5.12; */ 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 ) } } } ////// /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/join.sol /// join.sol -- Basic token adapters // Copyright (C) 2018 Rain <[email protected]> // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <https://www.gnu.org/licenses/>. /* pragma solidity 0.5.12; */ /* import "./lib.sol"; */ contract GemLike { function decimals() public view returns (uint); function transfer(address,uint) external returns (bool); function transferFrom(address,address,uint) external returns (bool); } contract DSTokenLike { function mint(address,uint) external; function burn(address,uint) external; } contract VatLike { function slip(bytes32,address,int) external; function move(address,address,uint) external; } /* Here we provide *adapters* to connect the Vat to arbitrary external token implementations, creating a bounded context for the Vat. The adapters here are provided as working examples: - `GemJoin`: For well behaved ERC20 tokens, with simple transfer semantics. - `ETHJoin`: For native Ether. - `DaiJoin`: For connecting internal Dai balances to an external `DSToken` implementation. In practice, adapter implementations will be varied and specific to individual collateral types, accounting for different transfer semantics and token standards. Adapters need to implement two basic methods: - `join`: enter collateral into the system - `exit`: remove collateral from the system */ contract GemJoin is LibNote { // --- Auth --- mapping (address => uint) public wards; function rely(address usr) external note auth { wards[usr] = 1; } function deny(address usr) external note auth { wards[usr] = 0; } modifier auth { require(wards[msg.sender] == 1, "GemJoin/not-authorized"); _; } VatLike public vat; bytes32 public ilk; GemLike public gem; uint public dec; uint public live; // Access Flag constructor(address vat_, bytes32 ilk_, address gem_) public { wards[msg.sender] = 1; live = 1; vat = VatLike(vat_); ilk = ilk_; gem = GemLike(gem_); dec = gem.decimals(); } function cage() external note auth { live = 0; } function join(address usr, uint wad) external note { require(live == 1, "GemJoin/not-live"); require(int(wad) >= 0, "GemJoin/overflow"); vat.slip(ilk, usr, int(wad)); require(gem.transferFrom(msg.sender, address(this), wad), "GemJoin/failed-transfer"); } function exit(address usr, uint wad) external note { require(wad <= 2 ** 255, "GemJoin/overflow"); vat.slip(ilk, msg.sender, -int(wad)); require(gem.transfer(usr, wad), "GemJoin/failed-transfer"); } } contract ETHJoin is LibNote { // --- Auth --- mapping (address => uint) public wards; function rely(address usr) external note auth { wards[usr] = 1; } function deny(address usr) external note auth { wards[usr] = 0; } modifier auth { require(wards[msg.sender] == 1, "ETHJoin/not-authorized"); _; } VatLike public vat; bytes32 public ilk; uint public live; // Access Flag constructor(address vat_, bytes32 ilk_) public { wards[msg.sender] = 1; live = 1; vat = VatLike(vat_); ilk = ilk_; } function cage() external note auth { live = 0; } function join(address usr) external payable note { require(live == 1, "ETHJoin/not-live"); require(int(msg.value) >= 0, "ETHJoin/overflow"); vat.slip(ilk, usr, int(msg.value)); } function exit(address payable usr, uint wad) external note { require(int(wad) >= 0, "ETHJoin/overflow"); vat.slip(ilk, msg.sender, -int(wad)); usr.transfer(wad); } } contract DaiJoin is LibNote { // --- Auth --- mapping (address => uint) public wards; function rely(address usr) external note auth { wards[usr] = 1; } function deny(address usr) external note auth { wards[usr] = 0; } modifier auth { require(wards[msg.sender] == 1, "DaiJoin/not-authorized"); _; } VatLike public vat; DSTokenLike public dai; uint public live; // Access Flag constructor(address vat_, address dai_) public { wards[msg.sender] = 1; live = 1; vat = VatLike(vat_); dai = DSTokenLike(dai_); } function cage() external note auth { live = 0; } uint constant ONE = 10 ** 27; function mul(uint x, uint y) internal pure returns (uint z) { require(y == 0 || (z = x * y) / y == x); } function join(address usr, uint wad) external note { vat.move(address(this), usr, mul(ONE, wad)); dai.burn(msg.sender, wad); } function exit(address usr, uint wad) external note { require(live == 1, "DaiJoin/not-live"); vat.move(msg.sender, address(this), mul(ONE, wad)); dai.mint(usr, wad); } }
File 8 of 9: MigrationProxyActions
// hevm: flattened sources of /nix/store/nrmi9gk7q94ba1fbhq9bphlbpqd1y8hw-scd-mcd-migration-e730e63/src/MigrationProxyActions.sol pragma solidity =0.5.12 >0.4.13; ////// /nix/store/nrmi9gk7q94ba1fbhq9bphlbpqd1y8hw-scd-mcd-migration-e730e63/src/Interfaces.sol /* pragma solidity 0.5.12; */ contract GemLike { function allowance(address, address) public returns (uint); function approve(address, uint) public; function transfer(address, uint) public returns (bool); function transferFrom(address, address, uint) public returns (bool); } contract ValueLike { function peek() public returns (uint, bool); } contract SaiTubLike { function skr() public view returns (GemLike); function gem() public view returns (GemLike); function gov() public view returns (GemLike); function sai() public view returns (GemLike); function pep() public view returns (ValueLike); function vox() public view returns (VoxLike); function bid(uint) public view returns (uint); function ink(bytes32) public view returns (uint); function tag() public view returns (uint); function tab(bytes32) public returns (uint); function rap(bytes32) public returns (uint); function draw(bytes32, uint) public; function shut(bytes32) public; function exit(uint) public; function give(bytes32, address) public; } contract VoxLike { function par() public returns (uint); } contract JoinLike { function ilk() public returns (bytes32); function gem() public returns (GemLike); function dai() public returns (GemLike); function join(address, uint) public; function exit(address, uint) public; } contract VatLike { function ilks(bytes32) public view returns (uint, uint, uint, uint, uint); function hope(address) public; function frob(bytes32, address, address, address, int, int) public; } contract ManagerLike { function vat() public view returns (address); function urns(uint) public view returns (address); function open(bytes32, address) public returns (uint); function frob(uint, int, int) public; function give(uint, address) public; function move(uint, address, uint) public; } contract OtcLike { function getPayAmount(address, address, uint) public view returns (uint); function buyAllAmount(address, uint, address, uint) public; } ////// /nix/store/nrmi9gk7q94ba1fbhq9bphlbpqd1y8hw-scd-mcd-migration-e730e63/src/ScdMcdMigration.sol /* pragma solidity 0.5.12; */ /* import { JoinLike, ManagerLike, SaiTubLike, VatLike } from "./Interfaces.sol"; */ contract ScdMcdMigration { SaiTubLike public tub; VatLike public vat; ManagerLike public cdpManager; JoinLike public saiJoin; JoinLike public wethJoin; JoinLike public daiJoin; constructor( address tub_, // SCD tub contract address address cdpManager_, // MCD manager contract address address saiJoin_, // MCD SAI collateral adapter contract address address wethJoin_, // MCD ETH collateral adapter contract address address daiJoin_ // MCD DAI adapter contract address ) public { tub = SaiTubLike(tub_); cdpManager = ManagerLike(cdpManager_); vat = VatLike(cdpManager.vat()); saiJoin = JoinLike(saiJoin_); wethJoin = JoinLike(wethJoin_); daiJoin = JoinLike(daiJoin_); require(wethJoin.gem() == tub.gem(), "non-matching-weth"); require(saiJoin.gem() == tub.sai(), "non-matching-sai"); tub.gov().approve(address(tub), uint(-1)); tub.skr().approve(address(tub), uint(-1)); tub.sai().approve(address(tub), uint(-1)); tub.sai().approve(address(saiJoin), uint(-1)); wethJoin.gem().approve(address(wethJoin), uint(-1)); daiJoin.dai().approve(address(daiJoin), uint(-1)); vat.hope(address(daiJoin)); } function add(uint x, uint y) internal pure returns (uint z) { require((z = x + y) >= x, "add-overflow"); } function sub(uint x, uint y) internal pure returns (uint z) { require((z = x - y) <= x, "sub-underflow"); } function mul(uint x, uint y) internal pure returns (uint z) { require(y == 0 || (z = x * y) / y == x, "mul-overflow"); } function toInt(uint x) internal pure returns (int y) { y = int(x); require(y >= 0, "int-overflow"); } // Function to swap SAI to DAI // This function is to be used by users that want to get new DAI in exchange of old one (aka SAI) // wad amount has to be <= the value pending to reach the debt ceiling (the minimum between general and ilk one) function swapSaiToDai( uint wad ) external { // Get wad amount of SAI from user's wallet: saiJoin.gem().transferFrom(msg.sender, address(this), wad); // Join the SAI wad amount to the `vat`: saiJoin.join(address(this), wad); // Lock the SAI wad amount to the CDP and generate the same wad amount of DAI vat.frob(saiJoin.ilk(), address(this), address(this), address(this), toInt(wad), toInt(wad)); // Send DAI wad amount as a ERC20 token to the user's wallet daiJoin.exit(msg.sender, wad); } // Function to swap DAI to SAI // This function is to be used by users that want to get SAI in exchange of DAI // wad amount has to be <= the amount of SAI locked (and DAI generated) in the migration contract SAI CDP function swapDaiToSai( uint wad ) external { // Get wad amount of DAI from user's wallet: daiJoin.dai().transferFrom(msg.sender, address(this), wad); // Join the DAI wad amount to the vat: daiJoin.join(address(this), wad); // Payback the DAI wad amount and unlocks the same value of SAI collateral vat.frob(saiJoin.ilk(), address(this), address(this), address(this), -toInt(wad), -toInt(wad)); // Send SAI wad amount as a ERC20 token to the user's wallet saiJoin.exit(msg.sender, wad); } // Function to migrate a SCD CDP to MCD one (needs to be used via a proxy so the code can be kept simpler). Check MigrationProxyActions.sol code for usage. // In order to use migrate function, SCD CDP debtAmt needs to be <= SAI previously deposited in the SAI CDP * (100% - Collateralization Ratio) function migrate( bytes32 cup ) external returns (uint cdp) { // Get values uint debtAmt = tub.tab(cup); // CDP SAI debt uint pethAmt = tub.ink(cup); // CDP locked collateral uint ethAmt = tub.bid(pethAmt); // CDP locked collateral equiv in ETH // Take SAI out from MCD SAI CDP. For this operation is necessary to have a very low collateralization ratio // This is not actually a problem as this ilk will only be accessed by this migration contract, // which will make sure to have the amounts balanced out at the end of the execution. vat.frob( bytes32(saiJoin.ilk()), address(this), address(this), address(this), -toInt(debtAmt), 0 ); saiJoin.exit(address(this), debtAmt); // SAI is exited as a token // Shut SAI CDP and gets WETH back tub.shut(cup); // CDP is closed using the SAI just exited and the MKR previously sent by the user (via the proxy call) tub.exit(pethAmt); // Converts PETH to WETH // Open future user's CDP in MCD cdp = cdpManager.open(wethJoin.ilk(), address(this)); // Join WETH to Adapter wethJoin.join(cdpManager.urns(cdp), ethAmt); // Lock WETH in future user's CDP and generate debt to compensate the SAI used to paid the SCD CDP (, uint rate,,,) = vat.ilks(wethJoin.ilk()); cdpManager.frob( cdp, toInt(ethAmt), toInt(mul(debtAmt, 10 ** 27) / rate + 1) // To avoid rounding issues we add an extra wei of debt ); // Move DAI generated to migration contract (to recover the used funds) cdpManager.move(cdp, address(this), mul(debtAmt, 10 ** 27)); // Re-balance MCD SAI migration contract's CDP vat.frob( bytes32(saiJoin.ilk()), address(this), address(this), address(this), 0, -toInt(debtAmt) ); // Set ownership of CDP to the user cdpManager.give(cdp, msg.sender); } } ////// /nix/store/s6vv2mwc272ak68b4aibr7fhpa85ikw8-ds-math/dapp/ds-math/src/math.sol /// math.sol -- mixin for inline numerical wizardry // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. /* pragma solidity >0.4.13; */ contract DSMath { function add(uint x, uint y) internal pure returns (uint z) { require((z = x + y) >= x, "ds-math-add-overflow"); } function sub(uint x, uint y) internal pure returns (uint z) { require((z = x - y) <= x, "ds-math-sub-underflow"); } function mul(uint x, uint y) internal pure returns (uint z) { require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow"); } function min(uint x, uint y) internal pure returns (uint z) { return x <= y ? x : y; } function max(uint x, uint y) internal pure returns (uint z) { return x >= y ? x : y; } function imin(int x, int y) internal pure returns (int z) { return x <= y ? x : y; } function imax(int x, int y) internal pure returns (int z) { return x >= y ? x : y; } uint constant WAD = 10 ** 18; uint constant RAY = 10 ** 27; function wmul(uint x, uint y) internal pure returns (uint z) { z = add(mul(x, y), WAD / 2) / WAD; } function rmul(uint x, uint y) internal pure returns (uint z) { z = add(mul(x, y), RAY / 2) / RAY; } function wdiv(uint x, uint y) internal pure returns (uint z) { z = add(mul(x, WAD), y / 2) / y; } function rdiv(uint x, uint y) internal pure returns (uint z) { z = add(mul(x, RAY), y / 2) / y; } // This famous algorithm is called "exponentiation by squaring" // and calculates x^n with x as fixed-point and n as regular unsigned. // // It's O(log n), instead of O(n) for naive repeated multiplication. // // These facts are why it works: // // If n is even, then x^n = (x^2)^(n/2). // If n is odd, then x^n = x * x^(n-1), // and applying the equation for even x gives // x^n = x * (x^2)^((n-1) / 2). // // Also, EVM division is flooring and // floor[(n-1) / 2] = floor[n / 2]. // function rpow(uint x, uint n) internal pure returns (uint z) { z = n % 2 != 0 ? x : RAY; for (n /= 2; n != 0; n /= 2) { x = rmul(x, x); if (n % 2 != 0) { z = rmul(z, x); } } } } ////// /nix/store/nrmi9gk7q94ba1fbhq9bphlbpqd1y8hw-scd-mcd-migration-e730e63/src/MigrationProxyActions.sol /* pragma solidity 0.5.12; */ /* import "ds-math/math.sol"; */ /* import { GemLike, JoinLike, OtcLike, SaiTubLike } from "./Interfaces.sol"; */ /* import { ScdMcdMigration } from "./ScdMcdMigration.sol"; */ // This contract is intended to be executed via the Profile proxy of a user (DSProxy) which owns the SCD CDP contract MigrationProxyActions is DSMath { function swapSaiToDai( address scdMcdMigration, // Migration contract address uint wad // Amount to swap ) external { GemLike sai = SaiTubLike(ScdMcdMigration(scdMcdMigration).tub()).sai(); GemLike dai = JoinLike(ScdMcdMigration(scdMcdMigration).daiJoin()).dai(); sai.transferFrom(msg.sender, address(this), wad); if (sai.allowance(address(this), scdMcdMigration) < wad) { sai.approve(scdMcdMigration, wad); } ScdMcdMigration(scdMcdMigration).swapSaiToDai(wad); dai.transfer(msg.sender, wad); } function swapDaiToSai( address scdMcdMigration, // Migration contract address uint wad // Amount to swap ) external { GemLike sai = SaiTubLike(ScdMcdMigration(scdMcdMigration).tub()).sai(); GemLike dai = JoinLike(ScdMcdMigration(scdMcdMigration).daiJoin()).dai(); dai.transferFrom(msg.sender, address(this), wad); if (dai.allowance(address(this), scdMcdMigration) < wad) { dai.approve(scdMcdMigration, wad); } ScdMcdMigration(scdMcdMigration).swapDaiToSai(wad); sai.transfer(msg.sender, wad); } function migrate( address scdMcdMigration, // Migration contract address bytes32 cup // SCD CDP Id to migrate ) external returns (uint cdp) { SaiTubLike tub = ScdMcdMigration(scdMcdMigration).tub(); // Get necessary MKR fee and move it to the migration contract (uint val, bool ok) = tub.pep().peek(); if (ok && val != 0) { // Calculate necessary value of MKR to pay the govFee uint govFee = wdiv(tub.rap(cup), val); // Get MKR from the user's wallet and transfer to Migration contract tub.gov().transferFrom(msg.sender, address(scdMcdMigration), govFee); } // Transfer ownership of SCD CDP to the migration contract tub.give(cup, address(scdMcdMigration)); // Execute migrate function cdp = ScdMcdMigration(scdMcdMigration).migrate(cup); } function migratePayFeeWithGem( address scdMcdMigration, // Migration contract address bytes32 cup, // SCD CDP Id to migrate address otc, // Otc address address payGem, // Token address to be used for purchasing govFee MKR uint maxPayAmt // Max amount of payGem to sell for govFee MKR needed ) external returns (uint cdp) { SaiTubLike tub = ScdMcdMigration(scdMcdMigration).tub(); // Get necessary MKR fee and move it to the migration contract (uint val, bool ok) = tub.pep().peek(); if (ok && val != 0) { // Calculate necessary value of MKR to pay the govFee uint govFee = wdiv(tub.rap(cup), val); // Calculate how much payGem is needed for getting govFee value uint payAmt = OtcLike(otc).getPayAmount(payGem, address(tub.gov()), govFee); // Fails if exceeds maximum require(maxPayAmt >= payAmt, "maxPayAmt-exceeded"); // Set allowance, if necessary if (GemLike(payGem).allowance(address(this), otc) < payAmt) { GemLike(payGem).approve(otc, payAmt); } // Get payAmt of payGem from user's wallet require(GemLike(payGem).transferFrom(msg.sender, address(this), payAmt), "transfer-failed"); // Trade it for govFee amount of MKR OtcLike(otc).buyAllAmount(address(tub.gov()), govFee, payGem, payAmt); // Transfer govFee amount of MKR to Migration contract tub.gov().transfer(address(scdMcdMigration), govFee); } // Transfer ownership of SCD CDP to the migration contract tub.give(cup, address(scdMcdMigration)); // Execute migrate function cdp = ScdMcdMigration(scdMcdMigration).migrate(cup); } function _getRatio( SaiTubLike tub, bytes32 cup ) internal returns (uint ratio) { ratio = rdiv( rmul(tub.tag(), tub.ink(cup)), rmul(tub.vox().par(), tub.tab(cup)) ); } function migratePayFeeWithDebt( address scdMcdMigration, // Migration contract address bytes32 cup, // SCD CDP Id to migrate address otc, // Otc address uint maxPayAmt, // Max amount of SAI to generate to sell for govFee MKR needed uint minRatio // Min collateralization ratio after generating new debt (e.g. 180% = 1.8 RAY) ) external returns (uint cdp) { SaiTubLike tub = ScdMcdMigration(scdMcdMigration).tub(); // Get necessary MKR fee and move it to the migration contract (uint val, bool ok) = tub.pep().peek(); if (ok && val != 0) { // Calculate necessary value of MKR to pay the govFee uint govFee = wdiv(tub.rap(cup), val) + 1; // 1 extra wei MKR to avoid any possible rounding issue after drawing new SAI // Calculate how much SAI is needed for getting govFee value uint payAmt = OtcLike(otc).getPayAmount(address(tub.sai()), address(tub.gov()), govFee); // Fails if exceeds maximum require(maxPayAmt >= payAmt, "maxPayAmt-exceeded"); // Get payAmt of SAI from user's CDP tub.draw(cup, payAmt); require(_getRatio(tub, cup) > minRatio, "minRatio-failed"); // Set allowance, if necessary if (GemLike(address(tub.sai())).allowance(address(this), otc) < payAmt) { GemLike(address(tub.sai())).approve(otc, payAmt); } // Trade it for govFee amount of MKR OtcLike(otc).buyAllAmount(address(tub.gov()), govFee, address(tub.sai()), payAmt); // Transfer real needed govFee amount of MKR to Migration contract (it might leave some MKR dust in the proxy contract) govFee = wdiv(tub.rap(cup), val); tub.gov().transfer(address(scdMcdMigration), govFee); } // Transfer ownership of SCD CDP to the migration contract tub.give(cup, address(scdMcdMigration)); // Execute migrate function cdp = ScdMcdMigration(scdMcdMigration).migrate(cup); } }
File 9 of 9: SaiTub
// hevm: flattened sources of src/tub.sol pragma solidity ^0.4.18; ////// lib/ds-guard/lib/ds-auth/src/auth.sol // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. /* pragma solidity ^0.4.13; */ contract DSAuthority { function canCall( address src, address dst, bytes4 sig ) public 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; function DSAuth() public { owner = msg.sender; LogSetOwner(msg.sender); } function setOwner(address owner_) public auth { owner = owner_; LogSetOwner(owner); } function setAuthority(DSAuthority authority_) public auth { authority = authority_; LogSetAuthority(authority); } modifier auth { require(isAuthorized(msg.sender, msg.sig)); _; } 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, this, sig); } } } ////// lib/ds-spell/lib/ds-note/src/note.sol /// note.sol -- the `note' modifier, for logging calls as events // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. /* pragma solidity ^0.4.13; */ contract DSNote { event LogNote( bytes4 indexed sig, address indexed guy, bytes32 indexed foo, bytes32 indexed bar, uint wad, bytes fax ) anonymous; modifier note { bytes32 foo; bytes32 bar; assembly { foo := calldataload(4) bar := calldataload(36) } LogNote(msg.sig, msg.sender, foo, bar, msg.value, msg.data); _; } } ////// lib/ds-thing/lib/ds-math/src/math.sol /// math.sol -- mixin for inline numerical wizardry // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. /* pragma solidity ^0.4.13; */ contract DSMath { 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); } function min(uint x, uint y) internal pure returns (uint z) { return x <= y ? x : y; } function max(uint x, uint y) internal pure returns (uint z) { return x >= y ? x : y; } function imin(int x, int y) internal pure returns (int z) { return x <= y ? x : y; } function imax(int x, int y) internal pure returns (int z) { return x >= y ? x : y; } uint constant WAD = 10 ** 18; uint constant RAY = 10 ** 27; function wmul(uint x, uint y) internal pure returns (uint z) { z = add(mul(x, y), WAD / 2) / WAD; } function rmul(uint x, uint y) internal pure returns (uint z) { z = add(mul(x, y), RAY / 2) / RAY; } function wdiv(uint x, uint y) internal pure returns (uint z) { z = add(mul(x, WAD), y / 2) / y; } function rdiv(uint x, uint y) internal pure returns (uint z) { z = add(mul(x, RAY), y / 2) / y; } // This famous algorithm is called "exponentiation by squaring" // and calculates x^n with x as fixed-point and n as regular unsigned. // // It's O(log n), instead of O(n) for naive repeated multiplication. // // These facts are why it works: // // If n is even, then x^n = (x^2)^(n/2). // If n is odd, then x^n = x * x^(n-1), // and applying the equation for even x gives // x^n = x * (x^2)^((n-1) / 2). // // Also, EVM division is flooring and // floor[(n-1) / 2] = floor[n / 2]. // function rpow(uint x, uint n) internal pure returns (uint z) { z = n % 2 != 0 ? x : RAY; for (n /= 2; n != 0; n /= 2) { x = rmul(x, x); if (n % 2 != 0) { z = rmul(z, x); } } } } ////// lib/ds-thing/src/thing.sol // thing.sol - `auth` with handy mixins. your things should be DSThings // Copyright (C) 2017 DappHub, LLC // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. /* pragma solidity ^0.4.13; */ /* import 'ds-auth/auth.sol'; */ /* import 'ds-note/note.sol'; */ /* import 'ds-math/math.sol'; */ contract DSThing is DSAuth, DSNote, DSMath { function S(string s) internal pure returns (bytes4) { return bytes4(keccak256(s)); } } ////// lib/ds-token/lib/ds-stop/src/stop.sol /// stop.sol -- mixin for enable/disable functionality // Copyright (C) 2017 DappHub, LLC // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. /* pragma solidity ^0.4.13; */ /* import "ds-auth/auth.sol"; */ /* import "ds-note/note.sol"; */ contract DSStop is DSNote, DSAuth { bool public stopped; modifier stoppable { require(!stopped); _; } function stop() public auth note { stopped = true; } function start() public auth note { stopped = false; } } ////// lib/ds-token/lib/erc20/src/erc20.sol /// erc20.sol -- API for the ERC20 token standard // See <https://github.com/ethereum/EIPs/issues/20>. // This file likely does not meet the threshold of originality // required for copyright to apply. As a result, this is free and // unencumbered software belonging to the public domain. /* pragma solidity ^0.4.8; */ contract ERC20Events { event Approval(address indexed src, address indexed guy, uint wad); event Transfer(address indexed src, address indexed dst, uint wad); } contract ERC20 is ERC20Events { function totalSupply() public view returns (uint); function balanceOf(address guy) public view returns (uint); function allowance(address src, address guy) public view returns (uint); function approve(address guy, uint wad) public returns (bool); function transfer(address dst, uint wad) public returns (bool); function transferFrom( address src, address dst, uint wad ) public returns (bool); } ////// lib/ds-token/src/base.sol /// base.sol -- basic ERC20 implementation // Copyright (C) 2015, 2016, 2017 DappHub, LLC // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. /* pragma solidity ^0.4.13; */ /* import "erc20/erc20.sol"; */ /* import "ds-math/math.sol"; */ contract DSTokenBase is ERC20, DSMath { uint256 _supply; mapping (address => uint256) _balances; mapping (address => mapping (address => uint256)) _approvals; function DSTokenBase(uint supply) public { _balances[msg.sender] = supply; _supply = supply; } function totalSupply() public view returns (uint) { return _supply; } function balanceOf(address src) public view returns (uint) { return _balances[src]; } function allowance(address src, address guy) public view returns (uint) { return _approvals[src][guy]; } function transfer(address dst, uint wad) public returns (bool) { return transferFrom(msg.sender, dst, wad); } function transferFrom(address src, address dst, uint wad) public returns (bool) { if (src != msg.sender) { _approvals[src][msg.sender] = sub(_approvals[src][msg.sender], wad); } _balances[src] = sub(_balances[src], wad); _balances[dst] = add(_balances[dst], wad); Transfer(src, dst, wad); return true; } function approve(address guy, uint wad) public returns (bool) { _approvals[msg.sender][guy] = wad; Approval(msg.sender, guy, wad); return true; } } ////// lib/ds-token/src/token.sol /// token.sol -- ERC20 implementation with minting and burning // Copyright (C) 2015, 2016, 2017 DappHub, LLC // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. /* pragma solidity ^0.4.13; */ /* import "ds-stop/stop.sol"; */ /* import "./base.sol"; */ contract DSToken is DSTokenBase(0), DSStop { bytes32 public symbol; uint256 public decimals = 18; // standard token precision. override to customize function DSToken(bytes32 symbol_) public { symbol = symbol_; } event Mint(address indexed guy, uint wad); event Burn(address indexed guy, uint wad); function approve(address guy) public stoppable returns (bool) { return super.approve(guy, uint(-1)); } function approve(address guy, uint wad) public stoppable returns (bool) { return super.approve(guy, wad); } function transferFrom(address src, address dst, uint wad) public stoppable returns (bool) { if (src != msg.sender && _approvals[src][msg.sender] != uint(-1)) { _approvals[src][msg.sender] = sub(_approvals[src][msg.sender], wad); } _balances[src] = sub(_balances[src], wad); _balances[dst] = add(_balances[dst], wad); Transfer(src, dst, wad); return true; } function push(address dst, uint wad) public { transferFrom(msg.sender, dst, wad); } function pull(address src, uint wad) public { transferFrom(src, msg.sender, wad); } function move(address src, address dst, uint wad) public { transferFrom(src, dst, wad); } function mint(uint wad) public { mint(msg.sender, wad); } function burn(uint wad) public { burn(msg.sender, wad); } function mint(address guy, uint wad) public auth stoppable { _balances[guy] = add(_balances[guy], wad); _supply = add(_supply, wad); Mint(guy, wad); } function burn(address guy, uint wad) public auth stoppable { if (guy != msg.sender && _approvals[guy][msg.sender] != uint(-1)) { _approvals[guy][msg.sender] = sub(_approvals[guy][msg.sender], wad); } _balances[guy] = sub(_balances[guy], wad); _supply = sub(_supply, wad); Burn(guy, wad); } // Optional token name bytes32 public name = ""; function setName(bytes32 name_) public auth { name = name_; } } ////// lib/ds-value/src/value.sol /// value.sol - a value is a simple thing, it can be get and set // Copyright (C) 2017 DappHub, LLC // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. /* pragma solidity ^0.4.13; */ /* import 'ds-thing/thing.sol'; */ contract DSValue is DSThing { bool has; bytes32 val; function peek() public view returns (bytes32, bool) { return (val,has); } function read() public view returns (bytes32) { var (wut, haz) = peek(); assert(haz); return wut; } function poke(bytes32 wut) public note auth { val = wut; has = true; } function void() public note auth { // unset the value has = false; } } ////// src/vox.sol /// vox.sol -- target price feed // Copyright (C) 2016, 2017 Nikolai Mushegian <[email protected]> // Copyright (C) 2016, 2017 Daniel Brockman <[email protected]> // Copyright (C) 2017 Rain Break <[email protected]> // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. /* pragma solidity ^0.4.18; */ /* import "ds-thing/thing.sol"; */ contract SaiVox is DSThing { uint256 _par; uint256 _way; uint256 public fix; uint256 public how; uint256 public tau; function SaiVox(uint par_) public { _par = fix = par_; _way = RAY; tau = era(); } function era() public view returns (uint) { return block.timestamp; } function mold(bytes32 param, uint val) public note auth { if (param == 'way') _way = val; } // Dai Target Price (ref per dai) function par() public returns (uint) { prod(); return _par; } function way() public returns (uint) { prod(); return _way; } function tell(uint256 ray) public note auth { fix = ray; } function tune(uint256 ray) public note auth { how = ray; } function prod() public note { var age = era() - tau; if (age == 0) return; // optimised tau = era(); if (_way != RAY) _par = rmul(_par, rpow(_way, age)); // optimised if (how == 0) return; // optimised var wag = int128(how * age); _way = inj(prj(_way) + (fix < _par ? wag : -wag)); } function inj(int128 x) internal pure returns (uint256) { return x >= 0 ? uint256(x) + RAY : rdiv(RAY, RAY + uint256(-x)); } function prj(uint256 x) internal pure returns (int128) { return x >= RAY ? int128(x - RAY) : int128(RAY) - int128(rdiv(RAY, x)); } } ////// src/tub.sol /// tub.sol -- simplified CDP engine (baby brother of `vat') // Copyright (C) 2017 Nikolai Mushegian <[email protected]> // Copyright (C) 2017 Daniel Brockman <[email protected]> // Copyright (C) 2017 Rain Break <[email protected]> // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. /* pragma solidity ^0.4.18; */ /* import "ds-thing/thing.sol"; */ /* import "ds-token/token.sol"; */ /* import "ds-value/value.sol"; */ /* import "./vox.sol"; */ contract SaiTubEvents { event LogNewCup(address indexed lad, bytes32 cup); } contract SaiTub is DSThing, SaiTubEvents { DSToken public sai; // Stablecoin DSToken public sin; // Debt (negative sai) DSToken public skr; // Abstracted collateral ERC20 public gem; // Underlying collateral DSToken public gov; // Governance token SaiVox public vox; // Target price feed DSValue public pip; // Reference price feed DSValue public pep; // Governance price feed address public tap; // Liquidator address public pit; // Governance Vault uint256 public axe; // Liquidation penalty uint256 public cap; // Debt ceiling uint256 public mat; // Liquidation ratio uint256 public tax; // Stability fee uint256 public fee; // Governance fee uint256 public gap; // Join-Exit Spread bool public off; // Cage flag bool public out; // Post cage exit uint256 public fit; // REF per SKR (just before settlement) uint256 public rho; // Time of last drip uint256 _chi; // Accumulated Tax Rates uint256 _rhi; // Accumulated Tax + Fee Rates uint256 public rum; // Total normalised debt uint256 public cupi; mapping (bytes32 => Cup) public cups; struct Cup { address lad; // CDP owner uint256 ink; // Locked collateral (in SKR) uint256 art; // Outstanding normalised debt (tax only) uint256 ire; // Outstanding normalised debt } function lad(bytes32 cup) public view returns (address) { return cups[cup].lad; } function ink(bytes32 cup) public view returns (uint) { return cups[cup].ink; } function tab(bytes32 cup) public returns (uint) { return rmul(cups[cup].art, chi()); } function rap(bytes32 cup) public returns (uint) { return sub(rmul(cups[cup].ire, rhi()), tab(cup)); } // Total CDP Debt function din() public returns (uint) { return rmul(rum, chi()); } // Backing collateral function air() public view returns (uint) { return skr.balanceOf(this); } // Raw collateral function pie() public view returns (uint) { return gem.balanceOf(this); } //------------------------------------------------------------------ function SaiTub( DSToken sai_, DSToken sin_, DSToken skr_, ERC20 gem_, DSToken gov_, DSValue pip_, DSValue pep_, SaiVox vox_, address pit_ ) public { gem = gem_; skr = skr_; sai = sai_; sin = sin_; gov = gov_; pit = pit_; pip = pip_; pep = pep_; vox = vox_; axe = RAY; mat = RAY; tax = RAY; fee = RAY; gap = WAD; _chi = RAY; _rhi = RAY; rho = era(); } function era() public constant returns (uint) { return block.timestamp; } //--Risk-parameter-config------------------------------------------- function mold(bytes32 param, uint val) public note auth { if (param == 'cap') cap = val; else if (param == 'mat') { require(val >= RAY); mat = val; } else if (param == 'tax') { require(val >= RAY); drip(); tax = val; } else if (param == 'fee') { require(val >= RAY); drip(); fee = val; } else if (param == 'axe') { require(val >= RAY); axe = val; } else if (param == 'gap') { require(val >= WAD); gap = val; } else return; } //--Price-feed-setters---------------------------------------------- function setPip(DSValue pip_) public note auth { pip = pip_; } function setPep(DSValue pep_) public note auth { pep = pep_; } function setVox(SaiVox vox_) public note auth { vox = vox_; } //--Tap-setter------------------------------------------------------ function turn(address tap_) public note { require(tap == 0); require(tap_ != 0); tap = tap_; } //--Collateral-wrapper---------------------------------------------- // Wrapper ratio (gem per skr) function per() public view returns (uint ray) { return skr.totalSupply() == 0 ? RAY : rdiv(pie(), skr.totalSupply()); } // Join price (gem per skr) function ask(uint wad) public view returns (uint) { return rmul(wad, wmul(per(), gap)); } // Exit price (gem per skr) function bid(uint wad) public view returns (uint) { return rmul(wad, wmul(per(), sub(2 * WAD, gap))); } function join(uint wad) public note { require(!off); require(ask(wad) > 0); require(gem.transferFrom(msg.sender, this, ask(wad))); skr.mint(msg.sender, wad); } function exit(uint wad) public note { require(!off || out); require(gem.transfer(msg.sender, bid(wad))); skr.burn(msg.sender, wad); } //--Stability-fee-accumulation-------------------------------------- // Accumulated Rates function chi() public returns (uint) { drip(); return _chi; } function rhi() public returns (uint) { drip(); return _rhi; } function drip() public note { if (off) return; var rho_ = era(); var age = rho_ - rho; if (age == 0) return; // optimised rho = rho_; var inc = RAY; if (tax != RAY) { // optimised var _chi_ = _chi; inc = rpow(tax, age); _chi = rmul(_chi, inc); sai.mint(tap, rmul(sub(_chi, _chi_), rum)); } // optimised if (fee != RAY) inc = rmul(inc, rpow(fee, age)); if (inc != RAY) _rhi = rmul(_rhi, inc); } //--CDP-risk-indicator---------------------------------------------- // Abstracted collateral price (ref per skr) function tag() public view returns (uint wad) { return off ? fit : wmul(per(), uint(pip.read())); } // Returns true if cup is well-collateralized function safe(bytes32 cup) public returns (bool) { var pro = rmul(tag(), ink(cup)); var con = rmul(vox.par(), tab(cup)); var min = rmul(con, mat); return pro >= min; } //--CDP-operations-------------------------------------------------- function open() public note returns (bytes32 cup) { require(!off); cupi = add(cupi, 1); cup = bytes32(cupi); cups[cup].lad = msg.sender; LogNewCup(msg.sender, cup); } function give(bytes32 cup, address guy) public note { require(msg.sender == cups[cup].lad); require(guy != 0); cups[cup].lad = guy; } function lock(bytes32 cup, uint wad) public note { require(!off); cups[cup].ink = add(cups[cup].ink, wad); skr.pull(msg.sender, wad); require(cups[cup].ink == 0 || cups[cup].ink > 0.005 ether); } function free(bytes32 cup, uint wad) public note { require(msg.sender == cups[cup].lad); cups[cup].ink = sub(cups[cup].ink, wad); skr.push(msg.sender, wad); require(safe(cup)); require(cups[cup].ink == 0 || cups[cup].ink > 0.005 ether); } function draw(bytes32 cup, uint wad) public note { require(!off); require(msg.sender == cups[cup].lad); require(rdiv(wad, chi()) > 0); cups[cup].art = add(cups[cup].art, rdiv(wad, chi())); rum = add(rum, rdiv(wad, chi())); cups[cup].ire = add(cups[cup].ire, rdiv(wad, rhi())); sai.mint(cups[cup].lad, wad); require(safe(cup)); require(sai.totalSupply() <= cap); } function wipe(bytes32 cup, uint wad) public note { require(!off); var owe = rmul(wad, rdiv(rap(cup), tab(cup))); cups[cup].art = sub(cups[cup].art, rdiv(wad, chi())); rum = sub(rum, rdiv(wad, chi())); cups[cup].ire = sub(cups[cup].ire, rdiv(add(wad, owe), rhi())); sai.burn(msg.sender, wad); var (val, ok) = pep.peek(); if (ok && val != 0) gov.move(msg.sender, pit, wdiv(owe, uint(val))); } function shut(bytes32 cup) public note { require(!off); require(msg.sender == cups[cup].lad); if (tab(cup) != 0) wipe(cup, tab(cup)); if (ink(cup) != 0) free(cup, ink(cup)); delete cups[cup]; } function bite(bytes32 cup) public note { require(!safe(cup) || off); // Take on all of the debt, except unpaid fees var rue = tab(cup); sin.mint(tap, rue); rum = sub(rum, cups[cup].art); cups[cup].art = 0; cups[cup].ire = 0; // Amount owed in SKR, including liquidation penalty var owe = rdiv(rmul(rmul(rue, axe), vox.par()), tag()); if (owe > cups[cup].ink) { owe = cups[cup].ink; } skr.push(tap, owe); cups[cup].ink = sub(cups[cup].ink, owe); } //------------------------------------------------------------------ function cage(uint fit_, uint jam) public note auth { require(!off && fit_ != 0); off = true; axe = RAY; gap = WAD; fit = fit_; // ref per skr require(gem.transfer(tap, jam)); } function flow() public note auth { require(off); out = true; } }