ETH Price: $2,528.89 (+2.87%)

Contract

0x2EA682121f815FBcF86EA3F3CaFdd5d67F2dB143
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Create204926882024-08-09 17:59:1119 days ago1723226351IN
0x2EA68212...67F2dB143
0 ETH0.000136352.96724842
Create204926812024-08-09 17:57:4719 days ago1723226267IN
0x2EA68212...67F2dB143
0 ETH0.000098342.14015584
Create204926622024-08-09 17:53:5919 days ago1723226039IN
0x2EA68212...67F2dB143
0 ETH0.000143423.12122696
Deploy204507622024-08-03 21:39:4725 days ago1722721187IN
0x2EA68212...67F2dB143
0 ETH0.000784471.09743078
Register Agents204506892024-08-03 21:25:1125 days ago1722720311IN
0x2EA68212...67F2dB143
0 ETH0.000603721.98487786
Activate Registr...204506842024-08-03 21:24:1125 days ago1722720251IN
0x2EA68212...67F2dB143
0 ETH0.000101471.85012844
Update204506722024-08-03 21:21:4725 days ago1722720107IN
0x2EA68212...67F2dB143
0 ETH0.000217382.04650326
Unbond204500022024-08-03 19:07:2325 days ago1722712043IN
0x2EA68212...67F2dB143
0 ETH0.000249573.16820858
Terminate204499962024-08-03 19:06:1125 days ago1722711971IN
0x2EA68212...67F2dB143
0 ETH0.000297122.71518501
Deploy202212092024-07-02 20:27:4757 days ago1719952067IN
0x2EA68212...67F2dB143
0 ETH0.004678076.56843508
Register Agents202211842024-07-02 20:22:4757 days ago1719951767IN
0x2EA68212...67F2dB143
0 ETH0.001827726.00904354
Activate Registr...202211792024-07-02 20:21:4757 days ago1719951707IN
0x2EA68212...67F2dB143
0 ETH0.000329076
Update202211582024-07-02 20:17:3557 days ago1719951455IN
0x2EA68212...67F2dB143
0 ETH0.000685166.46956256
Update202211512024-07-02 20:16:1157 days ago1719951371IN
0x2EA68212...67F2dB143
0 ETH0.000517275.88305505
Unbond202211362024-07-02 20:13:1157 days ago1719951191IN
0x2EA68212...67F2dB143
0 ETH0.000401855.10126519
Terminate202211332024-07-02 20:12:3557 days ago1719951155IN
0x2EA68212...67F2dB143
0 ETH0.000543714.96849827
Deploy201896512024-06-28 10:40:5961 days ago1719571259IN
0x2EA68212...67F2dB143
0 ETH0.004324067.80696459
Register Agents201761062024-06-26 13:16:5963 days ago1719407819IN
0x2EA68212...67F2dB143
1 wei0.00165848.01295424
Activate Registr...201760912024-06-26 13:13:5963 days ago1719407639IN
0x2EA68212...67F2dB143
1 wei0.000416947.60215956
Create201758372024-06-26 12:22:4763 days ago1719404567IN
0x2EA68212...67F2dB143
0 ETH0.001654317.03515179
Create200102502024-06-03 8:57:4786 days ago1717405067IN
0x2EA68212...67F2dB143
0 ETH0.0030171613.01990877
Deploy196101752024-04-08 9:51:35142 days ago1712569895IN
0x2EA68212...67F2dB143
0 ETH0.0079937416.75917796
Register Agents196101732024-04-08 9:51:11142 days ago1712569871IN
0x2EA68212...67F2dB143
0.005 ETH0.0035361917.08585598
Activate Registr...196101712024-04-08 9:50:47142 days ago1712569847IN
0x2EA68212...67F2dB143
0.005 ETH0.0009502417.32577045
Create196101602024-04-08 9:48:35142 days ago1712569715IN
0x2EA68212...67F2dB143
0 ETH0.0041465317.62908169
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
204506892024-08-03 21:25:1125 days ago1722720311
0x2EA68212...67F2dB143
0 ETH
204506842024-08-03 21:24:1125 days ago1722720251
0x2EA68212...67F2dB143
0 ETH
202211842024-07-02 20:22:4757 days ago1719951767
0x2EA68212...67F2dB143
0 ETH
202211792024-07-02 20:21:4757 days ago1719951707
0x2EA68212...67F2dB143
0 ETH
201761062024-06-26 13:16:5963 days ago1719407819
0x2EA68212...67F2dB143
1 wei
201760912024-06-26 13:13:5963 days ago1719407639
0x2EA68212...67F2dB143
1 wei
200103282024-06-03 9:13:3586 days ago1717406015
0x2EA68212...67F2dB143
0.0005 ETH
200103282024-06-03 9:13:3586 days ago1717406015
0x2EA68212...67F2dB143
0.0005 ETH
200103172024-06-03 9:11:2386 days ago1717405883
0x2EA68212...67F2dB143
0.0005 ETH
200103172024-06-03 9:11:2386 days ago1717405883
0x2EA68212...67F2dB143
0.0005 ETH
196101732024-04-08 9:51:11142 days ago1712569871
0x2EA68212...67F2dB143
0.005 ETH
196101712024-04-08 9:50:47142 days ago1712569847
0x2EA68212...67F2dB143
0.005 ETH
195148022024-03-25 23:39:23155 days ago1711409963
0x2EA68212...67F2dB143
1 wei
195143112024-03-25 22:00:23156 days ago1711404023
0x2EA68212...67F2dB143
1 wei
194310862024-03-14 5:09:59167 days ago1710392999
0x2EA68212...67F2dB143
0 ETH
194238262024-03-13 4:39:59168 days ago1710304799
0x2EA68212...67F2dB143
0 ETH
194217732024-03-12 21:45:59169 days ago1710279959
0x2EA68212...67F2dB143
1 wei
194215692024-03-12 21:04:59169 days ago1710277499
0x2EA68212...67F2dB143
1 wei
188698642023-12-26 12:26:59246 days ago1703593619
0x2EA68212...67F2dB143
0 ETH
188698612023-12-26 12:26:23246 days ago1703593583
0x2EA68212...67F2dB143
0 ETH
188698212023-12-26 12:18:23246 days ago1703593103
0x2EA68212...67F2dB143
0 ETH
188698172023-12-26 12:17:35246 days ago1703593055
0x2EA68212...67F2dB143
0 ETH
186555772023-11-26 11:33:23276 days ago1700998403
0x2EA68212...67F2dB143
0.01 ETH
186555742023-11-26 11:32:47276 days ago1700998367
0x2EA68212...67F2dB143
0.01 ETH
186555012023-11-26 11:18:11276 days ago1700997491
0x2EA68212...67F2dB143
0 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ServiceManagerToken

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 750 runs

Other Settings:
default evmVersion
File 1 of 6 : ServiceManagerToken.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import {GenericManager} from "./GenericManager.sol";
import {OperatorSignedHashes} from "./utils/OperatorSignedHashes.sol";
import "./interfaces/IService.sol";
import "./interfaces/IServiceTokenUtility.sol";

// Operator whitelist interface
interface IOperatorWhitelist {
    /// @dev Gets operator whitelisting status.
    /// @param serviceId Service Id.
    /// @param operator Operator address.
    /// @return status Whitelisting status.
    function isOperatorWhitelisted(uint256 serviceId, address operator) external view returns (bool status);
}

// Generic token interface
interface IToken {
    /// @dev Gets the owner of the token Id.
    /// @param tokenId Token Id.
    /// @return Token Id owner address.
    function ownerOf(uint256 tokenId) external view returns (address);
}

