Пример #1
0
def test_calcPoolOutGivenSingleIn_base(network, alice_wallet):
    """Tests calculations with calcPoolOutGivenSingleIn."""
    pool = _deployBPool(network, alice_wallet)
    x = pool.calcPoolOutGivenSingleIn(
        tokenBalanceIn_base=to_base_18(10.0),
        tokenWeightIn_base=to_base_18(1.0),
        poolSupply_base=to_base_18(120.0),
        totalWeight_base=to_base_18(2.0),
        tokenAmountIn_base=to_base_18(0.1),
        swapFee_base=0,
    )
    assert round(from_base_18(x), 3) == 0.599
Пример #2
0
def test_calcSingleOutGivenPoolIn_base(network, alice_wallet):
    """Tests pricing with calcSingleOutGivenPoolIn."""
    pool = _deployBPool(network, alice_wallet)
    x = pool.calcSingleOutGivenPoolIn(
        tokenBalanceOut_base=to_base_18(10.0),
        tokenWeightOut_base=to_base_18(1.0),
        poolSupply_base=to_base_18(120.0),
        totalWeight_base=to_base_18(2.0),
        poolAmountIn_base=to_base_18(10.0),
        swapFee_base=0,
    )
    assert round(from_base_18(x), 3) == 1.597
Пример #3
0
def test_calcInGivenOut_base(network, alice_wallet):
    """Tests pricing with calcInGivenOut."""
    pool = _deployBPool(network, alice_wallet)
    x = pool.calcInGivenOut(
        tokenBalanceIn_base=to_base_18(10.0),
        tokenWeightIn_base=to_base_18(1.0),
        tokenBalanceOut_base=to_base_18(10.1),
        tokenWeightOut_base=to_base_18(1.0),
        tokenAmountOut_base=to_base_18(1.0),
        swapFee_base=0,
    )
    assert round(from_base_18(x), 3) == 1.099
Пример #4
0
 def calcSingleOutGivenPoolIn(self, pool_address: str,
                              token_out_address: str, pool_shares: float):
     pool = BPool(pool_address)
     return from_base_18(
         pool.calcSingleInGivenPoolOut(
             pool.getBalance(token_out_address),
             pool.getDenormalizedWeight(token_out_address),
             pool.totalSupply(),
             pool.getTotalDenormalizedWeight(),
             to_base_18(pool_shares),
             pool.getSwapFee(),
         ))
Пример #5
0
def test_calcPoolInGivenSingleOut_base(network, alice_wallet):
    """Tests calculations with calcPoolInGivenSingleOut."""
    pool = _deployBPool(network, alice_wallet)
    x = pool.calcPoolInGivenSingleOut(
        tokenBalanceOut_base=to_base_18(1000.0),
        tokenWeightOut_base=to_base_18(5.0),
        poolSupply_base=to_base_18(100.0),
        totalWeight_base=to_base_18(10.0),
        tokenAmountOut_base=to_base_18(0.1),
        swapFee_base=0,
    )
    assert round(from_base_18(x), 3) == 0.005
Пример #6
0
 def calcPoolOutGivenSingleIn(self, pool_address: str,
                              token_in_address: str,
                              token_in_amount: float):
     pool = BPool(pool_address)
     return from_base_18(
         pool.calcPoolOutGivenSingleIn(
             pool.getBalance(token_in_address),
             pool.getDenormalizedWeight(token_in_address),
             pool.totalSupply(),
             pool.getTotalDenormalizedWeight(),
             to_base_18(token_in_amount),
             pool.getSwapFee(),
         ))
Пример #7
0
    def get_token_price(self, pool_address: str) -> float:
        """

        :param pool_address: str the address of the pool contract
        :return: int price of data token in terms of OCEAN tokens
        """
        dtoken_address = self.get_token_address(pool_address)
        pool = BPool(pool_address)
        return from_base_18(
            pool.getSpotPrice(
                tokenIn_address=self.ocean_address, tokenOut_address=dtoken_address
            )
        )
Пример #8
0
def test_2tokens_basic(network, T1, T2, alice_wallet, alice_address):
    pool = _deployBPool(network, alice_wallet)
    assert T1.address != T2.address
    assert T1.address != pool.address

    assert from_base_18(T1.balanceOf(alice_address)) >= 90.0
    _ = from_base_18(T2.balanceOf(alice_address)) >= 10.0

    with pytest.raises(Exception):  # can't bind until we approve
        pool.bind(
            T1.address, to_base_18(90.0), to_base_18(9.0), from_wallet=alice_wallet
        )

    # Bind two tokens to the pool
    T1.approve(pool.address, to_base_18(90.0), from_wallet=alice_wallet)
    T2.approve(pool.address, to_base_18(10.0), from_wallet=alice_wallet)

    assert from_base_18(T1.allowance(alice_address, pool.address)) == 90.0
    assert from_base_18(T2.allowance(alice_address, pool.address)) == 10.0

    assert not pool.isBound(T1.address) and not pool.isBound(T1.address)
    pool.bind(T1.address, to_base_18(90.0), to_base_18(9.0), from_wallet=alice_wallet)
    pool.bind(T2.address, to_base_18(10.0), to_base_18(1.0), from_wallet=alice_wallet)
    assert pool.isBound(T1.address) and pool.isBound(T2.address)

    assert pool.getNumTokens() == 2
    assert pool.getCurrentTokens() == [T1.address, T2.address]

    assert pool.getDenormalizedWeight(T1.address) == to_base_18(9.0)
    assert pool.getDenormalizedWeight(T2.address) == to_base_18(1.0)
    assert pool.getTotalDenormalizedWeight() == to_base_18(9.0 + 1.0)

    assert pool.getNormalizedWeight(T1.address) == to_base_18(0.9)
    assert pool.getNormalizedWeight(T2.address) == to_base_18(0.1)

    assert pool.getBalance(T1.address) == to_base_18(90.0)
    assert pool.getBalance(T2.address) == to_base_18(10.0)

    assert str(pool)
