Example #1
0
    def sellDTV4(self, pool, DT, DT_sell_amt: float, min_OCEAN_amt: float = 0.0):
        """Swap DT for OCEAN. min_OCEAN_amt>0 protects from slippage."""
        DT.approve(pool.address, toBase18(DT_sell_amt), {"from": self._account})

        tokenIn_address = DT.address  # entering pool
        tokenAmountIn_base = toBase18(DT_sell_amt)  # ""
        tokenOut_address = globaltokens.OCEAN_address()  # leaving pool
        minAmountOut_base = toBase18(min_OCEAN_amt)  # ""
        maxPrice_base = 2 ** 255  # limit by min_OCEAN_amt, not price
        marketFeeAddress = OPF_ADDRESS
        tokenInOutMarket = [
            tokenIn_address,
            tokenOut_address,
            marketFeeAddress,
        ]  # [tokenIn,tokenOut,marketFeeAddress]
        amountsInOutMaxFee = [
            tokenAmountIn_base,
            minAmountOut_base,
            maxPrice_base,
            0,
        ]  # [exactAmountIn,minAmountOut,maxPrice,_swapMarketFee]

        pool.swapExactAmountIn(
            tokenInOutMarket,
            amountsInOutMaxFee,
            {"from": self._account},
        )
        self.resetCachedInfo()
Example #2
0
def createDatatokenFromDataNFT(
    DT_name: str, DT_symbol: str, DT_cap: int, dataNFT, from_account
):

    erc20_template_index = 1
    strings = [
        DT_name,
        DT_symbol,
    ]
    addresses = [
        from_account.address,  # minter
        from_account.address,  # fee mgr
        from_account.address,  # pub mkt
        ZERO_ADDRESS,  # pub mkt fee token addr
    ]
    uints = [
        toBase18(DT_cap),
        toBase18(0.0),  # pub mkt fee amt
    ]
    _bytes: List[Any] = []

    tx = dataNFT.createERC20(
        erc20_template_index, strings, addresses, uints, _bytes, {"from": from_account}
    )
    DT_address = tx.events["TokenCreated"]["newTokenAddress"]
    DT = BROWNIE_PROJECT080.ERC20Template.at(DT_address)

    return DT
def test_createBPool_via_util():
    brownie.chain.reset()
    router = oceanv4util.deployRouter(account0)
    (dataNFT,
     erc721_factory) = oceanv4util.createDataNFT("dataNFT", "DATANFT",
                                                 account0, router)
    DT = oceanv4util.createDatatokenFromDataNFT("DT", "DTSymbol", 10000,
                                                dataNFT, account0)

    fundOCEANFromAbove(address0, toBase18(10000.0))
    OCEAN = oceanv4util.OCEANtoken()

    OCEAN_init_liquidity = 2000.0
    DT_OCEAN_rate = 0.1
    DT_vest_amt = 100
    DT_vest_num_blocks = 600
    LP_swap_fee = 0.03
    mkt_swap_fee = 0.01
    pool = oceanv4util.createBPoolFromDatatoken(
        DT,
        erc721_factory,
        account0,
        OCEAN_init_liquidity,
        DT_OCEAN_rate,
        DT_vest_amt,
        DT_vest_num_blocks,
        LP_swap_fee,
        mkt_swap_fee,
    )
    pool_address = pool.address

    assert pool.getBaseTokenAddress() == OCEAN.address
    assert OCEAN.balanceOf(pool_address) < toBase18(10000.0)
    assert pool.getMarketFee() == toBase18(mkt_swap_fee)
    assert pool.getSwapFee() == toBase18(LP_swap_fee)
    def _candPoolAgents(  # pylint: disable=too-many-locals
        self, state
    ) -> List[PoolAgent]:
        """Pools that this agent can afford to buy 1.0 datatokens from,
        at least based on a first approximation.
        """
        OCEAN_address = globaltokens.OCEAN_address()
        OCEAN_base = toBase18(self.OCEAN())
        all_pool_agents = state.agents.filterToPoolV4()

        cand_pool_agents = []
        for pool_name, pool_agent in all_pool_agents.items():
            # filter 1: pool rugged?
            if hasattr(state, "rugged_pools") and pool_name in state.rugged_pools:
                continue

            # filter 2: agent has enough funds?
            pool = pool_agent.pool
            DT_address = pool_agent.datatoken_address

            tokenAmountOut = toBase18(1.0)  # number of DTs
            swapFee = pool.getSwapFee()

            OCEANamountIn_base = pool.getAmountInExactOut(
                OCEAN_address, DT_address, tokenAmountOut, swapFee
            )

            if OCEANamountIn_base >= OCEAN_base:
                continue

            # passed all filters! Add this agent
            cand_pool_agents.append(pool_agent)

        return cand_pool_agents