/// @title Service Manager - Periphery smart contract for managing services with custom ERC20 tokens or ETH
/// @author Aleksandr Kuperman - <[email protected]>
/// @author AL
contract ServiceManagerToken is GenericManager, OperatorSignedHashes {
    event OperatorWhitelistUpdated(address indexed operatorWhitelist);
    event CreateMultisig(address indexed multisig);

    // Service Registry address
    address public immutable serviceRegistry;
    // Service Registry Token Utility address
    address public immutable serviceRegistryTokenUtility;
    // A well-known representation of ETH as an address
    address public constant ETH_TOKEN_ADDRESS = address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
    // Bond wrapping constant
    uint96 public constant BOND_WRAPPER = 1;
    // Operator whitelist address
    address public operatorWhitelist;

    /// @dev ServiceRegistryTokenUtility constructor.
    /// @param _serviceRegistry Service Registry contract address.
    /// @param _serviceRegistryTokenUtility Service Registry Token Utility contract address.
    constructor(address _serviceRegistry, address _serviceRegistryTokenUtility, address _operatorWhitelist)
        OperatorSignedHashes("Service Manager Token", "1.1.1")
    {
        // Check for the Service Registry related contract zero addresses
        if (_serviceRegistry == address(0) || _serviceRegistryTokenUtility == address(0)) {
            revert ZeroAddress();
        }

        serviceRegistry = _serviceRegistry;
        serviceRegistryTokenUtility = _serviceRegistryTokenUtility;
        operatorWhitelist = _operatorWhitelist;
        owner = msg.sender;
    }

    /// @dev Sets the operator whitelist contract address.
    /// @param newOperatorWhitelist New operator whitelist contract address.
    function setOperatorWhitelist(address newOperatorWhitelist) external {
        // Check for the contract ownership
        if (msg.sender != owner) {
            revert OwnerOnly(msg.sender, owner);
        }

        operatorWhitelist = newOperatorWhitelist;
        emit OperatorWhitelistUpdated(newOperatorWhitelist);
    }

    /// @dev Creates a new service.
    /// @param serviceOwner Individual that creates and controls a service.
    /// @param token ERC20 token address for the security deposit, or ETH.
    /// @param configHash IPFS hash pointing to the config metadata.
    /// @param agentIds Canonical agent Ids.
    /// @param agentParams Number of agent instances and required bond to register an instance in the service.
    /// @param threshold Threshold for a multisig composed by agents.
    /// @return serviceId Created service Id.
    function create(
        address serviceOwner,
        address token,
        bytes32 configHash,
        uint32[] memory agentIds,
        IService.AgentParams[] memory agentParams,
        uint32 threshold
    ) external returns (uint256 serviceId)
    {
        // Check if the minting is paused
        if (paused) {
            revert Paused();
        }

        // Check for the zero address
        if (token == address(0)) {
            revert ZeroAddress();
        }

        // Check for the custom ERC20 token or ETH based bond
        if (token == ETH_TOKEN_ADDRESS) {
            // Call the original ServiceRegistry contract function
            serviceId = IService(serviceRegistry).create(serviceOwner, configHash, agentIds, agentParams, threshold);
        } else {
            // Wrap agent params with just 1 WEI bond going to the original ServiceRegistry contract,
            // and actual token bonds being recorded with the ServiceRegistryTokenUtility contract
            uint256 numAgents = agentParams.length;
            uint256[] memory bonds = new uint256[](numAgents);
            for (uint256 i = 0; i < numAgents; ++i) {
                // Check for the zero bond value
                if (agentParams[i].bond == 0) {
                    revert ZeroValue();
                }

                // Copy actual bond values for each agent Id
                bonds[i] = agentParams[i].bond;
                // Wrap bonds with the BOND_WRAPPER value for the original ServiceRegistry contract
                agentParams[i].bond = BOND_WRAPPER;
            }

            // Call the original ServiceRegistry contract function
            serviceId = IService(serviceRegistry).create(serviceOwner, configHash, agentIds, agentParams, threshold);
            // Create a token-related record for the service
            IServiceTokenUtility(serviceRegistryTokenUtility).createWithToken(serviceId, token, agentIds, bonds);
        }
    }

    /// @dev Updates a service in a CRUD way.
    /// @param token ERC20 token address for the security deposit, or ETH.
    /// @param configHash IPFS hash pointing to the config metadata.
    /// @param agentIds Canonical agent Ids.
    /// @param agentParams Number of agent instances and required bond to register an instance in the service.
    /// @param threshold Threshold for a multisig composed by agents.
    /// @param serviceId Service Id to be updated.
    /// @return success True, if function executed successfully.
    function update(
        address token,
        bytes32 configHash,
        uint32[] memory agentIds,
        IService.AgentParams[] memory agentParams,
        uint32 threshold,
        uint256 serviceId
    ) external returns (bool success)
    {
        // Check for the zero address
        if (token == address(0)) {
            revert ZeroAddress();
        }

        uint256 numAgents = agentParams.length;
        if (token == ETH_TOKEN_ADDRESS) {
            // If any of the slots is a non-zero, the correspondent bond cannot be zero
            for (uint256 i = 0; i < numAgents; ++i) {
                // Check for the zero bond value
                if (agentParams[i].slots > 0 && agentParams[i].bond == 0) {
                        revert ZeroValue();
                }
            }
            // Call the original ServiceRegistry contract function
            success = IService(serviceRegistry).update(msg.sender, configHash, agentIds, agentParams, threshold, serviceId);
            // Reset the service token-based data
            // This function still needs to be called as the previous token could be a custom ERC20 token
            IServiceTokenUtility(serviceRegistryTokenUtility).resetServiceToken(serviceId);
        } else {
            // Wrap agent params with just 1 WEI bond going to the original ServiceRegistry contract,
            // and actual token bonds being recorded with the ServiceRegistryTokenUtility contract
            uint256[] memory bonds = new uint256[](numAgents);
            for (uint256 i = 0; i < numAgents; ++i) {
                // Copy actual bond values for each agent Id that has at least one slot in the updated service
                if (agentParams[i].slots > 0) {
                    // Check for the zero bond value
                    if (agentParams[i].bond == 0) {
                        revert ZeroValue();
                    }
                    bonds[i] = agentParams[i].bond;
                    // Wrap bonds with the BOND_WRAPPER value for the original ServiceRegistry contract
                    agentParams[i].bond = BOND_WRAPPER;
                }
            }

            // Call the original ServiceRegistry contract function
            success = IService(serviceRegistry).update(msg.sender, configHash, agentIds, agentParams, threshold, serviceId);
            // Update relevant data in the ServiceRegistryTokenUtility contract
            // We follow the optimistic design where existing bonds are just overwritten without a clearing
            // bond values of agent Ids that are not going to be used in the service. This is coming from the fact
            // that all the checks are done on the original ServiceRegistry side
            IServiceTokenUtility(serviceRegistryTokenUtility).createWithToken(serviceId, token, agentIds, bonds);
        }
    }

    /// @dev Activates the service and its sensitive components.
    /// @param serviceId Correspondent service Id.
    /// @return success True, if function executed successfully.
    function activateRegistration(uint256 serviceId) external payable returns (bool success) {
        // Record the actual ERC20 security deposit
        bool isTokenSecured = IServiceTokenUtility(serviceRegistryTokenUtility).activateRegistrationTokenDeposit(serviceId);

        // Activate registration in the original ServiceRegistry contract
        if (isTokenSecured) {
            // If the service Id is based on the ERC20 token, the provided value to the standard registration is 1
            success = IService(serviceRegistry).activateRegistration{value: BOND_WRAPPER}(msg.sender, serviceId);
        } else {
            // Otherwise follow the standard msg.value path
            success = IService(serviceRegistry).activateRegistration{value: msg.value}(msg.sender, serviceId);
        }
    }

    /// @dev Registers agent instances.
    /// @param serviceId Service Id to be updated.
    /// @param agentInstances Agent instance addresses.
    /// @param agentIds Canonical Ids of the agent correspondent to the agent instance.
    /// @return success True, if function executed successfully.
    function registerAgents(
        uint256 serviceId,
        address[] memory agentInstances,
        uint32[] memory agentIds
    ) external payable returns (bool success) {
        if (operatorWhitelist != address(0)) {
            // Check if the operator is whitelisted
            if (!IOperatorWhitelist(operatorWhitelist).isOperatorWhitelisted(serviceId, msg.sender)) {
                revert WrongOperator(serviceId);
            }
        }

        // Record the actual ERC20 bond
        bool isTokenSecured = IServiceTokenUtility(serviceRegistryTokenUtility).registerAgentsTokenDeposit(msg.sender,
            serviceId, agentIds);

        // Register agent instances in a main ServiceRegistry contract
        if (isTokenSecured) {
            // If the service Id is based on the ERC20 token, the provided value to the standard registration is 1
            // multiplied by the number of agent instances
            success = IService(serviceRegistry).registerAgents{value: agentInstances.length * BOND_WRAPPER}(msg.sender,
                serviceId, agentInstances, agentIds);
        } else {
            // Otherwise follow the standard msg.value path
            success = IService(serviceRegistry).registerAgents{value: msg.value}(msg.sender, serviceId, agentInstances, agentIds);
        }
    }

    /// @dev Creates multisig instance controlled by the set of service agent instances and deploys the service.
    /// @param serviceId Correspondent service Id.
    /// @param multisigImplementation Multisig implementation address.
    /// @param data Data payload for the multisig creation.
    /// @return multisig Address of the created multisig.
    function deploy(
        uint256 serviceId,
        address multisigImplementation,
        bytes memory data
    ) external returns (address multisig)
    {
        multisig = IService(serviceRegistry).deploy(msg.sender, serviceId, multisigImplementation, data);
        emit CreateMultisig(multisig);
    }

    /// @dev Terminates the service.
    /// @param serviceId Service Id.
    /// @return success True, if function executed successfully.
    /// @return refund Refund for the service owner.
    function terminate(uint256 serviceId) external returns (bool success, uint256 refund) {
        // Withdraw the ERC20 token if the service is token-based
        uint256 tokenRefund = IServiceTokenUtility(serviceRegistryTokenUtility).terminateTokenRefund(serviceId);

        // Terminate the service with the regular service registry routine
        (success, refund) = IService(serviceRegistry).terminate(msg.sender, serviceId);

        // If the service is token-based, the actual refund is provided via the serviceRegistryTokenUtility contract
        if (tokenRefund > 0) {
            refund = tokenRefund;
        }
    }

    /// @dev Unbonds agent instances of the operator from the service.
    /// @param serviceId Service Id.
    /// @return success True, if function executed successfully.
    /// @return refund The amount of refund returned to the operator.
    function unbond(uint256 serviceId) external returns (bool success, uint256 refund) {
        // Withdraw the ERC20 token if the service is token-based
        uint256 tokenRefund = IServiceTokenUtility(serviceRegistryTokenUtility).unbondTokenRefund(msg.sender, serviceId);

        // Unbond with the regular service registry routine
        (success, refund) = IService(serviceRegistry).unbond(msg.sender, serviceId);

        // If the service is token-based, the actual refund is provided via the serviceRegistryTokenUtility contract
        if (tokenRefund > 0) {
            refund = tokenRefund;
        }
    }

    /// @dev Unbonds agent instances of the operator by the service owner via the operator's pre-signed message hash.
    /// @notice Note that this function accounts for the operator being the EOA, or the contract that has an
    ///         isValidSignature() function that would confirm the message hash was signed by the operator contract.
    ///         Otherwise, if the message hash has been pre-approved, the corresponding map of hashes is going to
    ///         to verify the signed hash, similar to the Safe contract implementation in v1.3.0:
    ///         https://github.com/safe-global/safe-contracts/blob/186a21a74b327f17fc41217a927dea7064f74604/contracts/GnosisSafe.sol#L240-L304
    ///         Also note that only the service owner is able to call this function on behalf of the operator.
    /// @param operator Operator address that signed the unbond message hash.
    /// @param serviceId Service Id.
    /// @param signature Signature byte array associated with operator message hash signature.
    /// @return success True, if the function executed successfully.
    /// @return refund The amount of refund returned to the operator.
    function unbondWithSignature(
        address operator,
        uint256 serviceId,
        bytes memory signature
    ) external returns (bool success, uint256 refund)
    {
        // Check the service owner
        address serviceOwner = IToken(serviceRegistry).ownerOf(serviceId);
        if (msg.sender != serviceOwner) {
            revert OwnerOnly(msg.sender, serviceOwner);
        }

        // Get the (operator | serviceId) nonce for the unbond message
        // Push a pair of key defining variables into one key. Service Id or operator are not enough by themselves
        // as another service might use the operator address at the same time frame
        // operator occupies first 160 bits
        uint256 operatorService = uint256(uint160(operator));
        // serviceId occupies next 32 bits
        operatorService |= serviceId << 160;
        uint256 nonce = mapOperatorUnbondNonces[operatorService];
        // Get the unbond message hash
        bytes32 msgHash = getUnbondHash(operator, serviceOwner, serviceId, nonce);

        // Verify the signed hash against the operator address
        _verifySignedHash(operator, msgHash, signature);

        // Update corresponding nonce value
        nonce++;
        mapOperatorUnbondNonces[operatorService] = nonce;

        // Withdraw the ERC20 token if the service is token-based
        uint256 tokenRefund = IServiceTokenUtility(serviceRegistryTokenUtility).unbondTokenRefund(operator, serviceId);

        // Unbond with the regular service registry routine
        (success, refund) = IService(serviceRegistry).unbond(operator, serviceId);

        // If the service is token-based, the actual refund is provided via the serviceRegistryTokenUtility contract
        if (tokenRefund > 0) {
            refund = tokenRefund;
        }
    }

    /// @dev Registers agent instances of the operator by the service owner via the operator's pre-signed message hash.
    /// @notice Note that this function accounts for the operator being the EOA, or the contract that has an
    ///         isValidSignature() function that would confirm the message hash was signed by the operator contract.
    ///         Otherwise, if the message hash has been pre-approved, the corresponding map of hashes is going to
    ///         to verify the signed hash, similar to the Safe contract implementation in v1.3.0:
    ///         https://github.com/safe-global/safe-contracts/blob/186a21a74b327f17fc41217a927dea7064f74604/contracts/GnosisSafe.sol#L240-L304
    ///         Also note that only the service owner is able to call this function on behalf of the operator.
    /// @param operator Operator address that signed the register agents message hash.
    /// @param serviceId Service Id.
    /// @param agentInstances Agent instance addresses.
    /// @param agentIds Canonical Ids of the agent correspondent to the agent instance.
    /// @param signature Signature byte array associated with operator message hash signature.
    /// @return success True, if the the function executed successfully.
    function registerAgentsWithSignature(
        address operator,
        uint256 serviceId,
        address[] memory agentInstances,
        uint32[] memory agentIds,
        bytes memory signature
    ) external payable returns (bool success) {
        // Check the service owner
        address serviceOwner = IToken(serviceRegistry).ownerOf(serviceId);
        if (msg.sender != serviceOwner) {
            revert OwnerOnly(msg.sender, serviceOwner);
        }

        // Get the (operator | serviceId) nonce for the registerAgents message
        // Push a pair of key defining variables into one key. Service Id or operator are not enough by themselves
        // as another service might use the operator address at the same time frame
        // operator occupies first 160 bits
        uint256 operatorService = uint256(uint160(operator));
        // serviceId occupies next 32 bits as serviceId is limited by the 2^32 - 1 value
        operatorService |= serviceId << 160;
        uint256 nonce = mapOperatorRegisterAgentsNonces[operatorService];
        // Get register agents message hash
        bytes32 msgHash = getRegisterAgentsHash(operator, serviceOwner, serviceId, agentInstances, agentIds, nonce);

        // Verify the signed hash against the operator address
        _verifySignedHash(operator, msgHash, signature);

        // Update corresponding nonce value
        nonce++;
        mapOperatorRegisterAgentsNonces[operatorService] = nonce;

        // Record the actual ERC20 bond
        bool isTokenSecured = IServiceTokenUtility(serviceRegistryTokenUtility).registerAgentsTokenDeposit(operator,
            serviceId, agentIds);

        // Register agent instances in a main ServiceRegistry contract
        if (isTokenSecured) {
            // If the service Id is based on the ERC20 token, the provided value to the standard registration is 1
            // multiplied by the number of agent instances
            success = IService(serviceRegistry).registerAgents{value: agentInstances.length * BOND_WRAPPER}(operator,
                serviceId, agentInstances, agentIds);
        } else {
            // Otherwise follow the standard msg.value path
            success = IService(serviceRegistry).registerAgents{value: msg.value}(operator, serviceId, agentInstances, agentIds);
        }
    }
}

File 2 of 6 : GenericManager.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;

import "./interfaces/IErrorsRegistries.sol";

/// @title Generic Manager - Smart contract for generic registry manager template
/// @author Aleksandr Kuperman - <[email protected]>
abstract contract GenericManager is IErrorsRegistries {
    event OwnerUpdated(address indexed owner);
    event Pause(address indexed owner);
    event Unpause(address indexed owner);

    // Owner address
    address public owner;
    // Pause switch
    bool public paused;

    /// @dev Changes the owner address.
    /// @param newOwner Address of a new owner.
    function changeOwner(address newOwner) external virtual {
        // Check for the ownership
        if (msg.sender != owner) {
            revert OwnerOnly(msg.sender, owner);
        }

        // Check for the zero address
        if (newOwner == address(0)) {
            revert ZeroAddress();
        }

        owner = newOwner;
        emit OwnerUpdated(newOwner);
    }

    /// @dev Pauses the contract.
    function pause() external virtual {
        // Check for the ownership
        if (msg.sender != owner) {
            revert OwnerOnly(msg.sender, owner);
        }

        paused = true;
        emit Pause(msg.sender);
    }

    /// @dev Unpauses the contract.
    function unpause() external virtual {
        // Check for the ownership
        if (msg.sender != owner) {
            revert OwnerOnly(msg.sender, owner);
        }

        paused = false;
        emit Unpause(msg.sender);
    }
}

File 3 of 6 : IErrorsRegistries.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;

/// @dev Errors.
interface IErrorsRegistries {
    /// @dev Only `manager` has a privilege, but the `sender` was provided.
    /// @param sender Sender address.
    /// @param manager Required sender address as a manager.
    error ManagerOnly(address sender, address manager);

