示例#1
0
def buy_data(
    ocean,
    private_key,
    token_address,
    seller_wallet,
    min_amount,
    max_amount,
):
    """Buy a dataset on the market.
    Define wallet, verify that there is enough ganache ETH and OCEAN.
    Create an exchange_id for a new exchange.
    Args:
        ocean ():
        private_key (str):
        token_address (str):
        seller_wallet (Wallet):
        min_amount (float):
        max_amount (float):
    Returns:

    """
    wallet = Wallet(ocean.web3, private_key, ocean.config.block_confirmations)
    assert ocean.web3.eth.get_balance(wallet.address) > 0, 'need ganache ETH'
    OCEAN_token = BToken(ocean.web3, ocean.OCEAN_address)
    assert OCEAN_token.balanceOf(wallet.address) > 0, 'need ganache OCEAN'
    exchange_id = ocean.exchange.create(token_address, to_wei(min_amount),
                                        seller_wallet)
    tx_result = ocean.exchange.buy_at_fixed_rate(to_wei(min_amount), wallet,
                                                 to_wei(max_amount),
                                                 exchange_id, token_address,
                                                 seller_wallet.address)
    assert tx_result, 'failed buying data tokens at fixed rate.'
示例#2
0
def test1():
    # ocean instance
    config = ExampleConfig.get_config()
    ConfigProvider.set_config(config)
    Web3Provider.init_web3(
        provider=get_web3_connection_provider(config.network_url))
    ContractHandler.set_artifacts_path(config.artifacts_path)

    ocean = Ocean(config)
    OCEAN_address_before = ocean.OCEAN_address

    # deploy, distribute, etc
    deploy_fake_OCEAN()

    # test: OCEAN address should have changed
    OCEAN_address_after = ocean.OCEAN_address
    assert OCEAN_address_before != OCEAN_address_after

    # test: TEST_PRIVATE_KEY{1,2} should each hold OCEAN
    wallet1 = Wallet(ocean.web3, private_key=os.getenv("TEST_PRIVATE_KEY1"))
    wallet2 = Wallet(ocean.web3, private_key=os.getenv("TEST_PRIVATE_KEY2"))

    OCEAN_after = BToken(ocean.OCEAN_address)
    assert OCEAN_after.balanceOf(wallet1.address) > 0
    assert OCEAN_after.balanceOf(wallet2.address) > 0
示例#3
0
def sell_data(
    ocean,
    private_key,
    data_token,
    amount,
    fixed_price=True,
):
    """Sell a dataset on the Ocean market.
    Mint the datatokens.
    In the create() step below, ganache OCEAN is needed.
    Finally, Approve the datatoken for sale.
    Args:
        ocean ():
        wallet ():
        data_token ():
        amount ():
        fixed_price (bool): Whether or not to sell the data at a fixed price.
    Returns:
        (bool): Returns True if successful.
    """
    wallet = Wallet(ocean.web3, private_key, ocean.config.block_confirmations)
    data_token.mint(wallet.address, to_wei(amount), wallet)
    OCEAN_token = BToken(ocean.web3, ocean.OCEAN_address)
    assert OCEAN_token.balanceOf(wallet.address) > 0, 'need OCEAN'
    data_token.approve(ocean.exchange._exchange_address, to_wei(amount),
                       wallet)
    return True
示例#4
0
    def sell_data_tokens(self, pool_address: str, amount_base: int,
                         min_OCEAN_amount_base: int,
                         from_wallet: Wallet) -> str:
        """
        Sell data tokens into this pool, receive `min_OCEAN_amount_base` of OCEAN tokens.
        If total income >= min_OCEAN_amount_base
        - Caller is spending DataTokens, and receiving OCEAN tokens
        - DataTokens are going into pool, OCEAN tokens are going out of pool

        The transaction fails if total income does not reach `min_OCEAN_amount_base`

        :param pool_address: str address of pool contract
        :param amount_base: int number of data tokens to add to this pool in *base*
        :param min_OCEAN_amount_base:
        :param from_wallet:
        :return: str transaction id/hash
        """
        dtoken_address = self.get_token_address(pool_address)
        dt = BToken(dtoken_address)
        dt.approve(pool_address, amount_base, from_wallet=from_wallet)

        pool = BPool(pool_address)
        return pool.swapExactAmountIn(
            tokenIn_address=dtoken_address,  # entering pool
            tokenAmountIn_base=amount_base,  # ""
            tokenOut_address=self.ocean_address,  # leaving pool
            minAmountOut_base=min_OCEAN_amount_base,  # ""
            maxPrice_base=2**255,  # here we limit by max_num_OCEAN, not price
            from_wallet=from_wallet,
        )