def test_exitPool_receiveTokens():
    brownie.chain.reset()
    OCEAN = OCEANtoken()
    (DT, pool, ssbot) = _deployBPool(do_extra_funding=True)

    account0_DT_balance = DT.balanceOf(address0)
    account0_OCEAN_balance = OCEAN.balanceOf(address0)
    account0_BPT_balance = pool.balanceOf(address0)
    ssContractDTbalance = DT.balanceOf(ssbot.address)
    ssContractBPTbalance = pool.balanceOf(ssbot.address)

    BPTAmountIn = toBase18(0.5)
    minAmountOut = [toBase18(1), toBase18(1)]
    tx = pool.exitPool(BPTAmountIn, minAmountOut, {"from": account0})

    assert tx.events["LOG_EXIT"][0]["tokenOut"] == DT.address
    assert tx.events["LOG_EXIT"][1]["tokenOut"] == OCEAN.address

    assert tx.events["LOG_EXIT"][0][
        "tokenAmountOut"] + account0_DT_balance == DT.balanceOf(address0)
    assert tx.events["LOG_EXIT"][1][
        "tokenAmountOut"] + account0_OCEAN_balance == OCEAN.balanceOf(address0)
    assert pool.balanceOf(address0) + BPTAmountIn == account0_BPT_balance

    # check the ssContract BPT and DT balance didn"t change
    assert ssContractBPTbalance == pool.balanceOf(ssbot.address)
    assert ssContractDTbalance == DT.balanceOf(ssbot.address)
def test_basic():
    n_blocks = len(chain)
    beneficiary = address1
    start_block = n_blocks + 1
    num_blocks_duration = 4

    # constructor
    vesting_wallet = BROWNIE_PROJECT080.VestingWallet080.deploy(
        beneficiary,
        toBase18(start_block),
        toBase18(num_blocks_duration),
        {"from": account0},
    )

    assert vesting_wallet.beneficiary() == beneficiary
    start_block_measured = int(vesting_wallet.startBlock() / 1e18)
    assert start_block_measured in [
        start_block - 1, start_block, start_block + 1
    ]
    assert int(vesting_wallet.numBlocksDuration() / 1e18) == 4
    assert vesting_wallet.released() == 0

    # time passes
    chain.mine(blocks=15, timedelta=1)
    assert vesting_wallet.released() == 0  # haven't released anything

    # call release
    vesting_wallet.release()
    assert vesting_wallet.released() == 0  # wallet never got funds to release!
def test_joinswapExternAmountIn_addOCEAN():
    brownie.chain.reset()
    OCEAN = OCEANtoken()
    (DT, pool, ssbot) = _deployBPool(do_extra_funding=True)

    account0_DT_balance = DT.balanceOf(address0)
    ssContractDTbalance = DT.balanceOf(ssbot.address)
    ssContractBPTbalance = pool.balanceOf(ssbot.address)

    oceanAmountIn = toBase18(100)
    minBPTOut = toBase18(0.1)

    tx = pool.joinswapExternAmountIn(oceanAmountIn, minBPTOut,
                                     {"from": account0})

    assert tx.events["LOG_JOIN"][0]["tokenIn"] == OCEAN.address
    assert tx.events["LOG_JOIN"][0]["tokenAmountIn"] == oceanAmountIn

    assert tx.events["LOG_JOIN"][1]["tokenIn"] == DT.address
    ssbotAmountIn = ssContractDTbalance - DT.balanceOf(ssbot.address)
    assert ssbotAmountIn == tx.events["LOG_JOIN"][1]["tokenAmountIn"]

    # we check ssContract actually moved DT and got back BPT
    assert (DT.balanceOf(ssbot.address) == ssContractDTbalance -
            tx.events["LOG_JOIN"][1]["tokenAmountIn"])
    assert (pool.balanceOf(ssbot.address) == ssContractBPTbalance +
            tx.events["LOG_BPT"]["bptAmount"])

    # no datatoken where taken from account0
    assert account0_DT_balance == DT.balanceOf(address0)
