Example #1
0
class TestToken:
    def setup_class(self):
        self.token = Token(
            "COW", Address('0xbeef00000000000000000000000000000000BEEF'), 4)

    def test_convert(self):
        # two
        chain_amount = Wad(20000)
        assert self.token.normalize_amount(chain_amount) == Wad.from_number(2)

        # three
        normalized_amount = Wad.from_number(3)
        assert self.token.unnormalize_amount(normalized_amount) == Wad(30000)

    def test_min_amount(self):
        assert self.token.min_amount == Wad.from_number(0.0001)
        assert float(self.token.min_amount) == 0.0001
        assert self.token.unnormalize_amount(self.token.min_amount) == Wad(1)

        assert Wad.from_number(0.0004) > self.token.min_amount
        assert Wad.from_number(0.00005) < self.token.min_amount

        assert self.token.unnormalize_amount(
            Wad.from_number(0.0006)) > self.token.unnormalize_amount(
                self.token.min_amount)
        assert self.token.unnormalize_amount(
            Wad.from_number(0.00007)) < self.token.unnormalize_amount(
                self.token.min_amount)
        assert self.token.unnormalize_amount(
            Wad.from_number(0.00008)) == Wad(0)
Example #2
0
 def set_and_approve_pair_token(self, pair_address: Address):
     self.pair_address = pair_address
     self._pair_contract = self._get_contract(self.web3,
                                              self.pair_abi['abi'],
                                              self.pair_address)
     self.pair_token = Token('Liquidity', self.pair_address, 18)
     self.is_new_pool = False
Example #3
0
    def get_exchange_balance(self, token: Token, pair_address: Address) -> Wad:
        assert (isinstance(token, Token))
        assert (isinstance(pair_address, Address))

        return token.normalize_amount(
            ERC20Token(web3=self.web3,
                       address=token.address).balance_of(pair_address))
    def setup_method(self):

        # Use Ganache docker container
        self.web3 = Web3(HTTPProvider("http://0.0.0.0:8555"))
        self.web3.eth.defaultAccount = Web3.toChecksumAddress(
            "0x9596C16D7bF9323265C2F2E22f43e6c80eB3d943")
        register_private_key(
            self.web3,
            "0x91cf2cc3671a365fcbf38010ff97ee31a5b7e674842663c56769e41600696ead"
        )

        self.our_address = Address(self.web3.eth.defaultAccount)

        self.weth_address = self._deploy(self.web3, self.weth_abi,
                                         self.weth_bin, [])
        self.factory_address = self._deploy(self.web3, self.factory_abi,
                                            self.factory_bin,
                                            [self.our_address.address])
        self.router_address = self._deploy(
            self.web3, self.router_abi, self.router_bin,
            [self.factory_address.address, self.weth_address.address])
        self._weth_contract = self._get_contract(self.web3, self.weth_abi,
                                                 self.weth_address)

        self.ds_systemcoin = DSToken.deploy(self.web3, 'SystemCoin', 'sys')
        self.ds_usdc = DSToken.deploy(self.web3, 'USDC', 'USDC')
        self.token_systemcoin = Token("SystemCoin", self.ds_systemcoin.address,
                                      18)
        self.token_usdc = Token("USDC", self.ds_usdc.address, 6)
        self.token_weth = Token("WETH", self.weth_address, 18)

        self.systemcoin_usdc_uniswap = UniswapV2(
            self.web3, self.token_systemcoin, self.token_usdc,
            self.our_address, self.router_address, self.factory_address)
        self.systemcoin_eth_uniswap = UniswapV2(
            self.web3, self.token_systemcoin, self.token_weth,
            self.our_address, self.router_address, self.factory_address)

        ## Useful for debugging failing transactions
        logger = logging.getLogger('eth')
        logger.setLevel(8)