示例#5
0
    def _add_liquidity(
        self,
        pool_address: str,
        token_address: str,
        amount_base: int,
        from_wallet: Wallet,
    ) -> str:
        assert amount_base >= 0
        if amount_base == 0:
            return ""

        pool = BPool(pool_address)
        token = BToken(token_address)
        assert token.balanceOf(from_wallet.address) >= amount_base, (
            f"Insufficient funds, {amount_base} tokens are required of token address {token_address}, "
            f"but only a balance of {token.balanceOf(from_wallet.address)} is available."
        )

        tx_id = token.approve(pool_address, amount_base, from_wallet)
        r = token.get_tx_receipt(tx_id)
        if not r or r.status != 1:
            return 0

        pool_amount = pool.joinswapExternAmountIn(token_address, amount_base,
                                                  0, from_wallet)
        return pool_amount
示例#6
0
    def add_liquidity_finalized(self, pool_address: str, bpt_amount_base: int,
                                max_data_token_amount_base: int,
                                max_OCEAN_amount_base: int,
                                from_wallet: Wallet) -> str:
        """
        Add liquidity to a pool that's been finalized.
        Buy bpt_amount_base tokens from the pool, spending DataTokens and OCEAN tokens
        as needed and up to the specified maximum amounts.

        :param pool_address: str address of pool contract
        :param bpt_amount_base: int number of pool shares to receive for adding the liquidity
        :param max_data_token_amount_base: int maximum amount of Data tokens to go into the pool
        :param max_OCEAN_amount_base: int maximum amount of OCEAN tokens to go into the pool
        :param from_wallet: Wallet instance
        :return: str transaction id/hash
        """
        assert self._is_valid_pool(pool_address)
        dt_address = self.get_token_address(pool_address)
        dt = BToken(dt_address)
        dt.approve(pool_address,
                   max_data_token_amount_base,
                   from_wallet=from_wallet)

        OCEAN = BToken(self.ocean_address)
        OCEAN.approve(pool_address,
                      max_OCEAN_amount_base,
                      from_wallet=from_wallet)

        pool = BPool(pool_address)
        return pool.joinPool(
            bpt_amount_base,
            [max_data_token_amount_base, max_OCEAN_amount_base],
            from_wallet=from_wallet)
示例#7
0
    def _add_liquidity(self, pool_address: str, token_address: str,
                       amount_base: int, from_wallet: Wallet) -> str:
        assert amount_base >= 0
        if amount_base == 0:
            return ''

        pool = BPool(pool_address)
        token = BToken(token_address)
        assert token.balanceOf(from_wallet.address) >= amount_base, \
            f'Insufficient funds, {amount_base} tokens are required of token address {token_address}, ' \
            f'but only a balance of {token.balanceOf(from_wallet.address)} is available.'

        token.approve(pool_address, amount_base, from_wallet)

        pool_amount = pool.joinswapExternAmountIn(token_address, amount_base,
                                                  0, from_wallet)
        return pool_amount