Example #8
0
    def buyDTV4(self, pool, DT, DT_buy_amt: float, max_OCEAN_allow: float):
        """Swap OCEAN for DT, oceanv4 contracts"""
        OCEAN = globaltokens.OCEANtoken()
        OCEAN.approve(pool.address, toBase18(max_OCEAN_allow), {"from": self._account})

        tokenIn_address = globaltokens.OCEAN_address()
        tokenOut_address = DT.address
        marketFeeAddress = OPF_ADDRESS

        maxAmountIn_base = toBase18(max_OCEAN_allow)
        tokenAmountOut_base = toBase18(DT_buy_amt)
        maxPrice_base = 2 ** 255

        tokenInOutMarket = [
            tokenIn_address,
            tokenOut_address,
            marketFeeAddress,
        ]  # // [tokenIn,tokenOut,marketFeeAddress]
        amountsInOutMaxFee = [
            maxAmountIn_base,
            tokenAmountOut_base,
            maxPrice_base,
            0,
        ]  # [maxAmountIn,exactAmountOut,maxPrice,_swapMarketFee]
        pool.swapExactAmountOut(
            tokenInOutMarket, amountsInOutMaxFee, {"from": self._account}
        )
        self.resetCachedInfo()
Example #9
0
def test_setSwapFee_fails():
    pool = _deployBPool()
    with pytest.raises(Exception):
        # fail, because account1 isn't controller
        pool.setSwapFee(toBase18(0.011), {"from": account1})
    pool.setController(address1, {"from": account0})
    pool.setSwapFee(toBase18(0.011), {"from": account1})  # pass now
Example #10
0
 def _createDatatoken(self, dt_name: str, mint_amt: float):
     """Create datatoken contract and mint DTs to self."""
     account = self._wallet._account
     DT = oceanv3util.newDatatoken("", dt_name, dt_name, toBase18(mint_amt),
                                   account)
     DT.mint(account.address, toBase18(mint_amt), {"from": account})
     self._wallet.resetCachedInfo()
     return DT
Example #11
0
def _dts():
    """Create datatokens, and mint into account0"""
    cap = toBase18(1e3)
    dts = []
    for i in range(2):
        dt = newDatatoken("blob", f"datatoken{i+1}", f"DT{i+1}", cap, account0)
        dt.mint(account0, toBase18(1e3), {"from": account0})
        dts.append(dt)
    return dts
def test_via_util():
    dt = sol057.contracts.oceanv3.oceanv3util.newDatatoken(
        "foo_blob", "datatoken1", "DT1", toBase18(100.0), account0)
    dt.mint(address0, toBase18(100.0), {"from": account0})
    assert dt.name() == "datatoken1"
    assert dt.symbol() == "DT1"
    assert dt.decimals() == 18
    assert dt.balanceOf(address0) == toBase18(100.0)
    assert dt.blob() == "foo_blob"
Example #13
0
def test_calcSpotPrice():
    pool = _deployBPool()
    tokenBalanceIn = toBase18(10.0)
    tokenWeightIn = toBase18(1.0)
    tokenBalanceOut = toBase18(11.0)
    tokenWeightOut = toBase18(1.0)
    swapFee = 0
    x = pool.calcSpotPrice(tokenBalanceIn, tokenWeightIn, tokenBalanceOut,
                           tokenWeightOut, swapFee)
    assert round(fromBase18(x), 3) == 0.909
Example #14
0
def test_rebind_more_tokens(T1, T2):
    pool = _createPoolWith2Tokens(T1, T2, 90.0, 10.0, 9.0, 1.0)

    # insufficient allowance
    with pytest.raises(Exception):
        pool.rebind(T1.address, toBase18(120.0), toBase18(9.0),
                    {"from": account0})

    # sufficient allowance
    T1.approve(pool.address, toBase18(30.0), {"from": account0})
    pool.rebind(T1.address, toBase18(120.0), toBase18(9.0), {"from": account0})