    /// @dev Only `owner` has a privilege, but the `sender` was provided.
    /// @param sender Sender address.
    /// @param owner Required sender address as an owner.
    error OwnerOnly(address sender, address owner);

    /// @dev Hash already exists in the records.
    error HashExists();

    /// @dev Provided zero address.
    error ZeroAddress();

    /// @dev Agent Id is not correctly provided for the current routine.
    /// @param agentId Component Id.
    error WrongAgentId(uint256 agentId);

    /// @dev Wrong length of two arrays.
    /// @param numValues1 Number of values in a first array.
    /// @param numValues2 Numberf of values in a second array.
    error WrongArrayLength(uint256 numValues1, uint256 numValues2);

    /// @dev Canonical agent Id is not found.
    /// @param agentId Canonical agent Id.
    error AgentNotFound(uint256 agentId);

    /// @dev Component Id is not found.
    /// @param componentId Component Id.
    error ComponentNotFound(uint256 componentId);

    /// @dev Multisig threshold is out of bounds.
    /// @param currentThreshold Current threshold value.
    /// @param minThreshold Minimum possible threshold value.
    /// @param maxThreshold Maximum possible threshold value.
    error WrongThreshold(uint256 currentThreshold, uint256 minThreshold, uint256 maxThreshold);

    /// @dev Agent instance is already registered with a specified `operator`.
    /// @param operator Operator that registered an instance.
    error AgentInstanceRegistered(address operator);

    /// @dev Wrong operator is specified when interacting with a specified `serviceId`.
    /// @param serviceId Service Id.
    error WrongOperator(uint256 serviceId);

    /// @dev Operator has no registered instances in the service.
    /// @param operator Operator address.
    /// @param serviceId Service Id.
    error OperatorHasNoInstances(address operator, uint256 serviceId);

    /// @dev Canonical `agentId` is not found as a part of `serviceId`.
    /// @param agentId Canonical agent Id.
    /// @param serviceId Service Id.
    error AgentNotInService(uint256 agentId, uint256 serviceId);

    /// @dev The contract is paused.
    error Paused();

    /// @dev Zero value when it has to be different from zero.
    error ZeroValue();

    /// @dev Value overflow.
    /// @param provided Overflow value.
    /// @param max Maximum possible value.
    error Overflow(uint256 provided, uint256 max);

    /// @dev Service must be inactive.
    /// @param serviceId Service Id.
    error ServiceMustBeInactive(uint256 serviceId);

    /// @dev All the agent instance slots for a specific `serviceId` are filled.
    /// @param serviceId Service Id.
    error AgentInstancesSlotsFilled(uint256 serviceId);

    /// @dev Wrong state of a service.
    /// @param state Service state.
    /// @param serviceId Service Id.
    error WrongServiceState(uint256 state, uint256 serviceId);

    /// @dev Only own service multisig is allowed.
    /// @param provided Provided address.
    /// @param expected Expected multisig address.
    /// @param serviceId Service Id.
    error OnlyOwnServiceMultisig(address provided, address expected, uint256 serviceId);

    /// @dev Multisig is not whitelisted.
    /// @param multisig Address of a multisig implementation.
    error UnauthorizedMultisig(address multisig);

    /// @dev Incorrect deposit provided for the registration activation.
    /// @param sent Sent amount.
    /// @param expected Expected amount.
    /// @param serviceId Service Id.
    error IncorrectRegistrationDepositValue(uint256 sent, uint256 expected, uint256 serviceId);

    /// @dev Insufficient value provided for the agent instance bonding.
    /// @param sent Sent amount.
    /// @param expected Expected amount.
    /// @param serviceId Service Id.
    error IncorrectAgentBondingValue(uint256 sent, uint256 expected, uint256 serviceId);

    /// @dev Failure of a transfer.
    /// @param token Address of a token.
    /// @param from Address `from`.
    /// @param to Address `to`.
    /// @param value Value.
    error TransferFailed(address token, address from, address to, uint256 value);

    /// @dev Caught reentrancy violation.
    error ReentrancyGuard();
}

File 4 of 6 : IService.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;

/// @dev Required interface for the service manipulation.
interface IService{
    struct AgentParams {
        // Number of agent instances
        uint32 slots;
        // Bond per agent instance
        uint96 bond;
    }

    /// @dev Creates a new service.
    /// @param serviceOwner Individual that creates and controls a service.
    /// @param configHash IPFS hash pointing to the config metadata.
    /// @param agentIds Canonical agent Ids in a sorted ascending order.
    /// @param agentParams Number of agent instances and required bond to register an instance in the service.
    /// @param threshold Signers threshold for a multisig composed by agent instances.
    /// @return serviceId Created service Id.
    function create(
        address serviceOwner,
        bytes32 configHash,
        uint32[] memory agentIds,
        AgentParams[] memory agentParams,
        uint32 threshold
    ) external returns (uint256 serviceId);

    /// @dev Updates a service in a CRUD way.
    /// @param serviceOwner Individual that creates and controls a service.
    /// @param configHash IPFS hash pointing to the config metadata.
    /// @param agentIds Canonical agent Ids in a sorted ascending order.
    /// @param agentParams Number of agent instances and required bond to register an instance in the service.
    /// @param threshold Signers threshold for a multisig composed by agent instances.
    /// @param serviceId Service Id to be updated.
    /// @return success True, if function executed successfully.
    function update(
        address serviceOwner,
        bytes32 configHash,
        uint32[] memory agentIds,
        AgentParams[] memory agentParams,
        uint32 threshold,
        uint256 serviceId
    ) external returns (bool success);

    /// @dev Activates the service.
    /// @param serviceOwner Individual that creates and controls a service.
    /// @param serviceId Correspondent service Id.
    /// @return success True, if function executed successfully.
    function activateRegistration(address serviceOwner, uint256 serviceId) external payable returns (bool success);

    /// @dev Registers agent instances.
    /// @param operator Address of the operator.
    /// @param serviceId Service Id to be updated.
    /// @param agentInstances Agent instance addresses.
    /// @param agentIds Canonical Ids of the agent correspondent to the agent instance.
    /// @return success True, if function executed successfully.
    function registerAgents(
        address operator,
        uint256 serviceId,
        address[] memory agentInstances,
        uint32[] memory agentIds
    ) external payable returns (bool success);

    /// @dev Creates multisig instance controlled by the set of service agent instances and deploys the service.
    /// @param serviceOwner Individual that creates and controls a service.
    /// @param serviceId Correspondent service Id.
    /// @param multisigImplementation Multisig implementation address.
    /// @param data Data payload for the multisig creation.
    /// @return multisig Address of the created multisig.
    function deploy(
        address serviceOwner,
        uint256 serviceId,
        address multisigImplementation,
        bytes memory data
    ) external returns (address multisig);

    /// @dev Terminates the service.
    /// @param serviceOwner Owner of the service.
    /// @param serviceId Service Id to be updated.
    /// @return success True, if function executed successfully.
    /// @return refund Refund to return to the serviceOwner.
    function terminate(address serviceOwner, uint256 serviceId) external returns (bool success, uint256 refund);

    /// @dev Unbonds agent instances of the operator from the service.
    /// @param operator Operator of agent instances.
    /// @param serviceId Service Id.
    /// @return success True, if function executed successfully.
    /// @return refund The amount of refund returned to the operator.
    function unbond(address operator, uint256 serviceId) external returns (bool success, uint256 refund);
}

File 5 of 6 : IServiceTokenUtility.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

/// @dev Interface for the service registration token utility manipulation.
interface IServiceTokenUtility {
    /// @dev Creates a record with the token-related information for the specified service.
    /// @param serviceId Service Id.
    /// @param token Token address.
    /// @param agentIds Set of agent Ids.
    /// @param bonds Set of correspondent bonds.
    function createWithToken(
        uint256 serviceId,
        address token,
        uint32[] memory agentIds,
        uint256[] memory bonds
    ) external;

    /// @dev Resets a record with token and security deposit data.
    /// @param serviceId Service Id.
    function resetServiceToken(uint256 serviceId) external;

    /// @dev Deposit a token security deposit for the service registration after its activation.
    /// @param serviceId Service Id.
    /// @return isTokenSecured True if the service Id is token secured, false if ETH secured otherwise.
    function activateRegistrationTokenDeposit(uint256 serviceId) external returns (bool isTokenSecured);

    /// @dev Deposits bonded tokens from the operator during the agent instance registration.
    /// @param operator Operator address.
    /// @param serviceId Service Id.
    /// @param agentIds Set of agent Ids for corresponding agent instances opertor is registering.
    /// @return isTokenSecured True if the service Id is token secured, false if ETH secured otherwise.
    function registerAgentsTokenDeposit(
        address operator,
        uint256 serviceId,
        uint32[] memory agentIds
    ) external returns (bool isTokenSecured);

    /// @dev Withdraws a token security deposit to the service owner after the service termination.
    /// @param serviceId Service Id.
    /// @return securityRefund Returned token security deposit, or zero if the service is ETH-secured.
    function terminateTokenRefund(uint256 serviceId) external returns (uint256 securityRefund);

    /// @dev Withdraws bonded tokens to the operator during the unbond phase.
    /// @param operator Operator address.
    /// @param serviceId Service Id.
    /// @return refund Returned bonded token amount, or zero if the service is ETH-secured.
    function unbondTokenRefund(address operator, uint256 serviceId) external returns (uint256 refund);

    /// @dev Gets service token secured status.
    /// @param serviceId Service Id.
    /// @return True if the service Id is token secured.
    function isTokenSecuredService(uint256 serviceId) external view returns (bool);
}

File 6 of 6 : OperatorSignedHashes.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

interface ISignatureValidator {
    /// @dev Should return whether the signature provided is valid for the provided hash.
    /// @notice MUST return the bytes4 magic value 0x1626ba7e when function passes.
    ///         MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5).
    ///         MUST allow external calls.
    /// @param hash Hash of the data to be signed.
    /// @param signature Signature byte array associated with hash.
    /// @return magicValue bytes4 magic value.
    function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);
}

/// @dev Provided zero address.
error ZeroOperatorAddress();

/// @dev Incorrect signature length provided.
/// @param signature Signature bytes.
/// @param provided Provided signature length.
/// @param expected Expected signature length.
error IncorrectSignatureLength(bytes signature, uint256 provided, uint256 expected);

/// @dev Hash is not validated.
/// @param operator Operator contract address.
/// @param msgHash Message hash.
/// @param signature Signature bytes associated with the message hash.
error HashNotValidated(address operator, bytes32 msgHash, bytes signature);

/// @dev Hash is not approved.
/// @param operator Operator address.
/// @param msgHash Message hash.
/// @param signature Signature bytes associated with the message hash.
error HashNotApproved(address operator, bytes32 msgHash, bytes signature);

/// @dev Obtained wrong operator address.
/// @param provided Provided address.
/// @param expected Expected address.
error WrongOperatorAddress(address provided, address expected);

