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

Cut out tooling from the PMA repository #3

Merged
merged 6 commits into from
Feb 9, 2024
Merged

Conversation

kongzii
Copy link
Contributor

@kongzii kongzii commented Feb 9, 2024

Almost exactly the same as in the other repository, will comment on differences.

Summary by CodeRabbit

  • New Features

    • Introduced a DeployableCoinFlipAgent for deploying a coin flip agent in prediction markets, with a Flask endpoint for operation.
    • Added functionality for deploying, running, scheduling, and removing Google Cloud Platform functions for prediction market agents.
    • Implemented API key configuration handling for prediction market agents.
    • Developed custom types and conversion functions for various data types in prediction market agent tooling.
    • Created data models for managing agent markets and interactions with Manifold and Omen prediction markets.
    • Provided Python API functions for interacting with Manifold and Omen markets, including market retrieval and bet placements.
    • Added utility functions for blockchain interactions, including balance retrieval and Web3 transactions.
  • Bug Fixes

    • N/A
  • Documentation

    • N/A
  • Refactor

    • N/A
  • Style

    • N/A
  • Tests

    • Added tests for local deployment of DeployableCoinFlipAgent, interactions with Manifold and Omen markets, and utility functions.
    • Introduced functionality to determine the execution of paid tests based on an environment variable.
    • Updated the test_smoke function with a return type hint.

Copy link

coderabbitai bot commented Feb 9, 2024

Warning

Rate Limit Exceeded

@kongzii has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 12 minutes and 42 seconds before requesting another review.

How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.
Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.
Please see our FAQ for further information.

Commits Files that changed from the base of the PR and between 72b854d and 23d9e18.

Walkthrough

The project introduces a suite of tools for deploying prediction market agents on Google Cloud Platform and interacting with platforms like Manifold. It includes deploying agents, configuring API keys, handling market types, and executing transactions. This update enhances the project's capabilities for automated market interactions, offering detailed deployment management and market strategy.

Changes

Files Summary
examples/cloud_deployment/gcp/agent.py
prediction_market_agent_tooling/deploy/agent.py
Introduce DeployableCoinFlipAgent for deploying a coin flip agent and functionality for running prediction market agents.
prediction_market_agent_tooling/config.py New file introducing APIKeys class for API key configuration.
prediction_market_agent_tooling/markets/manifold.py
prediction_market_agent_tooling/markets/markets.py
Introduce Python API functions for interacting with Manifold Markets and handling different market types.
tests/deploy/test_deploy.py
tests/markets/test_manifold.py
New tests for local deployment and interacting with Manifold markets.

"In the world of code and cloud, we hop,
Deploying agents that flip and flop.
Predicting markets, day and night,
🐰 With each commit, our future's bright."

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share

Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit-tests for this file.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit tests for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository from git and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit tests.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • The JSON schema for the configuration file is available here.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/coderabbit-overrides.v2.json

CodeRabbit Discord Community

Join our Discord Community to get help, request features, and share feedback.

@kongzii
Copy link
Contributor Author

kongzii commented Feb 9, 2024

@coderabbitai review

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Review Status

Actionable comments generated: 11

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 64c0c95 and 022d131.
Files ignored due to path filters (6)
  • mypy.ini is excluded by: !**/*.ini
  • poetry.lock is excluded by: !**/*.lock
  • prediction_market_agent_tooling/abis/omen_fpmm.abi.json is excluded by: !**/*.json
  • prediction_market_agent_tooling/abis/omen_fpmm_conditionaltokens.abi.json is excluded by: !**/*.json
  • prediction_market_agent_tooling/abis/wxdai.abi.json is excluded by: !**/*.json
  • pyproject.toml is excluded by: !**/*.toml
