Exemple #1
0
    def is_dispensable(self, dt_address: str, amount: int,
                       to_wallet: Wallet) -> bool:
        """
        :return: bool
        """
        if not amount:
            return False

        token = DataToken(self.web3, dt_address)
        if not self.is_active(dt_address):
            return False

        user_balance = token.balanceOf(to_wallet.address)
        max_balance = self.max_balance(dt_address)

        if user_balance >= max_balance:
            return False

        max_tokens = self.max_balance(dt_address)
        if amount > max_tokens:
            return False

        is_true_minter = self.is_true_minter(dt_address)
        if is_true_minter:
            return True

        contract_balance = self.balance(dt_address)
        if contract_balance >= amount:
            return True

        return False
Exemple #2
0
    def buy_data_tokens(
        self, pool_address: str, amount: int, max_OCEAN_amount: int, from_wallet: Wallet
    ) -> str:
        """
        Buy data tokens from this pool, paying `max_OCEAN_amount` of OCEAN tokens.
        If total spent <= max_OCEAN_amount.
        - Caller is spending OCEAN tokens, and receiving `amount` DataTokens
        - OCEAN tokens are going into pool, DataTokens are going out of pool

        The transaction fails if total spent exceeds `max_OCEAN_amount`.

        :param pool_address: str address of pool contract
        :param amount: int number of data tokens to add to this pool in *base*
        :param max_OCEAN_amount:
        :param from_wallet:
        :return: str transaction id/hash
        """
        ocean_tok = DataToken(self.web3, self.ocean_address)
        if ocean_tok.balanceOf(from_wallet.address) < max_OCEAN_amount:
            raise InsufficientBalance("Insufficient funds for buying DataTokens!")
        if ocean_tok.allowance(from_wallet.address, pool_address) < max_OCEAN_amount:
            ocean_tok.approve(pool_address, max_OCEAN_amount, from_wallet)

        dtoken_address = self.get_token_address(pool_address)
        pool = BPool(self.web3, pool_address)
        return pool.swapExactAmountOut(
            tokenIn_address=self.ocean_address,  # entering pool
            maxAmountIn=max_OCEAN_amount,  # ""
            tokenOut_address=dtoken_address,  # leaving pool
            tokenAmountOut=amount,  # ""
            maxPrice=2 ** 255,  # here we limit by max_num_OCEAN, not price
            from_wallet=from_wallet,
        )
Exemple #3
0
    def pay_for_service(
        amount: float,
        token_address: str,
        did: str,
        service_id: int,
        fee_receiver: str,
        from_wallet: Wallet,
        consumer: str,
    ) -> str:
        """
        Submits the payment for chosen service in DataTokens.

        :param amount:
        :param token_address:
        :param did:
        :param service_id:
        :param fee_receiver:
        :param from_wallet: Wallet instance
        :param consumer: str the address of consumer of the service, defaults to the payer (the `from_wallet` address)
        :return: hex str id of transfer transaction
        """
        amount_base = to_base_18(amount)
        dt = DataToken(token_address)
        balance = dt.balanceOf(from_wallet.address)
        if balance < amount_base:
            raise AssertionError(
                f"Your token balance {balance} is not sufficient "
                f"to execute the requested service. This service "
                f"requires {amount_base} number of tokens.")

        if did.startswith("did:"):
            did = add_0x_prefix(did_to_id(did))

        if fee_receiver is None:
            fee_receiver = ZERO_ADDRESS

        if consumer is None:
            consumer = from_wallet.address

        tx_hash = dt.startOrder(consumer, amount_base, service_id,
                                fee_receiver, from_wallet)

        try:
            dt.verify_order_tx(
                Web3Provider.get_web3(),
                tx_hash,
                did,
                service_id,
                amount_base,
                from_wallet.address,
            )
            return tx_hash
        except (AssertionError, Exception) as e:
            msg = (
                f"Downloading asset files failed. The problem is related to "
                f"the transfer of the data tokens required for the download "
                f"service: {e}")
            logger.error(msg)
            raise AssertionError(msg)