/// @title OperatorSignedHashes - Smart contract for managing operator signed hashes
/// @author AL
/// @author Aleksandr Kuperman - <[email protected]>
contract OperatorSignedHashes {
    event OperatorHashApproved(address indexed operator, bytes32 hash);

    // Value for the contract signature validation: bytes4(keccak256("isValidSignature(bytes32,bytes)")
    bytes4 constant internal MAGIC_VALUE = 0x1626ba7e;
    // Domain separator type hash
    bytes32 public constant DOMAIN_SEPARATOR_TYPE_HASH =
        keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
    // Unbond type hash
    bytes32 public constant UNBOND_TYPE_HASH =
        keccak256("Unbond(address operator,address serviceOwner,uint256 serviceId,uint256 nonce)");
    // Register agents type hash
    bytes32 public constant REGISTER_AGENTS_TYPE_HASH =
        keccak256("RegisterAgents(address operator,address serviceOwner,uint256 serviceId,bytes32 agentsData,uint256 nonce)");
    // Original domain separator value
    bytes32 public immutable domainSeparator;
    // Original chain Id
    uint256 public immutable chainId;
    // Name hash
    bytes32 public immutable nameHash;
    // Version hash
    bytes32 public immutable versionHash;

    // Name of a signing domain
    string public name;
    // Version of a signing domain
    string public version;

    // Map of operator address and serviceId => unbond nonce
    mapping(uint256 => uint256) public mapOperatorUnbondNonces;
    // Map of operator address and serviceId => register agents nonce
    mapping(uint256 => uint256) public mapOperatorRegisterAgentsNonces;
    // Mapping operator address => approved hashes status
    mapping(address => mapping(bytes32 => bool)) public mapOperatorApprovedHashes;

    /// @dev Contract constructor.
    /// @param _name Name of a signing domain.
    /// @param _version Version of a signing domain.
    constructor(string memory _name, string memory _version) {
        name = _name;
        version = _version;
        nameHash = keccak256(bytes(_name));
        versionHash = keccak256(bytes(_version));
        chainId = block.chainid;
        domainSeparator = _computeDomainSeparator();
    }

    /// @dev Verifies provided message hash against its signature.
    /// @param operator Operator address.
    /// @param msgHash Message hash.
    /// @param signature Signature bytes associated with the signed message hash.
    function _verifySignedHash(address operator, bytes32 msgHash, bytes memory signature) internal view {
        // Check for the operator zero address
        if (operator == address(0)) {
            revert ZeroOperatorAddress();
        }

        // Check for the signature length
        if (signature.length != 65) {
            revert IncorrectSignatureLength(signature, signature.length, 65);
        }

        // Decode the signature
        uint8 v = uint8(signature[64]);
        // For the correct ecrecover() function execution, the v value must be set to {0,1} + 27
        // Although v in a very rare case can be equal to {2,3} (with a probability of 3.73e-37%)
        // If v is set to just 0 or 1 when signing  by the EOA, it is most likely signed by the ledger and must be adjusted
        if (v < 4 && operator.code.length == 0) {
            // In case of a non-contract, adjust v to follow the standard ecrecover case
            v += 27;
        }
        bytes32 r;
        bytes32 s;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            r := mload(add(signature, 32))
            s := mload(add(signature, 64))
        }

        address recOperator;
        // Go through signature cases based on the value of v
        if (v == 4) {
            // Contract signature case, where the address of the contract is encoded into r
            recOperator = address(uint160(uint256(r)));

            // Check for the signature validity in the contract
            if (ISignatureValidator(recOperator).isValidSignature(msgHash, signature) != MAGIC_VALUE) {
                revert HashNotValidated(recOperator, msgHash, signature);
            }
        } else if (v == 5) {
            // Case of an approved hash, where the address of the operator is encoded into r
            recOperator = address(uint160(uint256(r)));

            // Hashes have been pre-approved by the operator via a separate message, see operatorApproveHash() function
            if (!mapOperatorApprovedHashes[recOperator][msgHash]) {
                revert HashNotApproved(recOperator, msgHash, signature);
            }
        } else {
            // Case of ecrecover with the message hash for EOA signatures
            recOperator = ecrecover(msgHash, v, r, s);
        }

        // Final check is for the operator address itself
        if (recOperator != operator) {
            revert WrongOperatorAddress(recOperator, operator);
        }
    }

    /// @dev Approves message hash for the operator address.
    /// @param hash Provided message hash to approve.
    function operatorApproveHash(bytes32 hash) external {
        mapOperatorApprovedHashes[msg.sender][hash] = true;
        emit OperatorHashApproved(msg.sender, hash);
    }

    /// @dev Computes domain separator hash.
    /// @return Hash of the domain separator based on its name, version, chain Id and contract address.
    function _computeDomainSeparator() internal view returns (bytes32) {
        return keccak256(
            abi.encode(
                DOMAIN_SEPARATOR_TYPE_HASH,
                nameHash,
                versionHash,
                block.chainid,
                address(this)
            )
        );
    }

    /// @dev Gets the already computed domain separator of recomputes one if the chain Id is different.
    /// @return Original or recomputed domain separator.
    function getDomainSeparator() public view returns (bytes32) {
        return block.chainid == chainId ? domainSeparator : _computeDomainSeparator();
    }

    /// @dev Gets the unbond message hash for the operator.
    /// @param operator Operator address.
    /// @param serviceOwner Service owner address.
    /// @param serviceId Service Id.
    /// @param nonce Nonce for the unbond message from the pair of (operator | service Id).
    /// @return Computed message hash.
    function getUnbondHash(
        address operator,
        address serviceOwner,
        uint256 serviceId,
        uint256 nonce
    ) public view returns (bytes32)
    {
        return keccak256(
            abi.encodePacked(
                "\x19\x01",
                getDomainSeparator(),
                keccak256(
                    abi.encode(
                        UNBOND_TYPE_HASH,
                        operator,
                        serviceOwner,
                        serviceId,
                        nonce
                    )
                )
            )
        );
    }

    /// @dev Gets the register agents message hash for the operator.
    /// @param operator Operator address.
    /// @param serviceOwner Service owner address.
    /// @param serviceId Service Id.
    /// @param agentInstances Agent instance addresses operator is going to register.
    /// @param agentIds Agent Ids corresponding to each agent instance address.
    /// @param nonce Nonce for the register agents message from the pair of (operator | service Id).
    /// @return Computed message hash.
    function getRegisterAgentsHash(
        address operator,
        address serviceOwner,
        uint256 serviceId,
        address[] memory agentInstances,
        uint32[] memory agentIds,
        uint256 nonce
    ) public view returns (bytes32)
    {
        return keccak256(
            abi.encodePacked(
                "\x19\x01",
                getDomainSeparator(),
                keccak256(
                    abi.encode(
                        REGISTER_AGENTS_TYPE_HASH,
                        operator,
                        serviceOwner,
                        serviceId,
                        keccak256(abi.encode(agentInstances, agentIds)),
                        nonce
                    )
                )
            )
        );
    }

    /// @dev Checks if the hash provided by the operator is approved.
    /// @param operator Operator address.
    /// @param hash Message hash.
    /// @return True, if the hash provided by the operator is approved.
    function isOperatorHashApproved(address operator, bytes32 hash) external view returns (bool) {
        return mapOperatorApprovedHashes[operator][hash];
    }

    /// @dev Gets the (operator | service Id) nonce for the unbond message data.
    /// @param operator Operator address.
    /// @param serviceId Service Id.
    /// @return nonce Obtained nonce.
    function getOperatorUnbondNonce(address operator, uint256 serviceId) external view returns (uint256 nonce) {
        // operator occupies first 160 bits
        uint256 operatorService = uint256(uint160(operator));
        // serviceId occupies next 32 bits as serviceId is limited by the 2^32 - 1 value
        operatorService |= serviceId << 160;
        nonce = mapOperatorUnbondNonces[operatorService];
    }

    /// @dev Gets the (operator | service Id) nonce for the register agents message data.
    /// @param operator Operator address.
    /// @param serviceId Service Id.
    /// @return nonce Obtained nonce.
    function getOperatorRegisterAgentsNonce(address operator, uint256 serviceId) external view returns (uint256 nonce) {
        // operator occupies first 160 bits
        uint256 operatorService = uint256(uint160(operator));
        // serviceId occupies next 32 bits as serviceId is limited by the 2^32 - 1 value
        operatorService |= serviceId << 160;
        nonce = mapOperatorRegisterAgentsNonces[operatorService];
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 750
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_serviceRegistry","type":"address"},{"internalType":"address","name":"_serviceRegistryTokenUtility","type":"address"},{"internalType":"address","name":"_operatorWhitelist","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"AgentInstanceRegistered","type":"error"},{"inputs":[{"internalType":"uint256","name":"serviceId","type":"uint256"}],"name":"AgentInstancesSlotsFilled","type":"error"},{"inputs":[{"internalType":"uint256","name":"agentId","type":"uint256"}],"name":"AgentNotFound","type":"error"},{"inputs":[{"internalType":"uint256","name":"agentId","type":"uint256"},{"internalType":"uint256","name":"serviceId","type":"uint256"}],"name":"AgentNotInService","type":"error"},{"inputs":[{"internalType":"uint256","name":"componentId","type":"uint256"}],"name":"ComponentNotFound","type":"error"},{"inputs":[],"name":"HashExists","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bytes32","name":"msgHash","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"HashNotApproved","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bytes32","name":"msgHash","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"HashNotValidated","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"serviceId","type":"uint256"}],"name":"IncorrectAgentBondingValue","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"serviceId","type":"uint256"}],"name":"IncorrectRegistrationDepositValue","type":"error"},{"inputs":[{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"provided","type":"uint256"},{"internalType":"uint256","name":"expected","type":"uint256"}],"name":"IncorrectSignatureLength","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"manager","type":"address"}],"name":"ManagerOnly","type":"error"},{"inputs":[{"internalType":"address","name":"provided","type":"address"},{"internalType":"address","name":"expected","type":"address"},{"internalType":"uint256","name":"serviceId","type":"uint256"}],"name":"OnlyOwnServiceMultisig","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"serviceId","type":"uint256"}],"name":"OperatorHasNoInstances","type":"error"},{"inputs":[{"internalType":"uint256","name":"provided","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"name":"Overflow","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"OwnerOnly","type":"error"},{"inputs":[],"name":"Paused","type":"error"},{"inputs":[],"name":"ReentrancyGuard","type":"error"},{"inputs":[{"internalType":"uint256","name":"serviceId","type":"uint256"}],"name":"ServiceMustBeInactive","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"TransferFailed","type":"error"},{"inputs":[{"internalType":"address","name":"multisig","type":"address"}],"name":"UnauthorizedMultisig","type":"error"},{"inputs":[{"internalType":"uint256","name":"agentId","type":"uint256"}],"name":"WrongAgentId","type":"error"},{"inputs":[{"internalType":"uint256","name":"numValues1","type":"uint256"},{"internalType":"uint256","name":"numValues2","type":"uint256"}],"name":"WrongArrayLength","type":"error"},{"inputs":[{"internalType":"uint256","name":"serviceId","type":"uint256"}],"name":"WrongOperator","type":"error"},{"inputs":[{"internalType":"address","name":"provided","type":"address"},{"internalType":"address","name":"expected","type":"address"}],"name":"WrongOperatorAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"state","type":"uint256"},{"internalType":"uint256","name":"serviceId","type":"uint256"}],"name":"WrongServiceState","type":"error"},{"inputs":[{"internalType":"uint256","name":"currentThreshold","type":"uint256"},{"internalType":"uint256","name":"minThreshold","type":"uint256"},{"internalType":"uint256","name":"maxThreshold","type":"uint256"}],"name":"WrongThreshold","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroOperatorAddress","type":"error"},{"inputs":[],"name":"ZeroValue","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"multisig","type":"address"}],"name":"CreateMultisig","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bytes32","name":"hash","type":"bytes32"}],"name":"OperatorHashApproved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operatorWhitelist","type":"address"}],"name":"OperatorWhitelistUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"OwnerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"Pause","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"Unpause","type":"event"},{"inputs":[],"name":"BOND_WRAPPER","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_SEPARATOR_TYPE_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ETH_TOKEN_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REGISTER_AGENTS_TYPE_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNBOND_TYPE_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"serviceId","type":"uint256"}],"name":"activateRegistration","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"chainId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"changeOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"serviceOwner","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"bytes32","name":"configHash","type":"bytes32"},{"internalType":"uint32[]","name":"agentIds","type":"uint32[]"},{"components":[{"internalType":"uint32","name":"slots","type":"uint32"},{"internalType":"uint96","name":"bond","type":"uint96"}],"internalType":"struct IService.AgentParams[]","name":"agentParams","type":"tuple[]"},{"internalType":"uint32","name":"threshold","type":"uint32"}],"name":"create","outputs":[{"internalType":"uint256","name":"serviceId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"serviceId","type":"uint256"},{"internalType":"address","name":"multisigImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"deploy","outputs":[{"internalType":"address","name":"multisig","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"domainSeparator","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDomainSeparator","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"serviceId","type":"uint256"}],"name":"getOperatorRegisterAgentsNonce","outputs":[{"internalType":"uint256","name":"nonce","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"serviceId","type":"uint256"}],"name":"getOperatorUnbondNonce","outputs":[{"internalType":"uint256","name":"nonce","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"serviceOwner","type":"address"},{"internalType":"uint256","name":"serviceId","type":"uint256"},{"internalType":"address[]","name":"agentInstances","type":"address[]"},{"internalType":"uint32[]","name":"agentIds","type":"uint32[]"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"getRegisterAgentsHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"serviceOwner","type":"address"},{"internalType":"uint256","name":"serviceId","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"getUnbondHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bytes32","name":"hash","type":"bytes32"}],"name":"isOperatorHashApproved","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"mapOperatorApprovedHashes","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"mapOperatorRegisterAgentsNonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"mapOperatorUnbondNonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nameHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"}],"name":"operatorApproveHash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"operatorWhitelist","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"serviceId","type":"uint256"},{"internalType":"address[]","name":"agentInstances","type":"address[]"},{"internalType":"uint32[]","name":"agentIds","type":"uint32[]"}],"name":"registerAgents","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"serviceId","type":"uint256"},{"internalType":"address[]","name":"agentInstances","type":"address[]"},{"internalType":"uint32[]","name":"agentIds","type":"uint32[]"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"registerAgentsWithSignature","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"serviceRegistry","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"serviceRegistryTokenUtility","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOperatorWhitelist","type":"address"}],"name":"setOperatorWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"serviceId","type":"uint256"}],"name":"terminate","outputs":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"uint256","name":"refund","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"serviceId","type":"uint256"}],"name":"unbond","outputs":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"uint256","name":"refund","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"serviceId","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"unbondWithSignature","outputs":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"uint256","name":"refund","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bytes32","name":"configHash","type":"bytes32"},{"internalType":"uint32[]","name":"agentIds","type":"uint32[]"},{"components":[{"internalType":"uint32","name":"slots","type":"uint32"},{"internalType":"uint96","name":"bond","type":"uint96"}],"internalType":"struct IService.AgentParams[]","name":"agentParams","type":"tuple[]"},{"internalType":"uint32","name":"threshold","type":"uint32"},{"internalType":"uint256","name":"serviceId","type":"uint256"}],"name":"update","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"versionHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"}]