Пример #9
0
def get_liquidity_history(poolAddress):
    """

    :param poolAddress:
    :return: json object with two keys: `ocean` and `datatoken`
      each has a list of datapoints sampled at specific time intervals from the pools liquidity history.
    """
    try:
        result = dict()
        ocean = Ocean(ConfigProvider.get_config())
        pool = BPool(poolAddress)
        dt_address = ocean.pool.get_token_address(poolAddress,
                                                  pool,
                                                  validate=False)
        swap_fee = from_base_18(pool.getSwapFee())
        ocn_weight = from_base_18(
            pool.getDenormalizedWeight(ocean.OCEAN_address))
        dt_weight = from_base_18(pool.getDenormalizedWeight(dt_address))

        ocn_add_remove_list, dt_add_remove_list = ocean.pool.get_liquidity_history(
            poolAddress)
        ocn_add_remove_list = [(v, int(t)) for v, t in ocn_add_remove_list]
        dt_add_remove_list = [(v, int(t)) for v, t in dt_add_remove_list]

        ocn_reserve_history, dt_reserve_history, price_history = build_liquidity_and_price_history(
            ocn_add_remove_list, dt_add_remove_list, ocn_weight, dt_weight,
            swap_fee)

        result['oceanAddRemove'] = ocn_add_remove_list
        result['datatokenAddRemove'] = dt_add_remove_list
        result['oceanReserveHistory'] = ocn_reserve_history
        result['datatokenReserveHistory'] = dt_reserve_history
        result['datatokenPriceHistory'] = price_history
        return Response(json.dumps(result),
                        200,
                        content_type='application/json')
    except Exception as e:
        logger.error(f'pools/history/{poolAddress}: {str(e)}', exc_info=1)
        return f'Get pool liquidity/price history failed: {str(e)}', 500
Пример #10
0
def test_joinSwapExternAmountIn(network, T1, T2, alice_wallet, alice_address):
    """Tests adding an external amount inside a pool.

    When the pool is not public, assert that an Exception is thrown.
    When the pool is public, assert that the swap is made and the correct balance remains.
    """
    init_T1balance = from_base_18(T1.balanceOf(alice_address))
    T2balance = from_base_18(T2.balanceOf(alice_address))
    pool = _createPoolWith2Tokens(network, T1, T2, alice_wallet, 90.0, 10.0,
                                  9.0, 1.0)
    T1.approve(pool.address, to_base_18(100.0), from_wallet=alice_wallet)

    # pool's not public
    with pytest.raises(Exception):
        pool.swapExactAmountOut(
            tokenIn_address=T1.address,
            maxAmountIn_base=to_base_18(100.0),
            tokenOut_address=T2.address,
            tokenAmountOut_base=to_base_18(10.0),
            maxPrice_base=HUGEINT,
            from_wallet=alice_wallet,
        )

    # pool's public
    pool.setPublicSwap(True, from_wallet=alice_wallet)
    pool.swapExactAmountOut(
        tokenIn_address=T1.address,
        maxAmountIn_base=to_base_18(100.0),
        tokenOut_address=T2.address,
        tokenAmountOut_base=to_base_18(1.0),
        maxPrice_base=HUGEINT,
        from_wallet=alice_wallet,
    )
    new_balance = init_T1balance - 91.055
    assert ((new_balance - 0.005) <= from_base_18(T1.balanceOf(alice_address))
            <= (new_balance + 0.005))
    assert from_base_18(T2.balanceOf(alice_address)) == (T2balance - 9.0)
Пример #11
0
    def _get_fixedrateexchange_price(self,
                                     dt_address,
                                     owner=None,
                                     exchange_id=None):
        fre = self.ex_contract
        try:
            if not exchange_id:
                assert owner is not None, 'owner is required when `exchange_id` is not given.'
                exchange_id = add_0x_prefix(
                    fre.generateExchangeId(self._checksum_ocean, dt_address,
                                           owner).hex())

            ex_data = fre.getExchange(exchange_id)
            if not ex_data or not ex_data.exchangeOwner:
                return None, None

            price = from_base_18(ex_data.fixedRate)
            supply = from_base_18(ex_data.supply)
            return price, supply
        except Exception as e:
            logger.error(
                f'Reading exchange price failed for datatoken {dt_address}, '
                f'owner {owner}, exchangeId {exchange_id}: {e}')
            return None, None
Пример #12
0
 def calculate_token_holders(
     self, from_block: int, to_block: int, min_token_amount: float
 ) -> List[Tuple[str, float]]:
     """Returns a list of addresses with token balances above a minimum token
     amount. Calculated from the transactions between `from_block` and `to_block`."""
     all_transfers, _ = self.get_all_transfers_from_events(from_block, to_block)
     balances_above_threshold = []
     balances = DataToken.calculate_balances(all_transfers)
     _min = to_base_18(min_token_amount)
     balances_above_threshold = sorted(
         [(a, from_base_18(b)) for a, b in balances.items() if b > _min],
         key=lambda x: x[1],
         reverse=True,
     )
     return balances_above_threshold
Пример #13
0
def test_ERC20(alice_ocean, alice_wallet, alice_address, bob_wallet,
               bob_address):
    """Tests DataToken minting, allowance and transfer."""
    token = alice_ocean.create_data_token("DataToken1",
                                          "DT1",
                                          from_wallet=alice_wallet,
                                          blob="foo_blob")
    assert token.datatoken_name() == "DataToken1"
    assert token.symbol()[:2] == "DT"
    assert token.decimals() == 18

    assert token.balanceOf(alice_address) == 0
    assert token.totalSupply() == 0

    token.mint(alice_address, to_base_18(100.0), from_wallet=alice_wallet)
    assert from_base_18(token.balanceOf(alice_address)) == 100.0

    assert token.allowance(alice_address, bob_address) == 0
    token.approve(bob_address, to_base_18(1.0), from_wallet=alice_wallet)
    assert token.allowance(alice_address, bob_address) == int(1e18)
    token.increaseAllowance(bob_address,
                            to_base_18(1.0),
                            from_wallet=alice_wallet)
    assert token.allowance(alice_address, bob_address) == int(2e18)
    token.decreaseAllowance(bob_address,
                            to_base_18(1.0),
                            from_wallet=alice_wallet)
    assert token.allowance(alice_address, bob_address) == int(1e18)
    token.transferFrom(alice_address,
                       bob_address,
                       to_base_18(1.0),
                       from_wallet=bob_wallet)
    assert from_base_18(token.balanceOf(alice_address)) == 99.0
    assert from_base_18(token.balanceOf(bob_address)) == 1.0

    token.transfer(bob_address, to_base_18(5.0), from_wallet=alice_wallet)
    assert from_base_18(token.balanceOf(alice_address)) == 94.0
    assert from_base_18(token.balanceOf(bob_address)) == 6.0

    token.transfer(alice_address, to_base_18(3.0), from_wallet=bob_wallet)
    assert from_base_18(token.balanceOf(alice_address)) == 97.0
    assert from_base_18(token.balanceOf(bob_address)) == 3.0

    # assert transfers were successful
    block = alice_ocean.web3.eth.blockNumber
    all_transfers = token.get_all_transfers_from_events(block - 2,
                                                        block + 1,
                                                        chunk=1)
    assert len(all_transfers[0]) == 3