Example #5
0
# reduce logspew
logging.getLogger('urllib3').setLevel(logging.INFO)
logging.getLogger("web3").setLevel(logging.INFO)
logging.getLogger("asyncio").setLevel(logging.INFO)
logging.getLogger("requests").setLevel(logging.INFO)

# Usage:
# python3 tests/manual_test_create_unsafe_vault [ADDRESS] [KEY] [COLLATERAL_TYPE]

geb = GfDeployment.from_node(web3, 'rai')
our_address = Address(web3.eth.defaultAccount)
collateral = geb.collaterals[str(
    sys.argv[3])] if len(sys.argv) > 3 else geb.collaterals['ETH-A']
collateral_type = geb.safe_engine.collateral_type(
    collateral.collateral_type.name)
token = Token(collateral.collateral.symbol(), collateral.collateral.address,
              collateral.adapter.decimals())
safe = geb.safe_engine.safe(collateral.collateral_type, our_address)
# geb.approve_system_coin(our_address)
# Transact.gas_estimate_for_bad_txs = 20000
osm_price = collateral.osm.peek()
redemption_price = geb.oracle_relayer.redemption_price()
action = sys.argv[4] if len(sys.argv) > 4 else "create"


def r(value, decimals=1):
    return round(float(value), decimals)


logging.info(
    f"{collateral_type.name:<6}: debt_floor={r(collateral_type.debt_floor)} osm_price={osm_price} safety_ratio={r(geb.oracle_relayer.safety_c_ratio(collateral_type))}"
)
class TestUniswapV2(Contract):
    """
    In order to run automated tests locally, all dependent contracts and deployable bytecode need to be available for deploying contract to local network. 
    Deployable bytecode differs from the runtime bytecode you would see on Etherscan.

    """
    pair_abi = Contract._load_abi(__name__,
                                  '../pyexchange/abi/IUniswapV2Pair.abi')
    Irouter_abi = Contract._load_abi(
        __name__, '../pyexchange/abi/IUniswapV2Router02.abi')['abi']
    router_abi = Contract._load_abi(__name__,
                                    '../pyexchange/abi/UniswapV2Router02.abi')
    router_bin = Contract._load_bin(__name__,
                                    '../pyexchange/abi/UniswapV2Router02.bin')
    factory_abi = Contract._load_abi(__name__,
                                     '../pyexchange/abi/UniswapV2Factory.abi')
    factory_bin = Contract._load_bin(__name__,
                                     '../pyexchange/abi/UniswapV2Factory.bin')
    weth_abi = Contract._load_abi(__name__, '../pyexchange/abi/WETH.abi')
    weth_bin = Contract._load_bin(__name__, '../pyexchange/abi/WETH.bin')

    def setup_method(self):

        # Use Ganache docker container
        self.web3 = Web3(HTTPProvider("http://0.0.0.0:8555"))
        self.web3.eth.defaultAccount = Web3.toChecksumAddress(
            "0x9596C16D7bF9323265C2F2E22f43e6c80eB3d943")
        register_private_key(
            self.web3,
            "0x91cf2cc3671a365fcbf38010ff97ee31a5b7e674842663c56769e41600696ead"
        )

        self.our_address = Address(self.web3.eth.defaultAccount)

        self.weth_address = self._deploy(self.web3, self.weth_abi,
                                         self.weth_bin, [])
        self.factory_address = self._deploy(self.web3, self.factory_abi,
                                            self.factory_bin,
                                            [self.our_address.address])
        self.router_address = self._deploy(
            self.web3, self.router_abi, self.router_bin,
            [self.factory_address.address, self.weth_address.address])
        self._weth_contract = self._get_contract(self.web3, self.weth_abi,
                                                 self.weth_address)

        self.ds_systemcoin = DSToken.deploy(self.web3, 'SystemCoin', 'sys')
        self.ds_usdc = DSToken.deploy(self.web3, 'USDC', 'USDC')
        self.token_systemcoin = Token("SystemCoin", self.ds_systemcoin.address,
                                      18)
        self.token_usdc = Token("USDC", self.ds_usdc.address, 6)
        self.token_weth = Token("WETH", self.weth_address, 18)

        self.systemcoin_usdc_uniswap = UniswapV2(
            self.web3, self.token_systemcoin, self.token_usdc,
            self.our_address, self.router_address, self.factory_address)
        self.systemcoin_eth_uniswap = UniswapV2(
            self.web3, self.token_systemcoin, self.token_weth,
            self.our_address, self.router_address, self.factory_address)

        ## Useful for debugging failing transactions
        logger = logging.getLogger('eth')
        logger.setLevel(8)
        # Transact.gas_estimate_for_bad_txs = 210000

    def add_liquidity_tokens(self) -> Receipt:
        self.ds_systemcoin.mint(Wad(
            17 * 10**18)).transact(from_address=self.our_address)
        self.ds_usdc.mint(
            self.token_usdc.unnormalize_amount(
                Wad.from_number(9))).transact(from_address=self.our_address)
        self.systemcoin_usdc_uniswap.approve(self.token_systemcoin)
        self.systemcoin_usdc_uniswap.approve(self.token_usdc)

        add_liquidity_tokens_args = {
            "amount_a_desired":
            Wad.from_number(1.9),
            "amount_b_desired":
            self.token_usdc.unnormalize_amount(Wad.from_number(2.0)),
            "amount_a_min":
            Wad.from_number(1.8),
            "amount_b_min":
            self.token_usdc.unnormalize_amount(Wad.from_number(1.9))
        }

        return self.systemcoin_usdc_uniswap.add_liquidity(
            add_liquidity_tokens_args, self.token_systemcoin,
            self.token_usdc).transact(from_address=self.our_address)

    def add_liquidity_eth(self) -> Receipt:
        self.ds_systemcoin.mint(Wad(
            300 * 10**18)).transact(from_address=self.our_address)
        self.systemcoin_eth_uniswap.approve(self.token_systemcoin)
        self.systemcoin_eth_uniswap.approve(self.token_weth)

        add_liquidity_eth_args = {
            "amount_b_desired": Wad.from_number(28),
            "amount_a_desired": Wad.from_number(.1),
            "amount_b_min": Wad.from_number(25),
            "amount_a_min": Wad.from_number(0.01)
        }

        return self.systemcoin_eth_uniswap.add_liquidity_eth(
            add_liquidity_eth_args, self.token_systemcoin,
            0).transact(from_address=self.our_address)

    def test_approval(self):
        # given
        assert self.ds_systemcoin.allowance_of(self.our_address,
                                               self.router_address) == Wad(0)

        # when
        self.systemcoin_usdc_uniswap.approve(self.token_systemcoin)

        # then
        assert self.ds_systemcoin.allowance_of(self.our_address,
                                               self.router_address) > Wad(0)

    def test_getting_token_balances(self):
        # given
        self.ds_systemcoin.mint(Wad(17 * 10**18)).transact()
        self.ds_usdc.mint(
            self.token_usdc.unnormalize_amount(Wad.from_number(9))).transact()

        # when
        balance_systemcoin = self.systemcoin_usdc_uniswap.get_account_token_balance(
            self.token_systemcoin)
        balance_usdc = self.systemcoin_usdc_uniswap.get_account_token_balance(
            self.token_usdc)

        # then
        assert balance_systemcoin == Wad.from_number(17)
        assert balance_usdc == Wad.from_number(9)

    def test_add_liquidity_tokens(self):
        # when
        add_liquidity = self.add_liquidity_tokens()

        # then
        assert add_liquidity.successful == True

        # when
        self.systemcoin_usdc_uniswap.set_and_approve_pair_token(
            self.systemcoin_usdc_uniswap.get_pair_address(
                self.token_systemcoin.address, self.token_usdc.address))

        # then
        assert self.systemcoin_usdc_uniswap.get_current_liquidity(
        ) > Wad.from_number(0)

    def test_add_liquidity_eth(self):
        # when
        add_liquidity_eth = self.add_liquidity_eth()

        # then
        assert add_liquidity_eth.successful == True

        # when
        self.systemcoin_eth_uniswap.set_and_approve_pair_token(
            self.systemcoin_usdc_uniswap.get_pair_address(
                self.token_systemcoin.address, self.token_weth.address))

        # then
        assert self.systemcoin_eth_uniswap.get_current_liquidity(
        ) > Wad.from_number(0)

    def test_remove_liquidity_tokens(self):
        # given
        add_liquidity = self.add_liquidity_tokens()
        self.systemcoin_usdc_uniswap.set_and_approve_pair_token(
            self.systemcoin_usdc_uniswap.get_pair_address(
                self.token_systemcoin.address, self.token_usdc.address))

        current_liquidity = self.systemcoin_usdc_uniswap.get_current_liquidity(
        )
        total_liquidity = self.systemcoin_usdc_uniswap.get_total_liquidity()
        systemcoin_exchange_balance = self.systemcoin_usdc_uniswap.get_exchange_balance(
            self.token_systemcoin, self.systemcoin_usdc_uniswap.pair_address)
        usdc_exchange_balance = self.token_usdc.unnormalize_amount(
            self.systemcoin_usdc_uniswap.get_exchange_balance(
                self.token_usdc, self.systemcoin_usdc_uniswap.pair_address))

        # then
        assert current_liquidity > Wad.from_number(0)
        assert total_liquidity > Wad.from_number(0)
        assert total_liquidity > current_liquidity

        # given
        amount_a_min = current_liquidity * systemcoin_exchange_balance / total_liquidity
        amount_b_min = current_liquidity * usdc_exchange_balance / total_liquidity
        remove_liquidity_tokens_args = {
            "liquidity": current_liquidity,
            "amountAMin": amount_a_min,
            "amountBMin": amount_b_min
        }

        # when
        remove_liquidity = self.systemcoin_usdc_uniswap.remove_liquidity(
            remove_liquidity_tokens_args, self.token_systemcoin,
            self.token_usdc).transact(from_address=self.our_address)

        # then
        assert remove_liquidity.successful == True
        assert self.systemcoin_usdc_uniswap.get_current_liquidity(
        ) == Wad.from_number(0)

    def test_remove_liquidity_eth(self):
        # given
        add_liquidity_eth = self.add_liquidity_eth()
        self.systemcoin_eth_uniswap.set_and_approve_pair_token(
            self.systemcoin_eth_uniswap.get_pair_address(
                self.token_systemcoin.address, self.token_weth.address))

        current_liquidity = self.systemcoin_eth_uniswap.get_current_liquidity()
        total_liquidity = self.systemcoin_eth_uniswap.get_total_liquidity()
        systemcoin_exchange_balance = self.systemcoin_eth_uniswap.get_exchange_balance(
            self.token_systemcoin, self.systemcoin_eth_uniswap.pair_address)
        weth_exchange_balance = self.systemcoin_eth_uniswap.get_exchange_balance(
            self.token_weth, self.systemcoin_eth_uniswap.pair_address)

        # then
        assert current_liquidity > Wad.from_number(0)
        assert total_liquidity > Wad.from_number(0)
        assert total_liquidity > current_liquidity

        # given
        amount_a_min = current_liquidity * weth_exchange_balance / total_liquidity
        amount_b_min = current_liquidity * systemcoin_exchange_balance / total_liquidity
        remove_liquidity_eth_args = {
            "liquidity": current_liquidity,
            "amountBMin": amount_b_min,
            "amountAMin": amount_a_min
        }

        # when
        remove_liquidity = self.systemcoin_eth_uniswap.remove_liquidity_eth(
            remove_liquidity_eth_args, self.token_systemcoin,
            0).transact(from_address=self.our_address)

        # then
        assert remove_liquidity.successful == True
        assert self.systemcoin_eth_uniswap.get_current_liquidity(
        ) == Wad.from_number(0)

    def test_tokens_swap(self):
        # given
        add_liquidity = self.add_liquidity_tokens()

        balance_systemcoin_before_swap = self.systemcoin_usdc_uniswap.get_account_token_balance(
            self.token_systemcoin)
        balance_usdc_before_swap = self.systemcoin_usdc_uniswap.get_account_token_balance(
            self.token_usdc)

        # when
        swap = self.systemcoin_usdc_uniswap.swap_exact_tokens_for_tokens(
            Wad.from_number(.2),
            self.token_usdc.unnormalize_amount(Wad.from_number(.01)),
            [self.ds_systemcoin.address.address, self.ds_usdc.address.address
             ]).transact(from_address=self.our_address)

        # then
        assert swap.successful == True

        balance_systemcoin_after_swap = self.systemcoin_usdc_uniswap.get_account_token_balance(
            self.token_systemcoin)
        balance_usdc_after_swap = self.systemcoin_usdc_uniswap.get_account_token_balance(
            self.token_usdc)

        assert balance_systemcoin_after_swap < balance_systemcoin_before_swap
        assert balance_usdc_before_swap < balance_usdc_after_swap