Files selected for processing (19)
  • examples/cloud_deployment/gcp/agent.py (1 hunks)
  • examples/cloud_deployment/gcp/deploy.py (1 hunks)
  • prediction_market_agent_tooling/config.py (1 hunks)
  • prediction_market_agent_tooling/deploy/agent.py (1 hunks)
  • prediction_market_agent_tooling/deploy/gcp/deploy.py (1 hunks)
  • prediction_market_agent_tooling/deploy/gcp/utils.py (1 hunks)
  • prediction_market_agent_tooling/gtypes.py (1 hunks)
  • prediction_market_agent_tooling/markets/data_models.py (1 hunks)
  • prediction_market_agent_tooling/markets/manifold.py (1 hunks)
  • prediction_market_agent_tooling/markets/markets.py (1 hunks)
  • prediction_market_agent_tooling/markets/omen.py (1 hunks)
  • prediction_market_agent_tooling/tools/gnosis_rpc.py (1 hunks)
  • prediction_market_agent_tooling/tools/utils.py (1 hunks)
  • prediction_market_agent_tooling/tools/web3_utils.py (1 hunks)
  • tests/deploy/test_deploy.py (1 hunks)
  • tests/markets/test_manifold.py (1 hunks)
  • tests/markets/test_omen.py (1 hunks)
  • tests/test_smoke.py (1 hunks)
  • tests/utils.py (1 hunks)
Additional comments: 18
tests/test_smoke.py (1)
  • 1-1: LGTM!
tests/utils.py (1)
  • 1-3: LGTM!
tests/markets/test_manifold.py (1)
  • 1-12: LGTM!
prediction_market_agent_tooling/tools/gnosis_rpc.py (1)
  • 1-19: LGTM!
examples/cloud_deployment/gcp/agent.py (1)
  • 1-24: LGTM!
tests/deploy/test_deploy.py (1)
  • 1-30: LGTM!
prediction_market_agent_tooling/gtypes.py (1)
  • 1-37: LGTM!
prediction_market_agent_tooling/config.py (1)
  • 1-34: LGTM!
examples/cloud_deployment/gcp/deploy.py (1)
  • 1-37: LGTM!
tests/markets/test_omen.py (1)
  • 1-47: LGTM!
prediction_market_agent_tooling/tools/utils.py (1)
  • 1-65: LGTM!
prediction_market_agent_tooling/markets/manifold.py (1)
  • 1-70: LGTM!
prediction_market_agent_tooling/deploy/gcp/deploy.py (1)
  • 1-83: LGTM!
prediction_market_agent_tooling/markets/markets.py (1)
  • 1-95: LGTM!
prediction_market_agent_tooling/deploy/agent.py (1)
  • 1-90: LGTM!
prediction_market_agent_tooling/deploy/gcp/utils.py (1)
  • 1-116: LGTM!
prediction_market_agent_tooling/tools/web3_utils.py (1)
  • 1-104: LGTM!
prediction_market_agent_tooling/markets/data_models.py (1)
  • 1-162: LGTM!

Comment on lines +8 to +34
import os
import requests
from typing import Optional
from web3 import Web3
from web3.types import TxReceipt, TxParams
from prediction_market_agent_tooling.markets.data_models import OmenMarket
from prediction_market_agent_tooling.tools.web3_utils import (
call_function_on_contract,
call_function_on_contract_tx,
WXDAI_ABI,
xdai_to_wei,
remove_fraction,
add_fraction,
check_tx_receipt,
ONE_NONCE,
Nonce,
)
from prediction_market_agent_tooling.tools.gnosis_rpc import GNOSIS_RPC_URL
from prediction_market_agent_tooling.gtypes import (
ABI,
HexAddress,
PrivateKey,
xDai,
Wei,
ChecksumAddress,
OmenOutcomeToken,
)
Copy link

Choose a reason for hiding this comment

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

Consider grouping imports from the same module/package together to improve readability.

- from prediction_market_agent_tooling.markets.data_models import OmenMarket
- from prediction_market_agent_tooling.tools.web3_utils import (
-     call_function_on_contract,
-     ...
- )
- from prediction_market_agent_tooling.tools.gnosis_rpc import GNOSIS_RPC_URL
- from prediction_market_agent_tooling.gtypes import (
-     ABI,
-     ...
- )
+ from prediction_market_agent_tooling import (
+     markets,
+     tools,
+     gtypes,
+ )

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
import os
import requests
from typing import Optional
from web3 import Web3
from web3.types import TxReceipt, TxParams
from prediction_market_agent_tooling.markets.data_models import OmenMarket
from prediction_market_agent_tooling.tools.web3_utils import (
call_function_on_contract,
call_function_on_contract_tx,
WXDAI_ABI,
xdai_to_wei,
remove_fraction,
add_fraction,
check_tx_receipt,
ONE_NONCE,
Nonce,
)
from prediction_market_agent_tooling.tools.gnosis_rpc import GNOSIS_RPC_URL
from prediction_market_agent_tooling.gtypes import (
ABI,
HexAddress,
PrivateKey,
xDai,
Wei,
ChecksumAddress,
OmenOutcomeToken,
)
import os
import requests
from typing import Optional
from web3 import Web3
from web3.types import TxReceipt, TxParams
from prediction_market_agent_tooling import (
markets,
tools,
gtypes,
)