Пример #14
0
 def calcOutGivenIn(
     self,
     pool_address: str,
     token_in_address: str,
     token_out_address: str,
     token_in_amount: float,
 ):
     pool = BPool(pool_address)
     out_amount = pool.calcOutGivenIn(
         pool.getBalance(token_in_address),
         pool.getDenormalizedWeight(token_in_address),
         pool.getBalance(token_out_address),
         pool.getDenormalizedWeight(token_out_address),
         to_base_18(token_in_amount),
         pool.getSwapFee(),
     )
     return from_base_18(out_amount)
Пример #15
0
def test_status_functions(alice_ocean, alice_wallet, alice_address):
    """Tests various status functions of the DataToken class."""
    token = alice_ocean.create_data_token("DataToken1",
                                          "DT1",
                                          from_wallet=alice_wallet,
                                          blob="foo_blob")

    token.mint(alice_address, to_base_18(100.0), from_wallet=alice_wallet)

    assert from_base_18(token.balanceOf(alice_address)) == 100.0
    assert token.totalSupply() == 100_000_000_000_000_000_000
    assert token.cap() == 1_000_000_000_000_000_000_000
    assert token.datatoken_name() == "DataToken1"
    assert token.minter() == alice_address
    assert token.isMinter(alice_address)
    with pytest.raises(ValueError):
        token.get_event_signature("not a registered event")
Пример #16
0
    def _get_liquidity_and_price(self, pools, dt_address):
        assert pools, f'pools should not be empty, got {pools}'
        logger.debug(f' Searching {pools} for {dt_address}')
        dt_address_lower = dt_address.lower()
        pool_to_price = dict()
        for _pool in pools:
            try:
                pool = BPool(_pool)
                try:
                    ptokens = {a.lower() for a in pool.getCurrentTokens()}
                except Exception:
                    continue

                if self._OCEAN not in ptokens or dt_address_lower not in ptokens:
                    logger.debug(
                        f' ignore pool {_pool}, cannot find {self._OCEAN} and {dt_address_lower} in tokens list {ptokens}'
                    )
                    continue

                price = from_base_18(
                    pool.getSpotPrice(self._checksum_ocean, dt_address))
                if price <= 0.0 or price > self.PRICE_TOO_LARGE:
                    continue

                pool_to_price[_pool] = price
                logger.debug(f' Adding pool {_pool} with price {price}')

            except Exception as e:
                logger.error(
                    f'failed to get liquidity/price info from pool {_pool} and datatoken {dt_address}: {e}'
                )

        if pool_to_price:
            _pool = sorted(pool_to_price.items(), key=lambda x: x[1])[0][0]
            dt_reserve, ocn_reserve, price, _pool = self.get_pool_reserves_and_price(
                _pool, dt_address)
            return dt_reserve, ocn_reserve, price, _pool

        # no pool or no pool with price was found
        return 0.0, 0.0, 0.0, pools[0]
Пример #17
0
def test_joinswapPoolAmountOut(network, T1, T2, alice_address, alice_wallet):
    T1balance = from_base_18(T1.balanceOf(alice_address))
    pool = _createPoolWith2Tokens(network, T1, T2, alice_wallet, 90.0, 10.0, 9.0, 1.0)
    BPT = pool
    pool.finalize(from_wallet=alice_wallet)
    pool_balance = from_base_18(BPT.balanceOf(alice_address))
    T1.approve(pool.address, to_base_18(90.0), from_wallet=alice_wallet)
    assert from_base_18(T1.balanceOf(alice_address)) == (T1balance - 90)
    T1balance = from_base_18(T1.balanceOf(alice_address))
    pool.joinswapPoolAmountOut(
        tokenIn_address=T1.address,
        poolAmountOut_base=to_base_18(10.0),  # BPT wanted
        maxAmountIn_base=to_base_18(90.0),  # max T1 to spend
        from_wallet=alice_wallet,
    )
    assert from_base_18(T1.balanceOf(alice_address)) >= (T1balance - 90.0)
    assert from_base_18(BPT.balanceOf(alice_address)) == (pool_balance + 10.0)
Пример #18
0
def test_status_functions(alice_ocean, alice_wallet, alice_address):
    """Tests various status functions of the DataToken class."""
    token = alice_ocean.create_data_token(
        "DataToken1", "DT1", from_wallet=alice_wallet, blob="foo_blob"
    )

    token.mint(alice_address, to_base_18(100.0), from_wallet=alice_wallet)

    assert from_base_18(token.balanceOf(alice_address)) == 100.0
    assert token.totalSupply() == 100_000_000_000_000_000_000
    assert token.cap() == 1_000_000_000_000_000_000_000
    assert token.datatoken_name() == "DataToken1"
    block = alice_ocean.web3.eth.blockNumber
    token_info = token.get_info(
        alice_ocean.web3,
        from_block=(block - 1),
        to_block=(block + 1),
        include_holders=True,
    )
    assert len(token_info) == 11
    assert token_info["totalSupply"] == 100
    with pytest.raises(ValueError):
        token.get_event_signature("not a registered event")
