예제 #1
0
def get_OCEAN_in_BPTs(state, agent):
    """Value of BPTs that this agent owns across all pools, denominated in OCEAN

    Args:
        state: SimState -- SimState, holds all pool agents (& their pools)
        agent:  AgentBase -- agent of interest

    Returns:
        value_held: float -- value of BPTs, denominated in OCEAN
    """
    OCEAN_address = globaltokens.OCEAN_address()
    value_held = 0

    for pool_agent in state.agents.filterToPool().values():
        pool = pool_agent._pool
        DT = pool_agent._dt

        price = fromBase18(pool.getSpotPrice(OCEAN_address, DT.address))
        pool_value_DT = price * fromBase18(pool.getBalance(DT.address))
        pool_value_OCEAN = fromBase18(pool.getBalance(OCEAN_address))
        pool_value = pool_value_DT + pool_value_OCEAN

        amt_pool_BPTs = fromBase18(pool.totalSupply())
        agent_percent_pool = agent.BPT(pool) / amt_pool_BPTs

        value_held += agent_percent_pool * pool_value

    return value_held
예제 #2
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()
예제 #3
0
    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
예제 #4
0
def test_get_OCEAN_in_BPTs(alice_info):
    state = MockSimState()

    pool, DT = alice_info.pool, alice_info.DT
    pool_agent = PoolAgent("pool_agent", pool)
    state.agents["agent1"] = pool_agent

    foo_agent = FooAgent("foo_agent")

    OCEAN_address = globaltokens.OCEAN_address()
    price = fromBase18(pool.getSpotPrice(OCEAN_address, DT.address))
    pool_value_DT = price * fromBase18(pool.getBalance(DT.address))
    pool_value_OCEAN = fromBase18(pool.getBalance(OCEAN_address))
    pool_value = pool_value_DT + pool_value_OCEAN

    # case: foo_agent no BPTs
    value_held = KPIs.get_OCEAN_in_BPTs(state, foo_agent)
    foo_agent_pool_shape = foo_agent._BPT / fromBase18(pool.totalSupply())

    assert value_held == approx(foo_agent_pool_shape * pool_value)

    # case: foo_agent has all BPTs
    foo_agent._BPT = fromBase18(
        pool.totalSupply())  # make pool think agent has 100% of BPTs
    value_held = KPIs.get_OCEAN_in_BPTs(state, foo_agent)

    assert value_held == 1.0 * pool_value
예제 #5
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()
예제 #6
0
 def _datatokenAddress(self):
     addrs = self._pool.getCurrentTokens()
     assert len(addrs) == 2
     OCEAN_addr = globaltokens.OCEAN_address()
     for addr in addrs:
         if addr != OCEAN_addr:
             return addr
     raise AssertionError("should never get here")
예제 #7
0
def _poolToDTaddress(pool) -> str:
    """Return the address of the datatoken of this pool.
    Don't make this public because it has strong assumptions:
    assumes 2 tokens; assumes one token is OCEAN; assumes other is DT
    """
    cur_addrs = pool.getCurrentTokens()
    assert len(cur_addrs) == 2, "this method currently assumes 2 tokens"
    OCEAN_addr = globaltokens.OCEAN_address()
    assert OCEAN_addr in cur_addrs, "this method expects one token is OCEAN"
    DT_addr = [addr for addr in cur_addrs if addr != OCEAN_addr][0]
    return DT_addr
예제 #8
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()
예제 #9
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()
예제 #10
0
def test_get_OCEAN_in_DTs(alice_info):
    state = MockSimState()

    pool, DT = alice_info.pool, alice_info.DT
    pool_agent = PoolAgent("pool_agent", pool)
    state.agents["agent1"] = pool_agent

    foo_agent = FooAgent("foo_agent")

    OCEAN_address = globaltokens.OCEAN_address()
    price = fromBase18(pool.getSpotPrice(OCEAN_address, DT.address))

    amt_DT = foo_agent.DT("bar")
    assert amt_DT == 3.0

    value_held = KPIs.get_OCEAN_in_DTs(state, foo_agent)
    assert value_held == amt_DT * price