Exemple #4
0
    def pay_for_service(
        web3: Web3,
        amount: int,
        token_address: str,
        did: str,
        service_id: int,
        fee_receiver: str,
        from_wallet: Wallet,
        consumer: str,
    ) -> str:
        """
        Submits the payment for chosen service in DataTokens.

        :param amount:
        :param token_address:
        :param did:
        :param service_id:
        :param fee_receiver:
        :param from_wallet: Wallet instance
        :param consumer: str the address of consumer of the service
        :return: hex str id of transfer transaction
        """
        dt = DataToken(web3, token_address)
        balance = dt.balanceOf(from_wallet.address)
        if balance < amount:
            raise InsufficientBalance(
                f"Your token balance {pretty_ether_and_wei(balance, dt.symbol())} is not sufficient "
                f"to execute the requested service. This service "
                f"requires {pretty_ether_and_wei(amount, dt.symbol())}."
            )

        if did.startswith("did:"):
            did = add_0x_prefix(did_to_id(did))

        if fee_receiver is None:
            fee_receiver = ZERO_ADDRESS

        tx_hash = dt.startOrder(consumer, amount, service_id, fee_receiver, from_wallet)

        try:
            dt.verify_order_tx(tx_hash, did, service_id, amount, from_wallet.address)
            return tx_hash
        except (AssertionError, Exception) as e:
            msg = (
                f"Downloading asset files failed. The problem is related to "
                f"the transfer of the data tokens required for the download "
                f"service: {e}"
            )
            logger.error(msg)
            raise AssertionError(msg)
Exemple #5
0
def mint_fake_OCEAN(config: Config) -> None:
    """
    Does the following:
    1. Mints tokens
    2. Distributes tokens to TEST_PRIVATE_KEY1 and TEST_PRIVATE_KEY2
    """
    addresses_file = config.address_file

    with open(addresses_file) as f:
        network_addresses = json.load(f)

    web3 = get_web3(config.network_url)
    deployer_wallet = Wallet(
        web3,
        private_key=os.environ.get("FACTORY_DEPLOYER_PRIVATE_KEY"),
        block_confirmations=config.block_confirmations,
        transaction_timeout=config.transaction_timeout,
    )

    OCEAN_token = DataToken(web3, address=network_addresses["development"]["Ocean"])

    amt_distribute = to_wei(1000)

    OCEAN_token.mint(
        deployer_wallet.address, 2 * amt_distribute, from_wallet=deployer_wallet
    )

    for key_label in ["TEST_PRIVATE_KEY1", "TEST_PRIVATE_KEY2"]:
        key = os.environ.get(key_label)
        if not key:
            continue

        w = Wallet(
            web3,
            private_key=key,
            block_confirmations=config.block_confirmations,
            transaction_timeout=config.transaction_timeout,
        )

        if OCEAN_token.balanceOf(w.address) < amt_distribute:
            OCEAN_token.transfer(w.address, amt_distribute, from_wallet=deployer_wallet)

        if get_ether_balance(web3, w.address) < to_wei(2):
            send_ether(deployer_wallet, w.address, to_wei(4))