Example #7
0
    def get_account_token_balance(self, token: Token) -> Wad:
        assert (isinstance(token, Token))

        return token.normalize_amount(
            ERC20Token(web3=self.web3,
                       address=token.address).balance_of(self.account_address))
Example #8
0
WETH_KOVAN_ADDRESS = Address("0xd0a1e359811322d97991e03f863a0c30c2cf029c")
DAI_ADDRESS = Address("0x6B175474E89094C44Da98b954EedeAC495271d0F")
DAI_KOVAN_ADDRESS = Address("0x4f96fe3b7a6cf9725f59d353f723c1bdb64ca6aa")
USDC_ADDRESS = Address("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48")
MKR_ADDRESS = Address("0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2")
MKR_KOVAN_ADDRESS = Address("0xAaF64BFCC32d0F15873a02163e7E500671a4ffcD")
FACTORY_ADDRESS = Address("0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f")
ROUTER_ADDRESS = Address("0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D")

web3 = Web3(HTTPProvider(sys.argv[1], request_kwargs={"timeout": 600}))
web3.eth.defaultAccount = sys.argv[2]
register_key(web3, sys.argv[3])

Transact.gas_estimate_for_bad_txs = 210000

dai = Token("DAI", DAI_KOVAN_ADDRESS, 18)
weth_kovan = Token("WETH", WETH_KOVAN_ADDRESS, 18)
weth_mainnet = Token("WETH", WETH_ADDRESS, 18)
usdc_kovan = Token("USDC", USDC_KOVAN_ADDRESS, 6)
usdc_mainnet = Token("USDC", USDC_MAINNET_ADDRESS, 6)

