async def test_deposit_withdraw(self, real_weth: Weth, dummy_address): real_weth.set_owner_address(dummy_address) real_weth.deposit(2) assert await real_weth.balance_of(dummy_address) == BigNumber(2) real_weth.withdraw(2) assert await real_weth.balance_of(dummy_address) == BigNumber(0)
def _swap_transaction(self, trade): path = list(map(lambda t: t.address, trade.path)) return self.contract.functions.swapExactTokensForTokens( BigNumber(trade.amount_in).value, BigNumber(trade.amount_in).value, path, self._get_account(), self.w3.eth.getBlock("latest").timestamp + self.timeout, )
def dummy_account(w3, empty_account) -> Account: balance = w3.eth.getBalance(empty_account.address) required = 11 - BigNumber.from_value(balance).to_number() required = max(0, required) tx_recip = w3.eth.sendTransaction({ "from": w3.eth.accounts[2], "to": empty_account.address, "value": BigNumber(required).value, }) w3.eth.waitForTransactionReceipt(tx_recip) return empty_account
async def pool_factory( dai: GenericToken, weth: GenericToken, yam: GenericToken, wbtc: GenericToken, bad, w3, deploy_address, ) -> BalancerFactory: factory = ContractFactory(w3, BalancerFactory).deploy_contract(deploy_address) f1 = factory.setup_pool( [weth, dai, yam], [5, 5, 5], [ BigNumber(small / 303.0), BigNumber(small / 0.9), BigNumber(small / 0.1), ], ) f2 = factory.setup_pool( [bad, dai], [5, 5], [ BigNumber(100), BigNumber(small / 0.9), ], approve_owner=False, ) factory.new_pool() f3 = factory.setup_pool( [weth, wbtc], [5, 1], [ BigNumber(5 * large / 301.0), BigNumber(large / 10000), ], # noqa: WPS221 ) f4 = factory.setup_pool( [weth, dai, wbtc], [2, 1, 1], [ BigNumber(2 * medium / 301.0), BigNumber(medium / 1.1), BigNumber(large / 10020), ], ) await asyncio.gather(f1, f2, f3, f4) return factory
async def pair_factory( # noqa: WPS210, WPS217 factory, dai: GenericToken, weth: GenericToken, yam: GenericToken, wbtc: GenericToken, paused_token: GenericToken, bad, w3, deploy_address, ) -> UniswapFactory: await factory.setup_pair( [wbtc, dai], [ BigNumber(medium / 20000.0), BigNumber(medium), ], ) await factory.setup_pair( [dai, yam], [ BigNumber(medium / 1.1), BigNumber(medium / 0.1), ], # noqa: WPS221 ) await factory.setup_pair( [weth, dai], [BigNumber(medium / 310), BigNumber(medium)], ) await factory.setup_pair( [wbtc, weth], [ BigNumber(medium / 10000), BigNumber(medium / 285), ], ) await factory.setup_pair( [paused_token, weth], [ BigNumber(medium / 10000), BigNumber(medium / 285), ], ) paused_token.pause() await factory.create_pair(weth, bad) await factory.create_pair(weth, yam) return factory
async def create_reserve(result: Tuple[float, GenericToken]): (value, token) = result try: exp = await token.decimals() except Exception: raise IERC20TokenError("Token doesn't contain decimals.") return BigNumber.from_value(value, exp)
def send_eth(web3, from_address, to_address, value): tx_hash = web3.eth.sendTransaction({ "to": to_address, "from": from_address, "value": BigNumber(value).value }) return web3.eth.waitForTransactionReceipt(tx_hash, 180)
def bind(self, address: str, balance: BigNumber, denorm_weight: int) -> bool: if denorm_weight < 1: raise ValueError("Weight should be larger than 1") eth_safe_weight = BigNumber(denorm_weight) transaction = self.contract.functions.bind(address, balance.value, eth_safe_weight.value) return self._transact_info(transaction)
async def test_swap(self, trade, router: UniswapV2Router, weth: GenericToken, dummy_account): trade.amount_in = 1 weth.transfer(dummy_account.address, BigNumber(2)) weth.set_account(dummy_account) balance_before = await weth.balance_of(dummy_account.address) assert balance_before > 1 weth.approve(router.get_address(), BigNumber(2)) router.set_account(dummy_account) assert router.swap(trade) amount_out = router.check_out_given_in(trade) balance_after = await weth.balance_of(dummy_account.address) assert (balance_after.to_number() - balance_before.to_number() > amount_out - trade.amount_in - 0.001)
def deposit(self, amount, dry_run=False): transaction = self.contract.functions.deposit() # The gas amount 4249 was achieved by testing the contract and checking how much gas was needed. return self._transact_info( transaction, value=BigNumber(amount).value, gas=44249, # noqa: WPS432 dry_run=dry_run, )
async def get_balances(self) -> List[BigNumber]: tokens = await self.get_tokens() balances = [] for token in tokens: b = self.contract.functions.getBalance(token.get_address()).call() try: decimals = await token.decimals() except Exception: raise IERC20TokenError("Bad token in balancer pool") balances.append(BigNumber.from_value(b, decimals)) return balances
def _transact_info(self, transaction, value=None, gas=None, dry_run=False) -> Tuple[bool, float]: if gas is None: gas = self._estimate_gas(transaction) gas_amount = self.w3.eth.generateGasPrice() if gas_amount: gas_cost = BigNumber.from_value(gas * gas_amount).to_number() else: # No gas strategy specified gas_cost = None if dry_run: return False, gas_cost return self._transact(transaction, value, gas).status, gas_cost
async def all_pairs(factory, weth, dai, wbtc, paused_token): """all_pairs set up a very specific arbitrage opportunity. We want a opportunity that requires less then 2 WETH and provides significant profit as to be able to separate profit from gas costs. If the numbers do not make sense it is because they are crafted to produce a high arbitrage opportunity and high slippage. """ p0 = await factory.setup_pair( [weth, dai], [ BigNumber(small / 500 / 300.0), BigNumber(small / 500), ], ) p1 = await factory.setup_pair( [wbtc, dai], [ BigNumber(large / 10000.0), BigNumber(large / 10), ], ) p2 = await factory.setup_pair( [wbtc, weth], [ BigNumber(large / 10000.0), BigNumber(large / 300.0 + 31000), ], ) p3 = await factory.setup_pair( [paused_token, weth], [ BigNumber(large / 10000.0), BigNumber(large / 285.0), ], ) paused_token.pause() return await async_map(create_pool, [p0, p1, p2, p3])
def approve(self, weth: GenericToken): if weth.allowance(self.get_address()) < BigNumber(10e6): # noqa: WPS432 return weth.approve(self.get_address(), BigNumber(10e8)) # noqa: WPS432 return True
def trader(self, trader_config, weth: GenericToken, dummy_account): weth.transfer(dummy_account.address, BigNumber(4)) config = yaml.safe_load(trader_config) app = App(config) yield app app.store.delete(Result.trader_profit)
async def check(self, address): amount_weth = await self.weth.balance_of(address) amount_eth = BigNumber.from_value(self.web3.eth.getBalance(address)) return amount_eth.to_number(), amount_weth.to_number()
"""Test uniswap contracts.""" import asyncio import pytest from Arbie import IERC20TokenError from Arbie.Contracts.tokens import BadERC20Token, GenericToken from Arbie.Contracts.uniswap import UniswapFactory, UniswapPair from Arbie.Variables import BigNumber, PoolType bg10 = BigNumber(10) bg5 = BigNumber(5) pytestmark = pytest.mark.asyncio @pytest.fixture async def factory_with_pair(factory, dai, weth) -> UniswapFactory: await factory.create_pair(dai, weth) return factory async def test_get_all_pairs_length(factory): assert await factory.all_pairs_length() == 0 async def test_create_pair(factory_with_pair): assert await factory_with_pair.all_pairs_length() == 1 async def test_get_all_pairs(factory_with_pair):
def withdraw(self, amount, dry_run=False): transaction = self.contract.functions.withdraw(BigNumber(amount).value) return self._transact_info(transaction, dry_run=dry_run)
def test_create_big_number(): bg = BigNumber(5) assert bg.to_number() == 5
"""Test uniswap contracts.""" import pytest from Arbie.Contracts import ContractFactory from Arbie.Contracts.tokens import GenericToken, Weth from Arbie.Variables import BigNumber bg10 = BigNumber(10) @pytest.fixture def token_factory(w3) -> ContractFactory: return ContractFactory(w3, GenericToken) @pytest.fixture def dai(deploy_address, token_factory) -> GenericToken: return token_factory.deploy_contract(deploy_address, "Dai", "DAI", bg10.value) @pytest.mark.asyncio async def test_decimals(dai: GenericToken): assert await dai.decimals() == 18 class TestToken(object): def test_equals(self, dai, token_factory): dai2 = token_factory.load_contract(owner_address=dai.owner_address, address=dai.get_address()) assert dai == dai2
def test_bind_weight(pool_factory): pool = pool_factory.new_pool() with pytest.raises(ValueError): amount = BigNumber(5) weight = 0.2 pool.bind("", amount, weight)
def trader_account(w3, weth: GenericToken, router, dummy_account): router.set_account(dummy_account) weth.transfer(dummy_account.address, BigNumber(2)) weth.set_account(dummy_account) weth.approve(router.get_address(), BigNumber(2)) return dummy_account
def test_not_list_equals(): assert [BigNumber(5)] != [BigNumber(6)]
def setup_eth(amounts): mock = MagicMock() mock.eth = mock mock.getBalance.side_effect = list( map(lambda a: BigNumber(a).value, amounts)) # noqa: WPS221 return mock
def amount_to_future(amount): future = asyncio.Future() future.set_result(BigNumber(amount)) return future
def test_list_equals(): assert [BigNumber(5)] == [BigNumber(5)]
def check_out_given_in(self, trade: Trade): path_address = list(map(lambda t: t.address, trade.path)) amount_out = self.contract.functions.getAmountsOut( BigNumber(trade.amount_in).value, path_address ).call() return BigNumber.from_value(amount_out[-1]).to_number()
async def balance_of(self, owner: str) -> BigNumber: result = await asyncio.gather( self._call_async(self.contract.functions.balanceOf(owner)), self.decimals()) return BigNumber.from_value(result[0], result[1])
def test_not_equal(): assert BigNumber(5) != BigNumber(6)
async def get_fee(self) -> float: fee = await self._call_async(self.contract.functions.getSwapFee()) return BigNumber.from_value(fee).to_number()