Пример #19
0
    def get_all_pools(self,
                      from_block=0,
                      chunk_size=1000,
                      include_balance=False):
        web3 = Web3Provider.get_web3()
        current_block = web3.eth.blockNumber

        bfactory = BFactory(self.bfactory_address)
        logs = bfactory.get_event_logs('BPoolRegistered',
                                       from_block,
                                       current_block, {},
                                       web3=web3,
                                       chunk_size=chunk_size)
        if include_balance:
            pools = sorted([(l.args.bpoolAddress,
                             from_base_18(
                                 BPool(l.args.bpoolAddress).getBalance(
                                     self.ocean_address))) for l in logs],
                           key=lambda x: x[1],
                           reverse=True)
        else:
            pools = {l.args.bpoolAddress for l in logs}

        return pools
Пример #20
0
 def get_quote(self, amount: float, exchange_id: str):
     exchange = self._exchange_contract()
     amount_base = to_base_18(amount)
     ocean_amount_base = exchange.get_base_token_quote(
         exchange_id, amount_base)
     return from_base_18(ocean_amount_base)
Пример #21
0
def test_fixed_rate_exchange(
    alice_ocean, alice_wallet, T1, bob_wallet, T2, contracts_addresses
):
    """
    tests:
        create
        generateExchangeId
        getExchange
        getExchanges
        getNumberOfExchanges
        get_base_token_quote
        buy_data_token

    """
    base_unit = to_base_18(1.0)
    fixed_ex = FixedRateExchange(contracts_addresses[FixedRateExchange.CONTRACT_NAME])
    num_ex = fixed_ex.getNumberOfExchanges()
    assert num_ex == len(
        fixed_ex.getExchanges()
    ), "num exchanges do not match num of exchange ids."

    ocean_t = alice_ocean.OCEAN_address
    ocn_token = DataToken(ocean_t)
    # owner_wallet = get_ganache_wallet()
    # ocn_token.transfer_tokens(bob_wallet.address, 100, owner_wallet)
    assert ocn_token.token_balance(bob_wallet.address) >= 100, (
        f"bob wallet does not have the expected OCEAN tokens balance, "
        f"got {ocn_token.token_balance(bob_wallet.address)} instead of 100"
    )

    # clear any previous ocean token allowance for the exchange contract
    assert (
        ocn_token.get_tx_receipt(
            ocn_token.approve(fixed_ex.address, 1, bob_wallet)
        ).status
        == 1
    ), "approve failed"
    assert ocn_token.allowance(bob_wallet.address, fixed_ex.address) == 1, ""

    rate = to_base_18(0.1)
    tx_id = fixed_ex.create(ocean_t, T1.address, rate, alice_wallet)
    r = fixed_ex.get_tx_receipt(tx_id)
    assert r.status == 1, f"create fixed rate exchange failed: TxId {tx_id}."

    ex_id = fixed_ex.generateExchangeId(ocean_t, T1.address, alice_wallet.address).hex()
    ex_data = fixed_ex.getExchange(ex_id)
    expected_values = (alice_wallet.address, T1.address, ocean_t, rate, True, 0)
    assert ex_data == expected_values, (
        f"fixed rate exchange {ex_id} with values {ex_data} "
        f"does not match the expected values {expected_values}"
    )

    assert (
        fixed_ex.getNumberOfExchanges() == num_ex + 1
    ), f"Number of exchanges does not match, expected {num_ex+1} got {fixed_ex.getNumberOfExchanges()}."

    ###################
    # Test quote and buy datatokens
    amount = to_base_18(10.0)  # 10 data tokens
    base_token_quote = fixed_ex.get_base_token_quote(ex_id, amount)
    # quote = from_base_18(base_token_quote)
    assert base_token_quote == (
        amount * rate / base_unit
    ), f"quote does not seem correct: expected {amount*rate/base_unit}, got {base_token_quote}"
    assert from_base_18(base_token_quote) == 1.0, ""
    # buy without approving OCEAN tokens, should fail
    assert (
        run_failing_tx(fixed_ex, fixed_ex.buy_data_token, ex_id, amount, bob_wallet)
        == 0
    ), (
        f"buy_data_token/swap on EX {ex_id} is expected to fail but did not, "
        f"maybe the FixedRateExchange is already approved as spender for bob_wallet."
    )
    # approve ocean tokens, buying should still fail because datatokens are not approved by exchange owner
    assert (
        ocn_token.get_tx_receipt(
            ocn_token.approve(fixed_ex.address, base_token_quote, bob_wallet)
        ).status
        == 1
    ), "approve failed"
    assert (
        run_failing_tx(fixed_ex, fixed_ex.buy_data_token, ex_id, amount, bob_wallet)
        == 0
    ), (
        f"buy_data_token/swap on EX {ex_id} is expected to fail but did not, "
        f"maybe the FixedRateExchange is already approved as spender for bob_wallet."
    )

    # approve data token, now buying should succeed
    assert (
        T1.get_tx_receipt(T1.approve(fixed_ex.address, amount, alice_wallet)).status
        == 1
    ), "approve failed"
    assert (
        ocn_token.allowance(bob_wallet.address, fixed_ex.address) == base_token_quote
    ), ""
    tx_id = fixed_ex.buy_data_token(ex_id, amount, bob_wallet)
    r = fixed_ex.get_tx_receipt(tx_id)
    assert (
        r.status == 1
    ), f"buy_data_token/swap on EX {ex_id} failed with status 0: amount {amount}."
    # verify bob's datatokens balance
    assert T1.balanceOf(bob_wallet.address) == amount, (
        f"bobs datatoken balance is not right, "
        f"should be {amount}, got {T1.balanceOf(bob_wallet.address)}"
    )
    assert ocn_token.allowance(bob_wallet.address, fixed_ex.address) == 0, ""

    #####################
    # create another ex then do more tests
    rate2 = to_base_18(0.8)
    tx_id = fixed_ex.create(ocean_t, T2.address, rate2, alice_wallet)
    r = fixed_ex.get_tx_receipt(tx_id)
    assert r.status == 1, f"create fixed rate exchange failed: TxId {tx_id}."

    assert fixed_ex.getNumberOfExchanges() == num_ex + 2, (
        f"Number of exchanges does not match, "
        f"expected {num_ex+2} got {fixed_ex.getNumberOfExchanges()}."
    )

    t2_ex_id = fixed_ex.generateExchangeId(
        ocean_t, T2.address, alice_wallet.address
    ).hex()
    exchange_ids = {ti.hex() for ti in fixed_ex.getExchanges()}
    assert ex_id in exchange_ids, "exchange id not found."
    assert t2_ex_id in exchange_ids, "exchange id not found."

    ##############################
    # test activate/deactivate
    assert fixed_ex.isActive(ex_id) is True, f"exchange {ex_id} is not active."
    assert fixed_ex.isActive(t2_ex_id) is True, f"exchange {t2_ex_id} is not active."

    assert (
        run_failing_tx(fixed_ex, fixed_ex.deactivate, t2_ex_id, bob_wallet) == 0
    ), f"exchange {t2_ex_id} deactivate (using bob_wallet) should fail but did not."

    assert (
        fixed_ex.get_tx_receipt(fixed_ex.deactivate(t2_ex_id, alice_wallet)).status == 1
    ), f"exchange {t2_ex_id} deactivate failed."
    assert (
        fixed_ex.isActive(t2_ex_id) is False
    ), f"exchange {t2_ex_id} is active, but it should be deactivated."

    ###################################
    # try buying from deactivated ex
    amount = to_base_18(4.0)  # num data tokens
    base_token_quote = fixed_ex.get_base_token_quote(
        t2_ex_id, amount
    )  # num base token (OCEAN tokens
    assert base_token_quote == (
        amount * rate2 / base_unit
    ), f"quote does not seem correct: expected {amount*rate2/base_unit}, got {base_token_quote}"
    ocn_token.get_tx_receipt(
        ocn_token.approve(fixed_ex.address, base_token_quote, bob_wallet)
    )
    # buy should fail (deactivated exchange)
    assert (
        run_failing_tx(fixed_ex, fixed_ex.buy_data_token, t2_ex_id, amount, bob_wallet)
        == 0
    ), (
        f"buy_data_token/swap on EX {t2_ex_id} is expected to fail but did not, "
        f"maybe the FixedRateExchange is already approved as spender for bob_wallet."
    )
    assert (
        ocn_token.allowance(bob_wallet.address, fixed_ex.address) == base_token_quote
    ), ""
    assert (
        fixed_ex.get_tx_receipt(fixed_ex.activate(t2_ex_id, alice_wallet)).status == 1
    ), f"exchange {t2_ex_id} deactivate failed."
    assert (
        fixed_ex.isActive(t2_ex_id) is True
    ), f"exchange {t2_ex_id} is not active, but it should be."

    ##############################
    # buy should still fail as datatokens are not approved to spend by the exchange contract
    assert (
        run_failing_tx(fixed_ex, fixed_ex.buy_data_token, t2_ex_id, amount, bob_wallet)
        == 0
    ), (
        f"buy_data_token/swap on EX {t2_ex_id} is expected to fail but did not, "
        f"maybe the FixedRateExchange is already approved as spender for bob_wallet."
    )

    # now buy tokens should succeed
    assert (
        T2.get_tx_receipt(T2.approve(fixed_ex.address, amount * 3, alice_wallet)).status
        == 1
    ), "approve failed"
    assert (
        fixed_ex.get_tx_receipt(
            fixed_ex.buy_data_token(t2_ex_id, amount, bob_wallet)
        ).status
        == 1
    ), f"buy_data_token/swap on EX {ex_id} failed, "
    assert ocn_token.allowance(bob_wallet.address, fixed_ex.address) == 0, ""

    # approve again for another purchase
    ocn_token.get_tx_receipt(
        ocn_token.approve(fixed_ex.address, base_token_quote, bob_wallet)
    )
    assert (
        run_failing_tx(
            fixed_ex, fixed_ex.buy_data_token, t2_ex_id, to_base_18(5.0), bob_wallet
        )
        == 0
    ), f"buy_data_token/swap on EX {t2_ex_id} should fail because not enough Ocean tokens are approved by buyer."

    # get new quote for new amount
    base_token_quote = fixed_ex.get_base_token_quote(
        t2_ex_id, to_base_18(5.0)
    )  # num base token (OCEAN tokens
    ocn_token.get_tx_receipt(
        ocn_token.approve(fixed_ex.address, base_token_quote, bob_wallet)
    )
    assert (
        fixed_ex.get_tx_receipt(
            fixed_ex.buy_data_token(t2_ex_id, to_base_18(5.0), bob_wallet)
        ).status
        == 1
    ), f"buy_data_token/swap on EX {t2_ex_id} failed."
    assert ocn_token.allowance(bob_wallet.address, fixed_ex.address) == 0, ""

    ##############################
    # test getRate/setRate
    assert (
        fixed_ex.getRate(t2_ex_id) == rate2
    ), f"T2 exchange rate does not match {rate2}, got {fixed_ex.getRate(t2_ex_id)}"
    assert (
        fixed_ex.getRate(ex_id) == rate
    ), f"T1 exchange rate does not match {rate}, got {fixed_ex.getRate(ex_id)}"
    rate2 = to_base_18(0.75)
    assert (
        fixed_ex.get_tx_receipt(fixed_ex.setRate(t2_ex_id, rate2, alice_wallet)).status
        == 1
    ), "setRate failed."
    assert (
        fixed_ex.getRate(t2_ex_id) == rate2
    ), f"T2 exchange rate does not match {rate2}, got {fixed_ex.getRate(t2_ex_id)}"

    assert (
        run_failing_tx(
            fixed_ex, fixed_ex.setRate, t2_ex_id, to_base_18(0.0), alice_wallet
        )
        == 0
    ), "should not accept rate of Zero."
    assert (
        run_failing_tx(
            fixed_ex, fixed_ex.setRate, t2_ex_id, -to_base_18(0.05), alice_wallet
        )
        == 0
    ), "should not accept a negative rate."
    assert (
        fixed_ex.get_tx_receipt(
            fixed_ex.setRate(t2_ex_id, to_base_18(1000.0), alice_wallet)
        ).status
        == 1
    ), "setRate failed."