Example #15
0
 def unstakeOCEAN(self, BPT_unstake: float, pool):
     tokenOut_address = globaltokens.OCEAN_address()
     poolAmountIn_base = toBase18(BPT_unstake)
     minAmountOut_base = toBase18(0.0)
     pool.exitswapPoolAmountIn(
         tokenOut_address,
         poolAmountIn_base,
         minAmountOut_base,
         {"from": self._account},
     )
     self.resetCachedInfo()
Example #16
0
def test_exitswapPoolAmountIn(T1, T2):
    pool = _createPoolWith2Tokens(T1, T2, 90.0, 10.0, 9.0, 1.0)
    BPT = pool
    pool.finalize({"from": account0})
    assert fromBase18(T1.balanceOf(address0)) == 910.0
    tokenOut_address = T1.address
    poolAmountIn = toBase18(10.0)  # BPT spent
    minAmountOut = toBase18(1.0)  # min T1 wanted
    pool.exitswapPoolAmountIn(tokenOut_address, poolAmountIn, minAmountOut,
                              {"from": account0})
    assert fromBase18(T1.balanceOf(address0)) >= (910.0 + 1.0)
    assert fromBase18(BPT.balanceOf(address0)) == (100.0 - 10.0)
Example #17
0
def test_calcPoolOutGivenSingleIn():
    pool = _deployBPool()
    tokenBalanceIn = toBase18(10.0)
    tokenWeightIn = toBase18(1.0)
    poolSupply = toBase18(120.0)
    totalWeight = toBase18(2.0)
    tokenAmountIn = toBase18(0.1)
    swapFee = 0
    x = pool.calcPoolOutGivenSingleIn(tokenBalanceIn, tokenWeightIn,
                                      poolSupply, totalWeight, tokenAmountIn,
                                      swapFee)
    assert round(fromBase18(x), 3) == 0.599
Example #18
0
def test_calcSingleOutGivenPoolIn():
    pool = _deployBPool()
    tokenBalanceOut = toBase18(10.0)
    tokenWeightOut = toBase18(1.0)
    poolSupply = toBase18(120.0)
    totalWeight = toBase18(2.0)
    poolAmountIn = toBase18(10.0)
    swapFee = 0
    x = pool.calcSingleOutGivenPoolIn(tokenBalanceOut, tokenWeightOut,
                                      poolSupply, totalWeight, poolAmountIn,
                                      swapFee)
    assert round(fromBase18(x), 3) == 1.597
Example #19
0
def test_joinswapPoolAmountOut(T1, T2):
    pool = _createPoolWith2Tokens(T1, T2, 90.0, 10.0, 9.0, 1.0)
    BPT = pool
    pool.finalize({"from": account0})
    T1.approve(pool.address, toBase18(90.0), {"from": account0})
    assert fromBase18(T1.balanceOf(address0)) == 910.0
    tokenIn_address = T1.address
    poolAmountOut = toBase18(10.0)  # BPT wanted
    maxAmountIn = toBase18(90.0)  # max T1 to spend
    pool.joinswapPoolAmountOut(tokenIn_address, poolAmountOut, maxAmountIn,
                               {"from": account0})
    assert fromBase18(T1.balanceOf(address0)) >= (910.0 - 90.0)
    assert fromBase18(BPT.balanceOf(address0)) == (100.0 + 10.0)
Example #20
0
    def joinPoolAddOCEAN(self, OCEAN_stake: float, pool):
        """adds more liquidity with joinswapExternAmountIn (only OCEAN), oceanv4 contracts"""
        OCEAN = globaltokens.OCEANtoken()
        OCEAN.approve(pool.address, toBase18(OCEAN_stake), {"from": self._account})
        tokenAmountIn_base = toBase18(OCEAN_stake)
        minPoolAmountOut_base = toBase18(0.1)

        pool.joinswapExternAmountIn(
            OCEAN.address,
            tokenAmountIn_base,
            minPoolAmountOut_base,
            {"from": self._account},
        )
        self.resetCachedInfo()
Example #21
0
 def stakeOCEAN(self, OCEAN_stake: float, pool):
     """Convert some OCEAN to DT, then add both as liquidity."""
     OCEAN = globaltokens.OCEANtoken()
     OCEAN.approve(pool.address, toBase18(OCEAN_stake), {"from": self._account})
     tokenIn_address = globaltokens.OCEAN_address()
     tokenAmountIn_base = toBase18(OCEAN_stake)
     minPoolAmountOut_base = toBase18(0.0)
     pool.joinswapExternAmountIn(
         tokenIn_address,
         tokenAmountIn_base,
         minPoolAmountOut_base,
         {"from": self._account},
     )
     self.resetCachedInfo()