Exemple #6
0
    def pay_for_service(amount: float, token_address: str, did: str,
                        service_id: int, fee_receiver: str,
                        from_wallet: Wallet) -> str:
        """
        Submits the payment for chosen service in DataTokens.

        :param amount:
        :param token_address:
        :param did:
        :param service_id:
        :param fee_receiver:
        :param from_wallet: Wallet instance
        :return: hex str id of transfer transaction
        """
        amount_base = to_base_18(amount)
        dt = DataToken(token_address)
        balance = dt.balanceOf(from_wallet.address)
        if balance < amount_base:
            raise AssertionError(
                f'Your token balance {balance} is not sufficient '
                f'to execute the requested service. This service '
                f'requires {amount_base} number of tokens.')
        if did.startswith('did:'):
            did = add_0x_prefix(did_to_id(did))

        tx_hash = dt.startOrder(from_wallet.address, amount_base, service_id,
                                fee_receiver, from_wallet)

        try:
            dt.verify_order_tx(Web3Provider.get_web3(), tx_hash, did,
                               service_id, amount_base, from_wallet.address)
            return tx_hash
        except (AssertionError, Exception) as e:
            msg = (
                f'Downloading asset files failed. The problem is related to '
                f'the transfer of the data tokens required for the download '
                f'service: {e}')
            logger.error(msg)
            raise AssertionError(msg)
Exemple #7
0
def setup_all(request, config, web3):
    # a test can skip setup_all() via decorator "@pytest.mark.nosetup_all"
    if "nosetup_all" in request.keywords:
        return

    wallet = get_ganache_wallet()

    if not wallet:
        return

    addresses_file = config.address_file
    if not os.path.exists(addresses_file):
        return

    with open(addresses_file) as f:
        network_addresses = json.load(f)

    print(f"sender: {wallet.key}, {wallet.address}, {wallet.keys_str()}")
    print(
        f"sender balance: {from_wei(get_ether_balance(web3, wallet.address))}")
    assert get_ether_balance(
        web3, wallet.address) >= to_wei(10), "Ether balance less than 10."

    from ocean_lib.models.data_token import DataToken

    OCEAN_token = DataToken(web3,
                            address=network_addresses["development"]["Ocean"])

    amt_distribute = to_wei(1000)

    for w in (get_publisher_wallet(), get_consumer_wallet()):
        if get_ether_balance(web3, w.address) < to_wei(2):
            send_ether(wallet, w.address, to_wei(4))

        if OCEAN_token.balanceOf(w.address) < to_wei(100):
            OCEAN_token.mint(wallet.address,
                             amt_distribute,
                             from_wallet=wallet)
            OCEAN_token.transfer(w.address, amt_distribute, from_wallet=wallet)
    def buy_at_fixed_rate(
        self,
        amount: int,
        wallet: Wallet,
        max_OCEAN_amount: int,
        exchange_id: Optional[Union[bytes, str]] = "",
        data_token: Optional[str] = "",
        exchange_owner: Optional[str] = "",
    ) -> bool:

        exchange, exchange_id = self.get_exchange_id_fallback_dt_and_owner(
            exchange_id, exchange_owner, data_token)

        # Figure out the amount of ocean tokens to approve before triggering the exchange function to do the swap
        ocean_amount = exchange.get_base_token_quote(exchange_id, amount)
        ocean_token = DataToken(self._web3, self.ocean_address)
        ocean_ticker = ocean_token.symbol()
        if ocean_amount > max_OCEAN_amount:
            raise ValidationError(
                f"Buying {pretty_ether_and_wei(amount, 'DataTokens')} requires {pretty_ether_and_wei(ocean_amount, ocean_ticker)} "
                f"tokens which exceeds the max_OCEAN_amount {pretty_ether_and_wei(max_OCEAN_amount, ocean_ticker)}."
            )
        if ocean_token.balanceOf(wallet.address) < ocean_amount:
            raise InsufficientBalance(
                f"Insufficient funds for buying {pretty_ether_and_wei(amount, 'DataTokens')}!"
            )
        if ocean_token.allowance(wallet.address,
                                 self._exchange_address) < ocean_amount:
            tx_id = ocean_token.approve(self._exchange_address, ocean_amount,
                                        wallet)
            tx_receipt = ocean_token.get_tx_receipt(self._web3, tx_id)
            if not tx_receipt or tx_receipt.status != 1:
                raise VerifyTxFailed(
                    f"Approve OCEAN tokens failed, exchange address was {self._exchange_address} and tx id was {tx_id}!"
                )
        tx_id = exchange.buy_data_token(exchange_id,
                                        data_token_amount=amount,
                                        from_wallet=wallet)
        return bool(exchange.get_tx_receipt(self._web3, tx_id).status)
