ocn-registry
Version:
Oli-systems OCN registry smart contracts
66 lines • 39.5 kB
JSON
{
"language": "Solidity",
"sources": {
"@openzeppelin/contracts/access/AccessControl.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)\n\npragma solidity ^0.8.20;\n\nimport {IAccessControl} from \"./IAccessControl.sol\";\nimport {Context} from \"../utils/Context.sol\";\nimport {ERC165} from \"../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address account => bool) hasRole;\n bytes32 adminRole;\n }\n\n mapping(bytes32 role => RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with an {AccessControlUnauthorizedAccount} error including the required role.\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n return _roles[role].hasRole[account];\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n * is missing `role`.\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert AccessControlUnauthorizedAccount(account, role);\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n if (callerConfirmation != _msgSender()) {\n revert AccessControlBadConfirmation();\n }\n\n _revokeRole(role, callerConfirmation);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n if (!hasRole(role, account)) {\n _roles[role].hasRole[account] = true;\n emit RoleGranted(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n\n /**\n * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n if (hasRole(role, account)) {\n _roles[role].hasRole[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n return true;\n } else {\n return false;\n }\n }\n}\n"
},
"@openzeppelin/contracts/access/IAccessControl.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev The `account` is missing a role.\n */\n error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n /**\n * @dev The caller of a function is not the expected one.\n *\n * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n */\n error AccessControlBadConfirmation();\n\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `callerConfirmation`.\n */\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n"
},
"@openzeppelin/contracts/token/ERC20/IERC20.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n /**\n * @dev Returns the value of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the value of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address to, uint256 value) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n * caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 value) external returns (bool);\n\n /**\n * @dev Moves a `value` amount of tokens from `from` to `to` using the\n * allowance mechanism. `value` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n"
},
"@openzeppelin/contracts/utils/Context.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n"
},
"@openzeppelin/contracts/utils/introspection/ERC165.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n"
},
"@openzeppelin/contracts/utils/introspection/IERC165.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"
},
"contracts/interfaces/ICertificateVerifier.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.24;\n\ninterface ICertificateVerifier {\n struct Signature {\n bytes32 r;\n bytes32 s;\n uint8 v;\n }\n\n struct EMPCertificate {\n string identifier;\n string name;\n string marktfunktion;\n string lieferant;\n string bilanzkreis;\n address owner;\n }\n\n struct CPOCertificate {\n string identifier;\n string name;\n address owner;\n }\n\n struct OtherCertificate {\n string identifier;\n string name;\n address owner;\n }\n\n function verifyEMP(\n bytes memory certificateData,\n bytes memory signature\n ) external view returns (address, EMPCertificate memory, Signature memory);\n\n function verifyCPO(\n bytes memory certificateData,\n bytes memory signature\n ) external view returns (address, CPOCertificate memory, Signature memory);\n\n function verifyOther(\n bytes memory certificateData,\n bytes memory signature\n ) external view returns (address, OtherCertificate memory, Signature memory);\n}\n"
},
"contracts/interfaces/IProviderOracle.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.24;\n\ninterface IProviderOracle {\n struct Provider {\n string name;\n string identifier;\n }\n\n function getProvider(\n string memory identifier\n ) external view returns (Provider memory);\n\n function addProvider(Provider memory provider) external;\n}\n"
},
"contracts/IOcnCvManager.sol": {
"content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity 0.8.24;\n\ninterface IOcnCvManager {\n /* ********************************** */\n /* ENUMS */\n /* ********************************** */\n\n enum CvStatus { NOT_VERIFIED, APPROVED, FAILED }\n\n}\n"
},
"contracts/IOcnPaymentManager.sol": {
"content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity 0.8.24;\n\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ninterface IOcnPaymentManager {\n /* ********************************** */\n /* ENUMS */\n /* ********************************** */\n\n enum PaymentStatus { PENDING, PAYMENT_UP_TO_DATE, INSUFFICIENT_FUNDS, INACTIVE }\n\n /* ********************************** */\n /* EVENTS */\n /* ********************************** */\n\n event OwnershipTransferred(address indexed oldAdmin, address indexed newAdmin);\n event PartyStaked(address stakedBy, address party, uint256 amount);\n event StakeWithdrawn(address indexed party, uint256 amount);\n\n /* ********************************** */\n /* FUNCTIONS */\n /* ********************************** */\n\n function initialize(address _euroStablecoin, uint256 _fundingYearlyAmount, address _operator) external;\n function pay(address party) external;\n function withdrawToRegistryOperator(address party) external;\n function getPaymentStatus(address party) external view returns (PaymentStatus);\n function getPaymentBlock(address party) external view returns (uint256, uint256);\n\n /* ********************************** */\n /* STORAGE VARIABLES */\n /* ********************************** */\n\n function euroStablecoin() external view returns (IERC20);\n function stakedFunds(address party) external view returns (uint256);\n function stakingBlock(address party) external view returns (uint256);\n\n /* ********************************** */\n /* ERRORS */\n /* ********************************** */\n\n error StakeAlreadyDeposited();\n error InsufficientAllowance();\n error TransferFailed();\n error NoFundsStaked();\n error WithdrawalNotAllowed();\n}\n"
},
"contracts/OcnRegistry.sol": {
"content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity 0.8.24;\n\nimport {IOcnPaymentManager} from \"./IOcnPaymentManager.sol\";\nimport {IOcnCvManager} from \"./IOcnCvManager.sol\";\nimport \"./interfaces/ICertificateVerifier.sol\";\nimport \"./interfaces/IProviderOracle.sol\";\n\nimport {AccessControl} from \"@openzeppelin/contracts/access/AccessControl.sol\";\n\ncontract OcnRegistry is AccessControl {\n /* ********************************** */\n /* STORAGE VARIABLES */\n /* ********************************** */\n\n string private prefix;\n\n // OCN Node Operator Listings\n mapping(address => string) private nodeOf;\n mapping(string => bool) private uniqueDomains;\n mapping(address => bool) private uniqueOperators;\n address[] private operators;\n\n // OCPI Party Listings\n enum Role {\n CPO,\n EMSP,\n NAP,\n NSP,\n OTHER,\n SCSP\n }\n\n struct RoleDetails {\n bytes certificateData;\n bytes signature;\n Role role;\n }\n\n struct PartyDetails {\n bytes2 countryCode;\n bytes3 partyId;\n Role[] roles;\n string name;\n string url;\n IOcnPaymentManager.PaymentStatus paymentStatus;\n IOcnCvManager.CvStatus cvStatus;\n bool active;\n uint256 partyIndex;\n }\n\n mapping(bytes2 => mapping(bytes3 => address)) private uniqueParties;\n mapping(address => bool) private uniquePartyAddresses;\n mapping(address => PartyDetails) private partyOf;\n mapping(address => address) private operatorOf;\n mapping(address => bool) private allowedCertificateVerifiers;\n address[] private parties;\n\n IOcnPaymentManager public paymentManager;\n ICertificateVerifier public certificateVerifier;\n\n // Providers Oracle\n mapping(Role => IProviderOracle) private roleOracle;\n\n /* ********************************** */\n /* CUSTOM ERRORS */\n /* ********************************** */\n error EmptyDomainName(string reason);\n error DomainNameAlreadyRegistered(string reason);\n error EmptyCountryCode(string reason);\n error EmptyPartyId(string reason);\n error NoRolesProvided(string reason);\n error EmptyOperator(string reason);\n error PartyAlreadyRegistered(string reason);\n error PartyNotRegistered(string reason);\n error SignerMismatch(string reason);\n error InvalidCertificate(address verifier, string reason);\n error ProviderNotFound(Role role, string reason);\n error CerificateOwnerMismatch(string reason);\n\n /* ********************************** */\n /* EVENTS */\n /* ********************************** */\n\n event OwnershipTransferred(address indexed oldAdmin, address indexed newAdmin);\n event OperatorUpdate(address indexed operator, string domain);\n event PartyUpdate(bytes2 countryCode, bytes3 partyId, address indexed partyAddress, Role[] roles, string name, string url, IOcnPaymentManager.PaymentStatus paymentStatus, IOcnCvManager.CvStatus cvStatus, bool active, address indexed operatorAddress);\n\n event PartyDelete(bytes2 countryCode, bytes3 partyId, address indexed partyAddress, Role[] roles, string name, string url, IOcnPaymentManager.PaymentStatus paymentStatus, IOcnCvManager.CvStatus cvStatus, bool active);\n\n /* ********************************** */\n /* INITIALIZER */\n /* ********************************** */\n\n constructor(address _paymentManager, address _certificateVerifier) {\n prefix = \"\\u0019Ethereum Signed Message:\\n32\";\n paymentManager = IOcnPaymentManager(_paymentManager);\n certificateVerifier = ICertificateVerifier(_certificateVerifier);\n _grantRole(DEFAULT_ADMIN_ROLE, msg.sender);\n }\n\n function transferOwnership(address newOwner) public onlyRole(DEFAULT_ADMIN_ROLE) {\n grantRole(DEFAULT_ADMIN_ROLE, newOwner);\n revokeRole(DEFAULT_ADMIN_ROLE, msg.sender);\n\n emit OwnershipTransferred(msg.sender, newOwner);\n }\n\n function adminDeleteOperator(address operator) public onlyRole(DEFAULT_ADMIN_ROLE) {\n deleteNode(operator);\n }\n\n function adminDeleteParty(bytes2 countryCode, bytes3 partyId) public onlyRole(DEFAULT_ADMIN_ROLE) {\n address party = uniqueParties[countryCode][partyId];\n deleteParty(party);\n }\n\n function setNode(address operator, string memory domain) private {\n if (bytes(domain).length == 0) {\n revert EmptyDomainName(\"Cannot set empty domain name. Use deleteNode method instead.\");\n }\n if (uniqueDomains[domain]) {\n revert DomainNameAlreadyRegistered(\"Domain name already registered.\");\n }\n uniqueDomains[domain] = true;\n\n if (!uniqueOperators[operator]) {\n operators.push(operator);\n }\n\n uniqueOperators[operator] = true;\n nodeOf[operator] = domain;\n emit OperatorUpdate(operator, domain);\n }\n\n function setNode(string memory domain) public {\n setNode(msg.sender, domain);\n }\n\n function setNodeRaw(address operator, string memory domain, uint8 v, bytes32 r, bytes32 s) public {\n bytes32 paramHash = keccak256(abi.encodePacked(operator, domain));\n address signer = ecrecover(keccak256(abi.encodePacked(prefix, paramHash)), v, r, s);\n setNode(signer, domain);\n }\n\n function deleteNode(address operator) private {\n string memory domain = nodeOf[operator];\n if (bytes(domain).length == 0) {\n revert EmptyDomainName(\"Cannot delete node that does not exist.\");\n }\n uniqueDomains[domain] = false;\n delete nodeOf[operator];\n emit OperatorUpdate(operator, \"\");\n }\n\n function deleteNode() public {\n deleteNode(msg.sender);\n }\n\n function deleteNodeRaw(address operator, uint8 v, bytes32 r, bytes32 s) public {\n bytes32 paramHash = keccak256(abi.encodePacked(operator));\n address signer = ecrecover(keccak256(abi.encodePacked(prefix, paramHash)), v, r, s);\n deleteNode(signer);\n }\n\n function getNode(address operator) public view returns (string memory) {\n return nodeOf[operator];\n }\n\n function getNodeOperators() public view returns (address[] memory) {\n return operators;\n }\n\n function setParty(bytes2 countryCode, bytes3 partyId, RoleDetails[] memory roles, address operator, string memory name, string memory url) public {\n if (countryCode == bytes2(0)) {\n revert EmptyCountryCode(\"Cannot set empty country_code. Use deleteParty method instead.\");\n }\n if (partyId == bytes3(0)) {\n revert EmptyPartyId(\"Cannot set empty party_id. Use deleteParty method instead.\");\n }\n if (roles.length == 0) {\n revert NoRolesProvided(\"No roles provided.\");\n }\n if (operator == address(0)) {\n revert EmptyOperator(\"Cannot set empty operator. Use deleteParty method instead.\");\n }\n\n Role[] memory verifiedRoles = new Role[](roles.length);\n address credentialOwner = address(0);\n\n // VC verification (All roles must be verified)\n for (uint8 i = 0; i < roles.length; i++) {\n RoleDetails memory roleDetails = roles[i];\n (string memory certificateIdentifier, address owner) = verifyCertificate(roleDetails);\n\n if (credentialOwner == address(0)) {\n credentialOwner = owner;\n }\n\n if (credentialOwner != owner) {\n revert CerificateOwnerMismatch(\"Certificates have different owners\");\n }\n\n IProviderOracle oracle = roleOracle[roleDetails.role];\n if (address(oracle) != address(0)) {\n IProviderOracle.Provider memory provider = oracle.getProvider(certificateIdentifier);\n if (!compareIdentifiers(certificateIdentifier, provider.identifier)) {\n revert ProviderNotFound(roleDetails.role, \"Not active in oracle\");\n }\n }\n\n verifiedRoles[i] = roleDetails.role;\n }\n\n address registeredParty = uniqueParties[countryCode][partyId];\n if (registeredParty != address(0) && registeredParty != credentialOwner) {\n revert PartyAlreadyRegistered(\"Party with country_code/party_id already registered under different address.\");\n }\n uniqueParties[countryCode][partyId] = credentialOwner;\n if (bytes(nodeOf[operator]).length == 0) {\n revert PartyNotRegistered(\"Provided operator not registered.\");\n }\n\n uint256 partyIndex = partyOf[credentialOwner].partyIndex;\n if (!uniquePartyAddresses[credentialOwner]) {\n parties.push(credentialOwner);\n // get last index of the array\n partyIndex = parties.length - 1;\n }\n\n uniquePartyAddresses[credentialOwner] = true;\n\n IOcnPaymentManager.PaymentStatus paymentStatus = paymentManager.getPaymentStatus(credentialOwner);\n partyOf[credentialOwner] = PartyDetails(countryCode, partyId, verifiedRoles, name, url, paymentStatus, IOcnCvManager.CvStatus.NOT_VERIFIED, true, partyIndex);\n operatorOf[credentialOwner] = operator;\n\n PartyDetails memory details = partyOf[credentialOwner];\n emit PartyUpdate(details.countryCode, details.partyId, credentialOwner, details.roles, details.name, details.url, details.paymentStatus, details.cvStatus, details.active, operator);\n }\n\n function setPartyRaw(address party, bytes2 countryCode, bytes3 partyId, RoleDetails[] memory roles, address operator, string memory name, string memory url, uint8 v, bytes32 r, bytes32 s) public {\n bytes memory rolesBytes = \"\";\n for (uint8 i = 0; i < roles.length; i++) {\n RoleDetails memory roleDetails = roles[i];\n rolesBytes = abi.encodePacked(rolesBytes, roleDetails.certificateData, roleDetails.signature, roleDetails.role);\n }\n bytes32 rolesHash = keccak256(rolesBytes);\n bytes32 paramHash = keccak256(abi.encodePacked(party, countryCode, partyId, rolesHash, operator, name, url));\n address signer = ecrecover(keccak256(abi.encodePacked(prefix, paramHash)), v, r, s);\n if (signer != party) {\n revert SignerMismatch(\"Signer and provided party address different.\");\n }\n setParty(countryCode, partyId, roles, operator, name, url);\n }\n\n function deleteParty(address party) private {\n if (operatorOf[party] == address(0)) {\n revert PartyNotRegistered(\"Cannot delete party that does not exist. No operator found for given party.\");\n }\n delete operatorOf[party];\n PartyDetails memory details = partyOf[party];\n delete uniqueParties[details.countryCode][details.partyId];\n delete partyOf[party];\n delete parties[details.partyIndex];\n uniquePartyAddresses[party] = false;\n\n emit PartyDelete(details.countryCode, details.partyId, party, details.roles, details.name, details.url, details.paymentStatus, details.cvStatus, details.active);\n }\n\n function deleteParty() public {\n deleteParty(msg.sender);\n }\n\n function deletePartyRaw(address party, uint8 v, bytes32 r, bytes32 s) public {\n bytes32 paramHash = keccak256(abi.encodePacked(party));\n address signer = ecrecover(keccak256(abi.encodePacked(prefix, paramHash)), v, r, s);\n if (signer != party) {\n revert SignerMismatch(\"Signer and provided party address different.\");\n }\n deleteParty(signer);\n }\n\n function getOperatorByAddress(address party) public view returns (address operator, string memory domain) {\n operator = operatorOf[party];\n domain = nodeOf[operator];\n }\n\n function getOperatorByOcpi(bytes2 countryCode, bytes3 partyId) public view returns (address operator, string memory domain) {\n address party = uniqueParties[countryCode][partyId];\n operator = operatorOf[party];\n domain = nodeOf[operator];\n }\n\n function getPartyDetailsByAddress(address _partyAddress) public view returns (address partyAddress, bytes2 countryCode, bytes3 partyId, Role[] memory roles, IOcnPaymentManager.PaymentStatus paymentStatus, address operatorAddress, string memory name, string memory url, bool active) {\n PartyDetails storage details = partyOf[_partyAddress];\n partyAddress = _partyAddress;\n countryCode = details.countryCode;\n partyId = details.partyId;\n roles = details.roles;\n paymentStatus = details.paymentStatus;\n operatorAddress = operatorOf[_partyAddress];\n name = details.name;\n url = details.url;\n active = details.active;\n }\n\n function getPartyDetailsByOcpi(bytes2 _countryCode, bytes3 _partyId) public view returns (address partyAddress, bytes2 countryCode, bytes3 partyId, Role[] memory roles, IOcnPaymentManager.PaymentStatus paymentStatus, address operatorAddress, string memory name, string memory url, bool active, uint256 stakingBlock) {\n partyAddress = uniqueParties[_countryCode][_partyId];\n (stakingBlock, ) = paymentManager.getPaymentBlock(partyAddress);\n PartyDetails storage details = partyOf[partyAddress];\n countryCode = details.countryCode;\n partyId = details.partyId;\n roles = details.roles;\n paymentStatus = paymentManager.getPaymentStatus(partyAddress);\n operatorAddress = operatorOf[partyAddress];\n name = details.name;\n url = details.url;\n active = details.active;\n }\n\n function getPartiesCount() public view returns (uint256) {\n return parties.length;\n }\n\n function getParties() public view returns (address[] memory) {\n return parties;\n }\n\n function getPartiesByOperator(address operator) public view returns (address[] memory) {\n address[] memory filteredParties = new address[](parties.length);\n uint32 count = 0;\n for (uint32 i = 0; i < parties.length; i++) {\n if (operatorOf[parties[i]] == operator) {\n filteredParties[count] = parties[i];\n count++;\n }\n }\n address[] memory result = new address[](count);\n for (uint32 i = 0; i < count; i++) {\n result[i] = filteredParties[i];\n }\n return result;\n }\n\n function getPartiesByRole(Role role) public view returns (address[] memory) {\n address[] memory filteredParties = new address[](parties.length);\n uint32 count = 0;\n for (uint32 i = 0; i < parties.length; i++) {\n PartyDetails memory details = partyOf[parties[i]];\n for (uint32 j = 0; j < details.roles.length; j++) {\n if (details.roles[j] == role) {\n filteredParties[count] = parties[i];\n count++;\n break;\n }\n }\n }\n address[] memory result = new address[](count);\n for (uint32 i = 0; i < count; i++) {\n result[i] = filteredParties[i];\n }\n return result;\n }\n\n function setVerifier(address verifier) public onlyRole(DEFAULT_ADMIN_ROLE) {\n require(verifier != address(0), \"Invalid verifier address\");\n require(!allowedCertificateVerifiers[verifier], \"Verifier already allowed\");\n\n allowedCertificateVerifiers[verifier] = true;\n }\n\n function removeVerifier(address verifier) public onlyRole(DEFAULT_ADMIN_ROLE) {\n require(verifier != address(0), \"Invalid verifier address\");\n require(allowedCertificateVerifiers[verifier], \"Verifier not currently allowed\");\n\n allowedCertificateVerifiers[verifier] = false;\n }\n\n function isAllowedVerifier(address verifier) public view returns (bool) {\n return allowedCertificateVerifiers[verifier];\n }\n\n function setProviderOracle(Role role, address oracleAddress) public onlyRole(DEFAULT_ADMIN_ROLE) {\n roleOracle[role] = IProviderOracle(oracleAddress);\n }\n\n function verifyCertificate(RoleDetails memory roleDetails) private view returns (string memory, address) {\n if (roleDetails.role == Role.EMSP) {\n (address verifier, ICertificateVerifier.EMPCertificate memory certificate, ) = certificateVerifier.verifyEMP(roleDetails.certificateData, roleDetails.signature);\n if (!isAllowedVerifier(verifier)) {\n revert InvalidCertificate(verifier, \"Invalid EMP certificate\");\n }\n return (certificate.identifier, certificate.owner);\n } else if (roleDetails.role == Role.CPO) {\n (address verifier, ICertificateVerifier.CPOCertificate memory certificate, ) = certificateVerifier.verifyCPO(roleDetails.certificateData, roleDetails.signature);\n if (!isAllowedVerifier(verifier)) {\n revert InvalidCertificate(verifier, \"Invalid CPO certificate\");\n }\n return (certificate.identifier, certificate.owner);\n } else {\n (address verifier, ICertificateVerifier.OtherCertificate memory certificate, ) = certificateVerifier.verifyOther(roleDetails.certificateData, roleDetails.signature);\n if (!isAllowedVerifier(verifier)) {\n revert InvalidCertificate(verifier, \"Invalid Other certificate\");\n }\n return (certificate.identifier, certificate.owner);\n }\n }\n\n function compareIdentifiers(string memory a, string memory b) private pure returns (bool) {\n return keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b));\n }\n}\n"
}
},
"settings": {
"optimizer": {
"enabled": true,
"runs": 200
},
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers",
"metadata",
"storageLayout",
"devdoc",
"userdoc",
"evm.gasEstimates"
],
"": [
"ast"
]
}
},
"metadata": {
"useLiteralContent": true
}
}
}