示例#8
0
    def __str__(self) -> str:
        """Formats with attributes as key, value pairs."""
        s = []
        s += ["BPool:"]
        s += [f"  pool_address={self.address}"]
        s += [f"  controller address = {self.getController()}"]
        s += [f"  isPublicSwap = {self.isPublicSwap()}"]
        s += [f"  isFinalized = {self.isFinalized()}"]

        swap_fee = from_wei(self.getSwapFee())
        s += ["  swapFee = %.2f%%" % (swap_fee * 100)]

        s += [f"  numTokens = {self.getNumTokens()}"]
        cur_addrs = self.getCurrentTokens()
        cur_symbols = [BToken(self.web3, addr).symbol() for addr in cur_addrs]
        s += [f"  currentTokens (as symbols) = {', '.join(cur_symbols)}"]

        if self.isFinalized():
            final_addrs = self.getFinalTokens()
            final_symbols = [
                BToken(self.web3, addr).symbol() for addr in final_addrs
            ]
            s += [f"  finalTokens (as symbols) = {final_symbols}"]

        s += ["  is bound:"]
        for addr, symbol in zip(cur_addrs, cur_symbols):
            s += [f"    {symbol}: {self.isBound(addr)}"]

        s += ["  weights (fromBase):"]
        for addr, symbol in zip(cur_addrs, cur_symbols):
            denorm_w = from_wei(self.getDenormalizedWeight(addr))
            norm_w = from_wei(self.getNormalizedWeight(addr))
            s += [f"    {symbol}: denorm_w={denorm_w}, norm_w={norm_w} "]

        total_denorm_w = from_wei(self.getTotalDenormalizedWeight())
        s += [f"    total_denorm_w={total_denorm_w}"]

        s += ["  balances (fromBase):"]
        for addr, symbol in zip(cur_addrs, cur_symbols):
            balance = self.getBalance(addr)
            dec = BToken(self.web3, addr).decimals()
            s += [f"    {symbol}: {from_wei(balance, dec)}"]

        return "\n".join(s)
示例#9
0
def _createPoolWith2Tokens(
    network: str,
    T1: BToken,
    T2: BToken,
    wallet: Wallet,
    bal1: float,
    bal2: float,
    w1: float,
    w2: float,
):
    """Helper function to create a basic pool containing 2 tokens."""
    pool = _deployBPool(network, wallet)

    T1.get_tx_receipt(
        T1.approve(pool.address, to_base_18(bal1), from_wallet=wallet))
    T2.get_tx_receipt(
        T2.approve(pool.address, to_base_18(bal2), from_wallet=wallet))

    if pool.isBound(T1.address):
        pool.unbind(T1.address, wallet)

    if pool.isBound(T2.address):
        pool.unbind(T2.address, wallet)

    pool.bind(T1.address, to_base_18(bal1), to_base_18(w1), from_wallet=wallet)
    pool.bind(T2.address, to_base_18(bal2), to_base_18(w2), from_wallet=wallet)

    return pool
示例#10
0
def _createPoolWith2Tokens(
    network: str,
    config: Config,
    web3: Web3,
    T1: BToken,
    T2: BToken,
    wallet: Wallet,
    bal1: Union[Decimal, str, int],
    bal2: Union[Decimal, str, int],
    w1: Union[Decimal, str, int],
    w2: Union[Decimal, str, int],
):
    """Helper function to create a basic pool containing 2 tokens."""
    pool = _deployBPool(web3, config.address_file, network, wallet)

    T1.get_tx_receipt(
        web3, T1.approve(pool.address, to_wei(bal1), from_wallet=wallet))
    T2.get_tx_receipt(
        web3, T2.approve(pool.address, to_wei(bal2), from_wallet=wallet))

    if pool.isBound(T1.address):
        pool.unbind(T1.address, wallet)

    if pool.isBound(T2.address):
        pool.unbind(T2.address, wallet)

    pool.bind(T1.address, to_wei(bal1), to_wei(w1), from_wallet=wallet)
    pool.bind(T2.address, to_wei(bal2), to_wei(w2), from_wallet=wallet)

    return pool