예제 #11
0
    def sellDT(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
        pool.swapExactAmountIn(
            tokenIn_address,
            tokenAmountIn_base,
            tokenOut_address,
            minAmountOut_base,
            maxPrice_base,
            {"from": self._account},
        )
        self.resetCachedInfo()
예제 #12
0
    def buyDT(self, pool, DT, DT_buy_amt: float, max_OCEAN_allow: float):
        """Swap OCEAN for DT"""
        OCEAN = globaltokens.OCEANtoken()
        OCEAN.approve(pool.address, toBase18(max_OCEAN_allow), {"from": self._account})

        tokenIn_address = globaltokens.OCEAN_address()
        maxAmountIn_base = toBase18(max_OCEAN_allow)
        tokenOut_address = DT.address
        tokenAmountOut_base = toBase18(DT_buy_amt)
        maxPrice_base = 2 ** 255
        pool.swapExactAmountOut(
            tokenIn_address,
            maxAmountIn_base,
            tokenOut_address,
            tokenAmountOut_base,
            maxPrice_base,
            {"from": self._account},
        )
        self.resetCachedInfo()
예제 #13
0
def get_OCEAN_in_DTs(state, agent) -> float:
    """Value of DT that this agent staked across all pools, denominated in OCEAN
    Args:
        state: SimState -- SimState, holds all pool agents (& their pools)
        agent:  AgentBase -- agent of interest
    Returns:
        value_held: float -- value staked, denominated in OCEAN
    """
    OCEAN_address = globaltokens.OCEAN_address()
    value_held = 0.0

    for pool_agent in state.agents.filterToPoolV4().values():
        pool = pool_agent._pool
        DT = pool_agent._dt
        swapFee = pool.getSwapFee()
        price = fromBase18(pool.getSpotPrice(OCEAN_address, DT.address, swapFee))
        amt_DT = agent.DT(DT)
        value_held += amt_DT * price

    return value_held
예제 #14
0
def test_OCEAN():
    assert globaltokens.OCEANtoken().symbol() == "OCEAN"
    assert globaltokens.OCEAN_address()[:2] == "0x"
예제 #15
0
import brownie
import pytest

import sol057.contracts.oceanv3.oceanv3util
from util import globaltokens
from util.base18 import toBase18, fromBase18

accounts = brownie.network.accounts
account0, account1 = accounts[0], accounts[1]
address0, address1 = account0.address, account1.address
OCEAN_address = globaltokens.OCEAN_address()
HUGEINT = 2**255


def test_notokens_basic():
    pool = _deployBPool()

    assert not pool.isPublicSwap()
    assert not pool.isFinalized()
    assert not pool.isBound(OCEAN_address)
    assert pool.getNumTokens() == 0
    assert pool.getCurrentTokens() == []
    with pytest.raises(Exception):
        pool.getFinalTokens()  # pool's not finalized
    assert pool.getSwapFee() == toBase18(1e-6)
    assert pool.getController() == address0
    assert str(pool)

    with pytest.raises(Exception):
        pool.finalize()  # can't finalize if no tokens
예제 #16
0
def netlist_createLogData(state): #pylint: disable=too-many-statements
    """SimEngine constructor uses this"""
    s = []  # for console logging
    dataheader = []  # for csv logging: list of string
    datarow = []  # for csv logging: list of float

    # SimEngine already logs: Tick, Second, Min, Hour, Day, Month, Year
    # So we log other things...
    agents_names = [
        "publisher",
        # "consumer",
        "stakerSpeculator",
        "speculator",
        # "buySellRobot",
        # "maliciousPublisher"
        # "erc721"
    ]
    # tracking OCEAN
    OCEANtoken = globaltokens.OCEANtoken()
    OCEAN_address = globaltokens.OCEAN_address()
    for name in agents_names:
        agent = state.getAgent(name)

        # in wallet
        dataheader += [f"{name}_OCEAN"]
        datarow += [agent.OCEAN()]

        # in DTs
        dataheader += [f"{name}_OCEAN_in_DTs"]
        datarow += [get_OCEAN_in_DTs(state, agent)]

        # in BPTs
        dataheader += [f"{name}_OCEAN_in_BPTs"]
        datarow += [get_OCEAN_in_BPTs(state, agent)]

        # networth
        dataheader += [f"{name}_OCEAN_networth"]
        datarow += [
            agent.OCEAN()
            + get_OCEAN_in_DTs(state, agent)
            + get_OCEAN_in_BPTs(state, agent)
        ]

        dataheader += [f"DT_{name}"]
        dataheader += [f"BPT_{name}"]

        # Tracking DT and BPT balances of agents
        if any(state.agents.filterToPoolV4().values()):
            poolAgent_0 = list(state.agents.filterToPoolV4().values())[0]
            DT = poolAgent_0._dt
            amt_DT = agent.DT(DT)
            datarow += [amt_DT]
            datarow += [agent.BPT(poolAgent_0._pool)]  # agent.BPT(pool)
        else:
            datarow += [0, 0]

    # Track pool0
    # 1. DT in pool,
    # 2. DT balance of 1ss contract
    # 3. BPT total supply,
    # 4. BPT balance of 1ss contract,
    # 5. DT spot price
    # 6. OCEAN in pool
    dataheader += ["DT_pool"]
    dataheader += ["DT_1ss_contract"]
    dataheader += ["BPT_total"]
    dataheader += ["BPT_1ss_contract"]
    dataheader += ["DT_price"]
    dataheader += ["pool_OCEAN"]
    if any(state.agents.filterToPoolV4().values()):
        poolAgent_0 = list(state.agents.filterToPoolV4().values())[0]
        pool0 = poolAgent_0._pool
        DT = poolAgent_0._dt
        oneSSContractAddress = pool0.getController()

        datarow += [fromBase18(DT.balanceOf(pool0.address))]  # 1
        datarow += [fromBase18(DT.balanceOf(oneSSContractAddress))]  # 2
        datarow += [fromBase18(pool0.totalSupply())]  # 3
        datarow += [fromBase18(pool0.balanceOf(oneSSContractAddress))]  # 4
        swapFee = pool0.getSwapFee()
        datarow += [
            fromBase18(pool0.getSpotPrice(OCEAN_address, DT.address, swapFee))
        ]  # 5
        datarow += [fromBase18(OCEANtoken.balanceOf(pool0.address))]
    else:
        datarow += [0, 0, 0, 0, 0, 0]

    pool_agents = state.agents.filterToPoolV4()
    n_pools = len(pool_agents)
    s += [f"; # pools={n_pools}"]
    dataheader += ["n_pools"]
    datarow += [n_pools]

    rugged_pool = state.rugged_pools
    n_rugged = len(rugged_pool)
    # s += [f"; # rugged pools={n_rugged}"]
    s += [f"; # block height={brownie.chain.height}"]
    dataheader += ["n_rugged"]
    datarow += [n_rugged]

    return s, dataheader, datarow