Example #22
0
def _make_info(account):
    assert account.address != GOD_ACCOUNT.address

    OCEAN = globaltokens.OCEANtoken()

    # reset OCEAN balances on-chain, to avoid relying on brownie chain reverts
    # -assumes that DT and BPT in each test are new tokens each time, and
    #  therefore don't need re-setting
    for a in accounts:
        if a.address != GOD_ACCOUNT.address:
            OCEAN.transfer(GOD_ACCOUNT, OCEAN.balanceOf(a), {"from": a})

    class Info:
        def __init__(self):
            self.account = None
            self.agent = None
            self.DT = None
            self.pool = None

    info = Info()
    info.account = account

    class SimpleAgent(AgentBase.AgentBaseEvm):
        def takeStep(self, state):
            pass

    info.agent = SimpleAgent("agent1", USD=0.0, OCEAN=0.0)
    info.agent._wallet._account = account  # force agent to use this account
    info.agent._wallet.resetCachedInfo()  # because account changed wallet

    info.DT = _createDT(account)
    info.agent._wallet.resetCachedInfo()  # because DT was deposited to account
    assert info.DT.balanceOf(account) == toBase18(_DT_INIT)

    globaltokens.fundOCEANFromAbove(account.address, toBase18(_OCEAN_INIT))
    info.agent._wallet.resetCachedInfo(
    )  # because OCEAN was deposited to account

    info.pool = _createPool(info.DT, account)  # create pool, stake DT & OCEAN
    info.agent._wallet.resetCachedInfo()  # because OCEAN & DT was staked

    # postconditions
    w = info.agent._wallet
    OCEAN1 = w.OCEAN()
    assert w._cached_OCEAN_base is not None
    OCEAN2 = fromBase18(int(w._cached_OCEAN_base))
    OCEAN3 = fromBase18(OCEAN.balanceOf(account))
    assert OCEAN1 == OCEAN2 == OCEAN3, (OCEAN1, OCEAN2, OCEAN3)

    return info
def test_via_newDatatoken_util():
    dt = sol057.contracts.oceanv3.oceanv3util.newDatatoken(
        "foo_blob", "datatoken1", "DT1", toBase18(100.0), account0
    )
    assert dt.blob() == "foo_blob"
    assert dt.name() == "datatoken1"
    assert dt.symbol() == "DT1"
Example #24
0
def test_exitswapExternAmountOut(T1, T2):
    pool = _createPoolWith2Tokens(T1, T2, 90.0, 10.0, 9.0, 1.0)
    BPT = pool
    pool.finalize({"from": account0})
    assert fromBase18(T1.balanceOf(address0)) == 910.0
    tokenOut_address = T1.address
    tokenAmountOut = toBase18(2.0)  # T1 wanted
    maxPoolAmountIn = toBase18(10.0)  # max BPT spent
    pool.exitswapExternAmountOut(
        tokenOut_address,
        tokenAmountOut,  # T1 wanted
        maxPoolAmountIn,  # max BPT spent
        {"from": account0},
    )
    assert fromBase18(T1.balanceOf(address0)) == (910.0 + 2.0)
    assert fromBase18(BPT.balanceOf(address0)) >= (100.0 - 10.0)
Example #25
0
def _deployBPool():
    brownie.chain.reset()
    router = oceanv4util.deployRouter(account0)
    fundOCEANFromAbove(address0, toBase18(100000))

    (dataNFT,
     erc721_factory) = oceanv4util.createDataNFT("dataNFT", "DATANFTSYMBOL",
                                                 account0, router)

    DT_cap = 10000
    datatoken = oceanv4util.createDatatokenFromDataNFT("DT", "DTSYMBOL",
                                                       DT_cap, dataNFT,
                                                       account0)

    OCEAN_init_liquidity = 80000
    DT_OCEAN_rate = 0.1
    DT_vest_amt = 1000
    DT_vest_num_blocks = 600
    pool = oceanv4util.createBPoolFromDatatoken(
        datatoken,
        erc721_factory,
        account0,
        OCEAN_init_liquidity,
        DT_OCEAN_rate,
        DT_vest_amt,
        DT_vest_num_blocks,
    )

    return pool