Пример #22
0
    def get_pool_info(self,
                      pool_address,
                      dt_address=None,
                      from_block=None,
                      to_block=None,
                      flags=None):
        if not flags:
            flags = self.POOL_INFO_FLAGS

        from18 = from_base_18
        web3 = Web3Provider.get_web3()
        current_block = to_block if to_block is not None else web3.eth.blockNumber  # RPC_CALL
        pool = BPool(pool_address)
        dt_address = dt_address if dt_address else self.get_token_address(
            pool_address, pool, validate=False)  # RPC_CALL
        from_block = from_block if from_block is not None else self.get_creation_block(
            pool_address)  # RPC_CALL

        pool_creator = None
        shares = None
        info_dict = {'address': pool.address, 'dataTokenAddress': dt_address}
        if 'datatokenInfo' in flags:
            info_dict['dataToken'] = DataToken(dt_address).get_info(
                web3,
                from_block,
                current_block,
                include_holders=bool('dtHolders' in flags))

        if 'price' in flags:
            info_dict.update({
                'spotPrice1DT':
                from18(pool.getSpotPrice(self.ocean_address, dt_address)),
                'totalPrice1DT':
                self.getOceanRequiredToBuyDT(pool_address, dt_amount=1.0),
            })

        if 'reserve' in flags:
            ocn_reserve = from18(pool.getBalance(self.ocean_address))
            dt_reserve = from18(pool.getBalance(dt_address))
            info_dict.update({
                'oceanWeight':
                from18(pool.getDenormalizedWeight(self.ocean_address)),
                'oceanReserve':
                ocn_reserve,
                'dtWeight':
                from18(pool.getDenormalizedWeight(dt_address)),
                'dtReserve':
                dt_reserve,
            })
        if 'shares' in flags or 'creator' in flags:
            pool_creator = pool.getController()
            shares = from18(pool.totalSupply())
            info_dict.update({
                'creator': pool_creator,
            })

        if 'shareHolders' in flags:
            pool_erc20 = DataToken(pool_address)
            all_transfers, block = pool_erc20.get_all_transfers_from_events(
                from_block, current_block)
            a_to_balance = DataToken.calculate_balances(all_transfers)
            _min = to_base_18(0.001)
            pool_holders = sorted(
                [(a, from_base_18(b))
                 for a, b in a_to_balance.items() if b > _min],
                key=lambda x: x[1],
                reverse=True)
            info_dict.update({
                'numShareHolders': len(pool_holders),
                'shareHolders': pool_holders
            })

        all_join_records = []
        all_exit_records = []
        if 'liquidityTotals' in flags or 'liquidity' in flags:
            all_join_records = self.get_all_liquidity_additions(
                web3,
                pool_address,
                from_block,
                current_block,
                dt_address,
                raw_result=False)  # RPC_CALL
            total_ocn_additions = from18(
                sum(r[2] for r in all_join_records
                    if r[1] == self.ocean_address))
            all_exit_records = self.get_all_liquidity_removals(
                web3,
                pool_address,
                from_block,
                current_block,
                dt_address,
                raw_result=False)  # RPC_CALL
            total_ocn_removals = from18(
                sum(r[2] for r in all_exit_records
                    if r[1] == self.ocean_address))
            info_dict.update({
                'totalOceanAdditions': total_ocn_additions,
                'totalOceanRemovals': total_ocn_removals,
            })

        if 'liquidity' in flags:
            creator_shares = from18(pool.balanceOf(pool_creator))
            creator_shares_percent = creator_shares / shares

            account_to_join_record = self.get_account_to_liquidity_records_map(
                all_join_records)
            ocean_additions = [
                from18(r[2]) for r in account_to_join_record[pool_creator]
                if r[1] == self.ocean_address
            ]
            dt_additions = [
                from18(r[2]) for r in account_to_join_record[pool_creator]
                if r[1] == dt_address
            ]

            account_to_exit_record = self.get_account_to_liquidity_records_map(
                all_exit_records)
            ocean_removals = [
                from18(r[2])
                for r in account_to_exit_record.get(pool_creator, [])
                if r[1] == self.ocean_address
            ]
            dt_removals = [
                from18(r[2])
                for r in account_to_exit_record.get(pool_creator, [])
                if r[1] == dt_address
            ]

            all_swap_records = self.get_all_swaps(web3,
                                                  pool_address,
                                                  from_block,
                                                  current_block,
                                                  dt_address,
                                                  raw_result=False)
            account_to_swap_record = self.get_account_to_liquidity_records_map(
                all_swap_records)
            ocean_in = [
                from18(r[2])
                for r in account_to_swap_record.get(pool_creator, [])
                if r[1] == self.ocean_address
            ]
            dt_in = [
                from18(r[2])
                for r in account_to_swap_record.get(pool_creator, [])
                if r[1] == dt_address
            ]
            ocean_out = [
                from18(r[4])
                for r in account_to_swap_record.get(pool_creator, [])
                if r[3] == self.ocean_address
            ]
            dt_out = [
                from18(r[4])
                for r in account_to_swap_record.get(pool_creator, [])
                if r[3] == dt_address
            ]

            swap_fee = from18(pool.getSwapFee())
            sum_ocean_additions = sum(ocean_additions)
            sum_ocean_removals = sum(ocean_removals)
            sum_ocn_swap_in = sum(ocean_in)
            sum_ocn_swap_out = sum(ocean_out)
            sum_dt_additions = sum(dt_additions)
            sum_dt_removals = sum(dt_removals)
            sum_dt_swap_in = sum(dt_in)
            sum_dt_swap_out = sum(dt_out)
            taxable_ocn = sum_ocn_swap_in + sum_ocn_swap_out + sum_ocean_additions + sum_ocean_removals - ocean_additions[
                0]
            taxable_dt = sum_dt_swap_in + sum_dt_swap_out + sum_dt_additions + sum_dt_removals - dt_additions[
                0]

            info_dict.update({
                'totalShares': shares,
                'creator': pool_creator,
                'creatorShares': creator_shares,
                'creatorSharesPercentage': creator_shares_percent,
                'creatorFirstOceanStake': ocean_additions[0],
                'creatorFirstDTStake': dt_additions[0],
                'creatorTotalOceanStake': sum(ocean_additions),
                'creatorTotalDTStake': sum(dt_additions),
                'creatorTotalOceanUnstake': sum(ocean_removals),
                'creatorTotalDTUnstake': sum(dt_removals),
                'totalOceanSwapIn': sum_ocn_swap_in,
                'totalOceanSwapOut': sum_ocn_swap_out,
                'totalDTSwapIn': sum_dt_swap_in,
                'totalDTSwapOut': sum_dt_swap_out,
                'totalSwapFeesDT': swap_fee * taxable_dt,
                'totalSwapFeesOcean': swap_fee * taxable_ocn,
            })

        info_dict.update({
            'fromBlockNumber': from_block,
            'latestBlockNumber': current_block
        })
        return info_dict
