Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add test to showcase that job-creator would profit from liars #442

Merged
merged 28 commits into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
c207cd4
Integrate Tenderly to local_web3
kongzii Sep 26, 2024
6e352b0
lint
kongzii Sep 26, 2024
1cdb9f7
Add a new contract used for debugging
kongzii Sep 26, 2024
7493519
Add a new validator to convert blockchain timestamps to correct datetime
kongzii Sep 26, 2024
28e68b8
lint
kongzii Sep 26, 2024
4159c71
Dont be quiet
kongzii Sep 26, 2024
3b4708b
lint
kongzii Sep 26, 2024
4da7b62
Create OmenMarket out of blockchain events
kongzii Sep 26, 2024
48258fe
fix creation timestamp
kongzii Sep 26, 2024
1fef71e
Add test to showcase that job-creator would profit from liars
kongzii Sep 26, 2024
d8337d0
typo
kongzii Sep 26, 2024
4c34b40
more typos
kongzii Sep 26, 2024
5a83924
typooo
kongzii Sep 26, 2024
0312c55
Use `mint_new_block`
kongzii Sep 30, 2024
75d1f1e
lower the difference
kongzii Sep 30, 2024
c3feff1
Merge branch 'main' into peter/debugging-contract
kongzii Sep 30, 2024
e869421
fix circular import
kongzii Sep 30, 2024
4930a23
fix another test
kongzii Sep 30, 2024
ec70b35
be less strict
kongzii Sep 30, 2024
51ac55f
lint
kongzii Sep 30, 2024
2484dfb
Merge branch 'peter/debugging-contract' into peter/new-timezone-valid…
kongzii Sep 30, 2024
853fe3e
fix bad merge
kongzii Sep 30, 2024
b33ebc0
Merge branch 'peter/new-timezone-validator' into peter/events
kongzii Sep 30, 2024
180902e
Merge branch 'peter/events' into peter/stealing
kongzii Sep 30, 2024
c265c42
use new f
kongzii Sep 30, 2024
2989b8e
remmove unused
kongzii Sep 30, 2024
959e531
Merge branch 'main' into peter/stealing
kongzii Oct 1, 2024
1c7161d
Remove more unsused vars and fix test
kongzii Oct 1, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/python_ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ jobs:
- name: Check with autoflake
run: |
poetry run autoflake --in-place --remove-all-unused-imports --remove-unused-variables --recursive .
git diff --exit-code --quiet || exit 1
git diff --exit-code || exit 1

isort:
runs-on: ubuntu-latest
Expand All @@ -74,4 +74,4 @@ jobs:
- name: Check with isort
run: |
poetry run isort --profile black .
git diff --exit-code --quiet || exit 1
git diff --exit-code || exit 1
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,6 @@ cython_debug/
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

