def main(): admin = accounts[0] alice = accounts[1] usdt = interface.IERC20Ex('0xdAC17F958D2ee523a2206206994597C13D831ec7') weth = interface.IERC20Ex('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2') lp = interface.IERC20Ex('0x0d4a11d5EEaaC28EC3F61d100daF4d40471f1852') crusdt = interface.ICErc20('0x797AAB1ce7c01eB727ab980762bA88e7133d2157') router = interface.IUniswapV2Router02( '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D') chef = accounts.at('0xc2edad668740f1aa35e4d8f227fb8e17dca888cd', force=True) wchef = WMasterChef.deploy(chef, {'from': admin}) werc20 = WERC20.deploy({'from': admin}) simple_oracle = SimpleOracle.deploy({'from': admin}) simple_oracle.setETHPx( [usdt, weth], [9011535487953795006625883219171279625142296, 2**112]) uniswap_oracle = UniswapV2Oracle.deploy(simple_oracle, {'from': admin}) core_oracle = CoreOracle.deploy({'from': admin}) oracle = ProxyOracle.deploy(core_oracle, {'from': admin}) oracle.setWhitelistERC1155([werc20], True, {'from': admin}) core_oracle.setRoute( [usdt, weth, lp], [simple_oracle, simple_oracle, uniswap_oracle], {'from': admin}, ) oracle.setOracles( [usdt, weth, lp], [ [10000, 10000, 10000], [10000, 10000, 10000], [10000, 10000, 10000], ], {'from': admin}, ) homora = HomoraBank.deploy({'from': admin}) homora.initialize(oracle, 1000, {'from': admin}) # 10% fee setup_bank_hack(homora) homora.addBank(usdt, crusdt, {'from': admin}) # setup initial funds to alice mint_tokens(usdt, alice) mint_tokens(weth, alice) # check alice's funds print(f'Alice usdt balance {usdt.balanceOf(alice)}') print(f'Alice weth balance {weth.balanceOf(alice)}') # Steal some LP from the staking pool mint_tokens(lp, alice) # set approval usdt.approve(homora, 2**256 - 1, {'from': alice}) usdt.approve(crusdt, 2**256 - 1, {'from': alice}) weth.approve(homora, 2**256 - 1, {'from': alice}) lp.approve(homora, 2**256 - 1, {'from': alice}) uniswap_spell = UniswapV2SpellV1.deploy(homora, werc20, router, {'from': admin}) # first time call to reduce gas uniswap_spell.getPair(weth, usdt, {'from': admin}) # whitelist spell in bank homora.setWhitelistSpells([uniswap_spell], [True], {'from': admin}) # whitelist lp in spell uniswap_spell.setWhitelistLPTokens([lp], [True], {'from': admin}) ##################################################################################### print( '=========================================================================' ) print('Case 1.') prevABal = usdt.balanceOf(alice) prevBBal = weth.balanceOf(alice) prevLPBal = lp.balanceOf(alice) prevLPBal_bank = lp.balanceOf(homora) prevLPBal_werc20 = lp.balanceOf(werc20) if interface.IUniswapV2Pair(lp).token0() == usdt: prevARes, prevBRes, _ = interface.IUniswapV2Pair(lp).getReserves() else: prevBRes, prevARes, _ = interface.IUniswapV2Pair(lp).getReserves() usdt_amt = 400 * 10**6 weth_amt = 10**18 lp_amt = 1 * 10**16 borrow_usdt_amt = 0 borrow_weth_amt = 0 tx = homora.execute( 0, uniswap_spell, uniswap_spell.addLiquidityWERC20.encode_input( usdt, # token 0 weth, # token 1 [ usdt_amt, # supply USDT weth_amt, # supply WETH lp_amt, # supply LP borrow_usdt_amt, # borrow USDT borrow_weth_amt, # borrow WETH 0, # borrow LP tokens 0, # min USDT 0 ], # min WETH ), {'from': alice}) curABal = usdt.balanceOf(alice) curBBal = weth.balanceOf(alice) curLPBal = lp.balanceOf(alice) curLPBal_bank = lp.balanceOf(homora) curLPBal_werc20 = lp.balanceOf(werc20) if interface.IUniswapV2Pair(lp).token0() == usdt: curARes, curBRes, _ = interface.IUniswapV2Pair(lp).getReserves() else: curBRes, curARes, _ = interface.IUniswapV2Pair(lp).getReserves() print('spell lp balance', lp.balanceOf(uniswap_spell)) print('Alice delta A balance', curABal - prevABal) print('Alice delta B balance', curBBal - prevBBal) print('add liquidity gas', tx.gas_used) print('bank lp balance', curLPBal_bank) _, _, _, totalDebt, totalShare = homora.getBankInfo(usdt) print('bank usdt totalDebt', totalDebt) print('bank usdt totalShare', totalShare) print('bank prev LP balance', prevLPBal_bank) print('bank cur LP balance', curLPBal_bank) print('werc20 prev LP balance', prevLPBal_werc20) print('werc20 cur LP balance', curLPBal_werc20) print('prev usdt res', prevARes) print('cur usdt res', curARes) print('prev weth res', prevBRes) print('cur weth res', curBRes) # alice assert almostEqual(curABal - prevABal, -usdt_amt), 'incorrect USDT amt' assert almostEqual(curBBal - prevBBal, -weth_amt), 'incorrect WETH amt' assert curLPBal - prevLPBal == -lp_amt, 'incorrect LP amt' # spell assert usdt.balanceOf(uniswap_spell) == 0, 'non-zero spell USDT balance' assert weth.balanceOf(uniswap_spell) == 0, 'non-zero spell WETH balance' assert lp.balanceOf(uniswap_spell) == 0, 'non-zero spell LP balance' assert totalDebt == borrow_usdt_amt # check balance and pool reserves assert curABal - prevABal - borrow_usdt_amt == - \ (curARes - prevARes), 'not all USDT tokens go to LP pool' assert almostEqual( curBBal - prevBBal - borrow_weth_amt, -(curBRes - prevBRes)), 'not all WETH tokens go to LP pool' ##################################################################################### print( '=========================================================================' ) print('Case 2.') # remove liquidity from the same position prevABal = usdt.balanceOf(alice) prevBBal = weth.balanceOf(alice) prevLPBal = lp.balanceOf(alice) prevLPBal_bank = lp.balanceOf(homora) prevLPBal_werc20 = lp.balanceOf(werc20) prevETHBal = alice.balance() if interface.IUniswapV2Pair(lp).token0() == usdt: prevARes, prevBRes, _ = interface.IUniswapV2Pair(lp).getReserves() else: prevBRes, prevARes, _ = interface.IUniswapV2Pair(lp).getReserves() lp_take_amt = 1 * 10**16 lp_want = 1 * 10**15 usdt_repay = 2**256 - 1 # max weth_repay = 0 real_usdt_repay = homora.borrowBalanceStored(1, usdt) tx = homora.execute( 1, uniswap_spell, uniswap_spell.removeLiquidityWERC20.encode_input( usdt, # token 0 weth, # token 1 [ lp_take_amt, # take out LP tokens lp_want, # withdraw LP tokens to wallet usdt_repay, # repay USDT 0, # repay WETH 0, # repay LP 0, # min USDT 0 ], # min WETH ), {'from': alice}) curABal = usdt.balanceOf(alice) curBBal = weth.balanceOf(alice) curLPBal = lp.balanceOf(alice) curLPBal_bank = lp.balanceOf(homora) curLPBal_werc20 = lp.balanceOf(werc20) curETHBal = alice.balance() if interface.IUniswapV2Pair(lp).token0() == usdt: curARes, curBRes, _ = interface.IUniswapV2Pair(lp).getReserves() else: curBRes, curARes, _ = interface.IUniswapV2Pair(lp).getReserves() print('spell lp balance', lp.balanceOf(uniswap_spell)) print('spell usdt balance', usdt.balanceOf(uniswap_spell)) print('spell weth balance', weth.balanceOf(uniswap_spell)) print('Alice delta A balance', curABal - prevABal) print('Alice delta B balance', curBBal - prevBBal) print('Alice delta LP balance', curLPBal - prevLPBal) print('remove liquidity gas', tx.gas_used) print('bank delta lp balance', curLPBal_bank - prevLPBal_bank) print('bank total lp balance', curLPBal_bank) _, _, _, totalDebt, totalShare = homora.getBankInfo(usdt) print('bank usdt totalDebt', totalDebt) print('bank usdt totalShare', totalShare) print('LP want', lp_want) print('bank delta LP amount', curLPBal_bank - prevLPBal_bank) print('LP take amount', lp_take_amt) print('prev werc20 LP balance', prevLPBal_werc20) print('cur werc20 LP balance', curLPBal_werc20) print('real usdt repay', real_usdt_repay) # alice assert almostEqual(curBBal - prevBBal, 0), 'incorrect WETH amt' assert almostEqual(curLPBal - prevLPBal, lp_want), 'incorrect LP amt' # werc20 assert almostEqual(curLPBal_werc20 - prevLPBal_werc20, -lp_take_amt), 'incorrect werc20 LP amt' # spell assert usdt.balanceOf(uniswap_spell) == 0, 'non-zero spell USDT balance' assert weth.balanceOf(uniswap_spell) == 0, 'non-zero spell WETH balance' assert lp.balanceOf(uniswap_spell) == 0, 'non-zero spell LP balance' # check balance and pool reserves assert almostEqual( curABal - prevABal + real_usdt_repay, -(curARes - prevARes)), 'inconsistent USDT from withdraw' assert almostEqual(curBBal - prevBBal, 0), 'inconsistent WETH from withdraw' assert almostEqual(curETHBal - prevETHBal + weth_repay, -(curBRes - prevBRes)), 'inconsistent ETH from withdraw' return tx
def main(): admin = accounts[0] alice = accounts[1] usdt = interface.IERC20Ex('0xdAC17F958D2ee523a2206206994597C13D831ec7') usdc = interface.IERC20Ex('0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48') lp = interface.IERC20Ex('0x3041cbd36888becc7bbcbc0045e3b1f144466f5f') crusdt = interface.ICErc20('0x797AAB1ce7c01eB727ab980762bA88e7133d2157') crusdc = interface.ICErc20('0x44fbebd2f576670a6c33f6fc0b00aa8c5753b322') router = interface.IUniswapV2Router02( '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D') chef = accounts.at('0xc2edad668740f1aa35e4d8f227fb8e17dca888cd', force=True) wchef = WMasterChef.deploy(chef, {'from': admin}) werc20 = WERC20.deploy({'from': admin}) simple_oracle = SimpleOracle.deploy({'from': admin}) simple_oracle.setETHPx([usdt, usdc], [ 8343331721347310729683379470025550036595362, 8344470555541464992529317899641128796042472 ]) uniswap_oracle = UniswapV2Oracle.deploy(simple_oracle, {'from': admin}) core_oracle = CoreOracle.deploy({'from': admin}) oracle = ProxyOracle.deploy(core_oracle, {'from': admin}) oracle.setWhitelistERC1155([werc20], True, {'from': admin}) core_oracle.setRoute( [usdt, usdc, lp], [simple_oracle, simple_oracle, uniswap_oracle], {'from': admin}, ) oracle.setOracles( [usdt, usdc, lp], [ [10000, 10000, 10000], [10000, 10000, 10000], [10000, 10000, 10000], ], {'from': admin}, ) # initialize homora = HomoraBank.deploy({'from': admin}) homora.initialize(oracle, 1000, {'from': admin}) # 10% fee setup_bank_hack(homora) # add bank homora.addBank(usdt, crusdt, {'from': admin}) homora.addBank(usdc, crusdc, {'from': admin}) # setup initial funds to alice mint_tokens(usdt, alice) mint_tokens(usdc, alice) # check alice's funds print(f'Alice usdt balance {usdt.balanceOf(alice)}') print(f'Alice usdc balance {usdc.balanceOf(alice)}') # steal some LP from the staking pool mint_tokens(lp, alice) # set approval usdt.approve(homora, 2**256 - 1, {'from': alice}) usdt.approve(crusdt, 2**256 - 1, {'from': alice}) usdc.approve(homora, 2**256 - 1, {'from': alice}) usdc.approve(crusdc, 2**256 - 1, {'from': alice}) lp.approve(homora, 2**256 - 1, {'from': alice}) uniswap_spell = UniswapV2SpellV1.deploy(homora, werc20, router, {'from': admin}) # first time call to reduce gas uniswap_spell.getPair(usdt, usdc, {'from': admin}) ##################################################################################### print( '=========================================================================' ) print('Case 1.') prevABal = usdt.balanceOf(alice) prevBBal = usdc.balanceOf(alice) prevLPBal = lp.balanceOf(alice) prevLPBal_bank = lp.balanceOf(homora) prevLPBal_werc20 = lp.balanceOf(werc20) usdt_amt = 40000 * 10**6 # 40000 USDT usdc_amt = 50000 * 10**6 # 50000 USDC lp_amt = 1 * 10**7 borrow_usdt_amt = 1000 * 10**6 # 1000 USDT borrow_usdc_amt = 200 * 10**6 # 200 USDC tx = homora.execute( 0, uniswap_spell, uniswap_spell.addLiquidityWERC20.encode_input( usdt, # token 0 usdc, # token 1 [ usdt_amt, # supply USDT usdc_amt, # supply USDC lp_amt, # supply LP borrow_usdt_amt, # borrow USDT borrow_usdc_amt, # borrow USDC 0, # borrow LP tokens 0, # min USDT 0 ], # min USDC ), {'from': alice}) curABal = usdt.balanceOf(alice) curBBal = usdc.balanceOf(alice) curLPBal = lp.balanceOf(alice) curLPBal_bank = lp.balanceOf(homora) curLPBal_werc20 = lp.balanceOf(werc20) print('spell lp balance', lp.balanceOf(uniswap_spell)) print('Alice delta A balance', curABal - prevABal) print('Alice delta B balance', curBBal - prevBBal) print('add liquidity gas', tx.gas_used) print('bank lp balance', curLPBal_bank) _, _, _, usdtDebt, usdtDebtShare = homora.getBankInfo(usdt) _, _, _, usdcDebt, usdcDebtShare = homora.getBankInfo(usdc) print('bank usdt totalDebt', usdtDebt) print('bank usdt totalShare', usdtDebtShare) print('bank usdc totalDebt', usdcDebt) print('bank usdc totalShare', usdcDebtShare) print('bank prev LP balance', prevLPBal_bank) print('bank cur LP balance', curLPBal_bank) print('werc20 prev LP balance', prevLPBal_werc20) print('werc20 cur LP balance', curLPBal_werc20) # alice assert almostEqual(curABal - prevABal, -usdt_amt), 'incorrect USDT amt' assert almostEqual(curBBal - prevBBal, -usdc_amt), 'incorrect USDC amt' assert almostEqual(curLPBal - prevLPBal, -lp_amt), 'incorrect LP amt' # spell assert usdt.balanceOf(uniswap_spell) == 0, 'non-zero spell USDT balance' assert usdc.balanceOf(uniswap_spell) == 0, 'non-zero spell USDC balance' assert lp.balanceOf(uniswap_spell) == 0, 'non-zero spell LP balance' # debt assert usdtDebt == borrow_usdt_amt assert usdcDebt == borrow_usdc_amt ##################################################################################### print( '=========================================================================' ) print('Case 2.') # remove liquidity from the same position prevABal = usdt.balanceOf(alice) prevBBal = usdc.balanceOf(alice) prevLPBal = lp.balanceOf(alice) prevLPBal_bank = lp.balanceOf(homora) prevLPBal_werc20 = lp.balanceOf(werc20) _, _, _, collSize = homora.getPositionInfo(1) lp_take_amt = 2**256 - 1 # max lp_want = 1 * 10**5 usdt_repay = 2**256 - 1 # max usdc_repay = 2**256 - 1 # max tx = homora.execute( 1, uniswap_spell, uniswap_spell.removeLiquidityWERC20.encode_input( usdt, # token 0 usdc, # token 1 [ lp_take_amt, # take out LP tokens lp_want, # withdraw LP tokens to wallet usdt_repay, # repay USDT usdc_repay, # repay USDC 0, # repay LP 0, # min USDT 0 ], # min USDC ), {'from': alice}) curABal = usdt.balanceOf(alice) curBBal = usdc.balanceOf(alice) curLPBal = lp.balanceOf(alice) curLPBal_bank = lp.balanceOf(homora) curLPBal_werc20 = lp.balanceOf(werc20) print('spell lp balance', lp.balanceOf(uniswap_spell)) print('spell usdt balance', usdt.balanceOf(uniswap_spell)) print('spell usdc balance', usdc.balanceOf(uniswap_spell)) print('Alice delta A balance', curABal - prevABal) print('Alice delta B balance', curBBal - prevBBal) print('Alice delta LP balance', curLPBal - prevLPBal) print('remove liquidity gas', tx.gas_used) print('bank delta lp balance', curLPBal_bank - prevLPBal_bank) print('bank total lp balance', curLPBal_bank) _, _, _, usdtDebt, usdtDebtShare = homora.getBankInfo(usdt) _, _, _, usdcDebt, usdcDebtShare = homora.getBankInfo(usdc) print('bank usdt totalDebt', usdtDebt) print('bank usdt totalShare', usdtDebtShare) print('bank usdc totalDebt', usdcDebt) print('bank usdc totalShare', usdcDebtShare) print('LP want', lp_want) print('bank delta LP amount', curLPBal_bank - prevLPBal_bank) print('LP take amount', lp_take_amt) print('prev werc20 LP balance', prevLPBal_werc20) print('cur werc20 LP balance', curLPBal_werc20) print('coll size', collSize) # alice assert almostEqual(curLPBal - prevLPBal, lp_want), 'incorrect LP amt' # werc20 assert almostEqual(curLPBal_werc20 - prevLPBal_werc20, -collSize), 'incorrect werc20 LP amt' # spell assert usdt.balanceOf(uniswap_spell) == 0, 'non-zero spell USDT balance' assert usdc.balanceOf(uniswap_spell) == 0, 'non-zero spell USDC balance' assert lp.balanceOf(uniswap_spell) == 0, 'non-zero spell LP balance' # debt assert usdtDebt == 0, 'usdtDebt should be 0' assert usdcDebt == 0, 'usdcDebt should be 0' return tx
def main(): admin = accounts[0] alice = accounts[1] usdt = interface.IERC20Ex('0xdAC17F958D2ee523a2206206994597C13D831ec7') lpusdt = interface.IERC20Ex('0x0d4a11d5EEaaC28EC3F61d100daF4d40471f1852') crusdt = interface.ICErc20('0x797AAB1ce7c01eB727ab980762bA88e7133d2157') router = interface.IUniswapV2Router02( '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D') erc20_oracle = ERC20KP3ROracle.deploy(KP3R_ADDRESS, {'from': admin}) lp_oracle = UniswapV2LPKP3ROracle.deploy(KP3R_ADDRESS, {'from': admin}) core_oracle = CoreOracle.deploy({'from': admin}) oracle = ProxyOracle.deploy(core_oracle, {'from': admin}) core_oracle.setRoute( [ '0xdAC17F958D2ee523a2206206994597C13D831ec7', # USDT '0x0d4a11d5EEaaC28EC3F61d100daF4d40471f1852', # USDT-ETH ], [erc20_oracle, lp_oracle], {'from': admin}, ) oracle.setOracles( [ '0xdAC17F958D2ee523a2206206994597C13D831ec7', # USDT '0x0d4a11d5EEaaC28EC3F61d100daF4d40471f1852', # USDT-ETH ], [ [10000, 10000, 10000], [10000, 10000, 10000], ], {'from': admin}, ) homora = HomoraBank.deploy({'from': admin}) homora.initialize(oracle, 1000, {'from': admin}) # 10% fee setup_bank_hack(homora) homora.addBank(usdt, crusdt, {'from': admin}) # lpusdt.approve(homora, 2**256-1, {'from': alice}) # Steal some LP from the staking pool lpusdt.transfer( alice, 1 * 10**17, { 'from': accounts.at('0x6C3e4cb2E96B01F4b866965A91ed4437839A121a', force=True) }) household_spell = HouseHoldSpell.deploy(homora, WETH_ADDRESS, {'from': admin}) tx = homora.execute( 0, # position id household_spell, household_spell.putCollateral.encode_input( '0x0d4a11d5EEaaC28EC3F61d100daF4d40471f1852', # USDT '0.00001 ether', # valued at approximately $600 ), {'from': alice}, ) print('put collateral gas', tx.gas_used) position_id = tx.return_value print(homora.getCollateralETHValue(position_id), homora.getBorrowETHValue(position_id)) tx = homora.execute( position_id, # position id household_spell, household_spell.borrow.encode_input( '0xdAC17F958D2ee523a2206206994597C13D831ec7', # USDT '500000000', # $500 ), {'from': alice}, ) print('bal', usdt.balanceOf(alice)) print('put collateral gas', tx.gas_used) _, _, _, totalDebt, totalShare = homora.getBankInfo(usdt) print('bank usdt totalDebt', totalDebt) print('bank usdt totalShare', totalShare) usdt.approve(homora, 2**256 - 1, {'from': alice}) usdt.approve(crusdt, 2**256 - 1, {'from': accounts.at(homora, force=True)}) tx = homora.execute( position_id, # position id household_spell, household_spell.repay.encode_input( '0xdAC17F958D2ee523a2206206994597C13D831ec7', # USDT '300000000', # $300 ), {'from': alice}, ) print('bal', usdt.balanceOf(alice)) print('repay gas', tx.gas_used)
def main(): admin = accounts[0] alice = accounts[1] bob = accounts[2] dpi = interface.IERC20Ex('0x1494ca1f11d487c2bbe4543e90080aeba4ba3c2b') weth = interface.IERC20Ex('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2') usdt = interface.IERC20Ex('0xdac17f958d2ee523a2206206994597c13d831ec7') lp = interface.IERC20Ex('0x4d5ef58aac27d99935e5b6b4a6778ff292059991') lp_usdt = interface.IERC20Ex('0x0d4a11d5eeaac28ec3f61d100daf4d40471f1852') crdpi = MockCErc20.deploy(dpi, {'from': admin}) crusdt = interface.ICErc20('0x797AAB1ce7c01eB727ab980762bA88e7133d2157') router = interface.IUniswapV2Router02( '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D') staking = accounts.at('0xB93b505Ed567982E2b6756177ddD23ab5745f309', force=True) index = interface.IERC20Ex( interface.IStakingRewardsEx(staking).rewardsToken()) wstaking = WStakingRewards.deploy(staking, lp, index, {'from': admin}) werc20 = WERC20.deploy({'from': admin}) simple_oracle = SimpleOracle.deploy({'from': admin}) simple_oracle.setETHPx([dpi, weth, usdt], [2**112 * 100 // 700, 2**112, 2**112 // 700]) uniswap_oracle = UniswapV2Oracle.deploy(simple_oracle, {'from': admin}) core_oracle = CoreOracle.deploy({'from': admin}) oracle = ProxyOracle.deploy(core_oracle, {'from': admin}) oracle.setWhitelistERC1155([werc20, wstaking], True, {'from': admin}) core_oracle.setRoute( [dpi, weth, lp, usdt, lp_usdt], [ simple_oracle, simple_oracle, uniswap_oracle, simple_oracle, uniswap_oracle ], {'from': admin}, ) oracle.setOracles( [dpi, weth, lp, usdt, lp_usdt], [ [10000, 10000, 10000], [10000, 10000, 10000], [10000, 10000, 10000], [10000, 10000, 10000], [10000, 10000, 10000], ], {'from': admin}, ) homora = HomoraBank.deploy({'from': admin}) homora.initialize(oracle, 1000, {'from': admin}) # 10% fee setup_bank_hack(homora) homora.addBank(dpi, crdpi, {'from': admin}) homora.addBank(usdt, crusdt, {'from': admin}) # setup initial funds to alice mint_tokens(dpi, alice) mint_tokens(weth, alice) mint_tokens(usdt, alice) mint_tokens(dpi, crdpi) # check alice's funds print(f'Alice dpi balance {dpi.balanceOf(alice)}') print(f'Alice weth balance {weth.balanceOf(alice)}') # Steal some LP from the staking pool mint_tokens(lp, alice) mint_tokens(lp, bob) mint_tokens(lp_usdt, alice) mint_tokens(lp_usdt, bob) # set approval dpi.approve(homora, 2**256 - 1, {'from': alice}) dpi.approve(crdpi, 2**256 - 1, {'from': alice}) weth.approve(homora, 2**256 - 1, {'from': alice}) usdt.approve(homora, 2**256 - 1, {'from': alice}) usdt.approve(crusdt, 2**256 - 1, {'from': alice}) lp.approve(homora, 2**256 - 1, {'from': alice}) lp.approve(staking, 2**256 - 1, {'from': bob}) uniswap_spell = UniswapV2SpellV1.deploy(homora, werc20, router, {'from': admin}) # first time call to reduce gas uniswap_spell.getPair(weth, dpi, {'from': admin}) ##################################################################################### print( '=========================================================================' ) print('Case 1. add liquidity first time') prevABal = dpi.balanceOf(alice) prevBBal = weth.balanceOf(alice) prevLPBal = lp.balanceOf(alice) prevLPBal_bank = lp.balanceOf(homora) prevLPBal_staking = lp.balanceOf(staking) if interface.IUniswapV2Pair(lp).token0() == dpi: prevARes, prevBRes, _ = interface.IUniswapV2Pair(lp).getReserves() else: prevBRes, prevARes, _ = interface.IUniswapV2Pair(lp).getReserves() dpi_amt = 10 * 10**18 weth_amt = 10**18 lp_amt = 0 borrow_dpi_amt = 10**18 borrow_weth_amt = 0 real_dpi_borrow_amt = borrow_dpi_amt tx = homora.execute( 0, uniswap_spell, uniswap_spell.addLiquidityWStakingRewards.encode_input( dpi, # token 0 weth, # token 1 [ dpi_amt, # supply DPI weth_amt, # supply WETH lp_amt, # supply LP borrow_dpi_amt, # borrow DPI borrow_weth_amt, # borrow WETH 0, # borrow LP tokens 0, # min DPI 0 ], # min WETH wstaking, ), {'from': alice}) curABal = dpi.balanceOf(alice) curBBal = weth.balanceOf(alice) curLPBal = lp.balanceOf(alice) curLPBal_bank = lp.balanceOf(homora) curLPBal_staking = lp.balanceOf(staking) if interface.IUniswapV2Pair(lp).token0() == dpi: curARes, curBRes, _ = interface.IUniswapV2Pair(lp).getReserves() else: curBRes, curARes, _ = interface.IUniswapV2Pair(lp).getReserves() print('spell lp balance', lp.balanceOf(uniswap_spell)) print('Alice delta A balance', curABal - prevABal) print('Alice delta B balance', curBBal - prevBBal) print('add liquidity gas', tx.gas_used) print('bank lp balance', curLPBal_bank) _, _, _, totalDebt, totalShare = homora.getBankInfo(dpi) print('bank dpi totalDebt', totalDebt) print('bank dpi totalShare', totalShare) print('bank prev LP balance', prevLPBal_bank) print('bank cur LP balance', curLPBal_bank) print('staking prev LP balance', prevLPBal_staking) print('staking cur LP balance', curLPBal_staking) print('prev dpi res', prevARes) print('cur dpi res', curARes) print('prev weth res', prevBRes) print('cur weth res', curBRes) # alice assert almostEqual(curABal - prevABal, -dpi_amt), 'incorrect DPI amt' assert almostEqual(curBBal - prevBBal, -weth_amt), 'incorrect WETH amt' assert curLPBal - prevLPBal == -lp_amt, 'incorrect LP amt' # spell assert dpi.balanceOf(uniswap_spell) == 0, 'non-zero spell DPI balance' assert weth.balanceOf(uniswap_spell) == 0, 'non-zero spell WETH balance' assert lp.balanceOf(uniswap_spell) == 0, 'non-zero spell LP balance' assert totalDebt == borrow_dpi_amt # check balance and pool reserves assert curABal - prevABal - borrow_dpi_amt == - \ (curARes - prevARes), 'not all DPI tokens go to LP pool' assert curBBal - prevBBal - borrow_weth_amt == - \ (curBRes - prevBRes), 'not all WETH tokens go to LP pool' _, _, collId, collSize = homora.getPositionInfo(1) print('collSize', collSize) # staking directly prevIndex = index.balanceOf(bob) print('bob lp balance', interface.IERC20Ex(lp).balanceOf(bob)) tx = interface.IStakingRewards(staking).stake(collSize, {'from': bob}) chain.sleep(20000) prevAliceIndexBalance = index.balanceOf(alice) print('Alice index balance', prevAliceIndexBalance) ##################################################################################### print( '=========================================================================' ) print('Case 2. add liquidity (failed tx desired)') usdt_amt = 10 * 10**6 weth_amt = 10**18 lp_amt = 0 borrow_usdt_amt = 0 borrow_weth_amt = 0 try: tx = homora.execute( 1, uniswap_spell, uniswap_spell.addLiquidityWStakingRewards.encode_input( usdt, # token 0 weth, # token 1 [ usdt_amt, # supply USDT weth_amt, # supply WETH lp_amt, # supply LP borrow_usdt_amt, # borrow USDT borrow_weth_amt, # borrow WETH 0, # borrow LP tokens 0, # min USDT 0 ], # min WETH wstaking, ), {'from': alice}) except VirtualMachineError: pass ##################################################################################### print( '=========================================================================' ) print('Case 3. remove liquidity (failed tx desired)') lp_take_amt = collSize lp_want = 0 usdt_repay = 0 weth_repay = 0 try: tx = homora.execute( 1, uniswap_spell, uniswap_spell.removeLiquidityWStakingRewards.encode_input( usdt, # token 0 weth, # token 1 [ lp_take_amt, # take out LP tokens lp_want, # withdraw LP tokens to wallet usdt_repay, # repay USDT weth_repay, # repay WETH 0, # repay LP tokens 0, # min USDT 0 ], # min WETH wstaking, ), {'from': alice}) except VirtualMachineError: pass ##################################################################################### print( '=========================================================================' ) print('Case 4. remove liquidity') prevABal = dpi.balanceOf(alice) prevBBal = weth.balanceOf(alice) prevLPBal = lp.balanceOf(alice) prevLPBal_bank = lp.balanceOf(homora) prevLPBal_staking = lp.balanceOf(staking) prevETHBal = alice.balance() if interface.IUniswapV2Pair(lp).token0() == dpi: prevARes, prevBRes, _ = interface.IUniswapV2Pair(lp).getReserves() else: prevBRes, prevARes, _ = interface.IUniswapV2Pair(lp).getReserves() lp_take_amt = collSize lp_want = 0 dpi_repay = 2**256 - 1 weth_repay = 0 tx = homora.execute( 1, uniswap_spell, uniswap_spell.removeLiquidityWStakingRewards.encode_input( dpi, # token 0 weth, # token 1 [ lp_take_amt, # take out LP tokens lp_want, # withdraw LP tokens to wallet dpi_repay, # repay DPI weth_repay, # repay WETH 0, # repay LP tokens 0, # min DPI 0 ], # min WETH wstaking, ), {'from': alice}) curABal = dpi.balanceOf(alice) curBBal = weth.balanceOf(alice) curLPBal = lp.balanceOf(alice) curLPBal_bank = lp.balanceOf(homora) curLPBal_staking = lp.balanceOf(staking) curETHBal = alice.balance() if interface.IUniswapV2Pair(lp).token0() == dpi: curARes, curBRes, _ = interface.IUniswapV2Pair(lp).getReserves() else: curBRes, curARes, _ = interface.IUniswapV2Pair(lp).getReserves() print('spell lp balance', lp.balanceOf(uniswap_spell)) print('Alice delta A balance', curABal - prevABal) print('Alice delta B balance', curBBal - prevBBal) print('add liquidity gas', tx.gas_used) print('bank lp balance', curLPBal_bank) _, _, _, totalDebt, totalShare = homora.getBankInfo(dpi) print('bank dpi totalDebt', totalDebt) print('bank dpi totalShare', totalShare) print('bank prev LP balance', prevLPBal_bank) print('bank cur LP balance', curLPBal_bank) print('wstaking prev LP balance', prevLPBal_staking) print('wstaking cur LP balance', curLPBal_staking) print('prev dpi res', prevARes) print('cur dpi res', curARes) print('prev weth res', prevBRes) print('cur weth res', curBRes) # alice assert almostEqual(curBBal - prevBBal, 0), 'incorrect WETH amt' assert almostEqual(curLPBal - prevLPBal, lp_want), 'incorrect LP amt' # staking assert almostEqual(curLPBal_staking - prevLPBal_staking, -lp_take_amt), 'incorrect staking LP amt' # spell assert dpi.balanceOf(uniswap_spell) == 0, 'non-zero spell DPI balance' assert weth.balanceOf(uniswap_spell) == 0, 'non-zero spell WETH balance' assert lp.balanceOf(uniswap_spell) == 0, 'non-zero spell LP balance' # check balance and pool reserves assert almostEqual(curABal - prevABal + real_dpi_borrow_amt, -(curARes - prevARes)), 'inconsistent DPI from withdraw' assert almostEqual(curBBal - prevBBal, 0), 'inconsistent WETH from withdraw' assert almostEqual(curETHBal - prevETHBal + weth_repay, -(curBRes - prevBRes)), 'inconsistent ETH from withdraw' curAliceIndexBalance = index.balanceOf(alice) print('Alice index balance', curAliceIndexBalance) receivedIndex = curAliceIndexBalance - prevAliceIndexBalance print('received index', receivedIndex) # check with staking directly tx = interface.IStakingRewards(staking).getReward({'from': bob}) receivedIndexFromStaking = index.balanceOf(bob) - prevIndex print('receivedIndexFromStaking', receivedIndexFromStaking) assert almostEqual(receivedIndex, receivedIndexFromStaking)
def mint_tokens(token, to, amount=None): if amount is None: # default is 1M tokens amount = 10**12 * 10**token.decimals() if token == USDT: owner = token.owner() token.issue(amount, {'from': owner}) token.transfer(to, amount, {'from': owner}) elif token == USDC: master_minter = token.masterMinter() token.configureMinter(master_minter, 2**256 - 1, {'from': master_minter}) token.mint(to, amount, {'from': master_minter}) elif token == DAI: auth = '0x9759a6ac90977b93b58547b4a71c78317f391a28' token.mint(to, amount, {'from': auth}) elif token == AUSDT: pool = '0x7d2768de32b0b80b7a3454c06bdac94a69ddc7a9' token.mint(to, amount, 10**18, {'from': pool}) elif token == AUSDC: pool = '0x7d2768de32b0b80b7a3454c06bdac94a69ddc7a9' token.mint(to, amount, 10**18, {'from': pool}) elif token == ADAI: pool = '0x7d2768de32b0b80b7a3454c06bdac94a69ddc7a9' token.mint(to, amount, 10**18, {'from': pool}) elif token == WETH: token.deposit({'from': to, 'value': amount}) elif token == SUSD: target = interface.IERC20Ex(token.target()) contract_issuer = target.resolverAddressesRequired()[2] resolver = interface.IERC20Ex(target.resolver()) resolver_target = interface.IERC20Ex(resolver.target()) issuer = resolver_target.repository(contract_issuer) target.issue(to, amount, {'from': issuer}) elif token == HUSD: issuer = '0xc2fbf9b9084e92f9649ca4cec9043daac9092539' token.issue(to, amount, {'from': issuer}) elif token == BUSD: supply_controller = token.supplyController() token.increaseSupply(amount, {'from': supply_controller}) token.transfer(to, amount, {'from': supply_controller}) elif token == YDAI: mint_tokens(interface.IERC20Ex(DAI), to, amount) interface.IERC20Ex(DAI).approve(token, 0, {'from': to}) interface.IERC20Ex(DAI).approve(token, 2**256 - 1, {'from': to}) token.deposit(amount, {'from': to}) elif token == YUSDT: mint_tokens(interface.IERC20Ex(USDT), to, amount) interface.IERC20Ex(USDT).approve(token, 0, {'from': to}) interface.IERC20Ex(USDT).approve(token, 2**256 - 1, {'from': to}) token.deposit(amount, {'from': to}) elif token == YBUSD: mint_tokens(interface.IERC20Ex(BUSD), to, amount) interface.IERC20Ex(BUSD).approve(token, 0, {'from': to}) interface.IERC20Ex(BUSD).approve(token, 2**256 - 1, {'from': to}) token.deposit(amount, {'from': to}) elif token == YUSDC: mint_tokens(interface.IERC20Ex(USDC), to, amount) interface.IERC20Ex(USDC).approve(token, 0, {'from': to}) interface.IERC20Ex(USDC).approve(token, 2**256 - 1, {'from': to}) token.deposit(amount, {'from': to}) elif token == DPI: module = token.getModules()[0] token.mint(to, amount, {'from': module}) elif token == WBTC: owner = token.owner() token.mint(to, amount, {'from': owner}) elif token == RENBTC: owner = token.owner() token.mint(to, amount, {'from': owner}) elif token == PERP: owner = token.owner() token.addMinter(owner, {'from': owner}) token.mint(to, amount, {'from': owner}) elif token == DFD: gov = token.governance() token.mint(to, amount, {'from': gov}) elif token == DUSD: core = token.core() token.mint(to, amount, {'from': core}) elif token == EURS: owner = '0x2EbBbc541E8f8F24386FA319c79CedA0579f1Efb' token.createTokens(amount, {'from': owner}) token.transfer(to, amount, {'from': owner}) elif token == SEUR: target = interface.IERC20Ex(token.target()) contract_issuer = target.resolverAddressesRequired()[2] resolver = interface.IERC20Ex(target.resolver()) resolver_target = interface.IERC20Ex(resolver.target()) issuer = resolver_target.repository(contract_issuer) target.issue(to, amount, {'from': issuer}) elif token == YFI: governor = token.governance() token.addMinter(to, {'from': governor}) token.mint(to, amount, {'from': to}) elif is_uni_lp(token): router = interface.IUniswapV2Router02( '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D') # Uniswap LP token token0 = interface.IERC20Ex(token.token0()) token1 = interface.IERC20Ex(token.token1()) # mint underlying amount0 = 10**12 * 10**token0.decimals() amount1 = 10**12 * 10**token1.decimals() mint_tokens(token0, to, amount0) mint_tokens(token1, to, amount1) # approve router token0.approve(router, 0, {'from': to}) token0.approve(router, 2**256 - 1, {'from': to}) token1.approve(router, 0, {'from': to}) token1.approve(router, 2**256 - 1, {'from': to}) # add liquidity interface.IUniswapV2Router02(router).addLiquidity( token0, token1, amount0, amount1, 0, 0, to, chain.time() + 1200, {'from': to}) elif is_sushi_lp(token): router = interface.IUniswapV2Router02( '0xd9e1ce17f2641f24ae83637ab66a2cca9c378b9f') # Sushiswap LP token token0 = interface.IERC20Ex(token.token0()) token1 = interface.IERC20Ex(token.token1()) # mint underlying amount0 = 10**12 * 10**token0.decimals() amount1 = 10**12 * 10**token1.decimals() mint_tokens(token0, to, amount0) mint_tokens(token1, to, amount1) # approve router token0.approve(router, 0, {'from': to}) token0.approve(router, 2**256 - 1, {'from': to}) token1.approve(router, 0, {'from': to}) token1.approve(router, 2**256 - 1, {'from': to}) # add liquidity interface.IUniswapV2Router02(router).addLiquidity( token0, token1, amount0, amount1, 0, 0, to, chain.time() + 1200, {'from': to}) elif is_bal_lp(token): # Balancer LP token tokens = token.getFinalTokens() max_amts = [] amt_desired = 10**100 for _token in tokens: _token = interface.IERC20Ex(_token) amt = 10**12 * 10**_token.decimals() mint_tokens(_token, to, amt) _token.approve(token, 0, {'from': to}) _token.approve(token, 2**256 - 1, {'from': to}) max_amts.append(amt) amt_desired = min( amt_desired, amt * token.totalSupply() // token.getBalance(_token)) token.joinPool(amt_desired * 9 // 10, max_amts, {'from': to}) elif is_crv_lp(token): # Curve LP token registry = interface.ICurveRegistry( '0x7d86446ddb609ed0f5f8684acf30380a356b2b4c') pool = registry.get_pool_from_lp_token(token) tokens = registry.get_coins(pool) amts = [] for _token in tokens: if _token == '0x0000000000000000000000000000000000000000': continue _token = interface.IERC20Ex(_token) amt = 10**6 * 10**_token.decimals() prevBal = _token.balanceOf(to) mint_tokens(_token, to, amt) curBal = _token.balanceOf(to) amts.append(curBal - prevBal) interface.IERC20Ex(_token).approve(pool, 0, {'from': to}) interface.IERC20Ex(_token).approve(pool, 2**256 - 1, {'from': to}) desc = f'uint[{len(amts)}],uint' print('adding liquidity to curve') print(amts) interface.ICurvePool(pool).add_liquidity[desc](amts, 0, {'from': to}) else: raise Exception('unsupported token')
def main(): admin = accounts[0] alice = accounts[1] bob = accounts[2] dpi = interface.IERC20Ex('0x1494ca1f11d487c2bbe4543e90080aeba4ba3c2b') weth = interface.IERC20Ex('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2') lp = interface.IERC20Ex('0x4d5ef58aac27d99935e5b6b4a6778ff292059991') crdpi = MockCErc20.deploy(dpi, {'from': admin}) router = interface.IUniswapV2Router02( '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D') staking = accounts.at('0xB93b505Ed567982E2b6756177ddD23ab5745f309', force=True) index = interface.IERC20Ex(interface.IStakingRewardsEx(staking).rewardsToken()) wstaking = WStakingRewards.deploy(staking, lp, index, {'from': admin}) werc20 = WERC20.deploy({'from': admin}) simple_oracle = SimpleOracle.deploy({'from': admin}) simple_oracle.setETHPx([dpi, weth], [2**112 * 100 // 700, 2**112]) uniswap_oracle = UniswapV2Oracle.deploy(simple_oracle, {'from': admin}) core_oracle = CoreOracle.deploy({'from': admin}) oracle = ProxyOracle.deploy(core_oracle, {'from': admin}) oracle.setWhitelistERC1155([werc20, wstaking], True, {'from': admin}) core_oracle.setRoute( [dpi, weth, lp], [simple_oracle, simple_oracle, uniswap_oracle], {'from': admin}, ) oracle.setOracles( [dpi, weth, lp], [ [10000, 10000, 10000], [10000, 10000, 10000], [10000, 10000, 10000], ], {'from': admin}, ) homora = HomoraBank.deploy({'from': admin}) homora.initialize(oracle, 1000, {'from': admin}) # 10% fee setup_bank_hack(homora) homora.addBank(dpi, crdpi, {'from': admin}) # setup initial funds to alice mint_tokens(dpi, alice) mint_tokens(weth, alice) mint_tokens(dpi, crdpi) # check alice's funds print(f'Alice dpi balance {dpi.balanceOf(alice)}') print(f'Alice weth balance {weth.balanceOf(alice)}') # Steal some LP from the staking pool mint_tokens(lp, alice) mint_tokens(lp, bob) # set approval dpi.approve(homora, 2**256-1, {'from': alice}) dpi.approve(crdpi, 2**256-1, {'from': alice}) weth.approve(homora, 2**256-1, {'from': alice}) lp.approve(homora, 2**256-1, {'from': alice}) lp.approve(staking, 2**256-1, {'from': bob}) uniswap_spell = UniswapV2SpellV1.deploy( homora, werc20, router, {'from': admin}) # first time call to reduce gas uniswap_spell.getPair(weth, dpi, {'from': admin}) # whitelist spell in bank homora.setWhitelistSpells([uniswap_spell], [True], {'from': admin}) # whitelist token in bank homora.setWhitelistTokens([dpi], [True], {'from': admin}) # whitelist lp in spell uniswap_spell.setWhitelistLPTokens([lp], [True], {'from': admin}) ##################################################################################### print('=========================================================================') print('Case 1. add liquidity') prevABal = dpi.balanceOf(alice) prevBBal = weth.balanceOf(alice) prevLPBal = lp.balanceOf(alice) prevLPBal_bank = lp.balanceOf(homora) prevLPBal_staking = lp.balanceOf(staking) if interface.IUniswapV2Pair(lp).token0() == dpi: prevARes, prevBRes, _ = interface.IUniswapV2Pair(lp).getReserves() else: prevBRes, prevARes, _ = interface.IUniswapV2Pair(lp).getReserves() dpi_amt = 10 * 10**18 weth_amt = 10**18 lp_amt = 0 borrow_dpi_amt = 10**18 borrow_weth_amt = 0 tx = homora.execute( 0, uniswap_spell, uniswap_spell.addLiquidityWStakingRewards.encode_input( dpi, # token 0 weth, # token 1 [dpi_amt, # supply DPI weth_amt, # supply WETH lp_amt, # supply LP borrow_dpi_amt, # borrow DPI borrow_weth_amt, # borrow WETH 0, # borrow LP tokens 0, # min DPI 0], # min WETH wstaking, ), {'from': alice} ) curABal = dpi.balanceOf(alice) curBBal = weth.balanceOf(alice) curLPBal = lp.balanceOf(alice) curLPBal_bank = lp.balanceOf(homora) curLPBal_staking = lp.balanceOf(staking) if interface.IUniswapV2Pair(lp).token0() == dpi: curARes, curBRes, _ = interface.IUniswapV2Pair(lp).getReserves() else: curBRes, curARes, _ = interface.IUniswapV2Pair(lp).getReserves() print('spell lp balance', lp.balanceOf(uniswap_spell)) print('Alice delta A balance', curABal - prevABal) print('Alice delta B balance', curBBal - prevBBal) print('add liquidity gas', tx.gas_used) print('bank lp balance', curLPBal_bank) _, _, _, totalDebt, totalShare = homora.getBankInfo(dpi) print('bank dpi totalDebt', totalDebt) print('bank dpi totalShare', totalShare) print('bank prev LP balance', prevLPBal_bank) print('bank cur LP balance', curLPBal_bank) print('staking prev LP balance', prevLPBal_staking) print('staking cur LP balance', curLPBal_staking) print('prev dpi res', prevARes) print('cur dpi res', curARes) print('prev weth res', prevBRes) print('cur weth res', curBRes) # alice assert almostEqual(curABal - prevABal, -dpi_amt), 'incorrect DPI amt' assert almostEqual(curBBal - prevBBal, -weth_amt), 'incorrect WETH amt' assert curLPBal - prevLPBal == -lp_amt, 'incorrect LP amt' # spell assert dpi.balanceOf(uniswap_spell) == 0, 'non-zero spell DPI balance' assert weth.balanceOf(uniswap_spell) == 0, 'non-zero spell WETH balance' assert lp.balanceOf(uniswap_spell) == 0, 'non-zero spell LP balance' assert totalDebt == borrow_dpi_amt # check balance and pool reserves assert curABal - prevABal - borrow_dpi_amt == - \ (curARes - prevARes), 'not all DPI tokens go to LP pool' assert curBBal - prevBBal - borrow_weth_amt == - \ (curBRes - prevBRes), 'not all WETH tokens go to LP pool' # ##################################################################################### print('=========================================================================') print('Case 2. harvest first time') prevIndexBalance = index.balanceOf(alice) print('Alice INDEX balance before harvest', prevIndexBalance) _, _, collId, collSize = homora.getPositionInfo(1) print('collSize', collSize) # staking directly prevIndex = index.balanceOf(bob) print('bob lp balance', interface.IERC20Ex(lp).balanceOf(bob)) tx = interface.IStakingRewards(staking).stake(collSize, {'from': bob}) chain.sleep(20000) tx = homora.execute( 1, uniswap_spell, uniswap_spell.harvestWStakingRewards.encode_input(wstaking), {'from': alice} ) print('tx gas used', tx.gas_used) curIndexBalance = index.balanceOf(alice) print('Alice INDEX balance after harvest', curIndexBalance) receivedIndex = curIndexBalance - prevIndexBalance # check with staking directly tx = interface.IStakingRewards(staking).getReward({'from': bob}) receivedIndexFromStaking = index.balanceOf(bob) - prevIndex print('receivedIndexFromStaking', receivedIndexFromStaking) assert almostEqual(receivedIndex, receivedIndexFromStaking) # ##################################################################################### print('=========================================================================') print('Case 3. harvest second time') prevIndexBalance = index.balanceOf(alice) print('Alice INDEX balance before harvest', prevIndexBalance) prevIndex = index.balanceOf(bob) print('bob lp balance', interface.IERC20Ex(lp).balanceOf(bob)) chain.sleep(20000) tx = homora.execute( 1, uniswap_spell, uniswap_spell.harvestWStakingRewards.encode_input(wstaking), {'from': alice} ) print('tx gas used', tx.gas_used) curIndexBalance = index.balanceOf(alice) print('Alice INDEX balance after harvest', curIndexBalance) receivedIndex = curIndexBalance - prevIndexBalance # check with staking directly tx = interface.IStakingRewards(staking).getReward({'from': bob}) receivedIndexFromStaking = index.balanceOf(bob) - prevIndex print('receivedIndexFromStaking', receivedIndexFromStaking) assert almostEqual(receivedIndex, receivedIndexFromStaking)
def main(): admin = accounts[0] alice = accounts[1] usdt = interface.IERC20Ex('0xdAC17F958D2ee523a2206206994597C13D831ec7') usdc = interface.IERC20Ex('0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48') lp = interface.IERC20Ex('0x3041cbd36888becc7bbcbc0045e3b1f144466f5f') crusdt = interface.ICErc20('0x797AAB1ce7c01eB727ab980762bA88e7133d2157') crusdc = interface.ICErc20('0x44fbebd2f576670a6c33f6fc0b00aa8c5753b322') router = interface.IUniswapV2Router02( '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D') werc20 = WERC20.deploy({'from': admin}) simple_oracle = SimpleOracle.deploy({'from': admin}) simple_oracle.setETHPx([usdt, usdc], [ 8343331721347310729683379470025550036595362, 8344470555541464992529317899641128796042472 ]) uniswap_oracle = UniswapV2Oracle.deploy(simple_oracle, {'from': admin}) oracle = ProxyOracle.deploy({'from': admin}) oracle.setWhitelistERC1155([werc20], True, {'from': admin}) oracle.setOracles( [ '0xdAC17F958D2ee523a2206206994597C13D831ec7', # USDT '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', # USDC '0x3041cbd36888becc7bbcbc0045e3b1f144466f5f', # USDT-USDC ], [ [simple_oracle, 10000, 10000, 10000], [simple_oracle, 10000, 10000, 10000], [uniswap_oracle, 10000, 10000, 10000], ], {'from': admin}, ) # initialize homora = HomoraBank.deploy({'from': admin}) homora.initialize(oracle, 1000, {'from': admin}) # 10% fee setup_bank_hack(homora) # add bank homora.addBank(usdt, crusdt, {'from': admin}) homora.addBank(usdc, crusdc, {'from': admin}) # setup initial funds 10^6 USDT + 10^6 USDC to alice setup_transfer( usdt, accounts.at('0xbe0eb53f46cd790cd13851d5eff43d12404d33e8', force=True), alice, 10**6 * 10**6) setup_transfer( usdc, accounts.at('0xa191e578a6736167326d05c119ce0c90849e84b7', force=True), alice, 10**6 * 10**6) # setup initial funds 10^6 USDT + 10^6 USDC to homora bank setup_transfer( usdt, accounts.at('0xbe0eb53f46cd790cd13851d5eff43d12404d33e8', force=True), homora, 10**6 * 10**6) setup_transfer( usdc, accounts.at('0x397ff1542f962076d0bfe58ea045ffa2d347aca0', force=True), homora, 10**6 * 10**6) # check alice's funds print(f'Alice usdt balance {usdt.balanceOf(alice)}') print(f'Alice usdc balance {usdc.balanceOf(alice)}') # steal some LP from the staking pool lp.transfer( alice, 1 * 10**8, { 'from': accounts.at('0x85af1678527f63eb6492ab158ed5d2a94b8732c0', force=True) }) # set approval usdt.approve(homora, 2**256 - 1, {'from': alice}) usdt.approve(crusdt, 2**256 - 1, {'from': alice}) usdc.approve(homora, 2**256 - 1, {'from': alice}) usdc.approve(crusdc, 2**256 - 1, {'from': alice}) lp.approve(homora, 2**256 - 1, {'from': alice}) uniswap_spell = UniswapV2SpellV1.deploy(homora, werc20, router, {'from': admin}) # first time call to reduce gas uniswap_spell.getPair(usdt, usdc, {'from': admin}) ##################################################################################### # add liquidity print( '=========================================================================' ) print('Case 1.') prevABal = usdt.balanceOf(alice) prevBBal = usdc.balanceOf(alice) prevLPBal = lp.balanceOf(alice) prevLPBal_bank = lp.balanceOf(homora) prevLPBal_werc20 = lp.balanceOf(werc20) if interface.IUniswapV2Pair(lp).token0() == usdt: prevARes, prevBRes, _ = interface.IUniswapV2Pair(lp).getReserves() else: prevBRes, prevARes, _ = interface.IUniswapV2Pair(lp).getReserves() usdt_amt = 40000 * 10**6 usdc_amt = 50000 * 10**6 lp_amt = 1 * 10**7 borrow_usdt_amt = 1000 * 10**6 borrow_usdc_amt = 200 * 10**6 tx = homora.execute( 0, uniswap_spell, uniswap_spell.addLiquidity.encode_input( usdt, # token 0 usdc, # token 1 [ usdt_amt, # supply USDT usdc_amt, # supply USDC lp_amt, # supply LP borrow_usdt_amt, # borrow USDT borrow_usdc_amt, # borrow USDC 0, # borrow 0 LP tokens 0, # min USDT 0 ], # min USDC ), {'from': alice}) position_id = tx.return_value print('position_id', position_id) curABal = usdt.balanceOf(alice) curBBal = usdc.balanceOf(alice) curLPBal = lp.balanceOf(alice) curLPBal_bank = lp.balanceOf(homora) curLPBal_werc20 = lp.balanceOf(werc20) if interface.IUniswapV2Pair(lp).token0() == usdt: curARes, curBRes, _ = interface.IUniswapV2Pair(lp).getReserves() else: curBRes, curARes, _ = interface.IUniswapV2Pair(lp).getReserves() print('spell lp balance', lp.balanceOf(uniswap_spell)) print('Alice delta A balance', curABal - prevABal) print('Alice delta B balance', curBBal - prevBBal) print('add liquidity gas', tx.gas_used) print('bank lp balance', curLPBal_bank) _, _, _, usdtDebt, usdtDebtShare = homora.getBankInfo(usdt) _, _, _, usdcDebt, usdcDebtShare = homora.getBankInfo(usdc) print('bank usdt debt', usdtDebt) print('bank usdt debt share', usdtDebtShare) print('bank usdc debt', usdcDebt) print('bank usdc debt share', usdcDebtShare) print('bank prev LP balance', prevLPBal_bank) print('bank cur LP balance', curLPBal_bank) print('werc20 prev LP balance', prevLPBal_werc20) print('werc20 cur LP balance', curLPBal_werc20) print('prev usdt res', prevARes) print('cur usdt res', curARes) print('prev usdc res', prevBRes) print('cur usdc res', curBRes) # alice assert almostEqual(curABal - prevABal, -usdt_amt), 'incorrect USDT amt' assert almostEqual(curBBal - prevBBal, -usdc_amt), 'incorrect USDC amt' assert curLPBal - prevLPBal == -lp_amt, 'incorrect LP amt' # spell assert usdt.balanceOf(uniswap_spell) == 0, 'non-zero spell USDT balance' assert usdc.balanceOf(uniswap_spell) == 0, 'non-zero spell USDC balance' assert lp.balanceOf(uniswap_spell) == 0, 'non-zero spell LP balance' assert usdtDebt == borrow_usdt_amt assert usdcDebt == borrow_usdc_amt # check balance and pool reserves assert curABal - prevABal - borrow_usdt_amt == - \ (curARes - prevARes), 'not all USDT tokens go to LP pool' assert curBBal - prevBBal - borrow_usdc_amt == - \ (curBRes - prevBRes), 'not all USDC tokens go to LP pool' ##################################################################################### # add liquidity to the same position print( '=========================================================================' ) print('Case 2.') prevABal = usdt.balanceOf(alice) prevBBal = usdc.balanceOf(alice) prevLPBal = lp.balanceOf(alice) prevLPBal_bank = lp.balanceOf(homora) prevLPBal_werc20 = lp.balanceOf(werc20) if interface.IUniswapV2Pair(lp).token0() == usdt: prevARes, prevBRes, _ = interface.IUniswapV2Pair(lp).getReserves() else: prevBRes, prevARes, _ = interface.IUniswapV2Pair(lp).getReserves() usdt_amt = 20000 * 10**6 usdc_amt = 30000 * 10**6 lp_amt = 1 * 10**7 borrow_usdt_amt = 1000 * 10**6 borrow_usdc_amt = 200 * 10**6 tx = homora.execute( 1, uniswap_spell, uniswap_spell.addLiquidity.encode_input( usdt, # token 0 usdc, # token 1 [ usdt_amt, # supply USDT usdc_amt, # supply USDC lp_amt, # supply LP borrow_usdt_amt, # borrow USDT borrow_usdc_amt, # borrow USDC 0, # borrow LP 0, # min USDT 0 ], # min USDC ), {'from': alice}) position_id = tx.return_value print('position_id', position_id) curABal = usdt.balanceOf(alice) curBBal = usdc.balanceOf(alice) curLPBal = lp.balanceOf(alice) curLPBal_bank = lp.balanceOf(homora) curLPBal_werc20 = lp.balanceOf(werc20) if interface.IUniswapV2Pair(lp).token0() == usdt: curARes, curBRes, _ = interface.IUniswapV2Pair(lp).getReserves() else: curBRes, curARes, _ = interface.IUniswapV2Pair(lp).getReserves() print('spell lp balance', lp.balanceOf(uniswap_spell)) print('Alice delta A balance', curABal - prevABal) print('Alice delta B balance', curBBal - prevBBal) print('add liquidity gas', tx.gas_used) print('bank lp balance', curLPBal_bank) _, _, _, usdtDebt, usdtDebtShare = homora.getBankInfo(usdt) _, _, _, usdcDebt, usdcDebtShare = homora.getBankInfo(usdc) print('bank usdt debt', usdtDebt) print('bank usdt debt share', usdtDebtShare) print('bank usdc debt', usdcDebt) print('bank usdc debt share', usdcDebtShare) print('bank prev LP balance', prevLPBal_bank) print('bank cur LP balance', curLPBal_bank) print('werc20 prev LP balance', prevLPBal_werc20) print('werc20 cur LP balance', curLPBal_werc20) print('prev usdt res', prevARes) print('cur usdt res', curARes) print('prev usdc res', prevBRes) print('cur usdc res', curBRes) # assert position_id assert position_id == 1 # position doesn't increase # alice assert almostEqual(curABal - prevABal, -usdt_amt), 'incorrect USDT amt' assert almostEqual(curBBal - prevBBal, -usdc_amt), 'incorrect USDC amt' assert curLPBal - prevLPBal == -lp_amt, 'incorrect LP amt' # spell assert usdt.balanceOf(uniswap_spell) == 0, 'non-zero spell USDT balance' assert usdc.balanceOf(uniswap_spell) == 0, 'non-zero spell USDC balance' assert lp.balanceOf(uniswap_spell) == 0, 'non-zero spell LP balance' # borrow same amount twice (with small interest accrued) assert usdtDebt >= borrow_usdt_amt * 2 # borrow same amount twice (with small interest accrued) assert usdcDebt >= borrow_usdc_amt * 2 # check balance and pool reserves assert curABal - prevABal - borrow_usdt_amt == - \ (curARes - prevARes), 'not all USDT tokens go to LP pool' assert curBBal - prevBBal - borrow_usdc_amt == - \ (curBRes - prevBRes), 'not all USDC tokens go to LP pool' ##################################################################################### # remove half liquidity from the same position print( '=========================================================================' ) print('Case 3.') prevABal = usdt.balanceOf(alice) prevBBal = usdc.balanceOf(alice) prevLPBal = lp.balanceOf(alice) prevLPBal_bank = lp.balanceOf(homora) prevLPBal_werc20 = lp.balanceOf(werc20) _, _, _, collSize = homora.getPositionInfo(position_id) lp_take_amt = collSize // 2 lp_want = 1 * 10**5 usdt_repay = MAX_INT usdc_repay = MAX_INT tx = homora.execute( position_id, uniswap_spell, uniswap_spell.removeLiquidity.encode_input( usdt, # token 0 usdc, # token 1 [ lp_take_amt, # take out LP lp_want, # withdraw LP to wallet usdt_repay, # repay USDT usdc_repay, # repay USDC 0, # repay LP 0, # min USDT 0 ], # min USDC ), {'from': alice}) curABal = usdt.balanceOf(alice) curBBal = usdc.balanceOf(alice) curLPBal = lp.balanceOf(alice) curLPBal_bank = lp.balanceOf(homora) curLPBal_werc20 = lp.balanceOf(werc20) print('spell lp balance', lp.balanceOf(uniswap_spell)) print('spell usdt balance', usdt.balanceOf(uniswap_spell)) print('spell usdc balance', usdc.balanceOf(uniswap_spell)) print('Alice delta A balance', curABal - prevABal) print('Alice delta B balance', curBBal - prevBBal) print('Alice delta LP balance', curLPBal - prevLPBal) print('remove liquidity gas', tx.gas_used) print('bank delta lp balance', curLPBal_bank - prevLPBal_bank) print('bank total lp balance', curLPBal_bank) _, _, _, usdtDebt, usdtDebtShare = homora.getBankInfo(usdt) _, _, _, usdcDebt, usdcDebtShare = homora.getBankInfo(usdc) print('bank usdt totalDebt', usdtDebt) print('bank usdt totalShare', usdtDebtShare) print('bank usdc totalDebt', usdcDebt) print('bank usdc totalShare', usdcDebtShare) print('LP want', lp_want) print('bank delta LP amount', curLPBal_bank - prevLPBal_bank) print('LP take amount', lp_take_amt) print('prev werc20 LP balance', prevLPBal_werc20) print('cur werc20 LP balance', curLPBal_werc20) print('coll size', collSize) # alice assert almostEqual(curLPBal - prevLPBal, lp_want), 'incorrect LP amt' # werc20 assert almostEqual(curLPBal_werc20 - prevLPBal_werc20, -lp_take_amt), 'incorrect werc20 LP amt' # spell assert usdt.balanceOf(uniswap_spell) == 0, 'non-zero spell USDT balance' assert usdc.balanceOf(uniswap_spell) == 0, 'non-zero spell USDC balance' assert lp.balanceOf(uniswap_spell) == 0, 'non-zero spell LP balance' # debt assert usdtDebt == 0, 'usdtDebt should be 0' assert usdcDebt == 0, 'usdcDebt should be 0' ##################################################################################### # remove remaining liquidity from the same position print( '=========================================================================' ) print('Case 4.') prevABal = usdt.balanceOf(alice) prevBBal = usdc.balanceOf(alice) prevLPBal = lp.balanceOf(alice) prevLPBal_bank = lp.balanceOf(homora) prevLPBal_werc20 = lp.balanceOf(werc20) _, _, _, collSize = homora.getPositionInfo(position_id) lp_take_amt = MAX_INT lp_want = 1 * 10**5 usdt_repay = MAX_INT usdc_repay = MAX_INT tx = homora.execute( position_id, uniswap_spell, uniswap_spell.removeLiquidity.encode_input( usdt, # token 0 usdc, # token 1 [ lp_take_amt, # take out LP lp_want, # withdraw LP to wallet usdt_repay, # repay USDT usdc_repay, # repay USDC 0, # repay LP 0, # min USDT 0 ], # min USDC ), {'from': alice}) curABal = usdt.balanceOf(alice) curBBal = usdc.balanceOf(alice) curLPBal = lp.balanceOf(alice) curLPBal_bank = lp.balanceOf(homora) curLPBal_werc20 = lp.balanceOf(werc20) print('spell lp balance', lp.balanceOf(uniswap_spell)) print('spell usdt balance', usdt.balanceOf(uniswap_spell)) print('spell usdc balance', usdc.balanceOf(uniswap_spell)) print('Alice delta A balance', curABal - prevABal) print('Alice delta B balance', curBBal - prevBBal) print('Alice delta LP balance', curLPBal - prevLPBal) print('remove liquidity gas', tx.gas_used) print('bank delta lp balance', curLPBal_bank - prevLPBal_bank) print('bank total lp balance', curLPBal_bank) _, _, _, usdtDebt, usdtDebtShare = homora.getBankInfo(usdt) _, _, _, usdcDebt, usdcDebtShare = homora.getBankInfo(usdc) print('bank usdt totalDebt', usdtDebt) print('bank usdt totalShare', usdtDebtShare) print('bank usdc totalDebt', usdcDebt) print('bank usdc totalShare', usdcDebtShare) print('LP want', lp_want) print('bank delta LP amount', curLPBal_bank - prevLPBal_bank) print('LP take amount', lp_take_amt) print('prev werc20 LP balance', prevLPBal_werc20) print('cur werc20 LP balance', curLPBal_werc20) print('coll size', collSize) # alice assert almostEqual(curLPBal - prevLPBal, lp_want), 'incorrect LP amt' # werc20 assert almostEqual(curLPBal_werc20 - prevLPBal_werc20, -collSize), 'incorrect werc20 LP amt' # spell assert usdt.balanceOf(uniswap_spell) == 0, 'non-zero spell USDT balance' assert usdc.balanceOf(uniswap_spell) == 0, 'non-zero spell USDC balance' assert lp.balanceOf(uniswap_spell) == 0, 'non-zero spell LP balance' # debt assert usdtDebt == 0, 'usdtDebt should be 0' assert usdcDebt == 0, 'usdcDebt should be 0' ##################################################################################### # add liquidity without borrowing (1x) print( '=========================================================================' ) print('Case 5.') prevABal = usdt.balanceOf(alice) prevBBal = usdc.balanceOf(alice) prevLPBal = lp.balanceOf(alice) prevLPBal_bank = lp.balanceOf(homora) prevLPBal_werc20 = lp.balanceOf(werc20) usdt_amt = 2000 * 10**6 # 2000 USDT usdc_amt = 3000 * 10**6 # 3000 USDC lp_amt = 0 borrow_usdt_amt = 0 borrow_usdc_amt = 0 prevBBal = usdc.balanceOf(alice) tx = homora.execute( 1, uniswap_spell, uniswap_spell.addLiquidity.encode_input( usdt, # token 0 usdc, # token 1 [ usdt_amt, # supply USDT usdc_amt, # supply USDC lp_amt, # supply LP borrow_usdt_amt, # borrow USDT borrow_usdc_amt, # borrow USDC 0, # borrow LP 0, # min USDT 0 ], # min USDC ), {'from': alice}) position_id = tx.return_value print('position_id', position_id) curABal = usdt.balanceOf(alice) curBBal = usdc.balanceOf(alice) curLPBal = lp.balanceOf(alice) curLPBal_bank = lp.balanceOf(homora) curLPBal_werc20 = lp.balanceOf(werc20) print('spell lp balance', lp.balanceOf(uniswap_spell)) print('Alice delta A balance', curABal - prevABal) print('Alice delta B balance', curBBal - prevBBal) print('Alice delta lp balance', curLPBal - prevLPBal) print('add liquidity gas', tx.gas_used) print('bank lp balance', curLPBal_bank) _, _, _, usdtDebt, usdtDebtShare = homora.getBankInfo(usdt) _, _, _, usdcDebt, usdcDebtShare = homora.getBankInfo(usdc) print('bank usdt totalDebt', usdtDebt) print('bank usdt totalShare', usdtDebtShare) print('bank usdc totalDebt', usdcDebt) print('bank usdc totalShare', usdcDebtShare) print('bank prev LP balance', prevLPBal_bank) print('bank cur LP balance', curLPBal_bank) print('werc20 prev LP balance', prevLPBal_werc20) print('werc20 cur LP balance', curLPBal_werc20) # alice assert almostEqual(curABal - prevABal, -usdt_amt), 'incorrect USDT amt' assert almostEqual(curBBal - prevBBal, -usdc_amt), 'incorrect USDC amt' assert almostEqual(curLPBal - prevLPBal, -lp_amt), 'incorrect LP amt' # spell assert usdt.balanceOf(uniswap_spell) == 0, 'non-zero spell USDT balance' assert usdc.balanceOf(uniswap_spell) == 0, 'non-zero spell USDC balance' assert lp.balanceOf(uniswap_spell) == 0, 'non-zero spell LP balance' # debt assert usdtDebt == borrow_usdt_amt assert usdcDebt == borrow_usdc_amt ##################################################################################### # remove all liquidity from the same position print( '=========================================================================' ) print('Case 6.') prevABal = usdt.balanceOf(alice) prevBBal = usdc.balanceOf(alice) prevLPBal = lp.balanceOf(alice) prevLPBal_bank = lp.balanceOf(homora) prevLPBal_werc20 = lp.balanceOf(werc20) _, _, _, collSize = homora.getPositionInfo(position_id) lp_take_amt = MAX_INT # max lp_want = 0 usdt_repay = 0 # max usdc_repay = 0 # max tx = homora.execute( position_id, uniswap_spell, uniswap_spell.removeLiquidity.encode_input( usdt, usdc, [ lp_take_amt, # take out LP lp_want, # withdraw LP to wallet usdt_repay, # repay USDT usdc_repay, # repay USDC 0, # repay LP 0, # min USDT 0 ], # min USDC ), {'from': alice}) curABal = usdt.balanceOf(alice) curBBal = usdc.balanceOf(alice) curLPBal = lp.balanceOf(alice) curLPBal_bank = lp.balanceOf(homora) curLPBal_werc20 = lp.balanceOf(werc20) print('spell lp balance', lp.balanceOf(uniswap_spell)) print('spell usdt balance', usdt.balanceOf(uniswap_spell)) print('spell usdc balance', usdc.balanceOf(uniswap_spell)) print('Alice delta A balance', curABal - prevABal) print('Alice delta B balance', curBBal - prevBBal) print('Alice delta LP balance', curLPBal - prevLPBal) print('remove liquidity gas', tx.gas_used) print('bank delta lp balance', curLPBal_bank - prevLPBal_bank) print('bank total lp balance', curLPBal_bank) _, _, _, usdtDebt, usdtDebtShare = homora.getBankInfo(usdt) _, _, _, usdcDebt, usdcDebtShare = homora.getBankInfo(usdc) print('bank usdt totalDebt', usdtDebt) print('bank usdt totalShare', usdtDebtShare) print('bank usdc totalDebt', usdcDebt) print('bank usdc totalShare', usdcDebtShare) print('LP want', lp_want) print('bank delta LP amount', curLPBal_bank - prevLPBal_bank) print('LP take amount', lp_take_amt) print('prev werc20 LP balance', prevLPBal_werc20) print('cur werc20 LP balance', curLPBal_werc20) print('coll size', collSize) # alice assert almostEqual(curLPBal - prevLPBal, lp_want), 'incorrect LP amt' # werc20 assert almostEqual(curLPBal_werc20 - prevLPBal_werc20, -collSize), 'incorrect werc20 LP amt' # spell assert usdt.balanceOf(uniswap_spell) == 0, 'non-zero spell USDT balance' assert usdc.balanceOf(uniswap_spell) == 0, 'non-zero spell USDC balance' assert lp.balanceOf(uniswap_spell) == 0, 'non-zero spell LP balance' # debt assert usdtDebt == 0, 'usdtDebt should be 0' assert usdcDebt == 0, 'usdcDebt should be 0' return tx
def main(): admin = accounts[0] alice = accounts[1] bob = accounts[2] usdt = interface.IERC20Ex('0xdac17f958d2ee523a2206206994597c13d831ec7') weth = interface.IERC20Ex('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2') usdc = interface.IERC20Ex('0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48') lp = interface.IERC20Ex('0x06da0fd433C1A5d7a4faa01111c044910A184553') lp_usdc = interface.IERC20Ex('0x3041cbd36888becc7bbcbc0045e3b1f144466f5f') crusdt = interface.ICErc20('0x797AAB1ce7c01eB727ab980762bA88e7133d2157') crusdc = interface.ICErc20('0x44fbebd2f576670a6c33f6fc0b00aa8c5753b322') sushi = interface.IERC20('0x6b3595068778dd592e39a122f4f5a5cf09c90fe2') # sushiswap router router = interface.IUniswapV2Router02( '0xd9e1ce17f2641f24ae83637ab66a2cca9c378b9f') chef = accounts.at('0xc2edad668740f1aa35e4d8f227fb8e17dca888cd', force=True) wchef = WMasterChef.deploy(chef, {'from': admin}) werc20 = WERC20.deploy({'from': admin}) simple_oracle = SimpleOracle.deploy({'from': admin}) simple_oracle.setETHPx([usdt, weth, usdc], [2**112 // 700, 2**112, 2**112 // 700]) uniswap_oracle = UniswapV2Oracle.deploy(simple_oracle, {'from': admin}) core_oracle = CoreOracle.deploy({'from': admin}) oracle = ProxyOracle.deploy(core_oracle, {'from': admin}) oracle.setWhitelistERC1155([werc20, wchef], True, {'from': admin}) core_oracle.setRoute( [usdt, weth, lp, usdc, lp_usdc], [ simple_oracle, simple_oracle, uniswap_oracle, simple_oracle, uniswap_oracle ], {'from': admin}, ) oracle.setOracles( [usdt, weth, lp, usdc, lp_usdc], [ [10000, 10000, 10000], [10000, 10000, 10000], [10000, 10000, 10000], [10000, 10000, 10000], [10000, 10000, 10000], ], {'from': admin}, ) homora = HomoraBank.deploy({'from': admin}) homora.initialize(oracle, 1000, {'from': admin}) # 10% fee setup_bank_hack(homora) homora.addBank(usdt, crusdt, {'from': admin}) homora.addBank(usdc, crusdc, {'from': admin}) # setup initial funds to alice mint_tokens(usdt, alice) mint_tokens(weth, alice) mint_tokens(usdc, alice) # check alice's funds print(f'Alice usdt balance {usdt.balanceOf(alice)}') print(f'Alice weth balance {weth.balanceOf(alice)}') # Steal some LP from the staking pool mint_tokens(lp, alice) mint_tokens(lp, bob) # set approval usdt.approve(homora, 2**256 - 1, {'from': alice}) usdt.approve(crusdt, 2**256 - 1, {'from': alice}) usdc.approve(homora, 2**256 - 1, {'from': alice}) usdc.approve(crusdc, 2**256 - 1, {'from': alice}) weth.approve(homora, 2**256 - 1, {'from': alice}) lp.approve(homora, 2**256 - 1, {'from': alice}) lp.approve(chef, 2**256 - 1, {'from': bob}) sushiswap_spell = SushiswapSpellV1.deploy(homora, werc20, router, wchef, {'from': admin}) # first time call to reduce gas sushiswap_spell.getPair(weth, usdt, {'from': admin}) ##################################################################################### print( '=========================================================================' ) print('Case 1. add liquidity first time') prevABal = usdt.balanceOf(alice) prevBBal = weth.balanceOf(alice) prevLPBal = lp.balanceOf(alice) prevLPBal_bank = lp.balanceOf(homora) prevLPBal_chef = lp.balanceOf(chef) if interface.IUniswapV2Pair(lp).token0() == usdt: prevARes, prevBRes, _ = interface.IUniswapV2Pair(lp).getReserves() else: prevBRes, prevARes, _ = interface.IUniswapV2Pair(lp).getReserves() usdt_amt = 10 * 10**6 weth_amt = 10**18 lp_amt = 0 borrow_usdt_amt = 0 borrow_weth_amt = 0 pid = 0 tx = homora.execute( 0, sushiswap_spell, sushiswap_spell.addLiquidityWMasterChef.encode_input( usdt, # token 0 weth, # token 1 [ usdt_amt, # supply USDT weth_amt, # supply WETH lp_amt, # supply LP borrow_usdt_amt, # borrow USDT borrow_weth_amt, # borrow WETH 0, # borrow LP tokens 0, # min USDT 0 ], # min WETH pid, ), {'from': alice}) curABal = usdt.balanceOf(alice) curBBal = weth.balanceOf(alice) curLPBal = lp.balanceOf(alice) curLPBal_bank = lp.balanceOf(homora) curLPBal_chef = lp.balanceOf(chef) if interface.IUniswapV2Pair(lp).token0() == usdt: curARes, curBRes, _ = interface.IUniswapV2Pair(lp).getReserves() else: curBRes, curARes, _ = interface.IUniswapV2Pair(lp).getReserves() print('spell lp balance', lp.balanceOf(sushiswap_spell)) print('Alice delta A balance', curABal - prevABal) print('Alice delta B balance', curBBal - prevBBal) print('add liquidity gas', tx.gas_used) print('bank lp balance', curLPBal_bank) _, _, _, totalDebt, totalShare = homora.getBankInfo(usdt) print('bank usdt totalDebt', totalDebt) print('bank usdt totalShare', totalShare) print('bank prev LP balance', prevLPBal_bank) print('bank cur LP balance', curLPBal_bank) print('chef prev LP balance', prevLPBal_chef) print('chef cur LP balance', curLPBal_chef) print('prev usdt res', prevARes) print('cur usdt res', curARes) print('prev weth res', prevBRes) print('cur weth res', curBRes) # alice assert almostEqual(curABal - prevABal, -usdt_amt), 'incorrect USDT amt' assert almostEqual(curBBal - prevBBal, -weth_amt), 'incorrect WETH amt' assert curLPBal - prevLPBal == -lp_amt, 'incorrect LP amt' # spell assert usdt.balanceOf(sushiswap_spell) == 0, 'non-zero spell USDT balance' assert weth.balanceOf(sushiswap_spell) == 0, 'non-zero spell WETH balance' assert lp.balanceOf(sushiswap_spell) == 0, 'non-zero spell LP balance' assert totalDebt == borrow_usdt_amt # check balance and pool reserves assert curABal - prevABal - borrow_usdt_amt == - \ (curARes - prevARes), 'not all USDT tokens go to LP pool' assert almostEqual( curBBal - prevBBal - borrow_weth_amt, -(curBRes - prevBRes)), 'not all WETH tokens go to LP pool' _, _, collId, collSize = homora.getPositionInfo(1) print('collSize', collSize) # staking directly prevSushi = sushi.balanceOf(bob) pid = 0 print('bob lp balance', interface.IERC20Ex(lp).balanceOf(bob)) tx = interface.IMasterChef(chef).deposit(pid, collSize, {'from': bob}) chain.sleep(20000) prevAliceSushiBalance = sushi.balanceOf(alice) print('Alice sushi balance', prevAliceSushiBalance) ##################################################################################### print( '=========================================================================' ) print('Case 2. add liquidity (failed tx desired)') usdc_amt = 10 * 10**6 weth_amt = 10**18 lp_amt = 0 borrow_usdc_amt = 0 borrow_weth_amt = 0 pid = 0 try: tx = homora.execute( 1, sushiswap_spell, sushiswap_spell.addLiquidityWMasterChef.encode_input( usdc, # token 0 weth, # token 1 [ usdc_amt, # supply USDC weth_amt, # supply WETH lp_amt, # supply LP borrow_usdc_amt, # borrow USDC borrow_weth_amt, # borrow WETH 0, # borrow LP tokens 0, # min USDC 0 ], # min WETH pid, ), {'from': alice}) assert False, 'tx not fail' except VirtualMachineError: pass ##################################################################################### print( '=========================================================================' ) print('Case 3. remove liquidity (failed tx desired)') lp_take_amt = collSize lp_want = 0 usdc_repay = 0 weth_repay = 0 try: tx = homora.execute( 1, sushiswap_spell, sushiswap_spell.removeLiquidityWMasterChef.encode_input( usdc, # token 0 weth, # token 1 [ lp_take_amt, # take out LP tokens lp_want, # withdraw LP tokens to wallet usdc_repay, # repay USDC weth_repay, # repay WETH 0, # repay LP tokens 0, # min USDC 0 ], # min WETH ), {'from': alice}) assert False, 'tx not failed' except VirtualMachineError: pass ##################################################################################### print( '=========================================================================' ) print('Case 4. remove liquidity') prevABal = usdt.balanceOf(alice) prevBBal = weth.balanceOf(alice) prevLPBal = lp.balanceOf(alice) prevLPBal_bank = lp.balanceOf(homora) prevLPBal_chef = lp.balanceOf(chef) prevETHBal = alice.balance() if interface.IUniswapV2Pair(lp).token0() == usdt: prevARes, prevBRes, _ = interface.IUniswapV2Pair(lp).getReserves() else: prevBRes, prevARes, _ = interface.IUniswapV2Pair(lp).getReserves() lp_take_amt = collSize lp_want = 0 usdt_repay = 0 weth_repay = 0 pid = 0 tx = homora.execute( 1, sushiswap_spell, sushiswap_spell.removeLiquidityWMasterChef.encode_input( usdt, # token 0 weth, # token 1 [ lp_take_amt, # take out LP tokens lp_want, # withdraw LP tokens to wallet usdt_repay, # repay USDT weth_repay, # repay WETH 0, # repay LP tokens 0, # min USDT 0 ], # min WETH ), {'from': alice}) curABal = usdt.balanceOf(alice) curBBal = weth.balanceOf(alice) curLPBal = lp.balanceOf(alice) curLPBal_bank = lp.balanceOf(homora) curLPBal_chef = lp.balanceOf(chef) curETHBal = alice.balance() if interface.IUniswapV2Pair(lp).token0() == usdt: curARes, curBRes, _ = interface.IUniswapV2Pair(lp).getReserves() else: curBRes, curARes, _ = interface.IUniswapV2Pair(lp).getReserves() print('spell lp balance', lp.balanceOf(sushiswap_spell)) print('Alice delta A balance', curABal - prevABal) print('Alice delta B balance', curBBal - prevBBal) print('add liquidity gas', tx.gas_used) print('bank lp balance', curLPBal_bank) _, _, _, totalDebt, totalShare = homora.getBankInfo(usdt) print('bank usdt totalDebt', totalDebt) print('bank usdt totalShare', totalShare) print('bank prev LP balance', prevLPBal_bank) print('bank cur LP balance', curLPBal_bank) print('chef prev LP balance', prevLPBal_chef) print('chef cur LP balance', curLPBal_chef) print('prev usdt res', prevARes) print('cur usdt res', curARes) print('prev weth res', prevBRes) print('cur weth res', curBRes) # alice assert almostEqual(curBBal - prevBBal, 0), 'incorrect WETH amt' assert almostEqual(curLPBal - prevLPBal, lp_want), 'incorrect LP amt' # chef assert almostEqual(curLPBal_chef - prevLPBal_chef, -lp_take_amt), 'incorrect chef LP amt' # spell assert usdt.balanceOf(sushiswap_spell) == 0, 'non-zero spell USDT balance' assert weth.balanceOf(sushiswap_spell) == 0, 'non-zero spell WETH balance' assert lp.balanceOf(sushiswap_spell) == 0, 'non-zero spell LP balance' # check balance and pool reserves assert almostEqual( curABal - prevABal + usdt_repay, -(curARes - prevARes)), 'inconsistent USDT from withdraw' assert almostEqual(curBBal - prevBBal, 0), 'inconsistent WETH from withdraw' assert almostEqual(curETHBal - prevETHBal + weth_repay, -(curBRes - prevBRes)), 'inconsistent ETH from withdraw' curAliceSushiBalance = sushi.balanceOf(alice) print('Alice sushi balance', curAliceSushiBalance) receivedSushi = curAliceSushiBalance - prevAliceSushiBalance print('received sushi', receivedSushi) # check with staking directly pid = 0 tx = interface.IMasterChef(chef).withdraw(pid, collSize, {'from': bob}) receivedSushiFromStaking = sushi.balanceOf(bob) - prevSushi print('receivedSushiFromStaking', receivedSushiFromStaking) assert almostEqual(receivedSushi, receivedSushiFromStaking)
def main(): admin = accounts[0] alice = accounts[1] alpha = interface.IERC20Ex('0xa1faa113cbe53436df28ff0aee54275c13b40975') ibethv2 = SafeBoxETH.at('0xeEa3311250FE4c3268F8E684f7C87A82fF183Ec1') mint_tokens(alpha, alice) mint_tokens(alpha, admin) ibethv2.deposit({'from': alice, 'value': '100000 ether'}) ibethv2.deposit({'from': admin, 'value': '100000 ether'}) pair = interface.IUniswapV2Pair( '0xf79a07cd3488BBaFB86dF1bAd09a6168D935c017') # sushi router router = interface.IUniswapV2Router02( '0xd9e1ce17f2641f24ae83637ab66a2cca9c378b9f') ibethv2_router = IbETHRouterV2.deploy(alpha, ibethv2, router, {'from': admin}) alpha.approve(ibethv2_router, 2**256 - 1, {'from': alice}) ibethv2.approve(ibethv2_router, 2**256 - 1, {'from': alice}) pair.approve(ibethv2_router, 2**256 - 1, {'from': alice}) ####################################################################### # setup liquidity first time init_alpha_amt = 1000 * 10**alpha.decimals() init_ibethv2_amt = 1 * 10**ibethv2.decimals() ibethv2.transfer(pair, init_ibethv2_amt, {'from': admin}) alpha.transfer(pair, init_alpha_amt, {'from': admin}) pair.mint(admin, {'from': admin}) prevIbethv2Bal = ibethv2.balanceOf(admin) ibethv2.deposit({'from': admin, 'value': '1 ether'}) curIbethv2Bal = ibethv2.balanceOf(admin) ibethv2_eth_rate = 10**18 / (curIbethv2Bal - prevIbethv2Bal) print('conversion rate', ibethv2_eth_rate) print('init ibethv2 amt', init_ibethv2_amt * ibethv2_eth_rate) print('deposited', 10**18, 'ether') print('received', curIbethv2Bal - prevIbethv2Bal, 'ibethv2') ######################################################################## # check state vars print('=======================================') print('Case. check state vars') assert ibethv2_router.alpha() == alpha assert ibethv2_router.ibETHv2() == ibethv2 assert ibethv2_router.lpToken() == pair assert ibethv2_router.router() == router ####################################################################### # test swap exact ETH to ALPHA print('===========================================') print('Case. test swap exact eth to alpha') eth_amt = 10**12 prevETHBal = alice.balance() prevAlphaBal = alpha.balanceOf(alice) ibethv2_router.swapExactETHToAlpha(0, alice, 2**256 - 1, { 'from': alice, 'value': eth_amt, 'gas_price': 0 }) curETHBal = alice.balance() curAlphaBal = alpha.balanceOf(alice) print('∆ alpha', curAlphaBal - prevAlphaBal) print( 'calc alpha', eth_amt * (init_alpha_amt / init_ibethv2_amt) / ibethv2_eth_rate * 0.997) assert curETHBal - prevETHBal == -eth_amt, 'incorrect ETH amount' assert almostEqual( curAlphaBal - prevAlphaBal, eth_amt * (init_alpha_amt / init_ibethv2_amt) / ibethv2_eth_rate * 0.997), 'incorrect alpha amount' ####################################################################### # test swap exact ALPHA to ETH print('=========================================') print('Case. swap exact alpha to eth') alpha_amt = 10**18 prevETHBal = alice.balance() prevAlphaBal = alpha.balanceOf(alice) ibethv2_router.swapExactAlphaToETH(alpha_amt, 0, alice, 2**256 - 1, { 'from': alice, 'gas_price': 0 }) curETHBal = alice.balance() curAlphaBal = alpha.balanceOf(alice) print('∆ eth', curETHBal - prevETHBal) print( 'calc eth', alpha_amt / (init_alpha_amt / init_ibethv2_amt) * ibethv2_eth_rate * 0.997) assert almostEqual( curETHBal - prevETHBal, alpha_amt / (init_alpha_amt / init_ibethv2_amt) * ibethv2_eth_rate * 0.997), 'incorrect ETH amount' assert almostEqual(curAlphaBal - prevAlphaBal, -alpha_amt), 'incorrect alpha amount' ####################################################################### # test add liquidity eth alpha optimal print('=========================================') print('Case. test add liquidity eth alpha optimal') alpha_amt = 100000 * 10**18 eth_amt = 1000 * 10**18 prevETHBal = alice.balance() prevAlphaBal = alpha.balanceOf(alice) prevLPBal = pair.balanceOf(alice) prevLPSupply = pair.totalSupply() r0, r1, _ = pair.getReserves() ibethv2_router.addLiquidityETHAlphaOptimal(alpha_amt, 0, alice, 2**256 - 1, { 'from': alice, 'value': eth_amt, 'gas_price': 0 }) curETHBal = alice.balance() curAlphaBal = alpha.balanceOf(alice) curLPBal = pair.balanceOf(alice) new_r0, new_r1, _ = pair.getReserves() expected_lp = (sqrt((new_r0 * new_r1) / (r0 * r1)) - 1) * prevLPSupply print('prev total lp supply', prevLPSupply) print('prev reserves', r0, r1) print('cur reserves', new_r0, new_r1) print('∆ lp', curLPBal - prevLPBal) print('calc lp', expected_lp) assert almostEqual(new_r0, r0 + alpha_amt), 'incorrect r0 new amt' assert almostEqual(new_r1, r1 + eth_amt / ibethv2_eth_rate), 'incorrect r1 new amt' assert curETHBal - prevETHBal == -eth_amt, 'incorrect ETH add' assert curAlphaBal - prevAlphaBal == -alpha_amt, 'incorrect Alpha add' assert almostEqual(curLPBal - prevLPBal, expected_lp), 'incorrect LP received' # ########################################################################### # # test add liquidity ibethv2 alpha optimal print('=========================================') print('Case. test add liquidity ibethv2 alpha optimal') alpha_amt = 1000000 * 10**18 ibethv2_amt = 1000 * 10**5 prevETHBal = alice.balance() prevIbethv2Bal = ibethv2.balanceOf(alice) prevAlphaBal = alpha.balanceOf(alice) prevLPBal = pair.balanceOf(alice) prevLPSupply = pair.totalSupply() r0, r1, _ = pair.getReserves() ibethv2_router.addLiquidityIbETHv2AlphaOptimal(ibethv2_amt, alpha_amt, 0, alice, 2**256 - 1, { 'from': alice, 'gas_price': 0 }) curETHBal = alice.balance() curAlphaBal = alpha.balanceOf(alice) curIbethv2Bal = ibethv2.balanceOf(alice) curLPBal = pair.balanceOf(alice) new_r0, new_r1, _ = pair.getReserves() expected_lp = (sqrt((new_r0 * new_r1) / (r0 * r1)) - 1) * prevLPSupply print('prev total lp supply', prevLPSupply) print('prev reserves', r0, r1) print('cur reserves', new_r0, new_r1) print('∆ lp', curLPBal - prevLPBal) print('calc lp', expected_lp) assert almostEqual(new_r0, r0 + alpha_amt), 'incorrect r0 new amt' assert almostEqual(new_r1, r1 + ibethv2_amt), 'incorrect r1 new amt' assert curIbethv2Bal - prevIbethv2Bal == -ibethv2_amt, 'incorrect ibethv2 add' assert curAlphaBal - prevAlphaBal == -alpha_amt, 'incorrect Alpha add' assert almostEqual(curLPBal - prevLPBal, expected_lp), 'incorrect LP received' ############################################################################### # test remove liquidity eth alpha print('===========================================') print('Case. test remove liquidity eth alpha') lp_amt = pair.balanceOf(alice) // 3 prevETHBal = alice.balance() prevIbethv2Bal = ibethv2.balanceOf(alice) prevAlphaBal = alpha.balanceOf(alice) prevLPBal = pair.balanceOf(alice) prevLPSupply = pair.totalSupply() r0, r1, _ = pair.getReserves() # token0 = alpha ibethv2_router.removeLiquidityETHAlpha(lp_amt, 0, 0, alice, 2**256 - 1, {'from': alice}) curETHBal = alice.balance() curAlphaBal = alpha.balanceOf(alice) curIbethv2Bal = ibethv2.balanceOf(alice) curLPBal = pair.balanceOf(alice) print('∆ alpha', curAlphaBal - prevAlphaBal) print('∆ ibethv2', curIbethv2Bal - prevIbethv2Bal) assert curLPBal - prevLPBal == -lp_amt, 'incorrect LP withdraw' assert almostEqual(curAlphaBal - prevAlphaBal, lp_amt / prevLPSupply * r0), 'incorrect alpha withdraw amount' assert almostEqual(curETHBal - prevETHBal, lp_amt / prevLPSupply * r1 * ibethv2_eth_rate), 'incorrect eth withraw amount' ################################################################################## # test remove liquidity alpha only print('===============================================') print('Case. test remove liquidity alpha only') lp_amt = pair.balanceOf(alice) // 10**3 prevETHBal = alice.balance() prevIbethv2Bal = ibethv2.balanceOf(alice) prevAlphaBal = alpha.balanceOf(alice) prevLPBal = pair.balanceOf(alice) prevLPSupply = pair.totalSupply() r0, r1, _ = pair.getReserves() # token0 = alpha ibethv2_router.removeLiquidityAlphaOnly(lp_amt, 0, alice, 2**256 - 1, {'from': alice}) curETHBal = alice.balance() curAlphaBal = alpha.balanceOf(alice) curIbethv2Bal = ibethv2.balanceOf(alice) curLPBal = pair.balanceOf(alice) assert curLPBal - prevLPBal == -lp_amt, 'incorrect LP withdraw' assert almostEqual(curAlphaBal - prevAlphaBal, lp_amt / prevLPSupply * r0 * 2), 'incorrect alpha withdraw amount'
def main(): admin = accounts[0] alice = accounts[1] bob = accounts[2] usdt = interface.IERC20Ex('0xdac17f958d2ee523a2206206994597c13d831ec7') weth = interface.IERC20Ex('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2') lp = interface.IERC20Ex('0x06da0fd433C1A5d7a4faa01111c044910A184553') crusdt = interface.ICErc20('0x797AAB1ce7c01eB727ab980762bA88e7133d2157') sushi = interface.IERC20('0x6b3595068778dd592e39a122f4f5a5cf09c90fe2') # sushiswap router router = interface.IUniswapV2Router02( '0xd9e1ce17f2641f24ae83637ab66a2cca9c378b9f') chef = accounts.at('0xc2edad668740f1aa35e4d8f227fb8e17dca888cd', force=True) wchef = WMasterChef.deploy(chef, {'from': admin}) werc20 = WERC20.deploy({'from': admin}) simple_oracle = SimpleOracle.deploy({'from': admin}) simple_oracle.setETHPx([usdt, weth], [2**112 // 700, 2**112]) uniswap_oracle = UniswapV2Oracle.deploy(simple_oracle, {'from': admin}) core_oracle = CoreOracle.deploy({'from': admin}) oracle = ProxyOracle.deploy(core_oracle, {'from': admin}) oracle.setWhitelistERC1155([werc20, wchef], True, {'from': admin}) core_oracle.setRoute( [usdt, weth, lp], [simple_oracle, simple_oracle, uniswap_oracle], {'from': admin}, ) oracle.setOracles( [usdt, weth, lp], [ [10000, 10000, 10000], [10000, 10000, 10000], [10000, 10000, 10000], ], {'from': admin}, ) homora = HomoraBank.deploy({'from': admin}) homora.initialize(oracle, 1000, {'from': admin}) # 10% fee setup_bank_hack(homora) homora.addBank(usdt, crusdt, {'from': admin}) # setup initial funds to alice mint_tokens(usdt, alice) mint_tokens(weth, alice) # check alice's funds print(f'Alice usdt balance {usdt.balanceOf(alice)}') print(f'Alice weth balance {weth.balanceOf(alice)}') # Steal some LP from the staking pool mint_tokens(lp, alice) mint_tokens(lp, bob) # set approval usdt.approve(homora, 2**256 - 1, {'from': alice}) usdt.approve(crusdt, 2**256 - 1, {'from': alice}) weth.approve(homora, 2**256 - 1, {'from': alice}) lp.approve(homora, 2**256 - 1, {'from': alice}) lp.approve(chef, 2**256 - 1, {'from': bob}) sushiswap_spell = SushiswapSpellV1.deploy(homora, werc20, router, wchef, {'from': admin}) # first time call to reduce gas sushiswap_spell.getPair(weth, usdt, {'from': admin}) # whitelist spell in bank homora.setWhitelistSpells([sushiswap_spell], [True], {'from': admin}) # whitelist lp in spell sushiswap_spell.setWhitelistLPTokens([lp], [True], {'from': admin}) ##################################################################################### print( '=========================================================================' ) print('Case 1. add liquidity') prevABal = usdt.balanceOf(alice) prevBBal = weth.balanceOf(alice) prevLPBal = lp.balanceOf(alice) prevLPBal_bank = lp.balanceOf(homora) prevLPBal_wchef = lp.balanceOf(wchef) if interface.IUniswapV2Pair(lp).token0() == usdt: prevARes, prevBRes, _ = interface.IUniswapV2Pair(lp).getReserves() else: prevBRes, prevARes, _ = interface.IUniswapV2Pair(lp).getReserves() usdt_amt = 10 * 10**6 weth_amt = 10**18 lp_amt = 0 borrow_usdt_amt = 0 borrow_weth_amt = 0 pid = 0 tx = homora.execute( 0, sushiswap_spell, sushiswap_spell.addLiquidityWMasterChef.encode_input( usdt, # token 0 weth, # token 1 [ usdt_amt, # supply USDT weth_amt, # supply WETH lp_amt, # supply LP borrow_usdt_amt, # borrow USDT borrow_weth_amt, # borrow WETH 0, # borrow LP tokens 0, # min USDT 0 ], # min WETH pid, ), {'from': alice}) curABal = usdt.balanceOf(alice) curBBal = weth.balanceOf(alice) curLPBal = lp.balanceOf(alice) curLPBal_bank = lp.balanceOf(homora) curLPBal_wchef = lp.balanceOf(wchef) if interface.IUniswapV2Pair(lp).token0() == usdt: curARes, curBRes, _ = interface.IUniswapV2Pair(lp).getReserves() else: curBRes, curARes, _ = interface.IUniswapV2Pair(lp).getReserves() print('spell lp balance', lp.balanceOf(sushiswap_spell)) print('Alice delta A balance', curABal - prevABal) print('Alice delta B balance', curBBal - prevBBal) print('add liquidity gas', tx.gas_used) print('bank lp balance', curLPBal_bank) _, _, _, totalDebt, totalShare = homora.getBankInfo(usdt) print('bank usdt totalDebt', totalDebt) print('bank usdt totalShare', totalShare) print('bank prev LP balance', prevLPBal_bank) print('bank cur LP balance', curLPBal_bank) print('wchef prev LP balance', prevLPBal_wchef) print('wchef cur LP balance', curLPBal_wchef) print('prev usdt res', prevARes) print('cur usdt res', curARes) print('prev weth res', prevBRes) print('cur weth res', curBRes) # alice assert almostEqual(curABal - prevABal, -usdt_amt), 'incorrect USDT amt' assert almostEqual(curBBal - prevBBal, -weth_amt), 'incorrect WETH amt' assert curLPBal - prevLPBal == -lp_amt, 'incorrect LP amt' # spell assert usdt.balanceOf(sushiswap_spell) == 0, 'non-zero spell USDT balance' assert weth.balanceOf(sushiswap_spell) == 0, 'non-zero spell WETH balance' assert lp.balanceOf(sushiswap_spell) == 0, 'non-zero spell LP balance' assert totalDebt == borrow_usdt_amt # check balance and pool reserves assert curABal - prevABal - borrow_usdt_amt == - \ (curARes - prevARes), 'not all USDT tokens go to LP pool' assert almostEqual( curBBal - prevBBal - borrow_weth_amt, -(curBRes - prevBRes)), 'not all WETH tokens go to LP pool' # ##################################################################################### print( '=========================================================================' ) print('Case 2. harvest first time') prevSushiBalance = sushi.balanceOf(alice) print('Alice SUSHI balance before harvest', prevSushiBalance) _, _, collId, collSize = homora.getPositionInfo(1) print('collSize', collSize) # staking directly prevSushi = sushi.balanceOf(bob) print('bob lp balance', interface.IERC20Ex(lp).balanceOf(bob)) pid = 0 tx = interface.IMasterChef(chef).deposit(pid, collSize, {'from': bob}) chain.mine(100) tx = homora.execute(1, sushiswap_spell, sushiswap_spell.harvestWMasterChef.encode_input(), {'from': alice}) print('tx gas used', tx.gas_used) curSushiBalance = sushi.balanceOf(alice) print('Alice SUSHI balance after harvest', curSushiBalance) receivedSushi = curSushiBalance - prevSushiBalance # check with staking directly pid = 0 tx = interface.IMasterChef(chef).withdraw(pid, collSize, {'from': bob}) receivedSushiFromStaking = sushi.balanceOf(bob) - prevSushi print('receivedSushiFromStaking', receivedSushiFromStaking) assert almostEqual(receivedSushi, receivedSushiFromStaking) # ##################################################################################### print( '=========================================================================' ) print('Case 3. harvest second time') prevSushiBalance = sushi.balanceOf(alice) print('Alice SUSHI balance before harvest', prevSushiBalance) prevSushi = sushi.balanceOf(bob) print('bob lp balance', interface.IERC20Ex(lp).balanceOf(bob)) # staking directly prevSushi = sushi.balanceOf(bob) print('bob lp balance', interface.IERC20Ex(lp).balanceOf(bob)) pid = 0 tx = interface.IMasterChef(chef).deposit(pid, collSize, {'from': bob}) chain.mine(100) tx = homora.execute(1, sushiswap_spell, sushiswap_spell.harvestWMasterChef.encode_input(), {'from': alice}) print('tx gas used', tx.gas_used) curSushiBalance = sushi.balanceOf(alice) print('Alice SUSHI balance after harvest', curSushiBalance) receivedSushi = curSushiBalance - prevSushiBalance # check with staking directly tx = interface.IMasterChef(chef).withdraw(pid, collSize, {'from': bob}) receivedSushiFromStaking = sushi.balanceOf(bob) - prevSushi print('receivedSushiFromStaking', receivedSushiFromStaking) assert almostEqual(receivedSushi, receivedSushiFromStaking)
def main(): admin = accounts[0] alice = accounts[1] usdt = interface.IERC20Ex('0xdAC17F958D2ee523a2206206994597C13D831ec7') weth = interface.IERC20Ex('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2') lp = interface.IERC20Ex('0x0d4a11d5EEaaC28EC3F61d100daF4d40471f1852') crusdt = interface.ICErc20('0x797AAB1ce7c01eB727ab980762bA88e7133d2157') router = interface.IUniswapV2Router02( '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D') werc20 = WERC20.deploy({'from': admin}) simple_oracle = SimpleOracle.deploy({'from': admin}) simple_oracle.setETHPx( [usdt, weth], [9011535487953795006625883219171279625142296, 2**112]) uniswap_oracle = UniswapV2Oracle.deploy(simple_oracle, {'from': admin}) oracle = ProxyOracle.deploy({'from': admin}) oracle.setWhitelistERC1155([werc20], True, {'from': admin}) oracle.setOracles( [ '0xdAC17F958D2ee523a2206206994597C13D831ec7', # USDT '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', # WETH '0x0d4a11d5EEaaC28EC3F61d100daF4d40471f1852', # USDT-WETH ], [ [simple_oracle, 10000, 10000, 10000], [simple_oracle, 10000, 10000, 10000], [uniswap_oracle, 10000, 10000, 10000], ], {'from': admin}, ) homora = HomoraBank.deploy({'from': admin}) homora.initialize(oracle, 1000, {'from': admin}) # 10% fee setup_bank_hack(homora) homora.addBank(usdt, crusdt, {'from': admin}) # setup initial funds 10^5 USDT + 10^4 WETH to alice setup_transfer( usdt, accounts.at('0xbe0eb53f46cd790cd13851d5eff43d12404d33e8', force=True), alice, 10**5 * 10**6) setup_transfer( weth, accounts.at('0x397ff1542f962076d0bfe58ea045ffa2d347aca0', force=True), alice, 10**4 * 10**18) # setup initial funds 10^6 USDT + 10^5 WETH to homora bank setup_transfer( usdt, accounts.at('0xbe0eb53f46cd790cd13851d5eff43d12404d33e8', force=True), homora, 10**6 * 10**6) setup_transfer( weth, accounts.at('0x397ff1542f962076d0bfe58ea045ffa2d347aca0', force=True), homora, 10**4 * 10**18) # check alice's funds print(f'Alice usdt balance {usdt.balanceOf(alice)}') print(f'Alice weth balance {weth.balanceOf(alice)}') # Steal some LP from the staking pool lp.transfer( alice, 1 * 10**17, { 'from': accounts.at('0x767ecb395def19ab8d1b2fcc89b3ddfbed28fd6b', force=True) }) lp.transfer( homora, 2 * 10**17, { 'from': accounts.at('0x767ecb395def19ab8d1b2fcc89b3ddfbed28fd6b', force=True) }) # set approval usdt.approve(homora, 2**256 - 1, {'from': alice}) usdt.approve(crusdt, 2**256 - 1, {'from': alice}) weth.approve(homora, 2**256 - 1, {'from': alice}) lp.approve(homora, 2**256 - 1, {'from': alice}) uniswap_spell = UniswapV2SpellV1.deploy(homora, werc20, router, {'from': admin}) # first time call to reduce gas uniswap_spell.getPair(weth, usdt, {'from': admin}) ##################################################################################### print( '=========================================================================' ) print('Case 1.') prevABal = usdt.balanceOf(alice) prevBBal = weth.balanceOf(alice) prevETHBal = alice.balance() prevLPBal = lp.balanceOf(alice) prevLPBal_bank = lp.balanceOf(homora) prevLPBal_werc20 = lp.balanceOf(werc20) if interface.IUniswapV2Pair(lp).token0() == usdt: prevARes, prevBRes, _ = interface.IUniswapV2Pair(lp).getReserves() else: prevBRes, prevARes, _ = interface.IUniswapV2Pair(lp).getReserves() usdt_amt = 400 * 10**6 weth_amt = 10**18 eth_amt = 10**18 lp_amt = 1 * 10**16 borrow_usdt_amt = 1000 * 10**6 borrow_weth_amt = 0 tx = homora.execute( 0, uniswap_spell, uniswap_spell.addLiquidity.encode_input( usdt, # token 0 weth, # token 1 [ usdt_amt, # supply USDT weth_amt, # supply WETH lp_amt, # supply LP borrow_usdt_amt, # borrow USDT borrow_weth_amt, # borrow WETH 0, # borrow LP tokens 0, # min USDT 0 ], # min WETH ), { 'from': alice, 'value': eth_amt }) position_id = tx.return_value print('position_id', position_id) curABal = usdt.balanceOf(alice) curBBal = weth.balanceOf(alice) curETHBal = alice.balance() curLPBal = lp.balanceOf(alice) curLPBal_bank = lp.balanceOf(homora) curLPBal_werc20 = lp.balanceOf(werc20) if interface.IUniswapV2Pair(lp).token0() == usdt: curARes, curBRes, _ = interface.IUniswapV2Pair(lp).getReserves() else: curBRes, curARes, _ = interface.IUniswapV2Pair(lp).getReserves() print('spell lp balance', lp.balanceOf(uniswap_spell)) print('Alice delta A balance', curABal - prevABal) print('Alice delta B balance', curBBal - prevBBal) print('add liquidity gas', tx.gas_used) print('bank lp balance', curLPBal_bank) _, _, _, totalDebt, totalShare = homora.getBankInfo(usdt) print('bank usdt totalDebt', totalDebt) print('bank usdt totalShare', totalShare) print('bank prev LP balance', prevLPBal_bank) print('bank cur LP balance', curLPBal_bank) print('werc20 prev LP balance', prevLPBal_werc20) print('werc20 cur LP balance', curLPBal_werc20) # alice assert almostEqual(curABal - prevABal, -usdt_amt), 'incorrect USDT amt' assert almostEqual(curBBal - prevBBal, -weth_amt), 'incorrect WETH amt' assert almostEqual(curETHBal - prevETHBal, -eth_amt), 'incorrect ETH amt' assert curLPBal - prevLPBal == -lp_amt, 'incorrect LP amt' # spell assert usdt.balanceOf(uniswap_spell) == 0, 'non-zero spell USDT balance' assert weth.balanceOf(uniswap_spell) == 0, 'non-zero spell WETH balance' assert uniswap_spell.balance() == 0, 'non-zero spell ETH balance' assert lp.balanceOf(uniswap_spell) == 0, 'non-zero spell LP balance' assert totalDebt == borrow_usdt_amt # check balance and pool reserves assert curABal - prevABal - borrow_usdt_amt == - \ (curARes - prevARes), 'not all USDT tokens go to LP pool' assert curBBal - prevBBal - borrow_weth_amt - eth_amt == - \ (curBRes - prevBRes), 'not all WETH tokens go to LP pool' ##################################################################################### print( '=========================================================================' ) print('Case 2.') # remove liquidity from the same position prevABal = usdt.balanceOf(alice) prevBBal = weth.balanceOf(alice) prevLPBal = lp.balanceOf(alice) prevLPBal_bank = lp.balanceOf(homora) prevLPBal_werc20 = lp.balanceOf(werc20) prevETHBal = alice.balance() if interface.IUniswapV2Pair(lp).token0() == usdt: prevARes, prevBRes, _ = interface.IUniswapV2Pair(lp).getReserves() else: prevBRes, prevARes, _ = interface.IUniswapV2Pair(lp).getReserves() lp_take_amt = 1 * 10**16 lp_want = 1 * 10**15 usdt_repay = 2**256 - 1 # max weth_repay = 0 real_usdt_repay = homora.borrowBalanceStored(position_id, usdt) tx = homora.execute( position_id, uniswap_spell, uniswap_spell.removeLiquidity.encode_input( usdt, # token 0 weth, # token 1 [ lp_take_amt, # take out LP tokens lp_want, # withdraw LP tokens to wallet usdt_repay, # repay USDT weth_repay, # repay WETH 0, # repay LP 0, # min USDT 0 ], # min WETH ), {'from': alice}) curABal = usdt.balanceOf(alice) curBBal = weth.balanceOf(alice) curLPBal = lp.balanceOf(alice) curLPBal_bank = lp.balanceOf(homora) curLPBal_werc20 = lp.balanceOf(werc20) curETHBal = alice.balance() if interface.IUniswapV2Pair(lp).token0() == usdt: curARes, curBRes, _ = interface.IUniswapV2Pair(lp).getReserves() else: curBRes, curARes, _ = interface.IUniswapV2Pair(lp).getReserves() print('spell lp balance', lp.balanceOf(uniswap_spell)) print('spell usdt balance', usdt.balanceOf(uniswap_spell)) print('spell weth balance', weth.balanceOf(uniswap_spell)) print('Alice delta A balance', curABal - prevABal) print('Alice delta B balance', curBBal - prevBBal) print('Alice delta LP balance', curLPBal - prevLPBal) print('remove liquidity gas', tx.gas_used) print('bank delta lp balance', curLPBal_bank - prevLPBal_bank) print('bank total lp balance', curLPBal_bank) _, _, _, totalDebt, totalShare = homora.getBankInfo(usdt) print('bank usdt totalDebt', totalDebt) print('bank usdt totalShare', totalShare) print('LP want', lp_want) print('bank delta LP amount', curLPBal_bank - prevLPBal_bank) print('LP take amount', lp_take_amt) print('prev werc20 LP balance', prevLPBal_werc20) print('cur werc20 LP balance', curLPBal_werc20) # alice assert almostEqual(curBBal - prevBBal, 0), 'incorrect WETH amt' assert almostEqual(curLPBal - prevLPBal, lp_want), 'incorrect LP amt' # werc20 assert almostEqual(curLPBal_werc20 - prevLPBal_werc20, -lp_take_amt), 'incorrect werc20 LP amt' # spell assert usdt.balanceOf(uniswap_spell) == 0, 'non-zero spell USDT balance' assert weth.balanceOf(uniswap_spell) == 0, 'non-zero spell WETH balance' assert uniswap_spell.balance() == 0, 'non-zero spell ETH balance' assert lp.balanceOf(uniswap_spell) == 0, 'non-zero spell LP balance' # check balance and pool reserves assert almostEqual( curABal - prevABal + real_usdt_repay, -(curARes - prevARes)), 'inconsistent USDT from withdraw' assert almostEqual(curBBal - prevBBal, 0), 'inconsistent WETH from withdraw' assert almostEqual(curETHBal - prevETHBal + weth_repay, -(curBRes - prevBRes)), 'inconsistent ETH from withdraw' return tx