Пример #23
0
 def getReserve(self, pool_address: str, token_address: str):
     return from_base_18(BPool(pool_address).getBalance(token_address))
Пример #24
0
def test_public_pool(network, bob_wallet):
    alice = alice_info()
    alice_address = alice.address
    alice_wallet = alice.wallet
    bob_address = bob_wallet.address
    T1 = alice.T1
    T2 = alice.T2

    pool = _createPoolWith2Tokens(network, alice.T1, alice.T2, alice.wallet,
                                  90.0, 10.0, 9.0, 1.0)
    BPT = pool
    web3 = alice.wallet.web3

    #alice give Bob some tokens
    alice.T1.transfer(bob_wallet.address,
                      to_base_18(100.0),
                      from_wallet=alice.wallet)
    alice.T2.transfer(bob_wallet.address,
                      to_base_18(100.0),
                      from_wallet=alice.wallet)

    #verify holdings
    assert from_base_18(alice.T1.balanceOf(alice.address)) == (1000.0 - 90.0 -
                                                               100.0)
    assert from_base_18(alice.T2.balanceOf(alice.address)) == (1000.0 - 10.0 -
                                                               100.0)
    assert from_base_18(BPT.balanceOf(alice.address)) == 0

    assert from_base_18(alice.T1.balanceOf(bob_address)) == 100.0
    assert from_base_18(alice.T2.balanceOf(bob_address)) == 100.0
    assert from_base_18(BPT.balanceOf(bob_address)) == 0

    assert from_base_18(T1.balanceOf(pool.address)) == 90.0
    assert from_base_18(T2.balanceOf(pool.address)) == 10.0
    assert from_base_18(BPT.balanceOf(pool.address)) == 0

    #finalize
    pool = BPool(pool.address)
    pool.finalize(from_wallet=alice.wallet)

    #verify holdings
    assert from_base_18(alice.T1.balanceOf(alice.address)) == (1000.0 - 90.0 -
                                                               100.0)
    assert from_base_18(alice.T2.balanceOf(alice.address)) == (1000.0 - 10.0 -
                                                               100.0)
    assert from_base_18(BPT.balanceOf(alice.address)) == 100.0  #new!

    assert from_base_18(T1.balanceOf(pool.address)) == 90.0
    assert from_base_18(T2.balanceOf(pool.address)) == 10.0
    assert from_base_18(BPT.balanceOf(pool.address)) == 0

    #bob join pool. Wants 10 BPT
    T1.approve(pool.address, to_base_18(100.0), from_wallet=bob_wallet)
    T2.approve(pool.address, to_base_18(100.0), from_wallet=bob_wallet)
    pool.joinPool(
        poolAmountOut_base=to_base_18(10.0),  #10 BPT
        maxAmountsIn_base=[to_base_18(100.0),
                           to_base_18(100.0)],
        from_wallet=bob_wallet)

    #verify holdings
    assert from_base_18(T1.balanceOf(alice_address)) == (1000.0 - 90.0 - 100.0)
    assert from_base_18(T2.balanceOf(alice_address)) == (1000.0 - 10.0 - 100.0)
    assert from_base_18(BPT.balanceOf(alice_address)) == 100.0

    assert from_base_18(T1.balanceOf(bob_address)) == (100.0 - 9.0)
    assert from_base_18(T2.balanceOf(bob_address)) == (100.0 - 1.0)
    assert from_base_18(BPT.balanceOf(bob_address)) == 10.0

    assert from_base_18(T1.balanceOf(pool.address)) == (90.0 + 9.0)
    assert from_base_18(T2.balanceOf(pool.address)) == (10.0 + 1.0)
    assert from_base_18(BPT.balanceOf(pool.address)) == 0

    #bob sells 2 BPT
    # -this is where BLabs fee kicks in. But the fee is currently set to 0.
    pool.exitPool(poolAmountIn_base=to_base_18(2.0),
                  minAmountsOut_base=[to_base_18(0.0),
                                      to_base_18(0.0)],
                  from_wallet=bob_wallet)
    assert from_base_18(T1.balanceOf(bob_address)) == 92.8
    assert from_base_18(T2.balanceOf(bob_address)) == 99.2
    assert from_base_18(BPT.balanceOf(bob_address)) == 8.0

    #bob buys 5 more BPT
    pool.joinPool(poolAmountOut_base=to_base_18(5.0),
                  maxAmountsIn_base=[to_base_18(90.0),
                                     to_base_18(90.0)],
                  from_wallet=bob_wallet)
    assert from_base_18(BPT.balanceOf(bob_address)) == 13.0

    #bob fully exits
    pool.exitPool(poolAmountIn_base=to_base_18(13.0),
                  minAmountsOut_base=[to_base_18(0.0),
                                      to_base_18(0.0)],
                  from_wallet=bob_wallet)
    assert from_base_18(BPT.balanceOf(bob_address)) == 0.0
