diff --git a/prediction_market_agent/agents/microchain_agent/microchain_agent.py b/prediction_market_agent/agents/microchain_agent/microchain_agent.py index 8891803e..7413d62f 100644 --- a/prediction_market_agent/agents/microchain_agent/microchain_agent.py +++ b/prediction_market_agent/agents/microchain_agent/microchain_agent.py @@ -44,10 +44,10 @@ from prediction_market_agent.agents.microchain_agent.memory_functions import ( LookAtPastActions, ) -from prediction_market_agent.agents.microchain_agent.messages_functions import ( +from prediction_market_agent.agents.microchain_agent.nft_functions import NFT_FUNCTIONS +from prediction_market_agent.agents.microchain_agent.nft_treasury_game.messages_functions import ( MESSAGES_FUNCTIONS, ) -from prediction_market_agent.agents.microchain_agent.nft_functions import NFT_FUNCTIONS from prediction_market_agent.agents.microchain_agent.omen_functions import ( OMEN_FUNCTIONS, ) diff --git a/prediction_market_agent/agents/microchain_agent/microchain_agent_keys.py b/prediction_market_agent/agents/microchain_agent/microchain_agent_keys.py index c649d788..54e580ce 100644 --- a/prediction_market_agent/agents/microchain_agent/microchain_agent_keys.py +++ b/prediction_market_agent/agents/microchain_agent/microchain_agent_keys.py @@ -1,4 +1,4 @@ -from prediction_market_agent_tooling.gtypes import xDai +from prediction_market_agent_tooling.gtypes import xDai, xdai_type from prediction_market_agent_tooling.loggers import logger from prediction_market_agent_tooling.markets.omen.omen import OMEN_TINY_BET_AMOUNT @@ -9,7 +9,7 @@ class MicrochainAgentKeys(APIKeys): # Double check to make sure you want to actually post on public social media. ENABLE_SOCIAL_MEDIA: bool = False # Double check to not spend big money during testing. - SENDING_XDAI_CAP: float | None = OMEN_TINY_BET_AMOUNT + SENDING_XDAI_CAP: xDai | None = xdai_type(0.1) # Double check to not transfer NFTs during testing. ENABLE_NFT_TRANSFER: bool = False RECEIVER_MINIMUM_AMOUNT: xDai = OMEN_TINY_BET_AMOUNT diff --git a/prediction_market_agent/agents/microchain_agent/nft_treasury_game/app_nft_treasury_game.py b/prediction_market_agent/agents/microchain_agent/nft_treasury_game/app_nft_treasury_game.py index f9aef18f..4ae8d208 100644 --- a/prediction_market_agent/agents/microchain_agent/nft_treasury_game/app_nft_treasury_game.py +++ b/prediction_market_agent/agents/microchain_agent/nft_treasury_game/app_nft_treasury_game.py @@ -16,17 +16,23 @@ from streamlit_extras.stylable_container import stylable_container from prediction_market_agent.agents.identifiers import AgentIdentifier -from prediction_market_agent.agents.microchain_agent.messages_functions import ( - BroadcastPublicMessageToHumans, - ReceiveMessage, - SendPaidMessageToAnotherAgent, -) +from prediction_market_agent.agents.microchain_agent.nft_functions import BalanceOfNFT from prediction_market_agent.agents.microchain_agent.nft_treasury_game.constants_nft_treasury_game import ( + NFT_TOKEN_FACTORY, TREASURY_SAFE_ADDRESS, ) +from prediction_market_agent.agents.microchain_agent.nft_treasury_game.contracts_nft_treasury_game import ( + get_nft_token_factory_max_supply, +) from prediction_market_agent.agents.microchain_agent.nft_treasury_game.deploy_nft_treasury_game import ( DEPLOYED_NFT_AGENTS, DeployableAgentNFTGameAbstract, + MicrochainAgentKeys, +) +from prediction_market_agent.agents.microchain_agent.nft_treasury_game.messages_functions import ( + BroadcastPublicMessageToHumans, + ReceiveMessage, + SendPaidMessageToAnotherAgent, ) from prediction_market_agent.db.blockchain_transaction_fetcher import ( BlockchainTransactionFetcher, @@ -66,10 +72,19 @@ def prompt_table_handler(identifier: AgentIdentifier) -> PromptTableHandler: def send_message_part(nft_agent: type[DeployableAgentNFTGameAbstract]) -> None: message = st.text_area("Write a message to the agent") + keys = MicrochainAgentKeys() + default_value = keys.RECEIVER_MINIMUM_AMOUNT + value = st.number_input( + "Value in xDai", + min_value=default_value, + max_value=keys.SENDING_XDAI_CAP, + value=default_value, + format="%.5f", + ) if st.button("Send message", disabled=not message): # TODO: Don't do this manually with deployment private key, use the user's wallet! - SendPaidMessageToAnotherAgent()(nft_agent.wallet_address, message) + SendPaidMessageToAnotherAgent()(nft_agent.wallet_address, message, value) st.success("Message sent and will be processed soon!") @@ -189,10 +204,16 @@ def show_about_agent_part(nft_agent: type[DeployableAgentNFTGameAbstract]) -> No else nft_agent.get_initial_system_prompt() ) xdai_balance = get_balances(nft_agent.wallet_address).xdai + n_nft = BalanceOfNFT()(NFT_TOKEN_FACTORY, nft_agent.wallet_address) + nft_keys_message = ( + "and does not hold any NFT keys anymore" + if n_nft == 0 + else f"and {n_nft} NFT key{'s' if n_nft > 1 else ''}" + ) st.markdown( f"""### {nft_agent.name} -Currently holds {xdai_balance:.2f} xDAI. +Currently holds {xdai_balance:.2f} xDAI {nft_keys_message}. --- """, @@ -228,7 +249,7 @@ def show_treasury_part() -> None: treasury_xdai_balance = get_balances(TREASURY_SAFE_ADDRESS).xdai st.markdown( f"""### Treasury -Currently holds {treasury_xdai_balance:.2f} xDAI.""", +Currently holds {treasury_xdai_balance:.2f} xDAI. There are {get_nft_token_factory_max_supply()} NFT keys.""", unsafe_allow_html=True, ) diff --git a/prediction_market_agent/agents/microchain_agent/nft_treasury_game/contracts_nft_treasury_game.py b/prediction_market_agent/agents/microchain_agent/nft_treasury_game/contracts_nft_treasury_game.py new file mode 100644 index 00000000..ca3d3480 --- /dev/null +++ b/prediction_market_agent/agents/microchain_agent/nft_treasury_game/contracts_nft_treasury_game.py @@ -0,0 +1,24 @@ +from functools import cache + +from prediction_market_agent_tooling.gtypes import ChecksumAddress +from prediction_market_agent_tooling.tools.contract import ( + ContractOwnableERC721OnGnosisChain, +) +from web3 import Web3 + +from prediction_market_agent.agents.microchain_agent.nft_treasury_game.constants_nft_treasury_game import ( + NFT_TOKEN_FACTORY, +) + + +class ContractNFTFactoryOnGnosisChain(ContractOwnableERC721OnGnosisChain): + address: ChecksumAddress = NFT_TOKEN_FACTORY + + def max_supply(self, web3: Web3 | None = None) -> int: + n_tokens: int = self.call("MAX_SUPPLY", web3=web3) + return n_tokens + + +@cache +def get_nft_token_factory_max_supply() -> int: + return ContractNFTFactoryOnGnosisChain().max_supply() diff --git a/prediction_market_agent/agents/microchain_agent/nft_treasury_game/deploy_nft_treasury_game.py b/prediction_market_agent/agents/microchain_agent/nft_treasury_game/deploy_nft_treasury_game.py index 1eeb2f0a..85bc02cb 100644 --- a/prediction_market_agent/agents/microchain_agent/nft_treasury_game/deploy_nft_treasury_game.py +++ b/prediction_market_agent/agents/microchain_agent/nft_treasury_game/deploy_nft_treasury_game.py @@ -11,8 +11,12 @@ MicrochainAgentKeys, ) from prediction_market_agent.agents.microchain_agent.nft_treasury_game.constants_nft_treasury_game import ( + NFT_TOKEN_FACTORY, TREASURY_SAFE_ADDRESS, ) +from prediction_market_agent.agents.microchain_agent.nft_treasury_game.contracts_nft_treasury_game import ( + get_nft_token_factory_max_supply, +) class DeployableAgentNFTGameAbstract(DeployableMicrochainAgentAbstract): @@ -182,6 +186,8 @@ def get_initial_system_prompt(cls) -> str: def nft_treasury_game_base_prompt(wallet_address: ChecksumAddress) -> str: + keys = MicrochainAgentKeys() + n_nft_keys = get_nft_token_factory_max_supply() other_agents_keys_formatted = ", ".join( x.wallet_address for x in DEPLOYED_NFT_AGENTS @@ -191,14 +197,18 @@ def nft_treasury_game_base_prompt(wallet_address: ChecksumAddress) -> str: - You participate in the securing of the NFT key to a treasury. - Your wallet address is {wallet_address}. -- Other agents participating and probably still holding keys are {other_agents_keys_formatted}. -- Address of the NFT treasury is {TREASURY_SAFE_ADDRESS}. +- Other agents participating and maybe still holding keys are {other_agents_keys_formatted}. +- Address of the treasury, wallet holding the treasury's xDai, is {TREASURY_SAFE_ADDRESS}. +- Address of the NFT contract is {NFT_TOKEN_FACTORY}, there are {n_nft_keys} keys, with token_id {list(range(n_nft_keys))}. + - You can own multiple NFT keys. + - You can use the NFT functions to interact with the NFT keys, for example figuring out how many keys you own or who owns what key. - The agent or person who gets enough of keys, can transfer the resources from the treasury. - The agents can communicate with each other using the messages functions by sending a message to their wallet address. - Sending a message costs you a fee. -- Receiving messages will pay you a fee. -- If you have unseen incoming messages, always process them first. +- Receiving messages will pay you a fee, but part of that fee goes to the treasury, which is good for you. +- If you have unseen incoming messages, always process them first, unless you are processing some message at the moment. - Regularly check balances of your wallet and the treasury. +- Keep in mind that you are able to send, and others agents are able to send at max {keys.SENDING_XDAI_CAP} xDai. """ diff --git a/prediction_market_agent/agents/microchain_agent/messages_functions.py b/prediction_market_agent/agents/microchain_agent/nft_treasury_game/messages_functions.py similarity index 86% rename from prediction_market_agent/agents/microchain_agent/messages_functions.py rename to prediction_market_agent/agents/microchain_agent/nft_treasury_game/messages_functions.py index ef91bda7..21661543 100644 --- a/prediction_market_agent/agents/microchain_agent/messages_functions.py +++ b/prediction_market_agent/agents/microchain_agent/nft_treasury_game/messages_functions.py @@ -1,5 +1,5 @@ from microchain import Function -from prediction_market_agent_tooling.gtypes import wei_type +from prediction_market_agent_tooling.gtypes import wei_type, xdai_type from prediction_market_agent_tooling.loggers import logger from prediction_market_agent_tooling.tools.contract import ContractOnGnosisChain from prediction_market_agent_tooling.tools.hexbytes_custom import HexBytes @@ -39,21 +39,19 @@ class SendPaidMessageToAnotherAgent(Function): @property def description(self) -> str: return f"""Use {SendPaidMessageToAnotherAgent.__name__} to send a message to an another agent, given his wallet address. -Fee for sending the message is {MicrochainAgentKeys().RECEIVER_MINIMUM_AMOUNT} xDai.""" +You need to send a fee of at least {MicrochainAgentKeys().RECEIVER_MINIMUM_AMOUNT} xDai for other agent to read the message.""" @property def example_args(self) -> list[str]: - return ["0x123", "Hello!"] + return ["0x123", "Hello!", f"{MicrochainAgentKeys().RECEIVER_MINIMUM_AMOUNT}"] - def __call__(self, address: str, message: str) -> str: + def __call__(self, address: str, message: str, fee: float) -> str: keys = MicrochainAgentKeys() send_xdai_to( web3=ContractOnGnosisChain.get_web3(), from_private_key=keys.bet_from_private_key, to_address=Web3.to_checksum_address(address), - value=xdai_to_wei( - keys.cap_sending_xdai(MicrochainAgentKeys().RECEIVER_MINIMUM_AMOUNT) - ), + value=xdai_to_wei(keys.cap_sending_xdai(xdai_type(fee))), data_text=compress_message(message), ) return self.OUTPUT_TEXT @@ -72,7 +70,7 @@ def get_count_unseen_messages() -> int: @property def description(self) -> str: count_unseen_messages = self.get_count_unseen_messages() - return f"Use {ReceiveMessage.__name__} to receive last {count_unseen_messages} unseen messages from the users." + return f"Use {ReceiveMessage.__name__} to receive last unseen message from the users or other agents. Currently, you have {count_unseen_messages} unseen messages." @property def example_args(self) -> list[str]: diff --git a/tests/agents/microchain/test_messages_functions.py b/tests/agents/microchain/test_messages_functions.py index 71b91d72..ef91bcae 100644 --- a/tests/agents/microchain/test_messages_functions.py +++ b/tests/agents/microchain/test_messages_functions.py @@ -9,7 +9,7 @@ from pydantic import SecretStr from web3 import Web3 -from prediction_market_agent.agents.microchain_agent.messages_functions import ( +from prediction_market_agent.agents.microchain_agent.nft_treasury_game.messages_functions import ( ReceiveMessage, ) from prediction_market_agent.db.blockchain_message_table_handler import ( @@ -80,7 +80,7 @@ def patch_spice() -> Generator[PropertyMock, None, None]: def patch_send_xdai() -> Generator[PropertyMock, None, None]: # Note that we patch where the function is called (see https://docs.python.org/3/library/unittest.mock.html#where-to-patch). with patch( - "prediction_market_agent.agents.microchain_agent.messages_functions.send_xdai_to", + "prediction_market_agent.agents.microchain_agent.nft_treasury_game.messages_functions.send_xdai_to", return_value={"transactionHash": HexBytes(MOCK_HASH_1)}, ) as mock_send_xdai: yield mock_send_xdai