Exemple #9
0
def test_fixed_rate_exchange(web3, alice_ocean, alice_wallet, T1, bob_wallet,
                             T2, contracts_addresses):
    """Tests for fixed rate exchange.

    tests:
        create
        generateExchangeId
        getExchange
        getExchanges
        getNumberOfExchanges
        get_base_token_quote
        buy_data_token

    """
    fixed_ex = FixedRateExchange(
        web3, 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(web3, ocean_t)
    bob_ocean_balance = ocn_token.balanceOf(bob_wallet.address)
    assert bob_ocean_balance >= to_wei(100), (
        f"bob wallet does not have the expected OCEAN tokens balance, "
        f"got {from_wei(bob_ocean_balance)} instead of 100")

    # clear any previous ocean token allowance for the exchange contract
    assert (ocn_token.get_tx_receipt(
        web3, 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_wei("0.1")
    tx_id = fixed_ex.create(ocean_t, T1.address, rate, alice_wallet)
    r = fixed_ex.get_tx_receipt(web3, 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_wei(10)  # 10 data tokens
    base_token_quote = fixed_ex.get_base_token_quote(ex_id, amount)
    expected_base_token_quote = int(amount * rate / to_wei(1))
    assert base_token_quote == (
        expected_base_token_quote
    ), f"quote does not seem correct: expected {expected_base_token_quote}, got {base_token_quote}"
    assert base_token_quote == to_wei(1), ""
    # 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(
        web3, 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(
        web3, 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(web3, 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_wei("0.8")
    tx_id = fixed_ex.create(ocean_t, T2.address, rate2, alice_wallet)
    r = fixed_ex.get_tx_receipt(web3, 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(
        web3, 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_wei(4)  # num data tokens
    base_token_quote = fixed_ex.get_base_token_quote(
        t2_ex_id, amount)  # num base token (OCEAN tokens)
    expected_base_token_quote = int(amount * rate2 / to_wei(1))
    assert base_token_quote == (
        expected_base_token_quote
    ), f"quote does not seem correct: expected {expected_base_token_quote}, got {base_token_quote}"
    ocn_token.get_tx_receipt(
        web3, 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(web3,
                                    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(
        web3, T2.approve(fixed_ex.address, amount * 3,
                         alice_wallet)).status == 1), "approve failed"
    assert (fixed_ex.get_tx_receipt(
        web3, 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(
        web3, 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_wei(5),
                       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_wei(5))  # num base token (OCEAN tokens
    ocn_token.get_tx_receipt(
        web3, ocn_token.approve(fixed_ex.address, base_token_quote,
                                bob_wallet))
    assert (fixed_ex.get_tx_receipt(
        web3, fixed_ex.buy_data_token(t2_ex_id, to_wei(5),
                                      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_wei("0.75")
    assert (fixed_ex.get_tx_receipt(
        web3, 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, 0,
        alice_wallet) == 0), "should not accept rate of Zero."
    assert (run_failing_tx(
        fixed_ex, fixed_ex.setRate, t2_ex_id, -to_wei("0.05"),
        alice_wallet) == 0), "should not accept a negative rate."
    assert (fixed_ex.get_tx_receipt(
        web3, fixed_ex.setRate(t2_ex_id, to_wei(1000),
                               alice_wallet)).status == 1), "setRate failed."
Exemple #10
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:
            dt = DataToken(dt_address)
            minter = dt.minter()

            token_holders = []
            if "dtHolders" in flags:
                token_holders = dt.calculate_token_holders(
                    from_block, to_block, 0.000001)

            order_logs = dt.get_start_order_logs(web3,
                                                 from_block=from_block,
                                                 to_block=to_block)

            info_dict["dataToken"] = {
                "address": dt.address(),
                "name": dt.datatoken_name(),
                "symbol": dt.symbol(),
                "deciamls": dt.decimals(),
                "cap": from18(dt.cap()),
                "totalSupply": from18(dt.totalSupply()),
                "minter": minter,
                "minterBalance": from18(dt.balanceOf(minter)),
                "numHolders": len(token_holders),
                "holders": token_holders,
                "numOrders": len(order_logs),
            }

        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)
            pool_holders = pool_erc20.calculate_token_holders(
                from_block, current_block, 0.001)
            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
Exemple #11
0
    def create(
        self,
        data_token_address: str,
        data_token_amount: int,
        OCEAN_amount: int,
        from_wallet: Wallet,
        data_token_weight: int = balancer_constants.INIT_WEIGHT_DT,
        swap_fee: int = balancer_constants.DEFAULT_SWAP_FEE,
    ) -> BPool:
        """
        Create a new pool with bound datatoken and OCEAN token then finalize it.
        The pool will have publicSwap enabled and swap fee is set
        to `balancer_constants.DEFAULT_SWAP_FEE`.
        Balances of both data tokens and OCEAN tokens must be sufficient in the
        `from_wallet`, otherwise this will fail.

        :param data_token_address: str address of the DataToken contract
        :param data_token_amount: int amount of initial liquidity of data tokens
        :param OCEAN_amount: int amount of initial liquidity of OCEAN tokens
        :param from_wallet: Wallet instance of pool owner
        :param data_token_weight: int weight of the data token to be set in the new pool must be >= 1 & <= 9
        :param swap_fee: int the fee taken by the pool on each swap transaction
        :return: BPool instance
        """
        bfactory = BFactory(self.web3, self.bfactory_address)
        pool_address = bfactory.newBPool(from_wallet)
        pool = BPool(self.web3, pool_address)
        logger.debug(f"pool created with address {pool_address}.")

        assert to_wei("1") <= data_token_weight <= to_wei("9")
        base_weight = to_wei(10) - data_token_weight

        # Must approve datatoken and Ocean tokens to the new pool as spender
        dt = DataToken(self.web3, data_token_address)
        if dt.balanceOf(from_wallet.address) < data_token_amount:
            raise InsufficientBalance(
                "Insufficient datatoken balance for pool creation!"
            )
        if dt.allowance(from_wallet.address, pool_address) < data_token_amount:
            tx_id = dt.approve(pool_address, data_token_amount, from_wallet)
            if dt.get_tx_receipt(self.web3, tx_id).status != 1:
                raise VerifyTxFailed(
                    f"Approve datatokens failed, pool was created at {pool_address}"
                )

        ot = DataToken(self.web3, self.ocean_address)
        if ot.balanceOf(from_wallet.address) < OCEAN_amount:
            raise InsufficientBalance("Insufficient OCEAN balance for pool creation!")
        if ot.allowance(from_wallet.address, pool_address) < OCEAN_amount:
            tx_id = ot.approve(pool_address, OCEAN_amount, from_wallet)
            if ot.get_tx_receipt(self.web3, tx_id).status != 1:
                raise VerifyTxFailed(
                    f"Approve OCEAN tokens failed, pool was created at {pool_address}"
                )
        tx_id = pool.setup(
            data_token_address,
            data_token_amount,
            data_token_weight,
            self.ocean_address,
            OCEAN_amount,
            base_weight,
            swap_fee,
            from_wallet,
        )
        if pool.get_tx_receipt(self.web3, tx_id).status != 1:
            raise VerifyTxFailed(
                f"pool.setup failed: txId={tx_id}, receipt={pool.get_tx_receipt(self.web3, tx_id)}"
            )

        logger.debug(
            f"create pool completed: poolAddress={pool_address}, pool setup TxId={tx_id}"
        )

        return pool