Example #26
0
    def __init__(self, USD: float = 0.0, OCEAN: float = 0.0, private_key=None):
        AgentWalletAbstract.__init__(self, USD, OCEAN, private_key)
        UsdNoEvmWalletMixIn.__init__(self, USD)

        self._account: Account = None

        accounts = brownie.network.accounts
        if private_key is None:
            self._account = accounts.add()
        else:
            self._account = accounts.add(private_key=private_key)

        # Give the new wallet ETH to pay gas fees (but don't track otherwise)
        GOD_ACCOUNT.transfer(self._account, "0.01 ether")

        # OCEAN is tracked in EVM, not here. But we cache here for speed
        self._burnOCEAN_nocache()  # ensure 0 OCEAN (eg >1 unit tests)
        self._cached_OCEAN_base: typing.Union[int, None] = None
        self._total_OCEAN_in: float = OCEAN
        assert self.OCEAN() == 0.0

        globaltokens.fundOCEANFromAbove(self._account.address, toBase18(OCEAN))
        self._cached_OCEAN_base = None

        # postconditions
        assert self.USD() == USD
        assert self.OCEAN() == OCEAN
Example #27
0
    def transferOCEAN(self, dst_wallet, amt: float) -> None:
        assert isinstance(dst_wallet, (AgentWalletEvm, BurnWallet))
        dst_address = dst_wallet.address

        amt_base = toBase18(amt)
        assert amt_base >= 0
        if amt_base == 0:
            return

        OCEAN_base = self._OCEAN_base()
        if OCEAN_base == 0:
            raise ValueError("no funds to transfer from")

        tol = 1e-12
        if (1.0 - tol) <= amt / fromBase18(OCEAN_base) <= (1.0 + tol):
            amt_base = OCEAN_base

        if amt_base > OCEAN_base:
            raise ValueError(
                "transfer amt ({fromBase18(amt_base)})"
                " exceeds OCEAN holdings ({fromBase18(OCEAN_base)})"
            )

        globaltokens.OCEANtoken().transfer(
            dst_address, amt_base, {"from": self._account}
        )

        dst_wallet._total_OCEAN_in += amt
        self.resetCachedInfo()
        dst_wallet.resetCachedInfo()
def test_swapExactAmountOut():
    brownie.chain.reset()
    OCEAN = OCEANtoken()
    (DT, pool, _) = _deployBPool(do_extra_funding=True)

    tokenInOutMarket = [
        OCEAN.address,
        DT.address,
        address0,
    ]  # // [tokenIn,tokenOut,marketFeeAddress]
    amountsInOutMaxFee = [toBase18(1000), toBase18(10), toBase18(1000), 0]

    assert DT.balanceOf(address0) == 0
    pool.swapExactAmountOut(tokenInOutMarket, amountsInOutMaxFee,
                            {"from": account0})
    assert DT.balanceOf(address0) > 0
Example #29
0
def test_calcInGivenOut():
    pool = _deployBPool()
    tokenBalanceIn = toBase18(10.0)
    tokenWeightIn = toBase18(1.0)
    tokenBalanceOut = toBase18(10.1)
    tokenWeightOut = toBase18(1.0)
    tokenAmountOut = toBase18(1.0)
    swapFee = 0
    x = pool.calcInGivenOut(
        tokenBalanceIn,
        tokenWeightIn,
        tokenBalanceOut,
        tokenWeightOut,
        tokenAmountOut,
        swapFee,
    )
    assert round(fromBase18(x), 3) == 1.099
Example #30
0
def test_calcPoolInGivenSingleOut():
    pool = _deployBPool()
    tokenBalanceOut = toBase18(1000.0)
    tokenWeightOut = toBase18(5.0)
    poolSupply = toBase18(100.0)
    totalWeight = toBase18(10.0)
    tokenAmountOut = toBase18(0.1)
    swapFee = 0
    x = pool.calcPoolInGivenSingleOut(
        tokenBalanceOut,
        tokenWeightOut,
        poolSupply,
        totalWeight,
        tokenAmountOut,
        swapFee,
    )
    assert round(fromBase18(x), 3) == 0.005