示例#11
0
    def sell_data_tokens(
        self, pool_address: str, amount: int, min_OCEAN_amount: int, from_wallet: Wallet
    ) -> str:
        """
        Sell data tokens into this pool, receive `min_OCEAN_amount` of OCEAN tokens.
        If total income >= min_OCEAN_amount
        - Caller is spending DataTokens, and receiving OCEAN tokens
        - DataTokens are going into pool, OCEAN tokens are going out of pool

        The transaction fails if total income does not reach `min_OCEAN_amount`

        :param pool_address: str address of pool contract
        :param amount: int number of data tokens to add to this pool
        :param min_OCEAN_amount:
        :param from_wallet:
        :return: str transaction id/hash
        """
        dtoken_address = self.get_token_address(pool_address)
        dt = BToken(self.web3, dtoken_address)
        if dt.balanceOf(from_wallet.address) < amount:
            raise InsufficientBalance("Insufficient funds for selling DataTokens!")
        if dt.allowance(from_wallet.address, pool_address) < amount:
            dt.approve(pool_address, amount, from_wallet=from_wallet)

        pool = BPool(self.web3, pool_address)
        return pool.swapExactAmountIn(
            tokenIn_address=dtoken_address,  # entering pool
            tokenAmountIn=amount,  # ""
            tokenOut_address=self.ocean_address,  # leaving pool
            minAmountOut=min_OCEAN_amount,  # ""
            maxPrice=2 ** 255,  # here we limit by max_num_OCEAN, not price
            from_wallet=from_wallet,
        )
示例#12
0
    def _add_liquidity(
        self, pool_address: str, token_address: str, amount: int, from_wallet: Wallet
    ) -> str:
        assert amount >= 0
        if amount == 0:
            return ""
        pool = BPool(self.web3, pool_address)
        token = BToken(self.web3, token_address)
        assert token.balanceOf(from_wallet.address) >= amount, (
            f"Insufficient funds, {amount} tokens are required of token address {token_address}, "
            f"but only a balance of {token.balanceOf(from_wallet.address)} is available."
        )
        if token.allowance(from_wallet.address, pool_address) < amount:
            tx_id = token.approve(pool_address, amount, from_wallet)
            r = token.get_tx_receipt(self.web3, tx_id)
            if not r or r.status != 1:
                raise VerifyTxFailed(
                    f"Approve OCEAN tokens failed, pool was created at {pool_address}"
                )

        pool_amount = pool.joinswapExternAmountIn(token_address, amount, 0, from_wallet)
        return pool_amount