Comment on lines +39 to +46
with open(
os.path.join(
os.path.dirname(os.path.realpath(__file__)), "../abis/omen_fpmm.abi.json"
)
) as f:
# File content taken from https://github.com/protofire/omen-exchange/blob/master/app/src/abi/marketMaker.json.
# Factory contract at https://gnosisscan.io/address/0x9083a2b699c0a4ad06f63580bde2635d26a3eef0.
OMEN_FPMM_ABI = ABI(f.read())
Copy link

Choose a reason for hiding this comment

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

Validate the existence of the ABI file at the specified path to prevent runtime errors.

Comment on lines +48 to +55
with open(
os.path.join(
os.path.dirname(os.path.realpath(__file__)),
"../abis/omen_fpmm_conditionaltokens.abi.json",
)
) as f:
# Based on the code from OMEN_FPMM_ABI's factory contract.
OMEN_FPMM_CONDITIONALTOKENS_ABI = ABI(f.read())
Copy link

Choose a reason for hiding this comment

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

Validate the existence of the ABI file at the specified path to prevent runtime errors.

Comment on lines +101 to +113
def get_omen_markets(first: int, outcomes: list[str]) -> list[OmenMarket]:
markets = requests.post(
THEGRAPH_QUERY_URL,
json={
"query": _QUERY_GET_FIXED_PRODUCT_MARKETS_MAKERS,
"variables": {
"first": first,
"outcomes": outcomes,
},
},
headers={"Content-Type": "application/json"},
).json()["data"]["fixedProductMarketMakers"]
return [OmenMarket.model_validate(market) for market in markets]
Copy link

Choose a reason for hiding this comment

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

Add error handling for the HTTP request to manage potential request failures or non-200 responses.

Comment on lines +124 to +135
def get_market(market_id: str) -> OmenMarket:
market = requests.post(
THEGRAPH_QUERY_URL,
json={
"query": _QUERY_GET_SINGLE_FIXED_PRODUCT_MARKET_MAKER,
"variables": {
"id": market_id,
},
},
headers={"Content-Type": "application/json"},
).json()["data"]["fixedProductMarketMaker"]
return OmenMarket.model_validate(market)
Copy link

Choose a reason for hiding this comment

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

Add error handling for the HTTP request to manage potential request failures or non-200 responses.

Comment on lines +161 to +185
def omen_approve_all_market_maker_to_move_conditionaltokens_tx(
web3: Web3,
market: OmenMarket,
approve: bool,
from_address: ChecksumAddress,
from_private_key: PrivateKey,
tx_params: Optional[TxParams] = None,
) -> TxReceipt:
# Get the address of conditional token's of this market.
conditionaltokens_address = omen_get_market_maker_conditionaltokens_address(
web3, market
)
return call_function_on_contract_tx(
web3=web3,
contract_address=Web3.to_checksum_address(conditionaltokens_address),
contract_abi=OMEN_FPMM_CONDITIONALTOKENS_ABI,
from_address=from_address,
from_private_key=from_private_key,
function_name="setApprovalForAll",
function_params=[
market.market_maker_contract_address_checksummed,
approve,
],
tx_params=tx_params,
)
Copy link

Choose a reason for hiding this comment

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

Consider extracting the repeated pattern of calling call_function_on_contract_tx into a utility function to reduce code duplication.

