diff --git a/packages/valory/contracts/mech_marketplace/README.md b/packages/valory/contracts/mech_marketplace/README.md new file mode 100644 index 000000000..22522064e --- /dev/null +++ b/packages/valory/contracts/mech_marketplace/README.md @@ -0,0 +1 @@ +# Agent Mech Marketplace Contract diff --git a/packages/valory/contracts/mech_marketplace/__init__.py b/packages/valory/contracts/mech_marketplace/__init__.py new file mode 100644 index 000000000..bb07482ea --- /dev/null +++ b/packages/valory/contracts/mech_marketplace/__init__.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2024 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 an agent MechMarketplace.""" diff --git a/packages/valory/contracts/mech_marketplace/build/mech.json b/packages/valory/contracts/mech_marketplace/build/mech.json new file mode 100644 index 000000000..dae53c607 --- /dev/null +++ b/packages/valory/contracts/mech_marketplace/build/mech.json @@ -0,0 +1,837 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "AgentMech", + "sourceName": "contracts/AgentMech.sol", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_stakingFactory", + "type": "address" + }, + { + "internalType": "address", + "name": "_karmaProxy", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_minResponseTimeout", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_maxResponseTimeout", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + } + ], + "name": "AlreadyDelivered", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "provided", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "min", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "max", + "type": "uint256" + } + ], + "name": "OutOfBounds", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "provided", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "max", + "type": "uint256" + } + ], + "name": "Overflow", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "OwnerOnly", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "expected", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "current", + "type": "uint256" + } + ], + "name": "PriorityMechResponseTimeout", + "type": "error" + }, + { + "inputs": [], + "name": "ReentrancyGuard", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingInstance", + "type": "address" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "ServiceNotStaked", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "UnauthorizedAccount", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddress", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroValue", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "factory", + "type": "address" + } + ], + "name": "FactoryUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "priorityMech", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "actualMech", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "MarketplaceDeliver", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "requestedMech", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "MarketplaceRequest", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "mech", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "status", + "type": "bool" + } + ], + "name": "MechRegistrationStatusChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "minResponseTimeout", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "maxResponseTimeout", + "type": "uint256" + } + ], + "name": "MinMaxResponseTimeoutUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "OwnerUpdated", + "type": "event" + }, + { + "inputs": [], + "name": "DOMAIN_SEPARATOR_TYPE_HASH", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "VERSION", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "chainId", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "mech", + "type": "address" + }, + { + "internalType": "address", + "name": "mechStakingInstance", + "type": "address" + }, + { + "internalType": "uint256", + "name": "mechServiceId", + "type": "uint256" + } + ], + "name": "checkMech", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "internalType": "address", + "name": "requesterStakingInstance", + "type": "address" + }, + { + "internalType": "uint256", + "name": "requesterServiceId", + "type": "uint256" + } + ], + "name": "checkRequester", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "stakingInstance", + "type": "address" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "checkStakingInstance", + "outputs": [], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "requestData", + "type": "bytes" + }, + { + "internalType": "address", + "name": "deliveryMechStakingInstance", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deliveryMechServiceId", + "type": "uint256" + } + ], + "name": "deliverMarketplace", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "domainSeparator", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getDeliveriesCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getDomainSeparator", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + } + ], + "name": "getMechDeliveryInfo", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "priorityMech", + "type": "address" + }, + { + "internalType": "address", + "name": "deliveryMech", + "type": "address" + }, + { + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "internalType": "uint32", + "name": "responseTimeout", + "type": "uint32" + } + ], + "internalType": "struct MechDelivery", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "mechService", + "type": "address" + } + ], + "name": "getMechServiceDeliveriesCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + } + ], + "name": "getRequestId", + "outputs": [ + { + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + } + ], + "name": "getRequestStatus", + "outputs": [ + { + "internalType": "enum MechMarketplace.RequestStatus", + "name": "status", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "getRequestsCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "karmaProxy", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "mapDeliveryCounts", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "mapMechServiceDeliveryCounts", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "mapNonces", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "mapRequestCounts", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "mapRequestIdDeliveries", + "outputs": [ + { + "internalType": "address", + "name": "priorityMech", + "type": "address" + }, + { + "internalType": "address", + "name": "deliveryMech", + "type": "address" + }, + { + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "internalType": "uint32", + "name": "responseTimeout", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maxResponseTimeout", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "minResponseTimeout", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "numTotalRequests", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "numUndeliveredRequests", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "internalType": "address", + "name": "priorityMech", + "type": "address" + }, + { + "internalType": "address", + "name": "priorityMechStakingInstance", + "type": "address" + }, + { + "internalType": "uint256", + "name": "priorityMechServiceId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "requesterStakingInstance", + "type": "address" + }, + { + "internalType": "uint256", + "name": "requesterServiceId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "responseTimeout", + "type": "uint256" + } + ], + "name": "request", + "outputs": [ + { + "internalType": "uint256", + "name": "requestId", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "stakingFactory", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "bytecode": "0x60806040525f805534801562000013575f80fd5b50604051620026cc380380620026cc833981016040819052620000369162000391565b604080516001600160a01b03851660208201528082018490528151808203830181526060909101909152839083906200006f8162000145565b5050506001600160a01b0383166200009a5760405163d92e233d60e01b815260040160405180910390fd5b6040516331a9108f60e11b8152600481018390525f906001600160a01b03851690636352211e90602401602060405180830381865afa158015620000e0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190620001069190620003c6565b90506001600160a01b0381166200013857604051630ede975960e01b8152600481018490526024015b60405180910390fd5b50600155506200049a9050565b6200014f620001ad565b51156200019f5760405162461bcd60e51b815260206004820152601360248201527f416c726561647920696e697469616c697a65640000000000000000000000000060448201526064016200012f565b620001aa8162000218565b50565b6060620002136200020d604051606b60f91b6020820152602560fa1b60218201526001600160601b03193060601b166022820152600160f81b60368201525f90603701604051602081830303815290604052805190602001205f1c905090565b620002e1565b905090565b5f620002248262000339565b90505f8151602083015ff090506200028b604051606b60f91b6020820152602560fa1b60218201526001600160601b03193060601b166022820152600160f81b60368201525f90603701604051602081830303815290604052805190602001205f1c905090565b6001600160a01b0316816001600160a01b031614620002dc5760405162461bcd60e51b815260206004820152600c60248201526b15dc9a5d194819985a5b195960a21b60448201526064016200012f565b505050565b6060813b600181116200030357505060408051602081019091525f8152919050565b806200030f81620003fd565b9150506040519150601f19601f602083010116820160405280825280600160208401853c50919050565b6060815160016200034b919062000415565b826040516020016200035f92919062000431565b6040516020818303038152906040529050919050565b80516001600160a01b03811681146200038c575f80fd5b919050565b5f805f60608486031215620003a4575f80fd5b620003af8462000375565b925060208401519150604084015190509250925092565b5f60208284031215620003d7575f80fd5b620003e28262000375565b9392505050565b634e487b7160e01b5f52601160045260245ffd5b5f816200040e576200040e620003e9565b505f190190565b808201808211156200042b576200042b620003e9565b92915050565b606360f81b815260e083901b6001600160e01b03191660018201526880600e6000396000f360b81b60058201525f600e82018190528251815b8181101562000489576020818601810151600f8684010152016200046a565b505f9201600f019182525092915050565b61222480620004a85f395ff3fe60806040526004361061017a575f3560e01c8063a035b1fe116100d1578063bdf863171161007c578063f23a6e6111610057578063f23a6e61146104d2578063f6171e4414610517578063fc0c546a14610536575f80fd5b8063bdf8631714610472578063c7dec3fc14610487578063e00b9118146104b3575f80fd5b8063b0d691fe116100ac578063b0d691fe146103d1578063b94207d314610418578063bc197c811461042b575f80fd5b8063a035b1fe1461038a578063a4f9edbf1461039f578063affed0e0146103be575f80fd5b80633a871cdd116101315780636d70f7ae1161010c5780636d70f7ae146102fb5780637af734731461032a57806391b7f5ed1461036b575f80fd5b80633a871cdd1461028557806358ce0909146102a45780635fee6085146102d0575f80fd5b8063157305fe11610161578063157305fe146102255780631626ba7e1461024457806317d70f7c14610263575f80fd5b806223de2914610185578063150b7a02146101ab575f80fd5b3661018157005b5f80fd5b348015610190575f80fd5b506101a961019f366004611943565b5050505050505050565b005b3480156101b6575f80fd5b506101ef6101c53660046119ed565b7f150b7a020000000000000000000000000000000000000000000000000000000095945050505050565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020015b60405180910390f35b348015610230575f80fd5b506101a961023f366004611b2f565b61054a565b34801561024f575f80fd5b506101ef61025e366004611b2f565b610771565b34801561026e575f80fd5b50610277610914565b60405190815260200161021c565b348015610290575f80fd5b5061027761029f366004611b73565b610938565b3480156102af575f80fd5b506102c36102be366004611bc2565b610974565b60405161021c9190611be2565b3480156102db575f80fd5b506102776102ea366004611c25565b60036020525f908152604090205481565b348015610306575f80fd5b5061031a610315366004611c25565b610ada565b604051901515815260200161021c565b348015610335575f80fd5b50610277610344366004611c25565b73ffffffffffffffffffffffffffffffffffffffff165f9081526003602052604090205490565b348015610376575f80fd5b506101a9610385366004611c40565b610bac565b348015610395575f80fd5b5061027760015481565b3480156103aa575f80fd5b506101a96103b9366004611c57565b610c9a565b3480156103c9575f80fd5b505f54610277565b3480156103dc575f80fd5b50730576a174d229e3cfa37253523e645a78a0c91b575b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161021c565b610277610426366004611c57565b610d16565b348015610436575f80fd5b506101ef610445366004611cd2565b7fbc197c810000000000000000000000000000000000000000000000000000000098975050505050505050565b34801561047d575f80fd5b5061027760025481565b348015610492575f80fd5b506104a66104a1366004611d68565b610e63565b60405161021c9190611e45565b3480156104be575f80fd5b506102776104cd366004611e57565b610f4d565b3480156104dd575f80fd5b506101ef6104ec366004611e8e565b7ff23a6e61000000000000000000000000000000000000000000000000000000009695505050505050565b348015610522575f80fd5b50610277610531366004611bc2565b610f9e565b348015610541575f80fd5b506103f3610fc0565b61055333610ada565b80610571575033730576a174d229e3cfa37253523e645a78a0c91b57145b610602576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603e60248201527f4f6e6c792063616c6c61626c6520627920746865206d656368206f706572617460448201527f6f72206f722074686520656e74727920706f696e7420636f6e7472616374000060648201526084015b60405180910390fd5b5f828152600460205260408082208151808301928390529160029082845b8154815260200190600101908083116106205750505050509050805f6002811061064c5761064c611f05565b602002015115801561066057506020810151155b801561069557505f805260046020527f17ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ed548314155b156106cf576040517ffe239804000000000000000000000000000000000000000000000000000000008152600481018490526024016105f9565b6020818101805183515f908152600490935260408084206001908101929092558451925184528084209290925585835290822082815501819055600280549161071783611f5f565b91905055503373ffffffffffffffffffffffffffffffffffffffff167f0cd979445339c62199996f208428d987b1cea24d18e62b79ec24d94b636e8b708484604051610764929190611f93565b60405180910390a2505050565b5f805f8061079185602081015160408201516060909201515f1a92909190565b9094509250905060ff81165f036108a757828583016020016107b282610ada565b1580156107d5575073ffffffffffffffffffffffffffffffffffffffff82163014155b1561080857507fffffffff00000000000000000000000000000000000000000000000000000000945061090e9350505050565b6040517f1626ba7e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff831690631626ba7e9061085c908b908590600401611f93565b602060405180830381865afa158015610877573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061089b9190611fab565b9550505050505061090e565b6108b661031587838686610fdd565b156108e757507f1626ba7e00000000000000000000000000000000000000000000000000000000925061090e915050565b507fffffffff00000000000000000000000000000000000000000000000000000000925050505b92915050565b5f8061091e610ff9565b8060200190518101906109319190611fea565b9392505050565b5f6109416110cd565b61094b848461114c565b905061095a6040850185612016565b90505f0361096b5761096b8461124c565b610931826112ca565b6002546060905f849003610986578093505b806109918486612077565b11156109de576109a18385612077565b6040517f7ae596850000000000000000000000000000000000000000000000000000000081526004810191909152602481018290526044016105f9565b8315610ad3578367ffffffffffffffff8111156109fd576109fd611a5b565b604051908082528060200260200182016040528015610a26578160200160208202803683370190505b505f80805260046020527f17ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ed549193505b84811015610a81575f828152600460205260409020600101549150610a7a8161208a565b9050610a56565b505f5b85811015610ad05781848281518110610a9f57610a9f611f05565b6020908102919091018101919091525f9283526004905260409091206001015490610ac98161208a565b9050610a84565b50505b5092915050565b5f805f610ae5610ff9565b806020019051810190610af89190611fea565b915091508373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16636352211e836040518263ffffffff1660e01b8152600401610b4e91815260200190565b602060405180830381865afa158015610b69573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b8d91906120c1565b73ffffffffffffffffffffffffffffffffffffffff1614949350505050565b610bb533610ada565b80610bd3575033730576a174d229e3cfa37253523e645a78a0c91b57145b610c5f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603e60248201527f4f6e6c792063616c6c61626c6520627920746865206d656368206f706572617460448201527f6f72206f722074686520656e74727920706f696e7420636f6e7472616374000060648201526084016105f9565b60018190556040518181527f66cbca4f3c64fecf1dcb9ce094abcf7f68c3450a1d4e3a8e917dd621edb4ebe09060200160405180910390a150565b610ca2610ff9565b5115610d0a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f416c726561647920696e697469616c697a65640000000000000000000000000060448201526064016105f9565b610d138161133e565b50565b5f600154341015610d60576001546040517fb489782800000000000000000000000000000000000000000000000000000000815234600482015260248101919091526044016105f9565b610d6a3383610f4d565b335f908152600360205260408120805492935090610d878361208a565b909155505060046020525f81815260408082207f17ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ed80546001830181905590859055808452918320849055600280547f17ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ec94929392909190610e068361208a565b91905055503373ffffffffffffffffffffffffffffffffffffffff167f4bda649efe6b98b0f9c1d5e859c29e20910f45c66dabfe6fad4a4881f7faf9cc8587604051610e53929190611f93565b60405180910390a2505050919050565b6060610e6e33610ada565b80610e8c575033730576a174d229e3cfa37253523e645a78a0c91b57145b610f18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603e60248201527f4f6e6c792063616c6c61626c6520627920746865206d656368206f706572617460448201527f6f72206f722074686520656e74727920706f696e7420636f6e7472616374000060648201526084016105f9565b5f610f32878787878715610f2c57876114b3565b5a6114b3565b9250905080610f4357815160208301fd5b5095945050505050565b5f8282604051602001610f619291906120dc565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101209392505050565b6004602052815f5260405f208160028110610fb7575f80fd5b01549150829050565b5f80610fca610ff9565b80602001905181019061090e91906120c1565b5f805f610fec878787876115b6565b91509150610f438161169e565b60606110c86110c36040517fd60000000000000000000000000000000000000000000000000000000000000060208201527f940000000000000000000000000000000000000000000000000000000000000060218201527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003060601b1660228201527f010000000000000000000000000000000000000000000000000000000000000060368201525f90603701604051602081830303815290604052805190602001205f1c905090565b611850565b905090565b33730576a174d229e3cfa37253523e645a78a0c91b571461114a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f6163636f756e743a206e6f742066726f6d20456e747279506f696e740000000060448201526064016105f9565b565b5f806111a4836040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c81018290525f90605c01604051602081830303815290604052805190602001209050919050565b90507f1626ba7e00000000000000000000000000000000000000000000000000000000611212826111d9610140880188612016565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061077192505050565b7fffffffff00000000000000000000000000000000000000000000000000000000161461124357600191505061090e565b505f9392505050565b5f80546020830135918061125f8361208a565b9190505514610d13576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c6964206e6f6e63650000000000000000000000000000000000000060448201526064016105f9565b8015610d13576040515f9033907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90849084818181858888f193505050503d805f8114611332576040519150601f19603f3d011682016040523d82523d5f602084013e611337565b606091505b5050505050565b5f611348826118a5565b90505f8151602083015ff0905061141a6040517fd60000000000000000000000000000000000000000000000000000000000000060208201527f940000000000000000000000000000000000000000000000000000000000000060218201527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003060601b1660228201527f010000000000000000000000000000000000000000000000000000000000000060368201525f90603701604051602081830303815290604052805190602001205f1c905090565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146114ae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f5772697465206661696c6564000000000000000000000000000000000000000060448201526064016105f9565b505050565b5f606060018460018111156114ca576114ca61210a565b0361153e578673ffffffffffffffffffffffffffffffffffffffff1683866040516114f59190612137565b5f604051808303818686f4925050503d805f811461152e576040519150601f19603f3d011682016040523d82523d5f602084013e611533565b606091505b5090925090506115ac565b8673ffffffffffffffffffffffffffffffffffffffff168387876040516115659190612137565b5f60405180830381858888f193505050503d805f81146115a0576040519150601f19603f3d011682016040523d82523d5f602084013e6115a5565b606091505b5090925090505b9550959350505050565b5f807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156115eb57505f90506003611695565b604080515f8082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561163c573d5f803e3d5ffd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811661168f575f60019250925050611695565b91505f90505b94509492505050565b5f8160048111156116b1576116b161210a565b036116b95750565b60018160048111156116cd576116cd61210a565b03611734576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016105f9565b60028160048111156117485761174861210a565b036117af576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016105f9565b60038160048111156117c3576117c361210a565b03610d13576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f756500000000000000000000000000000000000000000000000000000000000060648201526084016105f9565b6060813b6001811161187157505060408051602081019091525f8152919050565b8061187b81611f5f565b9150506040519150601f19601f602083010116820160405280825280600160208401853c50919050565b6060815160016118b59190612077565b826040516020016118c7929190612152565b6040516020818303038152906040529050919050565b73ffffffffffffffffffffffffffffffffffffffff81168114610d13575f80fd5b5f8083601f84011261190e575f80fd5b50813567ffffffffffffffff811115611925575f80fd5b60208301915083602082850101111561193c575f80fd5b9250929050565b5f805f805f805f8060c0898b03121561195a575f80fd5b8835611965816118dd565b97506020890135611975816118dd565b96506040890135611985816118dd565b955060608901359450608089013567ffffffffffffffff808211156119a8575f80fd5b6119b48c838d016118fe565b909650945060a08b01359150808211156119cc575f80fd5b506119d98b828c016118fe565b999c989b5096995094979396929594505050565b5f805f805f60808688031215611a01575f80fd5b8535611a0c816118dd565b94506020860135611a1c816118dd565b935060408601359250606086013567ffffffffffffffff811115611a3e575f80fd5b611a4a888289016118fe565b969995985093965092949392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f82601f830112611a97575f80fd5b813567ffffffffffffffff80821115611ab257611ab2611a5b565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715611af857611af8611a5b565b81604052838152866020858801011115611b10575f80fd5b836020870160208301375f602085830101528094505050505092915050565b5f8060408385031215611b40575f80fd5b82359150602083013567ffffffffffffffff811115611b5d575f80fd5b611b6985828601611a88565b9150509250929050565b5f805f60608486031215611b85575f80fd5b833567ffffffffffffffff811115611b9b575f80fd5b84016101608187031215611bad575f80fd5b95602085013595506040909401359392505050565b5f8060408385031215611bd3575f80fd5b50508035926020909101359150565b602080825282518282018190525f9190848201906040850190845b81811015611c1957835183529284019291840191600101611bfd565b50909695505050505050565b5f60208284031215611c35575f80fd5b8135610931816118dd565b5f60208284031215611c50575f80fd5b5035919050565b5f60208284031215611c67575f80fd5b813567ffffffffffffffff811115611c7d575f80fd5b611c8984828501611a88565b949350505050565b5f8083601f840112611ca1575f80fd5b50813567ffffffffffffffff811115611cb8575f80fd5b6020830191508360208260051b850101111561193c575f80fd5b5f805f805f805f8060a0898b031215611ce9575f80fd5b8835611cf4816118dd565b97506020890135611d04816118dd565b9650604089013567ffffffffffffffff80821115611d20575f80fd5b611d2c8c838d01611c91565b909850965060608b0135915080821115611d44575f80fd5b611d508c838d01611c91565b909650945060808b01359150808211156119cc575f80fd5b5f805f805f60a08688031215611d7c575f80fd5b8535611d87816118dd565b945060208601359350604086013567ffffffffffffffff811115611da9575f80fd5b611db588828901611a88565b935050606086013560028110611dc9575f80fd5b949793965091946080013592915050565b5f5b83811015611df4578181015183820152602001611ddc565b50505f910152565b5f8151808452611e13816020860160208601611dda565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081525f6109316020830184611dfc565b5f8060408385031215611e68575f80fd5b8235611e73816118dd565b9150602083013567ffffffffffffffff811115611b5d575f80fd5b5f805f805f8060a08789031215611ea3575f80fd5b8635611eae816118dd565b95506020870135611ebe816118dd565b94506040870135935060608701359250608087013567ffffffffffffffff811115611ee7575f80fd5b611ef389828a016118fe565b979a9699509497509295939492505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f81611f6d57611f6d611f32565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b828152604060208201525f611c896040830184611dfc565b5f60208284031215611fbb575f80fd5b81517fffffffff0000000000000000000000000000000000000000000000000000000081168114610931575f80fd5b5f8060408385031215611ffb575f80fd5b8251612006816118dd565b6020939093015192949293505050565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612049575f80fd5b83018035915067ffffffffffffffff821115612063575f80fd5b60200191503681900382131561193c575f80fd5b8082018082111561090e5761090e611f32565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036120ba576120ba611f32565b5060010190565b5f602082840312156120d1575f80fd5b8151610931816118dd565b73ffffffffffffffffffffffffffffffffffffffff83168152604060208201525f611c896040830184611dfc565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b5f8251612148818460208701611dda565b9190910192915050565b7f630000000000000000000000000000000000000000000000000000000000000081527fffffffff000000000000000000000000000000000000000000000000000000008360e01b1660018201527f80600e6000396000f3000000000000000000000000000000000000000000000060058201525f600e8201525f82516121e081600f850160208701611dda565b91909101600f01939250505056fea2646970667358221220c1913351e275e1fecd00c79cd676ed135b575df5d3a88ccc57419dc3081980a264736f6c63430008150033", + "deployedBytecode": "0x60806040526004361061017a575f3560e01c8063a035b1fe116100d1578063bdf863171161007c578063f23a6e6111610057578063f23a6e61146104d2578063f6171e4414610517578063fc0c546a14610536575f80fd5b8063bdf8631714610472578063c7dec3fc14610487578063e00b9118146104b3575f80fd5b8063b0d691fe116100ac578063b0d691fe146103d1578063b94207d314610418578063bc197c811461042b575f80fd5b8063a035b1fe1461038a578063a4f9edbf1461039f578063affed0e0146103be575f80fd5b80633a871cdd116101315780636d70f7ae1161010c5780636d70f7ae146102fb5780637af734731461032a57806391b7f5ed1461036b575f80fd5b80633a871cdd1461028557806358ce0909146102a45780635fee6085146102d0575f80fd5b8063157305fe11610161578063157305fe146102255780631626ba7e1461024457806317d70f7c14610263575f80fd5b806223de2914610185578063150b7a02146101ab575f80fd5b3661018157005b5f80fd5b348015610190575f80fd5b506101a961019f366004611943565b5050505050505050565b005b3480156101b6575f80fd5b506101ef6101c53660046119ed565b7f150b7a020000000000000000000000000000000000000000000000000000000095945050505050565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020015b60405180910390f35b348015610230575f80fd5b506101a961023f366004611b2f565b61054a565b34801561024f575f80fd5b506101ef61025e366004611b2f565b610771565b34801561026e575f80fd5b50610277610914565b60405190815260200161021c565b348015610290575f80fd5b5061027761029f366004611b73565b610938565b3480156102af575f80fd5b506102c36102be366004611bc2565b610974565b60405161021c9190611be2565b3480156102db575f80fd5b506102776102ea366004611c25565b60036020525f908152604090205481565b348015610306575f80fd5b5061031a610315366004611c25565b610ada565b604051901515815260200161021c565b348015610335575f80fd5b50610277610344366004611c25565b73ffffffffffffffffffffffffffffffffffffffff165f9081526003602052604090205490565b348015610376575f80fd5b506101a9610385366004611c40565b610bac565b348015610395575f80fd5b5061027760015481565b3480156103aa575f80fd5b506101a96103b9366004611c57565b610c9a565b3480156103c9575f80fd5b505f54610277565b3480156103dc575f80fd5b50730576a174d229e3cfa37253523e645a78a0c91b575b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161021c565b610277610426366004611c57565b610d16565b348015610436575f80fd5b506101ef610445366004611cd2565b7fbc197c810000000000000000000000000000000000000000000000000000000098975050505050505050565b34801561047d575f80fd5b5061027760025481565b348015610492575f80fd5b506104a66104a1366004611d68565b610e63565b60405161021c9190611e45565b3480156104be575f80fd5b506102776104cd366004611e57565b610f4d565b3480156104dd575f80fd5b506101ef6104ec366004611e8e565b7ff23a6e61000000000000000000000000000000000000000000000000000000009695505050505050565b348015610522575f80fd5b50610277610531366004611bc2565b610f9e565b348015610541575f80fd5b506103f3610fc0565b61055333610ada565b80610571575033730576a174d229e3cfa37253523e645a78a0c91b57145b610602576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603e60248201527f4f6e6c792063616c6c61626c6520627920746865206d656368206f706572617460448201527f6f72206f722074686520656e74727920706f696e7420636f6e7472616374000060648201526084015b60405180910390fd5b5f828152600460205260408082208151808301928390529160029082845b8154815260200190600101908083116106205750505050509050805f6002811061064c5761064c611f05565b602002015115801561066057506020810151155b801561069557505f805260046020527f17ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ed548314155b156106cf576040517ffe239804000000000000000000000000000000000000000000000000000000008152600481018490526024016105f9565b6020818101805183515f908152600490935260408084206001908101929092558451925184528084209290925585835290822082815501819055600280549161071783611f5f565b91905055503373ffffffffffffffffffffffffffffffffffffffff167f0cd979445339c62199996f208428d987b1cea24d18e62b79ec24d94b636e8b708484604051610764929190611f93565b60405180910390a2505050565b5f805f8061079185602081015160408201516060909201515f1a92909190565b9094509250905060ff81165f036108a757828583016020016107b282610ada565b1580156107d5575073ffffffffffffffffffffffffffffffffffffffff82163014155b1561080857507fffffffff00000000000000000000000000000000000000000000000000000000945061090e9350505050565b6040517f1626ba7e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff831690631626ba7e9061085c908b908590600401611f93565b602060405180830381865afa158015610877573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061089b9190611fab565b9550505050505061090e565b6108b661031587838686610fdd565b156108e757507f1626ba7e00000000000000000000000000000000000000000000000000000000925061090e915050565b507fffffffff00000000000000000000000000000000000000000000000000000000925050505b92915050565b5f8061091e610ff9565b8060200190518101906109319190611fea565b9392505050565b5f6109416110cd565b61094b848461114c565b905061095a6040850185612016565b90505f0361096b5761096b8461124c565b610931826112ca565b6002546060905f849003610986578093505b806109918486612077565b11156109de576109a18385612077565b6040517f7ae596850000000000000000000000000000000000000000000000000000000081526004810191909152602481018290526044016105f9565b8315610ad3578367ffffffffffffffff8111156109fd576109fd611a5b565b604051908082528060200260200182016040528015610a26578160200160208202803683370190505b505f80805260046020527f17ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ed549193505b84811015610a81575f828152600460205260409020600101549150610a7a8161208a565b9050610a56565b505f5b85811015610ad05781848281518110610a9f57610a9f611f05565b6020908102919091018101919091525f9283526004905260409091206001015490610ac98161208a565b9050610a84565b50505b5092915050565b5f805f610ae5610ff9565b806020019051810190610af89190611fea565b915091508373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16636352211e836040518263ffffffff1660e01b8152600401610b4e91815260200190565b602060405180830381865afa158015610b69573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b8d91906120c1565b73ffffffffffffffffffffffffffffffffffffffff1614949350505050565b610bb533610ada565b80610bd3575033730576a174d229e3cfa37253523e645a78a0c91b57145b610c5f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603e60248201527f4f6e6c792063616c6c61626c6520627920746865206d656368206f706572617460448201527f6f72206f722074686520656e74727920706f696e7420636f6e7472616374000060648201526084016105f9565b60018190556040518181527f66cbca4f3c64fecf1dcb9ce094abcf7f68c3450a1d4e3a8e917dd621edb4ebe09060200160405180910390a150565b610ca2610ff9565b5115610d0a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f416c726561647920696e697469616c697a65640000000000000000000000000060448201526064016105f9565b610d138161133e565b50565b5f600154341015610d60576001546040517fb489782800000000000000000000000000000000000000000000000000000000815234600482015260248101919091526044016105f9565b610d6a3383610f4d565b335f908152600360205260408120805492935090610d878361208a565b909155505060046020525f81815260408082207f17ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ed80546001830181905590859055808452918320849055600280547f17ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ec94929392909190610e068361208a565b91905055503373ffffffffffffffffffffffffffffffffffffffff167f4bda649efe6b98b0f9c1d5e859c29e20910f45c66dabfe6fad4a4881f7faf9cc8587604051610e53929190611f93565b60405180910390a2505050919050565b6060610e6e33610ada565b80610e8c575033730576a174d229e3cfa37253523e645a78a0c91b57145b610f18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603e60248201527f4f6e6c792063616c6c61626c6520627920746865206d656368206f706572617460448201527f6f72206f722074686520656e74727920706f696e7420636f6e7472616374000060648201526084016105f9565b5f610f32878787878715610f2c57876114b3565b5a6114b3565b9250905080610f4357815160208301fd5b5095945050505050565b5f8282604051602001610f619291906120dc565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101209392505050565b6004602052815f5260405f208160028110610fb7575f80fd5b01549150829050565b5f80610fca610ff9565b80602001905181019061090e91906120c1565b5f805f610fec878787876115b6565b91509150610f438161169e565b60606110c86110c36040517fd60000000000000000000000000000000000000000000000000000000000000060208201527f940000000000000000000000000000000000000000000000000000000000000060218201527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003060601b1660228201527f010000000000000000000000000000000000000000000000000000000000000060368201525f90603701604051602081830303815290604052805190602001205f1c905090565b611850565b905090565b33730576a174d229e3cfa37253523e645a78a0c91b571461114a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f6163636f756e743a206e6f742066726f6d20456e747279506f696e740000000060448201526064016105f9565b565b5f806111a4836040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c81018290525f90605c01604051602081830303815290604052805190602001209050919050565b90507f1626ba7e00000000000000000000000000000000000000000000000000000000611212826111d9610140880188612016565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061077192505050565b7fffffffff00000000000000000000000000000000000000000000000000000000161461124357600191505061090e565b505f9392505050565b5f80546020830135918061125f8361208a565b9190505514610d13576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c6964206e6f6e63650000000000000000000000000000000000000060448201526064016105f9565b8015610d13576040515f9033907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90849084818181858888f193505050503d805f8114611332576040519150601f19603f3d011682016040523d82523d5f602084013e611337565b606091505b5050505050565b5f611348826118a5565b90505f8151602083015ff0905061141a6040517fd60000000000000000000000000000000000000000000000000000000000000060208201527f940000000000000000000000000000000000000000000000000000000000000060218201527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003060601b1660228201527f010000000000000000000000000000000000000000000000000000000000000060368201525f90603701604051602081830303815290604052805190602001205f1c905090565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146114ae576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f5772697465206661696c6564000000000000000000000000000000000000000060448201526064016105f9565b505050565b5f606060018460018111156114ca576114ca61210a565b0361153e578673ffffffffffffffffffffffffffffffffffffffff1683866040516114f59190612137565b5f604051808303818686f4925050503d805f811461152e576040519150601f19603f3d011682016040523d82523d5f602084013e611533565b606091505b5090925090506115ac565b8673ffffffffffffffffffffffffffffffffffffffff168387876040516115659190612137565b5f60405180830381858888f193505050503d805f81146115a0576040519150601f19603f3d011682016040523d82523d5f602084013e6115a5565b606091505b5090925090505b9550959350505050565b5f807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156115eb57505f90506003611695565b604080515f8082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa15801561163c573d5f803e3d5ffd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811661168f575f60019250925050611695565b91505f90505b94509492505050565b5f8160048111156116b1576116b161210a565b036116b95750565b60018160048111156116cd576116cd61210a565b03611734576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f45434453413a20696e76616c6964207369676e6174757265000000000000000060448201526064016105f9565b60028160048111156117485761174861210a565b036117af576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e6774680060448201526064016105f9565b60038160048111156117c3576117c361210a565b03610d13576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f756500000000000000000000000000000000000000000000000000000000000060648201526084016105f9565b6060813b6001811161187157505060408051602081019091525f8152919050565b8061187b81611f5f565b9150506040519150601f19601f602083010116820160405280825280600160208401853c50919050565b6060815160016118b59190612077565b826040516020016118c7929190612152565b6040516020818303038152906040529050919050565b73ffffffffffffffffffffffffffffffffffffffff81168114610d13575f80fd5b5f8083601f84011261190e575f80fd5b50813567ffffffffffffffff811115611925575f80fd5b60208301915083602082850101111561193c575f80fd5b9250929050565b5f805f805f805f8060c0898b03121561195a575f80fd5b8835611965816118dd565b97506020890135611975816118dd565b96506040890135611985816118dd565b955060608901359450608089013567ffffffffffffffff808211156119a8575f80fd5b6119b48c838d016118fe565b909650945060a08b01359150808211156119cc575f80fd5b506119d98b828c016118fe565b999c989b5096995094979396929594505050565b5f805f805f60808688031215611a01575f80fd5b8535611a0c816118dd565b94506020860135611a1c816118dd565b935060408601359250606086013567ffffffffffffffff811115611a3e575f80fd5b611a4a888289016118fe565b969995985093965092949392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f82601f830112611a97575f80fd5b813567ffffffffffffffff80821115611ab257611ab2611a5b565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715611af857611af8611a5b565b81604052838152866020858801011115611b10575f80fd5b836020870160208301375f602085830101528094505050505092915050565b5f8060408385031215611b40575f80fd5b82359150602083013567ffffffffffffffff811115611b5d575f80fd5b611b6985828601611a88565b9150509250929050565b5f805f60608486031215611b85575f80fd5b833567ffffffffffffffff811115611b9b575f80fd5b84016101608187031215611bad575f80fd5b95602085013595506040909401359392505050565b5f8060408385031215611bd3575f80fd5b50508035926020909101359150565b602080825282518282018190525f9190848201906040850190845b81811015611c1957835183529284019291840191600101611bfd565b50909695505050505050565b5f60208284031215611c35575f80fd5b8135610931816118dd565b5f60208284031215611c50575f80fd5b5035919050565b5f60208284031215611c67575f80fd5b813567ffffffffffffffff811115611c7d575f80fd5b611c8984828501611a88565b949350505050565b5f8083601f840112611ca1575f80fd5b50813567ffffffffffffffff811115611cb8575f80fd5b6020830191508360208260051b850101111561193c575f80fd5b5f805f805f805f8060a0898b031215611ce9575f80fd5b8835611cf4816118dd565b97506020890135611d04816118dd565b9650604089013567ffffffffffffffff80821115611d20575f80fd5b611d2c8c838d01611c91565b909850965060608b0135915080821115611d44575f80fd5b611d508c838d01611c91565b909650945060808b01359150808211156119cc575f80fd5b5f805f805f60a08688031215611d7c575f80fd5b8535611d87816118dd565b945060208601359350604086013567ffffffffffffffff811115611da9575f80fd5b611db588828901611a88565b935050606086013560028110611dc9575f80fd5b949793965091946080013592915050565b5f5b83811015611df4578181015183820152602001611ddc565b50505f910152565b5f8151808452611e13816020860160208601611dda565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081525f6109316020830184611dfc565b5f8060408385031215611e68575f80fd5b8235611e73816118dd565b9150602083013567ffffffffffffffff811115611b5d575f80fd5b5f805f805f8060a08789031215611ea3575f80fd5b8635611eae816118dd565b95506020870135611ebe816118dd565b94506040870135935060608701359250608087013567ffffffffffffffff811115611ee7575f80fd5b611ef389828a016118fe565b979a9699509497509295939492505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f81611f6d57611f6d611f32565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b828152604060208201525f611c896040830184611dfc565b5f60208284031215611fbb575f80fd5b81517fffffffff0000000000000000000000000000000000000000000000000000000081168114610931575f80fd5b5f8060408385031215611ffb575f80fd5b8251612006816118dd565b6020939093015192949293505050565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612049575f80fd5b83018035915067ffffffffffffffff821115612063575f80fd5b60200191503681900382131561193c575f80fd5b8082018082111561090e5761090e611f32565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036120ba576120ba611f32565b5060010190565b5f602082840312156120d1575f80fd5b8151610931816118dd565b73ffffffffffffffffffffffffffffffffffffffff83168152604060208201525f611c896040830184611dfc565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b5f8251612148818460208701611dda565b9190910192915050565b7f630000000000000000000000000000000000000000000000000000000000000081527fffffffff000000000000000000000000000000000000000000000000000000008360e01b1660018201527f80600e6000396000f3000000000000000000000000000000000000000000000060058201525f600e8201525f82516121e081600f850160208701611dda565b91909101600f01939250505056fea2646970667358221220c1913351e275e1fecd00c79cd676ed135b575df5d3a88ccc57419dc3081980a264736f6c63430008150033", + "linkReferences": {}, + "deployedLinkReferences": {} +} \ No newline at end of file diff --git a/packages/valory/contracts/mech_marketplace/contract.py b/packages/valory/contracts/mech_marketplace/contract.py new file mode 100644 index 000000000..33e5a91cc --- /dev/null +++ b/packages/valory/contracts/mech_marketplace/contract.py @@ -0,0 +1,260 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2024 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 class to connect to a Mech Marketplace contract.""" + +import concurrent.futures +from typing import Any, Callable, 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 eth_typing import HexStr +from web3.types import BlockData, BlockIdentifier, EventData, TxReceipt + + +PUBLIC_ID = PublicId.from_str("valory/mech_marketplace:0.1.0") +FIVE_MINUTES = 300.0 + + + +class MechMarketplace(Contract): + """The Mech Marketplace contract.""" + + contract_id = PUBLIC_ID + + @staticmethod + def execute_with_timeout(func: Callable, timeout: float) -> Any: + """Execute a function with a timeout.""" + + # Create a ProcessPoolExecutor with a maximum of 1 worker (process) + with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor: + # Submit the function to the executor + future = executor.submit( + func, + ) + + try: + # Wait for the result with a 5-minute timeout + data = future.result(timeout=timeout) + except TimeoutError: + # Handle the case where the execution times out + err = f"The RPC didn't respond in {timeout}." + return None, err + + # Check if an error occurred + if isinstance(data, str): + # Handle the case where the execution failed + return None, data + + return data, None + + @classmethod + def get_request_data( + cls, + ledger_api: LedgerApi, + contract_address: str, + request_data: bytes, + priority_mech: str, + priority_mech_staking_instance: str, + priority_mech_service_id: int, + requester_staking_instance: str, + requester_service_id: int, + response_timeout: int, + **kwargs: Any + ) -> Dict[str, bytes]: + """Gets the encoded arguments for a request tx, which should only be called via the multisig. + + :param ledger_api: the ledger API object + :param contract_address: the contract's address + :param request_data: the request data + :param priority_mech: the priority mech address + :param priority_mech_staking_instance: the priority mech staking instance address + :param priority_mech_service_id: the priority mech service id + :param requester_staking_instance: the requester staking instance address + :param requester_service_id: the requester service id + :param response_timeout: the response timeout + """ + contract_address = ledger_api.api.to_checksum_address(contract_address) + contract_instance = cls.get_instance(ledger_api, contract_address) + encoded_data = contract_instance.encodeABI( + fn_name="request", + args=( + request_data, + priority_mech, + priority_mech_staking_instance, + priority_mech_service_id, + requester_staking_instance, + requester_service_id, + response_timeout, + ) + ) + return {"data": bytes.fromhex(encoded_data[2:])} + + @classmethod + def _process_event( + cls, + ledger_api: LedgerApi, + contract: Any, + tx_hash: HexStr, + expected_logs: int, + event_name: str, + *args: Any, + **kwargs: Any + ) -> JSONLike: + """Process the logs of the given event.""" + ledger_api = cast(EthereumApi, ledger_api) + receipt: TxReceipt = ledger_api.api.eth.get_transaction_receipt(tx_hash) + event_method = getattr(contract.events, event_name) + logs: List[EventData] = list(event_method().process_receipt(receipt)) + + n_logs = len(logs) + if n_logs != expected_logs: + error = f"{expected_logs} {event_name!r} events were expected. tx {tx_hash} emitted {n_logs} instead." + return {"error": error} + + results = [] + for log in logs: + event_args = log.get("args", None) + if event_args is None or any( + expected_key not in event_args for expected_key in args + ): + return {"error": f"The emitted event's ({event_name}) logs for tx {tx_hash} do not match the expected format: {log}"} + results.append({arg_name: event_args[arg_name] for arg_name in args}) + + return dict(results=results) + + @classmethod + def process_request_event( + cls, + ledger_api: LedgerApi, + contract_address: str, + tx_hash: HexStr, + expected_logs: int = 1, + **kwargs: Any + ) -> JSONLike: + """ + Process the request receipt to get the requestId and the given data from the `Request` event's logs. + + :param ledger_api: the ledger apis. + :param contract_address: the contract address. + :param tx_hash: the hash of a request tx to be processed. + :param expected_logs: the number of logs expected. + :return: a dictionary with a key named `results` + which contains a list of dictionaries (as many as the expected logs) containing the request id and the data. + """ + contract_address = ledger_api.api.to_checksum_address(contract_address) + contract_instance = cls.get_instance(ledger_api, contract_address) + res = cls._process_event( + ledger_api, contract_instance, tx_hash, expected_logs, "MarketplaceRequest", "requestId", "data" + ) + + return res + + @classmethod + def process_deliver_event( + cls, + ledger_api: LedgerApi, + contract_address: str, + tx_hash: HexStr, + expected_logs: int = 1, + **kwargs: Any + ) -> JSONLike: + """ + Process the request receipt to get the requestId and the delivered data if the `MarketplaceDeliver` event has been emitted. + + :param ledger_api: the ledger apis. + :param contract_address: the contract address. + :param tx_hash: the hash of a request tx to be processed. + :param expected_logs: the number of logs expected. + :return: a dictionary with the request id and the data. + """ + contract_address = ledger_api.api.to_checksum_address(contract_address) + contract_instance = cls.get_instance(ledger_api, contract_address) + res = cls._process_event( + ledger_api, contract_instance, tx_hash, expected_logs, "MarketplaceDeliver", "requestId", "data" + ) + + return res + + @classmethod + def get_block_number( + cls, + ledger_api: EthereumApi, + contract_address: str, + tx_hash: HexStr, + **kwargs: Any + ) -> JSONLike: + """Get the number of the block in which the tx of the given hash was settled.""" + contract_address = ledger_api.api.to_checksum_address(contract_address) + receipt: TxReceipt = ledger_api.api.eth.get_transaction_receipt(tx_hash) + block: BlockData = ledger_api.api.eth.get_block(receipt["blockNumber"]) + return dict(number=block["number"]) + + @classmethod + def get_response( + cls, + ledger_api: LedgerApi, + contract_address: str, + request_id: int, + from_block: BlockIdentifier = "earliest", + to_block: BlockIdentifier = "latest", + timeout: float = FIVE_MINUTES, + **kwargs: Any + ) -> JSONLike: + """Filter the `MarketplaceDeliver` events emitted by the contract and get the data of the given `request_id`.""" + contract_address = ledger_api.api.to_checksum_address(contract_address) + ledger_api = cast(EthereumApi, ledger_api) + + def get_responses() -> Any: + """Get the responses from the contract.""" + contract_instance = cls.get_instance(ledger_api, contract_address) + deliver_filter = contract_instance.events.MarketplaceDeliver.build_filter() + deliver_filter.fromBlock = from_block + deliver_filter.toBlock = to_block + deliver_filter.args.requestId.match_single(request_id) + delivered = list(deliver_filter.deploy(ledger_api.api).get_all_entries()) + n_delivered = len(delivered) + + if n_delivered == 0: + info = f"The mech ({contract_address}) has not delivered a response yet for request with id {request_id}." + return {"info": info} + + if n_delivered != 1: + error = ( + f"A single response was expected by the mech ({contract_address}) for request with id {request_id}. " + f"Received {n_delivered} responses: {delivered}." + ) + return error + + delivered_event = delivered.pop() + deliver_args = delivered_event.get("args", None) + if deliver_args is None or "data" not in deliver_args: + error = f"The mech's response does not match the expected format: {delivered_event}" + return error + + return dict(data=deliver_args["data"]) + + data, err = cls.execute_with_timeout(get_responses, timeout=timeout) + if err is not None: + return {"error": err} + + return data diff --git a/packages/valory/contracts/mech_marketplace/contract.yaml b/packages/valory/contracts/mech_marketplace/contract.yaml new file mode 100644 index 000000000..d41799bd0 --- /dev/null +++ b/packages/valory/contracts/mech_marketplace/contract.yaml @@ -0,0 +1,23 @@ +name: mech_marketplace +author: valory +version: 0.1.0 +type: contract +description: Agent mech marketplace contract. +license: Apache-2.0 +aea_version: '>=1.0.0, <2.0.0' +fingerprint: + README.md: bafybeihygfmkbo4cegrqnz5ws6bbjaifubvk7r2uyvuanxpqy24l634tba + __init__.py: bafybeie6625ddrcph7pcxef4fbfcuhyd6yuzdyyqcoqpc5xdjb4rttw7my + build/mech.json: bafybeif2doizav5rs5hig6bruaoz2bedlyesyh23s735llblh64vazespi + contract.py: bafybeiawzcqvkx7tip7tck2czf47d5rnolebmet3fbmv5p4hzpv3fmarwq +fingerprint_ignore_patterns: [] +contracts: [] +class_name: MechMarketplace +contract_interface_paths: + ethereum: build/mech.json +dependencies: + open-aea-ledger-ethereum: + version: ==1.53.0 + web3: + version: <7,>=6.0.0 + eth_typing: {} diff --git a/packages/valory/skills/decision_maker_abci/behaviours/sampling.py b/packages/valory/skills/decision_maker_abci/behaviours/sampling.py index 250828133..fe5786209 100644 --- a/packages/valory/skills/decision_maker_abci/behaviours/sampling.py +++ b/packages/valory/skills/decision_maker_abci/behaviours/sampling.py @@ -19,20 +19,17 @@ """This module contains the behaviour for sampling a bet.""" -import random -from typing import Any, Generator, List, Optional +from typing import Generator, Iterator, List, Optional from packages.valory.skills.decision_maker_abci.behaviours.base import ( DecisionMakerBaseBehaviour, ) from packages.valory.skills.decision_maker_abci.payloads import SamplingPayload from packages.valory.skills.decision_maker_abci.states.sampling import SamplingRound -from packages.valory.skills.market_manager_abci.bets import Bet +from packages.valory.skills.market_manager_abci.bets import Bet, BetStatus -WEEKDAYS = 7 UNIX_DAY = 60 * 60 * 24 -UNIX_WEEK = WEEKDAYS * UNIX_DAY class SamplingBehaviour(DecisionMakerBaseBehaviour): @@ -40,44 +37,24 @@ class SamplingBehaviour(DecisionMakerBaseBehaviour): matching_round = SamplingRound - def __init__(self, **kwargs: Any) -> None: - """Initialize Behaviour.""" - super().__init__(**kwargs) - self.should_rebet: bool = False - - def setup(self) -> None: - """Setup the behaviour.""" - self.read_bets() - has_bet_in_the_past = any(bet.n_bets > 0 for bet in self.bets) - if has_bet_in_the_past: - random.seed(self.synchronized_data.most_voted_randomness) - self.should_rebet = random.random() <= self.params.rebet_chance # nosec - rebetting_status = "enabled" if self.should_rebet else "disabled" - self.context.logger.info(f"Rebetting {rebetting_status}.") - - def processable_bet(self, bet: Bet) -> bool: - """Whether we can process the given bet.""" - now = self.synced_timestamp - # Note: `openingTimestamp` is the timestamp when a question stops being available for voting. - within_opening_range = bet.openingTimestamp <= ( - now + self.params.sample_bets_closing_days * UNIX_DAY - ) - within_safe_range = now < bet.openingTimestamp + self.params.safe_voting_range - within_ranges = within_opening_range and within_safe_range - - # if we should not rebet, we have all the information we need - if not self.should_rebet: - return within_ranges - - # if we should rebet, we should have at least one bet processed in the past - if not bool(bet.n_bets): - return False - - # create a filter based on whether we can rebet or not - lifetime = bet.openingTimestamp - now - t_rebetting = (lifetime // UNIX_WEEK) + UNIX_DAY - can_rebet = now >= bet.processed_timestamp + t_rebetting - return within_ranges and can_rebet + @property + def available_bets(self) -> Iterator[Bet]: + """Get an iterator of the unprocessed bets.""" + + # Note: the openingTimestamp is misleading as it is the closing timestamp of the bet + if self.params.using_kelly: + # get only bets that close in the next 48 hours + self.bets = [ + bet + for bet in self.bets + if bet.openingTimestamp + <= ( + self.synced_timestamp + + self.params.sample_bets_closing_days * UNIX_DAY + ) + ] + + return filter(lambda bet: bet.status == BetStatus.UNPROCESSED, self.bets) def _sampled_bet_idx(self, bets: List[Bet]) -> int: """ @@ -93,7 +70,7 @@ def _sampled_bet_idx(self, bets: List[Bet]) -> int: def _sample(self) -> Optional[int]: """Sample a bet, mark it as processed, and return its index.""" - available_bets = list(filter(self.processable_bet, self.bets)) + available_bets = list(self.available_bets) if len(available_bets) == 0: msg = "There were no unprocessed bets available to sample from!" @@ -107,9 +84,8 @@ def _sample(self) -> Optional[int]: self.context.logger.warning(msg) return None - # update the bet's timestamp of processing and its number of rebets for the given id - self.bets[idx].processed_timestamp = self.synced_timestamp - self.bets[idx].n_bets += 1 + # update the bet's status for the given id to `PROCESSED` + self.bets[idx].status = BetStatus.PROCESSED msg = f"Sampled bet: {self.bets[idx]}" self.context.logger.info(msg) return idx @@ -117,6 +93,7 @@ def _sample(self) -> Optional[int]: def async_act(self) -> Generator: """Do the action.""" with self.context.benchmark_tool.measure(self.behaviour_id).local(): + self.read_bets() idx = self._sample() self.store_bets() if idx is None: @@ -125,4 +102,4 @@ def async_act(self) -> Generator: bets_hash = self.hash_stored_bets() payload = SamplingPayload(self.context.agent_address, bets_hash, idx) - yield from self.finish_behaviour(payload) + yield from self.finish_behaviour(payload) \ No newline at end of file