2019-10-20 17:05:00 +00:00
pragma solidity ^ 0 . 5 . 8 ;
interface TubInterface {
function open ( ) external returns ( bytes32 ) ;
function join ( uint ) external ;
function exit ( uint ) external ;
function lock ( bytes32 , uint ) external ;
function free ( bytes32 , uint ) external ;
function draw ( bytes32 , uint ) external ;
function wipe ( bytes32 , uint ) external ;
function give ( bytes32 , address ) external ;
function shut ( bytes32 ) external ;
function cups ( bytes32 ) external view returns ( address , uint , uint , uint ) ;
function gem ( ) external view returns ( TokenInterface ) ;
function gov ( ) external view returns ( TokenInterface ) ;
function skr ( ) external view returns ( TokenInterface ) ;
function sai ( ) external view returns ( TokenInterface ) ;
function ink ( bytes32 ) external view returns ( uint ) ;
function tab ( bytes32 ) external returns ( uint ) ;
function rap ( bytes32 ) external returns ( uint ) ;
function per ( ) external view returns ( uint ) ;
function pep ( ) external view returns ( PepInterface ) ;
}
interface TokenInterface {
function allowance ( address , address ) external view returns ( uint ) ;
function balanceOf ( address ) external view returns ( uint ) ;
function approve ( address , uint ) external ;
function transfer ( address , uint ) external returns ( bool ) ;
function transferFrom ( address , address , uint ) external returns ( bool ) ;
function deposit ( ) external payable ;
function withdraw ( uint ) external ;
}
interface PepInterface {
function peek ( ) external returns ( bytes32 , bool ) ;
}
interface UniswapExchange {
function getEthToTokenOutputPrice ( uint256 tokensBought ) external view returns ( uint256 ethSold ) ;
function getTokenToEthOutputPrice ( uint256 ethBought ) external view returns ( uint256 tokensSold ) ;
function tokenToTokenSwapOutput (
uint256 tokensBought ,
uint256 maxTokensSold ,
uint256 maxEthSold ,
uint256 deadline ,
address tokenAddr
2019-10-21 22:55:08 +00:00
) external returns ( uint256 tokensSold ) ;
function ethToTokenSwapOutput ( uint256 tokensBought , uint256 deadline ) external payable returns ( uint256 ethSold ) ;
}
interface UniswapFactoryInterface {
function getExchange ( address token ) external view returns ( address exchange ) ;
2019-10-20 17:05:00 +00:00
}
interface MCDInterface {
function swapDaiToSai ( uint wad ) external ;
function migrate ( bytes32 cup ) external returns ( uint cdp ) ;
}
interface PoolInterface {
function accessToken ( address [ ] calldata ctknAddr , uint [ ] calldata tknAmt , bool isCompound ) external ;
function paybackToken ( address [ ] calldata ctknAddr , bool isCompound ) external payable ;
}
2019-10-21 22:55:08 +00:00
interface OtcInterface {
function getPayAmount ( address , address , uint ) external view returns ( uint ) ;
function buyAllAmount (
address ,
uint ,
address ,
uint
) external ;
}
2019-10-28 22:46:25 +00:00
interface ManagerLike {
function cdpCan ( address , uint , address ) external view returns ( uint ) ;
function ilks ( uint ) external view returns ( bytes32 ) ;
function owns ( uint ) external view returns ( address ) ;
function urns ( uint ) external view returns ( address ) ;
function vat ( ) external view returns ( address ) ;
function open ( bytes32 ) external returns ( uint ) ;
function give ( uint , address ) external ;
function cdpAllow ( uint , address , uint ) external ;
function urnAllow ( address , uint ) external ;
function frob ( uint , int , int ) external ;
function frob (
uint ,
address ,
int ,
int
) external ;
function flux ( uint , address , uint ) external ;
function move ( uint , address , uint ) external ;
function exit (
address ,
uint ,
address ,
uint
) external ;
function quit ( uint , address ) external ;
function enter ( address , uint ) external ;
function shift ( uint , uint ) external ;
}
2019-10-20 17:05:00 +00:00
contract DSMath {
function add ( uint x , uint y ) internal pure returns ( uint z ) {
require ( ( z = x + y ) >= x , " math-not-safe " ) ;
}
function sub ( uint x , uint y ) internal pure returns ( uint z ) {
z = x - y <= x ? x - y : 0 ;
}
function mul ( uint x , uint y ) internal pure returns ( uint z ) {
require ( y == 0 || ( z = x * y ) / y == x , " math-not-safe " ) ;
}
uint constant WAD = 10 ** 18 ;
uint constant RAY = 10 ** 27 ;
function rmul ( uint x , uint y ) internal pure returns ( uint z ) {
z = add ( mul ( x , y ) , RAY / 2 ) / RAY ;
}
function wmul ( uint x , uint y ) internal pure returns ( uint z ) {
z = add ( mul ( x , y ) , WAD / 2 ) / WAD ;
}
function rdiv ( uint x , uint y ) internal pure returns ( uint z ) {
z = add ( mul ( x , RAY ) , y / 2 ) / y ;
}
function wdiv ( uint x , uint y ) internal pure returns ( uint z ) {
z = add ( mul ( x , WAD ) , y / 2 ) / y ;
}
}
contract Helpers is DSMath {
/**
2019-10-22 19:02:10 +00:00
* @ dev get MakerDAO SCD CDP engine
2019-10-20 17:05:00 +00:00
* /
function getSaiTubAddress ( ) public pure returns ( address sai ) {
sai = 0x448a5065aeBB8E423F0896E6c5D525C040f59af3 ;
}
2019-10-22 19:02:10 +00:00
/**
* @ dev get Sai ( Dai v1 ) address
* /
2019-10-20 17:05:00 +00:00
function getSaiAddress ( ) public pure returns ( address sai ) {
sai = 0x448a5065aeBB8E423F0896E6c5D525C040f59af3 ;
}
2019-10-21 22:55:08 +00:00
/**
* @ dev get Compound WETH Address
* /
function getWETHAddress ( ) public pure returns ( address wethAddr ) {
wethAddr = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 ; // main
}
/**
2019-10-22 19:02:10 +00:00
* @ dev get OTC Address
2019-10-21 22:55:08 +00:00
* /
function getOtcAddress ( ) public pure returns ( address otcAddr ) {
otcAddr = 0x39755357759cE0d7f32dC8dC45414CCa409AE24e ; // main
}
2019-10-20 17:05:00 +00:00
/**
* @ dev get uniswap MKR exchange
* /
function getUniswapMKRExchange ( ) public pure returns ( address ume ) {
ume = 0x2C4Bd064b998838076fa341A83d007FC2FA50957 ;
}
2019-10-21 22:55:08 +00:00
/**
* @ dev get uniswap factory
* /
function getUniswapFactory ( ) public pure returns ( address addr ) {
addr = 0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95 ;
}
2019-10-20 17:05:00 +00:00
/**
* @ dev get InstaDApp Liquidity Address
* /
function getPoolAddress ( ) public pure returns ( address payable liqAddr ) {
liqAddr = 0x1564D040EC290C743F67F5cB11f3C1958B39872A ;
}
/**
2019-10-22 19:02:10 +00:00
* @ dev setting allowance if required
2019-10-20 17:05:00 +00:00
* /
2019-10-21 22:55:08 +00:00
function setApproval ( address erc20 , uint srcAmt , address to ) internal {
TokenInterface erc20Contract = TokenInterface ( erc20 ) ;
uint tokenAllowance = erc20Contract . allowance ( address ( this ) , to ) ;
if ( srcAmt > tokenAllowance ) {
2019-10-22 19:02:10 +00:00
erc20Contract . approve ( to , uint ( - 1 ) ) ;
2019-10-21 22:55:08 +00:00
}
2019-10-20 17:05:00 +00:00
}
}
2019-10-29 11:58:50 +00:00
contract LiquidityResolver is Helpers {
//Had to write seprate for pool, remix was showing error.
function getLiquidity ( uint _wad ) internal {
uint [ ] memory _wadArr = new uint [ ] ( 1 ) ;
_wadArr [ 0 ] = _wad ;
address [ ] memory addrArr = new address [ ] ( 1 ) ;
addrArr [ 0 ] = address ( 0 ) ;
// Get liquidity assets to payback user wallet borrowed assets
PoolInterface ( getPoolAddress ( ) ) . accessToken ( addrArr , _wadArr , false ) ;
}
function paybackLiquidity ( uint _wad ) internal {
address [ ] memory addrArr = new address [ ] ( 1 ) ;
addrArr [ 0 ] = address ( 0 ) ;
// transfer and payback dai to InstaDApp pool.
require ( TokenInterface ( getSaiAddress ( ) ) . transfer ( getPoolAddress ( ) , _wad ) , " Not-enough-dai " ) ;
PoolInterface ( getPoolAddress ( ) ) . paybackToken ( addrArr , false ) ;
}
}
contract MKRSwapper is LiquidityResolver {
2019-10-24 21:09:08 +00:00
function swapToMkrOtc ( address tokenAddr , uint govFee ) internal {
TokenInterface mkr = TubInterface ( getSaiTubAddress ( ) ) . gov ( ) ;
uint payAmt = OtcInterface ( getOtcAddress ( ) ) . getPayAmount ( tokenAddr , address ( mkr ) , govFee ) ;
if ( tokenAddr == getWETHAddress ( ) ) {
TokenInterface weth = TokenInterface ( getWETHAddress ( ) ) ;
weth . deposit . value ( payAmt ) ( ) ;
} else {
require ( TokenInterface ( tokenAddr ) . transferFrom ( msg . sender , address ( this ) , payAmt ) , " Tranfer-failed " ) ;
}
setApproval ( tokenAddr , payAmt , getOtcAddress ( ) ) ;
OtcInterface ( getOtcAddress ( ) ) . buyAllAmount (
address ( mkr ) ,
govFee ,
tokenAddr ,
payAmt
) ;
}
}
contract SCDResolver is MKRSwapper {
2019-10-20 17:05:00 +00:00
2019-10-22 19:02:10 +00:00
function open ( ) internal returns ( bytes32 cup ) {
2019-10-20 17:05:00 +00:00
cup = TubInterface ( getSaiTubAddress ( ) ) . open ( ) ;
}
2019-10-24 21:09:08 +00:00
function wipe ( bytes32 cup , uint _wad , address payFeeWith ) internal {
2019-10-21 22:55:08 +00:00
if ( _wad > 0 ) {
TubInterface tub = TubInterface ( getSaiTubAddress ( ) ) ;
TokenInterface dai = tub . sai ( ) ;
TokenInterface mkr = tub . gov ( ) ;
( address lad , , , ) = tub . cups ( cup ) ;
require ( lad == address ( this ) , " cup-not-owned " ) ;
setAllowance ( dai , getSaiTubAddress ( ) ) ;
setAllowance ( mkr , getSaiTubAddress ( ) ) ;
2019-10-24 21:09:08 +00:00
( bytes32 val , bool ok ) = tub . pep ( ) . peek ( ) ;
2019-10-20 17:05:00 +00:00
2019-10-24 21:09:08 +00:00
if ( ok && val != 0 ) {
// MKR required for wipe = Stability fees accrued in Dai / MKRUSD value
2019-10-29 11:58:50 +00:00
uint mkrFee = rdiv ( tub . rap ( cup ) , tub . tab ( cup ) ) ;
2019-10-24 21:09:08 +00:00
mkrFee = rmul ( _wad , mkrFee ) ;
mkrFee = wdiv ( mkrFee , uint ( val ) ) ;
2019-10-20 17:05:00 +00:00
2019-10-24 21:09:08 +00:00
swapToMkrOtc ( payFeeWith , mkrFee ) ; //otc
}
2019-10-21 22:55:08 +00:00
2019-10-24 21:09:08 +00:00
tub . wipe ( cup , _wad ) ;
2019-10-20 17:05:00 +00:00
}
}
2019-10-24 21:09:08 +00:00
function free ( bytes32 cup , uint ink ) internal {
if ( ink > 0 ) {
2019-10-29 11:58:50 +00:00
TubInterface ( getSaiTubAddress ( ) ) . free ( cup , ink ) ; // free PETH
2019-10-24 21:09:08 +00:00
}
}
2019-10-20 17:05:00 +00:00
2019-10-24 21:09:08 +00:00
function lock ( bytes32 cup , uint ink ) internal {
if ( ink > 0 ) {
TubInterface tub = TubInterface ( getSaiTubAddress ( ) ) ;
2019-10-21 22:55:08 +00:00
TokenInterface peth = tub . skr ( ) ;
( address lad , , , ) = tub . cups ( cup ) ;
require ( lad == address ( this ) , " cup-not-owned " ) ;
2019-10-24 21:09:08 +00:00
setAllowance ( peth , getSaiTubAddress ( ) ) ;
2019-10-21 22:55:08 +00:00
tub . lock ( cup , ink ) ;
2019-10-20 17:05:00 +00:00
}
}
2019-10-21 22:55:08 +00:00
function draw ( bytes32 cup , uint _wad ) internal {
2019-10-20 17:05:00 +00:00
if ( _wad > 0 ) {
TubInterface tub = TubInterface ( getSaiTubAddress ( ) ) ;
tub . draw ( cup , _wad ) ;
}
}
2019-10-21 22:55:08 +00:00
function setAllowance ( TokenInterface _token , address _spender ) private {
if ( _token . allowance ( address ( this ) , _spender ) != uint ( - 1 ) ) {
_token . approve ( _spender , uint ( - 1 ) ) ;
}
}
2019-10-20 17:05:00 +00:00
2019-10-21 22:55:08 +00:00
}
2019-10-20 17:05:00 +00:00
2019-10-24 21:09:08 +00:00
contract MCDResolver is SCDResolver {
2019-10-20 17:05:00 +00:00
function migrateToMCD (
address payable scdMcdMigration , // Migration contract address
bytes32 cup , // SCD CDP Id to migrate
2019-10-29 11:58:50 +00:00
address payGem // Token address
2019-10-20 17:05:00 +00:00
) internal returns ( uint cdp )
{
TubInterface tub = TubInterface ( getSaiTubAddress ( ) ) ;
tub . give ( cup , address ( scdMcdMigration ) ) ;
// Get necessary MKR fee and move it to the migration contract
( bytes32 val , bool ok ) = tub . pep ( ) . peek ( ) ;
if ( ok && uint ( val ) != 0 ) {
// Calculate necessary value of MKR to pay the govFee
uint govFee = wdiv ( tub . rap ( cup ) , uint ( val ) ) ;
if ( payGem != address ( 0 ) ) {
2019-10-21 22:55:08 +00:00
swapToMkrOtc ( payGem , govFee ) ;
2019-10-20 17:05:00 +00:00
} else {
2019-10-24 21:09:08 +00:00
require ( tub . gov ( ) . transferFrom ( msg . sender , address ( this ) , govFee ) , " transfer-failed " ) ; // Check Samyak - We can directly transfer MKR to address(scdMcdMigration). Right?
2019-10-20 17:05:00 +00:00
}
require ( tub . gov ( ) . transfer ( address ( scdMcdMigration ) , govFee ) , " transfer-failed " ) ;
}
// Execute migrate function
cdp = MCDInterface ( scdMcdMigration ) . migrate ( cup ) ;
}
2019-10-28 22:46:25 +00:00
2019-10-29 11:58:50 +00:00
function shiftCDP (
2019-10-28 22:46:25 +00:00
address manager ,
uint cdpSrc ,
uint cdpOrg
) internal
{
2019-10-29 11:30:30 +00:00
require ( ManagerLike ( manager ) . owns ( cdpOrg ) == address ( this ) , " NOT-OWNER " ) ;
2019-10-28 22:46:25 +00:00
ManagerLike ( manager ) . shift ( cdpSrc , cdpOrg ) ;
}
2019-10-20 17:05:00 +00:00
}
2019-10-29 11:58:50 +00:00
contract MigrateHelper is MCDResolver {
2019-10-29 11:30:30 +00:00
function setSplitAmount ( bytes32 cup , uint toConvert , address daiJoin ) internal returns ( uint _wad , uint _ink , uint maxConvert ) {
// Set ratio according to user.
TubInterface tub = TubInterface ( getSaiTubAddress ( ) ) ;
maxConvert = toConvert ;
uint saiBal = tub . sai ( ) . balanceOf ( daiJoin ) ;
uint _wadTotal = tub . tab ( cup ) ;
// wad according to toConvert ratio
_wad = wmul ( _wadTotal , toConvert ) ;
//if sai_join has enough sai to migrate.
if ( saiBal < _wad ) {
// set saiBal as wad amount.
_wad = sub ( saiBal , 1000 ) ;
// set new convert ratio according to sai_join balance.
maxConvert = sub ( wdiv ( saiBal , _wadTotal ) , 100 ) ;
}
// ink according to maxConvert ratio.
_ink = wmul ( tub . ink ( cup ) , maxConvert ) ; // Taking collateral in PETH only
}
function splitCdp (
bytes32 scdCup ,
bytes32 splitCup ,
uint _wad ,
uint _ink ,
address payFeeWith
) internal
{
//getting InstaDApp Pool Balance.
uint initialPoolBal = sub ( getPoolAddress ( ) . balance , 10000000000 ) ;
//fetch liquidity from InstaDApp Pool.
getLiquidity ( _wad ) ;
//transfer assets from scdCup to splitCup.
wipe ( scdCup , _wad , payFeeWith ) ;
free ( scdCup , _ink ) ;
lock ( splitCup , _ink ) ;
draw ( splitCup , _wad ) ;
//transfer and payback liquidity to InstaDApp Pool.
paybackLiquidity ( _wad ) ;
uint finalPoolBal = getPoolAddress ( ) . balance ;
assert ( finalPoolBal >= initialPoolBal ) ;
}
}
contract MigrateResolver is MigrateHelper {
2019-10-26 19:42:48 +00:00
2019-10-29 11:30:30 +00:00
event LogMigrate ( uint scdCdp , uint toConvert , address payFeeWith , uint mcdCdp , uint newMcdCdp ) ;
2019-10-28 22:46:25 +00:00
event LogMigrateAndMerge ( uint scdCdp , uint toConvert , address payFeeWith , uint mcdMergeCdp ) ;
2019-10-26 19:42:48 +00:00
2019-10-20 17:05:00 +00:00
function migrate (
2019-10-22 19:02:10 +00:00
uint scdCDP ,
2019-10-29 11:30:30 +00:00
uint mergeCDP ,
2019-10-20 17:05:00 +00:00
uint toConvert ,
address payFeeWith ,
2019-10-26 19:09:27 +00:00
address payable scdMcdMigration ,
2019-10-29 11:30:30 +00:00
address manager ,
address daiJoin
2019-10-28 22:46:25 +00:00
) external payable returns ( uint newMcdCdp )
2019-10-20 17:05:00 +00:00
{
2019-10-22 19:02:10 +00:00
bytes32 scdCup = bytes32 ( scdCDP ) ;
2019-10-26 19:09:27 +00:00
uint maxConvert = toConvert ;
2019-10-22 19:02:10 +00:00
2019-10-21 22:55:08 +00:00
if ( toConvert < 10 ** 18 ) {
2019-10-29 11:30:30 +00:00
//new cdp for spliting assets.
2019-10-20 17:05:00 +00:00
bytes32 splitCup = TubInterface ( getSaiTubAddress ( ) ) . open ( ) ;
2019-10-29 11:30:30 +00:00
//set split amount according to toConvert and dai_join balance.
uint _wad ;
uint _ink ;
( _wad , _ink , maxConvert ) = setSplitAmount ( scdCup , toConvert , daiJoin ) ;
//split the assets into split cdp.
splitCdp (
scdCup ,
splitCup ,
_wad ,
_ink ,
payFeeWith
) ;
2019-10-20 17:05:00 +00:00
2019-10-29 11:30:30 +00:00
//migrate the split cdp.
2019-10-28 22:46:25 +00:00
newMcdCdp = migrateToMCD ( scdMcdMigration , splitCup , payFeeWith ) ;
2019-10-20 17:05:00 +00:00
} else {
2019-10-29 11:30:30 +00:00
//migrate the scd cdp.
2019-10-28 22:46:25 +00:00
newMcdCdp = migrateToMCD ( scdMcdMigration , scdCup , payFeeWith ) ;
2019-10-20 17:05:00 +00:00
}
2019-10-22 19:02:10 +00:00
2019-10-29 11:30:30 +00:00
//Transfer if any ETH leftover.
if ( address ( this ) . balance > 0 ) {
msg . sender . transfer ( address ( this ) . balance ) ;
}
2019-10-22 19:02:10 +00:00
2019-10-29 11:30:30 +00:00
//merge the already existing mcd cdp with the new migrated cdp.
2019-10-28 22:46:25 +00:00
if ( mergeCDP != 0 ) {
shiftCDP ( manager , newMcdCdp , mergeCDP ) ;
}
2019-10-29 11:30:30 +00:00
emit LogMigrate (
uint ( scdCup ) ,
maxConvert ,
payFeeWith ,
mergeCDP ,
newMcdCdp
) ;
2019-10-20 17:05:00 +00:00
}
}
contract InstaMcdMigrate is MigrateResolver {
function ( ) external payable { }
}