Comment on lines +188 to +204
def omen_deposit_collateral_token_tx(
web3: Web3,
market: OmenMarket,
amount_wei: Wei,
from_address: ChecksumAddress,
from_private_key: PrivateKey,
tx_params: Optional[TxParams] = None,
) -> TxReceipt:
return call_function_on_contract_tx(
web3=web3,
contract_address=market.collateral_token_contract_address_checksummed,
contract_abi=WXDAI_ABI,
from_address=from_address,
from_private_key=from_private_key,
function_name="deposit",
tx_params={"value": amount_wei, **(tx_params or {})},
)
Copy link

Choose a reason for hiding this comment

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

Consider extracting the repeated pattern of calling call_function_on_contract_tx into a utility function to reduce code duplication.

Comment on lines +207 to +223
def omen_withdraw_collateral_token_tx(
web3: Web3,
market: OmenMarket,
amount_wei: Wei,
from_address: ChecksumAddress,
from_private_key: PrivateKey,
tx_params: Optional[TxParams] = None,
) -> TxReceipt:
return call_function_on_contract_tx(
web3=web3,
contract_address=market.collateral_token_contract_address_checksummed,
contract_abi=WXDAI_ABI,
from_address=from_address,
from_private_key=from_private_key,
function_name="withdraw",
function_params=[amount_wei],
tx_params=tx_params or {},
Copy link

Choose a reason for hiding this comment

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

Consider extracting the repeated pattern of calling call_function_on_contract_tx into a utility function to reduce code duplication.

Comment on lines +330 to +394
def omen_buy_outcome_tx(
amount: xDai,
from_address: ChecksumAddress,
from_private_key: PrivateKey,
market: OmenMarket,
outcome: str,
auto_deposit: bool,
) -> None:
"""
Bets the given amount of xDai for the given outcome in the given market.
"""
web3 = Web3(Web3.HTTPProvider(GNOSIS_RPC_URL))
amount_wei = xdai_to_wei(amount)
from_address_checksummed = Web3.to_checksum_address(from_address)

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

# Get the current nonce for the given from_address.
# If making multiple transactions quickly after each other,
# it's better to increae it manually (otherwise we could get stale value from the network and error out).
nonce: Nonce = web3.eth.get_transaction_count(from_address_checksummed)

# Calculate the amount of shares we will get for the given investment amount.
expected_shares = omen_calculate_buy_amount(web3, market, amount_wei, outcome_index)
# Allow 1% slippage.
expected_shares = remove_fraction(expected_shares, 0.01)
# Approve the market maker to withdraw our collateral token.
approve_tx_receipt = omen_approve_market_maker_to_spend_collateral_token_tx(
web3=web3,
market=market,
amount_wei=amount_wei,
from_address=from_address_checksummed,
from_private_key=from_private_key,
tx_params={"nonce": nonce},
)
nonce = Nonce(nonce + ONE_NONCE) # Increase after each tx.
check_tx_receipt(approve_tx_receipt)
# Deposit xDai to the collateral token,
# this can be skipped, if we know we already have enough collateral tokens.
if auto_deposit:
deposit_receipt = omen_deposit_collateral_token_tx(
web3=web3,
market=market,
amount_wei=amount_wei,
from_address=from_address_checksummed,
from_private_key=from_private_key,
tx_params={"nonce": nonce},
)
nonce = Nonce(nonce + ONE_NONCE) # Increase after each tx.
check_tx_receipt(deposit_receipt)
# Buy shares using the deposited xDai in the collateral token.
buy_receipt = omen_buy_shares_tx(
web3,
market,
amount_wei,
outcome_index,
expected_shares,
from_address_checksummed,
from_private_key,
tx_params={"nonce": nonce},
)
nonce = Nonce(nonce + ONE_NONCE) # Increase after each tx.
check_tx_receipt(buy_receipt)

Copy link

Choose a reason for hiding this comment

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

Ensure nonce management is robust against race conditions and consider using a nonce manager if transactions are sent in quick succession.

Comment on lines +414 to +479
def omen_sell_outcome_tx(
amount: xDai,
from_address: ChecksumAddress,
from_private_key: PrivateKey,
market: OmenMarket,
outcome: str,
auto_withdraw: bool,
) -> None:
"""
Sells the given amount of shares for the given outcome in the given market.
"""
web3 = Web3(Web3.HTTPProvider(GNOSIS_RPC_URL))
amount_wei = xdai_to_wei(amount)
from_address_checksummed = Web3.to_checksum_address(from_address)

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

# Get the current nonce for the given from_address.
# If making multiple transactions quickly after each other,
# it's better to increae it manually (otherwise we could get stale value from the network and error out).
nonce: Nonce = web3.eth.get_transaction_count(from_address_checksummed)

# Calculate the amount of shares we will sell for the given selling amount of xdai.
max_outcome_tokens_to_sell = omen_calculate_sell_amount(
web3, market, amount_wei, outcome_index
)
# Allow 1% slippage.
max_outcome_tokens_to_sell = add_fraction(max_outcome_tokens_to_sell, 0.01)

# Approve the market maker to move our (all) conditional tokens.
approve_tx_receipt = omen_approve_all_market_maker_to_move_conditionaltokens_tx(
web3=web3,
market=market,
approve=True,
from_address=from_address_checksummed,
from_private_key=from_private_key,
tx_params={"nonce": nonce},
)
nonce = Nonce(nonce + ONE_NONCE) # Increase after each tx.
check_tx_receipt(approve_tx_receipt)
# Sell the shares.
sell_receipt = omen_sell_shares_tx(
web3,
market,
amount_wei,
outcome_index,
max_outcome_tokens_to_sell,
from_address_checksummed,
from_private_key,
tx_params={"nonce": nonce},
)
nonce = Nonce(nonce + ONE_NONCE) # Increase after each tx.
check_tx_receipt(sell_receipt)
if auto_withdraw:
# Optionally, withdraw from the collateral token back to the `from_address` wallet.
withdraw_receipt = omen_withdraw_collateral_token_tx(
web3=web3,
market=market,
amount_wei=amount_wei,
from_address=from_address_checksummed,
from_private_key=from_private_key,
tx_params={"nonce": nonce},
)
nonce = Nonce(nonce + ONE_NONCE) # Increase after each tx.
check_tx_receipt(withdraw_receipt)
Copy link

Choose a reason for hiding this comment

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

Ensure nonce management is robust against race conditions and consider using a nonce manager if transactions are sent in quick succession.



class APIKeys(BaseSettings):
model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8")
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Found out that Pydantic supports this, so we don't have to manually call os.getenv and changing env variables at runtime.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah so good!

LOCAL = "local"


class DeployableAgent(BaseModel):
Copy link
Contributor Author

Choose a reason for hiding this comment

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

What was the motivation to use BaseModel here? Seems like it doesn't have any fields.

Copy link
Contributor

Choose a reason for hiding this comment

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

Assumed it would have fields when I started working on it, but now looks like it will just be a class containing only static methods

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I see, then let's keep it, it can always be removed 😄

from cron_validator import CronValidator


def deploy_to_gcp(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved these from the agent's file to a separate, gcp-specific, file.

return get_manifold_binary_markets(1)[0]


def place_bet(amount: Mana, market_id: str, outcome: bool) -> None:
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed the api key as we talked about it on slack.

@kongzii kongzii marked this pull request as ready for review February 9, 2024 14:03
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Review Status

Actionable comments generated: 0

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 022d131 and 72b854d.
Files selected for processing (7)
  • examples/cloud_deployment/gcp/agent.py (1 hunks)
  • prediction_market_agent_tooling/config.py (1 hunks)
  • prediction_market_agent_tooling/deploy/agent.py (1 hunks)
  • prediction_market_agent_tooling/markets/manifold.py (1 hunks)
  • prediction_market_agent_tooling/markets/markets.py (1 hunks)
  • tests/deploy/test_deploy.py (1 hunks)
  • tests/markets/test_manifold.py (1 hunks)
Files skipped from review as they are similar to previous changes (7)
  • examples/cloud_deployment/gcp/agent.py
  • prediction_market_agent_tooling/config.py
  • prediction_market_agent_tooling/deploy/agent.py
  • prediction_market_agent_tooling/markets/manifold.py
  • prediction_market_agent_tooling/markets/markets.py
  • tests/deploy/test_deploy.py
  • tests/markets/test_manifold.py

@kongzii kongzii merged commit f0b069b into main Feb 9, 2024
4 checks passed
@kongzii kongzii deleted the peter/cut-out-from-pma branch February 9, 2024 15:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants