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 a new contract used for debugging #437

Merged
merged 10 commits into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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"
}
]
50 changes: 49 additions & 1 deletion prediction_market_agent_tooling/tools/contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import time
import typing as t
from contextlib import contextmanager
from datetime import datetime

import pytz
from pydantic import BaseModel, field_validator
from web3 import Web3

Expand All @@ -21,7 +23,11 @@
GNOSIS_NETWORK_ID,
GNOSIS_RPC_URL,
)
from prediction_market_agent_tooling.tools.utils import should_not_happen
from prediction_market_agent_tooling.tools.utils import (
DatetimeWithTimezone,
add_utc_timezone_validator,
should_not_happen,
)
from prediction_market_agent_tooling.tools.web3_utils import (
call_function_on_contract,
send_function_on_contract_tx,
Expand Down Expand Up @@ -423,6 +429,48 @@ def get_asset_token_contract(
return to_gnosis_chain_contract(super().get_asset_token_contract(web3=web3))


class DebuggingContract(ContractOnGnosisChain):
# Contract ABI taken from https://gnosisscan.io/address/0x5Aa82E068aE6a6a1C26c42E5a59520a74Cdb8998#code.
abi: ABI = abi_field_validator(
os.path.join(
os.path.dirname(os.path.realpath(__file__)),
"../abis/debuggingcontract.abi.json",
)
)
address: ChecksumAddress = Web3.to_checksum_address(
"0x5Aa82E068aE6a6a1C26c42E5a59520a74Cdb8998"
)
Comment on lines +440 to +442
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider parameterizing the contract address

The contract address is hard-coded in the DebuggingContract class. For better flexibility and maintainability, consider passing the address as a parameter or reading it from a configuration file. This will make it easier to update the address if it changes in the future.


def getNow(
self,
web3: Web3 | None = None,
) -> int:
now: int = self.call(
function_name="getNow",
web3=web3,
)
return now

def get_now(
self,
web3: Web3 | None = None,
) -> DatetimeWithTimezone:
return add_utc_timezone_validator(
datetime.fromtimestamp(self.getNow(web3), tz=pytz.UTC)
)
gabrielfior marked this conversation as resolved.
Show resolved Hide resolved

def inc(
self,
api_keys: APIKeys,
web3: Web3 | None = None,
) -> TxReceipt:
return self.send(
api_keys=api_keys,
function_name="inc",
web3=web3,
)


def contract_implements_function(
contract_address: ChecksumAddress,
function_name: str,
Expand Down
13 changes: 13 additions & 0 deletions tests/utils.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
import os

from web3 import Web3

from prediction_market_agent_tooling.config import APIKeys
from prediction_market_agent_tooling.tools.contract import DebuggingContract

RUN_PAID_TESTS = os.environ.get("RUN_PAID_TESTS", "0") == "1"


def mint_new_block(keys: APIKeys, web3: Web3) -> None:
"""
Mints a new block on the web3's blockchain.
Useful for tests that debends on chain's timestamp, this will update it.
"""
DebuggingContract().inc(keys, web3)
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import time

from ape_test import TestAccount
from eth_account import Account
from numpy import isclose
Expand All @@ -10,11 +12,14 @@
is_minimum_required_balance,
)
from prediction_market_agent_tooling.tools.balances import get_balances
from prediction_market_agent_tooling.tools.contract import DebuggingContract
from prediction_market_agent_tooling.tools.utils import utcnow
from prediction_market_agent_tooling.tools.web3_utils import (
send_xdai_to,
wei_to_xdai,
xdai_to_wei,
)
from tests.utils import mint_new_block


def test_connect_local_chain(local_web3: Web3) -> None:
Expand Down Expand Up @@ -93,3 +98,37 @@ def test_fresh_account_has_less_than_minimum_required_balance(
fresh_account_adr = Account.create().address
account_adr = Web3.to_checksum_address(fresh_account_adr)
assert not is_minimum_required_balance(account_adr, xdai_type(0.5), local_web3)


def test_now(local_web3: Web3, test_keys: APIKeys) -> None:
# we need to mint a new block to update timestamp
mint_new_block(test_keys, local_web3)
allowed_difference = 15 # seconds
chain_timestamp = DebuggingContract().getNow(local_web3)
utc_timestamp = int(utcnow().timestamp())
assert (
abs(chain_timestamp - utc_timestamp) <= allowed_difference
), f"chain_timestamp and utc_timestamp differ by more than {allowed_difference} seconds: {chain_timestamp=} {utc_timestamp=}"


def test_now_failed(local_web3: Web3, test_keys: APIKeys) -> None:
# Sleep a little to let the local chain go out of sync without updating the block
time.sleep(5)
allowed_difference = 5 # seconds
chain_timestamp = DebuggingContract().getNow(local_web3)
utc_timestamp = int(utcnow().timestamp())
assert (
abs(chain_timestamp - utc_timestamp) >= allowed_difference
), f"without minting a new block, timestamps should differ by more than {allowed_difference} seconds: {chain_timestamp=} {utc_timestamp=}"


def test_now_datetime(local_web3: Web3, test_keys: APIKeys) -> None:
# we need to mint a new block to update timestamp
mint_new_block(test_keys, local_web3)
allowed_difference = 15 # seconds
chain_datetime = DebuggingContract().get_now(local_web3)
utc_datetime = utcnow()
actual_difference = (utc_datetime - chain_datetime).total_seconds()
assert (
actual_difference <= allowed_difference
), f"chain_datetime and utc_datetime differ by more than {allowed_difference} seconds: {chain_datetime=} {utc_datetime=} {actual_difference=}"
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ def test_place_bet_with_autodeposit(

# Check that we have xdai funds, but no wxdai funds
initial_balances = get_balances(address=test_keys.bet_from_address, web3=local_web3)
assert initial_balances.wxdai == xdai_type(0)
assert np.isclose(initial_balances.wxdai, xdai_type(0))
assert initial_balances.xdai > xdai_type(0)

# Try to place a bet with 90% of the xDai funds
Expand Down
Loading