6101406040523480156200001257600080fd5b506040516200365e3803806200365e8339810160408190526200003591620001cf565b6040518060400160405280601581526020017f53657276696365204d616e6167657220546f6b656e000000000000000000000081525060405180604001604052806005815260200164312e312e3160d81b81525081600190816200009a9190620002be565b506002620000a98282620002be565b50815160208084019190912060c05281519082012060e0524660a0526200013160c0805160e051604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a08201526000910160405160208183030381529060405280519060200120905090565b60805250506001600160a01b03831615806200015457506001600160a01b038216155b15620001735760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b03928316610100529082166101205260068054919092166001600160a01b03199182161790915560008054909116331790556200038a565b80516001600160a01b0381168114620001ca57600080fd5b919050565b600080600060608486031215620001e557600080fd5b620001f084620001b2565b92506200020060208501620001b2565b91506200021060408501620001b2565b90509250925092565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200024457607f821691505b6020821081036200026557634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620002b957600081815260208120601f850160051c81016020861015620002945750805b601f850160051c820191505b81811015620002b557828155600101620002a0565b5050505b505050565b81516001600160401b03811115620002da57620002da62000219565b620002f281620002eb84546200022f565b846200026b565b602080601f8311600181146200032a5760008415620003115750858301515b600019600386901b1c1916600185901b178555620002b5565b600085815260208120601f198616915b828110156200035b578886015182559484019460019091019084016200033a565b50858210156200037a5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60805160a05160c05160e05161010051610120516131b9620004a56000396000818161042001528181610bc301528181610dcb01528181611030015281816111ec01528181611532015281816119a101528181611c0701528181611d420152612201015260008181610749015281816109c401528181610aa301528181610c4701528181610d0f01528181610e5701528181610ee8015281816110c80152818161127d01528181611318015281816115e00152818161190601528181611b6b01528181611dc801528181611e9001528181611faa015261216701526000818161033c01526122ea01526000818161083901526122c2015260008181610699015261226e0152600081816108a1015261234301526131b96000f3fe6080604052600436106102a05760003560e01c8063757b11561161016e578063cbcf252a116100cb578063e5da07531161007f578063f172a4ce11610064578063f172a4ce14610827578063f5dcb7bb1461085b578063f698da251461088f57600080fd5b8063e5da0753146107f2578063ed24911d1461081257600080fd5b8063d03ca40a116100b0578063d03ca40a1461078b578063dc1d95251461079e578063e42cdd7c146107d257600080fd5b8063cbcf252a14610737578063cbf994f81461076b57600080fd5b80639488791111610122578063a2e2ad7e11610107578063a2e2ad7e146106bb578063a6a7187f146106f7578063a6f9dae11461071757600080fd5b806394887911146106535780639a8a05921461068757600080fd5b80638456cb59116101535780638456cb59146105f15780638a39fa16146106065780638da5cb5b1461063357600080fd5b8063757b1156146105b15780637a828b28146105d157600080fd5b806328f223421161021c5780635405ecb9116101d057806356bda507116101b557806356bda50714610543578063599be46f146105705780635c975abb1461059057600080fd5b80635405ecb9146104f257806354fd4d501461052e57600080fd5b80633f4ba83a116102015780633f4ba83a1461049d57806341b60677146104b25780634d5a5827146104df57600080fd5b806328f22342146104425780633af5d04e1461046257600080fd5b80631878d1f11161027357806321561bfc1161025857806321561bfc146103b757806327de9e32146103d7578063287140511461040e57600080fd5b80631878d1f11461036c5780631ee81fb51461039457600080fd5b806306fdde03146102a557806307a3e0a8146102d05780630d0d57a8146102f2578063152b5c0f1461032a575b600080fd5b3480156102b157600080fd5b506102ba6108c3565b6040516102c79190612620565b60405180910390f35b3480156102dc57600080fd5b506102f06102eb36600461263a565b610951565b005b3480156102fe57600080fd5b5061031261030d36600461274b565b6109aa565b6040516001600160a01b0390911681526020016102c7565b34801561033657600080fd5b5061035e7f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020016102c7565b34801561037857600080fd5b5061031273eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b6103a76103a23660046128ac565b610a80565b60405190151581526020016102c7565b3480156103c357600080fd5b50600654610312906001600160a01b031681565b3480156103e357600080fd5b506103f76103f236600461263a565b610da0565b6040805192151583526020830191909152016102c7565b34801561041a57600080fd5b506103127f000000000000000000000000000000000000000000000000000000000000000081565b34801561044e57600080fd5b506103f761045d366004612951565b610ee1565b34801561046e57600080fd5b506103a761047d366004612994565b600560209081526000928352604080842090915290825290205460ff1681565b3480156104a957600080fd5b506102f0611152565b3480156104be57600080fd5b5061035e6104cd36600461263a565b60046020526000908152604090205481565b6103a76104ed36600461263a565b6111c9565b3480156104fe57600080fd5b5061035e61050d366004612994565b60a01b6001600160a01b039091161760009081526003602052604090205490565b34801561053a57600080fd5b506102ba611398565b34801561054f57600080fd5b50610558600181565b6040516001600160601b0390911681526020016102c7565b34801561057c57600080fd5b506102f061058b3660046129c0565b6113a5565b34801561059c57600080fd5b506000546103a790600160a01b900460ff1681565b3480156105bd57600080fd5b5061035e6105cc3660046129dd565b61143c565b3480156105dd57600080fd5b506103f76105ec36600461263a565b61152b565b3480156105fd57600080fd5b506102f0611617565b34801561061257600080fd5b5061035e61062136600461263a565b60036020526000908152604090205481565b34801561063f57600080fd5b50600054610312906001600160a01b031681565b34801561065f57600080fd5b5061035e7f92b2008d2a99f26809ac9d1989fe92334aa84124767331997ba0eec16050ecf481565b34801561069357600080fd5b5061035e7f000000000000000000000000000000000000000000000000000000000000000081565b3480156106c757600080fd5b5061035e6106d6366004612994565b60a01b6001600160a01b039091161760009081526004602052604090205490565b34801561070357600080fd5b5061035e610712366004612a78565b611694565b34801561072357600080fd5b506102f06107323660046129c0565b611750565b34801561074357600080fd5b506103127f000000000000000000000000000000000000000000000000000000000000000081565b34801561077757600080fd5b506103a7610786366004612b5a565b61180c565b6103a7610799366004612bf3565b611c81565b3480156107aa57600080fd5b5061035e7fde64b4c9fac43e1615e938b03573b078604f57b4d2e78d3a27d7b20ba017e12681565b3480156107de57600080fd5b5061035e6107ed366004612c56565b611f1b565b3480156107fe57600080fd5b506103a761080d366004612994565b61223c565b34801561081e57600080fd5b5061035e61226a565b34801561083357600080fd5b5061035e7f000000000000000000000000000000000000000000000000000000000000000081565b34801561086757600080fd5b5061035e7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81565b34801561089b57600080fd5b5061035e7f000000000000000000000000000000000000000000000000000000000000000081565b600180546108d090612cf8565b80601f01602080910402602001604051908101604052809291908181526020018280546108fc90612cf8565b80156109495780601f1061091e57610100808354040283529160200191610949565b820191906000526020600020905b81548152906001019060200180831161092c57829003601f168201915b505050505081565b336000818152600560209081526040808320858452825291829020805460ff1916600117905590518381527f85eb1f050732417c0566422b6004a6c5cbded9ded1a406de04060719af52a13a910160405180910390a250565b60405163f908bc7760e01b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f908bc77906109ff903390889088908890600401612d2c565b6020604051808303816000875af1158015610a1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a429190612d5e565b6040519091506001600160a01b038216907fec97633905b1dbe9773a7536e9a986dcf89803e1193934b7b6d76587c68beb4090600090a29392505050565b6040516331a9108f60e11b81526004810185905260009081906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690636352211e90602401602060405180830381865afa158015610aea573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b0e9190612d5e565b9050336001600160a01b03821614610b4f5760405163521eb56d60e11b81523360048201526001600160a01b03821660248201526044015b60405180910390fd5b60a086901b6001600160a01b0388161760008181526004602052604081205490610b7d8a858b8b8b8761143c565b9050610b8a8a8288612365565b81610b9481612d91565b60008581526004602081905260408083208490555163dc4f8bc560e01b81529295509092506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169163dc4f8bc591610bfa918f918f918e9101612deb565b6020604051808303816000875af1158015610c19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c3d9190612e2c565b90508015610cf8577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663dff7672460016001600160601b03168b51610c8b9190612e47565b8d8d8d8d6040518663ffffffff1660e01b8152600401610cae9493929190612e97565b60206040518083038185885af1158015610ccc573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610cf19190612e2c565b9550610d92565b6040516337fdd9c960e21b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063dff76724903490610d4c908f908f908f908f90600401612e97565b60206040518083038185885af1158015610d6a573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610d8f9190612e2c565b95505b505050505095945050505050565b60405163161e984960e31b815233600482015260248101829052600090819081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063b0f4c248906044016020604051808303816000875af1158015610e14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e389190612edc565b6040516352e82ce560e11b8152336004820152602481018690529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a5d059ca906044015b60408051808303816000875af1158015610ea8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ecc9190612ef5565b90935091508015610edb578091505b50915091565b60008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636352211e866040518263ffffffff1660e01b8152600401610f3491815260200190565b602060405180830381865afa158015610f51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f759190612d5e565b9050336001600160a01b03821614610fb15760405163521eb56d60e11b81523360048201526001600160a01b0382166024820152604401610b46565b60a085901b6001600160a01b0387161760008181526003602052604081205490610fdd89858a85611694565b9050610fea898289612365565b81610ff481612d91565b6000858152600360205260408082208390555163161e984960e31b81526001600160a01b038d81166004830152602482018d90529295509092507f00000000000000000000000000000000000000000000000000000000000000009091169063b0f4c248906044016020604051808303816000875af115801561107b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061109f9190612edc565b6040516352e82ce560e11b81526001600160a01b038c81166004830152602482018c90529192507f00000000000000000000000000000000000000000000000000000000000000009091169063a5d059ca9060440160408051808303816000875af1158015611112573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111369190612ef5565b90975095508015611145578095505b5050505050935093915050565b6000546001600160a01b031633146111925760005460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610b46565b6000805460ff60a01b1916815560405133917faeb196d352664784d1900b0e7414a8face7d29f4dae8c4b0cf68ed477423bbf491a2565b60405163542db44960e01b81526004810182905260009081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063542db449906024016020604051808303816000875af1158015611235573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112599190612e2c565b905080156112fc5760405163388fdbed60e21b8152336004820152602481018490527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e23f6fb49060019060440160206040518083038185885af11580156112d0573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906112f59190612e2c565b9150611392565b60405163388fdbed60e21b8152336004820152602481018490527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e23f6fb490349060440160206040518083038185885af115801561136a573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061138f9190612e2c565b91505b50919050565b600280546108d090612cf8565b6000546001600160a01b031633146113e55760005460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610b46565b6006805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040517ff8e76e8a7c35558598a944d509f1ed32b104e77b1098ef1dfa5b97b86b09df8f90600090a250565b600061144661226a565b7fde64b4c9fac43e1615e938b03573b078604f57b4d2e78d3a27d7b20ba017e126888888888860405160200161147d929190612f21565b60408051601f198184030181528282528051602091820120908301969096526001600160a01b0394851690820152929091166060830152608082015260a081019190915260c0810184905260e0016040516020818303038152906040528051906020012060405160200161150892919061190160f01b81526002810192909252602282015260420190565b6040516020818303038152906040528051906020012090505b9695505050505050565b60008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166325e1afc3856040518263ffffffff1660e01b815260040161157e91815260200190565b6020604051808303816000875af115801561159d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115c19190612edc565b60405163ccc9305d60e01b8152336004820152602481018690529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063ccc9305d90604401610e8a565b6000546001600160a01b031633146116575760005460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610b46565b6000805460ff60a01b1916600160a01b17815560405133917f5ee71a369c8672edded508e624ffc9257fa1ae6886ef32905c18e60196bca39991a2565b600061169e61226a565b604080517f92b2008d2a99f26809ac9d1989fe92334aa84124767331997ba0eec16050ecf460208201526001600160a01b038089169282019290925290861660608201526080810185905260a0810184905260c0016040516020818303038152906040528051906020012060405160200161173092919061190160f01b81526002810192909252602282015260420190565b604051602081830303815290604052805190602001209050949350505050565b6000546001600160a01b031633146117905760005460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610b46565b6001600160a01b0381166117b75760405163d92e233d60e01b815260040160405180910390fd5b6000805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b038316908117825560405190917f4ffd725fc4a22075e9ec71c59edf9c38cdeb588a91b24fc5b61388c5be41282b91a250565b60006001600160a01b0387166118355760405163d92e233d60e01b815260040160405180910390fd5b835173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03891601611a0a5760005b818110156118ee57600086828151811061187b5761187b612f46565b60200260200101516000015163ffffffff161180156118c057508581815181106118a7576118a7612f46565b6020026020010151602001516001600160601b03166000145b156118de57604051637c946ed760e01b815260040160405180910390fd5b6118e781612d91565b905061185f565b5060405163197f329f60e31b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063cbf994f8906119459033908b908b908b908b908b90600401612fa6565b6020604051808303816000875af1158015611964573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119889190612e2c565b604051630be6cc4b60e31b8152600481018590529092507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690635f36625890602401600060405180830381600087803b1580156119ed57600080fd5b505af1158015611a01573d6000803e3d6000fd5b50505050611c76565b60008167ffffffffffffffff811115611a2557611a2561266b565b604051908082528060200260200182016040528015611a4e578160200160208202803683370190505b50905060005b82811015611b53576000878281518110611a7057611a70612f46565b60200260200101516000015163ffffffff161115611b4357868181518110611a9a57611a9a612f46565b6020026020010151602001516001600160601b0316600003611acf57604051637c946ed760e01b815260040160405180910390fd5b868181518110611ae157611ae1612f46565b6020026020010151602001516001600160601b0316828281518110611b0857611b08612f46565b6020026020010181815250506001878281518110611b2857611b28612f46565b6020908102919091018101516001600160601b039092169101525b611b4c81612d91565b9050611a54565b5060405163197f329f60e31b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063cbf994f890611baa9033908c908c908c908c908c90600401612fa6565b6020604051808303816000875af1158015611bc9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bed9190612e2c565b6040516338f3a6a160e21b81529093506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063e3ce9a8490611c429087908d908c908790600401612ffc565b600060405180830381600087803b158015611c5c57600080fd5b505af1158015611c70573d6000803e3d6000fd5b50505050505b509695505050505050565b6006546000906001600160a01b031615611d28576006546040516356a7b60760e01b8152600481018690523360248201526001600160a01b03909116906356a7b60790604401602060405180830381865afa158015611ce4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d089190612e2c565b611d28576040516322ddebd960e21b815260048101859052602401610b46565b60405163dc4f8bc560e01b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063dc4f8bc590611d7b90339089908890600401612deb565b6020604051808303816000875af1158015611d9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dbe9190612e2c565b90508015611e79577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663dff7672460016001600160601b03168651611e0c9190612e47565b338888886040518663ffffffff1660e01b8152600401611e2f9493929190612e97565b60206040518083038185885af1158015611e4d573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190611e729190612e2c565b9150611f13565b6040516337fdd9c960e21b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063dff76724903490611ecd9033908a908a908a90600401612e97565b60206040518083038185885af1158015611eeb573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190611f109190612e2c565b91505b509392505050565b60008054600160a01b900460ff1615611f47576040516313d0ff5960e31b815260040160405180910390fd5b6001600160a01b038616611f6e5760405163d92e233d60e01b815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038716016120315760405163fbdeb3d760e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063fbdeb3d790611fe7908a908990899089908990600401613067565b6020604051808303816000875af1158015612006573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061202a9190612edc565b9050611521565b825160008167ffffffffffffffff81111561204e5761204e61266b565b604051908082528060200260200182016040528015612077578160200160208202803683370190505b50905060005b8281101561214f5785818151811061209757612097612f46565b6020026020010151602001516001600160601b03166000036120cc57604051637c946ed760e01b815260040160405180910390fd5b8581815181106120de576120de612f46565b6020026020010151602001516001600160601b031682828151811061210557612105612f46565b602002602001018181525050600186828151811061212557612125612f46565b6020908102919091018101516001600160601b0390921691015261214881612d91565b905061207d565b5060405163fbdeb3d760e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063fbdeb3d7906121a4908c908b908b908b908b90600401613067565b6020604051808303816000875af11580156121c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121e79190612edc565b6040516338f3a6a160e21b81529093506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063e3ce9a8490611c429086908c908b908790600401612ffc565b6001600160a01b038216600090815260056020908152604080832084845290915290205460ff165b92915050565b60007f000000000000000000000000000000000000000000000000000000000000000046146123405761233b604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b6001600160a01b03831661238c5760405163e63f571f60e01b815260040160405180910390fd5b80516041146123b5578051604051631d9f5a5f60e01b8152610b469183916041906004016130ba565b6000816040815181106123ca576123ca612f46565b016020015160f81c90506004811080156123ec57506001600160a01b0384163b155b156123ff576123fc601b826130df565b90505b60208201516040830151600060ff84166004036124d45750604051630b135d3f60e11b80825283916001600160a01b03831690631626ba7e90612448908a908a906004016130f8565b602060405180830381865afa158015612465573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124899190613119565b7fffffffff0000000000000000000000000000000000000000000000000000000016146124cf5780868660405163694d54dd60e01b8152600401610b469392919061315b565b61258c565b8360ff1660050361252c57506001600160a01b0382166000908152600560209081526040808320888452909152902054829060ff166124cf578086866040516312cf832560e01b8152600401610b469392919061315b565b60408051600081526020810180835288905260ff861691810191909152606081018490526080810183905260019060a0016020604051602081039080840390855afa15801561257f573d6000803e3d6000fd5b5050506020604051035190505b866001600160a01b0316816001600160a01b0316146125d15760405163a806216d60e01b81526001600160a01b03808316600483015288166024820152604401610b46565b50505050505050565b6000815180845260005b81811015612600576020818501810151868301820152016125e4565b506000602082860101526020601f19601f83011685010191505092915050565b60208152600061263360208301846125da565b9392505050565b60006020828403121561264c57600080fd5b5035919050565b6001600160a01b038116811461266857600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156126a4576126a461266b565b60405290565b604051601f8201601f1916810167ffffffffffffffff811182821017156126d3576126d361266b565b604052919050565b600082601f8301126126ec57600080fd5b813567ffffffffffffffff8111156127065761270661266b565b612719601f8201601f19166020016126aa565b81815284602083860101111561272e57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060006060848603121561276057600080fd5b83359250602084013561277281612653565b9150604084013567ffffffffffffffff81111561278e57600080fd5b61279a868287016126db565b9150509250925092565b600067ffffffffffffffff8211156127be576127be61266b565b5060051b60200190565b600082601f8301126127d957600080fd5b813560206127ee6127e9836127a4565b6126aa565b82815260059290921b8401810191818101908684111561280d57600080fd5b8286015b84811015611c7657803561282481612653565b8352918301918301612811565b803563ffffffff8116811461284557600080fd5b919050565b600082601f83011261285b57600080fd5b8135602061286b6127e9836127a4565b82815260059290921b8401810191818101908684111561288a57600080fd5b8286015b84811015611c765761289f81612831565b835291830191830161288e565b600080600080600060a086880312156128c457600080fd5b85356128cf81612653565b945060208601359350604086013567ffffffffffffffff808211156128f357600080fd5b6128ff89838a016127c8565b9450606088013591508082111561291557600080fd5b61292189838a0161284a565b9350608088013591508082111561293757600080fd5b50612944888289016126db565b9150509295509295909350565b60008060006060848603121561296657600080fd5b833561297181612653565b925060208401359150604084013567ffffffffffffffff81111561278e57600080fd5b600080604083850312156129a757600080fd5b82356129b281612653565b946020939093013593505050565b6000602082840312156129d257600080fd5b813561263381612653565b60008060008060008060c087890312156129f657600080fd5b8635612a0181612653565b95506020870135612a1181612653565b945060408701359350606087013567ffffffffffffffff80821115612a3557600080fd5b612a418a838b016127c8565b94506080890135915080821115612a5757600080fd5b50612a6489828a0161284a565b92505060a087013590509295509295509295565b60008060008060808587031215612a8e57600080fd5b8435612a9981612653565b93506020850135612aa981612653565b93969395505050506040820135916060013590565b600082601f830112612acf57600080fd5b81356020612adf6127e9836127a4565b82815260069290921b84018101918181019086841115612afe57600080fd5b8286015b84811015611c765760408189031215612b1b5760008081fd5b612b23612681565b612b2c82612831565b8152848201356001600160601b0381168114612b485760008081fd5b81860152835291830191604001612b02565b60008060008060008060c08789031215612b7357600080fd5b8635612b7e81612653565b955060208701359450604087013567ffffffffffffffff80821115612ba257600080fd5b612bae8a838b0161284a565b95506060890135915080821115612bc457600080fd5b50612bd189828a01612abe565b935050612be060808801612831565b915060a087013590509295509295509295565b600080600060608486031215612c0857600080fd5b83359250602084013567ffffffffffffffff80821115612c2757600080fd5b612c33878388016127c8565b93506040860135915080821115612c4957600080fd5b5061279a8682870161284a565b60008060008060008060c08789031215612c6f57600080fd5b8635612c7a81612653565b95506020870135612c8a81612653565b945060408701359350606087013567ffffffffffffffff80821115612cae57600080fd5b612cba8a838b0161284a565b94506080890135915080821115612cd057600080fd5b50612cdd89828a01612abe565b925050612cec60a08801612831565b90509295509295509295565b600181811c90821680612d0c57607f821691505b60208210810361139257634e487b7160e01b600052602260045260246000fd5b60006001600160a01b0380871683528560208401528085166040840152506080606083015261152160808301846125da565b600060208284031215612d7057600080fd5b815161263381612653565b634e487b7160e01b600052601160045260246000fd5b600060018201612da357612da3612d7b565b5060010190565b600081518084526020808501945080840160005b83811015612de057815163ffffffff1687529582019590820190600101612dbe565b509495945050505050565b6001600160a01b0384168152826020820152606060408201526000612e136060830184612daa565b95945050505050565b8051801515811461284557600080fd5b600060208284031215612e3e57600080fd5b61263382612e1c565b808202811582820484141761226457612264612d7b565b600081518084526020808501945080840160005b83811015612de05781516001600160a01b031687529582019590820190600101612e72565b6001600160a01b0385168152836020820152608060408201526000612ebf6080830185612e5e565b8281036060840152612ed18185612daa565b979650505050505050565b600060208284031215612eee57600080fd5b5051919050565b60008060408385031215612f0857600080fd5b612f1183612e1c565b9150602083015190509250929050565b604081526000612f346040830185612e5e565b8281036020840152611f108185612daa565b634e487b7160e01b600052603260045260246000fd5b600081518084526020808501945080840160005b83811015612de0578151805163ffffffff1688528301516001600160601b03168388015260409096019590820190600101612f70565b6001600160a01b038716815285602082015260c060408201526000612fce60c0830187612daa565b8281036060840152612fe08187612f5c565b63ffffffff959095166080840152505060a00152949350505050565b848152600060206001600160a01b03861681840152608060408401526130256080840186612daa565b838103606085015284518082528286019183019060005b818110156130585783518352928401929184019160010161303c565b50909998505050505050505050565b6001600160a01b038616815284602082015260a06040820152600061308f60a0830186612daa565b82810360608401526130a18186612f5c565b91505063ffffffff831660808301529695505050505050565b6060815260006130cd60608301866125da565b60208301949094525060400152919050565b60ff818116838216019081111561226457612264612d7b565b82815260406020820152600061311160408301846125da565b949350505050565b60006020828403121561312b57600080fd5b81517fffffffff000000000000000000000000000000000000000000000000000000008116811461263357600080fd5b6001600160a01b0384168152826020820152606060408201526000612e1360608301846125da56fea2646970667358221220f2d50ac7cf109448ada9fff306a728e5251fe66a1c6e6ec31ba9ad713c2ad83964736f6c6343000813003300000000000000000000000048b6af7b12c71f09e2fc8af4855de4ff54e775ca0000000000000000000000003fb926116d454b95c669b6bf2e7c3bad8d19affa00000000000000000000000042042799b0de38add2a70dc996f69f98e1a85260