示例#13
0
def test1(network, OCEAN_address, alice_wallet, alice_ocean, alice_address,
          bob_wallet):
    bfactory_address = get_bfactory_address(network)

    # ===============================================================
    # 1. Alice publishes a dataset (= publishes a datatoken)
    # For now, you're Alice:) Let's proceed.
    DT = alice_ocean.create_data_token("DataToken1",
                                       "DT1",
                                       alice_wallet,
                                       blob="localhost:8030")
    DT_address = DT.address

    # ===============================================================
    # 2. Alice hosts the dataset
    # Do from console:
    # >> touch /var/mydata/myFolder1/file
    # >> ENV DT="{'0x1234':'/var/mydata/myFolder1'}"
    # >> docker run @oceanprotocol/provider-py -e CONFIG=DT

    # ===============================================================
    # 3. Alice mints DTs
    DT.mint(alice_address, to_base_18(1000.0), alice_wallet)

    # ===============================================================
    # 4. Alice creates an OCEAN-DT pool (=a Balancer Pool)
    bfactory = BFactory(bfactory_address)
    pool_address = bfactory.newBPool(from_wallet=alice_wallet)
    pool = BPool(pool_address)

    pool.setPublicSwap(True, from_wallet=alice_wallet)

    pool.setSwapFee(to_base_18(0.1), from_wallet=alice_wallet)  # set 10% fee

    DT.approve(pool_address, to_base_18(90.0), from_wallet=alice_wallet)
    pool.bind(
        DT_address,
        to_base_18(90.0),
        balancer_constants.INIT_WEIGHT_DT_BASE,
        from_wallet=alice_wallet,
    )

    OCEAN_token = BToken(OCEAN_address)
    txid = OCEAN_token.approve(pool_address,
                               to_base_18(10.0),
                               from_wallet=alice_wallet)
    r = OCEAN_token.get_tx_receipt(txid)
    assert r and r.status == 1, f"approve failed, receipt={r}"
    pool.bind(
        OCEAN_address,
        to_base_18(10.0),
        balancer_constants.INIT_WEIGHT_OCEAN_BASE,
        from_wallet=alice_wallet,
    )

    # ===============================================================
    # 5. Alice adds liquidity to pool
    DT.approve(pool_address, to_base_18(9.0), from_wallet=alice_wallet)
    pool.rebind(
        DT_address,
        to_base_18(90.0 + 9.0),
        balancer_constants.INIT_WEIGHT_DT_BASE,
        from_wallet=alice_wallet,
    )

    OCEAN_token.approve(pool_address,
                        to_base_18(1.0),
                        from_wallet=alice_wallet)
    pool.rebind(
        OCEAN_address,
        to_base_18(10.0 + 1.0),
        to_base_18(balancer_constants.INIT_WEIGHT_OCEAN),
        from_wallet=alice_wallet,
    )

    # 6. Bob buys a DT from pool
    OCEAN_token.approve(pool_address, to_base_18(2.0), from_wallet=bob_wallet)
    pool.swapExactAmountOut(
        tokenIn_address=OCEAN_address,
        maxAmountIn_base=to_base_18(2.0),
        tokenOut_address=DT_address,
        tokenAmountOut_base=to_base_18(1.0),
        maxPrice_base=2**255,
        from_wallet=bob_wallet,
    )

    # ===============================================================
    # 7. Bob consumes dataset
    # <don't need to show here>

    # ===============================================================
    # 8. Alice removes liquidity
    pool.rebind(
        DT_address,
        to_base_18(90.0 + 9.0 - 2.0),
        balancer_constants.INIT_WEIGHT_DT_BASE,
        from_wallet=alice_wallet,
    )
    pool.rebind(
        OCEAN_address,
        to_base_18(10.0 + 1.0 - 3.0),
        balancer_constants.INIT_WEIGHT_OCEAN_BASE,
        from_wallet=alice_wallet,
    )

    # ===============================================================
    # 9. Alice sells data tokens
    DT.approve(pool_address, to_base_18(1.0), from_wallet=alice_wallet)
    pool.swapExactAmountIn(
        tokenIn_address=DT_address,
        tokenAmountIn_base=to_base_18(1.0),
        tokenOut_address=OCEAN_address,
        minAmountOut_base=to_base_18(0.0001),
        maxPrice_base=2**255,
        from_wallet=alice_wallet,
    )

    # ===============================================================
    # 10. Alice finalizes pool. Now others can add liquidity.
    pool.finalize(from_wallet=alice_wallet)

    # ===============================================================
    # 11. Bob adds liquidity
    DT.approve(pool_address, to_base_18(1.0), from_wallet=bob_wallet)
    OCEAN_token.approve(pool_address, to_base_18(1.0), from_wallet=bob_wallet)
    pool.joinPool(to_base_18(0.1),
                  [to_base_18(1.0), to_base_18(1.0)],
                  from_wallet=bob_wallet)

    # ===============================================================
    # 12. Bob adds liquidity AGAIN
    DT.approve(pool_address, to_base_18(1.0), from_wallet=bob_wallet)
    OCEAN_token.approve(pool_address, to_base_18(1.0), from_wallet=bob_wallet)
    pool.joinPool(to_base_18(0.1),
                  [to_base_18(1.0), to_base_18(1.0)],
                  from_wallet=bob_wallet)
示例#14
0
def test_ERC20(network, alice_wallet, alice_address, bob_wallet, bob_address,
               OCEAN_address):
    token = BToken(OCEAN_address)

    token.approve(bob_address, 0, from_wallet=alice_wallet)
    assert token.symbol() == 'OCEAN'
    assert token.decimals() == 18
    assert token.balanceOf(alice_address) > util.to_base_18(10.0)
    assert token.balanceOf(bob_address) > util.to_base_18(10.0)

    assert token.allowance(alice_address, bob_address) == 0
    token.approve(bob_address, int(1e18), from_wallet=alice_wallet)
    assert token.allowance(alice_address, bob_address) == int(1e18)

    # alice sends all her OCEAN to Bob, then Bob sends it back
    alice_OCEAN = token.balanceOf(alice_address)
    bob_OCEAN = token.balanceOf(bob_address)
    token.transfer(bob_address, alice_OCEAN, from_wallet=alice_wallet)
    assert token.balanceOf(alice_address) == 0
    assert token.balanceOf(bob_address) == (alice_OCEAN + bob_OCEAN)

    token.transfer(alice_address, alice_OCEAN, from_wallet=bob_wallet)
    assert token.balanceOf(alice_address) == alice_OCEAN
    assert token.balanceOf(bob_address) == bob_OCEAN