tests_files/*
!tests_files/.gitkeep
29 changes: 29 additions & 0 deletions prediction_market_agent_tooling/abis/debuggingcontract.abi.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
[
{
"constant": false,
"inputs": [],
"name": "inc",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "counter",
"outputs": [{ "name": "", "type": "uint256" }],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getNow",
"outputs": [{ "name": "", "type": "uint32" }],
"payable": false,
"stateMutability": "view",
"type": "function"
}
]
1 change: 1 addition & 0 deletions prediction_market_agent_tooling/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class APIKeys(BaseSettings):
SAFE_ADDRESS: t.Optional[ChecksumAddress] = None
OPENAI_API_KEY: t.Optional[SecretStr] = None
GRAPH_API_KEY: t.Optional[SecretStr] = None
TENDERLY_FORK_RPC: t.Optional[str] = None

GOOGLE_SEARCH_API_KEY: t.Optional[SecretStr] = None
GOOGLE_SEARCH_ENGINE_ID: t.Optional[SecretStr] = None
Expand Down
6 changes: 3 additions & 3 deletions prediction_market_agent_tooling/markets/agent_market.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
TokenAmount,
)
from prediction_market_agent_tooling.tools.utils import (
add_utc_timezone_validator,
check_not_none,
convert_to_utc_datetime,
should_not_happen,
utcnow,
)
Expand Down Expand Up @@ -61,10 +61,10 @@ class AgentMarket(BaseModel):
volume: float | None # Should be in currency of `currency` above.

_add_timezone_validator_created_time = field_validator("created_time")(
add_utc_timezone_validator
convert_to_utc_datetime
)
_add_timezone_validator_close_time = field_validator("close_time")(
add_utc_timezone_validator
convert_to_utc_datetime
)

@field_validator("outcome_token_pool")
Expand Down
191 changes: 189 additions & 2 deletions prediction_market_agent_tooling/markets/omen/data_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
OmenOutcomeToken,
Probability,
Wei,
wei_type,
xDai,
)
from prediction_market_agent_tooling.markets.data_models import (
Expand All @@ -37,6 +38,7 @@
INVALID_ANSWER_STR = HexStr(INVALID_ANSWER_HEX_BYTES.hex())
OMEN_BASE_URL = "https://aiomen.eth.limo"
PRESAGIO_BASE_URL = "https://presagio.pages.dev"
TEST_CATEGORY = "test" # This category is hidden on Presagio for testing purposes.


def get_boolean_outcome(outcome_str: str) -> bool:
Expand Down Expand Up @@ -207,8 +209,6 @@ class OmenMarket(BaseModel):
creationTimestamp: int
condition: Condition
question: Question
lastActiveDay: int
lastActiveHour: int

@property
def openingTimestamp(self) -> int:
Expand Down Expand Up @@ -376,6 +376,75 @@ def get_resolution_enum(self) -> t.Optional[Resolution]:
def url(self) -> str:
return f"{PRESAGIO_BASE_URL}/markets?id={self.id}"

@staticmethod
def from_created_market(model: "CreatedMarket") -> "OmenMarket":
"""
OmenMarket is meant to be retrieved from subgraph, however in tests against local chain it's very handy to create it out of `CreatedMarket`,
which is collection of events that are emitted during the market creation in omen_create_market_tx function.
"""
if len(model.market_event.conditionIds) != 1:
raise ValueError(
f"Unexpected number of conditions: {len(model.market_event.conditionIds)}"
)
outcome_token_amounts = model.funding_event.outcome_token_amounts
total_amount = sum(outcome_token_amounts)
outcome_token_marginal_prices = [
xDai((total_amount - amount) / total_amount)
for amount in outcome_token_amounts
]
return OmenMarket(
id=HexAddress(
HexStr(model.market_event.fixedProductMarketMaker.lower())
), # Lowering to be identical with subgraph's output.
title=model.question_event.parsed_question.question,
creator=HexAddress(
HexStr(model.market_event.creator.lower())
), # Lowering to be identical with subgraph's output.
category=model.question_event.parsed_question.category,
collateralVolume=Wei(0), # No volume possible yet.
liquidityParameter=calculate_liquidity_parameter(outcome_token_amounts),
usdVolume=USD(0), # No volume possible yet.
fee=model.fee,
collateralToken=HexAddress(
HexStr(model.market_event.collateralToken.lower())
), # Lowering to be identical with subgraph's output.
outcomes=model.question_event.parsed_question.outcomes,
outcomeTokenAmounts=outcome_token_amounts,
outcomeTokenMarginalPrices=outcome_token_marginal_prices,
answerFinalizedTimestamp=None, # It's a fresh market.
currentAnswer=None, # It's a fresh market.
creationTimestamp=model.market_creation_timestamp,
condition=Condition(
id=model.market_event.conditionIds[0],
outcomeSlotCount=len(model.question_event.parsed_question.outcomes),
),
question=Question(
id=model.question_event.question_id,
title=model.question_event.parsed_question.question,
data=model.question_event.question, # Question in the event holds the "raw" data.
templateId=model.question_event.template_id,
outcomes=model.question_event.parsed_question.outcomes,
isPendingArbitration=False, # Can not be, it's a fresh market.
openingTimestamp=model.question_event.opening_ts,
answerFinalizedTimestamp=None, # It's a new one, can not be.
currentAnswer=None, # It's a new one, no answer yet.
),
)


def calculate_liquidity_parameter(
outcome_token_amounts: list[OmenOutcomeToken],
) -> Wei:
"""
Converted to Python from https://github.com/protofire/omen-subgraph/blob/f92bbfb6fa31ed9cd5985c416a26a2f640837d8b/src/utils/fpmm.ts#L171.
"""
amounts_product = 1.0
for amount in outcome_token_amounts:
amounts_product *= amount
n = len(outcome_token_amounts)
liquidity_parameter = amounts_product ** (1.0 / n)
return wei_type(liquidity_parameter)


class OmenBetCreator(BaseModel):
id: HexAddress
Expand Down Expand Up @@ -533,3 +602,121 @@ class RealityAnswers(BaseModel):

class RealityAnswersResponse(BaseModel):
data: RealityAnswers


def format_realitio_question(
question: str,
outcomes: list[str],
category: str,
language: str,
template_id: int,
) -> str:
"""If you add a new template id here, also add to the parsing function below."""
if template_id == 2:
return "␟".join(
[
question,
",".join(f'"{o}"' for o in outcomes),
category,
language,
]
)

raise ValueError(f"Unsupported template id {template_id}.")


def parse_realitio_question(question_raw: str, template_id: int) -> "ParsedQuestion":
"""If you add a new template id here, also add to the encoding function above."""
if template_id == 2:
question, outcomes_raw, category, language = question_raw.split("␟")
outcomes = [o.strip('"') for o in outcomes_raw.split(",")]
return ParsedQuestion(
question=question, outcomes=outcomes, category=category, language=language
)

raise ValueError(f"Unsupported template id {template_id}.")


class ParsedQuestion(BaseModel):
question: str
outcomes: list[str]
language: str
category: str


class RealitioLogNewQuestionEvent(BaseModel):
question_id: HexBytes
user: HexAddress
template_id: int
question: str # Be aware, this is question in format of format_realitio_question function, it's raw data.
content_hash: HexBytes
arbitrator: HexAddress
timeout: int
opening_ts: int
nonce: int
created: int

@property
def user_checksummed(self) -> ChecksumAddress:
return Web3.to_checksum_address(self.user)

@property
def parsed_question(self) -> ParsedQuestion:
return parse_realitio_question(
question_raw=self.question, template_id=self.template_id
)


class OmenFixedProductMarketMakerCreationEvent(BaseModel):
creator: HexAddress
fixedProductMarketMaker: HexAddress
conditionalTokens: HexAddress
collateralToken: HexAddress
conditionIds: list[HexBytes]
fee: int

@property
def creator_checksummed(self) -> ChecksumAddress:
return Web3.to_checksum_address(self.creator)

@property
def fixed_product_market_maker_checksummed(self) -> ChecksumAddress:
return Web3.to_checksum_address(self.fixedProductMarketMaker)

@property
def conditional_tokens_checksummed(self) -> ChecksumAddress:
return Web3.to_checksum_address(self.conditionalTokens)

@property
def collateral_token_checksummed(self) -> ChecksumAddress:
return Web3.to_checksum_address(self.collateralToken)


class ConditionPreparationEvent(BaseModel):
conditionId: HexBytes
oracle: HexAddress
questionId: HexBytes
outcomeSlotCount: int


class FPMMFundingAddedEvent(BaseModel):
funder: HexAddress
amountsAdded: list[OmenOutcomeToken]
sharesMinted: Wei

@property
def outcome_token_amounts(self) -> list[OmenOutcomeToken]:
# Just renaming so we remember what it is.
return self.amountsAdded


class CreatedMarket(BaseModel):
market_creation_timestamp: int
market_event: OmenFixedProductMarketMakerCreationEvent
funding_event: FPMMFundingAddedEvent
condition_id: HexBytes
question_event: RealitioLogNewQuestionEvent
condition_event: ConditionPreparationEvent | None
initial_funds: Wei
fee: Wei
distribution_hint: list[OmenOutcomeToken] | None
Loading
Loading