Skip to content

Commit

Permalink
Fix bet amount calculation in sDai markets (#393)
Browse files Browse the repository at this point in the history
  • Loading branch information
kongzii authored Sep 10, 2024
1 parent b634be3 commit fffbc83
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 25 deletions.
11 changes: 8 additions & 3 deletions prediction_market_agent_tooling/markets/omen/omen.py
Original file line number Diff line number Diff line change
Expand Up @@ -611,32 +611,36 @@ def omen_buy_outcome_tx(
market_contract: OmenFixedProductMarketMakerContract = market.get_contract()
collateral_token_contract = market_contract.get_collateral_token_contract()

# In case of ERC4626, obtained (for example) sDai out of xDai could be lower than the `amount_wei`, so we need to handle it.
amount_wei_to_buy = collateral_token_contract.get_in_shares(amount_wei, web3)

# Get the index of the outcome we want to buy.
outcome_index: int = market.get_outcome_index(outcome)

# Calculate the amount of shares we will get for the given investment amount.
expected_shares = market_contract.calcBuyAmount(
amount_wei, outcome_index, web3=web3
amount_wei_to_buy, outcome_index, web3=web3
)
# Allow 1% slippage.
expected_shares = remove_fraction(expected_shares, 0.01)
# Approve the market maker to withdraw our collateral token.
collateral_token_contract.approve(
api_keys=api_keys,
for_address=market_contract.address,
amount_wei=amount_wei,
amount_wei=amount_wei_to_buy,
web3=web3,
)

if auto_deposit:
# In auto-depositing, we need to deposit the original `amount_wei`, e.g. we can deposit 2 xDai, but receive 1.8 sDai, so for the bet we will use `amount_wei_to_buy`.
auto_deposit_collateral_token(
collateral_token_contract, amount_wei, api_keys, web3
)

# Buy shares using the deposited xDai in the collateral token.
market_contract.buy(
api_keys=api_keys,
amount_wei=amount_wei,
amount_wei=amount_wei_to_buy,
outcome_index=outcome_index,
min_outcome_tokens_to_buy=expected_shares,
web3=web3,
Expand Down Expand Up @@ -827,6 +831,7 @@ def omen_create_market_tx(
web3=web3,
)

# In case of ERC4626, obtained (for example) sDai out of xDai could be lower than the `amount_wei`, so we need to handle it.
initial_funds_in_shares = collateral_token_contract.get_in_shares(
amount=initial_funds_wei, web3=web3
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@
byte32_to_ipfscidv0,
)

# TODO: Agents don't know how to convert value between other tokens, we assume 1 unit = 1xDai = $1 (for example if market would be in wETH, betting 1 unit of wETH would be crazy :D)
SAFE_COLLATERAL_TOKEN_MARKETS = (
WrappedxDaiContract().address,
sDaiContract().address,
)


class OmenSubgraphHandler(metaclass=SingletonMeta):
"""
Expand Down Expand Up @@ -318,6 +324,8 @@ def get_omen_binary_markets_simple(
# Additional filters, these can not be modified by the enums above.
created_after: datetime | None = None,
excluded_questions: set[str] | None = None, # question titles
collateral_token_address_in: tuple[ChecksumAddress, ...]
| None = SAFE_COLLATERAL_TOKEN_MARKETS,
) -> t.List[OmenMarket]:
"""
Simplified `get_omen_binary_markets` method, which allows to fetch markets based on the filter_by and sort_by values.
Expand Down Expand Up @@ -354,6 +362,7 @@ def get_omen_binary_markets_simple(
sort_by_field=sort_by_field,
created_after=created_after,
excluded_questions=excluded_questions,
collateral_token_address_in=collateral_token_address_in,
)

def get_omen_binary_markets(
Expand All @@ -375,12 +384,8 @@ def get_omen_binary_markets(
sort_by_field: FieldPath | None = None,
sort_direction: str | None = None,
outcomes: list[str] = [OMEN_TRUE_OUTCOME, OMEN_FALSE_OUTCOME],
# TODO: Agents don't know how to convert value between other tokens, we assume 1 unit = 1xDai = $1 (for example if market would be in wETH, betting 1 unit of wETH would be crazy :D)
collateral_token_address_in: tuple[ChecksumAddress, ...]
| None = (
WrappedxDaiContract().address,
sDaiContract().address,
),
| None = SAFE_COLLATERAL_TOKEN_MARKETS,
) -> t.List[OmenMarket]:
"""
Complete method to fetch Omen binary markets with various filters, use `get_omen_binary_markets_simple` for simplified version that uses FilterBy and SortBy enums.
Expand Down
41 changes: 24 additions & 17 deletions tests_integration_with_local_chain/markets/omen/test_omen.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
from prediction_market_agent_tooling.markets.omen.omen_contracts import (
OMEN_DEFAULT_MARKET_FEE,
ContractDepositableWrapperERC20OnGnosisChain,
ContractERC4626OnGnosisChain,
OmenConditionalTokenContract,
OmenFixedProductMarketMakerContract,
OmenRealitioContract,
Expand Down Expand Up @@ -309,23 +310,41 @@ def get_market_outcome_tokens() -> TokenAmount:
assert np.isclose(remaining_tokens.amount, 0, atol=1e-5)


@pytest.mark.parametrize(
"collateral_token_address, expected_symbol",
[
(WrappedxDaiContract().address, "WXDAI"),
(sDaiContract().address, "sDAI"),
],
)
def test_place_bet_with_autodeposit(
collateral_token_address: ChecksumAddress,
expected_symbol: str,
local_web3: Web3,
test_keys: APIKeys,
) -> None:
market = OmenAgentMarket.from_data_model(pick_binary_market())
market = OmenAgentMarket.from_data_model(
OmenSubgraphHandler().get_omen_binary_markets_simple(
limit=1,
filter_by=FilterBy.OPEN,
sort_by=SortBy.CLOSING_SOONEST,
collateral_token_address_in=(collateral_token_address,),
)[0]
)
initial_balances = get_balances(address=test_keys.bet_from_address, web3=local_web3)
collateral_token_contract = market.get_contract().get_collateral_token_contract()
assert (
collateral_token_contract.symbol() == "WXDAI"
), "Should have retrieve wxDai market."
collateral_token_contract.symbol() == expected_symbol
), f"Should have retrieve {expected_symbol} market."
assert isinstance(
collateral_token_contract, ContractDepositableWrapperERC20OnGnosisChain
), "wxDai market should adhere to this class."
) or isinstance(
collateral_token_contract, ContractERC4626OnGnosisChain
), "Omen market should adhere to one of these classes."

# Start by moving all funds from wxdai to xdai
if initial_balances.wxdai > 0:
collateral_token_contract.withdraw(
WrappedxDaiContract().withdraw(
api_keys=test_keys,
amount_wei=xdai_to_wei(initial_balances.wxdai),
web3=local_web3,
Expand All @@ -336,20 +355,8 @@ def test_place_bet_with_autodeposit(
assert initial_balances.wxdai == xdai_type(0)
assert initial_balances.xdai > xdai_type(0)

# Convert half of the xDai to wxDai
collateral_token_contract.deposit(
api_keys=test_keys,
amount_wei=xdai_to_wei(xdai_type(initial_balances.xdai * 0.5)),
web3=local_web3,
)
new_balances = get_balances(address=test_keys.bet_from_address, web3=local_web3)
assert np.allclose(new_balances.total, initial_balances.total)

# Try to place a bet with 90% of the xDai funds
bet_amount = BetAmount(amount=initial_balances.xdai * 0.9, currency=Currency.xDai)
assert new_balances.xdai < bet_amount.amount
assert new_balances.wxdai < bet_amount.amount
assert new_balances.total > bet_amount.amount
market.place_bet(
outcome=True,
amount=bet_amount,
Expand Down

0 comments on commit fffbc83

Please sign in to comment.