Deployed Bytecode

0x6080604052600436106102a05760003560e01c8063757b11561161016e578063cbcf252a116100cb578063e5da07531161007f578063f172a4ce11610064578063f172a4ce14610827578063f5dcb7bb1461085b578063f698da251461088f57600080fd5b8063e5da0753146107f2578063ed24911d1461081257600080fd5b8063d03ca40a116100b0578063d03ca40a1461078b578063dc1d95251461079e578063e42cdd7c146107d257600080fd5b8063cbcf252a14610737578063cbf994f81461076b57600080fd5b80639488791111610122578063a2e2ad7e11610107578063a2e2ad7e146106bb578063a6a7187f146106f7578063a6f9dae11461071757600080fd5b806394887911146106535780639a8a05921461068757600080fd5b80638456cb59116101535780638456cb59146105f15780638a39fa16146106065780638da5cb5b1461063357600080fd5b8063757b1156146105b15780637a828b28146105d157600080fd5b806328f223421161021c5780635405ecb9116101d057806356bda507116101b557806356bda50714610543578063599be46f146105705780635c975abb1461059057600080fd5b80635405ecb9146104f257806354fd4d501461052e57600080fd5b80633f4ba83a116102015780633f4ba83a1461049d57806341b60677146104b25780634d5a5827146104df57600080fd5b806328f22342146104425780633af5d04e1461046257600080fd5b80631878d1f11161027357806321561bfc1161025857806321561bfc146103b757806327de9e32146103d7578063287140511461040e57600080fd5b80631878d1f11461036c5780631ee81fb51461039457600080fd5b806306fdde03146102a557806307a3e0a8146102d05780630d0d57a8146102f2578063152b5c0f1461032a575b600080fd5b3480156102b157600080fd5b506102ba6108c3565b6040516102c79190612620565b60405180910390f35b3480156102dc57600080fd5b506102f06102eb36600461263a565b610951565b005b3480156102fe57600080fd5b5061031261030d36600461274b565b6109aa565b6040516001600160a01b0390911681526020016102c7565b34801561033657600080fd5b5061035e7f9dd6d964e72a376a8989d1d2720ab48ff4f2ad77466fb517dabc84f4a79478d481565b6040519081526020016102c7565b34801561037857600080fd5b5061031273eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b6103a76103a23660046128ac565b610a80565b60405190151581526020016102c7565b3480156103c357600080fd5b50600654610312906001600160a01b031681565b3480156103e357600080fd5b506103f76103f236600461263a565b610da0565b6040805192151583526020830191909152016102c7565b34801561041a57600080fd5b506103127f0000000000000000000000003fb926116d454b95c669b6bf2e7c3bad8d19affa81565b34801561044e57600080fd5b506103f761045d366004612951565b610ee1565b34801561046e57600080fd5b506103a761047d366004612994565b600560209081526000928352604080842090915290825290205460ff1681565b3480156104a957600080fd5b506102f0611152565b3480156104be57600080fd5b5061035e6104cd36600461263a565b60046020526000908152604090205481565b6103a76104ed36600461263a565b6111c9565b3480156104fe57600080fd5b5061035e61050d366004612994565b60a01b6001600160a01b039091161760009081526003602052604090205490565b34801561053a57600080fd5b506102ba611398565b34801561054f57600080fd5b50610558600181565b6040516001600160601b0390911681526020016102c7565b34801561057c57600080fd5b506102f061058b3660046129c0565b6113a5565b34801561059c57600080fd5b506000546103a790600160a01b900460ff1681565b3480156105bd57600080fd5b5061035e6105cc3660046129dd565b61143c565b3480156105dd57600080fd5b506103f76105ec36600461263a565b61152b565b3480156105fd57600080fd5b506102f0611617565b34801561061257600080fd5b5061035e61062136600461263a565b60036020526000908152604090205481565b34801561063f57600080fd5b50600054610312906001600160a01b031681565b34801561065f57600080fd5b5061035e7f92b2008d2a99f26809ac9d1989fe92334aa84124767331997ba0eec16050ecf481565b34801561069357600080fd5b5061035e7f000000000000000000000000000000000000000000000000000000000000000181565b3480156106c757600080fd5b5061035e6106d6366004612994565b60a01b6001600160a01b039091161760009081526004602052604090205490565b34801561070357600080fd5b5061035e610712366004612a78565b611694565b34801561072357600080fd5b506102f06107323660046129c0565b611750565b34801561074357600080fd5b506103127f00000000000000000000000048b6af7b12c71f09e2fc8af4855de4ff54e775ca81565b34801561077757600080fd5b506103a7610786366004612b5a565b61180c565b6103a7610799366004612bf3565b611c81565b3480156107aa57600080fd5b5061035e7fde64b4c9fac43e1615e938b03573b078604f57b4d2e78d3a27d7b20ba017e12681565b3480156107de57600080fd5b5061035e6107ed366004612c56565b611f1b565b3480156107fe57600080fd5b506103a761080d366004612994565b61223c565b34801561081e57600080fd5b5061035e61226a565b34801561083357600080fd5b5061035e7fe7800624217e1c766f5717ba8792e0b2f3e1c1bda11f870b724d9bef903d5b2d81565b34801561086757600080fd5b5061035e7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81565b34801561089b57600080fd5b5061035e7f27b1db74c9a3fc9e566972b761e2366b72470c34498303516dad89ec572a88e781565b600180546108d090612cf8565b80601f01602080910402602001604051908101604052809291908181526020018280546108fc90612cf8565b80156109495780601f1061091e57610100808354040283529160200191610949565b820191906000526020600020905b81548152906001019060200180831161092c57829003601f168201915b505050505081565b336000818152600560209081526040808320858452825291829020805460ff1916600117905590518381527f85eb1f050732417c0566422b6004a6c5cbded9ded1a406de04060719af52a13a910160405180910390a250565b60405163f908bc7760e01b81526000906001600160a01b037f00000000000000000000000048b6af7b12c71f09e2fc8af4855de4ff54e775ca169063f908bc77906109ff903390889088908890600401612d2c565b6020604051808303816000875af1158015610a1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a429190612d5e565b6040519091506001600160a01b038216907fec97633905b1dbe9773a7536e9a986dcf89803e1193934b7b6d76587c68beb4090600090a29392505050565b6040516331a9108f60e11b81526004810185905260009081906001600160a01b037f00000000000000000000000048b6af7b12c71f09e2fc8af4855de4ff54e775ca1690636352211e90602401602060405180830381865afa158015610aea573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b0e9190612d5e565b9050336001600160a01b03821614610b4f5760405163521eb56d60e11b81523360048201526001600160a01b03821660248201526044015b60405180910390fd5b60a086901b6001600160a01b0388161760008181526004602052604081205490610b7d8a858b8b8b8761143c565b9050610b8a8a8288612365565b81610b9481612d91565b60008581526004602081905260408083208490555163dc4f8bc560e01b81529295509092506001600160a01b037f0000000000000000000000003fb926116d454b95c669b6bf2e7c3bad8d19affa169163dc4f8bc591610bfa918f918f918e9101612deb565b6020604051808303816000875af1158015610c19573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c3d9190612e2c565b90508015610cf8577f00000000000000000000000048b6af7b12c71f09e2fc8af4855de4ff54e775ca6001600160a01b031663dff7672460016001600160601b03168b51610c8b9190612e47565b8d8d8d8d6040518663ffffffff1660e01b8152600401610cae9493929190612e97565b60206040518083038185885af1158015610ccc573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610cf19190612e2c565b9550610d92565b6040516337fdd9c960e21b81526001600160a01b037f00000000000000000000000048b6af7b12c71f09e2fc8af4855de4ff54e775ca169063dff76724903490610d4c908f908f908f908f90600401612e97565b60206040518083038185885af1158015610d6a573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610d8f9190612e2c565b95505b505050505095945050505050565b60405163161e984960e31b815233600482015260248101829052600090819081906001600160a01b037f0000000000000000000000003fb926116d454b95c669b6bf2e7c3bad8d19affa169063b0f4c248906044016020604051808303816000875af1158015610e14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e389190612edc565b6040516352e82ce560e11b8152336004820152602481018690529091507f00000000000000000000000048b6af7b12c71f09e2fc8af4855de4ff54e775ca6001600160a01b03169063a5d059ca906044015b60408051808303816000875af1158015610ea8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ecc9190612ef5565b90935091508015610edb578091505b50915091565b60008060007f00000000000000000000000048b6af7b12c71f09e2fc8af4855de4ff54e775ca6001600160a01b0316636352211e866040518263ffffffff1660e01b8152600401610f3491815260200190565b602060405180830381865afa158015610f51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f759190612d5e565b9050336001600160a01b03821614610fb15760405163521eb56d60e11b81523360048201526001600160a01b0382166024820152604401610b46565b60a085901b6001600160a01b0387161760008181526003602052604081205490610fdd89858a85611694565b9050610fea898289612365565b81610ff481612d91565b6000858152600360205260408082208390555163161e984960e31b81526001600160a01b038d81166004830152602482018d90529295509092507f0000000000000000000000003fb926116d454b95c669b6bf2e7c3bad8d19affa9091169063b0f4c248906044016020604051808303816000875af115801561107b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061109f9190612edc565b6040516352e82ce560e11b81526001600160a01b038c81166004830152602482018c90529192507f00000000000000000000000048b6af7b12c71f09e2fc8af4855de4ff54e775ca9091169063a5d059ca9060440160408051808303816000875af1158015611112573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111369190612ef5565b90975095508015611145578095505b5050505050935093915050565b6000546001600160a01b031633146111925760005460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610b46565b6000805460ff60a01b1916815560405133917faeb196d352664784d1900b0e7414a8face7d29f4dae8c4b0cf68ed477423bbf491a2565b60405163542db44960e01b81526004810182905260009081906001600160a01b037f0000000000000000000000003fb926116d454b95c669b6bf2e7c3bad8d19affa169063542db449906024016020604051808303816000875af1158015611235573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112599190612e2c565b905080156112fc5760405163388fdbed60e21b8152336004820152602481018490527f00000000000000000000000048b6af7b12c71f09e2fc8af4855de4ff54e775ca6001600160a01b03169063e23f6fb49060019060440160206040518083038185885af11580156112d0573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906112f59190612e2c565b9150611392565b60405163388fdbed60e21b8152336004820152602481018490527f00000000000000000000000048b6af7b12c71f09e2fc8af4855de4ff54e775ca6001600160a01b03169063e23f6fb490349060440160206040518083038185885af115801561136a573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061138f9190612e2c565b91505b50919050565b600280546108d090612cf8565b6000546001600160a01b031633146113e55760005460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610b46565b6006805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040517ff8e76e8a7c35558598a944d509f1ed32b104e77b1098ef1dfa5b97b86b09df8f90600090a250565b600061144661226a565b7fde64b4c9fac43e1615e938b03573b078604f57b4d2e78d3a27d7b20ba017e126888888888860405160200161147d929190612f21565b60408051601f198184030181528282528051602091820120908301969096526001600160a01b0394851690820152929091166060830152608082015260a081019190915260c0810184905260e0016040516020818303038152906040528051906020012060405160200161150892919061190160f01b81526002810192909252602282015260420190565b6040516020818303038152906040528051906020012090505b9695505050505050565b60008060007f0000000000000000000000003fb926116d454b95c669b6bf2e7c3bad8d19affa6001600160a01b03166325e1afc3856040518263ffffffff1660e01b815260040161157e91815260200190565b6020604051808303816000875af115801561159d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115c19190612edc565b60405163ccc9305d60e01b8152336004820152602481018690529091507f00000000000000000000000048b6af7b12c71f09e2fc8af4855de4ff54e775ca6001600160a01b03169063ccc9305d90604401610e8a565b6000546001600160a01b031633146116575760005460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610b46565b6000805460ff60a01b1916600160a01b17815560405133917f5ee71a369c8672edded508e624ffc9257fa1ae6886ef32905c18e60196bca39991a2565b600061169e61226a565b604080517f92b2008d2a99f26809ac9d1989fe92334aa84124767331997ba0eec16050ecf460208201526001600160a01b038089169282019290925290861660608201526080810185905260a0810184905260c0016040516020818303038152906040528051906020012060405160200161173092919061190160f01b81526002810192909252602282015260420190565b604051602081830303815290604052805190602001209050949350505050565b6000546001600160a01b031633146117905760005460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610b46565b6001600160a01b0381166117b75760405163d92e233d60e01b815260040160405180910390fd5b6000805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b038316908117825560405190917f4ffd725fc4a22075e9ec71c59edf9c38cdeb588a91b24fc5b61388c5be41282b91a250565b60006001600160a01b0387166118355760405163d92e233d60e01b815260040160405180910390fd5b835173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03891601611a0a5760005b818110156118ee57600086828151811061187b5761187b612f46565b60200260200101516000015163ffffffff161180156118c057508581815181106118a7576118a7612f46565b6020026020010151602001516001600160601b03166000145b156118de57604051637c946ed760e01b815260040160405180910390fd5b6118e781612d91565b905061185f565b5060405163197f329f60e31b81526001600160a01b037f00000000000000000000000048b6af7b12c71f09e2fc8af4855de4ff54e775ca169063cbf994f8906119459033908b908b908b908b908b90600401612fa6565b6020604051808303816000875af1158015611964573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119889190612e2c565b604051630be6cc4b60e31b8152600481018590529092507f0000000000000000000000003fb926116d454b95c669b6bf2e7c3bad8d19affa6001600160a01b031690635f36625890602401600060405180830381600087803b1580156119ed57600080fd5b505af1158015611a01573d6000803e3d6000fd5b50505050611c76565b60008167ffffffffffffffff811115611a2557611a2561266b565b604051908082528060200260200182016040528015611a4e578160200160208202803683370190505b50905060005b82811015611b53576000878281518110611a7057611a70612f46565b60200260200101516000015163ffffffff161115611b4357868181518110611a9a57611a9a612f46565b6020026020010151602001516001600160601b0316600003611acf57604051637c946ed760e01b815260040160405180910390fd5b868181518110611ae157611ae1612f46565b6020026020010151602001516001600160601b0316828281518110611b0857611b08612f46565b6020026020010181815250506001878281518110611b2857611b28612f46565b6020908102919091018101516001600160601b039092169101525b611b4c81612d91565b9050611a54565b5060405163197f329f60e31b81526001600160a01b037f00000000000000000000000048b6af7b12c71f09e2fc8af4855de4ff54e775ca169063cbf994f890611baa9033908c908c908c908c908c90600401612fa6565b6020604051808303816000875af1158015611bc9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bed9190612e2c565b6040516338f3a6a160e21b81529093506001600160a01b037f0000000000000000000000003fb926116d454b95c669b6bf2e7c3bad8d19affa169063e3ce9a8490611c429087908d908c908790600401612ffc565b600060405180830381600087803b158015611c5c57600080fd5b505af1158015611c70573d6000803e3d6000fd5b50505050505b509695505050505050565b6006546000906001600160a01b031615611d28576006546040516356a7b60760e01b8152600481018690523360248201526001600160a01b03909116906356a7b60790604401602060405180830381865afa158015611ce4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d089190612e2c565b611d28576040516322ddebd960e21b815260048101859052602401610b46565b60405163dc4f8bc560e01b81526000906001600160a01b037f0000000000000000000000003fb926116d454b95c669b6bf2e7c3bad8d19affa169063dc4f8bc590611d7b90339089908890600401612deb565b6020604051808303816000875af1158015611d9a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dbe9190612e2c565b90508015611e79577f00000000000000000000000048b6af7b12c71f09e2fc8af4855de4ff54e775ca6001600160a01b031663dff7672460016001600160601b03168651611e0c9190612e47565b338888886040518663ffffffff1660e01b8152600401611e2f9493929190612e97565b60206040518083038185885af1158015611e4d573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190611e729190612e2c565b9150611f13565b6040516337fdd9c960e21b81526001600160a01b037f00000000000000000000000048b6af7b12c71f09e2fc8af4855de4ff54e775ca169063dff76724903490611ecd9033908a908a908a90600401612e97565b60206040518083038185885af1158015611eeb573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190611f109190612e2c565b91505b509392505050565b60008054600160a01b900460ff1615611f47576040516313d0ff5960e31b815260040160405180910390fd5b6001600160a01b038616611f6e5760405163d92e233d60e01b815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038716016120315760405163fbdeb3d760e01b81526001600160a01b037f00000000000000000000000048b6af7b12c71f09e2fc8af4855de4ff54e775ca169063fbdeb3d790611fe7908a908990899089908990600401613067565b6020604051808303816000875af1158015612006573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061202a9190612edc565b9050611521565b825160008167ffffffffffffffff81111561204e5761204e61266b565b604051908082528060200260200182016040528015612077578160200160208202803683370190505b50905060005b8281101561214f5785818151811061209757612097612f46565b6020026020010151602001516001600160601b03166000036120cc57604051637c946ed760e01b815260040160405180910390fd5b8581815181106120de576120de612f46565b6020026020010151602001516001600160601b031682828151811061210557612105612f46565b602002602001018181525050600186828151811061212557612125612f46565b6020908102919091018101516001600160601b0390921691015261214881612d91565b905061207d565b5060405163fbdeb3d760e01b81526001600160a01b037f00000000000000000000000048b6af7b12c71f09e2fc8af4855de4ff54e775ca169063fbdeb3d7906121a4908c908b908b908b908b90600401613067565b6020604051808303816000875af11580156121c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121e79190612edc565b6040516338f3a6a160e21b81529093506001600160a01b037f0000000000000000000000003fb926116d454b95c669b6bf2e7c3bad8d19affa169063e3ce9a8490611c429086908c908b908790600401612ffc565b6001600160a01b038216600090815260056020908152604080832084845290915290205460ff165b92915050565b60007f000000000000000000000000000000000000000000000000000000000000000146146123405761233b604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527fe7800624217e1c766f5717ba8792e0b2f3e1c1bda11f870b724d9bef903d5b2d918101919091527f9dd6d964e72a376a8989d1d2720ab48ff4f2ad77466fb517dabc84f4a79478d460608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b905090565b507f27b1db74c9a3fc9e566972b761e2366b72470c34498303516dad89ec572a88e790565b6001600160a01b03831661238c5760405163e63f571f60e01b815260040160405180910390fd5b80516041146123b5578051604051631d9f5a5f60e01b8152610b469183916041906004016130ba565b6000816040815181106123ca576123ca612f46565b016020015160f81c90506004811080156123ec57506001600160a01b0384163b155b156123ff576123fc601b826130df565b90505b60208201516040830151600060ff84166004036124d45750604051630b135d3f60e11b80825283916001600160a01b03831690631626ba7e90612448908a908a906004016130f8565b602060405180830381865afa158015612465573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124899190613119565b7fffffffff0000000000000000000000000000000000000000000000000000000016146124cf5780868660405163694d54dd60e01b8152600401610b469392919061315b565b61258c565b8360ff1660050361252c57506001600160a01b0382166000908152600560209081526040808320888452909152902054829060ff166124cf578086866040516312cf832560e01b8152600401610b469392919061315b565b60408051600081526020810180835288905260ff861691810191909152606081018490526080810183905260019060a0016020604051602081039080840390855afa15801561257f573d6000803e3d6000fd5b5050506020604051035190505b866001600160a01b0316816001600160a01b0316146125d15760405163a806216d60e01b81526001600160a01b03808316600483015288166024820152604401610b46565b50505050505050565b6000815180845260005b81811015612600576020818501810151868301820152016125e4565b506000602082860101526020601f19601f83011685010191505092915050565b60208152600061263360208301846125da565b9392505050565b60006020828403121561264c57600080fd5b5035919050565b6001600160a01b038116811461266857600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156126a4576126a461266b565b60405290565b604051601f8201601f1916810167ffffffffffffffff811182821017156126d3576126d361266b565b604052919050565b600082601f8301126126ec57600080fd5b813567ffffffffffffffff8111156127065761270661266b565b612719601f8201601f19166020016126aa565b81815284602083860101111561272e57600080fd5b816020850160208301376000918101602001919091529392505050565b60008060006060848603121561276057600080fd5b83359250602084013561277281612653565b9150604084013567ffffffffffffffff81111561278e57600080fd5b61279a868287016126db565b9150509250925092565b600067ffffffffffffffff8211156127be576127be61266b565b5060051b60200190565b600082601f8301126127d957600080fd5b813560206127ee6127e9836127a4565b6126aa565b82815260059290921b8401810191818101908684111561280d57600080fd5b8286015b84811015611c7657803561282481612653565b8352918301918301612811565b803563ffffffff8116811461284557600080fd5b919050565b600082601f83011261285b57600080fd5b8135602061286b6127e9836127a4565b82815260059290921b8401810191818101908684111561288a57600080fd5b8286015b84811015611c765761289f81612831565b835291830191830161288e565b600080600080600060a086880312156128c457600080fd5b85356128cf81612653565b945060208601359350604086013567ffffffffffffffff808211156128f357600080fd5b6128ff89838a016127c8565b9450606088013591508082111561291557600080fd5b61292189838a0161284a565b9350608088013591508082111561293757600080fd5b50612944888289016126db565b9150509295509295909350565b60008060006060848603121561296657600080fd5b833561297181612653565b925060208401359150604084013567ffffffffffffffff81111561278e57600080fd5b600080604083850312156129a757600080fd5b82356129b281612653565b946020939093013593505050565b6000602082840312156129d257600080fd5b813561263381612653565b60008060008060008060c087890312156129f657600080fd5b8635612a0181612653565b95506020870135612a1181612653565b945060408701359350606087013567ffffffffffffffff80821115612a3557600080fd5b612a418a838b016127c8565b94506080890135915080821115612a5757600080fd5b50612a6489828a0161284a565b92505060a087013590509295509295509295565b60008060008060808587031215612a8e57600080fd5b8435612a9981612653565b93506020850135612aa981612653565b93969395505050506040820135916060013590565b600082601f830112612acf57600080fd5b81356020612adf6127e9836127a4565b82815260069290921b84018101918181019086841115612afe57600080fd5b8286015b84811015611c765760408189031215612b1b5760008081fd5b612b23612681565b612b2c82612831565b8152848201356001600160601b0381168114612b485760008081fd5b81860152835291830191604001612b02565b60008060008060008060c08789031215612b7357600080fd5b8635612b7e81612653565b955060208701359450604087013567ffffffffffffffff80821115612ba257600080fd5b612bae8a838b0161284a565b95506060890135915080821115612bc457600080fd5b50612bd189828a01612abe565b935050612be060808801612831565b915060a087013590509295509295509295565b600080600060608486031215612c0857600080fd5b83359250602084013567ffffffffffffffff80821115612c2757600080fd5b612c33878388016127c8565b93506040860135915080821115612c4957600080fd5b5061279a8682870161284a565b60008060008060008060c08789031215612c6f57600080fd5b8635612c7a81612653565b95506020870135612c8a81612653565b945060408701359350606087013567ffffffffffffffff80821115612cae57600080fd5b612cba8a838b0161284a565b94506080890135915080821115612cd057600080fd5b50612cdd89828a01612abe565b925050612cec60a08801612831565b90509295509295509295565b600181811c90821680612d0c57607f821691505b60208210810361139257634e487b7160e01b600052602260045260246000fd5b60006001600160a01b0380871683528560208401528085166040840152506080606083015261152160808301846125da565b600060208284031215612d7057600080fd5b815161263381612653565b634e487b7160e01b600052601160045260246000fd5b600060018201612da357612da3612d7b565b5060010190565b600081518084526020808501945080840160005b83811015612de057815163ffffffff1687529582019590820190600101612dbe565b509495945050505050565b6001600160a01b0384168152826020820152606060408201526000612e136060830184612daa565b95945050505050565b8051801515811461284557600080fd5b600060208284031215612e3e57600080fd5b61263382612e1c565b808202811582820484141761226457612264612d7b565b600081518084526020808501945080840160005b83811015612de05781516001600160a01b031687529582019590820190600101612e72565b6001600160a01b0385168152836020820152608060408201526000612ebf6080830185612e5e565b8281036060840152612ed18185612daa565b979650505050505050565b600060208284031215612eee57600080fd5b5051919050565b60008060408385031215612f0857600080fd5b612f1183612e1c565b9150602083015190509250929050565b604081526000612f346040830185612e5e565b8281036020840152611f108185612daa565b634e487b7160e01b600052603260045260246000fd5b600081518084526020808501945080840160005b83811015612de0578151805163ffffffff1688528301516001600160601b03168388015260409096019590820190600101612f70565b6001600160a01b038716815285602082015260c060408201526000612fce60c0830187612daa565b8281036060840152612fe08187612f5c565b63ffffffff959095166080840152505060a00152949350505050565b848152600060206001600160a01b03861681840152608060408401526130256080840186612daa565b838103606085015284518082528286019183019060005b818110156130585783518352928401929184019160010161303c565b50909998505050505050505050565b6001600160a01b038616815284602082015260a06040820152600061308f60a0830186612daa565b82810360608401526130a18186612f5c565b91505063ffffffff831660808301529695505050505050565b6060815260006130cd60608301866125da565b60208301949094525060400152919050565b60ff818116838216019081111561226457612264612d7b565b82815260406020820152600061311160408301846125da565b949350505050565b60006020828403121561312b57600080fd5b81517fffffffff000000000000000000000000000000000000000000000000000000008116811461263357600080fd5b6001600160a01b0384168152826020820152606060408201526000612e1360608301846125da56fea2646970667358221220f2d50ac7cf109448ada9fff306a728e5251fe66a1c6e6ec31ba9ad713c2ad83964736f6c63430008130033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

00000000000000000000000048b6af7b12c71f09e2fc8af4855de4ff54e775ca0000000000000000000000003fb926116d454b95c669b6bf2e7c3bad8d19affa00000000000000000000000042042799b0de38add2a70dc996f69f98e1a85260

-----Decoded View---------------
Arg [0] : _serviceRegistry (address): 0x48b6af7B12C71f09e2fC8aF4855De4Ff54e775cA
Arg [1] : _serviceRegistryTokenUtility (address): 0x3Fb926116D454b95c669B6Bf2E7c3bad8d19affA
Arg [2] : _operatorWhitelist (address): 0x42042799B0DE38AdD2a70dc996f69f98E1a85260

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 00000000000000000000000048b6af7b12c71f09e2fc8af4855de4ff54e775ca
Arg [1] : 0000000000000000000000003fb926116d454b95c669b6bf2e7c3bad8d19affa
Arg [2] : 00000000000000000000000042042799b0de38add2a70dc996f69f98e1a85260


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.