Пример #25
0
def test_setSwapFee_works(network, alice_wallet):
    """Tests that a swap fee can be set on the pool by the controller of that pool."""
    pool = _deployBPool(network, alice_wallet)
    pool.setSwapFee(to_base_18(0.011), from_wallet=alice_wallet)
    assert from_base_18(pool.getSwapFee()) == 0.011
Пример #26
0
def test_public_pool(network, bob_wallet, alice_ocean):
    """Tests successful transfers inside a public pool."""
    alice = alice_info()
    alice_address = alice.address
    bob_address = bob_wallet.address
    T1 = alice.T1
    T2 = alice.T2

    pool = _createPoolWith2Tokens(network, alice.T1, alice.T2, alice.wallet,
                                  90.0, 10.0, 9.0, 1.0)
    BPT = pool

    # alice give Bob some tokens
    alice.T1.transfer(bob_wallet.address,
                      to_base_18(100.0),
                      from_wallet=alice.wallet)
    alice.T2.transfer(bob_wallet.address,
                      to_base_18(100.0),
                      from_wallet=alice.wallet)

    # verify holdings
    assert from_base_18(alice.T1.balanceOf(alice.address)) == (1000.0 - 90.0 -
                                                               100.0)
    assert from_base_18(alice.T2.balanceOf(alice.address)) == (1000.0 - 10.0 -
                                                               100.0)
    assert from_base_18(BPT.balanceOf(alice.address)) == 0

    assert from_base_18(alice.T1.balanceOf(bob_address)) == 100.0
    assert from_base_18(alice.T2.balanceOf(bob_address)) == 100.0
    assert from_base_18(BPT.balanceOf(bob_address)) == 0

    assert from_base_18(T1.balanceOf(pool.address)) == 90.0
    assert from_base_18(T2.balanceOf(pool.address)) == 10.0
    assert from_base_18(BPT.balanceOf(pool.address)) == 0

    # finalize
    pool = BPool(pool.address)
    pool.finalize(from_wallet=alice.wallet)

    # verify holdings
    assert from_base_18(alice.T1.balanceOf(alice.address)) == (1000.0 - 90.0 -
                                                               100.0)
    assert from_base_18(alice.T2.balanceOf(alice.address)) == (1000.0 - 10.0 -
                                                               100.0)
    assert from_base_18(BPT.balanceOf(alice.address)) == 100.0  # new!

    assert from_base_18(T1.balanceOf(pool.address)) == 90.0
    assert from_base_18(T2.balanceOf(pool.address)) == 10.0
    assert from_base_18(BPT.balanceOf(pool.address)) == 0

    # bob join pool. Wants 10 BPT
    T1.approve(pool.address, to_base_18(100.0), from_wallet=bob_wallet)
    T2.approve(pool.address, to_base_18(100.0), from_wallet=bob_wallet)
    pool.joinPool(
        poolAmountOut_base=to_base_18(10.0),  # 10 BPT
        maxAmountsIn_base=[to_base_18(100.0),
                           to_base_18(100.0)],
        from_wallet=bob_wallet,
    )

    # verify holdings
    assert from_base_18(T1.balanceOf(alice_address)) == (1000.0 - 90.0 - 100.0)
    assert from_base_18(T2.balanceOf(alice_address)) == (1000.0 - 10.0 - 100.0)
    assert from_base_18(BPT.balanceOf(alice_address)) == 100.0

    assert from_base_18(T1.balanceOf(bob_address)) == (100.0 - 9.0)
    assert from_base_18(T2.balanceOf(bob_address)) == (100.0 - 1.0)
    assert from_base_18(BPT.balanceOf(bob_address)) == 10.0

    assert from_base_18(T1.balanceOf(pool.address)) == (90.0 + 9.0)
    assert from_base_18(T2.balanceOf(pool.address)) == (10.0 + 1.0)
    assert from_base_18(BPT.balanceOf(pool.address)) == 0

    # bob sells 2 BPT
    # -this is where BLabs fee kicks in. But the fee is currently set to 0.
    pool.exitPool(
        poolAmountIn_base=to_base_18(2.0),
        minAmountsOut_base=[to_base_18(0.0), to_base_18(0.0)],
        from_wallet=bob_wallet,
    )
    assert from_base_18(T1.balanceOf(bob_address)) == 92.8
    assert from_base_18(T2.balanceOf(bob_address)) == 99.2
    assert from_base_18(BPT.balanceOf(bob_address)) == 8.0

    # bob buys 5 more BPT
    pool.joinPool(
        poolAmountOut_base=to_base_18(5.0),
        maxAmountsIn_base=[to_base_18(90.0),
                           to_base_18(90.0)],
        from_wallet=bob_wallet,
    )
    assert from_base_18(BPT.balanceOf(bob_address)) == 13.0

    # bob fully exits
    pool.exitPool(
        poolAmountIn_base=to_base_18(13.0),
        minAmountsOut_base=[to_base_18(0.0), to_base_18(0.0)],
        from_wallet=bob_wallet,
    )
    assert from_base_18(BPT.balanceOf(bob_address)) == 0.0

    block = alice_ocean.web3.eth.blockNumber
    join_log = pool.get_join_logs(alice_ocean.web3, block - 1, block + 1)[0]
    assert join_log["args"]["tokenIn"] == T1.address
Пример #27
0
def _spotPrices(network: str, T1: BToken, T2: BToken, wallet: Wallet,
                bal1: float, bal2: float, w1: float, w2: float):
    pool = _createPoolWith2Tokens(network, T1, T2, wallet, bal1, bal2, w1, w2)
    a1, a2 = T1.address, T2.address
    return (from_base_18(pool.getSpotPrice(a1, a2)),
            from_base_18(pool.getSpotPriceSansFee(a1, a2)))
Пример #28
0
 def token_balance(self, account: str):
     return from_base_18(self.balanceOf(account))
Пример #29
0
def test_setSwapFee_works(network, alice_wallet):
    pool = _deployBPool(network, alice_wallet)
    pool.setSwapFee(to_base_18(0.011), from_wallet=alice_wallet)
    assert from_base_18(pool.getSwapFee()) == 0.011