示例#15
0
def test_ERC20(network, alice_wallet, alice_address, bob_wallet, bob_address,
               OCEAN_address):
    """Tests an OCEAN token approval, allowance and transfers."""
    token = BToken(OCEAN_address)

    token.approve(bob_address, 0, from_wallet=alice_wallet)
    # generating ERC20 Tokens, so the symbol is irrelevant
    assert token.symbol() == "DTT"
    assert token.decimals() == 18
    assert token.balanceOf(alice_address) > util.to_base_18(10.0)
    assert token.balanceOf(bob_address) > util.to_base_18(10.0)

    assert token.allowance(alice_address, bob_address) == 0
    token.approve(bob_address, int(1e18), from_wallet=alice_wallet)
    assert token.allowance(alice_address, bob_address) == int(1e18)

    # alice sends all her OCEAN to Bob, then Bob sends it back
    alice_OCEAN = token.balanceOf(alice_address)
    bob_OCEAN = token.balanceOf(bob_address)
    token.transfer(bob_address, alice_OCEAN, from_wallet=alice_wallet)
    assert token.balanceOf(alice_address) == 0
    assert token.balanceOf(bob_address) == (alice_OCEAN + bob_OCEAN)

    token.transfer(alice_address, alice_OCEAN, from_wallet=bob_wallet)
    assert token.balanceOf(alice_address) == alice_OCEAN
    assert token.balanceOf(bob_address) == bob_OCEAN
示例#16
0
    def add_liquidity_finalized(
        self,
        pool_address: str,
        bpt_amount: int,
        max_data_token_amount: int,
        max_OCEAN_amount: int,
        from_wallet: Wallet,
    ) -> str:
        """
        Add liquidity to a pool that's been finalized.
        Buy bpt_amount tokens from the pool, spending DataTokens and OCEAN tokens
        as needed and up to the specified maximum amounts.

        :param pool_address: str address of pool contract
        :param bpt_amount: int number of pool shares to receive for adding the liquidity
        :param max_data_token_amount: int maximum amount of Data tokens to go into the pool
        :param max_OCEAN_amount: int maximum amount of OCEAN tokens to go into the pool
        :param from_wallet: Wallet instance
        :return: str transaction id/hash
        """
        assert self._is_valid_pool(pool_address), "The pool address is not valid."
        dt_address = self.get_token_address(pool_address)
        dt = BToken(self.web3, dt_address)
        if dt.balanceOf(from_wallet.address) < max_data_token_amount:
            raise InsufficientBalance(
                f"Insufficient funds for adding liquidity for {dt.address} datatoken!"
            )
        if dt.allowance(from_wallet.address, pool_address) < max_data_token_amount:
            dt.approve(pool_address, max_data_token_amount, from_wallet=from_wallet)

        OCEAN = BToken(self.web3, self.ocean_address)
        if OCEAN.balanceOf(from_wallet.address) < max_OCEAN_amount:
            raise InsufficientBalance(
                f"Insufficient funds for adding liquidity for {OCEAN.address} OCEAN token!"
            )
        if OCEAN.allowance(from_wallet.address, pool_address) < max_OCEAN_amount:
            OCEAN.approve(pool_address, max_OCEAN_amount, from_wallet=from_wallet)

        pool = BPool(self.web3, pool_address)
        return pool.joinPool(
            bpt_amount,
            [max_data_token_amount, max_OCEAN_amount],
            from_wallet=from_wallet,
        )