def main(): admin = accounts[0] alice = accounts[1] bob = accounts[2] dfd = interface.IERC20Ex('0x20c36f062a31865bED8a5B1e512D9a1A20AA333A') dusd = interface.IERC20Ex('0x5BC25f649fc4e26069dDF4cF4010F9f706c23831') lp = interface.IERC20Ex('0xd8e9690eff99e21a2de25e0b148ffaf47f47c972') # pool is lp for balancer pool = interface.IBalancerPool( '0xd8e9690eff99e21a2de25e0b148ffaf47f47c972') crdfd = MockCErc20.deploy(dfd, {'from': admin}) crdusd = MockCErc20.deploy(dusd, {'from': admin}) werc20 = WERC20.deploy({'from': admin}) staking = accounts.at('0xf068236ecad5fabb9883bbb26a6445d6c7c9a924', force=True) wstaking = WStakingRewards.deploy(staking, lp, dfd, {'from': admin}) simple_oracle = SimpleOracle.deploy({'from': admin}) simple_oracle.setETHPx([dfd, dusd], [2**112 // 2 // 700, 2**112 * 2 // 700]) balancer_oracle = BalancerPairOracle.deploy(simple_oracle, {'from': alice}) core_oracle = CoreOracle.deploy({'from': admin}) oracle = ProxyOracle.deploy(core_oracle, {'from': admin}) oracle.setWhitelistERC1155([werc20, wstaking], True, {'from': admin}) core_oracle.setRoute( [dfd, dusd, lp], [simple_oracle, simple_oracle, balancer_oracle], {'from': admin}, ) oracle.setOracles( [dfd, dusd, 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(dfd, crdfd, {'from': admin}) homora.addBank(dusd, crdusd, {'from': admin}) # setup initial funds to alice mint_tokens(dfd, alice) mint_tokens(dusd, alice) # check alice's funds print(f'Alice dusd balance {dusd.balanceOf(alice)}') print(f'Alice dfd balance {dfd.balanceOf(alice)}') # Steal some LP from the staking pool mint_tokens(lp, alice) mint_tokens(lp, bob) # set approval dfd.approve(homora, 2**256 - 1, {'from': alice}) dfd.approve(crdfd, 2**256 - 1, {'from': alice}) dusd.approve(homora, 2**256 - 1, {'from': alice}) dusd.approve(crdusd, 2**256 - 1, {'from': alice}) lp.approve(homora, 2**256 - 1, {'from': alice}) lp.approve(staking, 2**256 - 1, {'from': bob}) balancer_spell = BalancerSpellV1.deploy( homora, werc20, '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', {'from': admin}) # first time call to reduce gas balancer_spell.getPair(lp, {'from': admin}) ##################################################################################### print( '=========================================================================' ) print('Case 1.') prevABal = dfd.balanceOf(alice) prevBBal = dusd.balanceOf(alice) prevLPBal = lp.balanceOf(alice) prevLPBal_bank = lp.balanceOf(homora) prevLPBal_staking = lp.balanceOf(staking) prevARes = interface.IBalancerPool(lp).getBalance(dfd) prevBRes = interface.IBalancerPool(lp).getBalance(dusd) dfd_amt = 100 * 10**18 dusd_amt = 10**18 lp_amt = 0 borrow_dfd_amt = 0 borrow_dusd_amt = 0 # calculate slippage control total_dfd_amt = dfd_amt + borrow_dfd_amt total_dusd_amt = dusd_amt + borrow_dusd_amt dfd_weight = 0.58 dusd_weight = 0.42 ratio = (((prevARes + total_dfd_amt) / prevARes) ** dfd_weight) * \ (((prevBRes + total_dusd_amt) / prevBRes) ** dusd_weight) - 1 lp_desired = lp_amt + int( interface.IERC20(lp).totalSupply() * ratio * 0.995) print('lp desired', lp_desired) tx = homora.execute( 0, balancer_spell, balancer_spell.addLiquidityWStakingRewards.encode_input( lp, # lp token [ dfd_amt, # supply DFD dusd_amt, # supply DUSD lp_amt, # supply LP borrow_dfd_amt, # borrow DFD borrow_dusd_amt, # borrow DUSD 0, # borrow LP tokens lp_desired ], # LP desired wstaking), {'from': alice}) curABal = dfd.balanceOf(alice) curBBal = dusd.balanceOf(alice) curLPBal = lp.balanceOf(alice) curLPBal_bank = lp.balanceOf(homora) curLPBal_staking = lp.balanceOf(staking) curARes = interface.IBalancerPool(lp).getBalance(dfd) curBRes = interface.IBalancerPool(lp).getBalance(dusd) print('spell lp balance', lp.balanceOf(balancer_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) _, _, _, dfdDebt, dfdShare = homora.getBankInfo(dfd) print('bank dfd dfdDebt', dfdDebt) print('bank dfd dfdShare', dfdShare) 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 dfd res', prevARes) print('cur dfd res', curARes) print('prev dusd res', prevBRes) print('cur dusd res', curBRes) # alice assert almostEqual(curABal - prevABal, -dfd_amt), 'incorrect DFD amt' assert almostEqual(curBBal - prevBBal, -dusd_amt), 'incorrect DUSD amt' assert curLPBal - prevLPBal == -lp_amt, 'incorrect LP amt' # spell assert dfd.balanceOf(balancer_spell) == 0, 'non-zero spell DFD balance' assert dusd.balanceOf(balancer_spell) == 0, 'non-zero spell DUSD balance' assert lp.balanceOf(balancer_spell) == 0, 'non-zero spell LP balance' assert dfdDebt == borrow_dfd_amt # check balance and pool reserves assert almostEqual( curABal - prevABal - borrow_dfd_amt, -(curARes - prevARes)), 'not all DFD tokens go to LP pool' assert almostEqual( curBBal - prevBBal - borrow_dusd_amt, -(curBRes - prevBRes)), 'not all DUSD tokens go to LP pool' # ##################################################################################### print( '=========================================================================' ) print('Case 2. harvest first time') prevDfdBalance = dfd.balanceOf(alice) print('Alice DFD balance before harvest', prevDfdBalance) _, _, collId, collSize = homora.getPositionInfo(1) print('collSize', collSize) # staking directly prevDfd = dfd.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, balancer_spell, balancer_spell.harvestWStakingRewards.encode_input(wstaking), {'from': alice}) print('tx gas used', tx.gas_used) curDfdBalance = dfd.balanceOf(alice) print('Alice DFD balance after harvest', curDfdBalance) receivedDfd = curDfdBalance - prevDfdBalance # check with staking directly tx = interface.IStakingRewards(staking).getReward({'from': bob}) receivedDfdFromStaking = dfd.balanceOf(bob) - prevDfd print('receivedDfdFromStaking', receivedDfdFromStaking) assert almostEqual(receivedDfd, receivedDfdFromStaking) # ##################################################################################### print( '=========================================================================' ) print('Case 3. harvest second time') prevDfdBalance = dfd.balanceOf(alice) print('Alice DFD balance before harvest', prevDfdBalance) # staking directly prevDfd = dfd.balanceOf(bob) print('bob lp balance', interface.IERC20Ex(lp).balanceOf(bob)) chain.sleep(20000) tx = homora.execute( 1, balancer_spell, balancer_spell.harvestWStakingRewards.encode_input(wstaking), {'from': alice}) print('tx gas used', tx.gas_used) curDfdBalance = dfd.balanceOf(alice) print('Alice DFD balance after harvest', curDfdBalance) receivedDfd = curDfdBalance - prevDfdBalance # check with staking directly tx = interface.IStakingRewards(staking).getReward({'from': bob}) receivedDfdFromStaking = dfd.balanceOf(bob) - prevDfd print('receivedDfdFromStaking', receivedDfdFromStaking) assert almostEqual(receivedDfd, receivedDfdFromStaking)
def main(): admin = accounts[0] alice = accounts[1] bob = accounts[2] renbtc = interface.IERC20Ex('0xeb4c2781e4eba804ce9a9803c67d0893436bb27d') wbtc = interface.IERC20Ex('0x2260fac5e5542a773aa44fbcfedf7c193bc2c599') eurs = interface.IERC20Ex('0xdB25f211AB05b1c97D595516F45794528a807ad8') seur = interface.IERC20Ex('0xD71eCFF9342A5Ced620049e616c5035F1dB98620') lp = interface.IERC20Ex('0x49849C98ae39Fff122806C06791Fa73784FB3675') pool = interface.ICurvePool('0x93054188d876f558f4a66B2EF1d97d16eDf0895B') lp_eurs = interface.IERC20Ex('0x194eBd173F6cDacE046C53eACcE9B953F28411d1') pool_eurs = interface.ICurvePool( '0x0Ce6a5fF5217e38315f87032CF90686C96627CAA') registry = interface.ICurveRegistry( '0x7d86446ddb609ed0f5f8684acf30380a356b2b4c') crrenbtc = MockCErc20.deploy(renbtc, {'from': admin}) crwbtc = MockCErc20.deploy(wbtc, {'from': admin}) creurs = MockCErc20.deploy(eurs, {'from': admin}) crseur = MockCErc20.deploy(seur, {'from': admin}) gauge = accounts.at('0xB1F2cdeC61db658F091671F5f199635aEF202CAC', force=True) wgauge = WLiquidityGauge.deploy( registry, '0xD533a949740bb3306d119CC777fa900bA034cd52', {'from': admin}) crv = interface.IERC20Ex(wgauge.crv()) werc20 = WERC20.deploy({'from': admin}) simple_oracle = SimpleOracle.deploy({'from': admin}) simple_oracle.setETHPx( [renbtc, wbtc, eurs, seur], [2**112 * 30, 2**112 * 30, 2**112 // 700, 2**112 // 700]) curve_oracle = CurveOracle.deploy(simple_oracle, registry, {'from': admin}) curve_oracle.registerPool(lp) # update pool info curve_oracle.registerPool(lp_eurs) # update pool info core_oracle = CoreOracle.deploy({'from': admin}) oracle = ProxyOracle.deploy(core_oracle, {'from': admin}) oracle.setWhitelistERC1155([werc20, wgauge], True, {'from': admin}) core_oracle.setRoute( [renbtc, wbtc, lp, eurs, seur, lp_eurs], [ simple_oracle, simple_oracle, curve_oracle, simple_oracle, simple_oracle, curve_oracle ], {'from': admin}, ) oracle.setOracles( [renbtc, wbtc, lp, eurs, seur, lp_eurs], [ [10000, 10000, 10000], [10000, 10000, 10000], [10000, 10000, 10000], [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(renbtc, crrenbtc, {'from': admin}) homora.addBank(wbtc, crwbtc, {'from': admin}) homora.addBank(eurs, creurs, {'from': admin}) homora.addBank(seur, crseur, {'from': admin}) # setup initial funds to alice mint_tokens(renbtc, alice) mint_tokens(wbtc, alice) mint_tokens(eurs, alice) mint_tokens(seur, alice) mint_tokens(wbtc, crwbtc) # check alice's funds print(f'Alice renbtc balance {renbtc.balanceOf(alice)}') print(f'Alice wbtc balance {wbtc.balanceOf(alice)}') print(f'Alice eurs balance {eurs.balanceOf(alice)}') print(f'Alice seur balance {seur.balanceOf(alice)}') # steal some LP from the staking pool mint_tokens(lp, alice) mint_tokens(lp, bob) mint_tokens(lp_eurs, alice) # set approval renbtc.approve(homora, 2**256 - 1, {'from': alice}) renbtc.approve(crrenbtc, 2**256 - 1, {'from': alice}) wbtc.approve(homora, 2**256 - 1, {'from': alice}) wbtc.approve(crwbtc, 2**256 - 1, {'from': alice}) eurs.approve(homora, 2**256 - 1, {'from': alice}) eurs.approve(creurs, 2**256 - 1, {'from': alice}) seur.approve(homora, 2**256 - 1, {'from': alice}) seur.approve(crseur, 2**256 - 1, {'from': alice}) lp.approve(homora, 2**256 - 1, {'from': alice}) lp.approve(gauge, 2**256 - 1, {'from': bob}) lp_eurs.approve(homora, 2**256 - 1, {'from': alice}) curve_spell = CurveSpellV1.deploy( homora, werc20, '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', wgauge, {'from': admin}) # register gauge wgauge.registerGauge(9, 0) wgauge.registerGauge(23, 0) # set up pools curve_spell.getPool(lp) curve_spell.getPool(lp_eurs) # first time call to reduce gas curve_spell.ensureApproveN(lp, 2, {'from': admin}) curve_spell.ensureApproveN(lp_eurs, 2, {'from': admin}) # whitelist spell in bank homora.setWhitelistSpells([curve_spell], [True], {'from': admin}) # whitelist token in bank homora.setWhitelistTokens([wbtc], [True], {'from': admin}) # whitelist lp in spell curve_spell.setWhitelistLPTokens([lp, lp_eurs], [True, True], {'from': admin}) ##################################################################################### print( '=========================================================================' ) print('Case 1.') prevABal = renbtc.balanceOf(alice) prevBBal = wbtc.balanceOf(alice) prevLPBal = lp.balanceOf(alice) prevLPBal_bank = lp.balanceOf(homora) prevLPBal_gauge = lp.balanceOf(gauge) renbtc_amt = 1 * 10**7 wbtc_amt = 1 * 10**7 lp_amt = 10**13 borrow_renbtc_amt = 0 borrow_wbtc_amt = 20 * 10**6 borrow_lp_amt = 0 minLPMint = 0 pid = 9 gid = 0 tx = homora.execute( 0, curve_spell, curve_spell.addLiquidity2.encode_input( lp, # LP [renbtc_amt, wbtc_amt], # supply tokens lp_amt, # supply LP [borrow_renbtc_amt, borrow_wbtc_amt], # borrow tokens borrow_lp_amt, # borrow LP minLPMint, # min LP mint pid, gid), {'from': alice}) curABal = renbtc.balanceOf(alice) curBBal = wbtc.balanceOf(alice) curLPBal = lp.balanceOf(alice) curLPBal_bank = lp.balanceOf(homora) curLPBal_gauge = lp.balanceOf(gauge) print('spell lp balance', lp.balanceOf(curve_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) _, _, _, renbtcDebt, renbtcDebtShare = homora.getBankInfo(renbtc) _, _, _, wbtcDebt, wbtcDebtShare = homora.getBankInfo(wbtc) print('bank renbtc totalDebt', renbtcDebt) print('bank renbtc totalShare', renbtcDebtShare) print('bank wbtc totalDebt', wbtcDebt) print('bank wbtc totalShare', wbtcDebtShare) print('bank prev LP balance', prevLPBal_bank) print('bank cur LP balance', curLPBal_bank) print('gauge prev LP balance', prevLPBal_gauge) print('gauge cur LP balance', curLPBal_gauge) # alice assert almostEqual(curABal - prevABal, -renbtc_amt), 'incorrect renbtc amt' assert almostEqual(curBBal - prevBBal, -wbtc_amt), 'incorrect wbtc amt' assert almostEqual(curLPBal - prevLPBal, -lp_amt), 'incorrect LP amt' # spell assert renbtc.balanceOf(curve_spell) == 0, 'non-zero spell renbtc balance' assert wbtc.balanceOf(curve_spell) == 0, 'non-zero spell wbtc balance' assert lp.balanceOf(curve_spell) == 0, 'non-zero spell LP balance' # debt assert renbtcDebt == borrow_renbtc_amt assert wbtcDebt == borrow_wbtc_amt _, _, collId, collSize = homora.getPositionInfo(1) print('collSize', collSize) # staking directly prevCrv = crv.balanceOf(bob) print('bob lp balance', interface.IERC20Ex(lp).balanceOf(bob)) pid, gid = 9, 0 gauge, _ = wgauge.gauges(pid, gid) print('gauge address', gauge) tx = interface.ILiquidityGauge(gauge).deposit(collSize, {'from': bob}) chain.sleep(20000) prevAliceCrvBalance = crv.balanceOf(alice) print('Alice crv balance', prevAliceCrvBalance) # ##################################################################################### print( '=========================================================================' ) print('Case 2. add liquidity (failed tx desired)') eurs_amt = 1 * 10**3 seur_amt = 1 * 10**3 lp_amt = 0 borrow_eurs_amt = 0 borrow_seur_amt = 0 borrow_lp_amt = 0 minLPMint = 0 pid = 9 gid = 0 try: tx = homora.execute( 1, curve_spell, curve_spell.addLiquidity2.encode_input( lp_eurs, # lp_eurs [eurs_amt, seur_amt], # supply tokens lp_amt, # supply LP [borrow_eurs_amt, borrow_seur_amt], # borrow tokens borrow_lp_amt, # borrow LP minLPMint, # min LP mint pid, gid), {'from': alice}) assert False, 'tx should fail' except VirtualMachineError: pass # ##################################################################################### print( '=========================================================================' ) print('Case 3. add liquidity (failed tx desired)') eurs_amt = 1 * 10**3 seur_amt = 1 * 10**3 lp_amt = 0 borrow_eurs_amt = 0 borrow_seur_amt = 0 borrow_lp_amt = 0 minLPMint = 0 pid = 23 gid = 0 try: tx = homora.execute( 1, curve_spell, curve_spell.addLiquidity2.encode_input( lp_eurs, # lp_eurs [eurs_amt, seur_amt], # supply tokens lp_amt, # supply LP [borrow_eurs_amt, borrow_seur_amt], # borrow tokens borrow_lp_amt, # borrow LP minLPMint, # min LP mint pid, gid), {'from': alice}) assert False, 'tx should fail' except VirtualMachineError: pass # ##################################################################################### print( '=========================================================================' ) print('Case 4. remove liquidity (failed tx desired)') lp_take_amt = 2**256 - 1 # max lp_want = 1 * 10**17 eurs_repay = 2**256 - 1 # max seur_repay = 2**256 - 1 # max lp_repay = 0 try: tx = homora.execute( 1, curve_spell, curve_spell.removeLiquidity2.encode_input( lp_eurs, # lp_eurs token lp_take_amt, # LP amount to take out lp_want, # LP amount to withdraw to wallet [eurs_repay, seur_repay], # repay amounts lp_repay, # repay LP amount [0, 0] # min amounts ), {'from': alice}) assert False, 'tx should revert' except VirtualMachineError: pass # ##################################################################################### print( '=========================================================================' ) print('Case 5. remove liquidity') # remove liquidity from the same position prevABal = renbtc.balanceOf(alice) prevBBal = wbtc.balanceOf(alice) prevLPBal = lp.balanceOf(alice) prevLPBal_bank = lp.balanceOf(homora) prevLPBal_gauge = lp.balanceOf(gauge) _, _, _, collSize = homora.getPositionInfo(1) lp_take_amt = 2**256 - 1 # max lp_want = 1 * 10**12 renbtc_repay = 2**256 - 1 # max wbtc_repay = 2**256 - 1 # max lp_repay = 0 tx = homora.execute( 1, curve_spell, curve_spell.removeLiquidity2.encode_input( lp, # LP token lp_take_amt, # LP amount to take out lp_want, # LP amount to withdraw to wallet [renbtc_repay, wbtc_repay], # repay amounts lp_repay, # repay LP amount [0, 0] # min amounts ), {'from': alice}) curABal = renbtc.balanceOf(alice) curBBal = wbtc.balanceOf(alice) curLPBal = lp.balanceOf(alice) curLPBal_bank = lp.balanceOf(homora) curLPBal_gauge = lp.balanceOf(gauge) print('spell lp balance', lp.balanceOf(curve_spell)) print('spell renbtc balance', renbtc.balanceOf(curve_spell)) print('spell wbtc balance', wbtc.balanceOf(curve_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) _, _, _, renbtcDebt, renbtcDebtShare = homora.getBankInfo(renbtc) _, _, _, wbtcDebt, wbtcDebtShare = homora.getBankInfo(wbtc) print('bank renbtc totalDebt', renbtcDebt) print('bank renbtc totalDebt', renbtcDebt) print('bank wbtc totalShare', wbtcDebtShare) print('bank wbtc totalShare', wbtcDebtShare) print('LP want', lp_want) print('bank delta LP amount', curLPBal_bank - prevLPBal_bank) print('LP take amount', lp_take_amt) print('prev gauge LP balance', prevLPBal_gauge) print('cur gauge LP balance', curLPBal_gauge) print('coll size', collSize) # alice assert almostEqual(curLPBal - prevLPBal, lp_want), 'incorrect LP amt' # gauge assert almostEqual(curLPBal_gauge - prevLPBal_gauge, -collSize), 'incorrect gauge LP amt' # spell assert renbtc.balanceOf(curve_spell) == 0, 'non-zero spell renbtc balance' assert wbtc.balanceOf(curve_spell) == 0, 'non-zero spell wbtc balance' assert lp.balanceOf(curve_spell) == 0, 'non-zero spell LP balance' # debt assert wbtcDebt == 0, 'wbtcDebt should be 0' assert renbtcDebt == 0, 'renbtcDebt should be 0' curAliceCrvBalance = crv.balanceOf(alice) print('Alice crv balance', curAliceCrvBalance) receivedCrv = curAliceCrvBalance - prevAliceCrvBalance print('received crv', receivedCrv) # check with staking directly minter = interface.ILiquidityGaugeMinter( interface.ILiquidityGauge(gauge).minter()) print('minter', minter) tx = minter.mint(gauge, {'from': bob}) print('tx status', tx.status) tx = interface.ILiquidityGauge(gauge).withdraw(collSize, {'from': bob}) receivedCrvFromGauge = crv.balanceOf(bob) - prevCrv print('receivedCrvFromGauge', receivedCrvFromGauge) assert almostEqual(receivedCrv, receivedCrvFromGauge) # ##################################################################################### print( '=========================================================================' ) print('Case 6. add & remove all LP') lp_amt = 10 * 10**6 prevLPBal = lp.balanceOf(alice) pid, gid = 9, 0 tx = homora.execute( 0, curve_spell, curve_spell.addLiquidity2.encode_input( lp, # LP [0, 0], # supply tokens lp_amt, # supply LP [0, 0], # borrow tokens 0, # borrow LP 0, # min LP mint pid, gid), {'from': alice}) tx = homora.execute( 2, curve_spell, curve_spell.removeLiquidity2.encode_input( lp, # LP token 2**256 - 1, # LP amount to take out lp_amt, # LP amount to withdraw to wallet [0, 0], # repay amounts 0, # repay LP amount [0, 0] # min amounts ), {'from': alice}) curLPBal = lp.balanceOf(alice) assert prevLPBal == curLPBal, 'incorrect LP Balance' 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') 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^5 USDT + 10^5 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}) ##################################################################################### 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.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 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) 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(position_id) 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( position_id, uniswap_spell, uniswap_spell.removeLiquidity.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] 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) # 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 = 0 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' _, _, 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 = 0 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 + dpi_repay, -(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 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}) # 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 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] bob = accounts[2] dfd = interface.IERC20Ex('0x20c36f062a31865bED8a5B1e512D9a1A20AA333A') dusd = interface.IERC20Ex('0x5BC25f649fc4e26069dDF4cF4010F9f706c23831') weth = interface.IERC20Ex('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2') dai = interface.IERC20Ex('0x6B175474E89094C44Da98b954EedeAC495271d0F') lp = interface.IERC20Ex('0xd8e9690eff99e21a2de25e0b148ffaf47f47c972') # pool is lp for balancer pool = interface.IBalancerPool('0xd8e9690eff99e21a2de25e0b148ffaf47f47c972') lp_dai = interface.IERC20Ex('0x8b6e6e7b5b3801fed2cafd4b22b8a16c2f2db21a') pool_dai = interface.IBalancerPool('0x8b6e6e7b5b3801fed2cafd4b22b8a16c2f2db21a') crdfd = MockCErc20.deploy(dfd, {'from': admin}) crdusd = MockCErc20.deploy(dusd, {'from': admin}) crdai = MockCErc20.deploy(dai, {'from': admin}) crweth = MockCErc20.deploy(weth, {'from': admin}) werc20 = WERC20.deploy({'from': admin}) staking = accounts.at('0xf068236ecad5fabb9883bbb26a6445d6c7c9a924', force=True) wstaking = WStakingRewards.deploy(staking, lp, dfd, {'from': admin}) simple_oracle = SimpleOracle.deploy({'from': admin}) simple_oracle.setETHPx([dfd, dusd], [2**112 // 2 // 700, 2**112 * 2 // 700]) balancer_oracle = BalancerPairOracle.deploy(simple_oracle, {'from': alice}) core_oracle = CoreOracle.deploy({'from': admin}) oracle = ProxyOracle.deploy(core_oracle, {'from': admin}) oracle.setWhitelistERC1155([werc20, wstaking], True, {'from': admin}) core_oracle.setRoute( [dfd, dusd, lp], [simple_oracle, simple_oracle, balancer_oracle], {'from': admin}, ) oracle.setOracles( [dfd, dusd, 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(dfd, crdfd, {'from': admin}) homora.addBank(dusd, crdusd, {'from': admin}) # setup initial funds to alice mint_tokens(dfd, alice) mint_tokens(dusd, alice) mint_tokens(weth, alice) mint_tokens(dai, alice) mint_tokens(dfd, crdfd) # check alice's funds print(f'Alice dusd balance {dusd.balanceOf(alice)}') print(f'Alice dfd balance {dfd.balanceOf(alice)}') # Steal some LP from the staking pool mint_tokens(lp, alice) mint_tokens(lp, bob) # set approval dfd.approve(homora, 2**256-1, {'from': alice}) dfd.approve(crdfd, 2**256-1, {'from': alice}) dusd.approve(homora, 2**256-1, {'from': alice}) dusd.approve(crdusd, 2**256-1, {'from': alice}) dai.approve(homora, 2**256-1, {'from': alice}) dai.approve(crdai, 2**256-1, {'from': alice}) weth.approve(homora, 2**256-1, {'from': alice}) weth.approve(crweth, 2**256-1, {'from': alice}) lp.approve(homora, 2**256-1, {'from': alice}) lp.approve(staking, 2**256-1, {'from': bob}) balancer_spell = BalancerSpellV1.deploy( homora, werc20, '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', {'from': admin}) # first time call to reduce gas balancer_spell.getPair(lp, {'from': admin}) ##################################################################################### print('=========================================================================') print('Case 1.') prevABal = dfd.balanceOf(alice) prevBBal = dusd.balanceOf(alice) prevLPBal = lp.balanceOf(alice) prevLPBal_bank = lp.balanceOf(homora) prevLPBal_staking = lp.balanceOf(staking) prevARes = interface.IBalancerPool(lp).getBalance(dfd) prevBRes = interface.IBalancerPool(lp).getBalance(dusd) dfd_amt = 100 * 10**18 dusd_amt = 10 ** 18 lp_amt = 0 borrow_dfd_amt = 10**18 borrow_dusd_amt = 0 # calculate slippage control total_dfd_amt = dfd_amt + borrow_dfd_amt total_dusd_amt = dusd_amt + borrow_dusd_amt dfd_weight = 0.58 dusd_weight = 0.42 ratio = (((prevARes + total_dfd_amt) / prevARes) ** dfd_weight) * \ (((prevBRes + total_dusd_amt) / prevBRes) ** dusd_weight) - 1 lp_desired = lp_amt + int(interface.IERC20(lp).totalSupply() * ratio * 0.995) print('lp desired', lp_desired) tx = homora.execute( 0, balancer_spell, balancer_spell.addLiquidityWStakingRewards.encode_input( lp, # lp token [dfd_amt, # supply DFD dusd_amt, # supply DUSD lp_amt, # supply LP borrow_dfd_amt, # borrow DFD borrow_dusd_amt, # borrow DUSD 0, # borrow LP tokens lp_desired], # LP desired wstaking ), {'from': alice} ) curABal = dfd.balanceOf(alice) curBBal = dusd.balanceOf(alice) curLPBal = lp.balanceOf(alice) curLPBal_bank = lp.balanceOf(homora) curLPBal_staking = lp.balanceOf(staking) curARes = interface.IBalancerPool(lp).getBalance(dfd) curBRes = interface.IBalancerPool(lp).getBalance(dusd) print('spell lp balance', lp.balanceOf(balancer_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) _, _, _, dfdDebt, dfdShare = homora.getBankInfo(dfd) print('bank dfd dfdDebt', dfdDebt) print('bank dfd dfdShare', dfdShare) 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 dfd res', prevARes) print('cur dfd res', curARes) print('prev dusd res', prevBRes) print('cur dusd res', curBRes) # alice assert almostEqual(curABal - prevABal, -dfd_amt), 'incorrect DFD amt' assert almostEqual(curBBal - prevBBal, -dusd_amt), 'incorrect DUSD amt' assert curLPBal - prevLPBal == -lp_amt, 'incorrect LP amt' # spell assert dfd.balanceOf(balancer_spell) == 0, 'non-zero spell DFD balance' assert dusd.balanceOf(balancer_spell) == 0, 'non-zero spell DUSD balance' assert lp.balanceOf(balancer_spell) == 0, 'non-zero spell LP balance' assert dfdDebt == borrow_dfd_amt # check balance and pool reserves assert almostEqual(curABal - prevABal - borrow_dfd_amt, - (curARes - prevARes)), 'not all DFD tokens go to LP pool' assert almostEqual(curBBal - prevBBal - borrow_dusd_amt, - (curBRes - prevBRes)), 'not all DUSD tokens go to LP pool' _, _, collId, collSize = homora.getPositionInfo(1) print('collSize', collSize) # staking directly prevDfd = dfd.balanceOf(bob) print('bob lp balance', interface.IERC20Ex(lp).balanceOf(bob)) tx = interface.IStakingRewards(staking).stake(collSize, {'from': bob}) chain.sleep(20000) prevAliceDfdBalance = dfd.balanceOf(alice) print('Alice dfd balance', prevAliceDfdBalance) ##################################################################################### print('=========================================================================') print('Case 2. add liquidity (failed tx desired)') weth_amt = 100 * 10**18 dai_amt = 10 ** 18 lp_amt = 0 borrow_weth_amt = 0 borrow_dai_amt = 0 # calculate slippage control total_weth_amt = weth_amt + borrow_weth_amt total_dai_amt = dai_amt + borrow_dai_amt dfd_weight = 0.8 dusd_weight = 0.2 ratio = (((prevARes + total_weth_amt) / prevARes) ** dfd_weight) * \ (((prevBRes + total_dai_amt) / prevBRes) ** dusd_weight) - 1 lp_desired = lp_amt + int(interface.IERC20(lp).totalSupply() * ratio * 0.995) lp_desired = 0 print('lp desired', lp_desired) try: tx = homora.execute( 1, balancer_spell, balancer_spell.addLiquidityWStakingRewards.encode_input( lp_dai, # lp token [weth_amt, # supply DFD dai_amt, # supply DUSD lp_amt, # supply LP borrow_weth_amt, # borrow DFD borrow_dai_amt, # borrow DUSD 0, # borrow LP tokens lp_desired], # LP desired wstaking ), {'from': alice} ) assert False, 'tx should fail' except VirtualMachineError: pass ##################################################################################### print('=========================================================================') print('Case 3. remove liquidity (failed tx desired)') lp_take_amt = 2**256-1 # max lp_want = 0 weth_repay = 2**256-1 # max dai_repay = 2**256-1 # max real_weth_repay = homora.borrowBalanceStored(1, dfd) _, _, _, real_lp_take_amt = homora.getPositionInfo(1) expected_withdraw_dfd = collSize * prevARes // interface.IBalancerPool(lp).totalSupply() print('expected withdraw DFD', expected_withdraw_dfd) try: tx = homora.execute( 1, balancer_spell, balancer_spell.removeLiquidityWStakingRewards.encode_input( lp_dai, # LP token [lp_take_amt, # take out LP tokens lp_want, # withdraw LP tokens to wallet weth_repay, # repay DFD dai_repay, # repay DUSD 0, # repay LP 0, # min DFD 0], # min DUSD wstaking ), {'from': alice} ) assert False, 'tx should fail' except VirtualMachineError: pass ##################################################################################### print('=========================================================================') print('Case 4. remove liquidity') # remove liquidity from the same position prevABal = dfd.balanceOf(alice) prevBBal = dusd.balanceOf(alice) prevETHBal = alice.balance() prevLPBal = lp.balanceOf(alice) prevLPBal_bank = lp.balanceOf(homora) prevLPBal_staking = lp.balanceOf(staking) prevETHBal = alice.balance() prevCrdfdBal = lp.balanceOf(crdfd) prevARes = interface.IBalancerPool(lp).getBalance(dfd) prevBRes = interface.IBalancerPool(lp).getBalance(dusd) lp_take_amt = 2**256-1 # max lp_want = 0 dfd_repay = 2**256-1 # max dusd_repay = 0 real_dfd_repay = homora.borrowBalanceStored(1, dfd) _, _, _, real_lp_take_amt = homora.getPositionInfo(1) expected_withdraw_dfd = collSize * prevARes // interface.IBalancerPool(lp).totalSupply() print('expected withdraw DFD', expected_withdraw_dfd) tx = homora.execute( 1, balancer_spell, balancer_spell.removeLiquidityWStakingRewards.encode_input( lp, # LP token [lp_take_amt, # take out LP tokens lp_want, # withdraw LP tokens to wallet dfd_repay, # repay DFD dusd_repay, # repay DUSD 0, # repay LP 0, # min DFD 0], # min DUSD wstaking ), {'from': alice} ) curABal = dfd.balanceOf(alice) curBBal = dusd.balanceOf(alice) curETHBal = alice.balance() curLPBal = lp.balanceOf(alice) curLPBal_bank = lp.balanceOf(homora) curLPBal_staking = lp.balanceOf(staking) curETHBal = alice.balance() curCrdfdBal = lp.balanceOf(crdfd) curARes = interface.IBalancerPool(lp).getBalance(dfd) curBRes = interface.IBalancerPool(lp).getBalance(dusd) print('spell lp balance', lp.balanceOf(balancer_spell)) print('spell dfd balance', dfd.balanceOf(balancer_spell)) print('spell dusd balance', dusd.balanceOf(balancer_spell)) print('Alice delta A balance', curABal - prevABal) print('Alice delta B balance', curBBal - prevBBal) print('Alice delta ETH balance', curETHBal - prevETHBal) 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) _, _, _, dfdDebt, dfdShare = homora.getBankInfo(dfd) print('bank dfd totalDebt', dfdDebt) print('bank dfd totalShare', dfdShare) print('LP want', lp_want) print('bank delta LP amount', curLPBal_bank - prevLPBal_bank) print('LP take amount', lp_take_amt) print('prev staking LP balance', prevLPBal_staking) print('cur staking LP balance', curLPBal_staking) print('real dfd repay', real_dfd_repay) print('curCrdfdBal', curCrdfdBal) print('delta crdfd', curCrdfdBal - prevCrdfdBal) print('A res delta', prevARes - curARes) print('B res delta', prevBRes - curBRes) # alice assert almostEqual(curLPBal - prevLPBal, lp_want), 'incorrect LP amt' # staking assert almostEqual(curLPBal_staking - prevLPBal_staking, - real_lp_take_amt), 'incorrect staking LP amt' # spell assert dfd.balanceOf(balancer_spell) == 0, 'non-zero spell DFD balance' assert dusd.balanceOf(balancer_spell) == 0, 'non-zero spell DUSD balance' assert lp.balanceOf(balancer_spell) == 0, 'non-zero spell LP balance' # check balance and pool reserves assert almostEqual(curABal - prevABal + real_dfd_repay, - (curARes - prevARes)), 'inconsistent DFD from withdraw' assert almostEqual(curBBal - prevBBal + dusd_repay, -(curBRes - prevBRes) ), 'inconsistent DUSD from withdraw' curAliceDfdBalance = dfd.balanceOf(alice) print('Alice dfd balance', curAliceDfdBalance) receivedDfd = curAliceDfdBalance - prevAliceDfdBalance + real_dfd_repay - (prevARes - curARes) print('received dfd', receivedDfd) # check with staking directly tx = interface.IStakingRewards(staking).getReward({'from': bob}) receivedDfdFromStaking = dfd.balanceOf(bob) - prevDfd print('receivedDfdFromStaking', receivedDfdFromStaking) assert almostEqual(receivedDfd, receivedDfdFromStaking) return tx
def main(): admin = accounts[0] alice = accounts[1] bob = accounts[2] dai = interface.IERC20Ex('0x6B175474E89094C44Da98b954EedeAC495271d0F') usdc = interface.IERC20Ex('0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48') usdt = interface.IERC20Ex('0xdAC17F958D2ee523a2206206994597C13D831ec7') adai = interface.IERC20Ex('0x028171bCA77440897B824Ca71D1c56caC55b68A3') ausdc = interface.IERC20Ex('0xBcca60bB61934080951369a648Fb03DF4F96263C') ausdt = interface.IERC20Ex('0x3Ed3B47Dd13EC9a98b44e6204A523E766B225811') lp = interface.IERC20Ex('0x6c3f90f043a72fa612cbac8115ee7e52bde6e490') pool = interface.ICurvePool('0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7') lp_aave = interface.IERC20Ex('0xFd2a8fA60Abd58Efe3EeE34dd494cD491dC14900') pool_aave = interface.ICurvePool('0xDeBF20617708857ebe4F679508E7b7863a8A8EeE') registry = interface.ICurveRegistry( '0x7d86446ddb609ed0f5f8684acf30380a356b2b4c') crdai = interface.ICErc20('0x92B767185fB3B04F881e3aC8e5B0662a027A1D9f') crusdc = interface.ICErc20('0x44fbebd2f576670a6c33f6fc0b00aa8c5753b322') crusdt = interface.ICErc20('0x797AAB1ce7c01eB727ab980762bA88e7133d2157') cradai = MockCErc20.deploy(adai, {'from': admin}) crausdc = MockCErc20.deploy(ausdc, {'from': admin}) crausdt = MockCErc20.deploy(ausdt, {'from': admin}) gauge = accounts.at( '0xbFcF63294aD7105dEa65aA58F8AE5BE2D9d0952A', force=True) wgauge = WLiquidityGauge.deploy( registry, '0xD533a949740bb3306d119CC777fa900bA034cd52', {'from': admin}) crv = interface.IERC20Ex(wgauge.crv()) werc20 = WERC20.deploy({'from': admin}) simple_oracle = SimpleOracle.deploy({'from': admin}) simple_oracle.setETHPx([dai, usdt, usdc, adai, ausdc, ausdt], [2**112 // 700 // 10**12, 2**112 // 700, 2**112 // 700, 2**112 // 700, 2**112 // 700, 2**112 // 700]) curve_oracle = CurveOracle.deploy(simple_oracle, registry, {'from': admin}) curve_oracle.registerPool(lp) # update pool info curve_oracle.registerPool(lp_aave) # update pool info core_oracle = CoreOracle.deploy({'from': admin}) oracle = ProxyOracle.deploy(core_oracle, {'from': admin}) oracle.setWhitelistERC1155([werc20, wgauge], True, {'from': admin}) core_oracle.setRoute( [dai, usdc, usdt, lp, adai, ausdc, ausdt, lp_aave], [simple_oracle, simple_oracle, simple_oracle, curve_oracle, simple_oracle, simple_oracle, simple_oracle, curve_oracle], {'from': admin}, ) oracle.setOracles( [dai, usdc, usdt, lp, adai, ausdc, ausdt, lp_aave], [ [10000, 10000, 10000], [10000, 10000, 10000], [10000, 10000, 10000], [10000, 10000, 10000], [10000, 10000, 10000], [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(dai, crdai, {'from': admin}) homora.addBank(usdc, crusdc, {'from': admin}) homora.addBank(usdt, crusdt, {'from': admin}) # setup initial funds to alice mint_tokens(dai, alice) mint_tokens(usdc, alice) mint_tokens(usdt, alice) # check alice's funds print(f'Alice dai balance {dai.balanceOf(alice)}') print(f'Alice usdc balance {usdc.balanceOf(alice)}') print(f'Alice usdt balance {usdt.balanceOf(alice)}') # steal some LP from the staking pool mint_tokens(lp, alice) mint_tokens(lp, bob) # set approval dai.approve(homora, 2**256-1, {'from': alice}) dai.approve(crdai, 2**256-1, {'from': alice}) usdc.approve(homora, 2**256-1, {'from': alice}) usdc.approve(crusdc, 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(gauge, 2**256-1, {'from': bob}) curve_spell = CurveSpellV1.deploy( homora, werc20, '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', wgauge, {'from': admin}) # register gauge wgauge.registerGauge(0, 0) # set up pools curve_spell.getPool(lp) # first time call to reduce gas curve_spell.ensureApproveN(lp, 3, {'from': admin}) # whitelist spell in bank homora.setWhitelistSpells([curve_spell], [True], {'from': admin}) # whitelist token in bank homora.setWhitelistTokens([dai, usdt, usdc], [True, True, True], {'from': admin}) # whitelist lp in spell curve_spell.setWhitelistLPTokens([lp], [True], {'from': admin}) ##################################################################################### print('=========================================================================') print('Case 1.') prevABal = dai.balanceOf(alice) prevBBal = usdc.balanceOf(alice) prevCBal = usdt.balanceOf(alice) prevLPBal = lp.balanceOf(alice) prevLPBal_bank = lp.balanceOf(homora) prevLPBal_gauge = lp.balanceOf(gauge) dai_amt = 20000 * 10**18 # 20000 DAI usdc_amt = 50000 * 10**6 # 50000 USDC usdt_amt = 40000 * 10**6 # 40000 USDT lp_amt = 0 # 1 * 10**18 borrow_dai_amt = 2000 * 10**18 # 2000 DAI borrow_usdc_amt = 200 * 10**6 # 200 USDC borrow_usdt_amt = 1000 * 10**6 # 1000 USDT borrow_lp_amt = 0 minLPMint = 0 pid = 0 gid = 0 tx = homora.execute( 0, curve_spell, curve_spell.addLiquidity3.encode_input( lp, # LP [dai_amt, usdc_amt, usdt_amt], # supply tokens lp_amt, # supply LP [borrow_dai_amt, borrow_usdc_amt, borrow_usdt_amt], # borrow tokens borrow_lp_amt, # borrow LP minLPMint, # min LP mint pid, gid ), {'from': alice} ) curABal = dai.balanceOf(alice) curBBal = usdc.balanceOf(alice) curCBal = usdt.balanceOf(alice) curLPBal = lp.balanceOf(alice) curLPBal_bank = lp.balanceOf(homora) curLPBal_gauge = lp.balanceOf(gauge) print('spell lp balance', lp.balanceOf(curve_spell)) print('Alice delta A balance', curABal - prevABal) print('Alice delta B balance', curBBal - prevBBal) print('Alice delta C balance', curCBal - prevCBal) print('add liquidity gas', tx.gas_used) print('bank lp balance', curLPBal_bank) _, _, _, daiDebt, daiDebtShare = homora.getBankInfo(dai) _, _, _, usdcDebt, usdcDebtShare = homora.getBankInfo(usdc) _, _, _, usdtDebt, usdtDebtShare = homora.getBankInfo(usdt) _, _, _, lpDebt, usdcDebtShare = homora.getBankInfo(usdc) print('bank dai totalDebt', daiDebt) print('bank dai totalShare', daiDebtShare) 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('gauge prev LP balance', prevLPBal_gauge) print('gauge cur LP balance', curLPBal_gauge) # alice assert almostEqual(curABal - prevABal, -dai_amt), 'incorrect DAI amt' assert almostEqual(curBBal - prevBBal, -usdc_amt), 'incorrect USDC amt' assert almostEqual(curCBal - prevCBal, -usdt_amt), 'incorrect USDT amt' assert almostEqual(curLPBal - prevLPBal, -lp_amt), 'incorrect LP amt' # spell assert dai.balanceOf(curve_spell) == 0, 'non-zero spell DAI balance' assert usdc.balanceOf(curve_spell) == 0, 'non-zero spell USDC balance' assert usdt.balanceOf(curve_spell) == 0, 'non-zero spell USDT balance' assert lp.balanceOf(curve_spell) == 0, 'non-zero spell LP balance' # debt assert daiDebt == borrow_dai_amt assert usdcDebt == borrow_usdc_amt assert usdtDebt == borrow_usdt_amt # ##################################################################################### print('=========================================================================') print('Case 2. harvest first time') prevCRVBalance = crv.balanceOf(alice) print('Alice CRV balance before harvest', prevCRVBalance) _, _, collId, collSize = homora.getPositionInfo(1) print('collSize', collSize) # staking directly prevCrv = crv.balanceOf(bob) print('bob lp balance', interface.IERC20Ex(lp).balanceOf(bob)) pid, gid = 0, 0 gauge, _ = wgauge.gauges(pid, gid) tx = interface.ILiquidityGauge(gauge).deposit(collSize, {'from': bob}) chain.sleep(20000) tx = homora.execute( 1, curve_spell, curve_spell.harvest.encode_input(), {'from': alice} ) print('tx gas used', tx.gas_used) curCRVBalance = crv.balanceOf(alice) print('Alice CRV balance after harvest', curCRVBalance) receivedCrv = curCRVBalance - prevCRVBalance # check with staking directly minter = interface.ILiquidityGaugeMinter(interface.ILiquidityGauge(gauge).minter()) print('minter', minter) tx = minter.mint(gauge, {'from': bob}) print('tx status', tx.status) tx = interface.ILiquidityGauge(gauge).withdraw(collSize, {'from': bob}) receivedCrvFromGauge = crv.balanceOf(bob) - prevCrv print('receivedCrvFromGauge', receivedCrvFromGauge) assert almostEqual(receivedCrv, receivedCrvFromGauge) # ##################################################################################### print('=========================================================================') print('Case 3. harvest second time') prevCRVBalance = crv.balanceOf(alice) print('Alice CRV balance before harvest', prevCRVBalance) _, _, collId, collSize = homora.getPositionInfo(1) print('collSize', collSize) # staking directly prevCrv = crv.balanceOf(bob) print('bob lp balance', interface.IERC20Ex(lp).balanceOf(bob)) pid, gid = 0, 0 gauge, _ = wgauge.gauges(pid, gid) tx = interface.ILiquidityGauge(gauge).deposit(collSize, {'from': bob}) chain.sleep(20000) tx = homora.execute( 1, curve_spell, curve_spell.harvest.encode_input(), {'from': alice} ) print('tx gas used', tx.gas_used) curCRVBalance = crv.balanceOf(alice) print('Alice CRV balance after harvest', curCRVBalance) receivedCrv = curCRVBalance - prevCRVBalance # check with staking directly minter = interface.ILiquidityGaugeMinter(interface.ILiquidityGauge(gauge).minter()) print('minter', minter) tx = minter.mint(gauge, {'from': bob}) print('tx status', tx.status) tx = interface.ILiquidityGauge(gauge).withdraw(collSize, {'from': bob}) receivedCrvFromGauge = crv.balanceOf(bob) - prevCrv print('receivedCrvFromGauge', receivedCrvFromGauge) assert almostEqual(receivedCrv, receivedCrvFromGauge) return tx
def main(): admin = accounts[0] alice = accounts[1] usdt = interface.IERC20Ex('0xdAC17F958D2ee523a2206206994597C13D831ec7') weth = interface.IERC20Ex('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2') lp = interface.IERC20Ex('0x06da0fd433C1A5d7a4faa01111c044910A184553') crusdt = interface.ICErc20('0x797AAB1ce7c01eB727ab980762bA88e7133d2157') 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) # Steal some LP from the staking pool mint_tokens(lp, alice) # check alice's funds print(f'Alice usdt balance {usdt.balanceOf(alice)}') print(f'Alice weth balance {weth.balanceOf(alice)}') print(f'Alice weth balance {lp.balanceOf(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}) 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 token in bank homora.setWhitelistTokens([usdt], [True], {'from': admin}) # whitelist lp in spell sushiswap_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**13 borrow_usdt_amt = 10 * 10**6 borrow_weth_amt = 0 tx = homora.execute( 0, sushiswap_spell, sushiswap_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(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('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(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( '=========================================================================' ) 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 = collSize lp_want = 1 * 10**12 usdt_repay = 2**256 - 1 # max weth_repay = 0 real_usdt_repay = homora.borrowBalanceStored(1, usdt) tx = homora.execute( 1, sushiswap_spell, sushiswap_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(sushiswap_spell)) print('spell usdt balance', usdt.balanceOf(sushiswap_spell)) print('spell weth balance', weth.balanceOf(sushiswap_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(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 + 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' ##################################################################################### print( '=========================================================================' ) print('Case 3. add & remove all LP') lp_amt = 10 * 10**18 prevLPBal = lp.balanceOf(alice) tx = homora.execute( 0, sushiswap_spell, sushiswap_spell.addLiquidityWERC20.encode_input( usdt, # token 0 weth, # token 1 [ 0, # supply USDT 0, # supply WETH lp_amt, # supply LP 0, # borrow USDT 0, # borrow WETH 0, # borrow LP tokens 0, # min USDT 0 ], # min WETH ), {'from': alice}) tx = homora.execute( 2, sushiswap_spell, sushiswap_spell.removeLiquidityWERC20.encode_input( usdt, # token 0 weth, # token 1 [ 2**256 - 1, # take out LP tokens lp_amt, # withdraw LP tokens to wallet 0, # repay USDT 0, # repay WETH 0, # repay LP 0, # min USDT 0 ], # min WETH ), {'from': alice}) curLPBal = lp.balanceOf(alice) assert prevLPBal == curLPBal, 'incorrect LP Balance' return tx
def test_operation(pm, chain): dai_liquidity = accounts.at("0xbebc44782c7db0a1a60cb6fe97d0b483032ff1c7", force=True) # using curve pool (lots of dai) crv3_liquidity = accounts.at("0x6c3F90f043a72FA612cbac8115EE7e52BDe6E490", force=True) # yearn treasury (lots of crv3) altCRV_liquidity = accounts.at( "0xe6e6e25efda5f69687aa9914f8d750c523a1d261", force=True) # giant amount rewards = accounts[2] gov = accounts[3] guardian = accounts[4] bob = accounts[5] alice = accounts[6] strategist = accounts[7] tinytim = accounts[8] dai = Contract("0x6b175474e89094c44da98b954eedeac495271d0f", owner=gov) # DAI token dai.approve(dai_liquidity, Wei("1000000 ether"), {"from": dai_liquidity}) dai.transferFrom(dai_liquidity, gov, Wei("300000 ether"), {"from": dai_liquidity}) crv3 = Contract("0x6c3F90f043a72FA612cbac8115EE7e52BDe6E490", owner=gov) # crv3 token address (threePool) altCRV = Contract("0x1AEf73d49Dedc4b1778d0706583995958Dc862e6", owner=gov) # altCRV token (mUSDCrv) crv3.approve(crv3_liquidity, Wei("1000000 ether"), {"from": crv3_liquidity}) crv3.transferFrom(crv3_liquidity, gov, Wei("100 ether"), {"from": crv3_liquidity}) altCRV.approve(altCRV_liquidity, Wei("1000000 ether"), {"from": altCRV_liquidity}) altCRV.transferFrom(altCRV_liquidity, gov, Wei("1000 ether"), {"from": altCRV_liquidity}) # config dai vault. Vault = pm(config["dependencies"][0]).Vault yDAI = Vault.deploy({"from": gov}) yDAI.initialize(dai, gov, rewards, "", "", {"from": gov}) yDAI.setDepositLimit(Wei("1000000 ether")) threePool = Contract("0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7", owner=gov) # crv3 pool address (threePool) altCrvPool = Contract("0x8474DdbE98F5aA3179B3B3F5942D724aFcdec9f6", owner=gov) # atlCrvPool pool address (musdCrv) targetVault = Contract("0x0FCDAeDFb8A7DfDa2e9838564c5A1665d856AFDF", owner=gov) # target vault (musdCrv) targetVaultStrat = Contract("0xBA0c07BBE9C22a1ee33FE988Ea3763f21D0909a0", owner=gov) # targetVault strat (threePool) targetVaultStratOwner = Contract( "0xFEB4acf3df3cDEA7399794D0869ef76A6EfAff52", owner=gov) # targetVault stratOwner (threePool) strategy = guardian.deploy(StrategyDAImUSDv2, yDAI, dai, threePool, targetVault, crv3, altCRV, altCrvPool) strategy.setStrategist(strategist) yDAI.addStrategy(strategy, 10_000, 0, 0, {"from": gov}) dai.approve(gov, Wei("1000000 ether"), {"from": gov}) dai.transferFrom(gov, bob, Wei("1000 ether"), {"from": gov}) dai.transferFrom(gov, alice, Wei("4000 ether"), {"from": gov}) dai.transferFrom(gov, tinytim, Wei("10 ether"), {"from": gov}) dai.approve(yDAI, Wei("1000000 ether"), {"from": bob}) dai.approve(yDAI, Wei("1000000 ether"), {"from": alice}) dai.approve(yDAI, Wei("1000000 ether"), {"from": tinytim}) crv3.approve(gov, Wei("1000000 ether"), {"from": gov}) yDAI.approve(gov, Wei("1000000 ether"), {"from": gov}) targetVault.approve(gov, Wei("1000000 ether"), {"from": gov}) altCRV.approve(gov, Wei("1000000 ether"), {"from": gov}) dai.approve(threePool, Wei("1000000 ether"), {"from": gov}) crv3.approve(altCrvPool, Wei("1000000 ether"), {"from": gov}) targetVaultStrat.setStrategistReward(0, {"from": targetVaultStratOwner}) targetVaultStrat.setTreasuryFee(0, {"from": targetVaultStratOwner}) targetVaultStrat.setWithdrawalFee(0, {"from": targetVaultStratOwner}) # users deposit to vault yDAI.deposit(Wei("1000 ether"), {"from": bob}) yDAI.deposit(Wei("4000 ether"), {"from": alice}) yDAI.deposit(Wei("10 ether"), {"from": tinytim}) a = yDAI.pricePerShare() chain.mine(1) strategy.harvest({"from": gov}) assert targetVault.balanceOf(strategy) > 0 chain.sleep(3600 * 24 * 7 * 10) chain.mine(1) a = yDAI.pricePerShare() # small profit t = targetVault.getPricePerFullShare() c = strategy.estimatedTotalAssets() targetVaultStrat.harvest({"from": targetVaultStratOwner}) s = targetVault.getPricePerFullShare() d = strategy.estimatedTotalAssets() assert t < s assert d > c assert yDAI.strategies(strategy).dict()['totalDebt'] < d strategy.harvest({"from": gov}) chain.mine(1) b = yDAI.pricePerShare() assert b > a #withdrawals have a slippage protection parameter, defaults to 1 = 0.01%. #overwriting here to be 1.5%, to account for slippage from multiple hops. #slippage also counts "beneficial" slippage, such as DAI being overweight in these pools #d = yUSDT3.balanceOf(alice) c = yDAI.balanceOf(alice) yDAI.withdraw(c, alice, 150, {"from": alice}) assert dai.balanceOf(alice) > 0 assert dai.balanceOf(strategy) == 0 assert dai.balanceOf(bob) == 0 assert targetVault.balanceOf(strategy) > 0 d = yDAI.balanceOf(bob) yDAI.withdraw(d, bob, 150, {"from": bob}) assert dai.balanceOf(bob) > 0 assert dai.balanceOf(strategy) == 0 e = yDAI.balanceOf(tinytim) yDAI.withdraw(e, tinytim, 150, {"from": tinytim}) assert dai.balanceOf(tinytim) > 0 assert dai.balanceOf(strategy) == 0 # We should have made profit assert yDAI.pricePerShare() > 1 #print("\ntinytim", dai.balanceOf(tinytim)/1e18) #print("\nbob", dai.balanceOf(bob)/1e18) #print("\nalice", dai.balanceOf(alice)/1e18) #print("\nvault", targetVault.balanceOf(strategy)/1e18) pass
def main(): deployer = accounts.at('0xB593d82d53e2c187dc49673709a6E9f806cdC835', force=True) # deployer = accounts.load('gh') werc20 = WERC20.at('0xe28D9dF7718b0b5Ba69E01073fE82254a9eD2F98') wmas = WMasterChef.at('0x373ae78a14577682591E088F2E78EF1417612c68') wliq = WLiquidityGauge.at('0xfdB4f97953150e47C8606758C13e70b5a789a7ec') wsindex = WStakingRewards.at('0x713df2DDDA9C7d7bDa98A9f8fCd82c06c50fbd90') wsperp = WStakingRewards.at('0xC4635854480ffF80F742645da0310e9e59795c63') uni_kp3r_oracle = ERC20KP3ROracle.at( '0x8E2A3777AB22e1c5f6d1fF2BcC6C4aA6aB1DeA14') sushi_kp3r_oracle = ERC20KP3ROracle.at( '0xC331687FD71bb1D7f2e237091F8888dDcaD50C9a') core_oracle = CoreOracle.at('0x1E5BDdd0cDF8839d6b27b34927869eF0AD7bf692') uni_oracle = UniswapV2Oracle.at( '0x910aD02D355c2966e8dD8E32C890cD50DB29C3B9') bal_oracle = BalancerPairOracle.at( '0x8F93B0AA2643bf74ab38d6a5910fA82D2da02134') crv_oracle = CurveOracle.at('0x04DE0E42B3b0483248deafE86C4F5428613b76Ff') proxy_oracle = ProxyOracle.at('0x43c425fB2b00a991A51b18c217D749E393bF1AB2') # pair token with oracle from .tokens import Tokens # re-set oracles oracle_params = [ # base tokens [Tokens.weth, [12616, 7927, 10250]], [Tokens.dai, [10525, 9502, 10250]], [Tokens.usdc, [10525, 9502, 10250]], [Tokens.usdt, [10525, 9502, 10250]], [Tokens.dpi, [14886, 6718, 10250]], [Tokens.yfi, [13681, 7309, 10250]], [Tokens.perp, [14886, 6718, 10250]], [Tokens.snx, [13681, 7309, 10250]], [Tokens.susd, [11660, 8576, 10250]], [Tokens.uni, [14886, 6718, 10250]], [Tokens.sushi, [14886, 6718, 10250]], # lp tokens [Tokens.uni_eth_dpi, [14886, 6718, 10250]], [Tokens.uni_eth_yfi, [13681, 7309, 10250]], [Tokens.uni_eth_snx, [13681, 7309, 10250]], [Tokens.uni_eth_susd, [12616, 7927, 10250]], [Tokens.uni_eth_uni, [14886, 6718, 10250]], [Tokens.sushi_eth_dpi, [14886, 6718, 10250]], [Tokens.sushi_eth_yfi, [13681, 7309, 10250]], [Tokens.sushi_eth_snx, [13681, 7309, 10250]], [Tokens.sushi_eth_susd, [12616, 7927, 10250]], [Tokens.sushi_eth_sushi, [14886, 6718, 10250]], [Tokens.bal_perp_usdc, [14886, 6718, 10250]], [Tokens.crv_3pool, [10525, 9502, 10250]], [Tokens.crv_susd, [11660, 8576, 10250]], ] token_list_2, param_list = zip(*oracle_params) proxy_oracle.setOracles(token_list_2, param_list, {'from': deployer}) print('DONE')
def atomic_enter(): """Use a flash loan to deposit into leveraged cyy3crv position.""" # TODO: we need an account with private keys account = accounts.at(os.environ["LEVERAGE_ACCOUNT"]) print(f"Hello, {account}") min_3crv_to_claim = os.environ.get("MIN_3CRV_TO_CLAIM", 50) # deploy our contracts if necessary argobytes_factory = get_or_create(account, ArgobytesFactory) argobytes_flash_borrower = get_or_create(account, ArgobytesFlashBorrower) enter_cyy3crv_action = get_or_create(account, EnterCYY3CRVAction) # get the clone for the account argobytes_clone = get_or_clone(account, argobytes_factory, argobytes_flash_borrower) print(f"clone: {argobytes_clone}") assert account == argobytes_clone.owner(), "Wrong owner detected!" print("Preparing contracts...") # TODO: use multicall to get all the addresses? dai = lazy_contract(enter_cyy3crv_action.DAI()) usdc = lazy_contract(enter_cyy3crv_action.USDC()) usdt = lazy_contract(enter_cyy3crv_action.USDT()) threecrv = lazy_contract(enter_cyy3crv_action.THREE_CRV()) threecrv_pool = lazy_contract(enter_cyy3crv_action.THREE_CRV_POOL()) y3crv = lazy_contract(enter_cyy3crv_action.Y_THREE_CRV()) cyy3crv = lazy_contract(enter_cyy3crv_action.CY_Y_THREE_CRV()) fee_distribution = lazy_contract( enter_cyy3crv_action.THREE_CRV_FEE_DISTRIBUTION()) lender = DyDxFlashLender # use multiple workers to fetch the contracts # there will still be some to fetch, but this speeds things up some # this can take some time since solc/vyper may have to download # TODO: i think doing this in parallel might be confusiing things # poke_contracts([dai, usdc, usdt, threecrv, threecrv_pool, y3crv, cyy3crv, lender]) tokens = [dai, usdc, usdt, threecrv, y3crv, cyy3crv] balances = get_balances(account, tokens) print(f"{account} balances") print_token_balances(balances) claimable_3crv = get_claimable_3crv(account, fee_distribution, min_3crv_to_claim) # TODO: calculate/prompt for these min_3crv_mint_amount = 1 tip_3crv = 0 tip_address = _resolve_address( "tip.satoshiandkin.eth" ) # TODO: put this on a subdomain and uses an immutable min_cream_liquidity = 1000 enter_data = EnterData( dai=balances[dai], dai_flash_fee=None, usdc=balances[usdc], usdt=balances[usdt], min_3crv_mint_amount=min_3crv_mint_amount, threecrv=balances[threecrv], tip_3crv=tip_3crv, y3crv=balances[y3crv], min_cream_liquidity=min_cream_liquidity, sender=account, tip_address=tip_address, claim_3crv=claimable_3crv > min_3crv_to_claim, ) # TODO: do this properly. use virtualprice and yearn's price calculation print("warning! summed_balances is not actually priced in USD") summed_balances = (enter_data.dai + enter_data.usdc + enter_data.usdt + enter_data.threecrv + enter_data.y3crv + claimable_3crv) assert summed_balances > 100, "no coins" # TODO: figure out the actual max leverage, then prompt the user for it (though i dont see much reason not to go the full amount here) flash_loan_amount = int(summed_balances * 7.4) print(f"flash_loan_amount: {flash_loan_amount}") assert flash_loan_amount > 0, "no flash loan calculated" enter_data = enter_data._replace( dai_flash_fee=lender.flashFee(dai, flash_loan_amount)) pprint(enter_data) extra_balances = {} if enter_data.claim_3crv: extra_balances[threecrv.address] = claimable_3crv approve(account, balances, extra_balances, argobytes_clone) # flashloan through the clone enter_tx = argobytes_clone.flashBorrow( lender, dai, flash_loan_amount, Action( enter_cyy3crv_action, CallType.DELEGATE, False, "enter", enter_data, ).tuple, ) print(f"enter success! {enter_tx.return_value}") enter_tx.info() num_events = len(enter_tx.events) print(f"num events: {num_events}") enter_return = to_int(enter_tx.return_value) print(f"return value: {enter_return}") assert enter_return > 0, "no cyy3ccrv returned!" print(f"clone ({argobytes_clone.address}) balances") balances = get_balances(argobytes_clone, tokens) print_token_balances(balances) # TODO: why is this not working? we return cyy3crv.balanceOf! # assert balances[cyy3crv] == enter_tx.return_value # TODO: make sure the clone has cyy3crv? print(f"account ({account}) balances") print_token_balances(get_balances(account, tokens))
def testTransactions(self): rewardsEscrow = self.badger.rewardsEscrow multi = GnosisSafe(self.badger.devMultisig) opsMulti = GnosisSafe(self.badger.opsMultisig) # Setup accounts[7].transfer(multi.get_first_owner(), Wei("2 ether")) print( "Supplied ETH", accounts.at(multi.get_first_owner(), force=True).balance(), ) badger = self.badger tree = self.badger.badgerTree before = badger.token.balanceOf(tree) top_up = Wei("100000 ether") top_up_digg = Wei("40 gwei") harvest_badger = Wei("30000 ether") harvest_digg = Wei("40 gwei") # Top up Tree # TODO: Make the amount based on what we'll require for the next week id = multi.addTx( MultisigTxMetadata(description="Top up badger tree with Badger"), { "to": rewardsEscrow.address, "data": rewardsEscrow.transfer.encode_input(badger.token, tree, top_up), }, ) tx = multi.executeTx(id) after = badger.token.balanceOf(tree) assert after == before + top_up before = badger.digg.token.balanceOf(tree) tx = multi.execute( MultisigTxMetadata(description="Top up badger tree with DIGG"), { "to": rewardsEscrow.address, "data": rewardsEscrow.transfer.encode_input(badger.digg.token, tree, top_up_digg), }, ) print(tx.call_trace(), before, after) after = badger.digg.token.balanceOf(tree) assert after == before + top_up_digg # multi.execute( # MultisigTxMetadata(description="Top up rewards manager with Badger"), # { # "to": rewardsEscrow.address, # "data": rewardsEscrow.transfer.encode_input( # badger.token, badger.badgerRewardsManager, harvest_badger # ), # }, # ) multi.execute( MultisigTxMetadata(description="Top up rewards manager with DIGG"), { "to": rewardsEscrow.address, "data": rewardsEscrow.transfer.encode_input( badger.digg.token, badger.badgerRewardsManager, harvest_digg), }, ) # grant_token_locking_permission(self.badger, self.badger.unlockScheduler) geyserDists = [] for key, distribution in self.distributions.items(): if distribution.hasGeyserDistribution() == True: print("has geyser distribution", key) dist = GeyserDistributor() dists = dist.generate( badger, multi, key, distributions=distribution.getGeyserDistributions(), start=self.start, duration=self.duration, end=self.end, ) geyserDists.extend(dists) console.log("after " + key, geyserDists) # Add unlock schedeules inbulk console.log(geyserDists) tx = opsMulti.execute( MultisigTxMetadata(description="Signal unlock schedules"), { "to": badger.unlockScheduler.address, "data": badger.unlockScheduler.signalTokenLocks.encode_input( geyserDists), }, ) print(tx.call_trace()) tokens = [self.badger.token.address, self.badger.digg.token.address] for key in geyser_keys: print(key) geyser = self.badger.getGeyser(key) for token in tokens: print(token) console.log( "{} schedules for {}".format(token, key), geyser.getUnlockSchedulesFor(token), )
def test_operation(pm, chain): wbtc_liquidity = accounts.at("0x93054188d876f558f4a66b2ef1d97d16edf0895b", force=True) # using curve pool (lots of wbtc) sbtc_liquidity = accounts.at("0x13c1542a468319688b89e323fe9a3be3a90ebb27", force=True) # synthetix (lots of sbtc) rewards = accounts[2] gov = accounts[3] guardian = accounts[4] bob = accounts[5] alice = accounts[6] strategist = accounts[7] tinytim = accounts[8] wbtc = Contract("0x2260fac5e5542a773aa44fbcfedf7c193bc2c599", owner=gov) # wbtc token wbtc.approve(wbtc_liquidity, Wei("1000000 ether"), {"from": wbtc_liquidity}) wbtc.transferFrom(wbtc_liquidity, gov, 3000000000, {"from": wbtc_liquidity}) sbtc = Contract("0x075b1bb99792c9E1041bA13afEf80C91a1e70fB3", owner=gov) # sbtcCRV token address (threePool) sbtc.approve(sbtc_liquidity, Wei("1000000 ether"), {"from": sbtc_liquidity}) sbtc.transferFrom(sbtc_liquidity, gov, Wei("100 ether"), {"from": sbtc_liquidity}) # config vault. Vault = pm(config["dependencies"][0]).Vault yUSDT3 = Vault.deploy({"from": gov}) yUSDT3.initialize(wbtc, gov, rewards, "", "") yUSDT3.setDepositLimit(Wei("1000000 ether")) sbtcPool = Contract("0x7fC77b5c7614E1533320Ea6DDc2Eb61fa00A9714", owner=gov) # sbtcCRV pool address (threePool) ysBTC = Contract("0x7Ff566E1d69DEfF32a7b244aE7276b9f90e9D0f6", owner=gov) # sbtc vault (threePool) #crv3Strat = Contract( # "0xC59601F0CC49baa266891b7fc63d2D5FE097A79D", owner=gov #) # crv3 strat (threePool) #crv3StratOwner = Contract( # "0xd0aC37E3524F295D141d3839d5ed5F26A40b589D", owner=gov #) # crv3 stratOwner (threePool) # uni = Contract.from_explorer( # "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D", owner=gov # ) # UNI router v2 strategy = guardian.deploy(StrategyWBTCsBTCv2, yUSDT3, wbtc, sbtcPool, ysBTC, sbtc) strategy.setStrategist(strategist) yUSDT3.addStrategy(strategy, 10_000, 0, 0, {"from": gov}) wbtc.approve(gov, Wei("1000000 ether"), {"from": gov}) wbtc.transferFrom(gov, bob, 100000000, {"from": gov}) wbtc.transferFrom(gov, alice, 1000000000, {"from": gov}) wbtc.transferFrom(gov, tinytim, 1000000, {"from": gov}) wbtc.approve(yUSDT3, Wei("1000000 ether"), {"from": bob}) wbtc.approve(yUSDT3, Wei("1000000 ether"), {"from": alice}) wbtc.approve(yUSDT3, Wei("1000000 ether"), {"from": tinytim}) sbtc.approve(gov, Wei("1000000 ether"), {"from": gov}) yUSDT3.approve(gov, Wei("1000000 ether"), {"from": gov}) sbtc.approve(ysBTC, Wei("1000000 ether"), {"from": gov}) wbtc.approve(sbtcPool, Wei("1000000 ether"), {"from": gov}) wbtc.approve(sbtcPool, Wei("1000000 ether"), {"from": gov}) # depositing DAI to generate crv3 tokens. #crv3.approve(crv3_liquidity, Wei("1000000 ether"), {"from": crv3_liquidity}) #threePool.add_liquidity([0, 200000000000, 0], 0, {"from": gov}) #giving Gov some shares to mimic profit #yCRV3.depositAll({"from": gov}) # users deposit to vault yUSDT3.deposit(100000000, {"from": bob}) yUSDT3.deposit(1000000000, {"from": alice}) yUSDT3.deposit(1000000, {"from": tinytim}) chain.mine(1) strategy.harvest({"from": gov}) chain.mine(1) newstrategy = guardian.deploy(StrategyWBTCsBTCv2, yUSDT3, wbtc, sbtcPool, ysBTC, sbtc) newstrategy.setStrategist(strategist) yUSDT3.migrateStrategy(strategy, newstrategy, {"from": gov}) assert ysBTC.balanceOf(strategy) == 0 assert ysBTC.balanceOf(newstrategy) > 0 pass
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}) oracle = ProxyOracle.deploy({'from': admin}) oracle.setOracles( [ '0xdAC17F958D2ee523a2206206994597C13D831ec7', # USDT '0x0d4a11d5EEaaC28EC3F61d100daF4d40471f1852', # USDT-ETH ], [ [erc20_oracle, 10000, 10000, 10000], [lp_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}) # 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 check_vault(vault_proxy_addr, vault_impl_addr, beth_token_addr, bridge_connector_addr, rewards_liquidator_addr, insurance_connector_addr, terra_rewards_distributor_addr, vault_admin, vault_liquidations_admin, rew_liq_max_steth_eth_price_difference_percent, rew_liq_max_eth_usdc_price_difference_percent, rew_liq_max_usdc_ust_price_difference_percent, rew_liq_max_steth_ust_price_difference_percent): # Needed to properly decode LogMessagePublished events of Wormhole bridge wormhole = interface.Wormhole(c.wormhole_addr) vault_proxy = AnchorVaultProxy.at(vault_proxy_addr) vault_impl = AnchorVault.at(vault_impl_addr) vault = Contract.from_abi('AnchorVault', vault_proxy.address, AnchorVault.abi) beth_token = bEth.at(beth_token_addr) ust_token = interface.WormholeWrappedToken(c.ust_token_addr) steth_token = interface.Lido(c.steth_token_addr) bridge_connector = BridgeConnectorWormhole.at(bridge_connector_addr) rewards_liquidator = RewardsLiquidator.at(rewards_liquidator_addr) insurance_connector = InsuranceConnector.at(insurance_connector_addr) terra_rewards_distributor_wh_encoded_addr = wh.encode_addr( terra_rewards_distributor_addr) log.ok('vault admin', vault_admin) print() log.ok('stETH', steth_token.address) log.ok('UST', ust_token.address) print() log.ok('bETH', beth_token.address) assert_equals(' admin', beth_token.admin(), vault_admin) assert_equals(' minter', beth_token.minter(), vault_proxy) # assert_equals(' totalSupply', beth_token.totalSupply(), 0) assert_equals(' name', beth_token.name(), 'bETH') assert_equals(' symbol', beth_token.symbol(), 'bETH') assert_equals(' decimals', beth_token.decimals(), 18) print() log.ok('AnchorVault impl', vault_impl.address) assert_equals(' admin', vault_impl.admin(), ZERO_ADDRESS) assert_equals(' bridge_connector', vault_impl.bridge_connector(), ZERO_ADDRESS) assert_equals(' rewards_liquidator', vault_impl.rewards_liquidator(), ZERO_ADDRESS) assert_equals(' insurance_connector', vault_impl.insurance_connector(), ZERO_ADDRESS) print() no_liquidation_interval = 0 restricted_liquidation_interval = 26 * 60 * 60 log.ok('AnchorVaultProxy', vault_proxy.address) assert_equals(' proxy_getAdmin', vault_proxy.proxy_getAdmin(), vault_admin) assert_equals(' proxy_getIsOssified', vault_proxy.proxy_getIsOssified(), False) assert_equals(' implementation', vault_proxy.implementation(), vault_impl) assert_equals(' admin', vault.admin(), vault_admin) assert_equals(' beth_token', vault.beth_token(), beth_token.address) assert_equals(' steth_token', vault.steth_token(), steth_token.address) assert_equals(' bridge_connector', vault.bridge_connector(), bridge_connector.address) assert_equals(' rewards_liquidator', vault.rewards_liquidator(), rewards_liquidator.address) assert_equals(' insurance_connector', vault.insurance_connector(), insurance_connector.address) assert_equals(' vault_liquidations_admin', vault.liquidations_admin(), vault_liquidations_admin) assert_equals(' no_liquidation_interval', vault.no_liquidation_interval(), no_liquidation_interval) assert_equals(' restricted_liquidation_interval', vault.restricted_liquidation_interval(), restricted_liquidation_interval) assert_equals(' anchor_rewards_distributor', vault.anchor_rewards_distributor(), terra_rewards_distributor_wh_encoded_addr) assert_equals(' get_rate', vault.get_rate(), 10**18) print() log.ok('BridgeConnectorWormhole', bridge_connector.address) assert_equals(' wormhole_token_bridge', bridge_connector.wormhole_token_bridge(), c.wormhole_token_bridge_addr) print() log.ok('RewardsLiquidator', rewards_liquidator.address) assert_equals(' admin', rewards_liquidator.admin(), vault_admin) assert_equals(' vault', rewards_liquidator.vault(), vault_proxy.address) assert_equals( ' max_steth_eth_price_difference_percent', rewards_liquidator.max_steth_eth_price_difference_percent(), int(rew_liq_max_steth_eth_price_difference_percent * 10**18 / 100)) assert_equals( ' max_eth_usdc_price_difference_percent', rewards_liquidator.max_eth_usdc_price_difference_percent(), int(rew_liq_max_eth_usdc_price_difference_percent * 10**18 / 100)) assert_equals( ' max_usdc_ust_price_difference_percent', rewards_liquidator.max_usdc_ust_price_difference_percent(), int(rew_liq_max_usdc_ust_price_difference_percent * 10**18 / 100)) assert_equals( ' max_steth_ust_price_difference_percent', rewards_liquidator.max_steth_ust_price_difference_percent(), int(rew_liq_max_steth_ust_price_difference_percent * 10**18 / 100)) print() log.ok('InsuranceConnector', insurance_connector.address) print() log.ok('liquidations admin', vault_liquidations_admin) log.ok( 'no liquidation interval', f'{no_liquidation_interval} sec ({no_liquidation_interval / 3600} hrs)' ) log.ok( 'restricted liquidation interval', f'{restricted_liquidation_interval} sec ({restricted_liquidation_interval / 3600} hrs)' ) log.ok('terra rewards distributor', terra_rewards_distributor_wh_encoded_addr) print() if c.get_is_live(): print('Running on a live network, cannot run further checks.') print('Run on a mainnet fork to do this.') return log.h('Performing AnchorVault fork checks') with chain_snapshot(): if not vault.can_deposit_or_withdraw(): log.h('Selling rewards...') tx = vault.collect_rewards( {'from': accounts.at(vault_liquidations_admin, force=True)}) # tx.info() assert_equals('AnchorVault.can_deposit_or_withdraw', vault.can_deposit_or_withdraw(), True) beth_supply_before = beth_token.totalSupply() bridge_balance_before = beth_token.balanceOf( c.wormhole_token_bridge_addr) log.ok('bETH total supply', beth_supply_before) log.ok('bridge bETH balance', bridge_balance_before) log.h('Obtaining stETH...') holder_1 = accounts[0] holder_2 = accounts[1] steth_token.submit(ZERO_ADDRESS, { 'from': holder_1, 'value': 3 * 10**18 }) assert steth_token.balanceOf(holder_1) > 0 log.ok('holder_1 balance', steth_token.balanceOf(holder_1)) assert_equals('holder_2 balance', steth_token.balanceOf(holder_2), 0) log.h('Submitting stETH...') terra_recipient_1 = '0x0000000000000000000000008badf00d8badf00d8badf00d8badf00d8badf00d' steth_token.approve(vault, 2 * 10**18, {'from': holder_1}) tx = vault.submit(2 * 10**18, terra_recipient_1, b'', vault.version(), {'from': holder_1}) # tx.info() assert 'Deposited' in tx.events assert tx.events['Deposited'][0].address == vault.address log.ok('Deposited event emitted') deposited_amount = tx.events['Deposited']['amount'] assert deposited_amount >= 1.999 * 10**18 and deposited_amount <= 2 * 10**18 log.ok('Deposited.amount', deposited_amount) assert_equals('holder_1 balance', beth_token.balanceOf(holder_1), 0) beth_supply = beth_token.totalSupply() assert beth_supply == beth_supply_before + deposited_amount assert_equals('bETH total supply', beth_supply, beth_supply_before + deposited_amount) bridge_balance = beth_token.balanceOf(c.wormhole_token_bridge_addr) assert bridge_balance == bridge_balance_before + deposited_amount assert_equals('bridge bETH balance', bridge_balance, bridge_balance_before + deposited_amount) assert 'LogMessagePublished' in tx.events assert tx.events['LogMessagePublished'][0].address == c.wormhole_addr log.ok('LogMessagePublished event emitted') expected_payload = wh.assemble_transfer_payload( token_address=beth_token.address, normalized_amount=wh.normalize_amount(deposited_amount, 18), to_address=terra_recipient_1, token_chain_id=wh.CHAIN_ID_ETHERUM, to_chain_id=wh.CHAIN_ID_TERRA, fee=0) assert tx.events['LogMessagePublished'][0][ 'payload'] == expected_payload log.ok('LogMessagePublished.payload', expected_payload) log.h('Submitting ETH...') bridge_balance_before = bridge_balance beth_supply_before = beth_supply terra_recipient_2 = '0x000000000000000000000000deadbeefdeadbeefdeadbeefdeadbeefdeadbeef' tx = vault.submit(1 * 10**18, terra_recipient_2, b'', vault.version(), { 'from': holder_2, 'value': 1 * 10**18 }) # tx.info() assert 'Deposited' in tx.events assert tx.events['Deposited'][0].address == vault.address log.ok('Deposited event emitted') deposited_amount = tx.events['Deposited']['amount'] assert deposited_amount >= 0.999 * 10**18 and deposited_amount <= 1 * 10**18 log.ok('Deposited.amount', deposited_amount) assert_equals('holder_2 balance', beth_token.balanceOf(holder_2), 0) beth_supply = beth_token.totalSupply() assert beth_supply == beth_supply_before + deposited_amount assert_equals('bETH total supply', beth_supply, beth_supply_before + deposited_amount) bridge_balance = beth_token.balanceOf(c.wormhole_token_bridge_addr) assert bridge_balance == bridge_balance_before + deposited_amount assert_equals('bridge bETH balance', bridge_balance, bridge_balance_before + deposited_amount) assert 'LogMessagePublished' in tx.events assert tx.events['LogMessagePublished'][0].address == c.wormhole_addr log.ok('LogMessagePublished event emitted') expected_payload = wh.assemble_transfer_payload( token_address=beth_token.address, normalized_amount=wh.normalize_amount(deposited_amount, 18), to_address=terra_recipient_2, token_chain_id=wh.CHAIN_ID_ETHERUM, to_chain_id=wh.CHAIN_ID_TERRA, fee=0) assert tx.events['LogMessagePublished'][0][ 'payload'] == expected_payload log.ok('LogMessagePublished.payload', expected_payload) log.h('Rebasing stETH by 0.02%...') lido_oracle_report(steth_rebase_percent=0.02) assert_equals('AnchorVault.can_deposit_or_withdraw', vault.can_deposit_or_withdraw(), False) log.h('Selling rewards...') liquidations_admin = accounts.at(vault.liquidations_admin(), force=True) tx = vault.collect_rewards({'from': liquidations_admin}) # tx.info() assert 'RewardsCollected' in tx.events assert tx.events['RewardsCollected'][0].address == vault.address log.ok('RewardsCollected event emitted') ust_amount = tx.events['RewardsCollected'][0]['ust_amount'] assert ust_amount > 0 log.ok('RewardsCollected.ust_amount', ust_amount) assert 'LogMessagePublished' in tx.events assert tx.events['LogMessagePublished'][0].address == c.wormhole_addr log.ok('LogMessagePublished event emitted') expected_payload = wh.assemble_transfer_payload( # See https://github.com/certusone/wormhole/blob/aff369f/ethereum/contracts/bridge/Bridge.sol#L97-L103 # For wrapped tokens, the "token address" field is set to the address of the token on its native chain token_address=str(ust_token.nativeContract()), normalized_amount=wh.normalize_amount(ust_amount, ust_token.decimals()), to_address=terra_rewards_distributor_addr, token_chain_id=ust_token.chainId(), to_chain_id=wh.CHAIN_ID_TERRA, fee=0) assert tx.events['LogMessagePublished'][0][ 'payload'] == expected_payload log.ok('LogMessagePublished.payload', expected_payload)
def test_loss(pm, chain): # probably not needed rhegic_liquidity = accounts.at( "0x8ac7de95ff8d0ee72e0b54f781ab2e18f27108fb", force=True) # weth needed to test strategy weth_liquidity = accounts.at("0x2f0b23f53734252bda2277357e97e1517d6b042a", force=True) # Maker vault (~2.6mil) rewards = accounts[2] gov = accounts[3] guardian = accounts[4] bob = accounts[5] alice = accounts[6] strategist = accounts[7] rHegic = Contract.from_explorer( "0x47C0aD2aE6c0Ed4bcf7bc5b380D7205E89436e84", owner=gov) rHegic.approve(rhegic_liquidity, Wei("1000000 ether"), {"from": rhegic_liquidity}) rHegic.transferFrom(rhegic_liquidity, gov, Wei("888000 ether"), {"from": rhegic_liquidity}) # vault deals with weth, so addresses need it. weth = Contract.from_explorer("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", owner=gov) # weth token weth.approve(weth_liquidity, Wei("100 ether"), {"from": weth_liquidity}) weth.transferFrom(weth_liquidity, gov, Wei("88 ether"), {"from": weth_liquidity}) # declaring yEthLP as the vault Vault = pm(config["dependencies"][0]).Vault yEthLP = gov.deploy(Vault, weth, gov, rewards, "", "") ethPool = Contract.from_explorer( "0x878F15ffC8b894A1BA7647c7176E4C01f74e140b", owner=gov) # ETH LP pool (writeETH) ethPoolStaking = Contract.from_explorer( "0x9b18975e64763bDA591618cdF02D2f14a9875981", owner=gov) # ETH LP pool staking for rHegic uni = Contract.from_explorer("0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D", owner=gov) # UNI router v2 strategy = guardian.deploy(StrategyEthHegicLP, weth, yEthLP, rHegic, ethPoolStaking, ethPool, uni) strategy.setStrategist(strategist) # adding strategy to the vault yEthLP.addStrategy(strategy, Wei("88 ether"), 0, 50, {"from": gov}) # folks need weth for the contract weth.approve(gov, Wei("100 ether"), {"from": gov}) weth.transferFrom(gov, bob, Wei("10 ether"), {"from": gov}) weth.transferFrom(gov, alice, Wei("78 ether"), {"from": gov}) weth.approve(yEthLP, Wei("100 ether"), {"from": bob}) weth.approve(yEthLP, Wei("100 ether"), {"from": alice}) yEthLP.deposit(Wei("10 ether"), {"from": bob}) yEthLP.deposit(Wei("78 ether"), {"from": alice}) strategy.harvest() rHegic.approve(gov, Wei("1000 ether"), {"from": gov}) # TODO: Instead of sending rhegic to the strategy directly, # we should push the clock forward to grab rhegic from Hegic protocol rHegic.transferFrom(gov, strategy, Wei("100 ether"), {"from": gov}) strategy.harvest({"from": gov}) assert rHegic.balanceOf(strategy) == 0 assert ethPool.balanceOf(strategy) == 0 assert ethPoolStaking.balanceOf(strategy) > 0 # We should have made profit assert yEthLP.pricePerShare() / 1e18 > 1 chain.sleep(3600 * 24 * 15) # 15 days chain.mine(1) # This should work by doing it by hand since exitPosition is not working # strategy.setEmergencyExit({"from": gov}) # strategy.harvest({"from": gov}) # Withdraw funds pool = Contract.from_explorer(strategy.ethPool()) staking = Contract.from_explorer(strategy.ethPoolStaking()) staking.withdraw(staking.balanceOf(strategy), {"from": strategy}) pool.withdraw(pool.shareOf(strategy), pool.balanceOf(strategy), {"from": strategy}) # revoke, steal weth and let's see losses yEthLP.revokeStrategy(strategy, {"from": gov}) weth.transfer(gov, weth.balanceOf(strategy), {"from": strategy}) strategy.harvest({"from": gov}) assert yEthLP.strategies(strategy).dict()["totalLoss"] > 0
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 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 = 0 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' _, _, 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 the second 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**10 borrow_weth_amt = 0 tx = homora.execute( 1, 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' 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 test_hegic_strategy_infura(pm): hegic_liquidity = accounts.at( "0x736f85bf359e3e2db736d395ed8a4277123eeee1", force=True ) # Hegic: Liquidity M&U (lot's of hegic) rewards = accounts[2] gov = accounts[3] guardian = accounts[4] bob = accounts[5] alice = accounts[6] strategist = accounts[7] hegic = Contract.from_explorer( "0x584bC13c7D411c00c01A62e8019472dE68768430", owner=gov ) # Hegic token hegic.approve(hegic_liquidity, Wei("1000000 ether"), {"from": hegic_liquidity}) hegic.transferFrom( hegic_liquidity, gov, Wei("888000 ether"), {"from": hegic_liquidity} ) Vault = pm(config["dependencies"][0]).Vault yHegic = gov.deploy(Vault, hegic, gov, rewards, "", "") hegicStaking = Contract.from_explorer( "0x840a1AE46B7364855206Eb5b7286Ab7E207e515b", owner=gov ) # HEGIC WBTC Staking lot (hlWBTC) uni = Contract.from_explorer( "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D", owner=gov ) # UNI router v2 wbtcLiquidity = accounts.at( "0x9939d72411c6af3c97beff0ac81e3b780e4712ee", force=True ) wbtc = Contract.from_explorer("0x2260fac5e5542a773aa44fbcfedf7c193bc2c599") wbtc.approve(hegicStaking, Wei("100 ether"), {"from": wbtcLiquidity}) strategy = guardian.deploy( StrategyHegicWBTC, yHegic, hegic, hegicStaking, uni, wbtc ) strategy.setStrategist(strategist) yHegic.addStrategy(strategy, Wei("888000 ether"), 0, 50, {"from": gov}) hegic.approve(gov, Wei("1000000 ether"), {"from": gov}) hegic.transferFrom(gov, bob, Wei("100000 ether"), {"from": gov}) hegic.transferFrom(gov, alice, Wei("788000 ether"), {"from": gov}) hegic.approve(yHegic, Wei("1000000 ether"), {"from": bob}) hegic.approve(yHegic, Wei("1000000 ether"), {"from": alice}) yHegic.deposit(Wei("100000 ether"), {"from": bob}) yHegic.deposit(Wei("788000 ether"), {"from": alice}) strategy.harvest() assert hegic.balanceOf(strategy) == 0 assert hegicStaking.balanceOf(strategy) == 1 hegicStaking.sendProfit(1 * 1e8, {"from": wbtcLiquidity}) strategy.harvest({"from": gov}) # We should have made profit assert yHegic.pricePerShare() > 1
def main(): admin = accounts[0] alice = accounts[1] bob = accounts[2] dai = interface.IERC20Ex('0x6B175474E89094C44Da98b954EedeAC495271d0F') usdc = interface.IERC20Ex('0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48') usdt = interface.IERC20Ex('0xdAC17F958D2ee523a2206206994597C13D831ec7') susd = interface.IERC20Ex('0x57ab1ec28d129707052df4df418d58a2d46d5f51') ydai = interface.IERC20Ex('0xC2cB1040220768554cf699b0d863A3cd4324ce32') yusdc = interface.IERC20Ex('0x26EA744E5B887E5205727f55dFBE8685e3b21951') yusdt = interface.IERC20Ex('0xE6354ed5bC4b393a5Aad09f21c46E101e692d447') ybusd = interface.IERC20Ex('0x04bC0Ab673d88aE9dbC9DA2380cB6B79C4BCa9aE') lp = interface.IERC20Ex('0xC25a3A3b969415c80451098fa907EC722572917F') pool = interface.ICurvePool('0xA5407eAE9Ba41422680e2e00537571bcC53efBfD') lp_busd = interface.IERC20Ex('0x3B3Ac5386837Dc563660FB6a0937DFAa5924333B') pool_busd = interface.ICurvePool('0x79a8C46DeA5aDa233ABaFFD40F3A0A2B1e5A4F27') registry = interface.ICurveRegistry('0x7d86446ddb609ed0f5f8684acf30380a356b2b4c') crdai = interface.ICErc20('0x92B767185fB3B04F881e3aC8e5B0662a027A1D9f') crusdc = interface.ICErc20('0x44fbebd2f576670a6c33f6fc0b00aa8c5753b322') crusdt = interface.ICErc20('0x797AAB1ce7c01eB727ab980762bA88e7133d2157') crsusd = MockCErc20.deploy(susd, {'from': admin}) crydai = MockCErc20.deploy(ydai, {'from': admin}) cryusdc = MockCErc20.deploy(yusdc, {'from': admin}) cryusdt = MockCErc20.deploy(yusdt, {'from': admin}) crybusd = MockCErc20.deploy(ybusd, {'from': admin}) gauge = accounts.at( '0xA90996896660DEcC6E997655E065b23788857849', force=True) wgauge = WLiquidityGauge.deploy( registry, '0xD533a949740bb3306d119CC777fa900bA034cd52', {'from': admin}) crv = interface.IERC20Ex(wgauge.crv()) werc20 = WERC20.deploy({'from': admin}) simple_oracle = SimpleOracle.deploy({'from': admin}) simple_oracle.setETHPx([dai, usdt, usdc, susd, ydai, yusdc, yusdt, ybusd], [2**112 // 700, 2**112 * 10**12 // 700, 2**112 * 10**12 // 700, 2**112 // 700, 2**112 // 700, 2**112 * 10**12 // 700, 2**112 * 10**12 // 700, 2**112 // 700]) curve_oracle = CurveOracle.deploy(simple_oracle, registry, {'from': admin}) curve_oracle.registerPool(lp) # update pool info curve_oracle.registerPool(lp_busd) # update pool info core_oracle = CoreOracle.deploy({'from': admin}) oracle = ProxyOracle.deploy(core_oracle, {'from': admin}) oracle.setWhitelistERC1155([werc20, wgauge], True, {'from': admin}) core_oracle.setRoute( [dai, usdc, usdt, susd, lp, ydai, yusdc, yusdt, ybusd, lp_busd, ], [simple_oracle, simple_oracle, simple_oracle, simple_oracle, curve_oracle, simple_oracle, simple_oracle, simple_oracle, simple_oracle, curve_oracle], {'from': admin}, ) oracle.setOracles( [dai, usdc, usdt, susd, lp, ydai, yusdc, yusdt, ybusd, lp_busd], [ [10000, 10000, 10000], [10000, 10000, 10000], [10000, 10000, 10000], [10000, 10000, 10000], [10000, 10000, 10000], [10000, 10000, 10000], [10000, 10000, 10000], [10000, 10000, 10000], [10000, 10000, 10000], [10000, 10000, 10000], ], {'from': admin}, ) # initialize homora = HomoraBank.deploy({'from': admin}) print('donator ether', accounts[5].balance()) homora.initialize(oracle, 1000, {'from': admin}) # 10% fee setup_bank_hack(homora) # add bank homora.addBank(dai, crdai, {'from': admin}) homora.addBank(usdc, crusdc, {'from': admin}) homora.addBank(usdt, crusdt, {'from': admin}) homora.addBank(susd, crsusd, {'from': admin}) homora.addBank(ydai, crydai, {'from': admin}) homora.addBank(yusdc, cryusdc, {'from': admin}) homora.addBank(yusdt, cryusdt, {'from': admin}) homora.addBank(ybusd, crybusd, {'from': admin}) # setup initial funds to alice mint_tokens(dai, alice,) mint_tokens(usdc, alice) mint_tokens(usdt, alice) mint_tokens(susd, alice) mint_tokens(ydai, alice) mint_tokens(yusdc, alice) mint_tokens(yusdt, alice) mint_tokens(ybusd, alice) mint_tokens(susd, crsusd) # check alice's funds print(f'Alice dai balance {dai.balanceOf(alice)}') print(f'Alice usdc balance {usdc.balanceOf(alice)}') print(f'Alice usdt balance {usdt.balanceOf(alice)}') print(f'Alice susd balance {susd.balanceOf(alice)}') print(f'Alice ydai balance {ydai.balanceOf(alice)}') print(f'Alice yusdc balance {yusdc.balanceOf(alice)}') print(f'Alice yusdt balance {yusdt.balanceOf(alice)}') print(f'Alice ybusd balance {ybusd.balanceOf(alice)}') # steal some LP from the staking pool mint_tokens(lp, alice) mint_tokens(lp, bob) mint_tokens(lp_busd, alice) # set approval dai.approve(homora, 2**256-1, {'from': alice}) dai.approve(crdai, 2**256-1, {'from': alice}) usdc.approve(homora, 2**256-1, {'from': alice}) usdc.approve(crusdc, 2**256-1, {'from': alice}) usdt.approve(homora, 2**256-1, {'from': alice}) usdt.approve(crusdt, 2**256-1, {'from': alice}) susd.approve(homora, 2**256-1, {'from': alice}) susd.approve(crsusd, 2**256-1, {'from': alice}) ydai.approve(homora, 2**256-1, {'from': alice}) ydai.approve(crydai, 2**256-1, {'from': alice}) yusdc.approve(homora, 2**256-1, {'from': alice}) yusdc.approve(cryusdc, 2**256-1, {'from': alice}) yusdt.approve(homora, 2**256-1, {'from': alice}) yusdt.approve(cryusdt, 2**256-1, {'from': alice}) ybusd.approve(homora, 2**256-1, {'from': alice}) ybusd.approve(crybusd, 2**256-1, {'from': alice}) lp.approve(homora, 2**256-1, {'from': alice}) lp.approve(gauge, 2**256-1, {'from': bob}) lp_busd.approve(homora, 2**256-1, {'from': alice}) curve_spell = CurveSpellV1.deploy( homora, werc20, '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', wgauge, {'from': admin}) # register gauge wgauge.registerGauge(12, 0) wgauge.registerGauge(1, 0) # set up pools curve_spell.getPool(lp) curve_spell.getPool(lp_busd) # first time call to reduce gas curve_spell.ensureApproveN(lp, 4, {'from': admin}) curve_spell.ensureApproveN(lp_busd, 4, {'from': admin}) # whitelist spell in bank homora.setWhitelistSpells([curve_spell], [True], {'from': admin}) # whitelist token in bank homora.setWhitelistTokens([dai, usdt, usdc, susd], [True, True, True, True], {'from': admin}) # whitelist lp in spell curve_spell.setWhitelistLPTokens([lp, lp_busd], [True, True], {'from': admin}) ##################################################################################### print('=========================================================================') print('Case 1.') prevABal = dai.balanceOf(alice) prevBBal = usdc.balanceOf(alice) prevCBal = usdt.balanceOf(alice) prevDBal = susd.balanceOf(alice) prevLPBal = lp.balanceOf(alice) prevLPBal_bank = lp.balanceOf(homora) prevLPBal_gauge = lp.balanceOf(gauge) dai_amt = 200 * 10**18 usdc_amt = 1000 * 10**6 usdt_amt = 1000 * 10**6 susd_amt = 1000 * 10**18 lp_amt = 0 borrow_dai_amt = 10 * 10**18 borrow_usdc_amt = 10**6 borrow_usdt_amt = 10**6 borrow_susd_amt = 10**18 borrow_lp_amt = 0 minLPMint = 0 pid = 12 gid = 0 tx = homora.execute( 0, curve_spell, curve_spell.addLiquidity4.encode_input( lp, # LP [dai_amt, usdc_amt, usdt_amt, susd_amt], # supply tokens lp_amt, # supply LP [borrow_dai_amt, borrow_usdc_amt, borrow_usdt_amt, borrow_susd_amt], # borrow tokens borrow_lp_amt, # borrow LP minLPMint, # min LP mint pid, gid ), {'from': alice} ) curABal = dai.balanceOf(alice) curBBal = usdc.balanceOf(alice) curCBal = usdt.balanceOf(alice) curDBal = susd.balanceOf(alice) curLPBal = lp.balanceOf(alice) curLPBal_bank = lp.balanceOf(homora) curLPBal_gauge = lp.balanceOf(gauge) print('spell lp balance', lp.balanceOf(curve_spell)) print('Alice delta A balance', curABal - prevABal) print('Alice delta B balance', curBBal - prevBBal) print('Alice delta C balance', curCBal - prevCBal) print('add liquidity gas', tx.gas_used) print('bank lp balance', curLPBal_bank) _, _, _, daiDebt, daiDebtShare = homora.getBankInfo(dai) _, _, _, usdcDebt, usdcDebtShare = homora.getBankInfo(usdc) _, _, _, usdtDebt, usdtDebtShare = homora.getBankInfo(usdt) _, _, _, susdDebt, susdDebtShare = homora.getBankInfo(susd) print('bank dai totalDebt', daiDebt) print('bank dai totalShare', daiDebtShare) print('bank usdt totalDebt', usdtDebt) print('bank usdt totalShare', usdtDebtShare) print('bank usdc totalDebt', usdcDebt) print('bank usdc totalShare', usdcDebtShare) print('bank susd totalDebt', susdDebt) print('bank susd totalShare', susdDebtShare) print('bank prev LP balance', prevLPBal_bank) print('bank cur LP balance', curLPBal_bank) print('gauge prev LP balance', prevLPBal_gauge) print('gauge cur LP balance', curLPBal_gauge) # alice assert almostEqual(curABal - prevABal, -dai_amt), 'incorrect DAI amt' assert almostEqual(curBBal - prevBBal, -usdc_amt), 'incorrect USDC amt' assert almostEqual(curCBal - prevCBal, -usdt_amt), 'incorrect USDT amt' assert almostEqual(curDBal - prevDBal, -susd_amt), 'incorrect SUSD amt' assert almostEqual(curLPBal - prevLPBal, -lp_amt), 'incorrect LP amt' # spell assert dai.balanceOf(curve_spell) == 0, 'non-zero spell DAI balance' assert usdc.balanceOf(curve_spell) == 0, 'non-zero spell USDC balance' assert usdt.balanceOf(curve_spell) == 0, 'non-zero spell USDT balance' assert susd.balanceOf(curve_spell) == 0, 'non-zero spell SUSD balance' assert lp.balanceOf(curve_spell) == 0, 'non-zero spell LP balance' # debt assert daiDebt == borrow_dai_amt assert usdcDebt == borrow_usdc_amt assert usdtDebt == borrow_usdt_amt assert susdDebt == borrow_susd_amt _, _, collId, collSize = homora.getPositionInfo(1) print('collSize', collSize) # staking directly prevCrv = crv.balanceOf(bob) print('bob lp balance', interface.IERC20Ex(lp).balanceOf(bob)) pid, gid = 12, 0 gauge, _ = wgauge.gauges(pid, gid) print('gauge', gauge) tx = interface.ILiquidityGauge(gauge).deposit(collSize, {'from': bob}) chain.sleep(20000) prevAliceCrvBalance = crv.balanceOf(alice) print('Alice crv balance', prevAliceCrvBalance) # ##################################################################################### print('=========================================================================') print('Case 2. add liquidity (failed tx desired)') ydai_amt = 200 * 10**6 yusdc_amt = 500 * 10**6 yusdt_amt = 400 * 10**6 ybusd_amt = 100 * 10**6 lp_amt = 0 borrow_ydai_amt = 0 borrow_yusdc_amt = 0 borrow_yusdt_amt = 0 borrow_ybusd_amt = 0 borrow_lp_amt = 0 minLPMint = 0 pid = 12 gid = 0 try: tx = homora.execute( 1, curve_spell, curve_spell.addLiquidity4.encode_input( lp_busd, # LP_busd [ydai_amt, yusdc_amt, yusdt_amt, ybusd_amt], # supply tokens lp_amt, # supply LP [borrow_ydai_amt, borrow_yusdc_amt, borrow_yusdt_amt, borrow_ybusd_amt], # borrow tokens borrow_lp_amt, # borrow LP minLPMint, # min LP mint pid, gid ), {'from': alice} ) assert False, 'tx should fail' except VirtualMachineError: pass # ##################################################################################### print('=========================================================================') print('Case 3. add liquidity (failed tx desired)') ydai_amt = 0 # 2 * 10**6 yusdc_amt = 0 # 5 * 10**6 yusdt_amt = 0 # 4 * 10**6 ybusd_amt = 1 * 10**6 lp_amt = 0 borrow_ydai_amt = 0 borrow_yusdc_amt = 0 borrow_yusdt_amt = 0 borrow_ybusd_amt = 0 borrow_lp_amt = 0 minLPMint = 0 pid = 1 gid = 0 try: tx = homora.execute( 1, curve_spell, curve_spell.addLiquidity4.encode_input( lp_busd, # LP_busd [ydai_amt, yusdc_amt, yusdt_amt, ybusd_amt], # supply tokens lp_amt, # supply LP [borrow_ydai_amt, borrow_yusdc_amt, borrow_yusdt_amt, borrow_ybusd_amt], # borrow tokens borrow_lp_amt, # borrow LP minLPMint, # min LP mint pid, gid ), {'from': alice} ) assert False, 'tx should fail' except VirtualMachineError: pass # ##################################################################################### print('=========================================================================') print('Case 4. remove liquidity (failed tx desired)') lp_take_amt = 2**256-1 # max lp_want = 1 * 10**17 ydai_repay = 2**256-1 # max yusdc_repay = 2**256-1 # max yusdt_repay = 2**256-1 # max ybusd_repay = 2**256-1 # max lp_repay = 0 try: tx = homora.execute( 1, curve_spell, curve_spell.removeLiquidity4.encode_input( lp_busd, # LP_busd token lp_take_amt, # LP amount to take out lp_want, # LP amount to withdraw to wallet [ydai_repay, yusdc_repay, yusdt_repay, ybusd_repay], # repay amounts lp_repay, # repay LP amount [0, 0, 0, 0] # min amounts ), {'from': alice} ) assert False, 'tx should revert' except VirtualMachineError: pass # ##################################################################################### print('=========================================================================') print('Case 5. remove liqudiity') # remove liquidity from the same position prevABal = dai.balanceOf(alice) prevBBal = usdc.balanceOf(alice) prevCBal = usdt.balanceOf(alice) prevDBal = susd.balanceOf(alice) prevLPBal = lp.balanceOf(alice) prevLPBal_bank = lp.balanceOf(homora) prevLPBal_gauge = lp.balanceOf(gauge) _, _, _, collSize = homora.getPositionInfo(1) lp_take_amt = 2**256-1 # max lp_want = 0 dai_repay = 2**256-1 # max usdc_repay = 2**256-1 # max usdt_repay = 2**256-1 # max susd_repay = 2**256-1 # max lp_repay = 0 tx = homora.execute( 1, curve_spell, curve_spell.removeLiquidity4.encode_input( lp, # LP token lp_take_amt, # LP amount to take out lp_want, # LP amount to withdraw to wallet [dai_repay, usdc_repay, usdt_repay, susd_repay], # repay amounts lp_repay, # repay LP amount [0, 0, 0, 0] # min amounts ), {'from': alice} ) curABal = dai.balanceOf(alice) curBBal = usdc.balanceOf(alice) curCBal = usdt.balanceOf(alice) curLPBal = lp.balanceOf(alice) curLPBal_bank = lp.balanceOf(homora) curLPBal_gauge = lp.balanceOf(gauge) print('spell lp balance', lp.balanceOf(curve_spell)) print('spell dai balance', dai.balanceOf(curve_spell)) print('spell usdc balance', usdc.balanceOf(curve_spell)) print('spell usdt balance', usdt.balanceOf(curve_spell)) print('Alice delta A balance', curABal - prevABal) print('Alice delta B balance', curBBal - prevBBal) print('Alice delta C balance', curCBal - prevCBal) 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) _, _, _, daiDebt, daiDebtShare = homora.getBankInfo(dai) _, _, _, usdcDebt, usdcDebtShare = homora.getBankInfo(usdc) _, _, _, usdtDebt, usdtDebtShare = homora.getBankInfo(usdt) print('bank dai totalDebt', daiDebt) print('bank dai totalDebt', daiDebt) print('bank usdc totalShare', usdcDebtShare) print('bank usdc totalShare', usdcDebtShare) print('bank usdt totalDebt', usdtDebt) print('bank usdt totalShare', usdtDebtShare) print('LP want', lp_want) print('bank delta LP amount', curLPBal_bank - prevLPBal_bank) print('LP take amount', lp_take_amt) print('prev gauge LP balance', prevLPBal_gauge) print('cur gauge LP balance', curLPBal_gauge) print('coll size', collSize) # alice assert almostEqual(curLPBal - prevLPBal, lp_want), 'incorrect LP amt' # spell assert dai.balanceOf(curve_spell) == 0, 'non-zero spell DAI balance' assert usdc.balanceOf(curve_spell) == 0, 'non-zero spell USDC balance' assert usdt.balanceOf(curve_spell) == 0, 'non-zero spell USDT balance' assert lp.balanceOf(curve_spell) == 0, 'non-zero spell LP balance' # debt assert usdcDebt == 0, 'usdcDebt should be 0' assert daiDebt == 0, 'daiDebt should be 0' assert usdtDebt == 0, 'usdtDebt should be 0' curAliceCrvBalance = crv.balanceOf(alice) print('Alice crv balance', curAliceCrvBalance) receivedCrv = curAliceCrvBalance - prevAliceCrvBalance print('received crv', receivedCrv) # check with staking directly minter = interface.ILiquidityGaugeMinter(interface.ILiquidityGauge(gauge).minter()) print('minter', minter) tx = minter.mint(gauge, {'from': bob}) print('tx status', tx.status) tx = interface.ILiquidityGauge(gauge).withdraw(collSize, {'from': bob}) receivedCrvFromGauge = crv.balanceOf(bob) - prevCrv print('receivedCrvFromGauge', receivedCrvFromGauge) assert almostEqual(receivedCrv, receivedCrvFromGauge) # ##################################################################################### print('=========================================================================') print('Case 6. add & remove all LP') lp_amt = 10 * 10**6 prevLPBal = lp.balanceOf(alice) pid, gid = 12, 0 tx = homora.execute( 0, curve_spell, curve_spell.addLiquidity4.encode_input( lp, # LP [0, 0, 0, 0], # supply tokens lp_amt, # supply LP [0, 0, 0, 0], # borrow tokens 0, # borrow LP 0, # min LP mint pid, gid ), {'from': alice} ) tx = homora.execute( 2, curve_spell, curve_spell.removeLiquidity4.encode_input( lp, # LP token 2**256-1, # LP amount to take out lp_amt, # LP amount to withdraw to wallet [0, 0, 0, 0], # repay amounts 0, # repay LP amount [0, 0, 0, 0] # min amounts ), {'from': alice} ) curLPBal = lp.balanceOf(alice) assert prevLPBal == curLPBal, 'incorrect LP Balance' return tx
def live(): admin = accounts.at("0xC447FcAF1dEf19A583F97b3620627BF69c05b5fB") with open(config.DEPLOYMENTS_JSON) as fp: pool_proxy = json.load(fp)['PoolProxy'] transfer_ownership(admin, pool_proxy, config.REQUIRED_CONFIRMATIONS)
def main(): if USE_STRATEGIES: web3.eth.setGasPriceStrategy(gas_strategy) web3.middleware_onion.add(middleware.time_based_cache_middleware) web3.middleware_onion.add( middleware.latest_block_based_cache_middleware) web3.middleware_onion.add(middleware.simple_cache_middleware) if POA: web3.middleware_onion.inject(middleware.geth_poa_middleware, layer=0) deployer = accounts.at(DEPLOYER) lp_token = deploy_erc20s_and_pool(deployer) token = repeat(ERC20CRV.deploy, "Curve DAO Token", "CRV", 18, 10**9, { 'from': deployer, 'required_confs': CONFS }) save_abi(token, 'token_crv') escrow = repeat(VotingEscrow.deploy, token, "Vote-escrowed CRV", "veCRV", "veCRV_0.99", { 'from': deployer, 'required_confs': CONFS }) save_abi(escrow, 'voting_escrow') repeat(escrow.changeController, TOKEN_MANAGER, { 'from': deployer, 'required_confs': CONFS }) for account in DISTRIBUTION_ADDRESSES: repeat(token.transfer, account, DISTRIBUTION_AMOUNT, { 'from': deployer, 'required_confs': CONFS }) gauge_controller = repeat(GaugeController.deploy, token, escrow, { 'from': deployer, 'required_confs': CONFS }) save_abi(gauge_controller, 'gauge_controller') minter = repeat(Minter.deploy, token, gauge_controller, { 'from': deployer, 'required_confs': CONFS }) save_abi(minter, 'minter') liquidity_gauge = repeat(LiquidityGauge.deploy, lp_token, minter, { 'from': deployer, 'required_confs': CONFS }) save_abi(liquidity_gauge, 'liquidity_gauge') repeat(token.set_minter, minter, { 'from': deployer, 'required_confs': CONFS }) repeat(gauge_controller.add_type, b'Liquidity', { 'from': deployer, 'required_confs': CONFS }) repeat(gauge_controller.change_type_weight, 0, 10**18, { 'from': deployer, 'required_confs': CONFS }) repeat(gauge_controller.add_gauge, liquidity_gauge, 0, 10**18, { 'from': deployer, 'required_confs': CONFS }) repeat(gauge_controller.transfer_ownership, ARAGON_AGENT, { 'from': deployer, 'required_confs': CONFS }) repeat(escrow.transfer_ownership, ARAGON_AGENT, { 'from': deployer, 'required_confs': CONFS }) repeat(PoolProxy.deploy, {'from': deployer, 'required_confs': CONFS})
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}) # whitelist spell in bank homora.setWhitelistSpells([uniswap_spell], [True], {'from': admin}) # whitelist token in bank homora.setWhitelistTokens([usdt, usdc], [True, True], {'from': admin}) # whitelist lp in spell uniswap_spell.setWhitelistLPTokens([lp], [True], {'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.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 0 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) 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.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 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) 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' # 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(1) lp_take_amt = collSize // 2 lp_want = 1 * 10**5 usdt_repay = MAX_INT usdc_repay = MAX_INT tx = homora.execute( 1, uniswap_spell, uniswap_spell.removeLiquidityWERC20.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(1) lp_take_amt = MAX_INT lp_want = 1 * 10**5 usdt_repay = MAX_INT usdc_repay = MAX_INT tx = homora.execute( 1, uniswap_spell, uniswap_spell.removeLiquidityWERC20.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.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 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('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(1) lp_take_amt = MAX_INT # max lp_want = 0 usdt_repay = 0 # max usdc_repay = 0 # max tx = homora.execute( 1, uniswap_spell, uniswap_spell.removeLiquidityWERC20.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] dai = interface.IERC20Ex('0x6B175474E89094C44Da98b954EedeAC495271d0F') usdc = interface.IERC20Ex('0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48') usdt = interface.IERC20Ex('0xdAC17F958D2ee523a2206206994597C13D831ec7') wbtc = interface.IERC20Ex('0x2260fac5e5542a773aa44fbcfedf7c193bc2c599') renbtc = interface.IERC20Ex('0xeb4c2781e4eba804ce9a9803c67d0893436bb27d') crv = interface.IERC20Ex('0xD533a949740bb3306d119CC777fa900bA034cd52') lp_3pool = interface.IERC20Ex('0x6c3f90f043a72fa612cbac8115ee7e52bde6e490') lp_btc = interface.IERC20Ex('0x49849c98ae39fff122806c06791fa73784fb3675') pool_3pool = interface.ICurvePool( '0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7') pool_btc = interface.ICurvePool( '0x93054188d876f558f4a66B2EF1d97d16eDf0895B') registry = interface.ICurveRegistry( '0x7d86446ddb609ed0f5f8684acf30380a356b2b4c') gauge = accounts.at('0xbFcF63294aD7105dEa65aA58F8AE5BE2D9d0952A', force=True) wgauge = WLiquidityGauge.deploy( registry, '0xD533a949740bb3306d119CC777fa900bA034cd52', {'from': admin}) # set approval dai.approve(wgauge, 2**256 - 1, {'from': alice}) usdc.approve(wgauge, 2**256 - 1, {'from': alice}) usdt.approve(wgauge, 2**256 - 1, {'from': alice}) renbtc.approve(wgauge, 2**256 - 1, {'from': alice}) wbtc.approve(wgauge, 2**256 - 1, {'from': alice}) lp_3pool.approve(wgauge, 2**256 - 1, {'from': alice}) lp_3pool.approve(gauge, 2**256 - 1, {'from': alice}) lp_btc.approve(wgauge, 2**256 - 1, {'from': alice}) lp_btc.approve(gauge, 2**256 - 1, {'from': alice}) dai.approve(wgauge, 2**256 - 1, {'from': bob}) usdc.approve(wgauge, 2**256 - 1, {'from': bob}) usdt.approve(wgauge, 2**256 - 1, {'from': bob}) renbtc.approve(wgauge, 2**256 - 1, {'from': bob}) wbtc.approve(wgauge, 2**256 - 1, {'from': bob}) lp_3pool.approve(wgauge, 2**256 - 1, {'from': bob}) lp_3pool.approve(gauge, 2**256 - 1, {'from': bob}) lp_btc.approve(wgauge, 2**256 - 1, {'from': bob}) lp_btc.approve(gauge, 2**256 - 1, {'from': bob}) # setup initial funds to alice mint_tokens(dai, alice) mint_tokens(usdc, alice) mint_tokens(usdt, alice) mint_tokens(renbtc, alice) mint_tokens(wbtc, alice) mint_tokens(dai, bob) mint_tokens(usdc, bob) mint_tokens(usdt, bob) mint_tokens(renbtc, bob) mint_tokens(wbtc, bob) # steal some LP from the staking pool mint_tokens(lp_3pool, alice) mint_tokens(lp_btc, alice) mint_tokens(lp_3pool, bob) mint_tokens(lp_btc, bob) # register gauges wgauge.registerGauge(0, 0, {'from': admin}) wgauge.registerGauge(9, 0, {'from': admin}) ###################################################################### # Check encoding and decoding ids print( '######################################################################' ) print('Case 1.') # check 3pool pid = 0 gid = 0 crvPerShare = 210 encoded_id = wgauge.encodeId(pid, gid, crvPerShare) print('encoded id', encoded_id) assert (encoded_id >> 248) == pid assert (encoded_id >> 240) & ((1 << 8) - 1) == gid assert (encoded_id & ((1 << 240) - 1)) == crvPerShare d_pid, d_gid, d_crvPerShare = wgauge.decodeId(encoded_id) print('decoded pid', d_pid) print('decoded gid', d_gid) print('decoded crvPerShare', d_crvPerShare) assert d_pid == pid assert d_gid == gid assert d_crvPerShare == crvPerShare # check renbtc pool pid = 9 gid = 0 crvPerShare = 100 encoded_id = wgauge.encodeId(pid, gid, crvPerShare) print('encoded id', encoded_id) assert (encoded_id >> 248) == pid assert (encoded_id >> 240) & ((1 << 8) - 1) == gid assert (encoded_id & ((1 << 240) - 1)) == crvPerShare d_pid, d_gid, d_crvPerShare = wgauge.decodeId(encoded_id) print('decoded pid', d_pid) print('decoded gid', d_gid) print('decoded crvPerShare', d_crvPerShare) assert d_pid == pid assert d_gid == gid assert d_crvPerShare == crvPerShare ###################################################################### # check getUnderlyingToken pid = 0 gid = 0 crvPerShare = 200 id_num = wgauge.encodeId(pid, gid, crvPerShare) lpToken = wgauge.getUnderlyingToken(id_num) print('lpToken', lpToken) assert lpToken == lp_3pool pid = 9 gid = 0 crvPerShare = 100 id_num = wgauge.encodeId(pid, gid, crvPerShare) lpToken = wgauge.getUnderlyingToken(id_num) print('lpToken', lpToken) assert lpToken == lp_btc ###################################################################### # check mint & burn print( '######################################################################' ) print('Case 2.') pid = 0 gid = 0 amt = 10**18 print('alice lp 3pool balance', lp_3pool.balanceOf(alice)) # mint tx = wgauge.mint(pid, gid, amt, {'from': alice}) encoded_id = tx.return_value print('tx status', tx.status) print('encoded id', encoded_id) gauge, prevAccCrvPerShare = wgauge.gauges(pid, gid) print('gauge', gauge) print('prevAccCrvPerShare', prevAccCrvPerShare) print('alice wlp_3pool balance', wgauge.balanceOf(alice, encoded_id)) assert tx.status == 1 assert wgauge.balanceOf(alice, encoded_id) == amt chain.sleep(20000) # burn exact prevCrvBalance = crv.balanceOf(alice) tx = wgauge.burn(encoded_id, amt, {'from': alice}) print('tx status', tx.status) print('alice wlp_3pool balance', wgauge.balanceOf(alice, encoded_id)) print('alice crv balance', crv.balanceOf(alice)) receivedCrv = crv.balanceOf(alice) - prevCrvBalance assert tx.status == 1 assert tx.return_value == pid assert wgauge.balanceOf(alice, encoded_id) == 0 # remove all # check reward same as staking directly prevCrv = crv.balanceOf(alice) print('alice lp_3pool balance', interface.IERC20Ex(lp_3pool).balanceOf(alice)) gauge, _ = wgauge.gauges(pid, gid) tx = interface.ILiquidityGauge(gauge).deposit(amt, {'from': alice}) chain.sleep(20000) minter = interface.ILiquidityGaugeMinter( interface.ILiquidityGauge(gauge).minter()) print('minter', minter) tx = minter.mint(gauge, {'from': alice}) print('tx status', tx.status) tx = interface.ILiquidityGauge(gauge).withdraw(amt, {'from': alice}) receivedCrvFromGauge = crv.balanceOf(alice) - prevCrv print('receivedCrvFromGauge', receivedCrvFromGauge) assert almostEqual(receivedCrv, receivedCrvFromGauge) ###################################################################### # check mint & burn max_int print( '######################################################################' ) print('Case 3.') pid = 0 gid = 0 amt = 10**18 print('alice lp 3pool balance', lp_3pool.balanceOf(alice)) # mint alice tx = wgauge.mint(pid, gid, amt, {'from': alice}) encoded_id = tx.return_value print('tx status', tx.status) print('encoded id', encoded_id) gauge, prevAccCrvPerShare = wgauge.gauges(pid, gid) print('gauge', gauge) print('prevAccCrvPerShare', prevAccCrvPerShare) print('alice wlp_3pool balance', wgauge.balanceOf(alice, encoded_id)) assert tx.status == 1 assert wgauge.balanceOf(alice, encoded_id) == amt # mint bob prevCrvBob = crv.balanceOf(bob) print('bob lp_3pool balance', interface.IERC20Ex(lp_3pool).balanceOf(bob)) gauge, _ = wgauge.gauges(pid, gid) tx = interface.ILiquidityGauge(gauge).deposit(amt, {'from': bob}) chain.sleep(10000) # burn max_int alice prevCrvBalance = crv.balanceOf(alice) tx = wgauge.burn(encoded_id, 2**256 - 1, {'from': alice}) print('tx status', tx.status) print('alice wlp_3pool balance', wgauge.balanceOf(alice, encoded_id)) print('alice crv balance', crv.balanceOf(alice)) receivedCrv = crv.balanceOf(alice) - prevCrvBalance assert tx.status == 1 assert tx.return_value == pid assert wgauge.balanceOf(alice, encoded_id) == 0 # remove all # burn all bob minter = interface.ILiquidityGaugeMinter( interface.ILiquidityGauge(gauge).minter()) print('minter', minter) tx = minter.mint(gauge, {'from': bob}) print('tx status', tx.status) tx = interface.ILiquidityGauge(gauge).withdraw(amt, {'from': bob}) receivedCrvFromGauge = crv.balanceOf(bob) - prevCrvBob print('receivedCrv', receivedCrv) print('receivedCrvFromGauge', receivedCrvFromGauge) assert almostEqual(receivedCrv, receivedCrvFromGauge) ###################################################################### # check mint & burn (try more than available--revert, half, then remaining) print( '######################################################################' ) print('Case 4.') pid = 0 gid = 0 amt = 10**18 print('alice lp 3pool balance', lp_3pool.balanceOf(alice)) # mint alice tx = wgauge.mint(pid, gid, amt, {'from': alice}) encoded_id = tx.return_value print('tx status', tx.status) print('encoded id', encoded_id) gauge, prevAccCrvPerShare = wgauge.gauges(pid, gid) print('gauge', gauge) print('prevAccCrvPerShare', prevAccCrvPerShare) print('alice wlp_3pool balance', wgauge.balanceOf(alice, encoded_id)) assert tx.status == 1 assert wgauge.balanceOf(alice, encoded_id) == amt # mint bob prevCrvBob = crv.balanceOf(bob) print('bob lp_3pool balance', interface.IERC20Ex(lp_3pool).balanceOf(bob)) gauge, _ = wgauge.gauges(pid, gid) tx = interface.ILiquidityGauge(gauge).deposit(amt, {'from': bob}) chain.sleep(10000) # burn too much (expected failed) prevCrvBalance = crv.balanceOf(alice) try: tx = wgauge.burn(encoded_id, amt + 1, {'from': alice}) assert tx.status == 0 except: pass print('alice wlpusdt balance', wgauge.balanceOf(alice, encoded_id)) print('alice crv balance', crv.balanceOf(alice)) assert prevCrvBalance == crv.balanceOf(alice) assert wgauge.balanceOf(alice, encoded_id) == amt # burn half alice prevCrvBalance = crv.balanceOf(alice) tx = wgauge.burn(encoded_id, amt // 2, {'from': alice}) print('tx status', tx.status) print('alice wlp_3pool balance', wgauge.balanceOf(alice, encoded_id)) print('amt - amt//2', amt - amt // 2) print('alice crv balance', crv.balanceOf(alice)) assert tx.status == 1 assert tx.return_value == pid assert wgauge.balanceOf(alice, encoded_id) == amt - amt // 2 # remove half # burn half bob minter = interface.ILiquidityGaugeMinter( interface.ILiquidityGauge(gauge).minter()) print('minter', minter) tx = minter.mint(gauge, {'from': bob}) print('tx status', tx.status) tx = interface.ILiquidityGauge(gauge).withdraw(amt // 2, {'from': bob}) chain.sleep(10000) # burn remaining alice tx = wgauge.burn(encoded_id, 2**256 - 1, {'from': alice}) print('tx status', tx.status) print('alice wlp_3pool balance', wgauge.balanceOf(alice, encoded_id)) print('alice crv balance', crv.balanceOf(alice)) receivedCrv = crv.balanceOf(alice) - prevCrvBalance assert tx.status == 1 assert tx.return_value == pid # burn remaining bob tx = minter.mint(gauge, {'from': bob}) print('tx status', tx.status) tx = interface.ILiquidityGauge(gauge).withdraw(amt - amt // 2, {'from': bob}) receivedCrvFromGauge = crv.balanceOf(bob) - prevCrvBob print('receivedCrv alice', receivedCrv) print('receivedCrvFromGauge bob', receivedCrvFromGauge) assert wgauge.balanceOf(alice, encoded_id) == 0 # remove all # check reward same as staking directly assert almostEqual(receivedCrv, receivedCrvFromGauge)
def test_single_user_harvest_flow(settConfig): badger = badger_single_sett(settConfig) sett = badger.getSett(settConfig["id"]) strategy = badger.getStrategy(settConfig["id"]) want = badger.getStrategyWant(settConfig["id"]) settKeeper = accounts.at(sett.keeper(), force=True) strategyKeeper = accounts.at(strategy.keeper(), force=True) snap = DiggSnapshotManager(badger, settConfig["id"]) deployer = badger.deployer randomUser = accounts[6] tendable = strategy.isTendable() startingBalance = want.balanceOf(deployer) depositAmount = startingBalance // 2 assert startingBalance >= depositAmount assert startingBalance >= 0 # Deposit want.approve(sett, MaxUint256, {"from": deployer}) snap.settDeposit(depositAmount, {"from": deployer}) # Push/rebase on an exchange rate of 1.2 (DIGG trading at 1.2x BTC) snap.rebase(1.2 * 10**18, {"from": deployer}) # Earn snap.settEarn({"from": settKeeper}) if tendable: with reverts("onlyAuthorizedActors"): strategy.tend({"from": randomUser}) snap.settTend({"from": strategyKeeper}) chain.sleep(days(0.5)) chain.mine() # Push/rebase on an exchange rate of 0.6 (DIGG trading at 0.8x BTC) snap.rebase(0.6 * 10**18, {"from": deployer}) if tendable: snap.settTend({"from": strategyKeeper}) chain.sleep(days(1)) chain.mine() with reverts("onlyAuthorizedActors"): strategy.harvest({"from": randomUser}) snap.settHarvest({"from": strategyKeeper}) chain.sleep(days(1)) chain.mine() # Push/rebase on an exchange rate of 1.6 (DIGG trading at 1.6x BTC) snap.rebase(1.6 * 10**18, {"from": deployer}) if tendable: snap.settTend({"from": strategyKeeper}) snap.settWithdraw(depositAmount // 2, {"from": deployer}) chain.sleep(days(3)) chain.mine() # Push/rebase on an exchange rate of 0.7 (DIGG trading at 0.7x BTC) snap.rebase(0.7 * 10**18, {"from": deployer}) snap.settHarvest({"from": strategyKeeper}) snap.settWithdraw(depositAmount // 2 - 1, {"from": deployer}) assert False
def fx_ballot_maker(accounts): return accounts.at('0xAD4f7415407B83a081A0Bee22D05A8FDC18B42da', force=True)
from brownie import ProxyAdmin, accounts DEPLOYER = accounts.at("0x7EeAC6CDdbd1D0B8aF061742D41877D7F707289a", True) ADMINS = [ "0x7EeAC6CDdbd1D0B8aF061742D41877D7F707289a", "0x7EeAC6CDdbd1D0B8aF061742D41877D7F707289a", ] def main(): ProxyAdmin.deploy(ADMINS, {"from": DEPLOYER})
def test_operation(pm, chain): dai_liquidity = accounts.at( "0xbebc44782c7db0a1a60cb6fe97d0b483032ff1c7", force=True ) # using curve pool (lots of dai) crv3_liquidity = accounts.at( "0x6c3F90f043a72FA612cbac8115EE7e52BDe6E490", force=True ) # yearn treasury (lots of crv3) rewards = accounts[2] gov = accounts[3] guardian = accounts[4] bob = accounts[5] alice = accounts[6] strategist = accounts[7] tinytim = accounts[8] dai = Contract("0x6b175474e89094c44da98b954eedeac495271d0f", owner=gov) # DAI token dai.approve(dai_liquidity, Wei("1000000 ether"), {"from": dai_liquidity}) dai.transferFrom(dai_liquidity, gov, Wei("10000 ether"), {"from": dai_liquidity}) crv3 = Contract( "0x6c3F90f043a72FA612cbac8115EE7e52BDe6E490", owner=gov ) # crv3 token address (threePool) crv3.approve(crv3_liquidity, Wei("1000000 ether"), {"from": crv3_liquidity}) crv3.transferFrom(crv3_liquidity, gov, Wei("100 ether"), {"from": crv3_liquidity}) # config yvDAI vault. Vault = pm(config["dependencies"][0]).Vault yUSDT3 = gov.deploy(Vault, dai, gov, rewards, "", "") threePool = Contract( "0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7", owner=gov ) # crv3 pool address (threePool) yCRV3 = Contract( "0x9cA85572E6A3EbF24dEDd195623F188735A5179f", owner=gov ) # crv3 vault (threePool) # uni = Contract.from_explorer( # "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D", owner=gov # ) # UNI router v2 strategy = guardian.deploy(StrategyDAI3Pool, yUSDT3, dai, threePool, yCRV3, crv3) strategy.setStrategist(strategist) yUSDT3.addStrategy( strategy, Wei("1000000000 ether"), 2 ** 256 - 1, 50, {"from": gov} ) dai.approve(gov, Wei("1000000 ether"), {"from": gov}) dai.transferFrom(gov, bob, Wei("1000 ether"), {"from": gov}) dai.transferFrom(gov, alice, Wei("4000 ether"), {"from": gov}) dai.transferFrom(gov, tinytim, Wei("10 ether"), {"from":gov}) dai.approve(yUSDT3, Wei("1000000 ether"), {"from": bob}) dai.approve(yUSDT3, Wei("1000000 ether"), {"from": alice}) dai.approve(yUSDT3, Wei("1000000 ether"), {"from": tinytim}) crv3.approve(gov, Wei("1000000 ether"), {"from": gov}) yUSDT3.approve(gov, Wei("1000000 ether"), {"from": gov}) crv3.approve(yCRV3, Wei("1000000 ether"), {"from": gov}) dai.approve(threePool, Wei("1000000 ether"), {"from": gov}) # users deposit to vault yUSDT3.deposit(Wei("1000 ether"), {"from": bob}) yUSDT3.deposit(Wei("4000 ether"), {"from": alice}) yUSDT3.deposit(Wei("10 ether"), {"from": tinytim}) # a = dai.balanceOf(address(bob)) # b = dai.balanceOf(address(alice)) # print(a) # print(b) chain.mine(1) strategy.harvest({"from": gov}) chain.mine(10) crv3.transferFrom(gov, yCRV3, Wei("100 ether"), {"from": gov}) strategy.harvest({"from": gov}) chain.mine(10) assert 1 == 2 yUSDT3.withdraw({"from": alice}) assert dai.balanceOf(alice) > 0 assert dai.balanceOf(strategy) == 0 assert dai.balanceOf(bob) == 0 yUSDT3.withdraw({"from": bob}) assert dai.balanceOf(bob) > 0 assert dai.balanceOf(strategy) == 0 assert 1 == 2
def __init__(self, badger, multi, key, distributions, start=0, duration=0, end=0): # == Distribute to Geyser == geyser = badger.getGeyser(key) rewardsEscrow = badger.rewardsEscrow self.start = start self.duration = duration self.end = end multi = GnosisSafe(badger.devMultisig) for asset, dist in distributions.items(): token = asset_to_address(asset) self.validate_staking_rewards_emission(key, asset) stakingRewards = badger.getSettRewards(key) console.print( "Staking Rewards Distribution for asset {} on {}: {}".format( asset, key, val(dist)), style="yellow", ) # Approve if not approved if not rewardsEscrow.isApproved(stakingRewards): id = multi.addTx( MultisigTxMetadata( description="Approve StakingRewards " + key, operation="transfer", ), { "to": rewardsEscrow.address, "data": rewardsEscrow.approveRecipient.encode_input( stakingRewards), }, ) multi.executeTx(id) assert rewardsEscrow.isApproved(stakingRewards) == True # Add tokens if insufficent tokens preBal = badger.token.balanceOf(stakingRewards) print("PreBalance", val(preBal)) if preBal < dist: required = dist - preBal console.print( "⊁ We need to add {} to the {} Badger supply of {} to reach the goal of {} Badger" .format( val(required), key, val(preBal), val(dist), ), style="blue", ) id = multi.addTx( MultisigTxMetadata( description="Top up tokens for staking rewards " + key, operation="transfer", ), { "to": rewardsEscrow.address, "data": rewardsEscrow.transfer.encode_input( badger.token, stakingRewards, required), }, ) multi.executeTx(id) assert badger.token.balanceOf(stakingRewards) >= dist # Modify the rewards duration, if necessary if stakingRewards.rewardsDuration() != self.duration: id = multi.addTx( MultisigTxMetadata( description="Modify Staking Rewards duration for " + key, operation="call.notifyRewardAmount", ), { "to": stakingRewards.address, "data": stakingRewards.setRewardsDuration.encode_input( self.duration), }, ) tx = multi.executeTx(id) # assert stakingRewards.rewardsDuration() == self.duration # Notify Rewards Amount id = multi.addTx( MultisigTxMetadata( description="Distribute Staking Rewards For " + key, operation="call.notifyRewardAmount", ), { "to": stakingRewards.address, "data": stakingRewards.notifyRewardAmount.encode_input( self.start, dist, ), }, ) tx = multi.executeTx(id) console.print(tx.call_trace()) console.print("notify rewards events", tx.events) # Verify Results rewardsDuration = stakingRewards.rewardsDuration() rewardRate = stakingRewards.rewardRate() periodFinish = stakingRewards.periodFinish() lastUpdate = stakingRewards.lastUpdateTime() oldRewardsRate = Wei("50000 ether") // rewardsDuration console.log({ "start": to_utc_date(self.start), "end": to_utc_date(self.end), "finish": to_utc_date(periodFinish), "rewardRate": rewardRate, "expectedRewardRate": dist // rewardsDuration, "rewardsRateDiff": rewardRate - dist // rewardsDuration, "oldRewardsRate": oldRewardsRate, "howTheRateChanged": (dist // rewardsDuration) / oldRewardsRate, "howWeExpectedItToChange": Wei("35000 ether") / Wei("50000 ether"), "lastUpdate": to_utc_date(lastUpdate), }) assert lastUpdate == self.start assert rewardsDuration == self.duration assert rewardRate == dist // rewardsDuration assert periodFinish == self.start + self.duration bal = badger.token.balanceOf(stakingRewards) assert bal >= dist if bal > dist * 2: console.print( "[red] Warning: Staking rewards for {} has excessive coins [/red]" .format(key)) # Harvest the rewards and ensure the amount updated is appropriate strategy = badger.getStrategy(key) keeper = accounts.at(strategy.keeper(), force=True) before = strategy.balance() chain.sleep(self.start - chain.time() + 2) strategy.harvest({"from": keeper}) after = strategy.balance() print({"before": before, "after": after})
} EMERGENCY_DAO = { 'forwarder': "0xf409Ce40B5bb1e4Ef8e97b1979629859c6d5481f", 'agent': "0x00669DF67E4827FCc0E48A1838a8d5AB79281909", 'voting': "0x1115c9b3168563354137cdc60efb66552dd50678", 'token': "0x4c0947B16FB1f755A2D32EC21A0c4181f711C500", 'quorum': 51, } # the intended target of the vote, should be one of the above constant dicts TARGET = CURVE_DAO # address to create the vote from - you will need to modify this prior to mainnet use SENDER = accounts.at("0x9B44473E223f8a3c047AD86f387B80402536B029", force=True) # a list of calls to perform in the vote, formatted as a lsit of tuples # in the format (target, function name, *input args). # # for example, to call: # `GaugeController("0x2F50D538606Fa9EDD2B11E2446BEb18C9D5846bB").add_gauge("0xFA712EE4788C042e2B7BB55E6cb8ec569C4530c1", 0, 0) # # use the following: # [("0x2F50D538606Fa9EDD2B11E2446BEb18C9D5846bB", "add_gauge", "0xFA712EE4788C042e2B7BB55E6cb8ec569C4530c1", 0, 0),] ACTIONS = [ # ("target", "fn_name", *args), ] # metadata description to include with vote
def governance_timelock(): return accounts.at("0x21CF9b77F88Adf8F8C98d7E33Fe601DC57bC0893", force=True)