diff --git a/.gitignore b/.gitignore index 595566b2..41b47dfd 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,4 @@ leak_report agent/ backup_mech/ +/packages/valory/skills/termination_abci/ diff --git a/packages/packages.json b/packages/packages.json index bbb1cf07..da2f28e4 100644 --- a/packages/packages.json +++ b/packages/packages.json @@ -2,16 +2,17 @@ "dev": { "connection/valory/websocket_client/0.1.0": "bafybeiflmystocxaqblhpzqlcop2vkhsknpzjx2jomohomaxamwskeokzm", "skill/valory/contract_subscription/0.1.0": "bafybeicyugrkx5glat4p4ezwf6i7oduh26eycfie6ftd4uxrknztzl3ik4", - "agent/valory/mech/0.1.0": "bafybeiamnuotz3zj7whskv6hoieswntuobr3fowkfoh52xw4vait4b5eli", - "skill/valory/mech_abci/0.1.0": "bafybeid6pm3a3yd33hpcvcj5s4rydk623b6hmukrgs4oxnabct2zylzotm", - "contract/valory/agent_mech/0.1.0": "bafybeicshvlc2slopzidzblf2zhdcw2uuav3ntxcgqduxskjujvebikg5u", - "service/valory/mech/0.1.0": "bafybeigh5gm3yc5dsi2gjxcussokytzxqbjvpabedhdshxzgwkmdhknxom", + "agent/valory/mech/0.1.0": "bafybeih5idugp2jm7hxzj63tvvfep3tradk2hhnxipro2egaxnvmdaqjka", + "skill/valory/mech_abci/0.1.0": "bafybeigrndr6sd3nayqa3wbffl263f6guxcbnk67m6x2vzhpvpkmtdn6xu", + "contract/valory/agent_mech/0.1.0": "bafybeidyfhwye3ybk3vxrceljafe2n4o43oxtmjepvexpcrwlccboi34e4", + "service/valory/mech/0.1.0": "bafybeiewvz4sdoarlrgrjwnlnzgpxz6t7xafsbhifbuhoimq333bev7hwy", "protocol/valory/acn_data_share/0.1.0": "bafybeih5ydonnvrwvy2ygfqgfabkr47s4yw3uqxztmwyfprulwfsoe7ipq", - "skill/valory/task_submission_abci/0.1.0": "bafybeihluuiksi63kwp2kzn5hdbeek74bnhsctdwl72qv2xjmzqvf7j3va", - "skill/valory/task_execution/0.1.0": "bafybeianf56ypn6pjrqvj24uhmty2b5vtsewzjcrqxnrqyjsuudhyjpiue", + "skill/valory/task_submission_abci/0.1.0": "bafybeigdvfzghhjfrlov4f4newyalguuaxl7jk4ccomflgloy46wfijs5i", + "skill/valory/task_execution/0.1.0": "bafybeieup24rlnjosvbixq62f225qayflmxjohzmcopc2y5qfixohv2dlq", "contract/valory/agent_registry/0.1.0": "bafybeiargayav6yiztdnwzejoejstcx4idssch2h4f5arlgtzj3tgsgfmu", "protocol/valory/websocket_client/0.1.0": "bafybeih43mnztdv3v2hetr2k3gezg7d3yj4ur7cxdvcyaqhg65e52s5sf4", - "skill/valory/websocket_client/0.1.0": "bafybeidwntmkk4b2ixq5454ycbkknclqx7a6vpn7aqpm2nw3duszqrxvta" + "skill/valory/websocket_client/0.1.0": "bafybeidwntmkk4b2ixq5454ycbkknclqx7a6vpn7aqpm2nw3duszqrxvta", + "contract/valory/hash_checkpoint/0.1.0": "bafybeiap5fvi2w53e4uwxt75gjzie557hwuegf76xupimx3dvpkgfmj4ei" }, "third_party": { "skill/valory/transaction_settlement_abci/0.1.0": "bafybeifqase6vqfrakahogdl4h2hpxntug5ckioicfqlw2og5tn6htru3q", diff --git a/packages/valory/agents/mech/aea-config.yaml b/packages/valory/agents/mech/aea-config.yaml index 6b36635a..51f58f7e 100644 --- a/packages/valory/agents/mech/aea-config.yaml +++ b/packages/valory/agents/mech/aea-config.yaml @@ -15,7 +15,7 @@ connections: - valory/http_server:0.22.0:bafybeie6g5hxhvdijyjlz4opquapxbsh6udzdjvlqhguwd6wp5cb5a5wuy - valory/websocket_client:0.1.0:bafybeiflmystocxaqblhpzqlcop2vkhsknpzjx2jomohomaxamwskeokzm contracts: -- valory/agent_mech:0.1.0:bafybeicshvlc2slopzidzblf2zhdcw2uuav3ntxcgqduxskjujvebikg5u +- valory/agent_mech:0.1.0:bafybeidyfhwye3ybk3vxrceljafe2n4o43oxtmjepvexpcrwlccboi34e4 - valory/gnosis_safe:0.1.0:bafybeie7qpo4sue4i54pzsg6nx365q6d3i4sl6ygdilwldqqxwroukbkiu - valory/gnosis_safe_proxy_factory:0.1.0:bafybeig6evakqztiuyn67vwv63fzgqqfig4whp4qlef3w6pf7hmngrw3si - valory/multisend:0.1.0:bafybeig5byt5urg2d2bsecufxe5ql7f4mezg3mekfleeh32nmuusx66p4y @@ -37,11 +37,11 @@ skills: - valory/abstract_abci:0.1.0:bafybeieynwkrnlm6wwtufh2jsgnlprjbpmte7now5rk7fbgd5mh5yumhry - valory/abstract_round_abci:0.1.0:bafybeifcq2nwd6m5tgxooe7436bc6lwo73xcreedmhcwauzhp5jic6jeq4 - valory/contract_subscription:0.1.0:bafybeicyugrkx5glat4p4ezwf6i7oduh26eycfie6ftd4uxrknztzl3ik4 -- valory/mech_abci:0.1.0:bafybeid6pm3a3yd33hpcvcj5s4rydk623b6hmukrgs4oxnabct2zylzotm -- valory/task_execution:0.1.0:bafybeianf56ypn6pjrqvj24uhmty2b5vtsewzjcrqxnrqyjsuudhyjpiue +- valory/mech_abci:0.1.0:bafybeigrndr6sd3nayqa3wbffl263f6guxcbnk67m6x2vzhpvpkmtdn6xu +- valory/task_execution:0.1.0:bafybeieup24rlnjosvbixq62f225qayflmxjohzmcopc2y5qfixohv2dlq - valory/registration_abci:0.1.0:bafybeig5fb3ibz3tr4kie53venqtajnlhvh7gwt5h45rxwzakwgs6jjsjq - valory/reset_pause_abci:0.1.0:bafybeiergfseqtmsphdimzjijxezqyyhigktvqriw2xb4dyujim6s5dr4a -- valory/task_submission_abci:0.1.0:bafybeihluuiksi63kwp2kzn5hdbeek74bnhsctdwl72qv2xjmzqvf7j3va +- valory/task_submission_abci:0.1.0:bafybeigdvfzghhjfrlov4f4newyalguuaxl7jk4ccomflgloy46wfijs5i - valory/termination_abci:0.1.0:bafybeia73cl2vqj2uawt5lnoej3fzlhhum72i2p6ld4bbudd67lxb7f3cu - valory/transaction_settlement_abci:0.1.0:bafybeifqase6vqfrakahogdl4h2hpxntug5ckioicfqlw2og5tn6htru3q - valory/websocket_client:0.1.0:bafybeidwntmkk4b2ixq5454ycbkknclqx7a6vpn7aqpm2nw3duszqrxvta diff --git a/packages/valory/contracts/agent_mech/contract.py b/packages/valory/contracts/agent_mech/contract.py index 00392d8b..5279b371 100644 --- a/packages/valory/contracts/agent_mech/contract.py +++ b/packages/valory/contracts/agent_mech/contract.py @@ -18,7 +18,7 @@ # ------------------------------------------------------------------------------ """This module contains the dynamic_contribution contract definition.""" - +from enum import Enum from typing import Any, Dict, List, cast from aea.common import JSONLike @@ -81,6 +81,13 @@ ] +class MechOperation(Enum): + """Operation types.""" + + CALL = 0 + DELEGATE_CALL = 1 + + class AgentMechContract(Contract): """The scaffold contract class for a smart contract.""" @@ -272,3 +279,26 @@ def get_multiple_undelivered_reqs( ).get("data") pending_tasks.extend(pending_tasks_batch) return {"data": pending_tasks} + + @classmethod + def get_exec_tx_data( + cls, + ledger_api: LedgerApi, + contract_address: str, + to: str, + value: int, + data: bytes, + operation: int, + tx_gas: int, + ) -> JSONLike: + """Get tx data""" + ledger_api = cast(EthereumApi, ledger_api) + + if not isinstance(ledger_api, EthereumApi): + raise ValueError(f"Only EthereumApi is supported, got {type(ledger_api)}") + + contract_instance = cls.get_instance(ledger_api, contract_address) + data = contract_instance.encodeABI( + fn_name="exec", args=[to, value, data, operation, tx_gas] + ) + return {"data": bytes.fromhex(data[2:])} # type: ignore diff --git a/packages/valory/contracts/agent_mech/contract.yaml b/packages/valory/contracts/agent_mech/contract.yaml index 89f578b6..f0e94c07 100644 --- a/packages/valory/contracts/agent_mech/contract.yaml +++ b/packages/valory/contracts/agent_mech/contract.yaml @@ -8,7 +8,7 @@ aea_version: '>=1.0.0, <2.0.0' fingerprint: __init__.py: bafybeigpq5lxfj2aza6ok3fjuywtdafelkbvoqwaits7regfbgu4oynmku build/AgentMech.json: bafybeidrlu7vpusp2tzovyf5rbnqy2jicuq3e6czizfkzswjq4rjusu72i - contract.py: bafybeihm4bmidifvp225rpxtg5xu5dyd5k65gm33jkoms2brrshvu5lige + contract.py: bafybeig65qzfwsetro4ncnb4zlmtws3dliun6q57mw3xzy7qh5s2kczj64 fingerprint_ignore_patterns: [] class_name: AgentMechContract contract_interface_paths: diff --git a/packages/valory/contracts/hash_checkpoint/__init__.py b/packages/valory/contracts/hash_checkpoint/__init__.py new file mode 100644 index 00000000..ea5f140e --- /dev/null +++ b/packages/valory/contracts/hash_checkpoint/__init__.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""This module contains the support resources for the agent mech contract.""" diff --git a/packages/valory/contracts/hash_checkpoint/build/HashCheckpoint.json b/packages/valory/contracts/hash_checkpoint/build/HashCheckpoint.json new file mode 100644 index 00000000..a9d5413d --- /dev/null +++ b/packages/valory/contracts/hash_checkpoint/build/HashCheckpoint.json @@ -0,0 +1,241 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "HashCheckpoint", + "sourceName": "contracts/HashCheckpoint.sol", + "abi": [ + { + "inputs": [ + { + "internalType": "string", + "name": "_baseURI", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "OwnerOnly", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddress", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroValue", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "string", + "name": "baseURI", + "type": "string" + } + ], + "name": "BaseURIChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "emitter", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ], + "name": "HashUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "manager", + "type": "address" + } + ], + "name": "ManagerUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "OwnerUpdated", + "type": "event" + }, + { + "inputs": [], + "name": "CID_PREFIX", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "baseURI", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "changeOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "hash", + "type": "bytes32" + } + ], + "name": "checkpoint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_address", + "type": "address" + } + ], + "name": "latestHash", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_address", + "type": "address" + } + ], + "name": "latestHashURI", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "latestHashes", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "bURI", + "type": "string" + } + ], + "name": "setBaseURI", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x6080604052600080553480156200001557600080fd5b5060405162001d4538038062001d4583398101604081905262000038916200039f565b604080516001600160a01b038516602082015280820184905281518082038301815260609091019091528390839062000071816200014a565b5050506001600160a01b0383166200009c5760405163d92e233d60e01b815260040160405180910390fd5b6040516331a9108f60e11b8152600481018390526000906001600160a01b03851690636352211e90602401602060405180830381865afa158015620000e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200010b9190620003d7565b90506001600160a01b0381166200013d57604051630ede975960e01b8152600481018490526024015b60405180910390fd5b5060015550620004b39050565b62000154620001b2565b5115620001a45760405162461bcd60e51b815260206004820152601360248201527f416c726561647920696e697469616c697a656400000000000000000000000000604482015260640162000134565b620001af816200021f565b50565b60606200021a62000214604051606b60f91b6020820152602560fa1b60218201526001600160601b03193060601b166022820152600160f81b60368201526000906037016040516020818303038152906040528051906020012060001c905090565b620002ed565b905090565b60006200022c8262000346565b905060008151602083016000f0905062000297604051606b60f91b6020820152602560fa1b60218201526001600160601b03193060601b166022820152600160f81b60368201526000906037016040516020818303038152906040528051906020012060001c905090565b6001600160a01b0316816001600160a01b031614620002e85760405162461bcd60e51b815260206004820152600c60248201526b15dc9a5d194819985a5b195960a21b604482015260640162000134565b505050565b6060813b6001811162000310575050604080516020810190915260008152919050565b806200031c8162000412565b9150506040519150601f19601f602083010116820160405280825280600160208401853c50919050565b6060815160016200035891906200042c565b826040516020016200036c92919062000448565b6040516020818303038152906040529050919050565b80516001600160a01b03811681146200039a57600080fd5b919050565b600080600060608486031215620003b557600080fd5b620003c08462000382565b925060208401519150604084015190509250925092565b600060208284031215620003ea57600080fd5b620003f58262000382565b9392505050565b634e487b7160e01b600052601160045260246000fd5b600081620004245762000424620003fc565b506000190190565b80820180821115620004425762000442620003fc565b92915050565b606360f81b815260e083901b6001600160e01b03191660018201526880600e6000396000f360b81b60058201526000600e82018190528251815b81811015620004a1576020818601810151600f86840101520162000482565b5060009201600f019182525092915050565b61188280620004c36000396000f3fe60806040526004361061012c5760003560e01c8063a4f9edbf116100a5578063bc197c8111610074578063e00b911811610059578063e00b911814610371578063f23a6e6114610391578063fc0c546a146103be57600080fd5b8063bc197c8114610315578063c7dec3fc1461034457600080fd5b8063a4f9edbf14610292578063affed0e0146102b2578063b0d691fe146102c7578063b94207d31461030257600080fd5b806317d70f7c116100fc5780636d70f7ae116100e15780636d70f7ae1461022c57806391b7f5ed1461025c578063a035b1fe1461027c57600080fd5b806317d70f7c146101e95780633a871cdd1461020c57600080fd5b806223de2914610138578063150b7a021461015f578063157305fe146101a95780631626ba7e146101c957600080fd5b3661013357005b600080fd5b34801561014457600080fd5b5061015d610153366004611118565b5050505050505050565b005b34801561016b57600080fd5b5061018b61017a3660046111c9565b630a85bd0160e11b95945050505050565b6040516001600160e01b031990911681526020015b60405180910390f35b3480156101b557600080fd5b5061015d6101c43660046112df565b6103d3565b3480156101d557600080fd5b5061018b6101e43660046112df565b6104ae565b3480156101f557600080fd5b506101fe6105db565b6040519081526020016101a0565b34801561021857600080fd5b506101fe610227366004611326565b610600565b34801561023857600080fd5b5061024c61024736600461137a565b61063e565b60405190151581526020016101a0565b34801561026857600080fd5b5061015d610277366004611397565b6106ed565b34801561028857600080fd5b506101fe60015481565b34801561029e57600080fd5b5061015d6102ad3660046113b0565b6107c1565b3480156102be57600080fd5b506000546101fe565b3480156102d357600080fd5b50730576a174d229e3cfa37253523e645a78a0c91b575b6040516001600160a01b0390911681526020016101a0565b6101fe6103103660046113b0565b610823565b34801561032157600080fd5b5061018b610330366004611432565b63bc197c8160e01b98975050505050505050565b34801561035057600080fd5b5061036461035f3660046114d0565b6108a9565b6040516101a09190611598565b34801561037d57600080fd5b506101fe61038c3660046115ab565b61097a565b34801561039d57600080fd5b5061018b6103ac3660046115e5565b63f23a6e6160e01b9695505050505050565b3480156103ca57600080fd5b506102ea6109ae565b6103dc3361063e565b806103fa575033730576a174d229e3cfa37253523e645a78a0c91b57145b6104715760405162461bcd60e51b815260206004820152603e60248201527f4f6e6c792063616c6c61626c6520627920746865206d656368206f706572617460448201527f6f72206f722074686520656e74727920706f696e7420636f6e7472616374000060648201526084015b60405180910390fd5b7f3ec84da2cdc1ce60c063642b69ff2e65f3b69787a2b90443457ba274e51e7c7282826040516104a2929190611661565b60405180910390a15050565b6000806000806104d1856020810151604082015160609092015160001a92909190565b9094509250905060ff811660000361059f57828583016020016104f38261063e565b15801561050957506001600160a01b0382163014155b1561052457506001600160e01b031994506105d59350505050565b604051630b135d3f60e11b81526001600160a01b03831690631626ba7e90610552908b908590600401611661565b602060405180830381865afa15801561056f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610593919061167a565b955050505050506105d5565b6105ae610247878386866109cc565b156105c65750630b135d3f60e11b92506105d5915050565b506001600160e01b0319925050505b92915050565b6000806105e66109ea565b8060200190518101906105f991906116a4565b9392505050565b600061060a610a59565b6106148484610abe565b905061062360408501856116d2565b90506000036106355761063584610b91565b6105f982610bf6565b600080600061064b6109ea565b80602001905181019061065e91906116a4565b91509150836001600160a01b0316826001600160a01b0316636352211e836040518263ffffffff1660e01b815260040161069a91815260200190565b602060405180830381865afa1580156106b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106db9190611719565b6001600160a01b031614949350505050565b6106f63361063e565b80610714575033730576a174d229e3cfa37253523e645a78a0c91b57145b6107865760405162461bcd60e51b815260206004820152603e60248201527f4f6e6c792063616c6c61626c6520627920746865206d656368206f706572617460448201527f6f72206f722074686520656e74727920706f696e7420636f6e747261637400006064820152608401610468565b60018190556040518181527f66cbca4f3c64fecf1dcb9ce094abcf7f68c3450a1d4e3a8e917dd621edb4ebe09060200160405180910390a150565b6107c96109ea565b51156108175760405162461bcd60e51b815260206004820152601360248201527f416c726561647920696e697469616c697a6564000000000000000000000000006044820152606401610468565b61082081610c4f565b50565b6000600154341015610855576001546040516316912f0560e31b81523460048201526024810191909152604401610468565b61085f338361097a565b9050336001600160a01b03167f4bda649efe6b98b0f9c1d5e859c29e20910f45c66dabfe6fad4a4881f7faf9cc828460405161089c929190611661565b60405180910390a2919050565b60606108b43361063e565b806108d2575033730576a174d229e3cfa37253523e645a78a0c91b57145b6109445760405162461bcd60e51b815260206004820152603e60248201527f4f6e6c792063616c6c61626c6520627920746865206d656368206f706572617460448201527f6f72206f722074686520656e74727920706f696e7420636f6e747261637400006064820152608401610468565b600061095f8787878787156109595787610d2e565b5a610d2e565b925090508061097057815160208301fd5b5095945050505050565b6000828260405160200161098f929190611736565b60408051601f1981840301815291905280516020909101209392505050565b6000806109b96109ea565b8060200190518101906105d59190611719565b60008060006109dd87878787610e1e565b9150915061097081610ee2565b6060610a54610a4f604051606b60f91b6020820152602560fa1b60218201526bffffffffffffffffffffffff193060601b166022820152600160f81b60368201526000906037016040516020818303038152906040528051906020012060001c905090565b61102c565b905090565b33730576a174d229e3cfa37253523e645a78a0c91b5714610abc5760405162461bcd60e51b815260206004820152601c60248201527f6163636f756e743a206e6f742066726f6d20456e747279506f696e74000000006044820152606401610468565b565b600080610b18836040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b9050630b135d3f60e11b610b6e82610b346101408801886116d2565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506104ae92505050565b6001600160e01b03191614610b875760019150506105d5565b5060009392505050565b6000805460208301359180610ba58361176e565b91905055146108205760405162461bcd60e51b815260206004820152600d60248201527f496e76616c6964206e6f6e6365000000000000000000000000000000000000006044820152606401610468565b801561082057604051600090339060001990849084818181858888f193505050503d8060008114610c43576040519150601f19603f3d011682016040523d82523d6000602084013e610c48565b606091505b5050505050565b6000610c5a82611082565b905060008151602083016000f09050610cc9604051606b60f91b6020820152602560fa1b60218201526bffffffffffffffffffffffff193060601b166022820152600160f81b60368201526000906037016040516020818303038152906040528051906020012060001c905090565b6001600160a01b0316816001600160a01b031614610d295760405162461bcd60e51b815260206004820152600c60248201527f5772697465206661696c656400000000000000000000000000000000000000006044820152606401610468565b505050565b600060606001846001811115610d4657610d46611787565b03610db057866001600160a01b03168386604051610d64919061179d565b6000604051808303818686f4925050503d8060008114610da0576040519150601f19603f3d011682016040523d82523d6000602084013e610da5565b606091505b509092509050610e14565b866001600160a01b0316838787604051610dca919061179d565b600060405180830381858888f193505050503d8060008114610e08576040519150601f19603f3d011682016040523d82523d6000602084013e610e0d565b606091505b5090925090505b9550959350505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115610e555750600090506003610ed9565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015610ea9573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610ed257600060019250925050610ed9565b9150600090505b94509492505050565b6000816004811115610ef657610ef6611787565b03610efe5750565b6001816004811115610f1257610f12611787565b03610f5f5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610468565b6002816004811115610f7357610f73611787565b03610fc05760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610468565b6003816004811115610fd457610fd4611787565b036108205760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610468565b6060813b6001811161104e575050604080516020810190915260008152919050565b80611058816117b9565b9150506040519150601f19601f602083010116820160405280825280600160208401853c50919050565b60608151600161109291906117d0565b826040516020016110a49291906117e3565b6040516020818303038152906040529050919050565b6001600160a01b038116811461082057600080fd5b60008083601f8401126110e157600080fd5b50813567ffffffffffffffff8111156110f957600080fd5b60208301915083602082850101111561111157600080fd5b9250929050565b60008060008060008060008060c0898b03121561113457600080fd5b883561113f816110ba565b9750602089013561114f816110ba565b9650604089013561115f816110ba565b955060608901359450608089013567ffffffffffffffff8082111561118357600080fd5b61118f8c838d016110cf565b909650945060a08b01359150808211156111a857600080fd5b506111b58b828c016110cf565b999c989b5096995094979396929594505050565b6000806000806000608086880312156111e157600080fd5b85356111ec816110ba565b945060208601356111fc816110ba565b935060408601359250606086013567ffffffffffffffff81111561121f57600080fd5b61122b888289016110cf565b969995985093965092949392505050565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261126357600080fd5b813567ffffffffffffffff8082111561127e5761127e61123c565b604051601f8301601f19908116603f011681019082821181831017156112a6576112a661123c565b816040528381528660208588010111156112bf57600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080604083850312156112f257600080fd5b82359150602083013567ffffffffffffffff81111561131057600080fd5b61131c85828601611252565b9150509250929050565b60008060006060848603121561133b57600080fd5b833567ffffffffffffffff81111561135257600080fd5b8401610160818703121561136557600080fd5b95602085013595506040909401359392505050565b60006020828403121561138c57600080fd5b81356105f9816110ba565b6000602082840312156113a957600080fd5b5035919050565b6000602082840312156113c257600080fd5b813567ffffffffffffffff8111156113d957600080fd5b6113e584828501611252565b949350505050565b60008083601f8401126113ff57600080fd5b50813567ffffffffffffffff81111561141757600080fd5b6020830191508360208260051b850101111561111157600080fd5b60008060008060008060008060a0898b03121561144e57600080fd5b8835611459816110ba565b97506020890135611469816110ba565b9650604089013567ffffffffffffffff8082111561148657600080fd5b6114928c838d016113ed565b909850965060608b01359150808211156114ab57600080fd5b6114b78c838d016113ed565b909650945060808b01359150808211156111a857600080fd5b600080600080600060a086880312156114e857600080fd5b85356114f3816110ba565b945060208601359350604086013567ffffffffffffffff81111561151657600080fd5b61152288828901611252565b93505060608601356002811061153757600080fd5b949793965091946080013592915050565b60005b8381101561156357818101518382015260200161154b565b50506000910152565b60008151808452611584816020860160208601611548565b601f01601f19169290920160200192915050565b6020815260006105f9602083018461156c565b600080604083850312156115be57600080fd5b82356115c9816110ba565b9150602083013567ffffffffffffffff81111561131057600080fd5b60008060008060008060a087890312156115fe57600080fd5b8635611609816110ba565b95506020870135611619816110ba565b94506040870135935060608701359250608087013567ffffffffffffffff81111561164357600080fd5b61164f89828a016110cf565b979a9699509497509295939492505050565b8281526040602082015260006113e5604083018461156c565b60006020828403121561168c57600080fd5b81516001600160e01b0319811681146105f957600080fd5b600080604083850312156116b757600080fd5b82516116c2816110ba565b6020939093015192949293505050565b6000808335601e198436030181126116e957600080fd5b83018035915067ffffffffffffffff82111561170457600080fd5b60200191503681900382131561111157600080fd5b60006020828403121561172b57600080fd5b81516105f9816110ba565b6001600160a01b03831681526040602082015260006113e5604083018461156c565b634e487b7160e01b600052601160045260246000fd5b60006001820161178057611780611758565b5060010190565b634e487b7160e01b600052602160045260246000fd5b600082516117af818460208701611548565b9190910192915050565b6000816117c8576117c8611758565b506000190190565b808201808211156105d5576105d5611758565b606360f81b815263ffffffff60e01b8360e01b1660018201527f80600e6000396000f3000000000000000000000000000000000000000000000060058201526000600e8201526000825161183e81600f850160208701611548565b91909101600f01939250505056fea26469706673582212202a03e14f0f05f58be9cbbba4646c39d989209350f0ee3edaaf0da00994a368d164736f6c63430008130033", + "deployedBytecode": "0x60806040526004361061012c5760003560e01c8063a4f9edbf116100a5578063bc197c8111610074578063e00b911811610059578063e00b911814610371578063f23a6e6114610391578063fc0c546a146103be57600080fd5b8063bc197c8114610315578063c7dec3fc1461034457600080fd5b8063a4f9edbf14610292578063affed0e0146102b2578063b0d691fe146102c7578063b94207d31461030257600080fd5b806317d70f7c116100fc5780636d70f7ae116100e15780636d70f7ae1461022c57806391b7f5ed1461025c578063a035b1fe1461027c57600080fd5b806317d70f7c146101e95780633a871cdd1461020c57600080fd5b806223de2914610138578063150b7a021461015f578063157305fe146101a95780631626ba7e146101c957600080fd5b3661013357005b600080fd5b34801561014457600080fd5b5061015d610153366004611118565b5050505050505050565b005b34801561016b57600080fd5b5061018b61017a3660046111c9565b630a85bd0160e11b95945050505050565b6040516001600160e01b031990911681526020015b60405180910390f35b3480156101b557600080fd5b5061015d6101c43660046112df565b6103d3565b3480156101d557600080fd5b5061018b6101e43660046112df565b6104ae565b3480156101f557600080fd5b506101fe6105db565b6040519081526020016101a0565b34801561021857600080fd5b506101fe610227366004611326565b610600565b34801561023857600080fd5b5061024c61024736600461137a565b61063e565b60405190151581526020016101a0565b34801561026857600080fd5b5061015d610277366004611397565b6106ed565b34801561028857600080fd5b506101fe60015481565b34801561029e57600080fd5b5061015d6102ad3660046113b0565b6107c1565b3480156102be57600080fd5b506000546101fe565b3480156102d357600080fd5b50730576a174d229e3cfa37253523e645a78a0c91b575b6040516001600160a01b0390911681526020016101a0565b6101fe6103103660046113b0565b610823565b34801561032157600080fd5b5061018b610330366004611432565b63bc197c8160e01b98975050505050505050565b34801561035057600080fd5b5061036461035f3660046114d0565b6108a9565b6040516101a09190611598565b34801561037d57600080fd5b506101fe61038c3660046115ab565b61097a565b34801561039d57600080fd5b5061018b6103ac3660046115e5565b63f23a6e6160e01b9695505050505050565b3480156103ca57600080fd5b506102ea6109ae565b6103dc3361063e565b806103fa575033730576a174d229e3cfa37253523e645a78a0c91b57145b6104715760405162461bcd60e51b815260206004820152603e60248201527f4f6e6c792063616c6c61626c6520627920746865206d656368206f706572617460448201527f6f72206f722074686520656e74727920706f696e7420636f6e7472616374000060648201526084015b60405180910390fd5b7f3ec84da2cdc1ce60c063642b69ff2e65f3b69787a2b90443457ba274e51e7c7282826040516104a2929190611661565b60405180910390a15050565b6000806000806104d1856020810151604082015160609092015160001a92909190565b9094509250905060ff811660000361059f57828583016020016104f38261063e565b15801561050957506001600160a01b0382163014155b1561052457506001600160e01b031994506105d59350505050565b604051630b135d3f60e11b81526001600160a01b03831690631626ba7e90610552908b908590600401611661565b602060405180830381865afa15801561056f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610593919061167a565b955050505050506105d5565b6105ae610247878386866109cc565b156105c65750630b135d3f60e11b92506105d5915050565b506001600160e01b0319925050505b92915050565b6000806105e66109ea565b8060200190518101906105f991906116a4565b9392505050565b600061060a610a59565b6106148484610abe565b905061062360408501856116d2565b90506000036106355761063584610b91565b6105f982610bf6565b600080600061064b6109ea565b80602001905181019061065e91906116a4565b91509150836001600160a01b0316826001600160a01b0316636352211e836040518263ffffffff1660e01b815260040161069a91815260200190565b602060405180830381865afa1580156106b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106db9190611719565b6001600160a01b031614949350505050565b6106f63361063e565b80610714575033730576a174d229e3cfa37253523e645a78a0c91b57145b6107865760405162461bcd60e51b815260206004820152603e60248201527f4f6e6c792063616c6c61626c6520627920746865206d656368206f706572617460448201527f6f72206f722074686520656e74727920706f696e7420636f6e747261637400006064820152608401610468565b60018190556040518181527f66cbca4f3c64fecf1dcb9ce094abcf7f68c3450a1d4e3a8e917dd621edb4ebe09060200160405180910390a150565b6107c96109ea565b51156108175760405162461bcd60e51b815260206004820152601360248201527f416c726561647920696e697469616c697a6564000000000000000000000000006044820152606401610468565b61082081610c4f565b50565b6000600154341015610855576001546040516316912f0560e31b81523460048201526024810191909152604401610468565b61085f338361097a565b9050336001600160a01b03167f4bda649efe6b98b0f9c1d5e859c29e20910f45c66dabfe6fad4a4881f7faf9cc828460405161089c929190611661565b60405180910390a2919050565b60606108b43361063e565b806108d2575033730576a174d229e3cfa37253523e645a78a0c91b57145b6109445760405162461bcd60e51b815260206004820152603e60248201527f4f6e6c792063616c6c61626c6520627920746865206d656368206f706572617460448201527f6f72206f722074686520656e74727920706f696e7420636f6e747261637400006064820152608401610468565b600061095f8787878787156109595787610d2e565b5a610d2e565b925090508061097057815160208301fd5b5095945050505050565b6000828260405160200161098f929190611736565b60408051601f1981840301815291905280516020909101209392505050565b6000806109b96109ea565b8060200190518101906105d59190611719565b60008060006109dd87878787610e1e565b9150915061097081610ee2565b6060610a54610a4f604051606b60f91b6020820152602560fa1b60218201526bffffffffffffffffffffffff193060601b166022820152600160f81b60368201526000906037016040516020818303038152906040528051906020012060001c905090565b61102c565b905090565b33730576a174d229e3cfa37253523e645a78a0c91b5714610abc5760405162461bcd60e51b815260206004820152601c60248201527f6163636f756e743a206e6f742066726f6d20456e747279506f696e74000000006044820152606401610468565b565b600080610b18836040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b9050630b135d3f60e11b610b6e82610b346101408801886116d2565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506104ae92505050565b6001600160e01b03191614610b875760019150506105d5565b5060009392505050565b6000805460208301359180610ba58361176e565b91905055146108205760405162461bcd60e51b815260206004820152600d60248201527f496e76616c6964206e6f6e6365000000000000000000000000000000000000006044820152606401610468565b801561082057604051600090339060001990849084818181858888f193505050503d8060008114610c43576040519150601f19603f3d011682016040523d82523d6000602084013e610c48565b606091505b5050505050565b6000610c5a82611082565b905060008151602083016000f09050610cc9604051606b60f91b6020820152602560fa1b60218201526bffffffffffffffffffffffff193060601b166022820152600160f81b60368201526000906037016040516020818303038152906040528051906020012060001c905090565b6001600160a01b0316816001600160a01b031614610d295760405162461bcd60e51b815260206004820152600c60248201527f5772697465206661696c656400000000000000000000000000000000000000006044820152606401610468565b505050565b600060606001846001811115610d4657610d46611787565b03610db057866001600160a01b03168386604051610d64919061179d565b6000604051808303818686f4925050503d8060008114610da0576040519150601f19603f3d011682016040523d82523d6000602084013e610da5565b606091505b509092509050610e14565b866001600160a01b0316838787604051610dca919061179d565b600060405180830381858888f193505050503d8060008114610e08576040519150601f19603f3d011682016040523d82523d6000602084013e610e0d565b606091505b5090925090505b9550959350505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115610e555750600090506003610ed9565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015610ea9573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610ed257600060019250925050610ed9565b9150600090505b94509492505050565b6000816004811115610ef657610ef6611787565b03610efe5750565b6001816004811115610f1257610f12611787565b03610f5f5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610468565b6002816004811115610f7357610f73611787565b03610fc05760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610468565b6003816004811115610fd457610fd4611787565b036108205760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610468565b6060813b6001811161104e575050604080516020810190915260008152919050565b80611058816117b9565b9150506040519150601f19601f602083010116820160405280825280600160208401853c50919050565b60608151600161109291906117d0565b826040516020016110a49291906117e3565b6040516020818303038152906040529050919050565b6001600160a01b038116811461082057600080fd5b60008083601f8401126110e157600080fd5b50813567ffffffffffffffff8111156110f957600080fd5b60208301915083602082850101111561111157600080fd5b9250929050565b60008060008060008060008060c0898b03121561113457600080fd5b883561113f816110ba565b9750602089013561114f816110ba565b9650604089013561115f816110ba565b955060608901359450608089013567ffffffffffffffff8082111561118357600080fd5b61118f8c838d016110cf565b909650945060a08b01359150808211156111a857600080fd5b506111b58b828c016110cf565b999c989b5096995094979396929594505050565b6000806000806000608086880312156111e157600080fd5b85356111ec816110ba565b945060208601356111fc816110ba565b935060408601359250606086013567ffffffffffffffff81111561121f57600080fd5b61122b888289016110cf565b969995985093965092949392505050565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261126357600080fd5b813567ffffffffffffffff8082111561127e5761127e61123c565b604051601f8301601f19908116603f011681019082821181831017156112a6576112a661123c565b816040528381528660208588010111156112bf57600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080604083850312156112f257600080fd5b82359150602083013567ffffffffffffffff81111561131057600080fd5b61131c85828601611252565b9150509250929050565b60008060006060848603121561133b57600080fd5b833567ffffffffffffffff81111561135257600080fd5b8401610160818703121561136557600080fd5b95602085013595506040909401359392505050565b60006020828403121561138c57600080fd5b81356105f9816110ba565b6000602082840312156113a957600080fd5b5035919050565b6000602082840312156113c257600080fd5b813567ffffffffffffffff8111156113d957600080fd5b6113e584828501611252565b949350505050565b60008083601f8401126113ff57600080fd5b50813567ffffffffffffffff81111561141757600080fd5b6020830191508360208260051b850101111561111157600080fd5b60008060008060008060008060a0898b03121561144e57600080fd5b8835611459816110ba565b97506020890135611469816110ba565b9650604089013567ffffffffffffffff8082111561148657600080fd5b6114928c838d016113ed565b909850965060608b01359150808211156114ab57600080fd5b6114b78c838d016113ed565b909650945060808b01359150808211156111a857600080fd5b600080600080600060a086880312156114e857600080fd5b85356114f3816110ba565b945060208601359350604086013567ffffffffffffffff81111561151657600080fd5b61152288828901611252565b93505060608601356002811061153757600080fd5b949793965091946080013592915050565b60005b8381101561156357818101518382015260200161154b565b50506000910152565b60008151808452611584816020860160208601611548565b601f01601f19169290920160200192915050565b6020815260006105f9602083018461156c565b600080604083850312156115be57600080fd5b82356115c9816110ba565b9150602083013567ffffffffffffffff81111561131057600080fd5b60008060008060008060a087890312156115fe57600080fd5b8635611609816110ba565b95506020870135611619816110ba565b94506040870135935060608701359250608087013567ffffffffffffffff81111561164357600080fd5b61164f89828a016110cf565b979a9699509497509295939492505050565b8281526040602082015260006113e5604083018461156c565b60006020828403121561168c57600080fd5b81516001600160e01b0319811681146105f957600080fd5b600080604083850312156116b757600080fd5b82516116c2816110ba565b6020939093015192949293505050565b6000808335601e198436030181126116e957600080fd5b83018035915067ffffffffffffffff82111561170457600080fd5b60200191503681900382131561111157600080fd5b60006020828403121561172b57600080fd5b81516105f9816110ba565b6001600160a01b03831681526040602082015260006113e5604083018461156c565b634e487b7160e01b600052601160045260246000fd5b60006001820161178057611780611758565b5060010190565b634e487b7160e01b600052602160045260246000fd5b600082516117af818460208701611548565b9190910192915050565b6000816117c8576117c8611758565b506000190190565b808201808211156105d5576105d5611758565b606360f81b815263ffffffff60e01b8360e01b1660018201527f80600e6000396000f3000000000000000000000000000000000000000000000060058201526000600e8201526000825161183e81600f850160208701611548565b91909101600f01939250505056fea26469706673582212202a03e14f0f05f58be9cbbba4646c39d989209350f0ee3edaaf0da00994a368d164736f6c63430008130033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/packages/valory/contracts/hash_checkpoint/contract.py b/packages/valory/contracts/hash_checkpoint/contract.py new file mode 100644 index 00000000..835db5aa --- /dev/null +++ b/packages/valory/contracts/hash_checkpoint/contract.py @@ -0,0 +1,127 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2023 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""This module contains the hash checkpoint contract definition.""" +from enum import Enum +from typing import Any, Dict, List, cast + +from aea.common import JSONLike +from aea.configurations.base import PublicId +from aea.contracts.base import Contract +from aea.crypto.base import LedgerApi +from aea_ledger_ethereum import EthereumApi +from web3.types import BlockIdentifier, TxReceipt + + +class HashCheckpointContract(Contract): + """The scaffold contract class for a smart contract.""" + + contract_id = PublicId.from_str("valory/hash_checkpoint:0.1.0") + + @classmethod + def get_raw_transaction( + cls, ledger_api: LedgerApi, contract_address: str, **kwargs: Any + ) -> JSONLike: + """ + Handler method for the 'GET_RAW_TRANSACTION' requests. + + Implement this method in the sub class if you want + to handle the contract requests manually. + + :param ledger_api: the ledger apis. + :param contract_address: the contract address. + :param kwargs: the keyword arguments. + :return: the tx # noqa: DAR202 + """ + raise NotImplementedError + + @classmethod + def get_raw_message( + cls, ledger_api: LedgerApi, contract_address: str, **kwargs: Any + ) -> bytes: + """ + Handler method for the 'GET_RAW_MESSAGE' requests. + + Implement this method in the sub class if you want + to handle the contract requests manually. + + :param ledger_api: the ledger apis. + :param contract_address: the contract address. + :param kwargs: the keyword arguments. + :return: the tx # noqa: DAR202 + """ + raise NotImplementedError + + @classmethod + def get_state( + cls, ledger_api: LedgerApi, contract_address: str, **kwargs: Any + ) -> JSONLike: + """ + Handler method for the 'GET_STATE' requests. + + Implement this method in the sub class if you want + to handle the contract requests manually. + + :param ledger_api: the ledger apis. + :param contract_address: the contract address. + :param kwargs: the keyword arguments. + :return: the tx # noqa: DAR202 + """ + raise NotImplementedError + + @classmethod + def get_checkpoint_data( + cls, ledger_api: LedgerApi, contract_address: str, data: bytes + ) -> JSONLike: + """ + Deliver a response to a request. + + :param ledger_api: LedgerApi object + :param contract_address: the address of the token to be used + :param data: the ipfs hash + :return: the deliver data + """ + ledger_api = cast(EthereumApi, ledger_api) + + if not isinstance(ledger_api, EthereumApi): + raise ValueError(f"Only EthereumApi is supported, got {type(ledger_api)}") + + contract_instance = cls.get_instance(ledger_api, contract_address) + data = contract_instance.encodeABI( + fn_name="checkpoint", args=[data] + ) + return {"data": data} + + @classmethod + def get_latest_hash( + cls, + ledger_api: LedgerApi, + contract_address: str, + sender_address: str, + ) -> JSONLike: + """Get the Request events emitted by the contract.""" + ledger_api = cast(EthereumApi, ledger_api) + + if not isinstance(ledger_api, EthereumApi): + raise ValueError(f"Only EthereumApi is supported, got {type(ledger_api)}") + + contract_instance = cls.get_instance(ledger_api, contract_address) + sender_address = ledger_api.api.to_checksum_address(sender_address) + latest_ipfs_hash = contract_instance.functions.latestHash(sender_address).call() + return {"data": latest_ipfs_hash} diff --git a/packages/valory/contracts/hash_checkpoint/contract.yaml b/packages/valory/contracts/hash_checkpoint/contract.yaml new file mode 100644 index 00000000..e5cbf9ad --- /dev/null +++ b/packages/valory/contracts/hash_checkpoint/contract.yaml @@ -0,0 +1,21 @@ +name: hash_checkpoint +author: valory +version: 0.1.0 +type: contract +description: Hash checkpoint contract +license: Apache-2.0 +aea_version: '>=1.0.0, <2.0.0' +fingerprint: + __init__.py: bafybeigpq5lxfj2aza6ok3fjuywtdafelkbvoqwaits7regfbgu4oynmku + build/HashCheckpoint.json: bafybeicdse6k7xbis3mdurqee7a3ghiba4hzfk4llhc3hk6q4qbfjd5rg4 + contract.py: bafybeiaklk45tud5qogk6zeufwlewlgbaunux5kbahj4auf6xzkikfgwru +fingerprint_ignore_patterns: [] +class_name: HashCheckpointContract +contract_interface_paths: + ethereum: build/HashCheckpoint.json +dependencies: + open-aea-ledger-ethereum: + version: ==1.41.0.post1 + web3: + version: <7,>=6.0.0 +contracts: [] diff --git a/packages/valory/services/mech/service.yaml b/packages/valory/services/mech/service.yaml index acdc97d9..03e6eb03 100644 --- a/packages/valory/services/mech/service.yaml +++ b/packages/valory/services/mech/service.yaml @@ -7,7 +7,7 @@ license: Apache-2.0 fingerprint: README.md: bafybeif7ia4jdlazy6745ke2k2x5yoqlwsgwr6sbztbgqtwvs3ndm2p7ba fingerprint_ignore_patterns: [] -agent: valory/mech:0.1.0:bafybeiamnuotz3zj7whskv6hoieswntuobr3fowkfoh52xw4vait4b5eli +agent: valory/mech:0.1.0:bafybeih5idugp2jm7hxzj63tvvfep3tradk2hhnxipro2egaxnvmdaqjka number_of_agents: 4 deployment: agent: @@ -55,6 +55,8 @@ type: skill agent_registry_address: ${AGENT_REGISTRY_ADDRESS:str:0xE49CB081e8d96920C38aA7AB90cb0294ab4Bc8EA} agent_id: ${AGENT_ID:int:3} metadata_hash: ${METADATA_HASH:str:f01701220caa53607238e340da63b296acab232c18a48e954f0af6ff2b835b2d93f1962f0} + profit_split_freq: ${PROFIT_SPLIT_FREQ:int:100} + hash_checkpoint_address: ${CHECKPOINT_ADDRESS:str:0x0000000000000000000000000000000000000000} 1: models: params: @@ -83,6 +85,8 @@ type: skill agent_registry_address: ${AGENT_REGISTRY_ADDRESS:str:0xE49CB081e8d96920C38aA7AB90cb0294ab4Bc8EA} agent_id: ${AGENT_ID:int:3} metadata_hash: ${METADATA_HASH:str:f01701220caa53607238e340da63b296acab232c18a48e954f0af6ff2b835b2d93f1962f0} + profit_split_freq: ${PROFIT_SPLIT_FREQ:int:100} + hash_checkpoint_address: ${CHECKPOINT_ADDRESS:str:0x0000000000000000000000000000000000000000} service_endpoint_base: ${SERVICE_ENDPOINT_BASE:str:https://dummy_service.autonolas.tech/} 2: models: @@ -113,6 +117,8 @@ type: skill agent_registry_address: ${AGENT_REGISTRY_ADDRESS:str:0xE49CB081e8d96920C38aA7AB90cb0294ab4Bc8EA} agent_id: ${AGENT_ID:int:3} metadata_hash: ${METADATA_HASH:str:f01701220caa53607238e340da63b296acab232c18a48e954f0af6ff2b835b2d93f1962f0} + profit_split_freq: ${PROFIT_SPLIT_FREQ:int:100} + hash_checkpoint_address: ${CHECKPOINT_ADDRESS:str:0x0000000000000000000000000000000000000000} 3: models: params: @@ -141,6 +147,8 @@ type: skill agent_registry_address: ${AGENT_REGISTRY_ADDRESS:str:0xE49CB081e8d96920C38aA7AB90cb0294ab4Bc8EA} agent_id: ${AGENT_ID:int:3} metadata_hash: ${METADATA_HASH:str:f01701220caa53607238e340da63b296acab232c18a48e954f0af6ff2b835b2d93f1962f0} + profit_split_freq: ${PROFIT_SPLIT_FREQ:int:100} + hash_checkpoint_address: ${CHECKPOINT_ADDRESS:str:0x0000000000000000000000000000000000000000} service_endpoint_base: ${SERVICE_ENDPOINT_BASE:str:https://dummy_service.autonolas.tech/} --- public_id: valory/task_execution:0.1.0 diff --git a/packages/valory/skills/mech_abci/skill.yaml b/packages/valory/skills/mech_abci/skill.yaml index 71608c8c..2260e426 100644 --- a/packages/valory/skills/mech_abci/skill.yaml +++ b/packages/valory/skills/mech_abci/skill.yaml @@ -23,7 +23,7 @@ skills: - valory/abstract_round_abci:0.1.0:bafybeifcq2nwd6m5tgxooe7436bc6lwo73xcreedmhcwauzhp5jic6jeq4 - valory/registration_abci:0.1.0:bafybeig5fb3ibz3tr4kie53venqtajnlhvh7gwt5h45rxwzakwgs6jjsjq - valory/reset_pause_abci:0.1.0:bafybeiergfseqtmsphdimzjijxezqyyhigktvqriw2xb4dyujim6s5dr4a -- valory/task_submission_abci:0.1.0:bafybeihluuiksi63kwp2kzn5hdbeek74bnhsctdwl72qv2xjmzqvf7j3va +- valory/task_submission_abci:0.1.0:bafybeigdvfzghhjfrlov4f4newyalguuaxl7jk4ccomflgloy46wfijs5i - valory/termination_abci:0.1.0:bafybeia73cl2vqj2uawt5lnoej3fzlhhum72i2p6ld4bbudd67lxb7f3cu - valory/transaction_settlement_abci:0.1.0:bafybeifqase6vqfrakahogdl4h2hpxntug5ckioicfqlw2og5tn6htru3q behaviours: @@ -159,8 +159,11 @@ models: agent_id: 3 metadata_hash: '00000000000000000000000000000000000000000000000000' slash_cooldown_hours: 3 + hash_checkpoint_address: '0x0000000000000000000000000000000000000000' slash_threshold_amount: 10000000000000000 light_slash_unit_amount: 5000000000000000 + service_owner_share: 0.1 + profit_split_freq: 100 serious_slash_unit_amount: 8000000000000000 service_endpoint_base: https://dummy_service.autonolas.tech/ class_name: Params diff --git a/packages/valory/skills/task_execution/behaviours.py b/packages/valory/skills/task_execution/behaviours.py index 0c8908ec..be421477 100644 --- a/packages/valory/skills/task_execution/behaviours.py +++ b/packages/valory/skills/task_execution/behaviours.py @@ -274,8 +274,15 @@ def _handle_done_task(self, task_result: Any) -> None: executing_task = cast(Dict[str, Any], self._executing_task) req_id = executing_task.get("requestId", None) mech_address = executing_task.get("contract_address", None) + tool = executing_task.get("tool", None) response = {"requestId": req_id, "result": "Invalid response"} - self._done_task = {"request_id": req_id, "mech_address": mech_address} + task_executor = self.context.agent_address + self._done_task = { + "request_id": req_id, + "mech_address": mech_address, + "task_executor_address": task_executor, + "tool": tool, + } if task_result is not None: # task succeeded deliver_msg, prompt, transaction = task_result @@ -330,6 +337,8 @@ def _handle_get_task(self, message: IpfsMessage, dialogue: Dialogue) -> None: self._prepare_task(task_data) elif is_data_valid: tool = task_data["tool"] + executing_task = cast(Dict[str, Any], self._executing_task) + executing_task["tool"] = tool self.context.logger.warning(f"Tool {tool} is not valid.") self._invalid_request = True else: @@ -358,6 +367,7 @@ def _prepare_task(self, task_data: Dict[str, Any]) -> None: future = self._submit_task(tool_task.execute, **task_data) executing_task = cast(Dict[str, Any], self._executing_task) executing_task["timeout_deadline"] = time.time() + self.params.task_deadline + executing_task["tool"] = task_data["tool"] self._async_result = cast(Optional[Future], future) def _build_ipfs_message( diff --git a/packages/valory/skills/task_execution/skill.yaml b/packages/valory/skills/task_execution/skill.yaml index b7ba2c09..cc96dd14 100644 --- a/packages/valory/skills/task_execution/skill.yaml +++ b/packages/valory/skills/task_execution/skill.yaml @@ -7,7 +7,7 @@ license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: __init__.py: bafybeidqhvvlnthkbnmrdkdeyjyx2f2ab6z4xdgmagh7welqnh2v6wczx4 - behaviours.py: bafybeie4h4m4py7u3ah4mcotiah32umi7lb5xnxmzpvvhikushaedcglkq + behaviours.py: bafybeiahzfpgcjpvbhpfkbifrkzb6qaj2gesnkswdi2lj7yszhe27dvjtm dialogues.py: bafybeid4zxalqdlo5mw4yfbuf34hx4jp5ay5z6chm4zviwu4cj7fudtwca handlers.py: bafybeidbt5ezj74cgfogk3w4uw4si2grlnk5g54veyumw7g5yh6gdscywu models.py: bafybeihc2kmymmh5oousjddbc7xujqbk5niermuqak2dhtgryukzq5wxeq @@ -20,7 +20,7 @@ connections: - valory/ipfs:0.1.0:bafybeigfmqvlzbp67fttccpl4hsu3zaztbxv6vd7ikzra2hfppfkalgpji - valory/p2p_libp2p_client:0.1.0:bafybeihge56dn3xep2dzomu7rtvbgo4uc2qqh7ljl3fubqdi2lq44gs5lq contracts: -- valory/agent_mech:0.1.0:bafybeicshvlc2slopzidzblf2zhdcw2uuav3ntxcgqduxskjujvebikg5u +- valory/agent_mech:0.1.0:bafybeidyfhwye3ybk3vxrceljafe2n4o43oxtmjepvexpcrwlccboi34e4 protocols: - valory/acn_data_share:0.1.0:bafybeih5ydonnvrwvy2ygfqgfabkr47s4yw3uqxztmwyfprulwfsoe7ipq - valory/contract_api:1.0.0:bafybeialhbjvwiwcnqq3ysxcyemobcbie7xza66gaofcvla5njezkvhcka diff --git a/packages/valory/skills/task_submission_abci/behaviours.py b/packages/valory/skills/task_submission_abci/behaviours.py index d5f04052..0fcf8d7b 100644 --- a/packages/valory/skills/task_submission_abci/behaviours.py +++ b/packages/valory/skills/task_submission_abci/behaviours.py @@ -18,33 +18,41 @@ # ------------------------------------------------------------------------------ """This package contains round behaviours of TaskExecutionAbciApp.""" -import abc import json import threading import time +from abc import ABC from copy import deepcopy from typing import Any, Dict, Generator, List, Optional, Set, Type, cast import openai # noqa +from aea.helpers.cid import CID, to_v1 from multibase import multibase from multicodec import multicodec -from packages.valory.contracts.agent_mech.contract import AgentMechContract +from packages.valory.contracts.agent_mech.contract import ( + AgentMechContract, + MechOperation, +) from packages.valory.contracts.agent_registry.contract import AgentRegistryContract from packages.valory.contracts.gnosis_safe.contract import ( GnosisSafeContract, SafeOperation, ) +from packages.valory.contracts.hash_checkpoint.contract import HashCheckpointContract from packages.valory.contracts.multisend.contract import ( MultiSendContract, MultiSendOperation, ) +from packages.valory.contracts.service_registry.contract import ServiceRegistryContract from packages.valory.protocols.contract_api import ContractApiMessage +from packages.valory.protocols.ledger_api import LedgerApiMessage from packages.valory.skills.abstract_round_abci.base import AbstractRound from packages.valory.skills.abstract_round_abci.behaviours import ( AbstractRoundBehaviour, BaseBehaviour, ) +from packages.valory.skills.abstract_round_abci.io_.store import SupportedFiletype from packages.valory.skills.task_submission_abci.models import Params from packages.valory.skills.task_submission_abci.payloads import TransactionPayload from packages.valory.skills.task_submission_abci.rounds import ( @@ -60,12 +68,17 @@ ZERO_ETHER_VALUE = 0 -SAFE_GAS = 0 +AUTO_GAS = SAFE_GAS = 0 DONE_TASKS = "ready_tasks" DONE_TASKS_LOCK = "lock" +NO_DATA = b"" +ZERO_IPFS_HASH = ( + "f017012200000000000000000000000000000000000000000000000000000000000000000" +) +FILENAME = "usage" -class TaskExecutionBaseBehaviour(BaseBehaviour, abc.ABC): +class TaskExecutionBaseBehaviour(BaseBehaviour, ABC): """Base behaviour for the task_execution_abci skill.""" @property @@ -116,8 +129,24 @@ def remove_tasks(self, submitted_tasks: List[Dict[str, Any]]) -> None: not_submitted.append(done_task) self.context.shared_state[DONE_TASKS] = not_submitted + @property + def mech_addresses(self) -> List[str]: + """Get the addresses of the MECHs.""" + return self.context.params.agent_mech_contract_addresses -class TaskPoolingBehaviour(TaskExecutionBaseBehaviour): + @staticmethod + def to_multihash(hash_string: str) -> str: + """To multihash string.""" + # Decode the Base32 CID to bytes + cid_bytes = multibase.decode(hash_string) + # Remove the multicodec prefix (0x01) from the bytes + multihash_bytes = multicodec.remove_prefix(cid_bytes) + # Convert the multihash bytes to a hexadecimal string + hex_multihash = multihash_bytes.hex() + return hex_multihash[6:] + + +class TaskPoolingBehaviour(TaskExecutionBaseBehaviour, ABC): """TaskPoolingBehaviour""" matching_round: Type[AbstractRound] = TaskPoolingRound @@ -166,7 +195,473 @@ def handle_submitted_tasks(self) -> None: self.remove_tasks(submitted_tasks) -class TransactionPreparationBehaviour(TaskExecutionBaseBehaviour): +class DeliverBehaviour(TaskExecutionBaseBehaviour, ABC): + """Behaviour for tracking task delivery by the agents.""" + + def _get_current_delivery_report( + self, + ) -> Generator[None, None, Optional[Dict[str, Any]]]: + """Get the current .""" + contract_api_msg = yield from self.get_contract_api_response( + performative=ContractApiMessage.Performative.GET_STATE, # type: ignore + contract_address=self.params.hash_checkpoint_address, + contract_id=str(HashCheckpointContract.contract_id), + contract_callable="get_latest_hash", + sender_address=self.synchronized_data.safe_contract_address, + ) + if contract_api_msg.performative != ContractApiMessage.Performative.STATE: + self.context.logger.warning( + f"get_latest_hash unsuccessful!: {contract_api_msg}" + ) + return None + latest_ipfs_hash = cast(str, contract_api_msg.state.body["data"]) + self.context.logger.debug(f"Latest IPFS hash: {latest_ipfs_hash}") + if latest_ipfs_hash == ZERO_IPFS_HASH: + return {} + # format the hash + ipfs_hash = str(CID.from_string(latest_ipfs_hash)) + usage_data = yield from self.get_from_ipfs( + ipfs_hash, filetype=SupportedFiletype.JSON + ) + if usage_data is None: + self.context.logger.warning( + f"Could not get usage data from IPFS: {latest_ipfs_hash}" + ) + return None + return cast(Dict[str, Any], usage_data) + + def _update_current_delivery_report( + self, + current_usage: Dict[str, Any], + done_tasks: List[Dict[str, Any]], + ) -> Dict[str, Any]: + """Update the usage of the tool on IPFS.""" + for task in done_tasks: + agent, tool = task["task_executor_address"], task["tool"] + if agent not in current_usage: + current_usage[agent] = {} + if tool not in current_usage[agent]: + current_usage[agent][tool] = 0 + current_usage[agent][tool] += 1 + return current_usage + + def get_delivery_report(self) -> Generator[None, None, Optional[Dict[str, Any]]]: + """ + Get the task delivery report. + + This method returns a dictionary of the form: + { + "agent_address": { + "tool_name": num_delivered_tasks + } + } + + Note that the report contains the tasks that are being delivered on-chain in the current period. + + :return: the delivery report: + :yield: None + """ + current_usage = yield from self._get_current_delivery_report() + if current_usage is None: + # something went wrong + self.context.logger.warning("Could not get current usage.") + return None + + done_tasks = self.synchronized_data.done_tasks + updated_usage = self._update_current_delivery_report(current_usage, done_tasks) + return updated_usage + + +class FundsSplittingBehaviour(DeliverBehaviour, ABC): + """FundsSplittingBehaviour""" + + def _get_num_requests_delivered(self) -> Generator[None, None, Optional[int]]: + """Return the total number of requests delivered.""" + reqs_by_agent = yield from self._get_num_reqs_by_agent() + if reqs_by_agent is None: + self.context.logger.warning( + "Could not get number of requests delivered. Don't split profits." + ) + return None + + total_reqs = sum(reqs_by_agent.values()) + return total_reqs + + def _get_num_reqs_by_agent(self) -> Generator[None, None, Optional[Dict[str, int]]]: + """Return the total number of requests delivered.""" + delivery_report = yield from self.get_delivery_report() + if delivery_report is None: + self.context.logger.warning( + "Could not get delivery report. Don't split profits." + ) + return None + + # accumulate the number of requests delivered by each agent + reqs_by_agent = {} + for agent, tool_usage in delivery_report.items(): + reqs_by_agent[agent] = sum(tool_usage.values()) + + return reqs_by_agent + + def _should_split_profits(self) -> Generator[None, None, bool]: + """ + Returns true if profits from the mech should be split. + + Profits will be split based on the number of requests that have been delivered. + I.e. We will be splitting every n-th request. Where, n- is configurable + + :returns: True if profits should be split, False otherwise. + :yields: None + """ + total_reqs = yield from self._get_num_requests_delivered() + if total_reqs is None: + self.context.logger.warning( + "Could not get number of requests delivered. Don't split profits." + ) + return False + return total_reqs % self.params.profit_split_freq == 0 + + def get_split_profit_txs( + self, + ) -> Generator[None, None, Optional[List[Dict[str, Any]]]]: + """Get and split all the profits from all the mechs.""" + should_split_profits = yield from self._should_split_profits() + if not should_split_profits: + self.context.logger.info("Not splitting profits.") + return [] + + self.context.logger.info(f"Splitting profits {self.mech_addresses}.") + txs = [] + for mech_address in self.mech_addresses: + profits = yield from self._get_profits(mech_address) + if profits is None: + self.context.logger.error( + f"Could not get profits from mech {mech_address}. Don't split profits." + ) + return None + + self.context.logger.info(f"Got {profits} profits from mech {mech_address}") + split_funds = yield from self._split_funds(profits) + if split_funds is None: + self.context.logger.error( + f"Could not split profits from mech {mech_address}. Don't split profits." + ) + return None + + self.context.logger.info( + f"Split {profits} profits from mech {mech_address} into {split_funds}" + ) + for receiver_address, amount in split_funds.items(): + tx = yield from self._get_transfer_tx( + mech_address, receiver_address, amount + ) + if tx is None: + self.context.logger.error( + f"Could not get transfer tx from mech {mech_address} to {receiver_address}. " + f"Don't split profits." + ) + return None + txs.append(tx) + + return txs + + def _get_profits(self, address: str) -> Generator[None, None, int]: + """Get the profits.""" + ledger_api_response = yield from self.get_ledger_api_response( + performative=LedgerApiMessage.Performative.GET_STATE, # type: ignore + ledger_callable="get_balance", + account=address, + ) + if ledger_api_response.performative != LedgerApiMessage.Performative.STATE: + return False # transition to await top-up round + balance = cast(int, ledger_api_response.state.body.get("get_balance_result")) + return balance + + def _split_funds( + self, profits: int + ) -> Generator[None, None, Optional[Dict[str, int]]]: + """ + Split the funds among the operators based on the number of txs their agents have made. + + :param profits: the amount of funds to split. + :returns: a dictionary mapping operator addresses to the amount of funds they should receive. + :yields: None + """ + on_chain_id = cast(int, self.params.on_chain_service_id) + service_owner = yield from self._get_service_owner(on_chain_id) + if service_owner is None: + self.context.logger.warning( + "Could not get service owner. Don't split profits." + ) + return None + + funds_by_address = {} + service_owner_share = int(self.params.service_owner_share * profits) + funds_by_address[service_owner] = service_owner_share + + operator_share = profits - service_owner_share + funds_by_operator = yield from self._get_funds_by_operator(operator_share) + if funds_by_operator is None: + self.context.logger.warning( + "Could not get funds by operator. Don't split profits." + ) + return None + + # accumulate the funds + funds_by_address.update(funds_by_operator) + return funds_by_address + + def _get_transfer_tx( + self, mech_address: str, receiver_address: str, amount: int + ) -> Generator[None, None, Optional[Dict[str, Any]]]: + """Get the transfer tx.""" + contract_api_msg = yield from self.get_contract_api_response( + performative=ContractApiMessage.Performative.GET_STATE, # type: ignore + contract_address=mech_address, + contract_id=str(AgentMechContract.contract_id), + contract_callable="get_exec_tx_data", + to=receiver_address, + value=amount, + data=NO_DATA, + tx_gas=AUTO_GAS, + operation=MechOperation.CALL.value, + ) + if ( + contract_api_msg.performative != ContractApiMessage.Performative.STATE + ): # pragma: nocover + self.context.logger.warning( + f"get_exec_tx_data unsuccessful!: {contract_api_msg}" + ) + return None + + data = cast(bytes, contract_api_msg.state.body["data"]) + return { + "to": mech_address, + # the safe is not moving any funds, the mech contract is + "value": ZERO_ETHER_VALUE, + "data": data, + } + + def _get_service_owner( + self, service_id: int + ) -> Generator[None, None, Optional[str]]: + """Get the service owner address.""" + contract_api_msg = yield from self.get_contract_api_response( + performative=ContractApiMessage.Performative.GET_STATE, # type: ignore + contract_address=self.params.service_registry_address, + contract_id=str(ServiceRegistryContract.contract_id), + contract_callable="get_service_owner", + service_id=service_id, + ) + if contract_api_msg.performative != ContractApiMessage.Performative.STATE: + self.context.logger.warning( + f"get_service_owner unsuccessful!: {contract_api_msg}" + ) + return None + return cast(str, contract_api_msg.state.body["service_owner"]) + + def _get_funds_by_operator( + self, operator_share: int + ) -> Generator[None, None, Optional[Dict[str, int]]]: + """Split the funds among the operators based on the number of txs their agents have made.""" + reqs_by_agent = yield from self._get_num_reqs_by_agent() + if reqs_by_agent is None: + self.context.logger.warning( + "Could not get number of requests delivered. Don't split profits." + ) + return None + + total_reqs = sum(reqs_by_agent.values()) + if total_reqs == 0: + # nothing to split + return {agent: 0 for agent in reqs_by_agent.keys()} + + accumulated_reqs_by_operator = yield from self._accumulate_reqs_by_operator( + reqs_by_agent + ) + if accumulated_reqs_by_operator is None: + self.context.logger.warning( + "Could not get number of requests delivered. Don't split profits." + ) + return None + + for agent, reqs in accumulated_reqs_by_operator.items(): + accumulated_reqs_by_operator[agent] = int( + operator_share * (reqs / total_reqs) + ) + + return accumulated_reqs_by_operator + + def _accumulate_reqs_by_operator( + self, reqs_by_agent: Dict[str, int] + ) -> Generator[None, None, Optional[Dict[str, int]]]: + """Accumulate requests by operator.""" + agent_instances = list(reqs_by_agent.keys()) + contract_api_msg = yield from self.get_contract_api_response( + performative=ContractApiMessage.Performative.GET_STATE, # type: ignore + contract_address=self.params.agent_registry_address, + contract_id=str(ServiceRegistryContract.contract_id), + contract_callable="get_operators_mapping", + agent_instances=agent_instances, + ) + if ( + contract_api_msg.performative != ContractApiMessage.Performative.STATE + ): # pragma: nocover + self.context.logger.warning( + f"get_operators_mapping unsuccessful!: {contract_api_msg}" + ) + return None + agent_to_operator = cast(Dict[str, str], contract_api_msg.state.body) + + # accumulate reqs by operator + reqs_by_operator = {} + for agent, reqs in reqs_by_agent.items(): + operator = agent_to_operator[agent] + if operator not in reqs_by_operator: + reqs_by_operator[operator] = reqs + else: + reqs_by_operator[operator] += reqs + return reqs_by_operator + + +class TrackingBehaviour(DeliverBehaviour, ABC): + """Behaviour to track the execution of a task.""" + + def _get_checkpoint_tx( + self, + hashcheckpoint_address: str, + ipfs_hash: str, + ) -> Generator[None, None, Optional[Dict[str, Any]]]: + """Get the transfer tx.""" + contract_api_msg = yield from self.get_contract_api_response( + performative=ContractApiMessage.Performative.GET_STATE, # type: ignore + contract_address=hashcheckpoint_address, + contract_id=str(HashCheckpointContract.contract_id), + contract_callable="get_checkpoint_data", + data=bytes.fromhex(ipfs_hash), + ) + if ( + contract_api_msg.performative != ContractApiMessage.Performative.STATE + ): # pragma: nocover + self.context.logger.warning( + f"get_checkpoint_data unsuccessful!: {contract_api_msg}" + ) + return None + + data = cast(bytes, contract_api_msg.state.body["data"]) + return { + "to": hashcheckpoint_address, + "value": ZERO_ETHER_VALUE, + "data": data, + } + + def _save_usage_to_ipfs( + self, current_usage: Dict[str, Any] + ) -> Generator[None, None, Optional[str]]: + """Save usage to ipfs.""" + ipfs_hash = yield from self.send_to_ipfs( + FILENAME, current_usage, filetype=SupportedFiletype.JSON + ) + if ipfs_hash is None: + self.context.logger.warning("Could not update usage.") + return None + return ipfs_hash + + def get_update_usage_tx(self) -> Generator: + """Get a tx to update the usage.""" + updated_usage = yield from self.get_delivery_report() + if updated_usage is None: + # something went wrong + self.context.logger.warning("Could not get current usage.") + return None + + ipfs_hash = yield from self._save_usage_to_ipfs(updated_usage) + if ipfs_hash is None: + # something went wrong + self.context.logger.warning("Could not save usage to IPFS.") + return None + + self.context.logger.info(f"Saved updated usage to IPFS: {ipfs_hash}") + ipfs_hash = self.to_multihash(to_v1(ipfs_hash)) + tx = yield from self._get_checkpoint_tx( + self.params.hash_checkpoint_address, ipfs_hash + ) + return tx + + +class HashUpdateBehaviour(TaskExecutionBaseBehaviour, ABC): + """HashUpdateBehaviour""" + + def _get_latest_hash(self) -> Generator[None, None, Optional[bytes]]: + """Get latest update hash.""" + contract_api_msg = yield from self.get_contract_api_response( + performative=ContractApiMessage.Performative.GET_STATE, # type: ignore + contract_address=self.params.agent_registry_address, + contract_id=str(AgentRegistryContract.contract_id), + contract_callable="get_token_hash", + token_id=self.params.agent_id, + ) + if ( + contract_api_msg.performative != ContractApiMessage.Performative.STATE + ): # pragma: nocover + self.context.logger.warning( + f"get_token_hash unsuccessful!: {contract_api_msg}" + ) + return None + + latest_hash = cast(bytes, contract_api_msg.state.body["data"]) + return latest_hash + + def _should_update_hash(self) -> Generator: + """Check if the agent should update the hash.""" + if self.params.task_mutable_params.latest_metadata_hash is None: + latest_hash = yield from self._get_latest_hash() + if latest_hash is None: + self.context.logger.warning( + "Could not get latest hash. Don't update the metadata." + ) + return False + self.params.task_mutable_params.latest_metadata_hash = latest_hash + + configured_hash = self.to_multihash(self.params.metadata_hash) + latest_hash = self.params.task_mutable_params.latest_metadata_hash + return configured_hash != latest_hash + + def get_mech_update_hash_tx(self) -> Generator: + """Get the mech update hash tx.""" + should_update_hash = yield from self._should_update_hash() + if not should_update_hash: + return None + + metadata_str = self.to_multihash(self.params.metadata_hash) + metadata = bytes.fromhex(metadata_str) + contract_api_msg = yield from self.get_contract_api_response( + performative=ContractApiMessage.Performative.GET_STATE, # type: ignore + contract_address=self.params.agent_registry_address, + contract_id=str(AgentRegistryContract.contract_id), + contract_callable="get_update_hash_tx_data", + token_id=self.params.agent_id, + metadata_hash=metadata, + ) + if ( + contract_api_msg.performative != ContractApiMessage.Performative.STATE + ): # pragma: nocover + self.context.logger.warning( + f"get_mech_update_hash unsuccessful!: {contract_api_msg}" + ) + return None + + data = cast(bytes, contract_api_msg.state.body["data"]) + return { + "to": self.params.agent_registry_address, + "value": ZERO_ETHER_VALUE, + "data": data, + } + + +class TransactionPreparationBehaviour( + FundsSplittingBehaviour, HashUpdateBehaviour, TrackingBehaviour +): """TransactionPreparationBehaviour""" matching_round: Type[AbstractRound] = TransactionPreparationRound @@ -185,24 +680,38 @@ def async_act(self) -> Generator: # pylint: disable=R0914,R0915 def get_payload_content(self) -> Generator[None, None, str]: """Prepare the transaction""" all_txs = [] - should_update_hash = yield from self._should_update_hash() - if should_update_hash: - update_hash_tx = yield from self._get_mech_update_hash_tx() - if update_hash_tx is None: - # something went wrong, respond with ERROR payload for now - return TransactionPreparationRound.ERROR_PAYLOAD + update_hash_tx = yield from self.get_mech_update_hash_tx() + if update_hash_tx is not None: + # in case of None, the agent should not update the hash + # if this is caused by an error, the agent should still proceed with the rest + # of the txs. The error will be logged. all_txs.append(update_hash_tx) + split_profit_txs = yield from self.get_split_profit_txs() + if split_profit_txs is not None: + # in case of None, the agent should not update the hash + # if this is caused by an error, the agent should still proceed with the rest + # of the txs. The error will be logged. + all_txs.extend(split_profit_txs) + for task in self.synchronized_data.done_tasks: deliver_tx = yield from self._get_deliver_tx(task) if deliver_tx is None: # something went wrong, respond with ERROR payload for now + # nothing should proceed if this happens return TransactionPreparationRound.ERROR_PAYLOAD all_txs.append(deliver_tx) response_tx = task.get("transaction", None) if response_tx is not None: all_txs.append(response_tx) + update_usage_tx = yield from self.get_update_usage_tx() + if update_usage_tx is None: + # something went wrong, respond with ERROR payload for now + # in case we cannot update the usage, we should not proceed with the rest of the txs + return TransactionPreparationRound.ERROR_PAYLOAD + + all_txs.append(update_usage_tx) multisend_tx_str = yield from self._to_multisend(all_txs) if multisend_tx_str is None: # something went wrong, respond with ERROR payload for now @@ -319,79 +828,6 @@ def _get_deliver_tx( "data": data, } - def _get_latest_hash(self) -> Generator[None, None, Optional[bytes]]: - """Get latest update hash.""" - contract_api_msg = yield from self.get_contract_api_response( - performative=ContractApiMessage.Performative.GET_STATE, # type: ignore - contract_address=self.params.agent_registry_address, - contract_id=str(AgentRegistryContract.contract_id), - contract_callable="get_token_hash", - token_id=self.params.agent_id, - ) - if ( - contract_api_msg.performative != ContractApiMessage.Performative.STATE - ): # pragma: nocover - self.context.logger.warning( - f"get_token_hash unsuccessful!: {contract_api_msg}" - ) - return None - - latest_hash = cast(bytes, contract_api_msg.state.body["data"]) - return latest_hash - - def _should_update_hash(self) -> Generator: - """Check if the agent should update the hash.""" - if self.params.task_mutable_params.latest_metadata_hash is None: - latest_hash = yield from self._get_latest_hash() - if latest_hash is None: - self.context.logger.warning( - "Could not get latest hash. Don't update the metadata." - ) - return False - self.params.task_mutable_params.latest_metadata_hash = latest_hash - - configured_hash = self.to_multihash(self.params.metadata_hash) - latest_hash = self.params.task_mutable_params.latest_metadata_hash - return configured_hash != latest_hash - - @staticmethod - def to_multihash(hash_string: str) -> str: - """To multihash string.""" - # Decode the Base32 CID to bytes - cid_bytes = multibase.decode(hash_string) - # Remove the multicodec prefix (0x01) from the bytes - multihash_bytes = multicodec.remove_prefix(cid_bytes) - # Convert the multihash bytes to a hexadecimal string - hex_multihash = multihash_bytes.hex() - return hex_multihash[6:] - - def _get_mech_update_hash_tx(self) -> Generator: - """Get the mech update hash tx.""" - metadata_str = self.to_multihash(self.params.metadata_hash) - metadata = bytes.fromhex(metadata_str) - contract_api_msg = yield from self.get_contract_api_response( - performative=ContractApiMessage.Performative.GET_STATE, # type: ignore - contract_address=self.params.agent_registry_address, - contract_id=str(AgentRegistryContract.contract_id), - contract_callable="get_update_hash_tx_data", - token_id=self.params.agent_id, - metadata_hash=metadata, - ) - if ( - contract_api_msg.performative != ContractApiMessage.Performative.STATE - ): # pragma: nocover - self.context.logger.warning( - f"get_mech_update_hash unsuccessful!: {contract_api_msg}" - ) - return None - - data = cast(bytes, contract_api_msg.state.body["data"]) - return { - "to": self.params.agent_registry_address, - "value": ZERO_ETHER_VALUE, - "data": data, - } - class TaskSubmissionRoundBehaviour(AbstractRoundBehaviour): """TaskSubmissionRoundBehaviour""" diff --git a/packages/valory/skills/task_submission_abci/models.py b/packages/valory/skills/task_submission_abci/models.py index aa79b666..6942b2c5 100644 --- a/packages/valory/skills/task_submission_abci/models.py +++ b/packages/valory/skills/task_submission_abci/models.py @@ -65,6 +65,14 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.metadata_hash: str = self._ensure("metadata_hash", kwargs, str) self.task_mutable_params = MutableParams() self.manual_gas_limit = self._ensure("manual_gas_limit", kwargs, int) + self.service_owner_share = self._ensure("service_owner_share", kwargs, float) + self.profit_split_freq = self._ensure("profit_split_freq", kwargs, int) + self.agent_mech_contract_addresses = self._ensure( + "agent_mech_contract_addresses", kwargs, list + ) + self.hash_checkpoint_address = self._ensure( + "hash_checkpoint_address", kwargs, str + ) super().__init__(*args, **kwargs) diff --git a/packages/valory/skills/task_submission_abci/skill.yaml b/packages/valory/skills/task_submission_abci/skill.yaml index b8e65e40..7a2e75e6 100644 --- a/packages/valory/skills/task_submission_abci/skill.yaml +++ b/packages/valory/skills/task_submission_abci/skill.yaml @@ -8,24 +8,27 @@ license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: __init__.py: bafybeiholqak7ltw6bbmn2c5tn3j7xgzkdlfzp3kcskiqsvmxoih6m4muq - behaviours.py: bafybeihcxwfsxa5hxftpqnm5ujtckk5ulsqdbtfavzblt3ae3qcbxg2o5e + behaviours.py: bafybeihpzxlxflvzfafffxdokxvx5qjr7bnkcqwaqmq76p67b7dsryypcu dialogues.py: bafybeibmac3m5u5h6ucoyjr4dazay72dyga656wvjl6z6saapluvjo54ne fsm_specification.yaml: bafybeig6bhn554qyou7kef5bstnlv54zke32avyti63uu4hvsol3lzqkoi handlers.py: bafybeibe5n7my2vd2wlwo73sbma65epjqc7kxgtittewlylcmvnmoxtxzq - models.py: bafybeiantvyh3lznvrwiaim5h3ot4lnoi4sxvdej2rifum43c67l3nkl4i + models.py: bafybeibil7zmdpa3daz4wdhx2ekvspawtqswt56elj4hrvtiwykc6td6de payloads.py: bafybeia2yorri2u5rwh6vukb6iwdrbn53ygsuuhthns2txptvjipyb6f4e rounds.py: bafybeicstmau4vlzpxz3kjgiwwsetwmotdk4un4iucmdddzvot5dgdkg2a tasks.py: bafybeicu5t5cvfhbndgpxbbtmp4vbmtyb6fba6vsnlewftvuderxp5lwcy fingerprint_ignore_patterns: [] connections: [] contracts: -- valory/agent_mech:0.1.0:bafybeicshvlc2slopzidzblf2zhdcw2uuav3ntxcgqduxskjujvebikg5u +- valory/agent_mech:0.1.0:bafybeidyfhwye3ybk3vxrceljafe2n4o43oxtmjepvexpcrwlccboi34e4 - valory/agent_registry:0.1.0:bafybeiargayav6yiztdnwzejoejstcx4idssch2h4f5arlgtzj3tgsgfmu - valory/gnosis_safe:0.1.0:bafybeie7qpo4sue4i54pzsg6nx365q6d3i4sl6ygdilwldqqxwroukbkiu - valory/multisend:0.1.0:bafybeig5byt5urg2d2bsecufxe5ql7f4mezg3mekfleeh32nmuusx66p4y +- valory/service_registry:0.1.0:bafybeib6eed4u2dqggq7jpnb4lury6ylqzdxp6oxxvgrouhcvtmwsbsjbq +- valory/hash_checkpoint:0.1.0:bafybeiap5fvi2w53e4uwxt75gjzie557hwuegf76xupimx3dvpkgfmj4ei protocols: - valory/acn_data_share:0.1.0:bafybeih5ydonnvrwvy2ygfqgfabkr47s4yw3uqxztmwyfprulwfsoe7ipq - valory/contract_api:1.0.0:bafybeialhbjvwiwcnqq3ysxcyemobcbie7xza66gaofcvla5njezkvhcka +- valory/ledger_api:1.0.0:bafybeige5agrztgzfevyglf7mb4o7pzfttmq4f6zi765y4g2zvftbyowru skills: - valory/abstract_round_abci:0.1.0:bafybeifcq2nwd6m5tgxooe7436bc6lwo73xcreedmhcwauzhp5jic6jeq4 - valory/transaction_settlement_abci:0.1.0:bafybeifqase6vqfrakahogdl4h2hpxntug5ckioicfqlw2og5tn6htru3q @@ -80,6 +83,8 @@ models: class_name: LedgerApiDialogues params: args: + agent_mech_contract_addresses: + - '0xFf82123dFB52ab75C417195c5fDB87630145ae81' cleanup_history_depth_current: null drand_public_key: 868f005eb8e6e4ca0a47c8a77ceaa5309a47978a7c71bc5cce96366b5d7a569937c529eeda66c7293784a9402801af31 finalize_timeout: 60.0 @@ -110,6 +115,7 @@ models: keeper_timeout: 30.0 max_attempts: 10 max_healthcheck: 120 + hash_checkpoint_address: '0x0000000000000000000000000000000000000000' on_chain_service_id: null request_retry_delay: 1.0 request_timeout: 10.0 @@ -138,6 +144,8 @@ models: manual_gas_limit: 1000000 validate_timeout: 1205 use_slashing: false + service_owner_share: 0.1 + profit_split_freq: 1000 slash_cooldown_hours: 3 slash_threshold_amount: 10000000000000000 light_slash_unit_amount: 5000000000000000