diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 44c52132..00000000 --- a/.gitmodules +++ /dev/null @@ -1,9 +0,0 @@ -[submodule "forge/lib/forge-std"] - path = forge/lib/forge-std - url = https://github.com/foundry-rs/forge-std -[submodule "forge/lib/openzeppelin-contracts"] - path = forge/lib/openzeppelin-contracts - url = https://github.com/OpenZeppelin/openzeppelin-contracts -[submodule "forge/lib/tnt-core"] - path = forge/lib/tnt-core - url = https://github.com/webb-tools/tnt-core diff --git a/Cargo.toml b/Cargo.toml index 9a26a47a..5c67aec9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -127,6 +127,7 @@ k256 = { version = "0.13.3", default-features = false } p256 = { version = "0.13.2", default-features = false } ecdsa-core = { package = "ecdsa", version = "0.16.9", default-features = false } starknet-crypto = { version = "0.7.1", default-features = false, features = ["signature-display", "alloc"] } + frost-core = { path = "frost", default-features = false } frost-ed25519 = { path = "frost/frost-ed25519", default-features = false } frost-ed448 = { path = "frost/frost-ed448", default-features = false } diff --git a/flake.lock b/flake.lock index 2850ce6d..735dfea1 100644 --- a/flake.lock +++ b/flake.lock @@ -28,11 +28,11 @@ ] }, "locked": { - "lastModified": 1728119511, - "narHash": "sha256-kJHt+BoDTc9aYXnmy7X+kQto9cT77lDKHAYp5FyY4OY=", + "lastModified": 1730625090, + "narHash": "sha256-lWfkkj+GEUM0UqYLD2Rx3zzILTL3xdmGJKGR4fwONpA=", "owner": "shazow", "repo": "foundry.nix", - "rev": "c45f6bc1f2110b1d209e116be203648a06a02f80", + "rev": "1c6a742bcbfd55a80de0e1f967a60174716a1560", "type": "github" }, "original": { @@ -44,11 +44,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1728538411, - "narHash": "sha256-f0SBJz1eZ2yOuKUr5CA9BHULGXVSn6miBuUWdTyhUhU=", + "lastModified": 1731245184, + "narHash": "sha256-vmLS8+x+gHRv1yzj3n+GTAEObwmhxmkkukB2DwtJRdU=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "b69de56fac8c2b6f8fd27f2eca01dcda8e0a4221", + "rev": "aebe249544837ce42588aa4b2e7972222ba12e8f", "type": "github" }, "original": { @@ -73,11 +73,11 @@ ] }, "locked": { - "lastModified": 1728959392, - "narHash": "sha256-fp4he1QQjE+vasDMspZYeXrwTm9otwEqLwEN6FKZ5v0=", + "lastModified": 1731464916, + "narHash": "sha256-WZ5rpjr/wCt7yBOUsvDE2i22hYz9g8W921jlwVktRQ4=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "4c6e317300f05b8871f585b826b6f583e7dc4a9b", + "rev": "2c19bad6e881b5a154cafb7f9106879b5b356d1f", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index ddb00eb9..e289c0c8 100644 --- a/flake.nix +++ b/flake.nix @@ -48,8 +48,6 @@ (lib.optionals pkgs.stdenv.isDarwin pkgs.darwin.apple_sdk.frameworks.SystemConfiguration) ]; buildInputs = [ - # We want the unwrapped version, wrapped comes with nixpkgs' toolchain - pkgs.rust-analyzer-unwrapped # Nodejs for test suite pkgs.nodePackages.typescript-language-server pkgs.nodejs_18 diff --git a/forge/.gitignore b/forge/.gitignore deleted file mode 100644 index 85198aaa..00000000 --- a/forge/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -# Compiler files -cache/ -out/ - -# Ignores development broadcast logs -!/broadcast -/broadcast/*/31337/ -/broadcast/**/dry-run/ - -# Docs -docs/ - -# Dotenv file -.env diff --git a/forge/foundry.toml b/forge/foundry.toml deleted file mode 100644 index f27e6464..00000000 --- a/forge/foundry.toml +++ /dev/null @@ -1,14 +0,0 @@ -[profile.default] -src = "src" -out = "out" -libs = ["lib"] - -remappings = [ - "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", - "ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/", - "forge-std/=lib/forge-std/src/", - "core/=lib/tnt-core/src/", - "@/=src/", -] - -# See more config options https://github.com/foundry-rs/foundry/tree/master/config diff --git a/forge/lib/forge-std b/forge/lib/forge-std deleted file mode 160000 index 1de6eecf..00000000 --- a/forge/lib/forge-std +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1de6eecf821de7fe2c908cc48d3ab3dced20717f diff --git a/forge/lib/openzeppelin-contracts b/forge/lib/openzeppelin-contracts deleted file mode 160000 index f989fff9..00000000 --- a/forge/lib/openzeppelin-contracts +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f989fff93168606c726bc5e831ef50dd6e543f45 diff --git a/forge/lib/tnt-core b/forge/lib/tnt-core deleted file mode 160000 index c1fa9c7c..00000000 --- a/forge/lib/tnt-core +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c1fa9c7c3c5891aab9bd25002a434d93c54942cd diff --git a/forge/src/SigningRules.sol b/forge/src/SigningRules.sol deleted file mode 100644 index 40002ef9..00000000 --- a/forge/src/SigningRules.sol +++ /dev/null @@ -1,238 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.13; - -import "forge-std/console.sol"; -// import {JOBS_CONTRACT} from "./Jobs.sol"; - -enum ProposalStatus { - Inactive, - Active, - Passed, - Executed, - Cancelled -} - -struct Proposal { - ProposalStatus _status; - uint256 _yesVotes; // bitmap, 256 maximum votes - uint8 _yesVotesTotal; - uint40 _proposedBlock; // 1099511627775 maximum block -} - -abstract contract SigningRules { - mapping(uint64 => mapping(address => bool)) public isValidForwarder; - mapping(uint64 => address) public admins; - mapping(uint64 => address[]) public voters; - mapping(uint64 => uint8) public threshold; - mapping(uint64 => uint64) public expiry; - mapping(uint64 => uint64) public ttl; - mapping(uint64 => bool) public useDemocracy; - mapping(uint64 => bool) public useValidators; - - // keccak256(proposalId, phase2JobHash) => Proposal - mapping(bytes32 => Proposal) public _proposals; - - bool public initialized; - // Limit voter number because proposal can fit only so much votes - uint256 public constant MAX_VOTERS = 256; - - event ProposalEvent(ProposalStatus status, uint64 phase1JobId, bytes32 phase2JobHash); - event ProposalVote(ProposalStatus status, uint64 phase1JobId, bytes32 phase2JobHash); - event FailedHandlerExecution(bytes lowLevelData); - - modifier onlyAdmin(uint64 id) { - require(admins[id] == msg.sender, "Only admin can call this function"); - _; - } - - function calculatePhase2JobHash(uint64 phase1JobId, bytes memory phase2JobDetails) public pure returns (bytes32) { - return keccak256(abi.encodePacked(phase1JobId, phase2JobDetails)); - } - - function initialize( - uint64 phase1JobId, - uint8 _threshold, - bool _useDemocracy, - address[] memory _voters, - uint64 _expiry, - uint64 _ttl - ) external { - require(_voters.length <= MAX_VOTERS, "Too many voters"); - require(initialized == false, "Already initialized"); - initialized = true; - - // Hash the job data to get the an ID for the job - threshold[phase1JobId] = _threshold; - useDemocracy[phase1JobId] = _useDemocracy; - expiry[phase1JobId] = _expiry; - ttl[phase1JobId] = _ttl; - admins[phase1JobId] = msg.sender; - - // If we have voters, add them to the list. - if (_voters.length > 0) { - voters[phase1JobId] = _voters; - } else { - // Otherwise, use the default list of being all validators ECDSA keys. - useValidators[phase1JobId] = true; - _refreshVoters(phase1JobId); - } - } - - /// @notice Refresh the list of voters for a proposal w/ validators - /// @param phase1JobId ID of the proposal to refresh voters for. - function refreshVoters(uint64 phase1JobId) public onlyAdmin(phase1JobId) { - _refreshVoters(phase1JobId); - } - - /// @notice Set a forwarder to be used. - /// @notice Only callable by an address that currently has the admin role. - /// @param forwarder Forwarder address to be added. - /// @param valid Decision for the specific forwarder. - function adminSetForwarder(uint64 phase1JobId, address forwarder, bool valid) external onlyAdmin(phase1JobId) { - isValidForwarder[phase1JobId][forwarder] = valid; - } - - function submitGovernanceProposal(uint64 phase1JobId, bytes memory phase2JobDetails) public { - // Validate the governance proposal - bytes32 phase2JobHash = keccak256(abi.encodePacked(phase1JobId, phase2JobDetails)); - require(_proposals[phase2JobHash]._status != ProposalStatus.Executed, "Proposal must have been executed"); - require(useDemocracy[phase1JobId], "Proposal must allow using governance"); - // Submit the proposal to governance pallet - _submitToDemocracyPallet(phase1JobId, phase2JobDetails); - } - - function voteProposal(uint64 phase1JobId, bytes memory phase2JobDetails) public { - // Validate the job/details are AUP - require(_isVotableProposal(phase1JobId, phase2JobDetails), "Proposal must be votable"); - // Check that we have received enough votes for the anchor update proposal. - // Execute the proposal happens in `_voteProposal` if this vote tips the balance. - _voteProposal(phase1JobId, phase2JobDetails); - } - - /// --------------------------------------------------------------------------------------- /// - /// ------------------------------------- Internals --------------------------------------- /// - /// --------------------------------------------------------------------------------------- /// - - /// @notice When called, {_msgSender()} will be marked as voting in favor of proposal. - /// @notice Proposal must not have already been passed or executed. - /// @notice {_msgSender()} must not have already voted on proposal. - /// @notice Emits {ProposalEvent} event with status indicating the proposal status. - /// @notice Emits {ProposalVote} event. - function _voteProposal(uint64 phase1JobId, bytes memory phase2JobDetails) internal { - bytes32 phase2JobHash = keccak256(abi.encodePacked(phase1JobId, phase2JobDetails)); - Proposal storage proposal = _proposals[phase2JobHash]; - if (proposal._status == ProposalStatus.Passed) { - _executeProposal(phase1JobId, phase2JobHash, phase2JobDetails); - return; - } - - address sender = _msgSender(phase1JobId); - - require(uint256(proposal._status) <= 1, "proposal already executed/cancelled"); - require(!_hasVoted(phase1JobId, phase2JobHash, sender), "relayer already voted"); - - if (proposal._status == ProposalStatus.Inactive) { - _proposals[phase2JobHash] = Proposal({ - _status: ProposalStatus.Active, - _yesVotes: 0, - _yesVotesTotal: 0, - _proposedBlock: uint40(block.number) // Overflow is desired. - }); - - emit ProposalEvent(ProposalStatus.Active, phase1JobId, phase2JobHash); - } else if (uint40(block.number - proposal._proposedBlock) > expiry[phase1JobId]) { - // if the number of blocks that has passed since this proposal was - // submitted exceeds the expiry threshold set, cancel the proposal - proposal._status = ProposalStatus.Cancelled; - - emit ProposalEvent(ProposalStatus.Cancelled, phase1JobId, phase2JobHash); - } - - if (proposal._status != ProposalStatus.Cancelled) { - proposal._yesVotes = (proposal._yesVotes | _voterBit(phase1JobId, sender)); - proposal._yesVotesTotal++; // TODO: check if bit counting is cheaper. - - emit ProposalVote(proposal._status, phase1JobId, phase2JobHash); - - // Finalize if _relayerThreshold has been reached - if (proposal._yesVotesTotal >= threshold[phase1JobId]) { - proposal._status = ProposalStatus.Passed; - emit ProposalEvent(ProposalStatus.Passed, phase1JobId, phase2JobHash); - } - } - _proposals[phase2JobHash] = proposal; - - if (proposal._status == ProposalStatus.Passed) { - _executeProposal(phase1JobId, phase2JobHash, phase2JobDetails); - } - } - - /// @notice Execute a proposal. - /// @param phase1JobId ID of the job that the proposal is associated with. - /// @notice Proposal must have Passed status. - /// @notice Emits {ProposalEvent} event with status {Executed}. - /// @notice Emits {FailedExecution} event with the failed reason. - function _executeProposal(uint64 phase1JobId, bytes32 phase2JobHash, bytes memory phase2JobDetails) internal { - Proposal storage proposal = _proposals[phase2JobHash]; - require(proposal._status == ProposalStatus.Passed, "Proposal must have Passed status"); - - // JOBS_CONTRACT.submitDkgPhaseTwoJob( - // expiry[phase1JobId], ttl[phase1JobId], phase1JobId, phase2JobDetails, bytes("") - // ); - - proposal._status = ProposalStatus.Executed; - emit ProposalEvent(ProposalStatus.Executed, phase1JobId, phase2JobHash); - } - - function _voterIndex(uint64 phase1JobId, address voter) internal view returns (uint256) { - for (uint256 i = 0; i < voters[phase1JobId].length; i++) { - if (voters[phase1JobId][i] == voter) { - return i + 1; - } - } - return MAX_VOTERS; - } - - function _voterBit(uint64 phase1JobId, address voter) internal view returns (uint256) { - return uint256(1) << (_voterIndex(phase1JobId, voter) - 1); - } - - function _hasVoted(uint64 phase1JobId, bytes32 phase2JobHash, address voter) internal view returns (bool) { - Proposal storage proposal = _proposals[phase2JobHash]; - return (_voterBit(phase1JobId, voter) & uint256(proposal._yesVotes)) > 0; - } - - function _msgSender(uint64 phase1JobId) internal view returns (address) { - address signer = msg.sender; - if (msg.data.length >= 20 && isValidForwarder[phase1JobId][signer]) { - assembly { - signer := shr(96, calldataload(sub(calldatasize(), 20))) - } - } - return signer; - } - - /// --------------------------------------------------------------------------------------- /// - /// -------------------------------------- Virtuals --------------------------------------- /// - /// --------------------------------------------------------------------------------------- /// - - function _isVotableProposal(uint64 phase1JobId, bytes memory phase2JobDetails) internal virtual returns (bool); - function _refreshVoters(uint64 phase1JobId) internal virtual; - function _submitToDemocracyPallet(uint64 phase1JobId, bytes memory phase2JobDetails) internal virtual; - - /// --------------------------------------------------------------------------------------- /// - /// -------------------------------------- Helpers ---------------------------------------- /// - /// --------------------------------------------------------------------------------------- /// - - function getProposalState(bytes32 phase2JobHash) public view returns (ProposalStatus) { - return _proposals[phase2JobHash]._status; - } - - function getProposalYesVotes(bytes32 phase2JobHash) public view returns (uint256) { - return _proposals[phase2JobHash]._yesVotes; - } - - function getProposalYesVotesTotal(bytes32 phase2JobHash) public view returns (uint8) { - return _proposals[phase2JobHash]._yesVotesTotal; - } -} diff --git a/forge/src/cggmp21/CGGMP21Blueprint.sol b/forge/src/cggmp21/CGGMP21Blueprint.sol deleted file mode 100644 index bb486e78..00000000 --- a/forge/src/cggmp21/CGGMP21Blueprint.sol +++ /dev/null @@ -1,102 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -// DO NOT USE THIS IN PRODUCTION, IT IS JUST FOR TESTING. -pragma solidity >=0.8.3; - -import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; -import "core/BlueprintServiceManagerBase.sol"; - -contract CGGMP21Blueprint is BlueprintServiceManagerBase { - /// A Simple List of all Operator Ecdsa Public Keys - struct Operator { - address addr; - bytes publicKey; - } - - uint8 constant KEYGEN_JOB = 0; - uint8 constant SIGNING_JOB = 1; - - Operator[] public blueprintOperators; - - struct Service { - /// The id of the service - uint64 id; - /// The list of participants of the service - Operator[] operators; - } - - // Keygens - // A mapping of serviceId -> JobCallId -> DKG Threshold - mapping(uint64 => mapping(uint64 => uint8)) public keygens; - - // A mapping of serviceId to Service - mapping(uint64 => Service) public services; - - error InvalidRequestInputs(); - error InvalidDKGThreshold(); - error KeygenJobNotFound(); - error InvalidJob(); - - function onRegister(bytes calldata operator, bytes calldata registrationInputs) - public - payable - override - onlyFromRootChain - { - address addr = operatorAddressFromPublicKey(operator); - // add the participant to the list - blueprintOperators.push(Operator(addr, operator)); - } - - function onRequest(uint64 serviceId, bytes[] calldata operators, bytes calldata requestInputs) - public - payable - override - onlyFromRootChain - { - // The requestInputs are empty, we don't need them. - if (requestInputs.length != 0) { - revert InvalidRequestInputs(); - } - // Create the service - Service storage service = services[serviceId]; - service.id = serviceId; - - for (uint256 i = 0; i < operators.length; i++) { - address addr = operatorAddressFromPublicKey(operators[i]); - service.operators.push(Operator(addr, operators[i])); - } - } - - function onJobCall(uint64 serviceId, uint8 job, uint64 jobCallId, bytes calldata inputs) - public - payable - override - onlyFromRootChain - { - // Job 0 is the Keygen Job - if (job == KEYGEN_JOB) { - // The inputs are the DKG threshold - uint8 t = abi.decode(inputs, (uint8)); - uint256 n = services[serviceId].operators.length; - // verify the DKG threshold is valid - if (t == 0 || t > n) { - revert InvalidDKGThreshold(); - } - // set the DKG threshold of the service - keygens[serviceId][jobCallId] = t; - } else if (job == SIGNING_JOB) { - // inputs are keygenJobCallId and message hash (32 bytes) - (uint64 keygenJobCallId, bytes32 _message) = abi.decode(inputs, (uint64, bytes32)); - // verify the keygen job exists - if (keygens[serviceId][keygenJobCallId] == 0) { - revert KeygenJobNotFound(); - } - } else { - revert InvalidJob(); - } - } - - function operatorAddressFromPublicKey(bytes calldata publicKey) public pure returns (address) { - return address(uint160(uint256(keccak256(publicKey)))); - } -} diff --git a/forge/test/SigningRules.sol b/forge/test/SigningRules.sol deleted file mode 100644 index 4b20315a..00000000 --- a/forge/test/SigningRules.sol +++ /dev/null @@ -1,148 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.13; - -import "forge-std/Test.sol"; -import "forge-std/console.sol"; -import "@/SigningRules.sol"; -import {Proposal, ProposalStatus} from "@/SigningRules.sol"; - -contract VotableSigningRules is SigningRules { - function _isVotableProposal(uint64 phase1JobId, bytes memory phase2JobDetails) - internal - pure - override - returns (bool) - { - require(phase2JobDetails.length != 0, "Job details must be non-empty"); - return true; - } - - function _refreshVoters(uint64 phase1JobId) internal override { - // Do nothing - } - - function _submitToDemocracyPallet(uint64 phase1JobId, bytes memory phase2JobDetails) internal override { - // Do nothing - } -} - -contract SigningRulesTest is Test { - VotableSigningRules public rules; - - function setUp() public { - rules = new VotableSigningRules(); - } - - function test_setup() public { - uint64 phase1JobId = 1; - uint8 threshold = 1; - bool useDemocracy = false; - address[] memory voters = new address[](0); - uint64 expiry = 1000; - uint64 ttl = 1000; - rules.initialize(phase1JobId, threshold, useDemocracy, voters, expiry, ttl); - assertTrue(rules.initialized()); - assertTrue(rules.threshold(phase1JobId) == threshold); - assertTrue(rules.useDemocracy(phase1JobId) == useDemocracy); - assertTrue(rules.expiry(phase1JobId) == expiry); - assertTrue(rules.useValidators(phase1JobId) == true); - assertTrue(rules.admins(phase1JobId) == address(this)); - } - - function test_submitAndVoteOnProposal() public { - uint64 phase1JobId = 1; - bytes memory phase2JobDetails = "test"; - uint8 threshold = 2; - bool useDemocracy = false; - address[] memory voters = new address[](2); - voters[0] = vm.addr(1); - voters[1] = vm.addr(2); - uint40 expiry = 1000; - uint64 ttl = 1000; - bytes32 phase2JobHash = rules.calculatePhase2JobHash(phase1JobId, phase2JobDetails); - - rules.initialize(phase1JobId, threshold, useDemocracy, voters, expiry, ttl); - vm.prank(vm.addr(1)); - rules.voteProposal(phase1JobId, phase2JobDetails); - assertTrue(rules.getProposalState(phase2JobHash) == ProposalStatus.Active); - - vm.expectRevert("relayer already voted"); - vm.prank(vm.addr(1)); - rules.voteProposal(phase1JobId, phase2JobDetails); - - vm.prank(vm.addr(2)); - rules.voteProposal(phase1JobId, phase2JobDetails); - assertTrue(rules.getProposalState(phase2JobHash) == ProposalStatus.Executed); - } - - function test_submitAndVote255Participants() public { - uint64 phase1JobId = 1; - bytes memory phase2JobDetails = "test"; - uint8 threshold = 255; - bool useDemocracy = false; - address[] memory voters = new address[](255); - for (uint8 i = 0; i < 255; i++) { - voters[i] = vm.addr(i + 1); - } - uint40 expiry = 1000; - uint64 ttl = 1000; - bytes32 phase2JobHash = rules.calculatePhase2JobHash(phase1JobId, phase2JobDetails); - rules.initialize(phase1JobId, threshold, useDemocracy, voters, expiry, ttl); - for (uint8 i = 0; i < 255; i++) { - vm.prank(vm.addr(i + 1)); - rules.voteProposal(phase1JobId, phase2JobDetails); - - if (i < 254) { - assertTrue(rules.getProposalState(phase2JobHash) == ProposalStatus.Active); - } - } - assertTrue(rules.getProposalState(phase2JobHash) == ProposalStatus.Executed); - } - - function test_submitVoteAndExpireProposal() public { - uint64 phase1JobId = 1; - bytes memory phase2JobDetails = "test"; - uint8 threshold = 2; - bool useDemocracy = false; - address[] memory voters = new address[](2); - voters[0] = vm.addr(1); - voters[1] = vm.addr(2); - uint40 expiry = 10; - uint64 ttl = 10; - uint256 nowBlockNumber = block.number; - bytes32 phase2JobHash = rules.calculatePhase2JobHash(phase1JobId, phase2JobDetails); - - rules.initialize(phase1JobId, threshold, useDemocracy, voters, expiry, ttl); - vm.prank(vm.addr(1)); - rules.voteProposal(phase1JobId, phase2JobDetails); - assertTrue(rules.getProposalState(phase2JobHash) == ProposalStatus.Active); - - vm.roll(nowBlockNumber + expiry + 1); - vm.prank(vm.addr(2)); - rules.voteProposal(phase1JobId, phase2JobDetails); - assertTrue(rules.getProposalState(phase2JobHash) == ProposalStatus.Cancelled); - vm.expectRevert("proposal already executed/cancelled"); - vm.prank(vm.addr(2)); - rules.voteProposal(phase1JobId, phase2JobDetails); - } - - function test_adminFunctions() public { - uint64 phase1JobId = 1; - uint8 threshold = 2; - bool useDemocracy = false; - address[] memory voters = new address[](2); - voters[0] = vm.addr(1); - voters[1] = vm.addr(2); - uint40 expiry = 1000; - uint64 ttl = 1000; - rules.initialize(phase1JobId, threshold, useDemocracy, voters, expiry, ttl); - - rules.adminSetForwarder(phase1JobId, vm.addr(100), true); - assertTrue(rules.isValidForwarder(phase1JobId, vm.addr(100))); - assertFalse(rules.isValidForwarder(phase1JobId, vm.addr(101))); - - vm.expectRevert("Only admin can call this function"); - vm.prank(vm.addr(1)); - rules.adminSetForwarder(phase1JobId, vm.addr(100), false); - } -} diff --git a/node/Cargo.toml b/node/Cargo.toml index 86f6855c..6b69c2f0 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -145,3 +145,5 @@ txpool = ["fc-rpc/txpool"] fast-runtime = ["tangle-testnet-runtime/fast-runtime", "tangle-runtime/fast-runtime"] metadata-hash = ["tangle-testnet-runtime?/metadata-hash", "tangle-runtime/metadata-hash"] manual-seal = ["tangle-testnet-runtime/manual-seal"] +try-runtime = [] + diff --git a/pallets/services/src/functions.rs b/pallets/services/src/functions.rs index b05f45a7..947e11a9 100644 --- a/pallets/services/src/functions.rs +++ b/pallets/services/src/functions.rs @@ -9,36 +9,33 @@ use std::{boxed::Box, string::String, vec::Vec}; use ethabi::Token; use frame_support::dispatch::{DispatchErrorWithPostInfo, PostDispatchInfo}; use sp_core::{H160, U256}; -use sp_runtime::traits::{AccountIdConversion, UniqueSaturatedInto}; +use sp_runtime::traits::UniqueSaturatedInto; use tangle_primitives::services::{ BlueprintManager, Field, OperatorPreferences, Service, ServiceBlueprint, }; use super::*; +use crate::types::BalanceOf; +#[allow(clippy::too_many_arguments)] impl Pallet { /// Returns the account id of the pallet. /// /// This function retrieves the account id associated with the pallet by converting - /// the pallet id into an account id. + /// the pallet evm address to an account id. /// /// # Returns /// * `T::AccountId` - The account id of the pallet. pub fn account_id() -> T::AccountId { - T::PalletId::get().into_account_truncating() + T::EvmAddressMapping::into_account_id(Self::address()) } - /// Returns the address of the pallet. - /// - /// This function converts the account id of the pallet to a 20-byte H160 address. + /// Returns the EVM address of the pallet. /// /// # Returns /// * `H160` - The address of the pallet. pub fn address() -> H160 { - // Convert the account id to bytes. - let account_id = Self::account_id().encode(); - // Convert the first 20 bytes to an H160. - H160::from_slice(&account_id[0..20]) + T::PalletEVMAddress::get() } /// Hook to be called upon a new operator registration on a blueprint. @@ -50,6 +47,7 @@ impl Pallet { /// * `blueprint` - The service blueprint. /// * `prefrences` - The operator preferences. /// * `registration_args` - The registration arguments. + /// * `value` - The value to be sent with the call. /// /// # Returns /// * `Result<(bool, Weight), DispatchErrorWithPostInfo>` - A tuple containing a boolean indicating @@ -58,6 +56,7 @@ impl Pallet { blueprint: &ServiceBlueprint, prefrences: &OperatorPreferences, registration_args: &[Field], + value: BalanceOf, ) -> Result<(bool, Weight), DispatchErrorWithPostInfo> { let (allowed, weight) = match blueprint.manager { BlueprintManager::Evm(contract) => { @@ -65,11 +64,7 @@ impl Pallet { let call = ethabi::Function { name: String::from("onRegister"), inputs: vec![ - ethabi::Param { - name: String::from("operator"), - kind: ethabi::ParamType::Bytes, - internal_type: None, - }, + OperatorPreferences::to_ethabi_param(), ethabi::Param { name: String::from("registrationInputs"), kind: ethabi::ParamType::Bytes, @@ -80,17 +75,18 @@ impl Pallet { constant: None, state_mutability: ethabi::StateMutability::Payable, }; + let args = prefrences .to_ethabi() .into_iter() .chain(iter::once(Token::Bytes(Field::encode_to_ethabi(registration_args)))) .collect::>(); + let value = value.using_encoded(U256::from_little_endian); let data = call.encode_input(&args).map_err(|_| Error::::EVMAbiEncode)?; let gas_limit = 300_000; - let info = - Self::evm_call(Self::address(), contract, U256::from(0), data, gas_limit)?; + let info = Self::evm_call(Self::address(), contract, value, data, gas_limit)?; (info.exit_reason.is_succeed(), Self::weight_from_call_info(&info)) }, _ => (true, Weight::zero()), @@ -98,25 +94,222 @@ impl Pallet { Ok((allowed, weight)) } + /// Hook to be called upon an operator unregistration on a blueprint. + /// + /// This function is called when an operator is unregistered. It performs an EVM call + /// to the `onUnregister` function of the service blueprint's manager contract. + /// + /// # Parameters + /// * `blueprint` - The service blueprint. + /// * `prefrences` - The operator preferences. + /// + /// # Returns + /// * `Result<(bool, Weight), DispatchErrorWithPostInfo>` - A tuple containing a boolean indicating + /// whether the unregistration is allowed and the weight of the operation. + pub fn on_unregister_hook( + blueprint: &ServiceBlueprint, + prefrences: &OperatorPreferences, + ) -> Result<(bool, Weight), DispatchErrorWithPostInfo> { + match blueprint.manager { + BlueprintManager::Evm(contract) => { + #[allow(deprecated)] + let call = ethabi::Function { + name: String::from("onUnregister"), + inputs: vec![OperatorPreferences::to_ethabi_param()], + outputs: Default::default(), + constant: None, + state_mutability: ethabi::StateMutability::NonPayable, + }; + + let args = prefrences.to_ethabi(); + let data = call.encode_input(&args).map_err(|_| Error::::EVMAbiEncode)?; + let gas_limit = 300_000; + + let info = Self::evm_call(Self::address(), contract, 0.into(), data, gas_limit)?; + Ok((info.exit_reason.is_succeed(), Self::weight_from_call_info(&info))) + }, + _ => Ok((true, Weight::zero())), + } + } + + /// Hook to be called upon a new price targets update on a blueprint. + /// This function is called when the price targets are updated. It performs an EVM call + /// to the `onUpdatePriceTargets` function of the service blueprint's manager contract. + /// + /// # Parameters + /// * `blueprint` - The service blueprint. + /// * `prefrences` - The operator preferences. + /// + /// # Returns + /// + /// * `Result<(bool, Weight), DispatchErrorWithPostInfo>` - A tuple containing a boolean indicating + /// whether the price targets update is allowed and the weight of the operation. + pub fn on_update_price_targets( + blueprint: &ServiceBlueprint, + prefrences: &OperatorPreferences, + ) -> Result<(bool, Weight), DispatchErrorWithPostInfo> { + match blueprint.manager { + BlueprintManager::Evm(contract) => { + #[allow(deprecated)] + let call = ethabi::Function { + name: String::from("onUpdatePriceTargets"), + inputs: vec![OperatorPreferences::to_ethabi_param()], + outputs: Default::default(), + constant: None, + state_mutability: ethabi::StateMutability::Payable, + }; + + let args = prefrences.to_ethabi(); + let data = call.encode_input(&args).map_err(|_| Error::::EVMAbiEncode)?; + let gas_limit = 300_000; + + let info = Self::evm_call(Self::address(), contract, 0.into(), data, gas_limit)?; + Ok((info.exit_reason.is_succeed(), Self::weight_from_call_info(&info))) + }, + _ => Ok((true, Weight::zero())), + } + } + + /// Hook to be called upon an operator approve a service request on a blueprint. + /// + /// This function is called when an operator approve a service request. It performs an EVM call + /// to the `onApprove` function of the service blueprint's manager contract. + /// + /// # Parameters + /// * `blueprint` - The service blueprint. + /// * `prefrences` - The operator preferences. + /// * `request_id` - The request id. + /// * `restaking_percent` - The restaking percent. + /// + /// # Returns + /// * `Result<(bool, Weight), DispatchErrorWithPostInfo>` - A tuple containing a boolean indicating + /// whether the approve is allowed and the weight of the operation. + pub fn on_approve_hook( + blueprint: &ServiceBlueprint, + prefrences: &OperatorPreferences, + request_id: u64, + restaking_percent: u8, + ) -> Result<(bool, Weight), DispatchErrorWithPostInfo> { + match blueprint.manager { + BlueprintManager::Evm(contract) => { + #[allow(deprecated)] + let call = ethabi::Function { + name: String::from("onApprove"), + inputs: vec![ + OperatorPreferences::to_ethabi_param(), + ethabi::Param { + name: String::from("requestId"), + kind: ethabi::ParamType::Uint(64), + internal_type: None, + }, + ethabi::Param { + name: String::from("restakingPercent"), + kind: ethabi::ParamType::Uint(8), + internal_type: None, + }, + ], + outputs: Default::default(), + constant: None, + state_mutability: ethabi::StateMutability::NonPayable, + }; + + let args = prefrences + .to_ethabi() + .into_iter() + .chain(iter::once(Token::Uint(U256::from(request_id)))) + .chain(iter::once(Token::Uint(U256::from(restaking_percent)))) + .collect::>(); + + let data = call.encode_input(&args).map_err(|_| Error::::EVMAbiEncode)?; + let gas_limit = 300_000; + + let info = Self::evm_call(Self::address(), contract, 0.into(), data, gas_limit)?; + Ok((info.exit_reason.is_succeed(), Self::weight_from_call_info(&info))) + }, + _ => Ok((true, Weight::zero())), + } + } + + /// Hook to be called upon an operator reject a service request on a blueprint. + /// This function is called when an operator reject a service request. It performs an EVM call + /// to the `onReject` function of the service blueprint's manager contract. + /// + /// # Parameters + /// * `blueprint` - The service blueprint. + /// * `prefrences` - The operator preferences. + /// * `request_id` - The request id. + /// + /// # Returns + /// * `Result<(bool, Weight), DispatchErrorWithPostInfo>` - A tuple containing a boolean indicating + /// whether the reject is allowed and the weight of the operation. + pub fn on_reject_hook( + blueprint: &ServiceBlueprint, + prefrences: &OperatorPreferences, + request_id: u64, + ) -> Result<(bool, Weight), DispatchErrorWithPostInfo> { + match blueprint.manager { + BlueprintManager::Evm(contract) => { + #[allow(deprecated)] + let call = ethabi::Function { + name: String::from("onReject"), + inputs: vec![ + OperatorPreferences::to_ethabi_param(), + ethabi::Param { + name: String::from("requestId"), + kind: ethabi::ParamType::Uint(64), + internal_type: None, + }, + ], + outputs: Default::default(), + constant: None, + state_mutability: ethabi::StateMutability::NonPayable, + }; + + let args = prefrences + .to_ethabi() + .into_iter() + .chain(iter::once(Token::Uint(U256::from(request_id)))) + .collect::>(); + + let data = call.encode_input(&args).map_err(|_| Error::::EVMAbiEncode)?; + let gas_limit = 300_000; + + let info = Self::evm_call(Self::address(), contract, 0.into(), data, gas_limit)?; + Ok((info.exit_reason.is_succeed(), Self::weight_from_call_info(&info))) + }, + _ => Ok((true, Weight::zero())), + } + } + /// Hook to be called upon new service request. /// /// This function is called when a service request is made. It performs an EVM call /// to the `onRequest` function of the service blueprint's manager contract. /// /// # Parameters + /// * `requester` - The requester of the service. /// * `blueprint` - The service blueprint. - /// * `service_id` - The service ID. + /// * `request_id` - The service request ID. /// * `operators` - The operator preferences. /// * `request_args` - The request arguments. + /// * `permitted_callers` - The permitted callers. + /// * `assets` - The assets to be used. + /// * `ttl` - The time to live. + /// * `value` - The value to be sent with the call. /// /// # Returns /// * `Result<(bool, Weight), DispatchErrorWithPostInfo>` - A tuple containing a boolean indicating /// whether the request is allowed and the weight of the operation. pub fn on_request_hook( + requester: &T::AccountId, blueprint: &ServiceBlueprint, - service_id: u64, + request_id: u64, operators: &[OperatorPreferences], request_args: &[Field], + permitted_callers: &[T::AccountId], + _assets: &[T::AssetId], + ttl: BlockNumberFor, + value: BalanceOf, ) -> Result<(bool, Weight), DispatchErrorWithPostInfo> { let (allowed, weight) = match blueprint.manager { BlueprintManager::Evm(contract) => { @@ -125,42 +318,234 @@ impl Pallet { name: String::from("onRequest"), inputs: vec![ ethabi::Param { - name: String::from("serviceId"), + name: String::from("requestId"), kind: ethabi::ParamType::Uint(64), internal_type: None, }, ethabi::Param { - name: String::from("operators"), - kind: ethabi::ParamType::Array(Box::new(ethabi::ParamType::Bytes)), + name: String::from("requester"), + kind: ethabi::ParamType::Address, internal_type: None, }, + ethabi::Param { + name: String::from("operatorsWithPreferences"), + kind: ethabi::ParamType::Array(Box::new( + OperatorPreferences::to_ethabi_param_type(), + )), + internal_type: Some(String::from("OperatorPreferences[]")), + }, ethabi::Param { name: String::from("requestInputs"), kind: ethabi::ParamType::Bytes, internal_type: None, }, + ethabi::Param { + name: String::from("permittedCallers"), + kind: ethabi::ParamType::Array(Box::new(ethabi::ParamType::Address)), + internal_type: Some(String::from("address[]")), + }, + // ethabi::Param { + // name: String::from("assets"), + // kind: ethabi::ParamType::Array(Box::new(ethabi::ParamType::Address)), + // internal_type: Some(String::from("address[]")), + // }, + ethabi::Param { + name: String::from("ttl"), + kind: ethabi::ParamType::Uint(64), + internal_type: None, + }, ], outputs: Default::default(), constant: None, state_mutability: ethabi::StateMutability::Payable, }; - let service_id = Token::Uint(ethabi::Uint::from(service_id)); + let request_id = Token::Uint(ethabi::Uint::from(request_id)); + let requester = + Token::Address(T::EvmAddressMapping::into_address(requester.clone())); let operators = Token::Array( operators.iter().flat_map(OperatorPreferences::to_ethabi).collect(), ); let request_args = Token::Bytes(Field::encode_to_ethabi(request_args)); + let permitted_callers = Token::Array( + permitted_callers + .iter() + .map(|caller| { + Token::Address(T::EvmAddressMapping::into_address(caller.clone())) + }) + .collect(), + ); + // TODO: Implement asset mapping or when we have AssetIds as an enum. + // let assets = Token::Array(vec![]); + let ttl = Token::Uint(ethabi::Uint::from(ttl.into())); let data = call - .encode_input(&[service_id, operators, request_args]) + .encode_input(&[ + request_id, + requester, + operators, + request_args, + permitted_callers, + // assets, + ttl, + ]) .map_err(|_| Error::::EVMAbiEncode)?; + let value = value.using_encoded(U256::from_little_endian); let gas_limit = 300_000; - let info = - Self::evm_call(Self::address(), contract, U256::from(0), data, gas_limit)?; + let info = Self::evm_call(Self::address(), contract, value, data, gas_limit)?; + (info.exit_reason.is_succeed(), Self::weight_from_call_info(&info)) + }, + _ => (true, Weight::zero()), + }; + + Ok((allowed, weight)) + } + + /// Hook to be called when a service is initialized. This function will call the `onServiceInitialized` + /// function of the service blueprint manager contract. + /// + /// # Arguments + /// * `blueprint` - The service blueprint. + /// * `request_id` - The service request ID. + /// * `service_id` - The service ID. + /// * `owner` - The owner of the service. + /// * `permitted_callers` - The permitted callers. + /// * `assets` - The assets to be used. + /// * `ttl` - The time to live. + /// + /// # Returns + /// * `Result<(bool, Weight), DispatchErrorWithPostInfo>` - A tuple containing a boolean indicating + /// whether the request is allowed and the weight of the operation. + pub fn on_service_init_hook( + blueprint: &ServiceBlueprint, + request_id: u64, + service_id: u64, + owner: &T::AccountId, + permitted_callers: &[T::AccountId], + _assets: &[T::AssetId], + ttl: BlockNumberFor, + ) -> Result<(bool, Weight), DispatchErrorWithPostInfo> { + let (allowed, weight) = match blueprint.manager { + BlueprintManager::Evm(contract) => { + #[allow(deprecated)] + let call = ethabi::Function { + name: String::from("onServiceInitialized"), + inputs: vec![ + ethabi::Param { + name: String::from("requestId"), + kind: ethabi::ParamType::Uint(64), + internal_type: None, + }, + ethabi::Param { + name: String::from("serviceId"), + kind: ethabi::ParamType::Uint(64), + internal_type: None, + }, + ethabi::Param { + name: String::from("owner"), + kind: ethabi::ParamType::Address, + internal_type: None, + }, + ethabi::Param { + name: String::from("permittedCallers"), + kind: ethabi::ParamType::Array(Box::new(ethabi::ParamType::Address)), + internal_type: Some(String::from("address[]")), + }, + // ethabi::Param { + // name: String::from("assets"), + // kind: ethabi::ParamType::Array(Box::new(ethabi::ParamType::Address)), + // internal_type: Some(String::from("address[]")), + // }, + ethabi::Param { + name: String::from("ttl"), + kind: ethabi::ParamType::Uint(64), + internal_type: None, + }, + ], + outputs: Default::default(), + constant: None, + state_mutability: ethabi::StateMutability::Payable, + }; + let request_id = Token::Uint(ethabi::Uint::from(request_id)); + let service_id = Token::Uint(ethabi::Uint::from(service_id)); + let owner = Token::Address(T::EvmAddressMapping::into_address(owner.clone())); + let permitted_callers = Token::Array( + permitted_callers + .iter() + .map(|caller| { + Token::Address(T::EvmAddressMapping::into_address(caller.clone())) + }) + .collect(), + ); + let ttl = Token::Uint(ethabi::Uint::from(ttl.into())); + let data = call + .encode_input(&[ + request_id, + service_id, + owner, + permitted_callers, + // assets, + ttl, + ]) + .map_err(|_| Error::::EVMAbiEncode)?; + let value = U256::zero(); + let gas_limit = 300_000; + let info = Self::evm_call(Self::address(), contract, value, data, gas_limit)?; (info.exit_reason.is_succeed(), Self::weight_from_call_info(&info)) }, _ => (true, Weight::zero()), }; + Ok((allowed, weight)) + } + /// Hook to be called when a service is terminated. This function will call the `onServiceTermination` + /// function of the service blueprint manager contract. + /// + /// # Arguments + /// * `blueprint` - The service blueprint. + /// * `service_id` - The service ID. + /// * `owner` - The owner of the service. + /// + /// # Returns + /// * `Result<(bool, Weight), DispatchErrorWithPostInfo>` - A tuple containing a boolean indicating + /// whether the request is allowed and the weight of the operation. + pub fn on_service_termination_hook( + blueprint: &ServiceBlueprint, + service_id: u64, + owner: &T::AccountId, + ) -> Result<(bool, Weight), DispatchErrorWithPostInfo> { + let (allowed, weight) = match blueprint.manager { + BlueprintManager::Evm(contract) => { + #[allow(deprecated)] + let call = ethabi::Function { + name: String::from("onServiceTermination"), + inputs: vec![ + ethabi::Param { + name: String::from("serviceId"), + kind: ethabi::ParamType::Uint(64), + internal_type: None, + }, + ethabi::Param { + name: String::from("owner"), + kind: ethabi::ParamType::Address, + internal_type: None, + }, + ], + outputs: Default::default(), + constant: None, + state_mutability: ethabi::StateMutability::NonPayable, + }; + let service_id = Token::Uint(ethabi::Uint::from(service_id)); + let owner = Token::Address(T::EvmAddressMapping::into_address(owner.clone())); + let data = call + .encode_input(&[service_id, owner]) + .map_err(|_| Error::::EVMAbiEncode)?; + let value = U256::zero(); + let gas_limit = 300_000; + let info = Self::evm_call(Self::address(), contract, value, data, gas_limit)?; + (info.exit_reason.is_succeed(), Self::weight_from_call_info(&info)) + }, + _ => (true, Weight::zero()), + }; Ok((allowed, weight)) } @@ -282,11 +667,7 @@ impl Pallet { kind: ethabi::ParamType::Uint(64), internal_type: None, }, - ethabi::Param { - name: String::from("operator"), - kind: ethabi::ParamType::Bytes, - internal_type: None, - }, + OperatorPreferences::to_ethabi_param(), ethabi::Param { name: String::from("inputs"), kind: ethabi::ParamType::Bytes, @@ -476,6 +857,13 @@ impl Pallet { hex::encode(&data), hex::encode(&info.value), ); + #[cfg(test)] + eprintln!( + "Call to: {:?} with data: 0x{} Reverted with reason: (0x{})", + to, + hex::encode(&data), + hex::encode(&info.value), + ); Self::deposit_event(Event::::EvmReverted { from, to, diff --git a/pallets/services/src/lib.rs b/pallets/services/src/lib.rs index 5cd736d0..1ddf855a 100644 --- a/pallets/services/src/lib.rs +++ b/pallets/services/src/lib.rs @@ -23,8 +23,7 @@ extern crate alloc; use frame_support::{ pallet_prelude::*, - traits::{Currency, ReservableCurrency}, - PalletId, + traits::{Currency, ExistenceRequirement, ReservableCurrency}, }; use frame_system::pallet_prelude::*; use sp_runtime::{traits::Get, DispatchResult}; @@ -54,6 +53,7 @@ pub use weights::WeightInfo; #[cfg(feature = "runtime-benchmarks")] pub use impls::BenchmarkingOperatorDelegationManager; +#[allow(clippy::too_many_arguments)] #[frame_support::pallet(dev_mode)] pub mod module { use super::*; @@ -76,9 +76,9 @@ pub mod module { /// The currency mechanism. type Currency: ReservableCurrency; - /// `PalletId` for the services pallet. + /// `Pallet` EVM Address. #[pallet::constant] - type PalletId: Get; + type PalletEVMAddress: Get; /// A type that implements the `EvmRunner` trait for the execution of EVM /// transactions. @@ -188,6 +188,16 @@ pub mod module { type WeightInfo: WeightInfo; } + #[pallet::hooks] + impl Hooks> for Pallet { + fn integrity_test() { + // Ensure that the pallet's configuration is valid. + // 1. Make sure that pallet's associated AccountId value maps correctly to the EVM address. + let account_id = T::EvmAddressMapping::into_account_id(Self::address()); + assert_eq!(account_id, Self::account_id(), "Services: AccountId mapping is incorrect."); + } + } + #[pallet::error] pub enum Error { /// The service blueprint was not found. @@ -196,6 +206,10 @@ pub mod module { AlreadyRegistered, /// The caller does not have the requirements to be a operator. InvalidRegistrationInput, + /// The Operator is not allowed to unregister. + NotAllowedToUnregister, + /// The Operator is not allowed to update their price targets. + NotAllowedToUpdatePriceTargets, /// The caller does not have the requirements to request a service. InvalidRequestInput, /// The caller does not have the requirements to call a job. @@ -204,10 +218,18 @@ pub mod module { InvalidJobResult, /// The caller is not registered as a operator. NotRegistered, + /// Approval Process is interrupted. + ApprovalInterrupted, + /// Rejection Process is interrupted. + RejectionInterrupted, /// The service request was not found. ServiceRequestNotFound, + /// Service Initialization interrupted. + ServiceInitializationInterrupted, /// The service was not found. ServiceNotFound, + /// The termination of the service was interrupted. + TerminationInterrupted, /// An error occurred while type checking the provided input input. TypeCheck(TypeCheckError), /// The maximum number of permitted callers per service has been exceeded. @@ -637,6 +659,7 @@ pub mod module { #[pallet::compact] blueprint_id: u64, preferences: OperatorPreferences, registration_args: Vec>, + #[pallet::compact] value: BalanceOf, ) -> DispatchResultWithPostInfo { let caller = ensure_signed(origin)?; let (_, blueprint) = Self::blueprints(blueprint_id)?; @@ -652,8 +675,16 @@ pub mod module { .type_check_registration(®istration_args) .map_err(Error::::TypeCheck)?; + // Transfer the registration value to the pallet + T::Currency::transfer( + &caller, + &Self::account_id(), + value, + ExistenceRequirement::KeepAlive, + )?; + let (allowed, _weight) = - Self::on_register_hook(&blueprint, &preferences, ®istration_args)?; + Self::on_register_hook(&blueprint, &preferences, ®istration_args, value)?; ensure!(allowed, Error::::InvalidRegistrationInput); @@ -698,11 +729,12 @@ pub mod module { pub fn unregister( origin: OriginFor, #[pallet::compact] blueprint_id: u64, - ) -> DispatchResult { + ) -> DispatchResultWithPostInfo { let caller = ensure_signed(origin)?; - ensure!(Blueprints::::contains_key(blueprint_id), Error::::BlueprintNotFound); - let registered = Operators::::contains_key(blueprint_id, &caller); - ensure!(registered, Error::::NotRegistered); + let (_, blueprint) = Self::blueprints(blueprint_id)?; + let preferences = Operators::::get(blueprint_id, &caller)?; + let (allowed, _weight) = Self::on_unregister_hook(&blueprint, &preferences)?; + ensure!(allowed, Error::::NotAllowedToUnregister); // TODO: check if the caller is not providing any service for the blueprint. Operators::::remove(blueprint_id, &caller); @@ -716,7 +748,8 @@ pub mod module { ensure!(removed, Error::::NotRegistered); Self::deposit_event(Event::Unregistered { operator: caller.clone(), blueprint_id }); - Ok(()) + // TODO: update weight for the unregistration. + Ok(PostDispatchInfo { actual_weight: None, pays_fee: Pays::Yes }) } /// Update the price targets for the caller for a specific service blueprint. @@ -727,22 +760,32 @@ pub mod module { origin: OriginFor, #[pallet::compact] blueprint_id: u64, price_targets: PriceTargets, - ) -> DispatchResult { + ) -> DispatchResultWithPostInfo { let caller = ensure_signed(origin)?; - ensure!(Blueprints::::contains_key(blueprint_id), Error::::BlueprintNotFound); - Operators::::try_mutate_exists(blueprint_id, &caller, |current_preferences| { - current_preferences - .as_mut() - .map(|v| v.price_targets = price_targets) - .ok_or(Error::::NotRegistered) - })?; + let (_, blueprint) = Self::blueprints(blueprint_id)?; + + let updated_preferences = + Operators::::try_mutate_exists(blueprint_id, &caller, |current_preferences| { + current_preferences + .as_mut() + .map(|v| { + v.price_targets = price_targets; + *v + }) + .ok_or(Error::::NotRegistered) + })?; + + let (allowed, _weight) = + Self::on_update_price_targets(&blueprint, &updated_preferences)?; + + ensure!(allowed, Error::::NotAllowedToUpdatePriceTargets); Self::deposit_event(Event::PriceTargetsUpdated { operator: caller.clone(), blueprint_id, price_targets, }); - Ok(()) + Ok(PostDispatchInfo { actual_weight: None, pays_fee: Pays::Yes }) } /// Request a new service to be initiated using the provided blueprint with a list of @@ -757,6 +800,7 @@ pub mod module { request_args: Vec>, assets: Vec, #[pallet::compact] ttl: BlockNumberFor, + #[pallet::compact] value: BalanceOf, ) -> DispatchResultWithPostInfo { let caller = ensure_signed(origin)?; let (_, blueprint) = Self::blueprints(blueprint_id)?; @@ -773,9 +817,26 @@ pub mod module { preferences.push(prefs); } + // Transfer the request value to the pallet + T::Currency::transfer( + &caller, + &Self::account_id(), + value, + ExistenceRequirement::KeepAlive, + )?; + let service_id = Self::next_instance_id(); - let (allowed, _weight) = - Self::on_request_hook(&blueprint, service_id, &preferences, &request_args)?; + let (allowed, _weight) = Self::on_request_hook( + &caller, + &blueprint, + service_id, + &preferences, + &request_args, + &permitted_callers, + &assets, + ttl, + value, + )?; ensure!(allowed, Error::::InvalidRequestInput); @@ -832,7 +893,7 @@ pub mod module { origin: OriginFor, #[pallet::compact] request_id: u64, #[pallet::compact] restaking_percent: Percent, - ) -> DispatchResult { + ) -> DispatchResultWithPostInfo { let caller = ensure_signed(origin)?; let mut request = Self::service_requests(request_id)?; let updated = request @@ -842,6 +903,8 @@ pub mod module { .map(|(_, s)| *s = ApprovalState::Approved { restaking_percent }); ensure!(updated.is_some(), Error::::ApprovalNotRequested); + let (_, blueprint) = Self::blueprints(request.blueprint)?; + let preferences = Operators::::get(request.blueprint, caller.clone())?; let approved = request .operators_with_approval_state .iter() @@ -861,6 +924,14 @@ pub mod module { ) .collect::>(); + let (allowed, _weight) = Self::on_approve_hook( + &blueprint, + &preferences, + request_id, + restaking_percent.deconstruct(), + )?; + + ensure!(allowed, Error::::ApprovalInterrupted); // we emit this event regardless of the outcome of the approval. Self::deposit_event(Event::ServiceRequestApproved { operator: caller.clone(), @@ -916,6 +987,18 @@ pub mod module { .map_err(|_| Error::::MaxServicesPerUserExceeded) })?; + let (allowed, _weight) = Self::on_service_init_hook( + &blueprint, + request_id, + service_id, + &request.owner, + &request.permitted_callers, + &request.assets, + request.ttl, + )?; + + ensure!(allowed, Error::::ServiceInitializationInterrupted); + Self::deposit_event(Event::ServiceInitiated { owner: request.owner, request_id, @@ -927,40 +1010,45 @@ pub mod module { // Update the service request. ServiceRequests::::insert(request_id, request); } - Ok(()) + + Ok(PostDispatchInfo { actual_weight: None, pays_fee: Pays::Yes }) } /// Reject a service request. /// The service will not be initiated, and the requester will need to update the service /// request. #[pallet::weight(T::WeightInfo::reject())] - pub fn reject(origin: OriginFor, #[pallet::compact] request_id: u64) -> DispatchResult { + pub fn reject( + origin: OriginFor, + #[pallet::compact] request_id: u64, + ) -> DispatchResultWithPostInfo { let caller = ensure_signed(origin)?; - let updated = ServiceRequests::::try_mutate_exists(request_id, |maybe_request| { - maybe_request - .as_mut() - .map(|r| { - r.operators_with_approval_state.iter_mut().find_map(|(v, s)| { - if v == &caller { - *s = ApprovalState::Rejected; - Some(r.blueprint) - } else { - None - } - }) - }) - .ok_or(Error::::ServiceRequestNotFound) - })?; - match updated { - Some(blueprint_id) => Self::deposit_event(Event::ServiceRequestRejected { - operator: caller.clone(), - request_id, - blueprint_id, - }), - None => return Err(Error::::ApprovalNotRequested.into()), - }; + let mut request = Self::service_requests(request_id)?; + let updated = request.operators_with_approval_state.iter_mut().find_map(|(v, s)| { + if v == &caller { + *s = ApprovalState::Rejected; + Some(()) + } else { + None + } + }); - Ok(()) + ensure!(updated.is_some(), Error::::ApprovalNotRequested); + + let (_, blueprint) = Self::blueprints(request.blueprint)?; + let prefs = Operators::::get(request.blueprint, caller.clone())?; + + let (allowed, _weight) = Self::on_reject_hook(&blueprint, &prefs, request_id)?; + + ensure!(allowed, Error::::RejectionInterrupted); + Self::deposit_event(Event::ServiceRequestRejected { + operator: caller, + blueprint_id: request.blueprint, + request_id, + }); + + // TODO: make use of the returned weight from the hook. + Ok(PostDispatchInfo { actual_weight: None, pays_fee: Pays::Yes }) } /// Terminates the service by the owner of the service. @@ -968,7 +1056,7 @@ pub mod module { pub fn terminate( origin: OriginFor, #[pallet::compact] service_id: u64, - ) -> DispatchResult { + ) -> DispatchResultWithPostInfo { let caller = ensure_signed(origin)?; let service = Self::services(service_id)?; // TODO: allow permissioned callers to terminate the service? @@ -978,6 +1066,11 @@ pub mod module { })?; ensure!(removed, Error::::ServiceNotFound); Instances::::remove(service_id); + let (_, blueprint) = Self::blueprints(service.blueprint)?; + let (allowed, _weight) = + Self::on_service_termination_hook(&blueprint, service_id, &service.owner)?; + + ensure!(allowed, Error::::TerminationInterrupted); // Remove the service from the operator's profile. for (operator, _) in &service.operators { OperatorsProfile::::try_mutate_exists(operator, |profile| { @@ -993,7 +1086,7 @@ pub mod module { service_id, blueprint_id: service.blueprint, }); - Ok(()) + Ok(PostDispatchInfo { actual_weight: None, pays_fee: Pays::Yes }) } /// Call a Job in the service. diff --git a/pallets/services/src/mock.rs b/pallets/services/src/mock.rs index a3a4f3ca..f54f0efd 100644 --- a/pallets/services/src/mock.rs +++ b/pallets/services/src/mock.rs @@ -204,7 +204,7 @@ impl pallet_staking::Config for Runtime { } parameter_types! { - pub const ServicesPalletId: PalletId = PalletId(*b"py/srvcs"); + pub const ServicesEVMAddress: H160 = H160([0x11; 20]); } pub struct PalletEVMGasWeightMapping; @@ -226,6 +226,14 @@ impl EvmAddressMapping for PalletEVMAddressMapping { use pallet_evm::AddressMapping; ::AddressMapping::into_account_id(address) } + + fn into_address(account_id: AccountId) -> H160 { + account_id.using_encoded(|b| { + let mut addr = [0u8; 20]; + addr.copy_from_slice(&b[0..20]); + H160(addr) + }) + } } pub type AssetId = u32; @@ -364,7 +372,7 @@ impl Config for Runtime { type RuntimeEvent = RuntimeEvent; type ForceOrigin = frame_system::EnsureRoot; type Currency = Balances; - type PalletId = ServicesPalletId; + type PalletEVMAddress = ServicesEVMAddress; type AssetId = AssetId; type EvmRunner = MockedEvmRunner; type EvmGasWeightMapping = PalletEVMGasWeightMapping; diff --git a/pallets/services/src/test-artifacts/CGGMP21Blueprint.json b/pallets/services/src/test-artifacts/CGGMP21Blueprint.json index db2270be..00708c59 100644 --- a/pallets/services/src/test-artifacts/CGGMP21Blueprint.json +++ b/pallets/services/src/test-artifacts/CGGMP21Blueprint.json @@ -1 +1 @@ -{"abi":[{"type":"function","name":"ROOT_CHAIN","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"blueprintOperators","inputs":[{"name":"","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"addr","type":"address","internalType":"address"},{"name":"publicKey","type":"bytes","internalType":"bytes"}],"stateMutability":"view"},{"type":"function","name":"keygens","inputs":[{"name":"","type":"uint64","internalType":"uint64"},{"name":"","type":"uint64","internalType":"uint64"}],"outputs":[{"name":"","type":"uint8","internalType":"uint8"}],"stateMutability":"view"},{"type":"function","name":"onJobCall","inputs":[{"name":"serviceId","type":"uint64","internalType":"uint64"},{"name":"job","type":"uint8","internalType":"uint8"},{"name":"jobCallId","type":"uint64","internalType":"uint64"},{"name":"inputs","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"payable"},{"type":"function","name":"onJobResult","inputs":[{"name":"serviceId","type":"uint64","internalType":"uint64"},{"name":"job","type":"uint8","internalType":"uint8"},{"name":"jobCallId","type":"uint64","internalType":"uint64"},{"name":"participant","type":"bytes","internalType":"bytes"},{"name":"inputs","type":"bytes","internalType":"bytes"},{"name":"outputs","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"payable"},{"type":"function","name":"onRegister","inputs":[{"name":"operator","type":"bytes","internalType":"bytes"},{"name":"registrationInputs","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"payable"},{"type":"function","name":"onRequest","inputs":[{"name":"serviceId","type":"uint64","internalType":"uint64"},{"name":"operators","type":"bytes[]","internalType":"bytes[]"},{"name":"requestInputs","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"payable"},{"type":"function","name":"onSlash","inputs":[{"name":"serviceId","type":"uint64","internalType":"uint64"},{"name":"offender","type":"bytes","internalType":"bytes"},{"name":"slashPercent","type":"uint8","internalType":"uint8"},{"name":"totalPayout","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"onUnappliedSlash","inputs":[{"name":"serviceId","type":"uint64","internalType":"uint64"},{"name":"offender","type":"bytes","internalType":"bytes"},{"name":"slashPercent","type":"uint8","internalType":"uint8"},{"name":"totalPayout","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"operatorAddressFromPublicKey","inputs":[{"name":"publicKey","type":"bytes","internalType":"bytes"}],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"pure"},{"type":"function","name":"queryDisputeOrigin","inputs":[{"name":"serviceId","type":"uint64","internalType":"uint64"}],"outputs":[{"name":"disputeOrigin","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"querySlashingOrigin","inputs":[{"name":"serviceId","type":"uint64","internalType":"uint64"}],"outputs":[{"name":"slashingOrigin","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"services","inputs":[{"name":"","type":"uint64","internalType":"uint64"}],"outputs":[{"name":"id","type":"uint64","internalType":"uint64"}],"stateMutability":"view"},{"type":"error","name":"InvalidDKGThreshold","inputs":[]},{"type":"error","name":"InvalidJob","inputs":[]},{"type":"error","name":"InvalidRequestInputs","inputs":[]},{"type":"error","name":"KeygenJobNotFound","inputs":[]}],"bytecode":{"object":"0x6080604052348015600f57600080fd5b50610e7c8061001f6000396000f3fe6080604052600436106100c25760003560e01c8063884673ac1161007f578063d32e11e211610059578063d32e11e21461021d578063d4e5fe2714610230578063e40b0d491461025e578063e926cbd1146100c757600080fd5b8063884673ac146101d45780639838caa3146101f7578063a7c66f861461020a57600080fd5b80630af7d743146100c757806314b4df4c146100e957806334a324e41461012657806356270e17146101735780636dfee236146101c157806374ceeb55146100e9575b600080fd5b3480156100d357600080fd5b506100e76100e236600461081d565b61027e565b005b3480156100f557600080fd5b50610109610104366004610889565b503090565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561013257600080fd5b506101616101413660046108ab565b600160209081526000928352604080842090915290825290205460ff1681565b60405160ff909116815260200161011d565b34801561017f57600080fd5b506101a961018e366004610889565b6002602052600090815260409020546001600160401b031681565b6040516001600160401b03909116815260200161011d565b6100e76101cf3660046108de565b6102bc565b3480156101e057600080fd5b506101096b6d6f646c70792f737276637360401b81565b6100e761020536600461098f565b610446565b6100e76102183660046109f3565b6105a3565b6100e761022b366004610a5e565b61068b565b34801561023c57600080fd5b5061025061024b366004610b2b565b6106c4565b60405161011d929190610b44565b34801561026a57600080fd5b50610109610279366004610ba3565b610786565b336b6d6f646c70792f737276637360401b146102b55760405162461bcd60e51b81526004016102ac90610be4565b60405180910390fd5b5050505050565b336b6d6f646c70792f737276637360401b146102ea5760405162461bcd60e51b81526004016102ac90610be4565b80156103095760405163702e9b1960e11b815260040160405180910390fd5b6001600160401b0385166000818152600260205260408120805467ffffffffffffffff191690921782555b8481101561043d57600061036587878481811061035357610353610c35565b90506020028101906102799190610c4b565b9050826001016040518060400160405280836001600160a01b0316815260200189898681811061039757610397610c35565b90506020028101906103a99190610c4b565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920182905250939094525050835460018082018655948252602091829020845160029092020180546001600160a01b0319166001600160a01b039092169190911781559083015192939092908301915061042d9082610d32565b5050600190920191506103349050565b50505050505050565b336b6d6f646c70792f737276637360401b146104745760405162461bcd60e51b81526004016102ac90610be4565b60ff841661051657600061048a82840184610df1565b6001600160401b03871660009081526002602052604090206001015490915060ff821615806104bb5750808260ff16115b156104d95760405163b65cad8d60e01b815260040160405180910390fd5b506001600160401b038681166000908152600160209081526040808320938816835292905220805460ff191660ff929092169190911790556102b5565b60001960ff85160161058a5760008061053183850185610e0c565b6001600160401b03808a16600090815260016020908152604080832093861683529290529081205492945090925060ff90911690036105835760405163648bd07f60e11b815260040160405180910390fd5b50506102b5565b60405163038e47a360e51b815260040160405180910390fd5b336b6d6f646c70792f737276637360401b146105d15760405162461bcd60e51b81526004016102ac90610be4565b60006105dd8585610786565b905060006040518060400160405280836001600160a01b0316815260200187878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920182905250939094525050835460018082018655948252602091829020845160029092020180546001600160a01b0319166001600160a01b03909216919091178155908301519293909290830191506106819082610d32565b5050505050505050565b336b6d6f646c70792f737276637360401b146106b95760405162461bcd60e51b81526004016102ac90610be4565b505050505050505050565b600081815481106106d457600080fd5b6000918252602090912060029091020180546001820180546001600160a01b0390921693509061070390610ca7565b80601f016020809104026020016040519081016040528092919081815260200182805461072f90610ca7565b801561077c5780601f106107515761010080835404028352916020019161077c565b820191906000526020600020905b81548152906001019060200180831161075f57829003601f168201915b5050505050905082565b60008282604051610798929190610e36565b6040519081900390209392505050565b80356001600160401b03811681146107bf57600080fd5b919050565b60008083601f8401126107d657600080fd5b5081356001600160401b038111156107ed57600080fd5b60208301915083602082850101111561080557600080fd5b9250929050565b803560ff811681146107bf57600080fd5b60008060008060006080868803121561083557600080fd5b61083e866107a8565b945060208601356001600160401b0381111561085957600080fd5b610865888289016107c4565b909550935061087890506040870161080c565b949793965091946060013592915050565b60006020828403121561089b57600080fd5b6108a4826107a8565b9392505050565b600080604083850312156108be57600080fd5b6108c7836107a8565b91506108d5602084016107a8565b90509250929050565b6000806000806000606086880312156108f657600080fd5b6108ff866107a8565b945060208601356001600160401b038082111561091b57600080fd5b818801915088601f83011261092f57600080fd5b81358181111561093e57600080fd5b8960208260051b850101111561095357600080fd5b60208301965080955050604088013591508082111561097157600080fd5b5061097e888289016107c4565b969995985093965092949392505050565b6000806000806000608086880312156109a757600080fd5b6109b0866107a8565b94506109be6020870161080c565b93506109cc604087016107a8565b925060608601356001600160401b038111156109e757600080fd5b61097e888289016107c4565b60008060008060408587031215610a0957600080fd5b84356001600160401b0380821115610a2057600080fd5b610a2c888389016107c4565b90965094506020870135915080821115610a4557600080fd5b50610a52878288016107c4565b95989497509550505050565b600080600080600080600080600060c08a8c031215610a7c57600080fd5b610a858a6107a8565b9850610a9360208b0161080c565b9750610aa160408b016107a8565b965060608a01356001600160401b0380821115610abd57600080fd5b610ac98d838e016107c4565b909850965060808c0135915080821115610ae257600080fd5b610aee8d838e016107c4565b909650945060a08c0135915080821115610b0757600080fd5b50610b148c828d016107c4565b915080935050809150509295985092959850929598565b600060208284031215610b3d57600080fd5b5035919050565b60018060a01b03831681526000602060406020840152835180604085015260005b81811015610b8157858101830151858201606001528201610b65565b506000606082860101526060601f19601f830116850101925050509392505050565b60008060208385031215610bb657600080fd5b82356001600160401b03811115610bcc57600080fd5b610bd8858286016107c4565b90969095509350505050565b60208082526031908201527f526f6f74436861696e3a204f6e6c7920726f6f7420636861696e2063616e206360408201527030b636103a3434b990333ab731ba34b7b760791b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b6000808335601e19843603018112610c6257600080fd5b8301803591506001600160401b03821115610c7c57600080fd5b60200191503681900382131561080557600080fd5b634e487b7160e01b600052604160045260246000fd5b600181811c90821680610cbb57607f821691505b602082108103610cdb57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115610d2d576000816000526020600020601f850160051c81016020861015610d0a5750805b601f850160051c820191505b81811015610d2957828155600101610d16565b5050505b505050565b81516001600160401b03811115610d4b57610d4b610c91565b610d5f81610d598454610ca7565b84610ce1565b602080601f831160018114610d945760008415610d7c5750858301515b600019600386901b1c1916600185901b178555610d29565b600085815260208120601f198616915b82811015610dc357888601518255948401946001909101908401610da4565b5085821015610de15787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060208284031215610e0357600080fd5b6108a48261080c565b60008060408385031215610e1f57600080fd5b610e28836107a8565b946020939093013593505050565b818382376000910190815291905056fea264697066735822122055f3e02035080f611479594acd7a82f0f041619f35935466925bece4c675178164736f6c63430008190033","sourceMap":"236:3072:28:-:0;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x6080604052600436106100c25760003560e01c8063884673ac1161007f578063d32e11e211610059578063d32e11e21461021d578063d4e5fe2714610230578063e40b0d491461025e578063e926cbd1146100c757600080fd5b8063884673ac146101d45780639838caa3146101f7578063a7c66f861461020a57600080fd5b80630af7d743146100c757806314b4df4c146100e957806334a324e41461012657806356270e17146101735780636dfee236146101c157806374ceeb55146100e9575b600080fd5b3480156100d357600080fd5b506100e76100e236600461081d565b61027e565b005b3480156100f557600080fd5b50610109610104366004610889565b503090565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561013257600080fd5b506101616101413660046108ab565b600160209081526000928352604080842090915290825290205460ff1681565b60405160ff909116815260200161011d565b34801561017f57600080fd5b506101a961018e366004610889565b6002602052600090815260409020546001600160401b031681565b6040516001600160401b03909116815260200161011d565b6100e76101cf3660046108de565b6102bc565b3480156101e057600080fd5b506101096b6d6f646c70792f737276637360401b81565b6100e761020536600461098f565b610446565b6100e76102183660046109f3565b6105a3565b6100e761022b366004610a5e565b61068b565b34801561023c57600080fd5b5061025061024b366004610b2b565b6106c4565b60405161011d929190610b44565b34801561026a57600080fd5b50610109610279366004610ba3565b610786565b336b6d6f646c70792f737276637360401b146102b55760405162461bcd60e51b81526004016102ac90610be4565b60405180910390fd5b5050505050565b336b6d6f646c70792f737276637360401b146102ea5760405162461bcd60e51b81526004016102ac90610be4565b80156103095760405163702e9b1960e11b815260040160405180910390fd5b6001600160401b0385166000818152600260205260408120805467ffffffffffffffff191690921782555b8481101561043d57600061036587878481811061035357610353610c35565b90506020028101906102799190610c4b565b9050826001016040518060400160405280836001600160a01b0316815260200189898681811061039757610397610c35565b90506020028101906103a99190610c4b565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920182905250939094525050835460018082018655948252602091829020845160029092020180546001600160a01b0319166001600160a01b039092169190911781559083015192939092908301915061042d9082610d32565b5050600190920191506103349050565b50505050505050565b336b6d6f646c70792f737276637360401b146104745760405162461bcd60e51b81526004016102ac90610be4565b60ff841661051657600061048a82840184610df1565b6001600160401b03871660009081526002602052604090206001015490915060ff821615806104bb5750808260ff16115b156104d95760405163b65cad8d60e01b815260040160405180910390fd5b506001600160401b038681166000908152600160209081526040808320938816835292905220805460ff191660ff929092169190911790556102b5565b60001960ff85160161058a5760008061053183850185610e0c565b6001600160401b03808a16600090815260016020908152604080832093861683529290529081205492945090925060ff90911690036105835760405163648bd07f60e11b815260040160405180910390fd5b50506102b5565b60405163038e47a360e51b815260040160405180910390fd5b336b6d6f646c70792f737276637360401b146105d15760405162461bcd60e51b81526004016102ac90610be4565b60006105dd8585610786565b905060006040518060400160405280836001600160a01b0316815260200187878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920182905250939094525050835460018082018655948252602091829020845160029092020180546001600160a01b0319166001600160a01b03909216919091178155908301519293909290830191506106819082610d32565b5050505050505050565b336b6d6f646c70792f737276637360401b146106b95760405162461bcd60e51b81526004016102ac90610be4565b505050505050505050565b600081815481106106d457600080fd5b6000918252602090912060029091020180546001820180546001600160a01b0390921693509061070390610ca7565b80601f016020809104026020016040519081016040528092919081815260200182805461072f90610ca7565b801561077c5780601f106107515761010080835404028352916020019161077c565b820191906000526020600020905b81548152906001019060200180831161075f57829003601f168201915b5050505050905082565b60008282604051610798929190610e36565b6040519081900390209392505050565b80356001600160401b03811681146107bf57600080fd5b919050565b60008083601f8401126107d657600080fd5b5081356001600160401b038111156107ed57600080fd5b60208301915083602082850101111561080557600080fd5b9250929050565b803560ff811681146107bf57600080fd5b60008060008060006080868803121561083557600080fd5b61083e866107a8565b945060208601356001600160401b0381111561085957600080fd5b610865888289016107c4565b909550935061087890506040870161080c565b949793965091946060013592915050565b60006020828403121561089b57600080fd5b6108a4826107a8565b9392505050565b600080604083850312156108be57600080fd5b6108c7836107a8565b91506108d5602084016107a8565b90509250929050565b6000806000806000606086880312156108f657600080fd5b6108ff866107a8565b945060208601356001600160401b038082111561091b57600080fd5b818801915088601f83011261092f57600080fd5b81358181111561093e57600080fd5b8960208260051b850101111561095357600080fd5b60208301965080955050604088013591508082111561097157600080fd5b5061097e888289016107c4565b969995985093965092949392505050565b6000806000806000608086880312156109a757600080fd5b6109b0866107a8565b94506109be6020870161080c565b93506109cc604087016107a8565b925060608601356001600160401b038111156109e757600080fd5b61097e888289016107c4565b60008060008060408587031215610a0957600080fd5b84356001600160401b0380821115610a2057600080fd5b610a2c888389016107c4565b90965094506020870135915080821115610a4557600080fd5b50610a52878288016107c4565b95989497509550505050565b600080600080600080600080600060c08a8c031215610a7c57600080fd5b610a858a6107a8565b9850610a9360208b0161080c565b9750610aa160408b016107a8565b965060608a01356001600160401b0380821115610abd57600080fd5b610ac98d838e016107c4565b909850965060808c0135915080821115610ae257600080fd5b610aee8d838e016107c4565b909650945060a08c0135915080821115610b0757600080fd5b50610b148c828d016107c4565b915080935050809150509295985092959850929598565b600060208284031215610b3d57600080fd5b5035919050565b60018060a01b03831681526000602060406020840152835180604085015260005b81811015610b8157858101830151858201606001528201610b65565b506000606082860101526060601f19601f830116850101925050509392505050565b60008060208385031215610bb657600080fd5b82356001600160401b03811115610bcc57600080fd5b610bd8858286016107c4565b90969095509350505050565b60208082526031908201527f526f6f74436861696e3a204f6e6c7920726f6f7420636861696e2063616e206360408201527030b636103a3434b990333ab731ba34b7b760791b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b6000808335601e19843603018112610c6257600080fd5b8301803591506001600160401b03821115610c7c57600080fd5b60200191503681900382131561080557600080fd5b634e487b7160e01b600052604160045260246000fd5b600181811c90821680610cbb57607f821691505b602082108103610cdb57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115610d2d576000816000526020600020601f850160051c81016020861015610d0a5750805b601f850160051c820191505b81811015610d2957828155600101610d16565b5050505b505050565b81516001600160401b03811115610d4b57610d4b610c91565b610d5f81610d598454610ca7565b84610ce1565b602080601f831160018114610d945760008415610d7c5750858301515b600019600386901b1c1916600185901b178555610d29565b600085815260208120601f198616915b82811015610dc357888601518255948401946001909101908401610da4565b5085821015610de15787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060208284031215610e0357600080fd5b6108a48261080c565b60008060408385031215610e1f57600080fd5b610e28836107a8565b946020939093013593505050565b818382376000910190815291905056fea264697066735822122055f3e02035080f611479594acd7a82f0f041619f35935466925bece4c675178164736f6c63430008190033","sourceMap":"236:3072:28:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4235:220:24;;;;;;;;;;-1:-1:-1;4235:220:24;;;;;:::i;:::-;;:::i;:::-;;5554:144;;;;;;;;;;-1:-1:-1;5554:144:24;;;;;:::i;:::-;-1:-1:-1;5686:4:24;;5554:144;;;;-1:-1:-1;;;;;1681:32:30;;;1663:51;;1651:2;1636:18;5554:144:24;;;;;;;;784:58:28;;;;;;;;;;-1:-1:-1;784:58:28;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2158:4:30;2146:17;;;2128:36;;2116:2;2101:18;784:58:28;1986:184:30;890:42:28;;;;;;;;;;-1:-1:-1;890:42:28;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;890:42:28;;;;;;-1:-1:-1;;;;;2337:31:30;;;2319:50;;2307:2;2292:18;890:42:28;2175:200:30;1398:656:28;;;;;;:::i;:::-;;:::i;451:79:26:-;;;;;;;;;;;;-1:-1:-1;;;451:79:26;;2060:1075:28;;;;;;:::i;:::-;;:::i;1062:330::-;;;;;;:::i;:::-;;:::i;2963:294:24:-;;;;;;:::i;:::-;;:::i;503:36:28:-;;;;;;;;;;-1:-1:-1;503:36:28;;;;;:::i;:::-;;:::i;:::-;;;;;;;;:::i;3141:165::-;;;;;;;;;;-1:-1:-1;3141:165:28;;;;;:::i;:::-;;:::i;4235:220:24:-;703:10:26;-1:-1:-1;;;703:24:26;695:86;;;;-1:-1:-1;;;695:86:26;;;;;;;:::i;:::-;;;;;;;;;4235:220:24;;;;;:::o;1398:656:28:-;703:10:26;-1:-1:-1;;;703:24:26;695:86;;;;-1:-1:-1;;;695:86:26;;;;;;;:::i;:::-;1645:25:28;;1641:85:::1;;1693:22;;-1:-1:-1::0;;;1693:22:28::1;;;;;;;;;;;1641:85;-1:-1:-1::0;;;;;1791:19:28;::::1;1765:23;1791:19:::0;;;:8:::1;:19;::::0;;;;1820:22;;-1:-1:-1;;1820:22:28::1;::::0;;::::1;::::0;;1853:195:::1;1873:20:::0;;::::1;1853:195;;;1914:12;1929:42;1958:9;;1968:1;1958:12;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;1929:42::-;1914:57;;1985:7;:17;;2008:28;;;;;;;;2017:4;-1:-1:-1::0;;;;;2008:28:28::1;;;;;2023:9;;2033:1;2023:12;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;2008:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;;;-1:-1:-1;2008:28:28;;;;-1:-1:-1;;1985:52:28;;::::1;::::0;;::::1;::::0;;;;;::::1;::::0;;;;;;::::1;::::0;;::::1;;::::0;;-1:-1:-1;;;;;;1985:52:28::1;-1:-1:-1::0;;;;;1985:52:28;;::::1;::::0;;;::::1;::::0;;;;::::1;::::0;;;;;;;::::1;::::0;-1:-1:-1;1985:52:28::1;::::0;;::::1;:::i;:::-;-1:-1:-1::0;;1895:3:28::1;::::0;;::::1;::::0;-1:-1:-1;1853:195:28::1;::::0;-1:-1:-1;1853:195:28::1;;;1571:483;1398:656:::0;;;;;:::o;2060:1075::-;703:10:26;-1:-1:-1;;;703:24:26;695:86;;;;-1:-1:-1;;;695:86:26;;;;;;;:::i;:::-;2276:17:28::1;::::0;::::1;2272:857;;2357:7;2367:27;::::0;;::::1;2378:6:::0;2367:27:::1;:::i;:::-;-1:-1:-1::0;;;;;2420:19:28;::::1;2408:9;2420:19:::0;;;:8:::1;:19;::::0;;;;:29:::1;;:36:::0;2357:37;;-1:-1:-1;2523:6:28::1;::::0;::::1;::::0;;:15:::1;;;2537:1;2533;:5;;;2523:15;2519:82;;;2565:21;;-1:-1:-1::0;;;2565:21:28::1;;;;;;;;;;;2519:82;-1:-1:-1::0;;;;;;2666:18:28;;::::1;;::::0;;;:7:::1;:18;::::0;;;;;;;:29;;::::1;::::0;;;;;;:33;;-1:-1:-1;;2666:33:28::1;;::::0;;;::::1;::::0;;;::::1;::::0;;2272:857:::1;;;-1:-1:-1::0;;2720:18:28::1;::::0;::::1;::::0;2716:413:::1;;2825:22;::::0;2869:37:::1;::::0;;::::1;2880:6:::0;2869:37:::1;:::i;:::-;-1:-1:-1::0;;;;;2968:18:28;;::::1;;::::0;;;:7:::1;:18;::::0;;;;;;;:35;;::::1;::::0;;;;;;;;;2824:82;;-1:-1:-1;2824:82:28;;-1:-1:-1;2968:35:28::1;::::0;;::::1;:40:::0;;2964:105:::1;;3035:19;;-1:-1:-1::0;;;3035:19:28::1;;;;;;;;;;;2964:105;2740:339;;2716:413;;;3106:12;;-1:-1:-1::0;;;3106:12:28::1;;;;;;;;;;;1062:330:::0;703:10:26;-1:-1:-1;;;703:24:26;695:86;;;;-1:-1:-1;;;695:86:26;;;;;;;:::i;:::-;1230:12:28::1;1245:38;1274:8;;1245:28;:38::i;:::-;1230:53;;1336:18;1360:24;;;;;;;;1369:4;-1:-1:-1::0;;;;;1360:24:28::1;;;;;1375:8;;1360:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;;;-1:-1:-1;1360:24:28;;;;-1:-1:-1;;1336:49:28;;::::1;::::0;;::::1;::::0;;;;;::::1;::::0;;;;;;::::1;::::0;;::::1;;::::0;;-1:-1:-1;;;;;;1336:49:28::1;-1:-1:-1::0;;;;;1336:49:28;;::::1;::::0;;;::::1;::::0;;;;::::1;::::0;;;;;;;::::1;::::0;-1:-1:-1;1336:49:28::1;::::0;;::::1;:::i;:::-;;;;1220:172;1062:330:::0;;;;:::o;2963:294:24:-;703:10:26;-1:-1:-1;;;703:24:26;695:86;;;;-1:-1:-1;;;695:86:26;;;;;;;:::i;:::-;2963:294:24;;;;;;;;;:::o;503:36:28:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;503:36:28;;;;-1:-1:-1;503:36:28;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;3141:165::-;3226:7;3286:9;;3276:20;;;;;;;:::i;:::-;;;;;;;;;;3141:165;-1:-1:-1;;;3141:165:28:o;14:171:30:-;81:20;;-1:-1:-1;;;;;130:30:30;;120:41;;110:69;;175:1;172;165:12;110:69;14:171;;;:::o;190:347::-;241:8;251:6;305:3;298:4;290:6;286:17;282:27;272:55;;323:1;320;313:12;272:55;-1:-1:-1;346:20:30;;-1:-1:-1;;;;;378:30:30;;375:50;;;421:1;418;411:12;375:50;458:4;450:6;446:17;434:29;;510:3;503:4;494:6;486;482:19;478:30;475:39;472:59;;;527:1;524;517:12;472:59;190:347;;;;;:::o;542:156::-;608:20;;668:4;657:16;;647:27;;637:55;;688:1;685;678:12;703:620;797:6;805;813;821;829;882:3;870:9;861:7;857:23;853:33;850:53;;;899:1;896;889:12;850:53;922:28;940:9;922:28;:::i;:::-;912:38;;1001:2;990:9;986:18;973:32;-1:-1:-1;;;;;1020:6:30;1017:30;1014:50;;;1060:1;1057;1050:12;1014:50;1099:58;1149:7;1140:6;1129:9;1125:22;1099:58;:::i;:::-;1176:8;;-1:-1:-1;1073:84:30;-1:-1:-1;1230:36:30;;-1:-1:-1;1262:2:30;1247:18;;1230:36;:::i;:::-;703:620;;;;-1:-1:-1;703:620:30;;1313:2;1298:18;1285:32;;703:620;-1:-1:-1;;703:620:30:o;1328:184::-;1386:6;1439:2;1427:9;1418:7;1414:23;1410:32;1407:52;;;1455:1;1452;1445:12;1407:52;1478:28;1496:9;1478:28;:::i;:::-;1468:38;1328:184;-1:-1:-1;;;1328:184:30:o;1725:256::-;1791:6;1799;1852:2;1840:9;1831:7;1827:23;1823:32;1820:52;;;1868:1;1865;1858:12;1820:52;1891:28;1909:9;1891:28;:::i;:::-;1881:38;;1938:37;1971:2;1960:9;1956:18;1938:37;:::i;:::-;1928:47;;1725:256;;;;;:::o;2380:985::-;2505:6;2513;2521;2529;2537;2590:2;2578:9;2569:7;2565:23;2561:32;2558:52;;;2606:1;2603;2596:12;2558:52;2629:28;2647:9;2629:28;:::i;:::-;2619:38;;2708:2;2697:9;2693:18;2680:32;-1:-1:-1;;;;;2772:2:30;2764:6;2761:14;2758:34;;;2788:1;2785;2778:12;2758:34;2826:6;2815:9;2811:22;2801:32;;2871:7;2864:4;2860:2;2856:13;2852:27;2842:55;;2893:1;2890;2883:12;2842:55;2933:2;2920:16;2959:2;2951:6;2948:14;2945:34;;;2975:1;2972;2965:12;2945:34;3028:7;3023:2;3013:6;3010:1;3006:14;3002:2;2998:23;2994:32;2991:45;2988:65;;;3049:1;3046;3039:12;2988:65;3080:2;3076;3072:11;3062:21;;3102:6;3092:16;;;3161:2;3150:9;3146:18;3133:32;3117:48;;3190:2;3180:8;3177:16;3174:36;;;3206:1;3203;3196:12;3174:36;;3245:60;3297:7;3286:8;3275:9;3271:24;3245:60;:::i;:::-;2380:985;;;;-1:-1:-1;2380:985:30;;-1:-1:-1;3324:8:30;;3219:86;2380:985;-1:-1:-1;;;2380:985:30:o;3370:624::-;3463:6;3471;3479;3487;3495;3548:3;3536:9;3527:7;3523:23;3519:33;3516:53;;;3565:1;3562;3555:12;3516:53;3588:28;3606:9;3588:28;:::i;:::-;3578:38;;3635:36;3667:2;3656:9;3652:18;3635:36;:::i;:::-;3625:46;;3690:37;3723:2;3712:9;3708:18;3690:37;:::i;:::-;3680:47;;3778:2;3767:9;3763:18;3750:32;-1:-1:-1;;;;;3797:6:30;3794:30;3791:50;;;3837:1;3834;3827:12;3791:50;3876:58;3926:7;3917:6;3906:9;3902:22;3876:58;:::i;3999:717::-;4089:6;4097;4105;4113;4166:2;4154:9;4145:7;4141:23;4137:32;4134:52;;;4182:1;4179;4172:12;4134:52;4222:9;4209:23;-1:-1:-1;;;;;4292:2:30;4284:6;4281:14;4278:34;;;4308:1;4305;4298:12;4278:34;4347:58;4397:7;4388:6;4377:9;4373:22;4347:58;:::i;:::-;4424:8;;-1:-1:-1;4321:84:30;-1:-1:-1;4512:2:30;4497:18;;4484:32;;-1:-1:-1;4528:16:30;;;4525:36;;;4557:1;4554;4547:12;4525:36;;4596:60;4648:7;4637:8;4626:9;4622:24;4596:60;:::i;:::-;3999:717;;;;-1:-1:-1;4675:8:30;-1:-1:-1;;;;3999:717:30:o;4721:1221::-;4854:6;4862;4870;4878;4886;4894;4902;4910;4918;4971:3;4959:9;4950:7;4946:23;4942:33;4939:53;;;4988:1;4985;4978:12;4939:53;5011:28;5029:9;5011:28;:::i;:::-;5001:38;;5058:36;5090:2;5079:9;5075:18;5058:36;:::i;:::-;5048:46;;5113:37;5146:2;5135:9;5131:18;5113:37;:::i;:::-;5103:47;;5201:2;5190:9;5186:18;5173:32;-1:-1:-1;;;;;5265:2:30;5257:6;5254:14;5251:34;;;5281:1;5278;5271:12;5251:34;5320:58;5370:7;5361:6;5350:9;5346:22;5320:58;:::i;:::-;5397:8;;-1:-1:-1;5294:84:30;-1:-1:-1;5485:3:30;5470:19;;5457:33;;-1:-1:-1;5502:16:30;;;5499:36;;;5531:1;5528;5521:12;5499:36;5570:60;5622:7;5611:8;5600:9;5596:24;5570:60;:::i;:::-;5649:8;;-1:-1:-1;5544:86:30;-1:-1:-1;5737:3:30;5722:19;;5709:33;;-1:-1:-1;5754:16:30;;;5751:36;;;5783:1;5780;5773:12;5751:36;;5822:60;5874:7;5863:8;5852:9;5848:24;5822:60;:::i;:::-;5796:86;;5901:8;5891:18;;;5928:8;5918:18;;;4721:1221;;;;;;;;;;;:::o;5947:180::-;6006:6;6059:2;6047:9;6038:7;6034:23;6030:32;6027:52;;;6075:1;6072;6065:12;6027:52;-1:-1:-1;6098:23:30;;5947:180;-1:-1:-1;5947:180:30:o;6132:643::-;6336:1;6332;6327:3;6323:11;6319:19;6311:6;6307:32;6296:9;6289:51;6270:4;6359:2;6397;6392;6381:9;6377:18;6370:30;6429:6;6423:13;6472:6;6467:2;6456:9;6452:18;6445:34;6497:1;6507:140;6521:6;6518:1;6515:13;6507:140;;;6616:14;;;6612:23;;6606:30;6582:17;;;6601:2;6578:26;6571:66;6536:10;;6507:140;;;6511:3;6696:1;6691:2;6682:6;6671:9;6667:22;6663:31;6656:42;6766:2;6759;6755:7;6750:2;6742:6;6738:15;6734:29;6723:9;6719:45;6715:54;6707:62;;;;6132:643;;;;;:::o;6780:409::-;6850:6;6858;6911:2;6899:9;6890:7;6886:23;6882:32;6879:52;;;6927:1;6924;6917:12;6879:52;6967:9;6954:23;-1:-1:-1;;;;;6992:6:30;6989:30;6986:50;;;7032:1;7029;7022:12;6986:50;7071:58;7121:7;7112:6;7101:9;7097:22;7071:58;:::i;:::-;7148:8;;7045:84;;-1:-1:-1;6780:409:30;-1:-1:-1;;;;6780:409:30:o;7194:413::-;7396:2;7378:21;;;7435:2;7415:18;;;7408:30;7474:34;7469:2;7454:18;;7447:62;-1:-1:-1;;;7540:2:30;7525:18;;7518:47;7597:3;7582:19;;7194:413::o;7612:127::-;7673:10;7668:3;7664:20;7661:1;7654:31;7704:4;7701:1;7694:15;7728:4;7725:1;7718:15;7744:521;7821:4;7827:6;7887:11;7874:25;7981:2;7977:7;7966:8;7950:14;7946:29;7942:43;7922:18;7918:68;7908:96;;8000:1;7997;7990:12;7908:96;8027:33;;8079:20;;;-1:-1:-1;;;;;;8111:30:30;;8108:50;;;8154:1;8151;8144:12;8108:50;8187:4;8175:17;;-1:-1:-1;8218:14:30;8214:27;;;8204:38;;8201:58;;;8255:1;8252;8245:12;8270:127;8331:10;8326:3;8322:20;8319:1;8312:31;8362:4;8359:1;8352:15;8386:4;8383:1;8376:15;8402:380;8481:1;8477:12;;;;8524;;;8545:61;;8599:4;8591:6;8587:17;8577:27;;8545:61;8652:2;8644:6;8641:14;8621:18;8618:38;8615:161;;8698:10;8693:3;8689:20;8686:1;8679:31;8733:4;8730:1;8723:15;8761:4;8758:1;8751:15;8615:161;;8402:380;;;:::o;8912:542::-;9013:2;9008:3;9005:11;9002:446;;;9049:1;9073:5;9070:1;9063:16;9117:4;9114:1;9104:18;9187:2;9175:10;9171:19;9168:1;9164:27;9158:4;9154:38;9223:4;9211:10;9208:20;9205:47;;;-1:-1:-1;9246:4:30;9205:47;9301:2;9296:3;9292:12;9289:1;9285:20;9279:4;9275:31;9265:41;;9356:82;9374:2;9367:5;9364:13;9356:82;;;9419:17;;;9400:1;9389:13;9356:82;;;9360:3;;;9002:446;8912:542;;;:::o;9630:1341::-;9754:3;9748:10;-1:-1:-1;;;;;9773:6:30;9770:30;9767:56;;;9803:18;;:::i;:::-;9832:96;9921:6;9881:38;9913:4;9907:11;9881:38;:::i;:::-;9875:4;9832:96;:::i;:::-;9983:4;;10040:2;10029:14;;10057:1;10052:662;;;;10758:1;10775:6;10772:89;;;-1:-1:-1;10827:19:30;;;10821:26;10772:89;-1:-1:-1;;9587:1:30;9583:11;;;9579:24;9575:29;9565:40;9611:1;9607:11;;;9562:57;10874:81;;10022:943;;10052:662;8859:1;8852:14;;;8896:4;8883:18;;-1:-1:-1;;10088:20:30;;;10205:236;10219:7;10216:1;10213:14;10205:236;;;10308:19;;;10302:26;10287:42;;10400:27;;;;10368:1;10356:14;;;;10235:19;;10205:236;;;10209:3;10469:6;10460:7;10457:19;10454:201;;;10530:19;;;10524:26;-1:-1:-1;;10613:1:30;10609:14;;;10625:3;10605:24;10601:37;10597:42;10582:58;10567:74;;10454:201;-1:-1:-1;;;;;10701:1:30;10685:14;;;10681:22;10668:36;;-1:-1:-1;9630:1341:30:o;10976:182::-;11033:6;11086:2;11074:9;11065:7;11061:23;11057:32;11054:52;;;11102:1;11099;11092:12;11054:52;11125:27;11142:9;11125:27;:::i;11163:252::-;11230:6;11238;11291:2;11279:9;11270:7;11266:23;11262:32;11259:52;;;11307:1;11304;11297:12;11259:52;11330:28;11348:9;11330:28;:::i;:::-;11320:38;11405:2;11390:18;;;;11377:32;;-1:-1:-1;;;11163:252:30:o;11420:271::-;11603:6;11595;11590:3;11577:33;11559:3;11629:16;;11654:13;;;11629:16;11420:271;-1:-1:-1;11420:271:30:o","linkReferences":{}},"methodIdentifiers":{"ROOT_CHAIN()":"884673ac","blueprintOperators(uint256)":"d4e5fe27","keygens(uint64,uint64)":"34a324e4","onJobCall(uint64,uint8,uint64,bytes)":"9838caa3","onJobResult(uint64,uint8,uint64,bytes,bytes,bytes)":"d32e11e2","onRegister(bytes,bytes)":"a7c66f86","onRequest(uint64,bytes[],bytes)":"6dfee236","onSlash(uint64,bytes,uint8,uint256)":"0af7d743","onUnappliedSlash(uint64,bytes,uint8,uint256)":"e926cbd1","operatorAddressFromPublicKey(bytes)":"e40b0d49","queryDisputeOrigin(uint64)":"14b4df4c","querySlashingOrigin(uint64)":"74ceeb55","services(uint64)":"56270e17"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.25+commit.b61c2a91\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"InvalidDKGThreshold\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidJob\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidRequestInputs\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"KeygenJobNotFound\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ROOT_CHAIN\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"blueprintOperators\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"name\":\"keygens\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"serviceId\",\"type\":\"uint64\"},{\"internalType\":\"uint8\",\"name\":\"job\",\"type\":\"uint8\"},{\"internalType\":\"uint64\",\"name\":\"jobCallId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"inputs\",\"type\":\"bytes\"}],\"name\":\"onJobCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"serviceId\",\"type\":\"uint64\"},{\"internalType\":\"uint8\",\"name\":\"job\",\"type\":\"uint8\"},{\"internalType\":\"uint64\",\"name\":\"jobCallId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"participant\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"inputs\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"outputs\",\"type\":\"bytes\"}],\"name\":\"onJobResult\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"operator\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"registrationInputs\",\"type\":\"bytes\"}],\"name\":\"onRegister\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"serviceId\",\"type\":\"uint64\"},{\"internalType\":\"bytes[]\",\"name\":\"operators\",\"type\":\"bytes[]\"},{\"internalType\":\"bytes\",\"name\":\"requestInputs\",\"type\":\"bytes\"}],\"name\":\"onRequest\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"serviceId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offender\",\"type\":\"bytes\"},{\"internalType\":\"uint8\",\"name\":\"slashPercent\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"totalPayout\",\"type\":\"uint256\"}],\"name\":\"onSlash\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"serviceId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offender\",\"type\":\"bytes\"},{\"internalType\":\"uint8\",\"name\":\"slashPercent\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"totalPayout\",\"type\":\"uint256\"}],\"name\":\"onUnappliedSlash\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"publicKey\",\"type\":\"bytes\"}],\"name\":\"operatorAddressFromPublicKey\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"serviceId\",\"type\":\"uint64\"}],\"name\":\"queryDisputeOrigin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"disputeOrigin\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"serviceId\",\"type\":\"uint64\"}],\"name\":\"querySlashingOrigin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"slashingOrigin\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"name\":\"services\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"id\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"onJobCall(uint64,uint8,uint64,bytes)\":{\"details\":\"Hook for job calls on the service. Called when a job is called within the service context.\",\"params\":{\"inputs\":\"Inputs required for the job execution in bytes format.\",\"job\":\"The job identifier.\",\"jobCallId\":\"A unique ID for the job call.\",\"serviceId\":\"The ID of the service where the job is called.\"}},\"onJobResult(uint64,uint8,uint64,bytes,bytes,bytes)\":{\"details\":\"Hook for handling job result. Called when operators send the result of a job execution.\",\"params\":{\"inputs\":\"Inputs used for the job execution in bytes format.\",\"job\":\"The job identifier.\",\"jobCallId\":\"The unique ID for the job call.\",\"outputs\":\"Outputs resulting from the job execution in bytes format.\",\"participant\":\"The participant (operator) sending the result in bytes format.\",\"serviceId\":\"The ID of the service related to the job.\"}},\"onRegister(bytes,bytes)\":{\"details\":\"Hook for service operator registration. Called when a service operator attempts to register with the blueprint.\",\"params\":{\"operator\":\"The operator's details in bytes format.\",\"registrationInputs\":\"Inputs required for registration in bytes format.\"}},\"onRequest(uint64,bytes[],bytes)\":{\"details\":\"Hook for service instance requests. Called when a user requests a service instance from the blueprint.\",\"params\":{\"operators\":\"The operators involved in the service in bytes array format.\",\"requestInputs\":\"Inputs required for the service request in bytes format.\",\"serviceId\":\"The ID of the requested service.\"}},\"onSlash(uint64,bytes,uint8,uint256)\":{\"details\":\"Hook for handling applied slashes. Called when a slash is applied to an offender.\",\"params\":{\"offender\":\"The offender's details in bytes format.\",\"serviceId\":\"The ID of the service related to the slash.\",\"slashPercent\":\"The percentage of the slash.\",\"totalPayout\":\"The total payout amount in wei.\"}},\"onUnappliedSlash(uint64,bytes,uint8,uint256)\":{\"details\":\"Hook for handling unapplied slashes. Called when a slash is queued and still not yet applied to an offender.\",\"params\":{\"offender\":\"The offender's details in bytes format.\",\"serviceId\":\"The ID of the service related to the slash.\",\"slashPercent\":\"The percentage of the slash.\",\"totalPayout\":\"The total payout amount in wei.\"}},\"queryDisputeOrigin(uint64)\":{\"details\":\"Query the dispute origin for a service. This mainly used by the runtime to determine the allowed account that can dispute an unapplied slash and remove it. by default, the service manager is the only account that can dispute a service. override this function to allow other accounts to dispute a service.\",\"params\":{\"serviceId\":\"The ID of the service.\"},\"returns\":{\"disputeOrigin\":\"The account that can dispute the unapplied slash for that service\"}},\"querySlashingOrigin(uint64)\":{\"details\":\"Query the slashing origin for a service. This mainly used by the runtime to determine the allowed account that can slash a service. by default, the service manager is the only account that can slash a service. override this function to allow other accounts to slash a service.\",\"params\":{\"serviceId\":\"The ID of the service.\"},\"returns\":{\"slashingOrigin\":\"The list of accounts that can slash the service.\"}}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/cggmp21/CGGMP21Blueprint.sol\":\"CGGMP21Blueprint\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[\":@/=src/\",\":@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/\",\":@prb/test/=lib/tnt-core/lib/prb-math/lib/prb-test/src/\",\":@uniswap/v3-core/=lib/tnt-core/lib/uniswap-v3-core/contracts/\",\":clones-with-immutable-args/=lib/tnt-core/lib/clones-with-immutable-args/src/\",\":clones/=lib/tnt-core/lib/clones-with-immutable-args/src/\",\":core/=lib/tnt-core/src/\",\":ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/\",\":erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/\",\":forge-std/=lib/forge-std/src/\",\":forge-test/=lib/tnt-core/lib/prb-test/src/\",\":halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/\",\":math/=lib/tnt-core/lib/prb-math/src/\",\":openzeppelin-contracts-upgradeable/=lib/tnt-core/lib/openzeppelin-contracts-upgradeable/\",\":openzeppelin-contracts/=lib/openzeppelin-contracts/\",\":openzeppelin/=lib/tnt-core/lib/openzeppelin-contracts/contracts/\",\":prb-math/=lib/tnt-core/lib/prb-math/src/\",\":prb-test/=lib/tnt-core/lib/prb-test/src/\",\":solmate/=lib/tnt-core/lib/solmate/src/\",\":src/=lib/tnt-core/lib/prb-math/src/\",\":test/=lib/tnt-core/test/\",\":tnt-core/=lib/tnt-core/\",\":uniswap-v3-core/=lib/tnt-core/lib/uniswap-v3-core/\"]},\"sources\":{\"lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol\":{\"keccak256\":\"0x69f54c02b7d81d505910ec198c11ed4c6a728418a868b906b4a0cf29946fda84\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://8e25e4bdb7ae1f21d23bfee996e22736fc0ab44cfabedac82a757b1edc5623b9\",\"dweb:/ipfs/QmQdWQvB6JCP9ZMbzi8EvQ1PTETqkcTWrbcVurS7DKpa5n\"]},\"lib/tnt-core/src/BlueprintServiceManagerBase.sol\":{\"keccak256\":\"0xdfac1a3f898ef4e7260f7d38459066d80bc34f03d9ada259347d92d443d2e8c4\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://65fd125b742e655ecec397ceebda6233b7e2f99ae43becdf06bcd8cabe17a824\",\"dweb:/ipfs/QmYh6uVQ8Yf6RH9vkUvWCMj4E2v4K9QAxcGPki5EQsHGe2\"]},\"lib/tnt-core/src/IBlueprintServiceManager.sol\":{\"keccak256\":\"0x2c5f11a35f9333da3e841e6fa372c12bc71bc1d9870845e6416c597c40c8080d\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://3cf770141c3bbadce4da6bf8517a7912488b0d844d9cf1a2b788c902d3b3a6f6\",\"dweb:/ipfs/QmY9zpsZkWhmVTqVyHVr1KwmX7UPMuzbhAXWj6qSwbXDt3\"]},\"lib/tnt-core/src/Permissions.sol\":{\"keccak256\":\"0x59f4aba2d5ffb36f7a4f6bfcaf5089679536f90f3183e558d8428b6085d34899\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://c2fe2467c455dccedafb9033cc0b760b01118036cb240a27456723821b421043\",\"dweb:/ipfs/QmdrqkgDbRYftq883XQaKbAKcn9W3jELcrEBNJzvVSEpY7\"]},\"src/cggmp21/CGGMP21Blueprint.sol\":{\"keccak256\":\"0xf2d94bf380c1411f6d736f1e081b6328b58ef274289af7e2d7f9783f5b56b060\",\"license\":\"GPL-3.0-only\",\"urls\":[\"bzz-raw://42edab7c87c2395fa00e45c72f50edd151ad305aaa43847fc20979718af36b5f\",\"dweb:/ipfs/Qmavi7PY87VjrzW5bJ84D3gZ3RrTDPYgm8kGqnpercEHuW\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.25+commit.b61c2a91"},"language":"Solidity","output":{"abi":[{"inputs":[],"type":"error","name":"InvalidDKGThreshold"},{"inputs":[],"type":"error","name":"InvalidJob"},{"inputs":[],"type":"error","name":"InvalidRequestInputs"},{"inputs":[],"type":"error","name":"KeygenJobNotFound"},{"inputs":[],"stateMutability":"view","type":"function","name":"ROOT_CHAIN","outputs":[{"internalType":"address","name":"","type":"address"}]},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function","name":"blueprintOperators","outputs":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"bytes","name":"publicKey","type":"bytes"}]},{"inputs":[{"internalType":"uint64","name":"","type":"uint64"},{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function","name":"keygens","outputs":[{"internalType":"uint8","name":"","type":"uint8"}]},{"inputs":[{"internalType":"uint64","name":"serviceId","type":"uint64"},{"internalType":"uint8","name":"job","type":"uint8"},{"internalType":"uint64","name":"jobCallId","type":"uint64"},{"internalType":"bytes","name":"inputs","type":"bytes"}],"stateMutability":"payable","type":"function","name":"onJobCall"},{"inputs":[{"internalType":"uint64","name":"serviceId","type":"uint64"},{"internalType":"uint8","name":"job","type":"uint8"},{"internalType":"uint64","name":"jobCallId","type":"uint64"},{"internalType":"bytes","name":"participant","type":"bytes"},{"internalType":"bytes","name":"inputs","type":"bytes"},{"internalType":"bytes","name":"outputs","type":"bytes"}],"stateMutability":"payable","type":"function","name":"onJobResult"},{"inputs":[{"internalType":"bytes","name":"operator","type":"bytes"},{"internalType":"bytes","name":"registrationInputs","type":"bytes"}],"stateMutability":"payable","type":"function","name":"onRegister"},{"inputs":[{"internalType":"uint64","name":"serviceId","type":"uint64"},{"internalType":"bytes[]","name":"operators","type":"bytes[]"},{"internalType":"bytes","name":"requestInputs","type":"bytes"}],"stateMutability":"payable","type":"function","name":"onRequest"},{"inputs":[{"internalType":"uint64","name":"serviceId","type":"uint64"},{"internalType":"bytes","name":"offender","type":"bytes"},{"internalType":"uint8","name":"slashPercent","type":"uint8"},{"internalType":"uint256","name":"totalPayout","type":"uint256"}],"stateMutability":"nonpayable","type":"function","name":"onSlash"},{"inputs":[{"internalType":"uint64","name":"serviceId","type":"uint64"},{"internalType":"bytes","name":"offender","type":"bytes"},{"internalType":"uint8","name":"slashPercent","type":"uint8"},{"internalType":"uint256","name":"totalPayout","type":"uint256"}],"stateMutability":"nonpayable","type":"function","name":"onUnappliedSlash"},{"inputs":[{"internalType":"bytes","name":"publicKey","type":"bytes"}],"stateMutability":"pure","type":"function","name":"operatorAddressFromPublicKey","outputs":[{"internalType":"address","name":"","type":"address"}]},{"inputs":[{"internalType":"uint64","name":"serviceId","type":"uint64"}],"stateMutability":"view","type":"function","name":"queryDisputeOrigin","outputs":[{"internalType":"address","name":"disputeOrigin","type":"address"}]},{"inputs":[{"internalType":"uint64","name":"serviceId","type":"uint64"}],"stateMutability":"view","type":"function","name":"querySlashingOrigin","outputs":[{"internalType":"address","name":"slashingOrigin","type":"address"}]},{"inputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function","name":"services","outputs":[{"internalType":"uint64","name":"id","type":"uint64"}]}],"devdoc":{"kind":"dev","methods":{"onJobCall(uint64,uint8,uint64,bytes)":{"details":"Hook for job calls on the service. Called when a job is called within the service context.","params":{"inputs":"Inputs required for the job execution in bytes format.","job":"The job identifier.","jobCallId":"A unique ID for the job call.","serviceId":"The ID of the service where the job is called."}},"onJobResult(uint64,uint8,uint64,bytes,bytes,bytes)":{"details":"Hook for handling job result. Called when operators send the result of a job execution.","params":{"inputs":"Inputs used for the job execution in bytes format.","job":"The job identifier.","jobCallId":"The unique ID for the job call.","outputs":"Outputs resulting from the job execution in bytes format.","participant":"The participant (operator) sending the result in bytes format.","serviceId":"The ID of the service related to the job."}},"onRegister(bytes,bytes)":{"details":"Hook for service operator registration. Called when a service operator attempts to register with the blueprint.","params":{"operator":"The operator's details in bytes format.","registrationInputs":"Inputs required for registration in bytes format."}},"onRequest(uint64,bytes[],bytes)":{"details":"Hook for service instance requests. Called when a user requests a service instance from the blueprint.","params":{"operators":"The operators involved in the service in bytes array format.","requestInputs":"Inputs required for the service request in bytes format.","serviceId":"The ID of the requested service."}},"onSlash(uint64,bytes,uint8,uint256)":{"details":"Hook for handling applied slashes. Called when a slash is applied to an offender.","params":{"offender":"The offender's details in bytes format.","serviceId":"The ID of the service related to the slash.","slashPercent":"The percentage of the slash.","totalPayout":"The total payout amount in wei."}},"onUnappliedSlash(uint64,bytes,uint8,uint256)":{"details":"Hook for handling unapplied slashes. Called when a slash is queued and still not yet applied to an offender.","params":{"offender":"The offender's details in bytes format.","serviceId":"The ID of the service related to the slash.","slashPercent":"The percentage of the slash.","totalPayout":"The total payout amount in wei."}},"queryDisputeOrigin(uint64)":{"details":"Query the dispute origin for a service. This mainly used by the runtime to determine the allowed account that can dispute an unapplied slash and remove it. by default, the service manager is the only account that can dispute a service. override this function to allow other accounts to dispute a service.","params":{"serviceId":"The ID of the service."},"returns":{"disputeOrigin":"The account that can dispute the unapplied slash for that service"}},"querySlashingOrigin(uint64)":{"details":"Query the slashing origin for a service. This mainly used by the runtime to determine the allowed account that can slash a service. by default, the service manager is the only account that can slash a service. override this function to allow other accounts to slash a service.","params":{"serviceId":"The ID of the service."},"returns":{"slashingOrigin":"The list of accounts that can slash the service."}}},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"remappings":["@/=src/","@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/","@prb/test/=lib/tnt-core/lib/prb-math/lib/prb-test/src/","@uniswap/v3-core/=lib/tnt-core/lib/uniswap-v3-core/contracts/","clones-with-immutable-args/=lib/tnt-core/lib/clones-with-immutable-args/src/","clones/=lib/tnt-core/lib/clones-with-immutable-args/src/","core/=lib/tnt-core/src/","ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/","erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/","forge-std/=lib/forge-std/src/","forge-test/=lib/tnt-core/lib/prb-test/src/","halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/","math/=lib/tnt-core/lib/prb-math/src/","openzeppelin-contracts-upgradeable/=lib/tnt-core/lib/openzeppelin-contracts-upgradeable/","openzeppelin-contracts/=lib/openzeppelin-contracts/","openzeppelin/=lib/tnt-core/lib/openzeppelin-contracts/contracts/","prb-math/=lib/tnt-core/lib/prb-math/src/","prb-test/=lib/tnt-core/lib/prb-test/src/","solmate/=lib/tnt-core/lib/solmate/src/","src/=lib/tnt-core/lib/prb-math/src/","test/=lib/tnt-core/test/","tnt-core/=lib/tnt-core/","uniswap-v3-core/=lib/tnt-core/lib/uniswap-v3-core/"],"optimizer":{"enabled":true,"runs":200},"metadata":{"bytecodeHash":"ipfs"},"compilationTarget":{"src/cggmp21/CGGMP21Blueprint.sol":"CGGMP21Blueprint"},"evmVersion":"paris","libraries":{}},"sources":{"lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol":{"keccak256":"0x69f54c02b7d81d505910ec198c11ed4c6a728418a868b906b4a0cf29946fda84","urls":["bzz-raw://8e25e4bdb7ae1f21d23bfee996e22736fc0ab44cfabedac82a757b1edc5623b9","dweb:/ipfs/QmQdWQvB6JCP9ZMbzi8EvQ1PTETqkcTWrbcVurS7DKpa5n"],"license":"MIT"},"lib/tnt-core/src/BlueprintServiceManagerBase.sol":{"keccak256":"0xdfac1a3f898ef4e7260f7d38459066d80bc34f03d9ada259347d92d443d2e8c4","urls":["bzz-raw://65fd125b742e655ecec397ceebda6233b7e2f99ae43becdf06bcd8cabe17a824","dweb:/ipfs/QmYh6uVQ8Yf6RH9vkUvWCMj4E2v4K9QAxcGPki5EQsHGe2"],"license":"UNLICENSED"},"lib/tnt-core/src/IBlueprintServiceManager.sol":{"keccak256":"0x2c5f11a35f9333da3e841e6fa372c12bc71bc1d9870845e6416c597c40c8080d","urls":["bzz-raw://3cf770141c3bbadce4da6bf8517a7912488b0d844d9cf1a2b788c902d3b3a6f6","dweb:/ipfs/QmY9zpsZkWhmVTqVyHVr1KwmX7UPMuzbhAXWj6qSwbXDt3"],"license":"UNLICENSED"},"lib/tnt-core/src/Permissions.sol":{"keccak256":"0x59f4aba2d5ffb36f7a4f6bfcaf5089679536f90f3183e558d8428b6085d34899","urls":["bzz-raw://c2fe2467c455dccedafb9033cc0b760b01118036cb240a27456723821b421043","dweb:/ipfs/QmdrqkgDbRYftq883XQaKbAKcn9W3jELcrEBNJzvVSEpY7"],"license":"UNLICENSED"},"src/cggmp21/CGGMP21Blueprint.sol":{"keccak256":"0xf2d94bf380c1411f6d736f1e081b6328b58ef274289af7e2d7f9783f5b56b060","urls":["bzz-raw://42edab7c87c2395fa00e45c72f50edd151ad305aaa43847fc20979718af36b5f","dweb:/ipfs/Qmavi7PY87VjrzW5bJ84D3gZ3RrTDPYgm8kGqnpercEHuW"],"license":"GPL-3.0-only"}},"version":1},"id":28} \ No newline at end of file +{"abi":[{"type":"function","name":"ROOT_CHAIN","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"onApprove","inputs":[{"name":"operator","type":"tuple","internalType":"struct IBlueprintServiceManager.OperatorPreferences","components":[{"name":"ecdsaPublicKey","type":"bytes","internalType":"bytes"},{"name":"priceTargets","type":"tuple","internalType":"struct IBlueprintServiceManager.PriceTargets","components":[{"name":"cpu","type":"uint64","internalType":"uint64"},{"name":"mem","type":"uint64","internalType":"uint64"},{"name":"storage_hdd","type":"uint64","internalType":"uint64"},{"name":"storage_ssd","type":"uint64","internalType":"uint64"},{"name":"storage_nvme","type":"uint64","internalType":"uint64"}]}]},{"name":"requestId","type":"uint64","internalType":"uint64"},{"name":"restakingPercent","type":"uint8","internalType":"uint8"}],"outputs":[],"stateMutability":"payable"},{"type":"function","name":"onJobCall","inputs":[{"name":"serviceId","type":"uint64","internalType":"uint64"},{"name":"job","type":"uint8","internalType":"uint8"},{"name":"jobCallId","type":"uint64","internalType":"uint64"},{"name":"inputs","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"payable"},{"type":"function","name":"onJobResult","inputs":[{"name":"serviceId","type":"uint64","internalType":"uint64"},{"name":"job","type":"uint8","internalType":"uint8"},{"name":"jobCallId","type":"uint64","internalType":"uint64"},{"name":"operator","type":"tuple","internalType":"struct IBlueprintServiceManager.OperatorPreferences","components":[{"name":"ecdsaPublicKey","type":"bytes","internalType":"bytes"},{"name":"priceTargets","type":"tuple","internalType":"struct IBlueprintServiceManager.PriceTargets","components":[{"name":"cpu","type":"uint64","internalType":"uint64"},{"name":"mem","type":"uint64","internalType":"uint64"},{"name":"storage_hdd","type":"uint64","internalType":"uint64"},{"name":"storage_ssd","type":"uint64","internalType":"uint64"},{"name":"storage_nvme","type":"uint64","internalType":"uint64"}]}]},{"name":"inputs","type":"bytes","internalType":"bytes"},{"name":"outputs","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"payable"},{"type":"function","name":"onRegister","inputs":[{"name":"operator","type":"tuple","internalType":"struct IBlueprintServiceManager.OperatorPreferences","components":[{"name":"ecdsaPublicKey","type":"bytes","internalType":"bytes"},{"name":"priceTargets","type":"tuple","internalType":"struct IBlueprintServiceManager.PriceTargets","components":[{"name":"cpu","type":"uint64","internalType":"uint64"},{"name":"mem","type":"uint64","internalType":"uint64"},{"name":"storage_hdd","type":"uint64","internalType":"uint64"},{"name":"storage_ssd","type":"uint64","internalType":"uint64"},{"name":"storage_nvme","type":"uint64","internalType":"uint64"}]}]},{"name":"registrationInputs","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"payable"},{"type":"function","name":"onReject","inputs":[{"name":"operator","type":"tuple","internalType":"struct IBlueprintServiceManager.OperatorPreferences","components":[{"name":"ecdsaPublicKey","type":"bytes","internalType":"bytes"},{"name":"priceTargets","type":"tuple","internalType":"struct IBlueprintServiceManager.PriceTargets","components":[{"name":"cpu","type":"uint64","internalType":"uint64"},{"name":"mem","type":"uint64","internalType":"uint64"},{"name":"storage_hdd","type":"uint64","internalType":"uint64"},{"name":"storage_ssd","type":"uint64","internalType":"uint64"},{"name":"storage_nvme","type":"uint64","internalType":"uint64"}]}]},{"name":"requestId","type":"uint64","internalType":"uint64"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"onRequest","inputs":[{"name":"requestId","type":"uint64","internalType":"uint64"},{"name":"requester","type":"address","internalType":"address"},{"name":"operators","type":"tuple[]","internalType":"struct IBlueprintServiceManager.OperatorPreferences[]","components":[{"name":"ecdsaPublicKey","type":"bytes","internalType":"bytes"},{"name":"priceTargets","type":"tuple","internalType":"struct IBlueprintServiceManager.PriceTargets","components":[{"name":"cpu","type":"uint64","internalType":"uint64"},{"name":"mem","type":"uint64","internalType":"uint64"},{"name":"storage_hdd","type":"uint64","internalType":"uint64"},{"name":"storage_ssd","type":"uint64","internalType":"uint64"},{"name":"storage_nvme","type":"uint64","internalType":"uint64"}]}]},{"name":"requestInputs","type":"bytes","internalType":"bytes"},{"name":"permittedCallers","type":"address[]","internalType":"address[]"},{"name":"ttl","type":"uint64","internalType":"uint64"}],"outputs":[],"stateMutability":"payable"},{"type":"function","name":"onServiceInitialized","inputs":[{"name":"requestId","type":"uint64","internalType":"uint64"},{"name":"serviceId","type":"uint64","internalType":"uint64"},{"name":"owner","type":"address","internalType":"address"},{"name":"permittedCallers","type":"address[]","internalType":"address[]"},{"name":"ttl","type":"uint64","internalType":"uint64"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"onServiceTermination","inputs":[{"name":"serviceId","type":"uint64","internalType":"uint64"},{"name":"owner","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"onSlash","inputs":[{"name":"serviceId","type":"uint64","internalType":"uint64"},{"name":"offender","type":"bytes","internalType":"bytes"},{"name":"slashPercent","type":"uint8","internalType":"uint8"},{"name":"totalPayout","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"onUnappliedSlash","inputs":[{"name":"serviceId","type":"uint64","internalType":"uint64"},{"name":"offender","type":"bytes","internalType":"bytes"},{"name":"slashPercent","type":"uint8","internalType":"uint8"},{"name":"totalPayout","type":"uint256","internalType":"uint256"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"onUnregister","inputs":[{"name":"operator","type":"tuple","internalType":"struct IBlueprintServiceManager.OperatorPreferences","components":[{"name":"ecdsaPublicKey","type":"bytes","internalType":"bytes"},{"name":"priceTargets","type":"tuple","internalType":"struct IBlueprintServiceManager.PriceTargets","components":[{"name":"cpu","type":"uint64","internalType":"uint64"},{"name":"mem","type":"uint64","internalType":"uint64"},{"name":"storage_hdd","type":"uint64","internalType":"uint64"},{"name":"storage_ssd","type":"uint64","internalType":"uint64"},{"name":"storage_nvme","type":"uint64","internalType":"uint64"}]}]}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"onUpdatePriceTargets","inputs":[{"name":"operator","type":"tuple","internalType":"struct IBlueprintServiceManager.OperatorPreferences","components":[{"name":"ecdsaPublicKey","type":"bytes","internalType":"bytes"},{"name":"priceTargets","type":"tuple","internalType":"struct IBlueprintServiceManager.PriceTargets","components":[{"name":"cpu","type":"uint64","internalType":"uint64"},{"name":"mem","type":"uint64","internalType":"uint64"},{"name":"storage_hdd","type":"uint64","internalType":"uint64"},{"name":"storage_ssd","type":"uint64","internalType":"uint64"},{"name":"storage_nvme","type":"uint64","internalType":"uint64"}]}]}],"outputs":[],"stateMutability":"payable"},{"type":"function","name":"queryDisputeOrigin","inputs":[{"name":"","type":"uint64","internalType":"uint64"}],"outputs":[{"name":"disputeOrigin","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"querySlashingOrigin","inputs":[{"name":"","type":"uint64","internalType":"uint64"}],"outputs":[{"name":"slashingOrigin","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"rootChain","inputs":[],"outputs":[{"name":"rootChainAddress","type":"address","internalType":"address"}],"stateMutability":"pure"},{"type":"error","name":"OnlyRootChainAllowed","inputs":[{"name":"caller","type":"address","internalType":"address"},{"name":"rootChain","type":"address","internalType":"address"}]}],"bytecode":{"object":"0x608060405234801561001057600080fd5b50610a37806100206000396000f3fe6080604052600436106100f35760003560e01c80639838caa31161008a578063bb43abd911610059578063bb43abd91461023b578063d7deb48214610249578063e926cbd1146100f8578063fe0dd3711461026957600080fd5b80639838caa3146101de578063987ab9db146101ec5780639d0410ee1461020d578063a24e8a901461022057600080fd5b806365ce59fa116100c657806365ce59fa1461018957806374ceeb551461011a578063821c7be21461019c578063884673ac146101bc57600080fd5b80630af7d743146100f857806314b4df4c1461011a57806337c2966214610156578063434698bb14610169575b600080fd5b34801561010457600080fd5b506101186101133660046104ff565b610277565b005b34801561012657600080fd5b5061013a61013536600461056c565b503090565b6040516001600160a01b03909116815260200160405180910390f35b6101186101643660046105a6565b6102c7565b34801561017557600080fd5b5061011861018436600461066c565b610315565b610118610197366004610705565b61035c565b3480156101a857600080fd5b506101186101b73660046107d0565b6103ab565b3480156101c857600080fd5b5061013a600080516020610a0b83398151915281565b61011861011336600461081e565b3480156101f857600080fd5b50600080516020610a0b83398151915261013a565b61011861021b366004610894565b6103f3565b34801561022c57600080fd5b506101186101b73660046108fd565b61011861021b366004610927565b34801561025557600080fd5b50610118610264366004610985565b61043c565b61011861018436600461066c565b33600080516020610a0b833981519152146102c0576040516359afe8af60e11b8152336004820152600080516020610a0b83398151915260248201526044015b60405180910390fd5b5050505050565b33600080516020610a0b8339815191521461030b576040516359afe8af60e11b8152336004820152600080516020610a0b83398151915260248201526044016102b7565b5050505050505050565b33600080516020610a0b83398151915214610359576040516359afe8af60e11b8152336004820152600080516020610a0b83398151915260248201526044016102b7565b50565b33600080516020610a0b833981519152146103a0576040516359afe8af60e11b8152336004820152600080516020610a0b83398151915260248201526044016102b7565b505050505050505050565b33600080516020610a0b833981519152146103ef576040516359afe8af60e11b8152336004820152600080516020610a0b83398151915260248201526044016102b7565b5050565b33600080516020610a0b83398151915214610437576040516359afe8af60e11b8152336004820152600080516020610a0b83398151915260248201526044016102b7565b505050565b33600080516020610a0b83398151915214610480576040516359afe8af60e11b8152336004820152600080516020610a0b83398151915260248201526044016102b7565b505050505050565b803567ffffffffffffffff811681146104a057600080fd5b919050565b60008083601f8401126104b757600080fd5b50813567ffffffffffffffff8111156104cf57600080fd5b6020830191508360208285010111156104e757600080fd5b9250929050565b803560ff811681146104a057600080fd5b60008060008060006080868803121561051757600080fd5b61052086610488565b9450602086013567ffffffffffffffff81111561053c57600080fd5b610548888289016104a5565b909550935061055b9050604087016104ee565b949793965091946060013592915050565b60006020828403121561057e57600080fd5b61058782610488565b9392505050565b600060c082840312156105a057600080fd5b50919050565b60008060008060008060008060c0898b0312156105c257600080fd5b6105cb89610488565b97506105d960208a016104ee565b96506105e760408a01610488565b9550606089013567ffffffffffffffff8082111561060457600080fd5b6106108c838d0161058e565b965060808b013591508082111561062657600080fd5b6106328c838d016104a5565b909650945060a08b013591508082111561064b57600080fd5b506106588b828c016104a5565b999c989b5096995094979396929594505050565b60006020828403121561067e57600080fd5b813567ffffffffffffffff81111561069557600080fd5b6106a18482850161058e565b949350505050565b80356001600160a01b03811681146104a057600080fd5b60008083601f8401126106d257600080fd5b50813567ffffffffffffffff8111156106ea57600080fd5b6020830191508360208260051b85010111156104e757600080fd5b600080600080600080600080600060c08a8c03121561072357600080fd5b61072c8a610488565b985061073a60208b016106a9565b975060408a013567ffffffffffffffff8082111561075757600080fd5b6107638d838e016106c0565b909950975060608c013591508082111561077c57600080fd5b6107888d838e016104a5565b909750955060808c01359150808211156107a157600080fd5b506107ae8c828d016106c0565b90945092506107c1905060a08b01610488565b90509295985092959850929598565b600080604083850312156107e357600080fd5b823567ffffffffffffffff8111156107fa57600080fd5b6108068582860161058e565b92505061081560208401610488565b90509250929050565b60008060008060006080868803121561083657600080fd5b61083f86610488565b945061084d602087016104ee565b935061085b60408701610488565b9250606086013567ffffffffffffffff81111561087757600080fd5b610883888289016104a5565b969995985093965092949392505050565b6000806000604084860312156108a957600080fd5b833567ffffffffffffffff808211156108c157600080fd5b6108cd8783880161058e565b945060208601359150808211156108e357600080fd5b506108f0868287016104a5565b9497909650939450505050565b6000806040838503121561091057600080fd5b61091983610488565b9150610815602084016106a9565b60008060006060848603121561093c57600080fd5b833567ffffffffffffffff81111561095357600080fd5b61095f8682870161058e565b93505061096e60208501610488565b915061097c604085016104ee565b90509250925092565b60008060008060008060a0878903121561099e57600080fd5b6109a787610488565b95506109b560208801610488565b94506109c3604088016106a9565b9350606087013567ffffffffffffffff8111156109df57600080fd5b6109eb89828a016106c0565b90945092506109fe905060808801610488565b9050929550929550929556fe0000000000000000000000001111111111111111111111111111111111111111a164736f6c6343000813000a","sourceMap":"693:3380:0:-:0;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x6080604052600436106100f35760003560e01c80639838caa31161008a578063bb43abd911610059578063bb43abd91461023b578063d7deb48214610249578063e926cbd1146100f8578063fe0dd3711461026957600080fd5b80639838caa3146101de578063987ab9db146101ec5780639d0410ee1461020d578063a24e8a901461022057600080fd5b806365ce59fa116100c657806365ce59fa1461018957806374ceeb551461011a578063821c7be21461019c578063884673ac146101bc57600080fd5b80630af7d743146100f857806314b4df4c1461011a57806337c2966214610156578063434698bb14610169575b600080fd5b34801561010457600080fd5b506101186101133660046104ff565b610277565b005b34801561012657600080fd5b5061013a61013536600461056c565b503090565b6040516001600160a01b03909116815260200160405180910390f35b6101186101643660046105a6565b6102c7565b34801561017557600080fd5b5061011861018436600461066c565b610315565b610118610197366004610705565b61035c565b3480156101a857600080fd5b506101186101b73660046107d0565b6103ab565b3480156101c857600080fd5b5061013a600080516020610a0b83398151915281565b61011861011336600461081e565b3480156101f857600080fd5b50600080516020610a0b83398151915261013a565b61011861021b366004610894565b6103f3565b34801561022c57600080fd5b506101186101b73660046108fd565b61011861021b366004610927565b34801561025557600080fd5b50610118610264366004610985565b61043c565b61011861018436600461066c565b33600080516020610a0b833981519152146102c0576040516359afe8af60e11b8152336004820152600080516020610a0b83398151915260248201526044015b60405180910390fd5b5050505050565b33600080516020610a0b8339815191521461030b576040516359afe8af60e11b8152336004820152600080516020610a0b83398151915260248201526044016102b7565b5050505050505050565b33600080516020610a0b83398151915214610359576040516359afe8af60e11b8152336004820152600080516020610a0b83398151915260248201526044016102b7565b50565b33600080516020610a0b833981519152146103a0576040516359afe8af60e11b8152336004820152600080516020610a0b83398151915260248201526044016102b7565b505050505050505050565b33600080516020610a0b833981519152146103ef576040516359afe8af60e11b8152336004820152600080516020610a0b83398151915260248201526044016102b7565b5050565b33600080516020610a0b83398151915214610437576040516359afe8af60e11b8152336004820152600080516020610a0b83398151915260248201526044016102b7565b505050565b33600080516020610a0b83398151915214610480576040516359afe8af60e11b8152336004820152600080516020610a0b83398151915260248201526044016102b7565b505050505050565b803567ffffffffffffffff811681146104a057600080fd5b919050565b60008083601f8401126104b757600080fd5b50813567ffffffffffffffff8111156104cf57600080fd5b6020830191508360208285010111156104e757600080fd5b9250929050565b803560ff811681146104a057600080fd5b60008060008060006080868803121561051757600080fd5b61052086610488565b9450602086013567ffffffffffffffff81111561053c57600080fd5b610548888289016104a5565b909550935061055b9050604087016104ee565b949793965091946060013592915050565b60006020828403121561057e57600080fd5b61058782610488565b9392505050565b600060c082840312156105a057600080fd5b50919050565b60008060008060008060008060c0898b0312156105c257600080fd5b6105cb89610488565b97506105d960208a016104ee565b96506105e760408a01610488565b9550606089013567ffffffffffffffff8082111561060457600080fd5b6106108c838d0161058e565b965060808b013591508082111561062657600080fd5b6106328c838d016104a5565b909650945060a08b013591508082111561064b57600080fd5b506106588b828c016104a5565b999c989b5096995094979396929594505050565b60006020828403121561067e57600080fd5b813567ffffffffffffffff81111561069557600080fd5b6106a18482850161058e565b949350505050565b80356001600160a01b03811681146104a057600080fd5b60008083601f8401126106d257600080fd5b50813567ffffffffffffffff8111156106ea57600080fd5b6020830191508360208260051b85010111156104e757600080fd5b600080600080600080600080600060c08a8c03121561072357600080fd5b61072c8a610488565b985061073a60208b016106a9565b975060408a013567ffffffffffffffff8082111561075757600080fd5b6107638d838e016106c0565b909950975060608c013591508082111561077c57600080fd5b6107888d838e016104a5565b909750955060808c01359150808211156107a157600080fd5b506107ae8c828d016106c0565b90945092506107c1905060a08b01610488565b90509295985092959850929598565b600080604083850312156107e357600080fd5b823567ffffffffffffffff8111156107fa57600080fd5b6108068582860161058e565b92505061081560208401610488565b90509250929050565b60008060008060006080868803121561083657600080fd5b61083f86610488565b945061084d602087016104ee565b935061085b60408701610488565b9250606086013567ffffffffffffffff81111561087757600080fd5b610883888289016104a5565b969995985093965092949392505050565b6000806000604084860312156108a957600080fd5b833567ffffffffffffffff808211156108c157600080fd5b6108cd8783880161058e565b945060208601359150808211156108e357600080fd5b506108f0868287016104a5565b9497909650939450505050565b6000806040838503121561091057600080fd5b61091983610488565b9150610815602084016106a9565b60008060006060848603121561093c57600080fd5b833567ffffffffffffffff81111561095357600080fd5b61095f8682870161058e565b93505061096e60208501610488565b915061097c604085016104ee565b90509250925092565b60008060008060008060a0878903121561099e57600080fd5b6109a787610488565b95506109b560208801610488565b94506109c3604088016106a9565b9350606087013567ffffffffffffffff8111156109df57600080fd5b6109eb89828a016106c0565b90945092506109fe905060808801610488565b9050929550929550929556fe0000000000000000000000001111111111111111111111111111111111111111a164736f6c6343000813000a","sourceMap":"693:3380:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3505:206;;;;;;;;;;-1:-1:-1;3505:206:0;;;;;:::i;:::-;;:::i;:::-;;3943:128;;;;;;;;;;-1:-1:-1;3943:128:0;;;;;:::i;:::-;-1:-1:-1;4059:4:0;;3943:128;;;;-1:-1:-1;;;;;1681:32:3;;;1663:51;;1651:2;1636:18;3943:128:0;;;;;;;2744:291;;;;;;:::i;:::-;;:::i;1077:100::-;;;;;;;;;;-1:-1:-1;1077:100:0;;;;;:::i;:::-;;:::i;1395:314::-;;;;;;:::i;:::-;;:::i;2024:114::-;;;;;;;;;;-1:-1:-1;2024:114:0;;;;;:::i;:::-;;:::i;386:79:2:-;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;386:79:2;;2483:210:0;;;;;;:::i;643:104:2:-;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;643:104:2;;827:199:0;;;;;;:::i;:::-;;:::i;3086:102::-;;;;;;;;;;-1:-1:-1;3086:102:0;;;;;:::i;1760:213::-;;;;;;:::i;2189:243::-;;;;;;;;;;-1:-1:-1;2189:243:0;;;;;:::i;:::-;;:::i;1228:116::-;;;;;;:::i;3505:206::-;915:10:2;-1:-1:-1;;;;;;;;;;;915:24:2;911:106;;962:44;;-1:-1:-1;;;962:44:2;;983:10;962:44;;;8976:34:3;-1:-1:-1;;;;;;;;;;;9026:18:3;;;9019:43;8911:18;;962:44:2;;;;;;;;911:106;3505:206:0;;;;;:::o;2744:291::-;915:10:2;-1:-1:-1;;;;;;;;;;;915:24:2;911:106;;962:44;;-1:-1:-1;;;962:44:2;;983:10;962:44;;;8976:34:3;-1:-1:-1;;;;;;;;;;;9026:18:3;;;9019:43;8911:18;;962:44:2;8764:304:3;911:106:2;2744:291:0;;;;;;;;:::o;1077:100::-;915:10:2;-1:-1:-1;;;;;;;;;;;915:24:2;911:106;;962:44;;-1:-1:-1;;;962:44:2;;983:10;962:44;;;8976:34:3;-1:-1:-1;;;;;;;;;;;9026:18:3;;;9019:43;8911:18;;962:44:2;8764:304:3;911:106:2;1077:100:0;:::o;1395:314::-;915:10:2;-1:-1:-1;;;;;;;;;;;915:24:2;911:106;;962:44;;-1:-1:-1;;;962:44:2;;983:10;962:44;;;8976:34:3;-1:-1:-1;;;;;;;;;;;9026:18:3;;;9019:43;8911:18;;962:44:2;8764:304:3;911:106:2;1395:314:0;;;;;;;;;:::o;2024:114::-;915:10:2;-1:-1:-1;;;;;;;;;;;915:24:2;911:106;;962:44;;-1:-1:-1;;;962:44:2;;983:10;962:44;;;8976:34:3;-1:-1:-1;;;;;;;;;;;9026:18:3;;;9019:43;8911:18;;962:44:2;8764:304:3;911:106:2;2024:114:0;;:::o;827:199::-;915:10:2;-1:-1:-1;;;;;;;;;;;915:24:2;911:106;;962:44;;-1:-1:-1;;;962:44:2;;983:10;962:44;;;8976:34:3;-1:-1:-1;;;;;;;;;;;9026:18:3;;;9019:43;8911:18;;962:44:2;8764:304:3;911:106:2;827:199:0;;;:::o;2189:243::-;915:10:2;-1:-1:-1;;;;;;;;;;;915:24:2;911:106;;962:44;;-1:-1:-1;;;962:44:2;;983:10;962:44;;;8976:34:3;-1:-1:-1;;;;;;;;;;;9026:18:3;;;9019:43;8911:18;;962:44:2;8764:304:3;911:106:2;2189:243:0;;;;;;:::o;14:171:3:-;81:20;;141:18;130:30;;120:41;;110:69;;175:1;172;165:12;110:69;14:171;;;:::o;190:347::-;241:8;251:6;305:3;298:4;290:6;286:17;282:27;272:55;;323:1;320;313:12;272:55;-1:-1:-1;346:20:3;;389:18;378:30;;375:50;;;421:1;418;411:12;375:50;458:4;450:6;446:17;434:29;;510:3;503:4;494:6;486;482:19;478:30;475:39;472:59;;;527:1;524;517:12;472:59;190:347;;;;;:::o;542:156::-;608:20;;668:4;657:16;;647:27;;637:55;;688:1;685;678:12;703:620;797:6;805;813;821;829;882:3;870:9;861:7;857:23;853:33;850:53;;;899:1;896;889:12;850:53;922:28;940:9;922:28;:::i;:::-;912:38;;1001:2;990:9;986:18;973:32;1028:18;1020:6;1017:30;1014:50;;;1060:1;1057;1050:12;1014:50;1099:58;1149:7;1140:6;1129:9;1125:22;1099:58;:::i;:::-;1176:8;;-1:-1:-1;1073:84:3;-1:-1:-1;1230:36:3;;-1:-1:-1;1262:2:3;1247:18;;1230:36;:::i;:::-;703:620;;;;-1:-1:-1;703:620:3;;1313:2;1298:18;1285:32;;703:620;-1:-1:-1;;703:620:3:o;1328:184::-;1386:6;1439:2;1427:9;1418:7;1414:23;1410:32;1407:52;;;1455:1;1452;1445:12;1407:52;1478:28;1496:9;1478:28;:::i;:::-;1468:38;1328:184;-1:-1:-1;;;1328:184:3:o;1725:168::-;1797:5;1842:3;1833:6;1828:3;1824:16;1820:26;1817:46;;;1859:1;1856;1849:12;1817:46;-1:-1:-1;1881:6:3;1725:168;-1:-1:-1;1725:168:3:o;1898:1191::-;2058:6;2066;2074;2082;2090;2098;2106;2114;2167:3;2155:9;2146:7;2142:23;2138:33;2135:53;;;2184:1;2181;2174:12;2135:53;2207:28;2225:9;2207:28;:::i;:::-;2197:38;;2254:36;2286:2;2275:9;2271:18;2254:36;:::i;:::-;2244:46;;2309:37;2342:2;2331:9;2327:18;2309:37;:::i;:::-;2299:47;;2397:2;2386:9;2382:18;2369:32;2420:18;2461:2;2453:6;2450:14;2447:34;;;2477:1;2474;2467:12;2447:34;2500:79;2571:7;2562:6;2551:9;2547:22;2500:79;:::i;:::-;2490:89;;2632:3;2621:9;2617:19;2604:33;2588:49;;2662:2;2652:8;2649:16;2646:36;;;2678:1;2675;2668:12;2646:36;2717:60;2769:7;2758:8;2747:9;2743:24;2717:60;:::i;:::-;2796:8;;-1:-1:-1;2691:86:3;-1:-1:-1;2884:3:3;2869:19;;2856:33;;-1:-1:-1;2901:16:3;;;2898:36;;;2930:1;2927;2920:12;2898:36;;2969:60;3021:7;3010:8;2999:9;2995:24;2969:60;:::i;:::-;1898:1191;;;;-1:-1:-1;1898:1191:3;;-1:-1:-1;1898:1191:3;;;;;;3048:8;-1:-1:-1;;;1898:1191:3:o;3094:379::-;3191:6;3244:2;3232:9;3223:7;3219:23;3215:32;3212:52;;;3260:1;3257;3250:12;3212:52;3300:9;3287:23;3333:18;3325:6;3322:30;3319:50;;;3365:1;3362;3355:12;3319:50;3388:79;3459:7;3450:6;3439:9;3435:22;3388:79;:::i;:::-;3378:89;3094:379;-1:-1:-1;;;;3094:379:3:o;3478:173::-;3546:20;;-1:-1:-1;;;;;3595:31:3;;3585:42;;3575:70;;3641:1;3638;3631:12;3656:395;3747:8;3757:6;3811:3;3804:4;3796:6;3792:17;3788:27;3778:55;;3829:1;3826;3819:12;3778:55;-1:-1:-1;3852:20:3;;3895:18;3884:30;;3881:50;;;3927:1;3924;3917:12;3881:50;3964:4;3956:6;3952:17;3940:29;;4024:3;4017:4;4007:6;4004:1;4000:14;3992:6;3988:27;3984:38;3981:47;3978:67;;;4041:1;4038;4031:12;4056:1375;4261:6;4269;4277;4285;4293;4301;4309;4317;4325;4378:3;4366:9;4357:7;4353:23;4349:33;4346:53;;;4395:1;4392;4385:12;4346:53;4418:28;4436:9;4418:28;:::i;:::-;4408:38;;4465;4499:2;4488:9;4484:18;4465:38;:::i;:::-;4455:48;;4554:2;4543:9;4539:18;4526:32;4577:18;4618:2;4610:6;4607:14;4604:34;;;4634:1;4631;4624:12;4604:34;4673:98;4763:7;4754:6;4743:9;4739:22;4673:98;:::i;:::-;4790:8;;-1:-1:-1;4647:124:3;-1:-1:-1;4878:2:3;4863:18;;4850:32;;-1:-1:-1;4894:16:3;;;4891:36;;;4923:1;4920;4913:12;4891:36;4962:60;5014:7;5003:8;4992:9;4988:24;4962:60;:::i;:::-;5041:8;;-1:-1:-1;4936:86:3;-1:-1:-1;5129:3:3;5114:19;;5101:33;;-1:-1:-1;5146:16:3;;;5143:36;;;5175:1;5172;5165:12;5143:36;;5214:100;5306:7;5295:8;5284:9;5280:24;5214:100;:::i;:::-;5333:8;;-1:-1:-1;5188:126:3;-1:-1:-1;5387:38:3;;-1:-1:-1;5420:3:3;5405:19;;5387:38;:::i;:::-;5377:48;;4056:1375;;;;;;;;;;;:::o;5436:451::-;5541:6;5549;5602:2;5590:9;5581:7;5577:23;5573:32;5570:52;;;5618:1;5615;5608:12;5570:52;5658:9;5645:23;5691:18;5683:6;5680:30;5677:50;;;5723:1;5720;5713:12;5677:50;5746:79;5817:7;5808:6;5797:9;5793:22;5746:79;:::i;:::-;5736:89;;;5844:37;5877:2;5866:9;5862:18;5844:37;:::i;:::-;5834:47;;5436:451;;;;;:::o;5892:624::-;5985:6;5993;6001;6009;6017;6070:3;6058:9;6049:7;6045:23;6041:33;6038:53;;;6087:1;6084;6077:12;6038:53;6110:28;6128:9;6110:28;:::i;:::-;6100:38;;6157:36;6189:2;6178:9;6174:18;6157:36;:::i;:::-;6147:46;;6212:37;6245:2;6234:9;6230:18;6212:37;:::i;:::-;6202:47;;6300:2;6289:9;6285:18;6272:32;6327:18;6319:6;6316:30;6313:50;;;6359:1;6356;6349:12;6313:50;6398:58;6448:7;6439:6;6428:9;6424:22;6398:58;:::i;:::-;5892:624;;;;-1:-1:-1;5892:624:3;;-1:-1:-1;6475:8:3;;6372:84;5892:624;-1:-1:-1;;;5892:624:3:o;6521:687::-;6638:6;6646;6654;6707:2;6695:9;6686:7;6682:23;6678:32;6675:52;;;6723:1;6720;6713:12;6675:52;6763:9;6750:23;6792:18;6833:2;6825:6;6822:14;6819:34;;;6849:1;6846;6839:12;6819:34;6872:79;6943:7;6934:6;6923:9;6919:22;6872:79;:::i;:::-;6862:89;;7004:2;6993:9;6989:18;6976:32;6960:48;;7033:2;7023:8;7020:16;7017:36;;;7049:1;7046;7039:12;7017:36;;7088:60;7140:7;7129:8;7118:9;7114:24;7088:60;:::i;:::-;6521:687;;7167:8;;-1:-1:-1;7062:86:3;;-1:-1:-1;;;;6521:687:3:o;7213:258::-;7280:6;7288;7341:2;7329:9;7320:7;7316:23;7312:32;7309:52;;;7357:1;7354;7347:12;7309:52;7380:28;7398:9;7380:28;:::i;:::-;7370:38;;7427;7461:2;7450:9;7446:18;7427:38;:::i;7476:521::-;7588:6;7596;7604;7657:2;7645:9;7636:7;7632:23;7628:32;7625:52;;;7673:1;7670;7663:12;7625:52;7713:9;7700:23;7746:18;7738:6;7735:30;7732:50;;;7778:1;7775;7768:12;7732:50;7801:79;7872:7;7863:6;7852:9;7848:22;7801:79;:::i;:::-;7791:89;;;7899:37;7932:2;7921:9;7917:18;7899:37;:::i;:::-;7889:47;;7955:36;7987:2;7976:9;7972:18;7955:36;:::i;:::-;7945:46;;7476:521;;;;;:::o;8002:757::-;8121:6;8129;8137;8145;8153;8161;8214:3;8202:9;8193:7;8189:23;8185:33;8182:53;;;8231:1;8228;8221:12;8182:53;8254:28;8272:9;8254:28;:::i;:::-;8244:38;;8301:37;8334:2;8323:9;8319:18;8301:37;:::i;:::-;8291:47;;8357:38;8391:2;8380:9;8376:18;8357:38;:::i;:::-;8347:48;;8446:2;8435:9;8431:18;8418:32;8473:18;8465:6;8462:30;8459:50;;;8505:1;8502;8495:12;8459:50;8544:98;8634:7;8625:6;8614:9;8610:22;8544:98;:::i;:::-;8661:8;;-1:-1:-1;8518:124:3;-1:-1:-1;8715:38:3;;-1:-1:-1;8748:3:3;8733:19;;8715:38;:::i;:::-;8705:48;;8002:757;;;;;;;;:::o","linkReferences":{}},"methodIdentifiers":{"ROOT_CHAIN()":"884673ac","onApprove((bytes,(uint64,uint64,uint64,uint64,uint64)),uint64,uint8)":"bb43abd9","onJobCall(uint64,uint8,uint64,bytes)":"9838caa3","onJobResult(uint64,uint8,uint64,(bytes,(uint64,uint64,uint64,uint64,uint64)),bytes,bytes)":"37c29662","onRegister((bytes,(uint64,uint64,uint64,uint64,uint64)),bytes)":"9d0410ee","onReject((bytes,(uint64,uint64,uint64,uint64,uint64)),uint64)":"821c7be2","onRequest(uint64,address,(bytes,(uint64,uint64,uint64,uint64,uint64))[],bytes,address[],uint64)":"65ce59fa","onServiceInitialized(uint64,uint64,address,address[],uint64)":"d7deb482","onServiceTermination(uint64,address)":"a24e8a90","onSlash(uint64,bytes,uint8,uint256)":"0af7d743","onUnappliedSlash(uint64,bytes,uint8,uint256)":"e926cbd1","onUnregister((bytes,(uint64,uint64,uint64,uint64,uint64)))":"434698bb","onUpdatePriceTargets((bytes,(uint64,uint64,uint64,uint64,uint64)))":"fe0dd371","queryDisputeOrigin(uint64)":"14b4df4c","querySlashingOrigin(uint64)":"74ceeb55","rootChain()":"987ab9db"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.19+commit.7dd6d404\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"rootChain\",\"type\":\"address\"}],\"name\":\"OnlyRootChainAllowed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ROOT_CHAIN\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"ecdsaPublicKey\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"cpu\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"mem\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"storage_hdd\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"storage_ssd\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"storage_nvme\",\"type\":\"uint64\"}],\"internalType\":\"struct IBlueprintServiceManager.PriceTargets\",\"name\":\"priceTargets\",\"type\":\"tuple\"}],\"internalType\":\"struct IBlueprintServiceManager.OperatorPreferences\",\"name\":\"operator\",\"type\":\"tuple\"},{\"internalType\":\"uint64\",\"name\":\"requestId\",\"type\":\"uint64\"},{\"internalType\":\"uint8\",\"name\":\"restakingPercent\",\"type\":\"uint8\"}],\"name\":\"onApprove\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"serviceId\",\"type\":\"uint64\"},{\"internalType\":\"uint8\",\"name\":\"job\",\"type\":\"uint8\"},{\"internalType\":\"uint64\",\"name\":\"jobCallId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"inputs\",\"type\":\"bytes\"}],\"name\":\"onJobCall\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"serviceId\",\"type\":\"uint64\"},{\"internalType\":\"uint8\",\"name\":\"job\",\"type\":\"uint8\"},{\"internalType\":\"uint64\",\"name\":\"jobCallId\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"ecdsaPublicKey\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"cpu\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"mem\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"storage_hdd\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"storage_ssd\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"storage_nvme\",\"type\":\"uint64\"}],\"internalType\":\"struct IBlueprintServiceManager.PriceTargets\",\"name\":\"priceTargets\",\"type\":\"tuple\"}],\"internalType\":\"struct IBlueprintServiceManager.OperatorPreferences\",\"name\":\"operator\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"inputs\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"outputs\",\"type\":\"bytes\"}],\"name\":\"onJobResult\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"ecdsaPublicKey\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"cpu\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"mem\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"storage_hdd\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"storage_ssd\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"storage_nvme\",\"type\":\"uint64\"}],\"internalType\":\"struct IBlueprintServiceManager.PriceTargets\",\"name\":\"priceTargets\",\"type\":\"tuple\"}],\"internalType\":\"struct IBlueprintServiceManager.OperatorPreferences\",\"name\":\"operator\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"registrationInputs\",\"type\":\"bytes\"}],\"name\":\"onRegister\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"ecdsaPublicKey\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"cpu\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"mem\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"storage_hdd\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"storage_ssd\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"storage_nvme\",\"type\":\"uint64\"}],\"internalType\":\"struct IBlueprintServiceManager.PriceTargets\",\"name\":\"priceTargets\",\"type\":\"tuple\"}],\"internalType\":\"struct IBlueprintServiceManager.OperatorPreferences\",\"name\":\"operator\",\"type\":\"tuple\"},{\"internalType\":\"uint64\",\"name\":\"requestId\",\"type\":\"uint64\"}],\"name\":\"onReject\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"requestId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"requester\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"ecdsaPublicKey\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"cpu\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"mem\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"storage_hdd\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"storage_ssd\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"storage_nvme\",\"type\":\"uint64\"}],\"internalType\":\"struct IBlueprintServiceManager.PriceTargets\",\"name\":\"priceTargets\",\"type\":\"tuple\"}],\"internalType\":\"struct IBlueprintServiceManager.OperatorPreferences[]\",\"name\":\"operators\",\"type\":\"tuple[]\"},{\"internalType\":\"bytes\",\"name\":\"requestInputs\",\"type\":\"bytes\"},{\"internalType\":\"address[]\",\"name\":\"permittedCallers\",\"type\":\"address[]\"},{\"internalType\":\"uint64\",\"name\":\"ttl\",\"type\":\"uint64\"}],\"name\":\"onRequest\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"requestId\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"serviceId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address[]\",\"name\":\"permittedCallers\",\"type\":\"address[]\"},{\"internalType\":\"uint64\",\"name\":\"ttl\",\"type\":\"uint64\"}],\"name\":\"onServiceInitialized\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"serviceId\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"onServiceTermination\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"serviceId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offender\",\"type\":\"bytes\"},{\"internalType\":\"uint8\",\"name\":\"slashPercent\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"totalPayout\",\"type\":\"uint256\"}],\"name\":\"onSlash\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"serviceId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"offender\",\"type\":\"bytes\"},{\"internalType\":\"uint8\",\"name\":\"slashPercent\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"totalPayout\",\"type\":\"uint256\"}],\"name\":\"onUnappliedSlash\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"ecdsaPublicKey\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"cpu\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"mem\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"storage_hdd\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"storage_ssd\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"storage_nvme\",\"type\":\"uint64\"}],\"internalType\":\"struct IBlueprintServiceManager.PriceTargets\",\"name\":\"priceTargets\",\"type\":\"tuple\"}],\"internalType\":\"struct IBlueprintServiceManager.OperatorPreferences\",\"name\":\"operator\",\"type\":\"tuple\"}],\"name\":\"onUnregister\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"ecdsaPublicKey\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"cpu\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"mem\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"storage_hdd\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"storage_ssd\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"storage_nvme\",\"type\":\"uint64\"}],\"internalType\":\"struct IBlueprintServiceManager.PriceTargets\",\"name\":\"priceTargets\",\"type\":\"tuple\"}],\"internalType\":\"struct IBlueprintServiceManager.OperatorPreferences\",\"name\":\"operator\",\"type\":\"tuple\"}],\"name\":\"onUpdatePriceTargets\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"name\":\"queryDisputeOrigin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"disputeOrigin\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"name\":\"querySlashingOrigin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"slashingOrigin\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rootChain\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"rootChainAddress\",\"type\":\"address\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Tangle Network Team\",\"details\":\"This contract acts as a manager for the lifecycle of a Blueprint Instance, facilitating various stages such as registration, service requests, job execution, and job result handling. It is designed to be used by the service blueprint designer (gadget developer) and integrates with the RootChain for permissioned operations. Each function serves as a hook for different lifecycle events, and reverting any of these functions interrupts the process flow.\",\"kind\":\"dev\",\"methods\":{\"onApprove((bytes,(uint64,uint64,uint64,uint64,uint64)),uint64,uint8)\":{\"details\":\"Hook for service request approval. Called when a service request is approved by an operator.\",\"params\":{\"operator\":\"The operator's details.\",\"requestId\":\"The ID of the request.\",\"restakingPercent\":\"The percentage of the restaking amount (0-100).\"}},\"onJobCall(uint64,uint8,uint64,bytes)\":{\"details\":\"Hook for job calls on the service. Called when a job is called within the service context.\",\"params\":{\"inputs\":\"Inputs required for the job execution in bytes format.\",\"job\":\"The job identifier.\",\"jobCallId\":\"A unique ID for the job call.\",\"serviceId\":\"The ID of the service where the job is called.\"}},\"onJobResult(uint64,uint8,uint64,(bytes,(uint64,uint64,uint64,uint64,uint64)),bytes,bytes)\":{\"details\":\"Hook for handling job result. Called when operators send the result of a job execution.\",\"params\":{\"inputs\":\"Inputs used for the job execution in bytes format.\",\"job\":\"The job identifier.\",\"jobCallId\":\"The unique ID for the job call.\",\"operator\":\"The operator sending the result in bytes format.\",\"outputs\":\"Outputs resulting from the job execution in bytes format.\",\"serviceId\":\"The ID of the service related to the job.\"}},\"onRegister((bytes,(uint64,uint64,uint64,uint64,uint64)),bytes)\":{\"details\":\"Hook for service operator registration. Called when a service operator attempts to register with the blueprint.\",\"params\":{\"operator\":\"The operator's details.\",\"registrationInputs\":\"Inputs required for registration in bytes format.\"}},\"onReject((bytes,(uint64,uint64,uint64,uint64,uint64)),uint64)\":{\"details\":\"Hook for service request rejection. Called when a service request is rejected by an operator.\",\"params\":{\"operator\":\"The operator's details.\",\"requestId\":\"The ID of the request.\"}},\"onRequest(uint64,address,(bytes,(uint64,uint64,uint64,uint64,uint64))[],bytes,address[],uint64)\":{\"details\":\"Hook for service instance requests. Called when a user requests a service instance from the blueprint but this does not mean the service is initiated yet. To get notified when the service is initiated, implement the `onServiceInitialized` hook.\",\"params\":{\"operators\":\"The list of operators to be considered for the service.\",\"permittedCallers\":\"The list of permitted callers for the service.\",\"requestId\":\"The ID of the request.\",\"requestInputs\":\"The inputs required for the service request in bytes format.\",\"requester\":\"The address of the service requester.\",\"ttl\":\"The time-to-live for the service.\"}},\"onServiceInitialized(uint64,uint64,address,address[],uint64)\":{\"details\":\"Hook for service initialization. Called when a service is initialized. This hook is called after the service is approved from all of the operators.\",\"params\":{\"owner\":\"The owner of the service.\",\"permittedCallers\":\"The list of permitted callers for the service.\",\"requestId\":\"The ID of the request.\",\"serviceId\":\"The ID of the service.\",\"ttl\":\"The time-to-live for the service.\"}},\"onServiceTermination(uint64,address)\":{\"details\":\"Hook for service termination. Called when a service is terminated.\",\"params\":{\"owner\":\"The owner of the service.\",\"serviceId\":\"The ID of the service to be terminated.\"}},\"onSlash(uint64,bytes,uint8,uint256)\":{\"details\":\"Hook for handling applied slashes. Called when a slash is applied to an offender.\",\"params\":{\"offender\":\"The offender's details in bytes format.\",\"serviceId\":\"The ID of the service related to the slash.\",\"slashPercent\":\"The percentage of the slash.\",\"totalPayout\":\"The total payout amount in wei.\"}},\"onUnappliedSlash(uint64,bytes,uint8,uint256)\":{\"details\":\"Hook for handling unapplied slashes. Called when a slash is queued and still not yet applied to an offender.\",\"params\":{\"offender\":\"The offender's details in bytes format.\",\"serviceId\":\"The ID of the service related to the slash.\",\"slashPercent\":\"The percentage of the slash.\",\"totalPayout\":\"The total payout amount in wei.\"}},\"onUnregister((bytes,(uint64,uint64,uint64,uint64,uint64)))\":{\"details\":\"Hook for service operator unregistration. Called when a service operator attempts to unregister from the blueprint.\",\"params\":{\"operator\":\"The operator's details.\"}},\"onUpdatePriceTargets((bytes,(uint64,uint64,uint64,uint64,uint64)))\":{\"details\":\"Hook for updating operator's Price Targets. Called when an operator updates their price targets.\",\"params\":{\"operator\":\"The operator's details with the to be updated price targets.\"}},\"queryDisputeOrigin(uint64)\":{\"details\":\"Query the dispute origin for a service. This mainly used by the runtime to determine the allowed account that can dispute an unapplied slash and remove it. by default, the service manager is the only account that can dispute a service. override this function to allow other accounts to dispute a service.\",\"params\":{\"serviceId\":\"The ID of the service.\"},\"returns\":{\"disputeOrigin\":\"The account that can dispute the unapplied slash for that service\"}},\"querySlashingOrigin(uint64)\":{\"details\":\"Query the slashing origin for a service. This mainly used by the runtime to determine the allowed account that can slash a service. by default, the service manager is the only account that can slash a service. override this function to allow other accounts to slash a service.\",\"params\":{\"serviceId\":\"The ID of the service.\"},\"returns\":{\"slashingOrigin\":\"The account that can slash the offender.\"}},\"rootChain()\":{\"details\":\"Get the root chain address\",\"returns\":{\"rootChainAddress\":\"The address of the root chain\"}}},\"title\":\"BlueprintServiceManagerBase\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"ROOT_CHAIN()\":{\"notice\":\"The address of the root chain\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/BlueprintServiceManagerBase.sol\":\"BlueprintServiceManagerBase\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"none\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[\":forge-std/=lib/forge-std/src/\"]},\"sources\":{\"src/BlueprintServiceManagerBase.sol\":{\"keccak256\":\"0x5b1186fffa1a3b9c18e5fa296adcb2ffd235725b0be058292a057b126b126dfb\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://e26f67d20617657bf76ccca895bf8b4095c5b3c9540786cdbbad706553090362\",\"dweb:/ipfs/QmfTi12AGc6uunRCrBsecGzqyzPQPA5dzXXRTXQwopXMQM\"]},\"src/IBlueprintServiceManager.sol\":{\"keccak256\":\"0x8c45354ea5da218db01db7eb0c9efdbe515b90fa13db74f385bedc48be7c1031\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://fb100112fd7d323522bcc8644e16c888ca57d9416c04ae67aae50cd671dd9012\",\"dweb:/ipfs/QmYi5f85kaHitKSgpuKN9NYb7FpZeoiMySwo8hTLa1KHJu\"]},\"src/Permissions.sol\":{\"keccak256\":\"0x13d0c19856a9ee02845b41fc0ec82d38fc9ae86284e74114b92f8228bf29705e\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://c329f722dc4e9242a4bb9ce16ce81487d7dfdfebe8121e230591a22e3543a214\",\"dweb:/ipfs/QmaVALpt222VYwyeaZxD9Qkjav96LKXWGr3WZUsY2YSQHW\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.19+commit.7dd6d404"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"address","name":"rootChain","type":"address"}],"type":"error","name":"OnlyRootChainAllowed"},{"inputs":[],"stateMutability":"view","type":"function","name":"ROOT_CHAIN","outputs":[{"internalType":"address","name":"","type":"address"}]},{"inputs":[{"internalType":"struct IBlueprintServiceManager.OperatorPreferences","name":"operator","type":"tuple","components":[{"internalType":"bytes","name":"ecdsaPublicKey","type":"bytes"},{"internalType":"struct IBlueprintServiceManager.PriceTargets","name":"priceTargets","type":"tuple","components":[{"internalType":"uint64","name":"cpu","type":"uint64"},{"internalType":"uint64","name":"mem","type":"uint64"},{"internalType":"uint64","name":"storage_hdd","type":"uint64"},{"internalType":"uint64","name":"storage_ssd","type":"uint64"},{"internalType":"uint64","name":"storage_nvme","type":"uint64"}]}]},{"internalType":"uint64","name":"requestId","type":"uint64"},{"internalType":"uint8","name":"restakingPercent","type":"uint8"}],"stateMutability":"payable","type":"function","name":"onApprove"},{"inputs":[{"internalType":"uint64","name":"serviceId","type":"uint64"},{"internalType":"uint8","name":"job","type":"uint8"},{"internalType":"uint64","name":"jobCallId","type":"uint64"},{"internalType":"bytes","name":"inputs","type":"bytes"}],"stateMutability":"payable","type":"function","name":"onJobCall"},{"inputs":[{"internalType":"uint64","name":"serviceId","type":"uint64"},{"internalType":"uint8","name":"job","type":"uint8"},{"internalType":"uint64","name":"jobCallId","type":"uint64"},{"internalType":"struct IBlueprintServiceManager.OperatorPreferences","name":"operator","type":"tuple","components":[{"internalType":"bytes","name":"ecdsaPublicKey","type":"bytes"},{"internalType":"struct IBlueprintServiceManager.PriceTargets","name":"priceTargets","type":"tuple","components":[{"internalType":"uint64","name":"cpu","type":"uint64"},{"internalType":"uint64","name":"mem","type":"uint64"},{"internalType":"uint64","name":"storage_hdd","type":"uint64"},{"internalType":"uint64","name":"storage_ssd","type":"uint64"},{"internalType":"uint64","name":"storage_nvme","type":"uint64"}]}]},{"internalType":"bytes","name":"inputs","type":"bytes"},{"internalType":"bytes","name":"outputs","type":"bytes"}],"stateMutability":"payable","type":"function","name":"onJobResult"},{"inputs":[{"internalType":"struct IBlueprintServiceManager.OperatorPreferences","name":"operator","type":"tuple","components":[{"internalType":"bytes","name":"ecdsaPublicKey","type":"bytes"},{"internalType":"struct IBlueprintServiceManager.PriceTargets","name":"priceTargets","type":"tuple","components":[{"internalType":"uint64","name":"cpu","type":"uint64"},{"internalType":"uint64","name":"mem","type":"uint64"},{"internalType":"uint64","name":"storage_hdd","type":"uint64"},{"internalType":"uint64","name":"storage_ssd","type":"uint64"},{"internalType":"uint64","name":"storage_nvme","type":"uint64"}]}]},{"internalType":"bytes","name":"registrationInputs","type":"bytes"}],"stateMutability":"payable","type":"function","name":"onRegister"},{"inputs":[{"internalType":"struct IBlueprintServiceManager.OperatorPreferences","name":"operator","type":"tuple","components":[{"internalType":"bytes","name":"ecdsaPublicKey","type":"bytes"},{"internalType":"struct IBlueprintServiceManager.PriceTargets","name":"priceTargets","type":"tuple","components":[{"internalType":"uint64","name":"cpu","type":"uint64"},{"internalType":"uint64","name":"mem","type":"uint64"},{"internalType":"uint64","name":"storage_hdd","type":"uint64"},{"internalType":"uint64","name":"storage_ssd","type":"uint64"},{"internalType":"uint64","name":"storage_nvme","type":"uint64"}]}]},{"internalType":"uint64","name":"requestId","type":"uint64"}],"stateMutability":"nonpayable","type":"function","name":"onReject"},{"inputs":[{"internalType":"uint64","name":"requestId","type":"uint64"},{"internalType":"address","name":"requester","type":"address"},{"internalType":"struct IBlueprintServiceManager.OperatorPreferences[]","name":"operators","type":"tuple[]","components":[{"internalType":"bytes","name":"ecdsaPublicKey","type":"bytes"},{"internalType":"struct IBlueprintServiceManager.PriceTargets","name":"priceTargets","type":"tuple","components":[{"internalType":"uint64","name":"cpu","type":"uint64"},{"internalType":"uint64","name":"mem","type":"uint64"},{"internalType":"uint64","name":"storage_hdd","type":"uint64"},{"internalType":"uint64","name":"storage_ssd","type":"uint64"},{"internalType":"uint64","name":"storage_nvme","type":"uint64"}]}]},{"internalType":"bytes","name":"requestInputs","type":"bytes"},{"internalType":"address[]","name":"permittedCallers","type":"address[]"},{"internalType":"uint64","name":"ttl","type":"uint64"}],"stateMutability":"payable","type":"function","name":"onRequest"},{"inputs":[{"internalType":"uint64","name":"requestId","type":"uint64"},{"internalType":"uint64","name":"serviceId","type":"uint64"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address[]","name":"permittedCallers","type":"address[]"},{"internalType":"uint64","name":"ttl","type":"uint64"}],"stateMutability":"nonpayable","type":"function","name":"onServiceInitialized"},{"inputs":[{"internalType":"uint64","name":"serviceId","type":"uint64"},{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"nonpayable","type":"function","name":"onServiceTermination"},{"inputs":[{"internalType":"uint64","name":"serviceId","type":"uint64"},{"internalType":"bytes","name":"offender","type":"bytes"},{"internalType":"uint8","name":"slashPercent","type":"uint8"},{"internalType":"uint256","name":"totalPayout","type":"uint256"}],"stateMutability":"nonpayable","type":"function","name":"onSlash"},{"inputs":[{"internalType":"uint64","name":"serviceId","type":"uint64"},{"internalType":"bytes","name":"offender","type":"bytes"},{"internalType":"uint8","name":"slashPercent","type":"uint8"},{"internalType":"uint256","name":"totalPayout","type":"uint256"}],"stateMutability":"nonpayable","type":"function","name":"onUnappliedSlash"},{"inputs":[{"internalType":"struct IBlueprintServiceManager.OperatorPreferences","name":"operator","type":"tuple","components":[{"internalType":"bytes","name":"ecdsaPublicKey","type":"bytes"},{"internalType":"struct IBlueprintServiceManager.PriceTargets","name":"priceTargets","type":"tuple","components":[{"internalType":"uint64","name":"cpu","type":"uint64"},{"internalType":"uint64","name":"mem","type":"uint64"},{"internalType":"uint64","name":"storage_hdd","type":"uint64"},{"internalType":"uint64","name":"storage_ssd","type":"uint64"},{"internalType":"uint64","name":"storage_nvme","type":"uint64"}]}]}],"stateMutability":"nonpayable","type":"function","name":"onUnregister"},{"inputs":[{"internalType":"struct IBlueprintServiceManager.OperatorPreferences","name":"operator","type":"tuple","components":[{"internalType":"bytes","name":"ecdsaPublicKey","type":"bytes"},{"internalType":"struct IBlueprintServiceManager.PriceTargets","name":"priceTargets","type":"tuple","components":[{"internalType":"uint64","name":"cpu","type":"uint64"},{"internalType":"uint64","name":"mem","type":"uint64"},{"internalType":"uint64","name":"storage_hdd","type":"uint64"},{"internalType":"uint64","name":"storage_ssd","type":"uint64"},{"internalType":"uint64","name":"storage_nvme","type":"uint64"}]}]}],"stateMutability":"payable","type":"function","name":"onUpdatePriceTargets"},{"inputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function","name":"queryDisputeOrigin","outputs":[{"internalType":"address","name":"disputeOrigin","type":"address"}]},{"inputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function","name":"querySlashingOrigin","outputs":[{"internalType":"address","name":"slashingOrigin","type":"address"}]},{"inputs":[],"stateMutability":"pure","type":"function","name":"rootChain","outputs":[{"internalType":"address","name":"rootChainAddress","type":"address"}]}],"devdoc":{"kind":"dev","methods":{"onApprove((bytes,(uint64,uint64,uint64,uint64,uint64)),uint64,uint8)":{"details":"Hook for service request approval. Called when a service request is approved by an operator.","params":{"operator":"The operator's details.","requestId":"The ID of the request.","restakingPercent":"The percentage of the restaking amount (0-100)."}},"onJobCall(uint64,uint8,uint64,bytes)":{"details":"Hook for job calls on the service. Called when a job is called within the service context.","params":{"inputs":"Inputs required for the job execution in bytes format.","job":"The job identifier.","jobCallId":"A unique ID for the job call.","serviceId":"The ID of the service where the job is called."}},"onJobResult(uint64,uint8,uint64,(bytes,(uint64,uint64,uint64,uint64,uint64)),bytes,bytes)":{"details":"Hook for handling job result. Called when operators send the result of a job execution.","params":{"inputs":"Inputs used for the job execution in bytes format.","job":"The job identifier.","jobCallId":"The unique ID for the job call.","operator":"The operator sending the result in bytes format.","outputs":"Outputs resulting from the job execution in bytes format.","serviceId":"The ID of the service related to the job."}},"onRegister((bytes,(uint64,uint64,uint64,uint64,uint64)),bytes)":{"details":"Hook for service operator registration. Called when a service operator attempts to register with the blueprint.","params":{"operator":"The operator's details.","registrationInputs":"Inputs required for registration in bytes format."}},"onReject((bytes,(uint64,uint64,uint64,uint64,uint64)),uint64)":{"details":"Hook for service request rejection. Called when a service request is rejected by an operator.","params":{"operator":"The operator's details.","requestId":"The ID of the request."}},"onRequest(uint64,address,(bytes,(uint64,uint64,uint64,uint64,uint64))[],bytes,address[],uint64)":{"details":"Hook for service instance requests. Called when a user requests a service instance from the blueprint but this does not mean the service is initiated yet. To get notified when the service is initiated, implement the `onServiceInitialized` hook.","params":{"operators":"The list of operators to be considered for the service.","permittedCallers":"The list of permitted callers for the service.","requestId":"The ID of the request.","requestInputs":"The inputs required for the service request in bytes format.","requester":"The address of the service requester.","ttl":"The time-to-live for the service."}},"onServiceInitialized(uint64,uint64,address,address[],uint64)":{"details":"Hook for service initialization. Called when a service is initialized. This hook is called after the service is approved from all of the operators.","params":{"owner":"The owner of the service.","permittedCallers":"The list of permitted callers for the service.","requestId":"The ID of the request.","serviceId":"The ID of the service.","ttl":"The time-to-live for the service."}},"onServiceTermination(uint64,address)":{"details":"Hook for service termination. Called when a service is terminated.","params":{"owner":"The owner of the service.","serviceId":"The ID of the service to be terminated."}},"onSlash(uint64,bytes,uint8,uint256)":{"details":"Hook for handling applied slashes. Called when a slash is applied to an offender.","params":{"offender":"The offender's details in bytes format.","serviceId":"The ID of the service related to the slash.","slashPercent":"The percentage of the slash.","totalPayout":"The total payout amount in wei."}},"onUnappliedSlash(uint64,bytes,uint8,uint256)":{"details":"Hook for handling unapplied slashes. Called when a slash is queued and still not yet applied to an offender.","params":{"offender":"The offender's details in bytes format.","serviceId":"The ID of the service related to the slash.","slashPercent":"The percentage of the slash.","totalPayout":"The total payout amount in wei."}},"onUnregister((bytes,(uint64,uint64,uint64,uint64,uint64)))":{"details":"Hook for service operator unregistration. Called when a service operator attempts to unregister from the blueprint.","params":{"operator":"The operator's details."}},"onUpdatePriceTargets((bytes,(uint64,uint64,uint64,uint64,uint64)))":{"details":"Hook for updating operator's Price Targets. Called when an operator updates their price targets.","params":{"operator":"The operator's details with the to be updated price targets."}},"queryDisputeOrigin(uint64)":{"details":"Query the dispute origin for a service. This mainly used by the runtime to determine the allowed account that can dispute an unapplied slash and remove it. by default, the service manager is the only account that can dispute a service. override this function to allow other accounts to dispute a service.","params":{"serviceId":"The ID of the service."},"returns":{"disputeOrigin":"The account that can dispute the unapplied slash for that service"}},"querySlashingOrigin(uint64)":{"details":"Query the slashing origin for a service. This mainly used by the runtime to determine the allowed account that can slash a service. by default, the service manager is the only account that can slash a service. override this function to allow other accounts to slash a service.","params":{"serviceId":"The ID of the service."},"returns":{"slashingOrigin":"The account that can slash the offender."}},"rootChain()":{"details":"Get the root chain address","returns":{"rootChainAddress":"The address of the root chain"}}},"version":1},"userdoc":{"kind":"user","methods":{"ROOT_CHAIN()":{"notice":"The address of the root chain"}},"version":1}},"settings":{"remappings":["forge-std/=lib/forge-std/src/"],"optimizer":{"enabled":true,"runs":200},"metadata":{"bytecodeHash":"none"},"compilationTarget":{"src/BlueprintServiceManagerBase.sol":"BlueprintServiceManagerBase"},"evmVersion":"paris","libraries":{}},"sources":{"src/BlueprintServiceManagerBase.sol":{"keccak256":"0x5b1186fffa1a3b9c18e5fa296adcb2ffd235725b0be058292a057b126b126dfb","urls":["bzz-raw://e26f67d20617657bf76ccca895bf8b4095c5b3c9540786cdbbad706553090362","dweb:/ipfs/QmfTi12AGc6uunRCrBsecGzqyzPQPA5dzXXRTXQwopXMQM"],"license":"UNLICENSED"},"src/IBlueprintServiceManager.sol":{"keccak256":"0x8c45354ea5da218db01db7eb0c9efdbe515b90fa13db74f385bedc48be7c1031","urls":["bzz-raw://fb100112fd7d323522bcc8644e16c888ca57d9416c04ae67aae50cd671dd9012","dweb:/ipfs/QmYi5f85kaHitKSgpuKN9NYb7FpZeoiMySwo8hTLa1KHJu"],"license":"UNLICENSED"},"src/Permissions.sol":{"keccak256":"0x13d0c19856a9ee02845b41fc0ec82d38fc9ae86284e74114b92f8228bf29705e","urls":["bzz-raw://c329f722dc4e9242a4bb9ce16ce81487d7dfdfebe8121e230591a22e3543a214","dweb:/ipfs/QmaVALpt222VYwyeaZxD9Qkjav96LKXWGr3WZUsY2YSQHW"],"license":"UNLICENSED"}},"version":1},"id":0} \ No newline at end of file diff --git a/pallets/services/src/tests.rs b/pallets/services/src/tests.rs index 95b44117..8a8c1c26 100644 --- a/pallets/services/src/tests.rs +++ b/pallets/services/src/tests.rs @@ -136,6 +136,7 @@ fn register_on_blueprint() { price_targets: price_targets(MachineKind::Large), }, Default::default(), + 0, ); assert_ok!(registration_call); @@ -160,6 +161,7 @@ fn register_on_blueprint() { 0, OperatorPreferences { key: zero_key(), price_targets: Default::default() }, Default::default(), + 0, ), crate::Error::::AlreadyRegistered ); @@ -171,6 +173,7 @@ fn register_on_blueprint() { 0, OperatorPreferences { key: zero_key(), price_targets: Default::default() }, Default::default(), + 0, ), crate::Error::::OperatorNotActive ); @@ -219,6 +222,7 @@ fn update_price_targets() { price_targets: price_targets(MachineKind::Small) }, Default::default(), + 0, )); assert_eq!( @@ -284,6 +288,7 @@ fn unregister_from_blueprint() { 0, OperatorPreferences { key: zero_key(), price_targets: Default::default() }, Default::default(), + 0, )); assert_ok!(Services::unregister(RuntimeOrigin::signed(bob.clone()), 0)); assert!(!Operators::::contains_key(0, &bob)); @@ -319,6 +324,7 @@ fn request_service() { 0, OperatorPreferences { key: zero_key(), price_targets: Default::default() }, Default::default(), + 0, )); let charlie = mock_pub_key(CHARLIE); assert_ok!(Services::register( @@ -326,6 +332,7 @@ fn request_service() { 0, OperatorPreferences { key: zero_key(), price_targets: Default::default() }, Default::default(), + 0, )); let dave = mock_pub_key(DAVE); assert_ok!(Services::register( @@ -333,6 +340,7 @@ fn request_service() { 0, OperatorPreferences { key: zero_key(), price_targets: Default::default() }, Default::default(), + 0, )); let eve = mock_pub_key(EVE); @@ -344,6 +352,7 @@ fn request_service() { Default::default(), vec![USDC, WETH], 100, + 0, )); assert_eq!(ServiceRequests::::iter_keys().collect::>().len(), 1); @@ -430,6 +439,7 @@ fn request_service_with_no_assets() { 0, OperatorPreferences { key: zero_key(), price_targets: Default::default() }, Default::default(), + 0, )); let eve = mock_pub_key(EVE); assert_err!( @@ -441,6 +451,7 @@ fn request_service_with_no_assets() { Default::default(), vec![], // no assets 100, + 0, ), Error::::NoAssetsProvided ); @@ -460,6 +471,7 @@ fn job_calls() { 0, OperatorPreferences { key: zero_key(), price_targets: Default::default() }, Default::default(), + 0, )); let charlie = mock_pub_key(CHARLIE); assert_ok!(Services::register( @@ -467,6 +479,7 @@ fn job_calls() { 0, OperatorPreferences { key: zero_key(), price_targets: Default::default() }, Default::default(), + 0, )); let dave = mock_pub_key(DAVE); assert_ok!(Services::register( @@ -474,6 +487,7 @@ fn job_calls() { 0, OperatorPreferences { key: zero_key(), price_targets: Default::default() }, Default::default(), + 0, )); let eve = mock_pub_key(EVE); @@ -485,6 +499,7 @@ fn job_calls() { Default::default(), vec![WETH], 100, + 0, )); assert_eq!(ServiceRequests::::iter_keys().collect::>().len(), 1); @@ -534,90 +549,6 @@ fn job_calls() { }); } -#[test] -fn job_calls_fails_with_invalid_input() { - new_test_ext(vec![ALICE, BOB, CHARLIE, DAVE, EVE]).execute_with(|| { - System::set_block_number(1); - let alice = mock_pub_key(ALICE); - let blueprint = cggmp21_blueprint(); - assert_ok!(Services::create_blueprint(RuntimeOrigin::signed(alice.clone()), blueprint)); - let bob = mock_pub_key(BOB); - assert_ok!(Services::register( - RuntimeOrigin::signed(bob.clone()), - 0, - OperatorPreferences { key: zero_key(), price_targets: Default::default() }, - Default::default(), - )); - let charlie = mock_pub_key(CHARLIE); - assert_ok!(Services::register( - RuntimeOrigin::signed(charlie.clone()), - 0, - OperatorPreferences { key: zero_key(), price_targets: Default::default() }, - Default::default(), - )); - let dave = mock_pub_key(DAVE); - assert_ok!(Services::register( - RuntimeOrigin::signed(dave.clone()), - 0, - OperatorPreferences { key: zero_key(), price_targets: Default::default() }, - Default::default(), - )); - - let eve = mock_pub_key(EVE); - assert_ok!(Services::request( - RuntimeOrigin::signed(eve.clone()), - 0, - vec![alice.clone()], - vec![bob.clone(), charlie.clone(), dave.clone()], - Default::default(), - vec![WETH], - 100, - )); - // this service gets immediately accepted by all providers. - assert_eq!(ServiceRequests::::iter_keys().collect::>().len(), 1); - assert_ok!(Services::approve( - RuntimeOrigin::signed(bob.clone()), - 0, - Percent::from_percent(10) - )); - - assert_ok!(Services::approve( - RuntimeOrigin::signed(charlie.clone()), - 0, - Percent::from_percent(10) - )); - - assert_ok!(Services::approve( - RuntimeOrigin::signed(dave.clone()), - 0, - Percent::from_percent(10) - )); - assert!(Instances::::contains_key(0)); - assert_events(vec![RuntimeEvent::Services(crate::Event::ServiceInitiated { - owner: eve.clone(), - request_id: 0, - service_id: 0, - blueprint_id: 0, - assets: vec![WETH], - })]); - - // now we can call the jobs - let job_call_id = 0; - assert_err!( - Services::call( - RuntimeOrigin::signed(eve.clone()), - 0, - 0, - // t > n - bounded_vec![Field::Uint8(4)], - ), - crate::Error::::InvalidJobCallInput - ); - - assert!(!JobCalls::::contains_key(0, job_call_id)); - }); -} - #[test] fn job_result() { new_test_ext(vec![ALICE, BOB, CHARLIE, DAVE, EVE]).execute_with(|| { @@ -631,6 +562,7 @@ fn job_result() { 0, OperatorPreferences { key: zero_key(), price_targets: Default::default() }, Default::default(), + 0, )); let charlie = mock_pub_key(CHARLIE); assert_ok!(Services::register( @@ -638,6 +570,7 @@ fn job_result() { 0, OperatorPreferences { key: zero_key(), price_targets: Default::default() }, Default::default(), + 0, )); let dave = mock_pub_key(DAVE); assert_ok!(Services::register( @@ -645,6 +578,7 @@ fn job_result() { 0, OperatorPreferences { key: zero_key(), price_targets: Default::default() }, Default::default(), + 0, )); let eve = mock_pub_key(EVE); @@ -656,6 +590,7 @@ fn job_result() { Default::default(), vec![WETH], 100, + 0, )); assert_eq!(ServiceRequests::::iter_keys().collect::>().len(), 1); @@ -758,6 +693,7 @@ fn deploy() -> Deployment { blueprint_id, OperatorPreferences { key: zero_key(), price_targets: Default::default() }, Default::default(), + 0, )); let eve = mock_pub_key(EVE); @@ -770,6 +706,7 @@ fn deploy() -> Deployment { Default::default(), vec![WETH], 100, + 0, )); assert_eq!(ServiceRequests::::iter_keys().collect::>().len(), 1); diff --git a/pallets/services/src/traits.rs b/pallets/services/src/traits.rs index 740c2e09..c8f50155 100644 --- a/pallets/services/src/traits.rs +++ b/pallets/services/src/traits.rs @@ -36,4 +36,7 @@ pub trait EvmGasWeightMapping { pub trait EvmAddressMapping { /// Convert an address to an account id. fn into_account_id(address: H160) -> A; + + /// Convert an account id to an address. + fn into_address(account_id: A) -> H160; } diff --git a/precompiles/services/Cargo.toml b/precompiles/services/Cargo.toml index c9a2f675..b878f90a 100644 --- a/precompiles/services/Cargo.toml +++ b/precompiles/services/Cargo.toml @@ -27,7 +27,7 @@ tangle-primitives = { workspace = true } pallet-services = { workspace = true } [dev-dependencies] -derive_more = { workspace = true } +derive_more = { workspace = true, features = ["full"] } hex-literal = { workspace = true } serde = { workspace = true } sha3 = { workspace = true } diff --git a/precompiles/services/Services.sol b/precompiles/services/Services.sol index 2bacce39..7d2a468a 100644 --- a/precompiles/services/Services.sol +++ b/precompiles/services/Services.sol @@ -12,8 +12,11 @@ interface ServicesPrecompile { /// @param blueprint_id The ID of the blueprint to register for /// @param preferences The operator's preferences encoded as bytes /// @param registration_args The registration arguments encoded as bytes - function registerOperator(uint256 blueprint_id, bytes calldata preferences, bytes calldata registration_args) - external; + function registerOperator( + uint256 blueprint_id, + bytes calldata preferences, + bytes calldata registration_args + ) external payable; /// @notice Unregister an operator from a specific blueprint /// @param blueprint_id The ID of the blueprint to unregister from @@ -50,13 +53,21 @@ interface ServicesPrecompile { /// @param service_id The ID of the service /// @param job The job index (as uint8) /// @param args_data The arguments of the job encoded as bytes - function callJob(uint256 service_id, uint8 job, bytes calldata args_data) external; + function callJob( + uint256 service_id, + uint8 job, + bytes calldata args_data + ) external; /// @notice Submit the result of a job call /// @param service_id The ID of the service /// @param call_id The ID of the call /// @param result_data The result data encoded as bytes - function submitResult(uint256 service_id, uint256 call_id, bytes calldata result_data) external; + function submitResult( + uint256 service_id, + uint256 call_id, + bytes calldata result_data + ) external; /// @notice Slash an operator (offender) for a service id with a given percent of their exposed stake for that service. /// @@ -66,7 +77,11 @@ interface ServicesPrecompile { /// @param offender The operator to be slashed encoded as bytes /// @param service_id The ID of the service to slash for /// @param percent The percent of the offender's exposed stake to slash - function slash(bytes calldata offender, uint256 service_id, uint8 percent) external; + function slash( + bytes calldata offender, + uint256 service_id, + uint8 percent + ) external; /// @notice Dispute an Unapplied Slash for a service id. /// diff --git a/precompiles/services/src/lib.rs b/precompiles/services/src/lib.rs index f073de67..324e783a 100644 --- a/precompiles/services/src/lib.rs +++ b/precompiles/services/src/lib.rs @@ -3,6 +3,7 @@ use fp_evm::PrecompileHandle; use frame_support::dispatch::{GetDispatchInfo, PostDispatchInfo}; use pallet_evm::AddressMapping; +use pallet_services::types::BalanceOf; use parity_scale_codec::Decode; use precompile_utils::prelude::*; use sp_core::U256; @@ -60,6 +61,8 @@ where ) -> EvmResult { handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; let origin = Runtime::AddressMapping::into_account_id(handle.context().caller); + // msg.value + let value = handle.context().apparent_value; let blueprint_id: u64 = blueprint_id.as_u64(); let preferences: Vec = preferences.into(); @@ -68,13 +71,24 @@ where .map_err(|_| revert("Invalid preferences data"))?; let registration_args: Vec> = - Decode::decode(&mut ®istration_args[..]) - .map_err(|_| revert("Invalid registration arguments"))?; - + if registration_args.is_empty() { + Vec::new() + } else { + Decode::decode(&mut ®istration_args[..]) + .map_err(|_| revert("Invalid registration arguments"))? + }; + let value_bytes = { + let mut value_bytes = [0u8; core::mem::size_of::()]; + value.to_little_endian(&mut value_bytes); + value_bytes + }; + let value = BalanceOf::::decode(&mut &value_bytes[..]) + .map_err(|_| revert("Value is not a valid balance"))?; let call = pallet_services::Call::::register { blueprint_id, preferences, registration_args, + value, }; RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; @@ -129,6 +143,14 @@ where let assets: Vec = assets.into_iter().map(|asset| asset.as_u32().into()).collect(); + let value_bytes = { + let value = handle.context().apparent_value; + let mut value_bytes = [0u8; core::mem::size_of::()]; + value.to_little_endian(&mut value_bytes); + value_bytes + }; + let value = BalanceOf::::decode(&mut &value_bytes[..]) + .map_err(|_| revert("Value is not a valid balance"))?; let call = pallet_services::Call::::request { blueprint_id, permitted_callers, @@ -136,6 +158,7 @@ where ttl: 10000_u32.into(), assets, request_args, + value, }; RuntimeHelper::::try_dispatch(handle, Some(origin).into(), call)?; diff --git a/precompiles/services/src/mock.rs b/precompiles/services/src/mock.rs index 718447c4..9a203e1e 100644 --- a/precompiles/services/src/mock.rs +++ b/precompiles/services/src/mock.rs @@ -22,7 +22,6 @@ use frame_election_provider_support::{ use frame_support::derive_impl; use frame_support::pallet_prelude::Hooks; use frame_support::pallet_prelude::Weight; -use frame_support::PalletId; use frame_support::{ construct_runtime, parameter_types, traits::{ConstU128, OneSessionHandler}, @@ -213,7 +212,7 @@ impl pallet_staking::Config for Runtime { } parameter_types! { - pub const ServicesPalletId: PalletId = PalletId(*b"py/srvcs"); + pub const ServicesEVMAddress: H160 = H160([0x11; 20]); } pub struct PalletEVMGasWeightMapping; @@ -235,6 +234,14 @@ impl EvmAddressMapping for PalletEVMAddressMapping { use pallet_evm::AddressMapping; ::AddressMapping::into_account_id(address) } + + fn into_address(account_id: AccountId) -> H160 { + account_id.using_encoded(|b| { + let mut addr = [0u8; 20]; + addr.copy_from_slice(&b[0..20]); + H160(addr) + }) + } } const PRECOMPILE_ADDRESS_BYTES: [u8; 32] = [ @@ -476,7 +483,7 @@ impl pallet_services::Config for Runtime { type ForceOrigin = frame_system::EnsureRoot; type Currency = Balances; type AssetId = AssetId; - type PalletId = ServicesPalletId; + type PalletEVMAddress = ServicesEVMAddress; type EvmRunner = MockedEvmRunner; type EvmAddressMapping = PalletEVMAddressMapping; type EvmGasWeightMapping = PalletEVMGasWeightMapping; diff --git a/precompiles/services/src/tests.rs b/precompiles/services/src/tests.rs index 44949097..5ec9d03f 100644 --- a/precompiles/services/src/tests.rs +++ b/precompiles/services/src/tests.rs @@ -138,7 +138,7 @@ fn test_register_operator() { PCall::register_operator { blueprint_id: U256::from(0), // We use the first blueprint preferences: UnboundedBytes::from(preferences_data), - registration_args: UnboundedBytes::from(vec![0u8]), + registration_args: UnboundedBytes::from(Vec::new()), }, ) .execute_returns(()); diff --git a/primitives/src/services/mod.rs b/primitives/src/services/mod.rs index 65ba94e1..7757ce25 100644 --- a/primitives/src/services/mod.rs +++ b/primitives/src/services/mod.rs @@ -40,7 +40,7 @@ use sp_core::{ecdsa, RuntimeDebug}; use sp_runtime::Percent; #[cfg(not(feature = "std"))] -use alloc::{vec, vec::Vec}; +use alloc::{string::String, vec, vec::Vec}; pub mod field; pub use field::*; @@ -546,6 +546,44 @@ pub struct PriceTargets { pub storage_nvme: u64, } +impl PriceTargets { + /// Converts the struct to ethabi ParamType. + pub fn to_ethabi_param_type() -> ethabi::ParamType { + ethabi::ParamType::Tuple(vec![ + // Price per vCPU per hour + ethabi::ParamType::Uint(64), + // Price per MB of memory per hour + ethabi::ParamType::Uint(64), + // Price per GB of HDD storage per hour + ethabi::ParamType::Uint(64), + // Price per GB of SSD storage per hour + ethabi::ParamType::Uint(64), + // Price per GB of NVMe storage per hour + ethabi::ParamType::Uint(64), + ]) + } + + /// Converts the struct to ethabi Param. + pub fn to_ethabi_param() -> ethabi::Param { + ethabi::Param { + name: String::from("priceTargets"), + kind: Self::to_ethabi_param_type(), + internal_type: Some(String::from("struct IBlueprintServiceManager.PriceTargets")), + } + } + + /// Converts the struct to ethabi Token. + pub fn to_ethabi(&self) -> ethabi::Token { + ethabi::Token::Tuple(vec![ + ethabi::Token::Uint(self.cpu.into()), + ethabi::Token::Uint(self.mem.into()), + ethabi::Token::Uint(self.storage_hdd.into()), + ethabi::Token::Uint(self.storage_ssd.into()), + ethabi::Token::Uint(self.storage_nvme.into()), + ]) + } +} + #[derive(PartialEq, Eq, Encode, Decode, RuntimeDebug, TypeInfo, Copy, Clone, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] pub struct OperatorPreferences { @@ -556,10 +594,34 @@ pub struct OperatorPreferences { } impl OperatorPreferences { + /// Returns the ethabi ParamType for OperatorPreferences. + pub fn to_ethabi_param_type() -> ethabi::ParamType { + ethabi::ParamType::Tuple(vec![ + // Operator's ECDSA Public Key (33 bytes) + ethabi::ParamType::Bytes, + // Operator's price targets + PriceTargets::to_ethabi_param_type(), + ]) + } + /// Returns the ethabi Param for OperatorPreferences. + pub fn to_ethabi_param() -> ethabi::Param { + ethabi::Param { + name: String::from("operatorPreferences"), + kind: Self::to_ethabi_param_type(), + internal_type: Some(String::from( + "struct IBlueprintServiceManager.OperatorPreferences", + )), + } + } + /// Encode the fields to ethabi bytes. pub fn to_ethabi(&self) -> Vec { - let tokens: Vec = vec![ethabi::Token::Bytes(self.key.0.to_vec())]; - tokens + vec![ethabi::Token::Tuple(vec![ + // operator public key + ethabi::Token::Bytes(self.key.0.to_vec()), + // price targets + self.price_targets.to_ethabi(), + ])] } } diff --git a/runtime/mainnet/src/tangle_services.rs b/runtime/mainnet/src/tangle_services.rs index 4b7b1c65..6c522baa 100644 --- a/runtime/mainnet/src/tangle_services.rs +++ b/runtime/mainnet/src/tangle_services.rs @@ -4,7 +4,7 @@ use pallet_evm::GasWeightMapping; use scale_info::TypeInfo; parameter_types! { - pub const ServicesPalletId: PalletId = PalletId(*b"py/srvcs"); + pub const ServicesEVMAddress: H160 = H160([0x11; 20]); } pub struct PalletEvmRunner; @@ -67,6 +67,14 @@ impl pallet_services::EvmAddressMapping for PalletEVMAddressMapping { use pallet_evm::AddressMapping; ::AddressMapping::into_account_id(address) } + + fn into_address(account_id: AccountId) -> H160 { + account_id.using_encoded(|b| { + let mut addr = [0u8; 20]; + addr.copy_from_slice(&b[0..20]); + H160(addr) + }) + } } parameter_types! { @@ -140,7 +148,7 @@ impl pallet_services::Config for Runtime { type RuntimeEvent = RuntimeEvent; type ForceOrigin = EnsureRootOrHalfCouncil; type Currency = Balances; - type PalletId = ServicesPalletId; + type PalletEVMAddress = ServicesEVMAddress; type EvmRunner = PalletEvmRunner; type EvmGasWeightMapping = PalletEVMGasWeightMapping; type EvmAddressMapping = PalletEVMAddressMapping; diff --git a/runtime/testnet/src/tangle_services.rs b/runtime/testnet/src/tangle_services.rs index 5b0b3635..afe1ffa2 100644 --- a/runtime/testnet/src/tangle_services.rs +++ b/runtime/testnet/src/tangle_services.rs @@ -1,7 +1,7 @@ use super::*; parameter_types! { - pub const ServicesPalletId: PalletId = PalletId(*b"py/srvcs"); + pub const ServicesEVMAddress: H160 = H160([0x11; 20]); } pub struct PalletEvmRunner; @@ -64,6 +64,14 @@ impl pallet_services::EvmAddressMapping for PalletEVMAddressMapping { use pallet_evm::AddressMapping; ::AddressMapping::into_account_id(address) } + + fn into_address(account_id: AccountId) -> H160 { + account_id.using_encoded(|b| { + let mut addr = [0u8; 20]; + addr.copy_from_slice(&b[0..20]); + H160(addr) + }) + } } parameter_types! { @@ -137,7 +145,7 @@ impl pallet_services::Config for Runtime { type RuntimeEvent = RuntimeEvent; type ForceOrigin = EnsureRootOrHalfCouncil; type Currency = Balances; - type PalletId = ServicesPalletId; + type PalletEVMAddress = ServicesEVMAddress; type EvmRunner = PalletEvmRunner; type EvmGasWeightMapping = PalletEVMGasWeightMapping; type EvmAddressMapping = PalletEVMAddressMapping; diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 8e9e19c9..e90983bc 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "1.79.0" -components = ["rustfmt", "clippy", "rust-src"] +channel = "1.79" +components = ["rustfmt", "clippy", "rust-src", "rust-analyzer"] targets = ["wasm32-unknown-unknown"]