wbtc = Token('WBTC', Address("0xe0c9275e44ea80ef17579d33c55136b7da269aeb"), 8)
uniswap = UniswapV2(web3, dai, weth_kovan)

dai_weth_pair = Token("POOL", uniswap.get_pair_address(DAI_KOVAN_ADDRESS, WETH_KOVAN_ADDRESS), 18)
# uniswap.approve(wbtc, web3.toWei(5, 'ether'))
# uniswap.approve(weth, web3.toWei(5, 'ether'))



# amounts_in = uniswap.get_amounts_in(web3.toWei(0.5, 'ether'), [DAI_KOVAN_ADDRESS.address, MKR_KOVAN_ADDRESS.address])
Example #9
0
 def setup_class(self):
     self.token = Token(
         "COW", Address('0xbeef00000000000000000000000000000000BEEF'), 4)
Example #10
0
def create_almost_risky_safe(geb: GfDeployment,
                             c: Collateral,
                             collateral_amount: Wad,
                             auction_income_recipient_address: Address,
                             draw_system_coin=True) -> SAFE:
    assert isinstance(geb, GfDeployment)
    assert isinstance(c, Collateral)
    assert isinstance(auction_income_recipient_address, Address)
    logging.debug("Creating almost risky safe")
    print("create_almost_risky")
    print(
        f"Liquidation price {geb.safe_engine.collateral_type(c.collateral_type.name).safety_price}"
    )
    print(
        f"Safety price {geb.safe_engine.collateral_type(c.collateral_type.name).liquidation_price}"
    )

    # Ensure vault isn't already unsafe (if so, this shouldn't be called)
    safe = geb.safe_engine.safe(c.collateral_type,
                                auction_income_recipient_address)
    assert is_safe_safe(
        geb.safe_engine.collateral_type(c.collateral_type.name), safe)

    # Add collateral to auction_income_recipient vault if necessary
    c.approve(auction_income_recipient_address)
    token = Token(c.collateral_type.name, c.collateral.address,
                  c.adapter.decimals())
    print(
        f"collateral_amount={collateral_amount} locked_collateral={safe.locked_collateral}"
    )
    delta_collateral = collateral_amount - safe.locked_collateral
    if delta_collateral > Wad(0):
        safe_engine_balance = geb.safe_engine.token_collateral(
            c.collateral_type, auction_income_recipient_address)
        balance = token.normalize_amount(
            c.collateral.balance_of(auction_income_recipient_address))
        print(
            f"before join: delta_collateral={delta_collateral} safe_engine_balance={safe_engine_balance} balance={balance} safe_engine_gap={delta_collateral - safe_engine_balance}"
        )
        if safe_engine_balance < delta_collateral:
            safe_engine_gap = delta_collateral - safe_engine_balance
            if balance < safe_engine_gap:
                if c.collateral_type.name.startswith("ETH"):
                    wrap_eth(geb, auction_income_recipient_address,
                             safe_engine_gap)
                else:
                    raise RuntimeError("Insufficient collateral balance")
            amount_to_join = token.unnormalize_amount(safe_engine_gap)
            if amount_to_join == Wad(
                    0):  # handle dusty balances with non-18-decimal tokens
                amount_to_join += token.unnormalize_amount(token.min_amount)
            assert c.adapter.join(
                auction_income_recipient_address, amount_to_join).transact(
                    from_address=auction_income_recipient_address)
        safe_engine_balance = geb.safe_engine.token_collateral(
            c.collateral_type, auction_income_recipient_address)
        print(
            f"after join: delta_collateral={delta_collateral} safe_engine_balance={safe_engine_balance} balance={balance} safe_engine_gap={delta_collateral - safe_engine_balance}"
        )
        assert safe_engine_balance >= delta_collateral
        assert geb.safe_engine.modify_safe_collateralization(
            c.collateral_type, auction_income_recipient_address,
            delta_collateral,
            Wad(0)).transact(from_address=auction_income_recipient_address)

    # Put auction_income_recipient SAFE at max possible debt
    delta_debt = max_delta_debt(geb, c,
                                auction_income_recipient_address) - Wad(1)
    if delta_debt > Wad(0):
        print(
            f"Attempting to modify safe collateralization with delta_debt={delta_debt}"
        )
        assert geb.safe_engine.modify_safe_collateralization(
            c.collateral_type, auction_income_recipient_address, Wad(0),
            delta_debt).transact(from_address=auction_income_recipient_address)

    # Draw our Dai, simulating the usual behavior
    safe = geb.safe_engine.safe(c.collateral_type,
                                auction_income_recipient_address)
    if draw_system_coin and safe.generated_debt > Wad(0):
        geb.approve_system_coin(auction_income_recipient_address)
        assert geb.system_coin_adapter.exit(
            auction_income_recipient_address, safe.generated_debt).transact(
                from_address=auction_income_recipient_address)
        print(f"Exited {safe.generated_debt} System coin from safe")

    logging.debug("Almost risky safe created")